1. 目的
2. 前準備
3. 自動微分(AUTOGRAD)
4. PyTorchのインポート
5. データタイプとデバイスの選択
6. 使用するデータ
7. 重み付けの初期化
8. 学習
9. データの入力
10. 損失の計算
11. 重み(Weight)の勾配計算
12. 重みの更新
13. 実行
13.1. 3_autograd.py
1. 目的
PyTorchのチュートリアルPyTorch: Tensors and autogradを参考にPyTorchテンソル(tensor)と自動微分(autograd)を使って、損失(loss)や重み(weight)の計算をする。
これまでは、PyTorchに実装されている自動微分機能を使わずにニューラルネットワークのパラメータの勾配を計算していましたが、PyTorchの自動微分(autograd)機能を使うとパラメータの勾配計算を簡単にすることができます。
2. 前準備
PyTorchのインストールはこちらから。
初めて、Google Colaboratoryを使いたい方は、こちらをご覧ください。
3. 自動微分(AUTOGRAD)
PyTorchにおけるテンソルは計算グラフでは、ノード(node)と表現されます。
例えば、テンソルx
にx.requires_grad=True
とフラグを設定すると、x.grad
でxの勾配を計算することができます。
4. PyTorchのインポート
import torch
5. データタイプとデバイスの選択
これから作成するテンソルのデータ型dtype
をfloat
にします。
テンソル計算をするデバイスは、torch.device
で指定することができます。
今回は、CPUを使用することにします。
dtype = torch.float device = torch.device("cpu")
GPUを使う方は、device
の部分を以下のコードに変えて下さい。
device = torch.device("cuda:0") # Uncomment this to run on GPU
6. 使用するデータ
バッチサイズNを64、入力の次元D_inを1000、隠れ層の次元Hを100、出力の次元D_outを10とします。
# N is batch size; D_in is input dimension; # H is hidden dimension; D_out is output dimension. N, D_in, H, D_out = 64, 1000, 100, 10
入力(x)と予測したい(y)を乱数で定義します。
PyTorchテンソルを定義する場合には、どのデバイスでdevice
、どのデータ型dtype
かを指定することができます。
# Create random input and output data x = torch.randn(N, D_in, device=device, dtype=dtype) y = torch.randn(N, D_out, device=device, dtype=dtype)
7. 重み付けの初期化
乱数を使って重みを初期化します。
注目してほしい点は、requires_grad=True
です。
自動微分をしたい場合には、初期化する時点でrequires_grad
のフラグをTrue
にしておきます。デフォルトはrequires_grad=False
です。
# Randomly initialize weights w1 = torch.randn(D_in, H, device=device, dtype=dtype, requires_grad=True) w2 = torch.randn(H, D_out, device=device, dtype=dtype, requires_grad=True)
8. 学習
学習率を1e-6
として、学習回数を500回とします。
learning_rate = 1e-6 for t in range(500):
9. データの入力
二次元テンソルの入力(x)と重み(w1)をmm
で掛け算することで重み付けをします(h)。(一次元テンソルの積は、dot
で計算できます。)
重み付けした値の要素から、clamp(min=~0)
で、0以上の要素は残し、0以下のものは0とします。
最後に、重み(w2)を掛け合わせて重み付けしますmm(w2)
。
この値がパーセプトロンの予測値(y_pred)となります。
# Forward pass: compute predicted y y_pred = x.mm(w1).clamp(min=0).mm(w2)
10. 損失の計算
パーセプトロンが予測した値(y_pred)と答え(y)との間の二乗誤差を計算しこれを損失(loss)とします。
損失の値を、tensor配列からスカラー値で取得したい場合には、item()
メソッドを用います。
各学習回数ごとに、学習回数(t)と二乗誤差(loss)を表示します。
今回は、結果を見やすくするためにif t % 100 == 99:
の部分で、学習回数100回ごとに結果を出力します。
やっていることは、学習回数(t)を100で割ったときのあまりが99であるときにprint(t, loss)
を実行です。
# Compute and print loss loss = (y_pred - y).pow(2).sum() if t % 100 == 99: print(t, loss.item())
11. 重み(Weight)の勾配計算
これより先は、パーセプトロンが予測した値(y_pred)と答え(y)を見比べて、正しく答え(y)を予測できるようにパーセプトロンのパラメータを更新していきます。
NumPyを用いたサンプルやPyTorchを用いたサンプルでは、ガリガリ勾配の計算式を書いていましたが、自動微分を使えば、一行で勾配を計算できます。
loss.backward()
12. 重みの更新
計算した勾配(grad_w1, grad_w2)をもとに、重み(w1, w2)を更新します。自動微分を用いた場合のパラメータの更新は、torch.no_grad()
で対象のパラメータをくくることで計算できます。
確率勾配降下法(SGD: stochastic gradient descent)は、重みを更新する上でよく使われる最適化アルゴリズムで、以下の式で表されます。
weight = weight - learning_rate gradient
SGDを用いてパラメータを更新するには、このように記述します。
一度更新した、パラメータはgrad.zero()
でゼロに初期化します。
with torch.no_grad(): w1 -= learning_rate w1.grad w2 -= learning_rate w2.grad # Manually zero the gradients after updating weights w1.grad.zero_() w2.grad.zero_()
13. 実行
以下のコードを3_autograd.py
として保存します。
13.1. 3_autograd.py
import torch dtype = torch.float device = torch.device("cpu") # device = torch.device("cuda:0") # Uncomment this to run on GPU # N is batch size; D_in is input dimension; # H is hidden dimension; D_out is output dimension. N, D_in, H, D_out = 64, 1000, 100, 10 # Create random Tensors to hold input and outputs. x = torch.randn(N, D_in, device=device, dtype=dtype) y = torch.randn(N, D_out, device=device, dtype=dtype) # Create random Tensors for weights. w1 = torch.randn(D_in, H, device=device, dtype=dtype, requires_grad=True) w2 = torch.randn(H, D_out, device=device, dtype=dtype, requires_grad=True) learning_rate = 1e-6 for t in range(500): # Forward pass: compute predicted y using operations on Tensors y_pred = x.mm(w1).clamp(min=0).mm(w2) # Compute and print loss using operations on Tensors. loss = (y_pred - y).pow(2).sum() if t % 100 == 99: print(t, loss.item()) # Use autograd to compute the backward pass. loss.backward() # Manually update weights using gradient descent. Wrap in torch.no_grad() with torch.no_grad(): w1 -= learning_rate w1.grad w2 -= learning_rate w2.grad # Manually zero the gradients after updating weights w1.grad.zero_() w2.grad.zero_()
保存ができたら実行しましょう。
左の数字が学習回数、右の数値がパーセプトロンの推定値と実際の答えと二乗誤差です。
学習を重ねるごとに、二乗誤差が小さくなることがわかります。
$ python3 3_autograd.py 99 743.60400390625 199 7.154838562011719 299 0.13969427347183228 399 0.0036201069597154856 499 0.000234781633480452
ピングバック: 【PyTorch】サンプル④ 〜Defining New autograd Functions(自動微分関数の定義)〜