PyTorch デザインノート : Autograd メカニクス (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 05/22/2018 (0.4.0)
* 本ページは、PyTorch Doc Notes の – Autograd mechanics を動作確認・翻訳した上で適宜、補足説明したものです:
* サンプルコードの動作確認はしておりますが、適宜、追加改変している場合もあります。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
このノートは autograd がどのように動作して演算を記録するかの概要を提示します。それは厳密には必ずしもこれの総てを理解する必要はありませんが、それに精通することを推奨します、何故ならばそれはより効率的で、きれいなプログラムを書くために役立ちそしてデバッグを助けることができます。
backward からサブグラフを除外する
総ての Tensor はフラグ : requires_grad を持ちます、これは勾配計算からサブグラフのきめ細かい除外を許し、効率性を増大できます。
requires_grad
勾配を要求する演算への単一の入力がある場合、その出力もまた勾配を要求します。逆に、総ての入力が勾配を要求しない場合に限り、出力もまたそれを要求しません。backward 計算は決してサブグラフ内では遂行されません、そこでは総ての Tensor が勾配を要求しません。
>>> x = torch.randn(5, 5) # requires_grad=False by default >>> y = torch.randn(5, 5) # requires_grad=False by default >>> z = torch.randn((5, 5), requires_grad=True) >>> a = x + y >>> a.requires_grad False >>> b = a + z >>> b.requires_grad True
貴方のモデルの一部を凍結することを望むときこれは特に有用です、あるいは幾つかのパラメータに関して勾配を使用しないことを前もって知るでしょう。例えば、貴方が事前訓練された CNN を再調整することを望む場合、requires_grad フラグを凍結ベースに切り替えれば十分で、そして計算が最後の層に到達するまで中間バッファはセーブされないでしょう。そこではアフィン変換は勾配を必要とする重みを使用し、そしてネットワーク出力もまたそれらを必要とするでしょう。
model = torchvision.models.resnet18(pretrained=True) for param in model.parameters(): param.requires_grad = False # Replace the last fully-connected layer # Parameters of newly constructed modules have requires_grad=True by default model.fc = nn.Linear(512, 100) # Optimize only the classifier optimizer = optim.SGD(model.fc.parameters(), lr=1e-2, momentum=0.9)
autograd はどのように履歴をエンコードするか
Autograd はリバース自動微分システムです。概念的には、autograd は演算を実行するときデータを生成した演算の総てを記録するグラフを記録します、貴方に有向非巡回グラフを与えその葉は入力 tensor で根は出力 tensor です。このグラフを根から葉へ追跡することにより、連鎖率を使用して勾配を自動的に計算できます。内部的には、autograd はこのグラフを関数オブジェクト (実際には式) のグラフとして表します、これはグラフの評価の結果を計算するために apply() することができます。forward パスを計算するとき、autograd は要求された計算を同時に遂行して勾配を計算する関数を表わすグラフを構築します (各 torch.Tensor の .grad_fn 属性はこのグラフへのエントリポイントです)。forward パスが完了したとき、勾配を計算するためにこのグラフを backward パスで評価します。
注意すべき重要はことはグラフは総ての iteration でスクラッチから再作成されることです、そしてこれは任意の Python 制御フロー・ステートメントを正確に可能にするもので、これは総ての iteration でグラフの全体の shape とサイズを変更することができます。訓練を launch する前に総ての起こりうるパスをエンコードする必要はありません – 貴方が実行するものが貴方が微分するものです。
autograd による in-place 演算
autograd の in-place 演算のサポートは困難な事柄で、殆どの場合それらの使用を奨励しません。autograd の積極的なバッファ解放と再利用は非常に効率的でそして in-place 演算が実際にメモリ使用を意味のある総量を減じるケースは非常に少ないです。メモリのきついプレッシャー下で操作しているのでないならば、それらを使用する必要はないでしょう。
in-place 演算の適用可能性を制限する 2 つの主要な理由があります :
- in-place 演算は勾配を計算するために必要な値を潜在的に上書きすることができます。
- 総ての in-place 演算は実際に計算グラフを書き換える実装を必要とします。out-of-place バージョンは単純に新しいオブジェクトを割り当てて古いグラフへの参照を保持しますが、その一方で in-place 演算は、この演算を表わす関数 (Function) への総ての入力の作成者を変更する必要があります。これはトリッキーでありえて、特に同じストレージを参照する多くの Tensor がある場合にです、そしてもし変更された入力のストレージが任意の他の Tensor により参照された場合、 in-place 関数は実際にエラーをあげます。
in-place 正当性チェック
総ての tensor はバージョン・カウンターを保持します、これは任意の演算でそれが dirty とマークされるたびにインクリメントされます。関数 (Function) が backward のために任意の tensor をセーブするとき、それらが含む Tensor のバージョン・カウンターもまたセーブされます。ひとたび self.saved_tensors にアクセスすればそれがチェックされて、もしそれがセーブされた値よりも大きい場合にはエラーが上げられます。これは貴方が in-place 関数を使用している場合にどのようなエラーも見ないのであれば、計算された勾配は正しいに違いありません。
以上