[Python] AI 08 Chainer + MNISTによる深層学習 学習成果のグラフ化

前回の続きです。

検証損失と検証精度の推移をグラフ化しました。

学習損失は学習データの難易度により上がったり下がったりですが、検証損失と検証精度は回を追うごとに確実に良くなっています。

Pythonで2軸グラフを初めて描きました。取りあえず描くだけならExcelより断然楽ですね。

import chainer
import chainer.links as L
import chainer.functions as F
from chainer import iterators
from chainer import optimizers
import numpy as np
import matplotlib.pyplot as plt
from chainer.dataset import concat_examples
from chainer import serializers

print(f'chainerバージョン {chainer.__version__}')

class MLP(chainer.Chain):
    def __init__(self, number_hidden_units=1000, number_out_units=10):
        super(MLP, self).__init__()

        with self.init_scope():
            self.layer1=L.Linear(None, number_hidden_units)
            self.layer2=L.Linear(number_hidden_units, number_hidden_units)
            self.layer3=L.Linear(number_hidden_units, number_out_units)

    def __call__(self, input_data):
        result1 = F.relu(self.layer1(input_data))
        result2 = F.relu(self.layer2(result1))
        return self.layer3(result2)

def testEpoch(train_iterator,loss,c):
    print(f'学習回数:{train_iterator.epoch:02d} --> 学習損失:{float(loss.data):.02f}')

    # 検証損失と精度
    test_losses = list()
    test_accuracies = list()
    i = 1
    while True:
        test_dataset = test_iterator.next()
        test_data, test_teacher_labels = concat_examples(test_dataset)

        # 検証データをモデルに渡す
        prediction_test = model(test_data)

        # 検証データに対して得られた予測値と正解を比較し損失を算出する
        loss_test = F.softmax_cross_entropy(prediction_test, test_teacher_labels)
        test_losses.append(loss_test.data)

        # 精度を計算する
        accuracy = F.accuracy(prediction_test, test_teacher_labels)
        test_accuracies.append(accuracy.data)

        print(f'{i}回目 検証損失:{np.mean(test_losses):.4f} 検証精度:{np.mean(test_accuracies):.2f}')

        if test_iterator.is_new_epoch:
            loss_and_acciracy = [c,np.mean(test_losses),np.mean(test_accuracies)]
            test_iterator.reset()
            print(loss_and_acciracy)
            print('\n', end='')
            break

        i = i + 1
    return loss_and_acciracy

train_data, test_data = chainer.datasets.get_mnist(withlabel=True, ndim=1)

model = MLP()

# print('入力層のバイアスパラメータ配列の形\n', model.layer1.b.shape)
# print('初期化後の値\n', model.layer1.b.data)

BATCH_SIZE = 100

train_iterator = iterators.SerialIterator(train_data, BATCH_SIZE)
test_iterator = iterators.SerialIterator(test_data, BATCH_SIZE,
repeat=False, shuffle=False)

optimizer = optimizers.SGD(lr=0.01)
optimizer.setup(model)

MAX_EPOCH = 5
c = 1
loss_list = list()
loss_and_acciracy = list()
while train_iterator.epoch < MAX_EPOCH:
    # 学習データセットをイテレータから取り出す
    train_dataset = train_iterator.next()

    # 学習データセットを学習データと正解データに分離する
    train_data, teacher_labels = concat_examples(train_dataset)

    # 予測値の計算をする
    prediction_train = model(train_data)

    # 得られた予測値と正解データと比較し学習損失を計算する
    loss = F.softmax_cross_entropy(prediction_train, teacher_labels)

    # ニューラルネットワークの中の勾配を初期化する
    model.cleargrads()

    # 勾配を計算する
    loss.backward()

    # 損失を反映してパラメータを更新する
    optimizer.update()

    # 一回学習(epoch)する度に検証データに対する予測精度を計る
    if train_iterator.is_new_epoch:
        loss_list.append(loss)
        print(loss_list)
        test_result = testEpoch(train_iterator,loss,c)
        loss_and_acciracy.append(test_result)
        c = c + 1

print(f'学習損失 loss_list {loss_list}')
print(f'検証損失&検証精度 loss_and_acciracy {loss_and_acciracy}')

# 2軸グラフの各データリスト作成
x_data = [data[0] for data in loss_and_acciracy]
bar_height_data = [data[1] for data in loss_and_acciracy]
line_height_data = [data[2] for data in loss_and_acciracy]

x = np.array(x_data)
bar_height = np.array(bar_height_data)
line_height = np.array(line_height_data)

# 棒グラフ(検証損失)を出力
fig, ax1 = plt.subplots()
ax1.bar(x, bar_height, align="center", color="#1e90ff", linewidth=0)
ax1.set_ylabel('loss')

# 折れ線グラフ(検証精度)を出力
ax2 = ax1.twinx()
ax2.plot(x, line_height, linewidth=4, color="#da70d6")
ax2.set_ylabel('acciracy')

plt.show()

# 学習済モデルを保存する
serializers.save_npz('chainer-mnist.model', model)
--------------------------------------------------

出力(最後の2行)
--------------------------------------------------
学習損失 loss_list [variable(0.6423535), variable(0.27920458), variable(0.25227988), variable(0.34563792), variable(0.2176703)]
検証損失&検証精度 loss_and_acciracy [[1, 0.48583707, 0.88409996], [2, 0.34386325, 0.9078999], [3, 0.29848826, 0.9186], [4, 0.27616385, 0.9211], [5, 0.25501966, 0.9291]]