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

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

 

2019年3月29日、UK時間の午前11時にBrexitが実施されます。UKがEUをとうとう離れますね。2016年6月にUKの国民投票で離脱派が過半数を獲得してから刻々と時は流れ、残り4ヶ月弱となってきました。UKがEUから離脱する事は確定しておりますが、その条件がどうなるのか。物流が絡む企業では、輸出入にかかる関税、消費税、そして税関審査に大きな影響がある可能性があるため目が話せない状況です。

という事を書いておりましたら、昨日12月8日に日本の参院本会議で日本・EU経済連携協定(EPA: Economic Partnership Agreement)が可決されましたね。12月中の欧州議会本会議で可決されれば、来年2月1日より、発行されるとの事です。外務省の資料によると、日本からEUへ輸出される農林水産品について、ほぼ全品目で関税が撤廃されるという事です。僕らのように、EUで日本食料品を消費する機会のある人間にとっては、日本商品をさらに安く買える可能性があるので、とても嬉しいニュースでございます。

日本とEU間の貿易障壁がますます低くなっていく、という時に、果たしてUKはどういう立場をとるのか。来週12月11日に、UKは重要な投票を迎えますが、次回の記事ではそれについて書いていきましょう。

 

f:id:KinnikuMegane:20181208192539j:plain

 

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

 

前回の記事では「勾配降下法」について書きました。勾配降下法、とはニューラルネットワークが「学習」すべき対象のある地点の勾配を求めて、その地点から、「合ってなさ加減」がさらに小さくなる方向へ、重みパラメーターを変化させる。そしてそれらのステップを繰り返す事で最終的に、「合ってなさ加減」が最小となる地点の重みパラメーターを求め、ニューラルネットワークに「学習」させる、というものでした。

 

本日は、2層ニューラルネットワークを一つのクラスとして実装し、そして同クラスを用いてニューラルネットワークが学習する、というコードを実装します。

 

先ずは、2層のニューラルネットワークを一つのクラスとして定義するコードです。

import sys, os
sys.path.append(os.pardir)  # 親ディレクトリのファイルをインポートするための設定
from common.functions import *
from common.gradient import numerical_gradient

class TwoLayerNet:

    def __init__(self, input_size, hidden_size, output_size, weight_init_std=0.01):
        # 重みの初期化
        self.params = {}
        self.params['W1'] = weight_init_std * np.random.randn(input_size, hidden_size)
        self.params['b1'] = np.zeros(hidden_size)
        self.params['W2'] = weight_init_std * np.random.randn(hidden_size, output_size)
        self.params['b2'] = np.zeros(output_size)

    def predict(self, x):
        W1, W2 = self.params['W1'], self.params['W2']
        b1, b2 = self.params['b1'], self.params['b2']
    
        a1 = np.dot(x, W1) + b1
        z1 = sigmoid(a1)
        a2 = np.dot(z1, W2) + b2
        y = softmax(a2)
        
        return y
        
    # x:入力データ, t:教師データ
    def loss(self, x, t):
        y = self.predict(x)
        
        return cross_entropy_error(y, t)
    
    def accuracy(self, x, t):
        y = self.predict(x)
        y = np.argmax(y, axis=1)
        t = np.argmax(t, axis=1)
        
        accuracy = np.sum(y == t) / float(x.shape[0])
        return accuracy
        
    # x:入力データ, t:教師データ
    def numerical_gradient(self, x, t):
        loss_W = lambda W: self.loss(x, t)
        
        grads = {}
        grads['W1'] = numerical_gradient(loss_W, self.params['W1'])
        grads['b1'] = numerical_gradient(loss_W, self.params['b1'])
        grads['W2'] = numerical_gradient(loss_W, self.params['W2'])
        grads['b2'] = numerical_gradient(loss_W, self.params['b2'])
        
        return grads
        
    def gradient(self, x, t):
        W1, W2 = self.params['W1'], self.params['W2']
        b1, b2 = self.params['b1'], self.params['b2']
        grads = {}
        
        batch_num = x.shape[0]
        
        # forward
        a1 = np.dot(x, W1) + b1
        z1 = sigmoid(a1)
        a2 = np.dot(z1, W2) + b2
        y = softmax(a2)
        
        # backward
        dy = (y - t) / batch_num
        grads['W2'] = np.dot(z1.T, dy)
        grads['b2'] = np.sum(dy, axis=0)
        
        dz1 = np.dot(dy, W2.T)
        da1 = sigmoid_grad(a1) * dz1
        grads['W1'] = np.dot(x.T, da1)
        grads['b1'] = np.sum(da1, axis=0)

        return grads

そして、実装したクラス、およびMNISTデータセットを使ってニューラルネットワークに学習を行わせます。

import numpy as np
from dataset.mnist import load_mnist
from two_layer_net import TwoLayerNet

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

train_loss_list = []

iters_num = 10000
train_size = x_train.shape[0]
batch_size = 100
learning_rate = 0.1

network = TwoLayerNet (input_size=784, hidden_size=50, output_size=10)

for i in range(iters_num):
     batch_mask = np.random.choice(train_size, batch_size)
     x_batch = x_train[batch_mask]
     t_batch = t_train[batch_mask]

     grad = network.numerical_gradient(x_batch, t_batch)

     for key in ('W1', 'b1', 'W2', 'b2'):
          network.params[key] -= learning_rate * grad[key]

     loss = network.loss(x_batch, t_batch)
     train_loss_list.append(loss)

100個ごとのバッチデータをMNISTデータセットから取り出し、100個のデータセット(画像データと正解ラベルデータ)に対して、勾配を求めます。勾配を求めた地点での座標をパラメーターとして、そのパラメーターlearning rate: 0.1で更新し、それを、随時重みパラメーターそしてバイアスの値として格納していきます。また、その時の損失関数をlossという変数へ格納します。それらの100個のバッチデータに対しての作業を1回として、計10000回、loopを回します。

何が起こるかというと、徐々にlossつまり損失関数の値が0に近づいていく事が確認できるんですね。

次回は、4章最後です。過学習について触れましょう。

 

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