【PyTorch】チュートリアル(日本語版 )② 〜AUTOGRAD〜

目次


1. 目的
2. AUTOGRADとは
3. AUTOGRADを体験


1. 目的

PyTorchのチュートリアルAutograd: Automatic Differentiationを参考にPyTorchでAUTOGRADの扱いになれること。

2. AUTOGRADとは

autogradパッケージは、PyTorchのニューラルネットワークの要です。

autogradパッケージによって、テンソル使ったあらゆる計算を自動的に微分することができます。
これはいわゆる、define-by-runフレームワーク(動的グラフ)というものに分類されます。
静的グラフと動的グラフの説明についてはこちらをご覧ください。
簡潔に言うと、入力するデータによってニューラルネットワーク構造を変化させることだそうです。
一方で、TensorFlowやTheanoといったフレームワークは、静的グラフであり計算グラフを事前に決めてから実行します。
PyTorchは、ニューラルネットワーク構造を定義する時点で固定する必要ななく、入力されたデータに対して例えば活性化関数を変えてネットワーク構造を変化させるため、柔軟な学習や推測が可能となります。

3. AUTOGRADを体験

ここらの話は難しいので手を動かしてAUTOGRADを感じてみます。

まずは、torchをimportします。

import torch

次に、テンソルを作りますがこのとき、requires_grad=Trueにしておきます。requires_grad=Trueにすることでこれからのテンソル計算をトレース(計算過程を記録)することができます。

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

tensor([[1., 1.],
[1., 1.]], requires_grad=True)

テンソルの足し算をしてみます。

print(y)

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

テンソル計算をした結果、yにgrad_fnができたことがわかります。

print(y.grad_fn)

>

さらに、yを使って計算していきます。
zはyの掛け算(multiply)で算出されたのでgrad_fnMulBackward0
outはzの平均(mean)で算出されたのでgrad_fnMeanBackward0となっている。

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

print(z, out)

tensor([[27., 27.],
[27., 27.]], grad_fn=) tensor(27., grad_fn=)

requires_gradのデフォルトはFalseですが、テンソルを定義するときにrequires_grad=Trueをしていなくても途中からTrueに変えてテンソル計算過程を記録することができます。

こちらは、.requires_grad_()で変更することができます。

a = torch.randn(2,2)
a = ((a * 3) / (a - 1))
print(a.requires_grad)

False

a.requires_grad_(True)

tensor([[ 1.5285, 1.8603],
[ 2.0531, -1.0013]], requires_grad=True)

print(a.requires_grad)

True

b = (a * a).sum()
print(b.grad_fn)

>

次に逆伝播してみます。

今、テンソルoutには一つのスカラーが格納されているのでout.backward()は、out.backward(torch.tensor(1.))と同じになります。
.backward()で微分対象を設定して、なにで微分するかを.gradで指定します。

ここでは、テンソルoutをxで微分(d(out)/dx)してみます。

print(out)

tensor(27., grad_fn=)

out.backward()
print(x)

tensor([[1., 1.],
[1., 1.]], requires_grad=True)

print(x.grad)

tensor([[4.5000, 4.5000],
[4.5000, 4.5000]])

実際に、手計算して考えてみる。
ここでテンソルoutをoとすると

torch.autogradの役割はベクトルーヤコビアンの積を計算することです。このベクトルーヤコビアンの積によって、スカラーを出力しないモデルに外部勾配を組み込みやすくなります。

ここで、ベクトルーヤコビアンの積の例を見てみます。
y.data.norm()yのL2ノルム(ユークリッドノルム)を返します。
以下の例では、yのL2ノルムが1000を超えるまでyを2倍し続けています。

x = torch.randn(3, requires_grad=True)
y = x * 2
while y.data.norm() < 1000:
	y = y * 2

print(y)

tensor([-0.6997, -0.0351, -5.1186], grad_fn=)

ここでyはスカラーではないので、torch.autogradではヤコビアンを直接的に計算することができません。

ですが、単にベクトルーヤコビアンの積の結果だけが欲しいので単純に.backward()メソッドを使ってやります。

v = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float)
y.backward(v)
print(x.grad)

tensor([2.0000e-01, 2.0000e+00, 2.0000e-04])

autogradを止めるには、with torch.no_grad():でテンソルをくくって.requires_gradをFalseにします。

print(x.requires_grad)

True

print((x ** 2).requires_grad)

True

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

False

あるいは、.detach()を使うことで、同じテンソルを新たに作ることができます。
ですが、require_gradFalseになります。

x.eq(y)は、各テンソルの各要素が同じ(equal)であるかをbool型で返します。
.allを最後に付け加えることで、すべての要素が同じであるかどうかをbool型で返します。

print(x.requires_grad)

True

y = x.detach()
print(y.requires_grad)

False

print(x.eq(y).all())

tensor(True)

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください