【初心者向け】基礎&実践プログラミング

初心者がつまづきやすいところ、最短で実力が身につく方法をお伝えします。

【PyTorch】サンプル⑧ 〜 複雑なモデルの構築方法 〜

f:id:AIProgrammer:20200413020244p:plain

目的

このチュートリアルに至るまでは、ニューラルネットワークモデルの定義を積み木を積み重ねるように単純なシーケンスtorch.nn.Sequentialで構築していました。

このtorch.nn.Sequentialを用いた方法は、モデルの定義が簡単である反面、ネットワーク構造も簡素なものしか作ることができません。

例えば、torch.nn.Sequentialでは、ResNetネットワーク構造を構築することがきません。 f:id:AIProgrammer:20200501211004p:plain (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を参考に、より複雑なニューラルネットワークのモデルが構築できる方法を紹介します。

前準備

PyTorchのインストールはこちらから。

初めて、Google Colaboratoryを使いたい方は、こちらをご覧ください。

コマンドラインの「>>>」の行がPythonで実行するコマンドです。 それ以外の行は、コマンドの実行結果です。

>>> print("PyTorch")    # コマンドラインに打ち込む
PyTorch    # 出力結果

関連記事

チュートリアル

サンプル

PyTorchのインポート

import torch

モデルの定義

これまでは、レイヤ(層)を積み重ねるようにして、ニューラルネットワークモデルを定義していましたが、今回はネットワークモデルをクラスを使って定義します。クラスについては、こちらが参考になりました。

簡単のために、線形結合が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

使用するデータ

バッチサイズ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)

ニューラルネットワークのモデルを構築

先程作成したニューラルネットワークモデルのクラスTwoLayerNetをつかってモデルを定義します。

model = TwoLayerNet(D_in, H, D_out)

損失関数の定義

二乗誤差をこのモデルの損失関数とします。

reductionのデフォルトはmeanですので、何も指定しなければtorch.nn.MSELossは平均二乗誤差を返します。

reduction=sumとした場合は、累積二乗誤差を算出します。

criterion = torch.nn.MSELoss(reduction='sum')

最適化関数の定義

optimパッケージを使って最適化関数として確率勾配降下法(SGD: stochastic gradient descent)を定義します。

lrは学習率です。

optimizer = torch.optim.SGD(model.parameters(), lr=1e-4)

学習回数

学習回数は500回にします。

for t in range(500):

モデルへのデータ入出力 (Forward pass)

定義したニューラルネットワークモデルmodelへデータxを入力し、予測値y_predを取得します。

    y_pred = model(x)

損失(loss)の計算

定義した損失関数SGDで予測値y_predと真値yとの間の損失を計算します。

    loss = criterion(y_pred, y)
    if t % 100 == 99:
        print(t, loss.item())

勾配の初期化

逆伝播(backward)させる前に、モデルのパラメータが持つ勾配を0(ゼロ)で初期化します。

    optimizer.zero_grad()

勾配の計算

backwardメソッドでモデルパラメータ(Weight)の勾配を算出します。

    loss.backward()

パラメータ(Weight)の更新

stepメソッドでモデルのパラメータを更新します。

    optimizer.step()

実行

以下のコードを8_class_model.pyとして保存します。

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()

コードを保存したら、実行してみましょう。

$ python3 8_class_model.py 
99 2.5070412158966064
199 0.04455046355724335
299 0.0011508199386298656
399 3.597284376155585e-05
499 1.361027443635976e-06

左の数字が学習回数、右の数値がパーセプトロンの推定値と実際の答えと二乗誤差です。

学習を重ねるごとに、二乗誤差が小さくなることがわかります。

終わりに

今回は、クラスを使ってニューラルネットワークモデルを定義しました。

より複雑なモデルを構築する場合には、コンストラクタに線形結合層、畳み込み層、プーリング層などのコンポーネントを増やし、それらをforwardオブジェクトで、自由に組み替えてみてください。



頑張れ!喝!!の代わりにB!ブックマークを押していただけるとただただうれしいです(^^)! ↓