私はこの例を実行していました- https://github.com/pytorch/examples/blob/master/dcgan/main.py そして私は基本的な質問があります。
_fake = netG(noise)
label = Variable(label.fill_(fake_label))
output = netD(fake.detach()) # detach to avoid training G on these labels
errD_fake = criterion(output, label)
errD_fake.backward()
D_G_z1 = output.data.mean()
errD = errD_real + errD_fake
optimizerD.step()
_
変数fake
でdetach()
を呼び出す理由を理解しているので、ジェネレーターパラメーターの勾配は計算されません。私の質問は、optimizerD.step()
がDiscriminatorに関連付けられたパラメーターのみを更新するので、それは重要ですか?
OptimizerDは次のように定義されます:optimizerD = optim.Adam(netD.parameters(), lr=opt.lr, betas=(opt.beta1, 0.999))
さらに、Generatorのパラメーターを更新する次のステップでは、その前にnetG.zero_grad()
を呼び出します。これにより、以前に計算されたすべての勾配が最終的に削除されます。さらに、Gネットワークのパラメーターを更新するときは、これを行います--output = netD(fake)
。ここでは、デタッチを使用していません。どうして?
では、なぜ上記のコードで変数(3行目)を切り離す必要があるのでしょうか?
そうです、optimizerD
はnetD
のみを更新し、netG.zero_grad()
が呼び出される前に、netG
のグラデーションは使用されないため、デタッチする必要はありません。ジェネレーターの勾配を計算していないため、時間を節約できます。
基本的には、他の質問にも自分で答えています。パラメータを更新できるようにfake
の勾配を計算する必要があるため、2番目のブロックでnetG
を切り離さないでください。
2番目のブロックreal_label
はfake
の対応するラベルとして使用されるため、ディスクリミネーターが偽の入力が本物であると判断した場合、最終的な損失は小さく、その逆も同様です。これはまさにジェネレーターに必要なものです。 。それがあなたを混乱させたものであるかどうかはわかりませんが、偽の入力で弁別器を訓練することと比較して、それは本当に唯一の違いです。
言っておくけど。デタッチの役割は、グラジエントドロップをフリーズすることです。ネットワークの識別用であれ、ネットワークの生成用であれ、logD(G(z))に関するすべてを更新します。判別ネットワークの場合、Gの凍結は全体的な勾配の更新に影響しません(つまり、内部関数は定数と見なされ、勾配を見つけるための外部関数には影響しません)が、逆に、Dが凍結されている場合はグラデーションの更新を完了する方法はありません。したがって、発電機を訓練する際に凍結Dの勾配を使用しませんでした。したがって、ジェネレーターについては、Dの勾配を計算しましたが、Dの重みを更新しなかったため(optimizer_g.stepのみが書き込まれました)、ジェネレーターのトレーニング時にディスクリミネーターは変更されません。あなたは尋ねるかもしれません、それであなたが弁別器を訓練するとき、あなたはデタッチを加える必要があります。これは余分な動きではありませんか?グラデーションをフリーズするので、トレーニングをスピードアップでき、使用できる場所で使用できます。それは余分な仕事ではありません。次に、ジェネレーターをトレーニングするとき、logD(G(z))のため、Dの勾配をフリーズする方法がないため、ここではデタッチを記述しません。
上位投票の回答は、不正確/不完全です。
これを確認してください: https://github.com/pytorch/examples/issues/116 そして@plopdの答えを見てください:
本当じゃない。グラフから
fake
をデタッチすることは、実際にジェネレーターを更新するときにノイズがGを順方向に通過するのを防ぐために必要です。デタッチしない場合、Dの勾配更新にfake
は必要ありませんが、それでも計算グラフに追加され、すべての変数をクリアするbackward
パスの結果として追加されます。グラフ内(retain_graph=False
デフォルト)、Gが更新されるとfake
は使用できなくなります。
この投稿はまた多くを明らかにします: https://zhuanlan.zhihu.com/p/43843694 (中国語)。
偽の変数がジェネレータグラフの一部になっているため [1] ですが、これは望ましくありません。したがって、ディスクリミネーターに入れる前に、彼から「切り離す」必要があります。