1. 目的
2. 前準備
3. PyTorchのインポート
4. モデルの定義
5. 使用するデータ
6. ニューラルネットワークのモデルを構築
7. 損失関数の定義
8. 最適化関数の定義
9. 学習回数
10. モデルへのデータ入出力 (Forward pass)
11. 損失(loss)の計算
12. 勾配の初期化
13. 勾配の計算
14. 実行
14.1. 8_class_model.py
15. 終わりに
1. 目的
このチュートリアルに至るまでは、ニューラルネットワークモデルの定義を積み木を積み重ねるように単純なシーケンスtorch.nn.Sequential
で構築していました。
このtorch.nn.Sequential
を用いた方法は、モデルの定義が簡単である反面、ネットワーク構造も簡素なものしか作ることができません。
例えば、torch.nn.Sequential
では、ResNetネットワーク構造を構築することがきません。
(Credit:Deep Residual Learning for Image Recognition. Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun. arXiv:1512.03385 [cs.CV]
(or arXiv:1512.03385v1 [cs.CV] for this version) )
このチュートリアルでは、PyTorch: Custom nn Modulesを参考に、より複雑なニューラルネットワークのモデルが構築できる方法を紹介します。
2. 前準備
PyTorchのインストールはこちらから。
初めて、Google Colaboratoryを使いたい方は、こちらをご覧ください。
3. PyTorchのインポート
import torch
4. モデルの定義
これまでは、レイヤ(層)を積み重ねるようにして、ニューラルネットワークモデルを定義していましたが、今回はネットワークモデルをクラスを使って定義します。クラスについては、こちらが参考になりました。
簡単のために、線形結合が2層のネットワークを構築していきます。
クラスの名前をTwoLayerNet
とします。引数torch.nn.Module
はお決まりです。
class TwoLayerNet(torch.nn.Module):
コンストラクタで2層の線形結合層をインスタンス化します。
コンストラクタとインスタンスについては、こちらが参考になりました。
def __init__(self, D_in, H, D_out): super(TwoLayerNet, self).__init__() self.linear1 = torch.nn.Linear(D_in, H) self.linear2 = torch.nn.Linear(H, D_out)
コンストラクタで定義された線形結合層をつかってモデルの予測値y_pred
を計算します。
テンソルの演算式は、forward
オブジェクトで自由に定義できます。
def forward(self, x): h_relu = self.linear1(x).clamp(min=0) y_pred = self.linear2(h_relu) return y_pred
5. 使用するデータ
バッチサイズ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
を乱数で定義します。
# Create random input and output data x = torch.randn(N, D_in) y = torch.randn(N, D_out)
6. ニューラルネットワークのモデルを構築
先程作成したニューラルネットワークモデルのクラスTwoLayerNet
をつかってモデルを定義します。
model = TwoLayerNet(D_in, H, D_out)
7. 損失関数の定義
二乗誤差をこのモデルの損失関数とします。
reduction
のデフォルトはmean
ですので、何も指定しなければtorch.nn.MSELoss
は平均二乗誤差を返します。
reduction=sum
とした場合は、累積二乗誤差を算出します。
criterion = torch.nn.MSELoss(reduction='sum')
8. 最適化関数の定義
optim
パッケージを使って最適化関数として確率勾配降下法(SGD: stochastic gradient descent)を定義します。
lr
は学習率です。
optimizer = torch.optim.SGD(model.parameters(), lr=1e-4)
9. 学習回数
学習回数は500回にします。
for t in range(500):
10. モデルへのデータ入出力 (Forward pass)
定義したニューラルネットワークモデルmodel
へデータx
を入力し、予測値y_pred
を取得します。
y_pred = model(x)
11. 損失(loss)の計算
定義した損失関数SGD
で予測値y_pred
と真値y
との間の損失を計算します。
loss = criterion(y_pred, y) if t % 100 == 99: print(t, loss.item())
12. 勾配の初期化
逆伝播(backward)させる前に、モデルのパラメータが持つ勾配を0(ゼロ)で初期化します。
optimizer.zero_grad()
13. 勾配の計算
backward
メソッドでモデルパラメータ(Weight)の勾配を算出します。
loss.backward()
パラメータ(Weight)の更新
step
メソッドでモデルのパラメータを更新します。
optimizer.step()
14. 実行
以下のコードを8_class_model.py
として保存します。
14.1. 8_class_model.py
import torch class TwoLayerNet(torch.nn.Module): def __init__(self, D_in, H, D_out): super(TwoLayerNet, self).__init__() self.linear1 = torch.nn.Linear(D_in, H) self.linear2 = torch.nn.Linear(H, D_out) def forward(self, x): h_relu = self.linear1(x).clamp(min=0) y_pred = self.linear2(h_relu) return y_pred # 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 inputs and outputs x = torch.randn(N, D_in) y = torch.randn(N, D_out) # Construct our model by instantiating the class defined above model = TwoLayerNet(D_in, H, D_out) # Construct our loss function and an Optimizer. criterion = torch.nn.MSELoss(reduction='sum') optimizer = torch.optim.SGD(model.parameters(), lr=1e-4) for t in range(500): # Forward pass: Compute predicted y by passing x to the model y_pred = model(x) # Compute and print loss loss = criterion(y_pred, y) if t % 100 == 99: print(t, loss.item()) # Zero gradients, perform a backward pass, and update the weights. optimizer.zero_grad() loss.backward() optimizer.step()
コードを保存したら、実行してみましょう。
In:
python3 8_class_model.py
Out:
99 2.5070412158966064 199 0.04455046355724335 299 0.0011508199386298656 399 3.597284376155585e-05 499 1.361027443635976e-06
左の数字が学習回数、右の数値がパーセプトロンの推定値と実際の答えと二乗誤差です。
学習を重ねるごとに、二乗誤差が小さくなることがわかります。
15. 終わりに
今回は、クラスを使ってニューラルネットワークモデルを定義しました。
より複雑なモデルを構築する場合には、コンストラクタに線形結合層、畳み込み層、プーリング層などのコンポーネントを増やし、それらをforward
オブジェクトで、自由に組み替えてみてください。