【Pytorch】モデルの構築・学習を行うプログラム【全結合層】

スポンサーリンク

【Pytorch】モデルの構築・学習を行うプログラム【全結合層】

Pytorchで全結合層で学習するモデルを実装するプログラムをまとめる。

nn.Moduleをベースに実装していく。

できるだけnnライブラリを使わず自力で実装していくパターン。

relu関数とsoftmax関数の実装

まずrelu関数とsoftmax関数を実装する。

def relu(x):
    x = torch.where(x > 0, x, torch.zeros_like(x))
    return x


def softmax(x):
    x -= torch.cat([x.max(axis=1, keepdim=True).values] * x.size()[1], dim=1)
    x_exp = torch.exp(x)
    return x_exp/torch.cat([x_exp.sum(dim=1, keepdim=True)] * x.size()[1], dim=1)

全結合層の実装(Dense)

次に全結合層を実装する。

ここではnn.Moduleを継承する。

Heの初期値を使う。

class Dense(nn.Module):  # nn.Moduleを継承する
    def __init__(self, in_dim, out_dim, function=lambda x: x):
        super().__init__()
        # He Initialization
        # in_dim: 入力の次元数、out_dim: 出力の次元数
        self.W = nn.Parameter(torch.tensor(rng.uniform(
                        low=-np.sqrt(6/in_dim),
                        high=np.sqrt(6/in_dim),
                        size=(in_dim, out_dim)
                    ).astype('float32')))
        self.b = nn.Parameter(torch.tensor(np.zeros([out_dim]).astype('float32')))
        self.function = function

    def forward(self, x):  # forwardをoverride
        return self.function(torch.matmul(x, self.W) + self.b)

Sequentialで複数層のネットワークを定義する

nnにはSequentialが用意されており、これを使うことであらかじめ定義したレイヤーを重ねて多層ネットワークを定義することができる。

mlp = nn.Sequential(
    Dense(2, 3, relu),  # 自分て定義した全結合層を重ねて2層ネットワークを定義する
    Dense(3, 2, softmax)
)

# mlp = MLP(2, 3, 2) でも同様のネットワークを定義できる

print(mlp)
print()

x = torch.Tensor([[0, 0], [0, 1], [1, 0], [1, 1]])
y = mlp(x)  # forward(x)が呼ばれる
print("feedforward:")
print(y)
print()

print("mlp.parameters()でモデルのパラメータ取得:")
print(mlp.parameters())

# 出力
# Sequential(
#   (0): Dense()
#   (1): Dense()
# )

# feedforward:
# tensor([[0.5000, 0.5000],
#         [0.2238, 0.7762],
#         [0.5246, 0.4754],
#         [0.5803, 0.4197]], grad_fn=<DivBackward0>)
# 
# mlp.parameters()でモデルのパラメータ取得:
# <generator object Module.parameters at 0x7f5f9f6d1c50>

optimizerの定義(最適化)

torch.optimに一般的なoptimizerが実装されている。

勾配のリセットは.zero_grad()で、パラメータの更新は.step()で行う。

# optimizerの定義
optimizer = optim.SGD([W1, W2], lr=0.1)

# 勾配のリセット
optimizer.zero_grad()

# パラメータの更新
optimizer.step()
スポンサーリンク

モデルの学習(XOR)

実際にMLPのモデルを学習させる。

今回はXORを学習させてみる。

# XORをMLPで行う
x = torch.tensor([[0, 0], [0, 1], [1, 0], [1, 1]], dtype=torch.float)
t = torch.tensor([0, 1, 1, 0], dtype=torch.long)

# モデルの定義
mlp = MLP(2, 3, 2)

# 最適化の定義
optimizer = optim.SGD(mlp.parameters(), lr=0.1)  # Moduleのパラメータは.parameters()で取得できる

# モデルを訓練モードにする(Dropout等に関係)
mlp.train()

