272 Views
June 03, 24
スライド概要
AI・機械学習を勉強したい学生たちが集まる、京都大学の自主ゼミサークルです。私たちのサークルに興味のある方はX(Twitter)をご覧ください!
2024年度前期輪読会#5 4章ニューラルネットワークの学習 システムエンジニア(Web系)義積 京都大学理学部物理学科(凝縮系理論専攻)卒 0
4.5 学習アルゴリズムの実装 ・タスク:数字(0〜9)の分類問題 (データセット:MNIST) ・モデル:2層ニューラルネットワーク ・損失関数:交差エントロピー ・手法:勾配降下法 1
4.5 学習アルゴリズムの実装 2層ニューラルネットワーク + x b1 = → a1 z1 w1 + z1 b2 = a2 → y w2 sigmoid x・w1 + b1 = a1 → z1 softmax z1・w2 + b2 = a2 → y 正規化 2
4.5 学習アルゴリズムの実装 概要 準備 { xn, tn } 60000 抽出 → 100 = N {w, b} 初期値, eta i = 1, …, 10000 学習 = 最適な w, b を得ること 損失関数(尤度) 勾配(尤度を最大) パラメータの更新 ( i : 隠れ層 ) 精度 損失関数の減少 (学習) 学習した結果の パラメータ { W, b } 汎化能力の測定 3
4.5 学習アルゴリズムの実装 準備(インプット、初期条件、計算の制限、など) 準備 { xn, tn } 60000 抽出 → 100 = N {w, b} 初期値, eta i = 1, …, 10000 学習 損失関数 勾配 パラメータの更新 ( i : 隠れ層 ) 精度 (学習) 学習した結果の パラメータ { W, b } 4
4.5 学習アルゴリズムの実装 準備(インプット、初期条件、計算の制限、など) 準備 train_nueralnet.py { xn, tn } (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True) 60000 抽出 →100=N {w, b} 初期値, eta network = TwoLayerNet( input_size=784, hidden_size=50, output_size=10, weight_init_std=0.01 ) iters_num = 10000 # 繰り返しの回数を適宜設定する 【初期値】ref. 6.2 wmn: ガウス分布 train_size = x_train.shape[0] = 60,000 batch_size = 100 learning_rate = 0.1 bn : 0 【ハイパーパラメータ】ref. 6.5 class TwoLayerNet: ・学習率 def __init__(self, input_size, hidden_size, output_size, weight_init_std): eta = 0.1 ・隠れ層ニューロン数 ノード数(1層、2層):50 【ミニバッチ数】 ・訓練データ60,000からランダムにサンプリング→100 ・訓練制度測定はステップ数/エポック数%0の時だけ実施 # 重みの初期化 self.params = {} random.randn(行列サイズ):標準分布に従うラン ダムな成分を持つ行列を生成 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) ※エポック数 = 訓練データ数/ミニバッチのサイズ = 60,000/100 = 600 →10000/600〜16回 5
4.5 学習アルゴリズムの実装 損失関数 準備 { xn, tn } 60000 抽出 → 100=N {w, b} 初期値, eta i = 1, …, 10000 学習 損失関数 勾配 パラメータの更新 ( i : 隠れ層 ) 精度 (学習) 学習した結果の パラメータ { W, b } 6
4.5 学習アルゴリズムの実装 損失関数 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 N=100(ミニバッチ) def cross_entropy_error(y, t): 今はyを各数字の確率のベクトルとして いるが、解き方によっては直接数字 を格納している場合もあって、たぶんそ の場合に流用したいから if y.ndim == 1: t = t.reshape(1, t.size) 交差エントロピー def loss(self, x, t): y = self.predict(x) 1次元配列→2次元配列 y = y.reshape(1, y.size) 今は(100, 10)の形で入っている # 教師データが one-hot-vectorの場合、正解ラベルのインデックスに変換 if t.size == y.size: t = t.argmax(axis=1) return cross_entropy_error(y, t) おそらくこれも流用を意図 t には、正解の数字を格納する (元々、正解の数字が格納されている場 合がある(上と同じ)) axis=0:行方向、axis=1:列方向 batch_size = y.shape[0] return -np.sum(np.log(y[np.arange(batch_size), t] + 1e-7)) batch_size 7
4.5 学習アルゴリズムの実装 損失関数 定義式通りに計算 テキスト sum2 = 0 def cross_entropy_error(y, t): for k in range(0, batch_size - 1): sum2 += -np.dot(np.log(y[k] + 1e-7), t[k]) / batch_size 1人で開発する場合、汎用性もたせるのは分かるけど、 if y.ndim == 1: 複数人で開発するシステムなんかの場合、本気で保守し t = t.reshape(1, t.size) ずらい. 分けた方が不具合起こしにくい y = y.reshape(1, y.size) # 教師データが one-hot-vectorの場合、正解ラベルのインデックスに変換 if t.size == y.size: t = t.argmax(axis=1) batch_size = y.shape[0] return -np.sum(np.log(y[np.arange(batch_size), t] + 1e-7)) batch_size 8
4.5 学習アルゴリズムの実装 勾配 準備 { xn, tn } 60000 抽出 → 100 = N {w, b} 初期値, eta i = 1, …, 10000 学習 N=100回 * 10000 〜40000回 * 10000 損失関数 勾配 パラメータの更新 ( i : 隠れ層 ) 最も計算負荷かかる工程 ※バッチ単位で処理できない 精度 (学習) 学習した結果の パラメータ { W, b } 9
4.5 学習アルゴリズムの実装 勾配 def numerical_gradient(f, x): h = 1e-4 # 0.0001 勾配 grad = np.zeros_like(x) it = np.nditer(x, flags=["multi_index"], op_flags=["readwrite"]) 配列xの全要素に対して演算 while not it.finished: idx = it.multi_index 初期値が、 tmp_val = x[idx] input_size=784, hidden_size=50 x[idx] = tmp_val + h fxh1 = f(x) # f(x+h) だったので、 1ステップごとに、 W1: 784 * 50 = 39200回 x[idx] = tmp_val - h fxh2 = f(x) # f(x-h) grad[idx] = (fxh1 - fxh2) / (2 * h) x[idx] = tmp_val # 値を元に戻す b1: 50 W2: 50 * 10 = 500 b2: 10 合計 39,760回ループする これが多いのかよく分からないが、 実際計算してみると…めっちゃ重い! it.iternext() return grad 10
4.5 学習アルゴリズムの実装
勾配
勾配法
def gradient(self, x, t):
W1, W2 = self.params["W1"], self.params["W2"]
b1, b2 = self.params["b1"], self.params["b2"]
・numerical_gradient()
grads = {}
(黎明期の方法?)
batch_num = x.shape[0]
⇨以下、
・gradient()
逆伝播誤差法(計算グラフ)
を用いる
# 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
11
4.5 学習アルゴリズムの実装 パラメータの更新 準備 { xn, tn } 60000 抽出 → 100 = N {w, b} 初期値, eta i = 1, …, 10000 学習 損失関数 勾配 パラメータの更新 ( i : 隠れ層 ) 精度 (学習) 学習した結果の パラメータ { W, b } 12
4.5 学習アルゴリズムの実装 パラメータの更新 # パラメータの更新 パラメータ更新 for key in ("W1", "b1", "W2", "b2"): a -= b は、a = a - b network.params[key] -= learning_rate * grad[key] ( i : 隠れ層 ) 13
4.5 学習アルゴリズムの実装 学習の精度 準備 { xn, tn } 60000 抽出 → 100 = N {w, b} 初期値, η i = 1, …, 10000 学習 損失関数 勾配 パラメータの更新 ( i : 隠れ層 ) 精度 (学習) 学習した結果の パラメータ { W, b } 14
4.5 学習アルゴリズムの実装 学習の精度 ・O(0.1) < O(0.01) < O(1) ・winiの大きさによって、収束性が影響を受ける ・O(1)だと10000回ステップ後も収束しない ・ηと同程度にすればいい? ・勾配法(テキスト)→逆伝播誤差法(左図)によっ て精度が上昇している ・分布の仕方の影響も大きいらしい(6章) 図: 損失関数の推移 15
4.5 学習アルゴリズムの実装 学習した結果のパラメター {w, b} 準備 { xn, tn } 60000 抽出 → 100 = N {w, b} 初期値, eta i = 1, …, 10000 学習 損失関数 勾配 パラメータの更新 ( i : 隠れ層 ) 精度 (学習) 学習した結果の パラメータ { W, b } { 60000回+10000回} * 16 〜 110000回 16
4.5 学習アルゴリズムの実装 学習した結果のパラメター {w, b} 汎化能力の測定 学習した結果の パラメータ { W, b } 目的 過学習になっていないか、を調べる 方法 訓練データで得られた{W, B}を用いて、 ・訓練データに対する認識精度と ・テストデータに対する精度 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]) (10000/600〜16回) return accuracy p114 def accuracy(self, x, t): (誤)y = predict(x) (正)y = self.predict(x) 17
4.5 学習アルゴリズムの実装 学習した結果のパラメター {w, b} 学習精度の収束が、初期値に依存 していた割に、 データの違いに対して、認識精度が 合いすぎているように思える… (p.193とかp.194みたいなのを期待し ていた) 図:訓練データでの認識精度と、テストデータの認識精度 18
4.6 まとめ まとめ まとめ1 まとめ2 データセットは、訓練データとテストデータに分ける → 汎化能力を評価 ニューラルネットワークの学習は、損失関数を指標として、この値が小さくな るように重みパラメータ{W, b}を更新する まとめ3 その解法の一つに、勾配降下法(数値微分)がある (が、これは使い物にならない) まとめ 4 誤差逆伝播法を用いると、高速に勾配を求めることができる 19