計算グラフを勉強してなんとなく自動微分がわかりそうな気がします。
理論的な基礎がないとチュートリアルも難しいね。
前回、計算グラフを勉強しました。計算グラフを勉強したことで、PyTorchのautogradがなんとなく、何をしたいのかがわかってきました。チュートリアルの最後の方はヤコビ行列など、数学的なお話も混ざっているのですが、このチュートリアルで重要なことは、「入力した値に対して素早く勾配を計算できること」というような気がします。autogradというモジュールがTensorモジュールと同じようにPyTorchのコアであり、ニューラルネットワークを構築するのに最適な環境を提供してくれる、という理解に落ち着きました。
ということで、チュートリアルのプログラムを実行しつつ、備忘録を綴りたいと思います。
autogradの理解のためには、計算グラフという概念について知っておいたほうが良いです。こちらの記事もご参考ください。
PyTorchのチュートリアルはこちらです。
こんな人の役にたつかも
・機械学習プログラミングを勉強したい人
・PyTorchのチュートリアルに取り組んでいる人
・PyTorchのautogradモジュールについてふんわりと知りたい人
autograd
autogradという機能は、PyTorchでもコアな部分、実際には、計算グラフの自動微分という概念をプログラムで実装したようなものになっています。
すごく簡単にまとめると、
「入力データの計算を記録して、計算グラフを構築しておき、素早く勾配を求めることができる」
機能です。
autogradを利用してみる
import torch
x = torch.ones(2, 2, requires_grad=True)
print(x)
テンソルxへのス●ーカーみたいなイメージでしょうか。
しつこい感じのやつですね。
チュートリアルでは、行列をxとして準備しています。required_gradもTrueになっていると表示されています。
tensor([[1., 1.],
[1., 1.]], requires_grad=True)
チュートリアルでは、テンソル(行列)の形のサンプルですが、普通の数値計算の場合もスカラーとしてtensorで作成します。PyTorchでは、tensorが基本になります。また、autogradもtensorモジュールに対してオンオフするので、基本はtensorを利用して計算をしていきます。
テンソルでスカラーを作成した様子です。
x_scalar = torch.tensor(3.0 , requires_grad=True)
print(x_scalar)
tensor(3., requires_grad=True)
チュートリアルでは次に、テンソルxを元に演算を行っていきます。
y = x + 2
print(y)
tensor([[3., 3.],
[3., 3.]], grad_fn=<AddBackward0>)
Add、加算が記録されましたということですね。
計算はgrad_fnという所に記録されていくようです。
print(y.grad_fn)
<AddBackward0 object at 0x7f339d8252b0>
さらにyに対して計算を進めています。zという新しい変数と、outという新しい変数が出てきます。最終的な出力は「out」から出力されるスカラーとなります。
z = y * y * 3
out = z.mean()
print(z)
print(out)
tensor([[27., 27.],
[27., 27.]], grad_fn=<MulBackward0>)
tensor(27., grad_fn=<MeanBackward0>)
zのgrad_fn、outのgrad_fnにそれぞれ計算が記録されていきました。
autogradのオンオフ
自分でtensorを作成するときに、「requires_grad=True」を指定しておかないと、計算が記録されていないことになります。
プログラムの途中でrequired_gradをtrueにするには、「a.required_grad_(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 0x7f339e8fb860>
勾配を求める
計算グラフでいう、出力「out」からバックワード微分を行うのが「.backword()」という機能のようです。
次のようにして、バックワード微分を実行します。
out.backward()
計算の勾配が求められたので、次のようにして、確認したい勾配を出力できます。 xのoutに対する勾配「∂out/∂x」は「x.grad」のように確認できます。
print(x.grad)
tensor([[4.5000, 4.5000],
[4.5000, 4.5000]])
outに対するxの勾配を素早く計算することができます。
バックプロパゲーションでは、このように求めた勾配に学習係数をかけたもので重みを変化させて、勾配が最小の値となるような重みを探します。そのため、たくさんの勾配計算をすることになるので、このように素早く微分計算(勾配を求める計算)ができることが重要なようです。