4章続き。 学習アルゴリズムの実装
改めて学習とは:適応可能な重みとバイアスを訓練データに適応するように調整すること
学習の4ステップ
ステップ1:ミニバッチをランダムに選択 ステップ2:ミニバッチの損失関数を減らす勾配を算出 ステップ3:重みパラメータを勾配方向に微小量だけ更新 ステップ4:ステップ1−3を反復
ミニバッチをランダム選択することから、
確率的勾配下降法(SGD, stochastic gradient descent)と呼ぶ。
2層ニューラルネットワークのクラスプログラムを参照。今までの総まとめ。
# cat two_layer_net.py # coding: utf-8 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) da1 = np.dot(dy, W2.T) dz1 = sigmoid_grad(a1) * da1 grads['W1'] = np.dot(x.T, dz1) grads['b1'] = np.sum(dz1, axis=0) return grads
そして、バッチサイズ100を10000回SGDでパラメータ更新するサンプルプログラム
# cat train_neuralnet_save.py # coding: utf-8 import sys, os sys.path.append(os.pardir) # 親ディレクトリのファイルをインポートするための設定 import numpy as np import matplotlib.pyplot as plt plt.switch_backend('agg') 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) network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10) iters_num = 10000 # 繰り返しの回数を適宜設定する train_size = x_train.shape[0] batch_size = 100 learning_rate = 0.1 train_loss_list = [] train_acc_list = [] test_acc_list = [] iter_per_epoch = max(train_size / batch_size, 1) 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) grad = network.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) if i % iter_per_epoch == 0: train_acc = network.accuracy(x_train, t_train) test_acc = network.accuracy(x_test, t_test) train_acc_list.append(train_acc) test_acc_list.append(test_acc) print("train acc, test acc | " + str(train_acc) + ", " + str(test_acc)) # グラフの描画 markers = {'train': 'o', 'test': 's'} x = np.arange(len(train_acc_list)) plt.plot(x, train_acc_list, label='train acc') plt.plot(x, test_acc_list, label='test acc', linestyle='--') plt.xlabel("epochs") plt.ylabel("accuracy") plt.ylim(0, 1.0) plt.legend(loc='lower right') #plt.show() plt.savefig('train_neuralnet.png')
そして、実行結果。1エポックごとの認識精度が向上していることがわかる。
# py train_neuralnet_save.py train acc, test acc | 0.0987166666667, 0.098 train acc, test acc | 0.788433333333, 0.7953 train acc, test acc | 0.874716666667, 0.8796 train acc, test acc | 0.898033333333, 0.9014 train acc, test acc | 0.9083, 0.9109 train acc, test acc | 0.9141, 0.9171 train acc, test acc | 0.919933333333, 0.9215 train acc, test acc | 0.924516666667, 0.9264 train acc, test acc | 0.927233333333, 0.9293 train acc, test acc | 0.930866666667, 0.9316 train acc, test acc | 0.93405, 0.9344 train acc, test acc | 0.937083333333, 0.9367 train acc, test acc | 0.93835, 0.9372 train acc, test acc | 0.941066666667, 0.9402 train acc, test acc | 0.94335, 0.9426 train acc, test acc | 0.945, 0.9442 train acc, test acc | 0.946916666667, 0.9459
訓練データとテストデータに差異がほぼないことから過学習が起きていないことも分かった。