ゼロから作るDeep Learning(21日目)

こんにちは、筋肉めがねです。

 

クリスマス休暇を利用して、Schwaldzwaldにあるスパ付きのホテルに泊まって参りました。ドイツの方々は、それぞれの実家へ帰省したり、家族で過ごしたりするようですが、僕らはこういう時期を利用して、普段生活している空間から移動して、ゆっくりとリラックスできる場所で過ごしたいものですよね。

滞在日数は1日半と必ずしも長くはない滞在ではありましたが、ホテルにあるプール、サウナ、フィットネスセンター、そしてBaden Badenのクリスマスマーケットと充実したクリスマスを過ごす事ができました。極め付けは2日目の朝、ホテルのプールに行ってみるとまだ誰もきておらず、プライベートプールのような感覚でプールを独り占めする事ができました。 

f:id:KinnikuMegane:20181228073307j:plain

 

それでは、本日も「ゼロから作るDeep Learning」を進めていきましょう。本日は6章の続きです。

前回の記事では、ニューラルネットワークの「学習」フェーズにおいて、「勾配消失」という問題が発生しうる可能性がある事、そして「勾配消失」を発生させないためには、適切な重みパラメータの初期値を設定する必要がある事を書きました。

 

本日は、Batch Normalizationについて書いていきます。

前の記事で書いておりませんでしたが、重みパラメータの初期値を適切に設定するとニューラルネットワークの各層のアクティベーションの分布は適度な広がりを持ちます。そして、アクティベーションの分布が適度な広がりを持つという事が、「勾配消失」を防ぐために必要です。では、アクティベーションの分布とは何か。本書には、アクティベーションとは活性化関数の後の出力データとあります。つまり、ある層にある複数のニューロンから出力される出力データですね。それで、例えばそのデータ群を正規化(各値が0〜1までの値を取るように調整してあげる事)してあげて、各値がどのような値を取るか観察してあげると、0〜1の間のどこかしらの値を取る事になります。その分布が適度な広がりを持つ、という事が「勾配消失」を防ぐ上で大事な事になります。

それで、Batch Normalizationというのは、そのアクティベーションの分布を「強制的」に調整してあげる手法です。

それでは、MNISTのデータセットを使用して、Batch Normalizationを用いる時と用いない時で、「学習」の進み方がどう変わるのか実験してみましょう。その際に、重みパラメータのスケールを幾つか変化させてみましょう。

先ずは結果です。

f:id:KinnikuMegane:20181228072453p:plain

重みパラメータのスケール表示の文字が大きすぎるところはご愛嬌で。

そして、コードです。

import sys, os
sys.path.append(os.pardir) 
import numpy as np
import matplotlib.pyplot as plt
from dataset.mnist import load_mnist
from common.multi_layer_net_extend import MultiLayerNetExtend
from common.optimizer import SGD, Adam

(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True)

x_train = x_train[:1000]
t_train = t_train[:1000]

max_epochs = 20
train_size = x_train.shape[0]
batch_size = 100
learning_rate = 0.01


def __train(weight_init_std):
    bn_network = MultiLayerNetExtend(input_size=784, hidden_size_list=[100, 100, 100, 100, 100], output_size=10, 
                                    weight_init_std=weight_init_std, use_batchnorm=True)
    network = MultiLayerNetExtend(input_size=784, hidden_size_list=[100, 100, 100, 100, 100], output_size=10,
                                weight_init_std=weight_init_std)
    optimizer = SGD(lr=learning_rate)
    
    train_acc_list = []
    bn_train_acc_list = []
    
    iter_per_epoch = max(train_size / batch_size, 1)
    epoch_cnt = 0
    
    for i in range(1000000000):
        batch_mask = np.random.choice(train_size, batch_size)
        x_batch = x_train[batch_mask]
        t_batch = t_train[batch_mask]
    
        for _network in (bn_network, network):
            grads = _network.gradient(x_batch, t_batch)
            optimizer.update(_network.params, grads)
    
        if i % iter_per_epoch == 0:
            train_acc = network.accuracy(x_train, t_train)
            bn_train_acc = bn_network.accuracy(x_train, t_train)
            train_acc_list.append(train_acc)
            bn_train_acc_list.append(bn_train_acc)
    
            print("epoch:" + str(epoch_cnt) + " | " + str(train_acc) + " - " + str(bn_train_acc))
    
            epoch_cnt += 1
            if epoch_cnt >= max_epochs:
                break
                
    return train_acc_list, bn_train_acc_list

weight_scale_list = np.logspace(0, -4, num=16)
x = np.arange(max_epochs)

for i, w in enumerate(weight_scale_list):
    print( "============== " + str(i+1) + "/16" + " ==============")
    train_acc_list, bn_train_acc_list = __train(w)
    
    plt.subplot(4,4,i+1)
    plt.title("W:" + str(w))
    if i == 15:
        plt.plot(x, bn_train_acc_list, label='Batch Normalization', markevery=2)
        plt.plot(x, train_acc_list, linestyle = "--", label='Normal(without BatchNorm)', markevery=2)
    else:
        plt.plot(x, bn_train_acc_list, markevery=2)
        plt.plot(x, train_acc_list, linestyle="--", markevery=2)

    plt.ylim(0, 1.0)
    if i % 4:
        plt.yticks([])
    else:
        plt.ylabel("accuracy")
    if i < 12:
        plt.xticks([])
    else:
        plt.xlabel("epochs")
    plt.legend(loc='lower right')
    
plt.show()

重みパラメータのスケールが0.29および0.158の場合(右上の2ケース)を除いては、全てのケースでBatch Normalization有りのニューラルネットワークの方が学習の進みが早い事が分かります。そして、特に重みパラメータのスケールが、0.54以上および0.025以下の場合は、Batch Normalizationをかませないニューラルネットワークは全く学習が進んでいない事が分かります。

 

参考までに、こちらがBatch Normalizationに関するオリジナルの論文です。

https://arxiv.org/pdf/1502.03167.pdf

 

それでは、本日は以上でございます。

にほんブログ村 IT技術ブログへ
にほんブログ村



Pythonランキング