for i in range(1000):

    t_hot = torch.eye(2)[t]  # 正解ラベルをone-hot vector化

    # 順伝播
    y_pred = mlp(x)

    # 誤差の計算(クロスエントロピー誤差関数)
    loss = -(t_hot*torch.log(y_pred)).sum(axis=1).mean()

    # 逆伝播
    optimizer.zero_grad()
    loss.backward()

    # パラメータの更新
    optimizer.step()

    if i % 100 == 0:
        print(i, loss.item())

# 出力
# 0 0.7283064126968384
# 100 0.5940693616867065
# 200 0.4906403124332428
# 300 0.387647807598114
# 400 0.24243196845054626
# 500 0.13766250014305115
# 600 0.08652915805578232
# 700 0.05950736626982689
# 800 0.04409634321928024
# 900 0.034435056149959564

モデルの保存・読み込みをする

モデルを保存する

モデルを保存する際には、torch.save()を用るが、モデルのインスタンスを直接保存するのではなく、モデルのパラメータの情報を有するstate_dictを保存し、読み込む際にもstate_dictを読み込んでモデルのインスタンスにloadするのが一般的。

print(list(mlp.parameters()))
print()

# state_dictの取得
state_dict = mlp.state_dict()
print(state_dict)

# モデルの保存
torch.save(state_dict, './model.pth')

# 出力
# [Parameter containing:
# tensor([[ 1.7305,  2.7831, -0.4495],
#         [-1.6474, -2.7843, -1.6844]], requires_grad=True), Parameter containing:
# tensor([ 1.6473e+00, -1.5183e-03,  0.0000e+00], requires_grad=True), Parameter containing:
# tensor([[ 2.9200, -1.0661],
#         [-2.7757,  2.7199],
#         [-1.2010, -0.3710]], requires_grad=True), Parameter containing:
# tensor([-1.3526,  1.3526], requires_grad=True)]
# 
# OrderedDict([('linear1.W', tensor([[ 1.7305,  2.7831, -0.4495],
#         [-1.6474, -2.7843, -1.6844]])), ('linear1.b', tensor([ 1.6473e+00, -1.5183e-03,  0.0000e+00])), ('linear2.W', tensor([[ 2.9200, -1.0661],
#         [-2.7757,  2.7199],
#         [-1.2010, -0.3710]])), ('linear2.b', tensor([-1.3526,  1.3526]))])

モデルを読み込む

以下のようにしてモデルを読み込む

# モデルの定義
mlp2 = MLP(2, 3, 2)
print(list(mlp2.parameters()))  # ランダムな初期値
print()

# 学習済みパラメータの読み込み
state_dict = torch.load('./model.pth')
mlp2.load_state_dict(state_dict)
print(list(mlp2.parameters()))  # 学習済みパラメータ

# 出力
# [Parameter containing:
# tensor([[ 1.5004,  0.5244, -0.3561],
#         [ 1.0002, -0.6345,  0.2359]], requires_grad=True), Parameter containing:
# tensor([0., 0., 0.], requires_grad=True), Parameter containing:
# tensor([[ 1.0440, -0.1805],
#         [ 0.8546, -1.0076],
#         [ 0.5777,  0.5786]], requires_grad=True), Parameter containing:
# tensor([0., 0.], requires_grad=True)]

# [Parameter containing:
# tensor([[ 1.7305,  2.7831, -0.4495],
#         [-1.6474, -2.7843, -1.6844]], requires_grad=True), Parameter containing:
# tensor([ 1.6473e+00, -1.5183e-03,  0.0000e+00], requires_grad=True), Parameter containing:
# tensor([[ 2.9200, -1.0661],
#         [-2.7757,  2.7199],
#         [-1.2010, -0.3710]], requires_grad=True), Parameter containing:
# tensor([-1.3526,  1.3526], requires_grad=True)]

人気記事

人気記事はこちら。

CUDA、cuDNNのバージョンをターミナルで調べるコマンド
【Pytorch】テンソルを連結する方法(cat・stack)
【Pytorch】テンソルの次元を追加・削除する方法【dim】
【Protobuf】"TypeError: Descriptors cannot not be created directly."を解決する【solved】
【Python】Tensorflowをダウングレード・アップグレードするコマンド

タイトルとURLをコピーしました