Pytorch Debug

誤差逆伝搬がうまくできなかったときの備忘録

2020年09月08日

Pytorchの誤差逆伝搬

機械学習プログラムにおけるもっとも大切なポイント'誤差逆伝搬'. Pytorchはloss.backward()とするだけで実行できるんだが, ずっとこんなErrorが続いていた.

このエラー修正にマジ 1週間ちょいかかった...

そもそも, tensorflowの静的グラフと違って, pytorchは動的計算グラフを形成する.
モデルに入力する前に, 入力テンソルに対して, torch.autograd.Variable()とすれば, その後の計算を記録してくれる.
(なんか, テンソルのときにrequires_grad=Trueとかすれば同じらしいけど, まあ, データセットから読み込むからね... 後から付け足せるautograd使うとラクっすよね!!)

エラー内容

"inplace関数を使っているから情報が書き換えられているんだよ!"と書いてはある. どうやらinplace関数は, i += 1とかの他にも, x[3]=c[0]*x[0]のような行列の要素を見るときにもinplace関数が使われているらしい.
でもこのときに書き換わるといっても, それは,
" you use a tensor or its part to compute a part of the same tensor"
のときらしい! このときは別のテンソルを予め定義しておいて代入していく流れをとるらしいが, 今回はなんか違った...
cf) pyTorch backwardできない例まとめ
cf) RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation

clone()とdetach()の違い

なんかさっきのinplaceエラーのときに, やたら出てきた回答例が, "とりあえず .clone()しとけ!!"ってきな内容だった.
detach():

  1. メモリを共有してグラフからテンソルをコピーする(切り出す) → 何かしらの演算をするとコピー元も影響を受ける.
  2. 勾配情報を含まないテンソルの形で取り出すことができる.
clone():
  1. コピー元とメモリを共有しない → 一方が何かしらの演算を行っても影響を受けない.
  2. 勾配情報は... 含める!! (つまり, 計算グラフ(計算パス)は引き継がれている!!)
だから,

              # 一旦メモリを共有しない状態にしてから, requires_grad無しの固定入力とする
              x = my_tensor.clone().detach() 
            

              # requires_gradがNone(勾配情報が無い)状態(つまり, 計算Pathがコピーされない)で, メモリ共有を行わない完全なコピー
              x = my_tensor.detach().clone() 
            
っていう違いがでてくるらしい.
理解はできるが, どういうときにどういうふうに使うのかイメージがつかない...
detach()はGANなどの生成モデルで, GeneratorとDiscriminatorの重みの共有をしないように...とかあって, これからの楽しみが増えた.
cf) PyTorchのdetach()メソッドの意味

デバック方法その1 :ネットワークのパラメータ閲覧

自分が動かしているネットワークが実際のどのようなパラメータ('重み'っすね)をもっているか, 出力してみる.


              for param in model.parameters(): 
                print(param)
            
とすれば, すべてのパラメータが出力できるし,

              print(net.state_dict()['conv1.weight'])
            
をすれば指定したパラメータを出力できる.

              print(net.state_dict().keys())
            
とすれば名前だけ表示させれる.
cf) pyTorchのNetworkのパラメータの閲覧と書き換え

デバック方法その2 :勾配情報の閲覧

loss.backward()を行った後に, 実際に微分された値をinput_var.gradとすれば微分された値を見ることができる. なんか今現在は, ここがNoneになってて, いらついている.
ちなみに中間変数の勾配も求めることができるが, 今回は使わなかった.
cf) Pytorchの自動微分で勾配を求める

さらなるデバック方法: いま使ってないんだけど, tensorboardXやPyTorchVizを使うと, 計算グラフが視覚的に表示できてうれしい.
cf) tensorboardX
cf) pytorchviz