PyTorch 1.0 : Getting Started : Autograd: 自動微分

PyTorch 1.0 : Getting Started : Autograd: 自動微分 (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 12/07/2018 (1.0.0.dev20181128)

* 本ページは、PyTorch 1.0 Tutorials の Autograd: Automatic Differentiation を翻訳した上で適宜、補足説明したものです:

* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。

 

Autograd: 自動微分

PyTorch で総てのニューラルネットワークの中核をなすものは autograd パッケージです。最初に簡単にこれを見てましょう、そしてそれから最初のニューラルネットワークの訓練へと進みます。

autograd パッケージは Tensor 上の全ての演算に対して自動微分を提供します。それは define-by-run フレームワークで、これはどのようにコードが実行されるかによって backprop が定義されてそして総ての単一の iteration が異なることを意味します。

これを幾つかのサンプルでより単純な用語で見てみましょう。

 

Tensor

torch.Tensor はパッケージの中心的なクラスです。その属性 .requires_grad を True に設定すると、それはそれ上の総ての演算を追跡し始めます。計算を終了するとき .backward() を呼び出して総ての勾配を自動的に計算させることが可能です。この tensor のための勾配は .grad 属性に累積されます。

履歴の追跡から tensor を停止するために、計算履歴からそれをデタッチして将来の計算が追跡されることを回避するために .detach() を呼び出すことができます。

履歴の追跡 (そしてメモリ使用) を回避するために、コードブロックを with torch.no_grad(): 内にラップすることもできます。これはモデルを評価するときに特に有用です、何故ならばそのモデルは requires_grad=True を持つ訓練可能なパラメータを持つかもしれませんが、そのためには (訳注: モデル評価のためには) 勾配は必要ありません。

autograd 実装に対して非常に重要なもう一つのクラスがあります – Function です。

Tensor と Function は相互接続され非巡回グラフを構築します、これは計算の完全な履歴をエンコードします。各 Tensor は .grad_fn 属性を持ち、これは Tensor を作成した Function を参照します (ユーザにより作成された Tensor は除きます – それらの grad_fn is None です)。

導関数を計算することを望むのであれば、Tensor 上で .backward() を呼び出すことができます。もし Tensor がスカラーである (i.e. それが一つの要素データを保持する) ならば、backward() にどのような引数も指定する必要はありません、けれどもさらに要素を持つならば、適合する shape の tensor である gradient 引数を指定する必要があります。

import torch

tensor を作成してそれによる計算を追跡するために requires_grad=True を設定します。

x = torch.ones(2, 2, requires_grad=True)
print(x)
tensor([[1., 1.],
        [1., 1.]], requires_grad=True)

tensor の演算を行ないます :

y = x + 2
print(y)
tensor([[3., 3.],
        [3., 3.]], grad_fn=)

y は演算の結果として作成されましたので、grad_fn を持ちます。

print(y.grad_fn)
<AddBackward0 object at 0x7f82bad9f438>

y 上で更に演算を行ないます。

z = y * y * 3
out = z.mean()

print(z, out)
tensor([[27., 27.],
        [27., 27.]], grad_fn=<MulBackward0>) tensor(27., grad_fn=<MeanBackward1>)

.requires_grad_( … ) は既存の Tensor の requires_grad フラグを in-place で変更します。入力フラグが与えられない場合には False にデフォルト設定されます。

a = torch.randn(2, 2)
a = ((a * 3) / (a - 1))
print(a.requires_grad)
a.requires_grad_(True)
print(a.requires_grad)
b = (a * a).sum()
print(b.grad_fn)
False
True
<SumBackward0 object at 0x7f833e0d9940>

 

勾配

さて backprop を行ないましょう、out は単一のスカラーを含むので、out.backward() は out.backward(torch.Tensor(1)) と同値です。

out.backward()

勾配 d(out)/dx をプリントします。

print(x.grad)
tensor([[4.5000, 4.5000],
        [4.5000, 4.5000]])

4.5 の行列を得たはずです。out Tensor を “$o$” と呼称しましょう。$o = \frac{1}{4}\sum_iz_i$, $z_i = 3(x_i + 2)^2$ そして $z_i\mid_{x_i=1}=27$ を持ちますので、従って $\frac{\partial o}{\partial x_i} = \frac{3}{2}(x_i + 2)$ 更に $\frac{\partial o}{\partial x_i}\mid_{x_i=1} = \frac{9}{2} = 4.5$ となります。

You can do many crazy things with autograd!

x = torch.randn(3, requires_grad=True)

y = x * 2
while y.data.norm() < 1000:
    y = y * 2

print(y)
tensor([-1178.9551,  1202.9015,   293.6342], grad_fn=<MulBackward0>)
gradients = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float)
y.backward(gradients)

print(x.grad)
tensor([1.0240e+02, 1.0240e+03, 1.0240e-01])

with torch.no_grad(): 内にコードブロックをラッピングすることにより .requires_grad = True を持つ Tensor 上の履歴を追跡することから autograd を停止することもできます。

print(x.requires_grad)
print((x ** 2).requires_grad)

with torch.no_grad():
    print((x ** 2).requires_grad)
True
True
False

 
[Read Later]

autograd and Function のドキュメントは https://pytorch.org/docs/autograd です。

 
以上