1. 目的
2. 前準備
3. TENSOR(テンソル)
4. PyTorchのインポート
5. データタイプとデバイスの選択
6. 使用するデータ
7. 重み付けの初期化
8. 学習
9. データの入力
10. 損失の計算
11. 重み(Weight)の勾配計算
12. 重みの更新
13. 実行
13.1. 2_tensor.py
### 1. 目的
PyTorchのチュートリアルPyTorch: Tensorsを参考にPyTorch Tensor(テンソル)を使って、損失(loss)や重み(weight)の計算をする。
PyTorchの特徴の一つである、テンソルとNumPyの違いを手を動かしながら感じる。
NumPyを用いた例は、こちらから。
2. 前準備
PyTorchのインストールはこちらから。
初めて、Google Colaboratoryを使いたい方は、こちらをご覧ください。
3. TENSOR(テンソル)
PyTorchのtensor(テンソル)は、基本的にはnumpy配列と同じです。
しかし、PyTorchのテンソルは、deep learning(深層学習)や計算グラフ、勾配といった概念に合わせた配列です。
PyTorchテンソルだけがCPUとGPUのどちらでも計算が実行でき、これが、numpy配列とPyTorchテンソルの最も大きな違いです。
4. PyTorchのインポート
1 | import torch |
5. データタイプとデバイスの選択
これから作成するテンソルのデータ型dtype
をfloat
にします。
テンソル計算をするデバイスは、torch.device
で指定することができます。
今回は、CPUを使用することにします。
1 2 | dtype = torch. float device = torch.device( "cpu" ) |
GPUを使う方は、device
の部分を以下のコードに変えて下さい。
1 | device = torch.device( "cuda:0" ) # Uncomment this to run on GPU |
6. 使用するデータ
バッチサイズNを64、入力の次元D_inを1000、隠れ層の次元Hを100、出力の次元D_outを10とします。
1 2 3 | # 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
かを指定することができます。
1 2 3 | # 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. 重み付けの初期化
乱数を使って重みを初期化します。
1 2 3 | # Randomly initialize weights w1 = torch.randn(D_in, H, device = device, dtype = dtype) w2 = torch.randn(H, D_out, device = device, dtype = dtype) |
8. 学習
学習率を1e-6
として、学習回数を500回とします。
1 2 | learning_rate = 1e - 6 for t in range ( 500 ): |
9. データの入力
二次元テンソルの入力(x)と重み(w1)をmm
で掛け算することで重み付けをします(h)。(一次元テンソルの積は、dot
で計算できます。)
重み付けした値(h)の要素から、clamp(min=~0)
で、0以上のものは残し、0以下のものは0とします。numpyでは、numpy.maximum(h,0)
と書きます。
最後に、重み(w2)を掛け合わせて重み付けしますmm(w2)
。
この値がパーセプトロンの予測値(y_pred)となります。
1 2 3 4 | # Forward pass: compute predicted y h = x.mm(w1) h_relu = h.clamp( min = 0 ) y_pred = h_relu.mm(w2) |
10. 損失の計算
パーセプトロンが予測した値(y_pred)と答え(y)との間の二乗誤差を計算しこれを損失(loss)とします。
numpyでは、二乗計算をnumpy.square
で実行していましたが、PyTorchテンソルでの二乗計算はpow(2)
と記述します。
損失の値を、tensor配列からスカラー値で取得したい場合には、item()
メソッドを用います。
各学習回数ごとに、学習回数(t)と二乗誤差(loss)を表示します。
今回は、結果を見やすくするためにif t % 100 == 99:
の部分で、学習回数100回ごとに結果を出力します。
やっていることは、学習回数(t)を100で割ったときのあまりが99であるときにprint(t, loss)
を実行です。
1 2 3 4 | # Compute and print loss loss = (y_pred - y). pow ( 2 ). sum ().item() if t % 100 = = 99 : print (t, loss) |
11. 重み(Weight)の勾配計算
これより先は、パーセプトロンが予測した値(y_pred)と答え(y)を見比べて、正しく答え(y)を予測できるようにパーセプトロンのパラメータを更新していきます。
まず、重み(w1, w2)の勾配(grad_w1, grad_w2)を計算します。
numpyと違う点は、表のとおりです。
PyTorch | NumPy | |
---|---|---|
配列の転置 | .t() | .T |
二次元配列の掛け算 | .mm() | .dot() |
配列のコピー | .clone() | .copy() |
1 2 3 4 5 6 | grad_y_pred = 2.0 (y_pred - y) grad_w2 = h_relu.t().mm(grad_y_pred) grad_h_relu = grad_y_pred.mm(w2.t()) grad_h = grad_h_relu.clone() grad_h[h < 0 ] = 0 grad_w1 = x.t().mm(grad_h) |
12. 重みの更新
計算した勾配(grad_w1, grad_w2)をもとに、重み(w1, w2)を更新します。
確率勾配降下法(SGD: stochastic gradient descent)は、重みを更新する上でよく使われる最適化アルゴリズムで、以下の式で表されます。
weight = weight - learning_rate gradient
SGDは、以下のコードで実行できます。
ここの部分は、numpyもPyTorchテンソルも同じコードです。
1 2 3 | # Update weights using gradient descent w1 - = learning_rate grad_w1 w2 - = learning_rate grad_w2 |
13. 実行
以下のコードを2_tensor.py
として保存します。
13.1. 2_tensor.py
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | 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 input and output data x = torch.randn(N, D_in, device = device, dtype = dtype) y = torch.randn(N, D_out, device = device, dtype = dtype) # Randomly initialize weights w1 = torch.randn(D_in, H, device = device, dtype = dtype) w2 = torch.randn(H, D_out, device = device, dtype = dtype) learning_rate = 1e - 6 for t in range ( 500 ): # Forward pass: compute predicted y h = x.mm(w1) h_relu = h.clamp( min = 0 ) y_pred = h_relu.mm(w2) # Compute and print loss loss = (y_pred - y). pow ( 2 ). sum ().item() if t % 100 = = 99 : print (t, loss) # Backprop to compute gradients of w1 and w2 with respect to loss grad_y_pred = 2.0 (y_pred - y) grad_w2 = h_relu.t().mm(grad_y_pred) grad_h_relu = grad_y_pred.mm(w2.t()) grad_h = grad_h_relu.clone() grad_h[h < 0 ] = 0 grad_w1 = x.t().mm(grad_h) # Update weights using gradient descent w1 - = learning_rate grad_w1 w2 - = learning_rate grad_w2 |
保存ができたら実行しましょう。
左の数字が学習回数、右の数値がパーセプトロンの推定値と実際の答えと二乗誤差です。
学習を重ねるごとに、二乗誤差が小さくなることがわかります。
1 2 3 4 5 6 | $ python3 2_tensor .py 99 306.79400634765625 199 0.4559670686721802 299 0.0014809096464887261 399 6.634114834014326e - 05 499 1.7021899111568928e - 05 |
ピングバック: 【PyTorch】サンプル③ 〜TENSORS AND AUTOGRAD(テンソルと自動微分)〜