「ゼロから作るDeep Leaning」4章:ニューラルネットワークの学習
「ゼロから作るDeep Leaning」3章:ニューラルネットワークに引き続き、「ゼロから作るDeep Leaning」に関してざっくりまとめます。あくまで主観による重要箇所の備忘録程度!
今回は、ニューラルネットワークの学習フェーズについてまとめます。
損失関数
ニューラルネットワークの学習では、損失関数が使用される。出力値と正解ラベルの値との差が大きいほど損失関数の値は大きくなる。ニューラルネットワークの学習では、損失関数の出力値が小さくなるように重みパラメーターを調整していく。
損失関数に使用されるのは主に以下の二つ。
2乗和誤差
$$E=\frac12\Sigma _k(y _k – t _k)^2$$
pythonで実装すると以下の通り。
1 2 |
def mean_squared_error(y, t): return 0.5 * np.sum()(y-t)**2) |
※「ゼロから作るDeep Leaning」89pより引用
yはニューラルネットワークの出力値、tは教師データ。
例えば・・・
1 2 |
t = [0, 0, 0, 1, 0, 0, 0, 0, 0, 0] y = [0.1, 0.0, 0.05, 0.7, 0.0, 0.05, 0.0, 0.0, 0.05, 0.05] |
ニューラルネットワークの出力と教師データの値の差が大きくなれば大きくなるほど損失関数の出力値は大きくなることがわかる。
交差エントロピー誤差
$$E=-\Sigma _k t _k\log y _k$$
pythonで実装すると以下の通り。
1 2 3 |
def cross_entropy_error(y, t): delta = 1e - 7 return -np.sum(t * np.log(y + delta)) |
※「ゼロから作るDeep Leaning」91pより引用
微小な値であるdeltaを足している理由は、np.log(0)になるとマイナスの無限大を表す-infとなり、それ以上計算を行うことができなくなってしまうから。
数値微分
微小な差分によって微分を求めることを数値微分という。
pythonで実装すると以下の通り。
1 2 3 |
def numerical_diff(f, x): h = 1e-4 # 0.0001 return (f(x+h) - f(x-h)) / (2*h) |
※「ゼロから作るDeep Leaning」99pより引用
続いて、\[f_(x _0,x _1)=x _0^2 + x _1^2\]
のように、複数の変数からなる関数の微分を偏微分という。
pythonで実装すると以下の通り。
1 2 |
def function_2(x): # xは配列 return x[0]**2 + x[1]**2 |
※「ゼロから作るDeep Leaning」102pより引用
勾配
勾配とは、全ての変数の偏微分をベクトルとしてまとめたもの。
勾配法をpythonで実装すると以下の通り。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
def numerical_gradient(f, x): h = 1e-4 grad = np.zeros_like(x) # xと同じ形状の配列を生成 for idx in range(x.size): tmp_val = x[idx] # f(x+h)の計算 x[idx] = tmp_val + h fxh1 = f(x) # f(x-h)の計算 x[idx] = tmp_val - h fxh2 = f(x) grad[idx] = (fxh1 - fxh2) / (2*h) x[idx] = tmp_val # 値をもとに戻す return grad |
※「ゼロから作るDeep Leaning」104pより引用
一つ一つの変数に対する偏微分をfor文で求める。
勾配は、各場所に置いて関数の値を最も減らす方向を示している。つまり、損失関数の勾配が示す方向に、入力値である重みパラメーターを少しずつ更新していけば損失関数の値を減らしていくことができる。(勾配法)
数式で表すと以下の通り。
$$x _0=x _0 – \eta\frac{\partial f}{\partial x _0}$$
$$x _1=x _1 – \eta\frac{\partial f}{\partial x _1}$$
pythonで実装すると以下の通り。
1 2 3 4 5 6 7 8 |
def gradient_descent(f, init_x, lr=0.01, step_num=100): x = init_x for i in range(step_num): grad = numerical_gradient(f, x) x -= lr * grad return x |
※「ゼロから作るDeep Leaning」107,108pより引用
lrは学習率、step_numは繰り返し回数を表す。
学習率の値は大きすぎても小さすぎても学習がうまく進まないので、適切な値を自身で設定する必要がある。
ニューラルネットワークの学習の全体像
- ミニバッチ
- 勾配の算出
- パラメータの更新
- 1~3を繰り返す
ここから学習アルゴリズムを実装していく。まずは、2層のニューラルネットワークを実装する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
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 |
※「ゼロから作るDeep Leaning」114,115p、本書コード掲載のgithubより引用
このTwoLayerNetクラスを対象に、MNISTデータセットを使い学習させる。pythonで実装すると以下の通り。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
import sys, os sys.path.append(os.pardir) # 親ディレクトリのファイルをインポートするための設定 import numpy as np import matplotlib.pyplot as plt 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] |
※「ゼロから作るDeep Leaning」118p、本書コード掲載のgithubより引用
まとめ
■ニューラルネットワークの学習は、損失関数の出力値を指標に、その値が小さくなるように、重みパラメーターを更新する。
■重みパラメーターの更新には、重みパラメーターの勾配を利用して、勾配方向に重みパラメーターを更新する。
ディスカッション
コメント一覧
まだ、コメントがありません