PyTorch : Tutorial 初級 : Autograd: 自動微分

PyTorch : Tutorial 初級 : Autograd: 自動微分 (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
更新日時 : 07/23/2018 (0.4.0), 04/19/2018 (0.3.1.post2), 11/28/2017
作成日時 : 04/14/2017

* 0.4.0 に対応するために更新しました。
* 本ページは、PyTorch Tutorials の Autograd: automatic differentiation を動作確認・翻訳した上で適宜、補足説明したものです:

* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。

 

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

$autograd$ パッケージはテンソル上の全ての演算に対して自動微分を提供します。それは 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 のテンソルである $gradient$ 引数を指定する必要があります。

 

import torch

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

x = torch.ones(2, 2, requires_grad=True)
print(x)

Out:

tensor([[ 1.,  1.],
        [ 1.,  1.]])

tensor の演算を行ないます :

y = x + 2
print(y)

Out:

tensor([[ 3.,  3.],
        [ 3.,  3.]])

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

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

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

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

print(z, out)
tensor([[ 27.,  27.],
        [ 27.,  27.]]) tensor(27.)

$.requires\_grad_( … )$ は既存の Tensor の $requires\_grad$ フラグを in-place で変更します。入力フラグが与えられない場合には True がデフォルトです。

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 0x7f2bd44b6588>

 

勾配

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

out.backward()

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

print(x.grad)

Out:

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([ 1343.8188,  -530.4122,   592.2161])
gradients = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float)
y.backward(gradients)

print(x.grad)
tensor([  51.2000,  512.0000,    0.0512])

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:

Documentation of Variable and Function is at http://pytorch.org/docs/autograd

 
以上