>100 Views
May 24, 24
スライド概要
AI・機械学習を勉強したい学生たちが集まる、京都大学の自主ゼミサークルです。私たちのサークルに興味のある方はX(Twitter)をご覧ください!
2024年度前期輪読会#4 「ゼロから作るDeep Learning」 ニューラルネットワークの学習 4.3-4.4 京都大学経済学部 榊原陽介 0
アジェンダ 目次 4.3 数値微分 4.4 勾配法 まとめ 1
4.3 数値微分法 2
4.3 数値微分 ● 定義: • ● 変数xの微小な変化による、関数f(x)の変化の程度を示す 実装例: • 2つの問題が存在 def numerical_diff(f, x): #数値微分 h = 1e-50 return (f(x+h) - f(x)) / h 3
4.3 数値微分 2つの問題 ● 丸め誤差: 計算処理の過程で、微小な数値は省略される • 小さすぎる値はコンピュータ上で正確に表現できない →一般にh = 0.0001(10^-4) 程度が”ほぼ正確” ● ● 前方差分のみ考慮: 正確な数値微分ではない →中心差分 をとる 改善例: def numerical_diff(f, x): #数値微分 h = 1e-4 #0.0001 return (f(x+h) - f(x-h)) / 2h 4
4.3 数値微分 参考:https://qiita.com/Negelon/items/fafec9b0d33ab96d1446 h = 1e-4 # h = 0.0001 # 数値微分を行う f(x) = x**2 の定義 def func(x): return x**2 # 前方差分の定義 def front_numerical_diff(f, x): return (f(x + h) - f(x)) / h # 後方差分の定義 def back_numerical_diff(f, x): return (f(x) - f(x - h)) / h # 中心差分の定義 def center_numerical_diff(f, x): return (f(x + h) - f(x - h)) / (2 * h) print('前方差分 :', front_numerical_diff(func, 2)) 前方差分 : 4.0001000000078335 print('後方差分 :', back_numerical_diff(func, 2)) 後方差分 : 3.999900000000167 print('中心差分 :', center_numerical_diff(func, 2)) 中心差分 : 4.000000000004 #最も正確 5
4.3 数値微分 偏微分: 2変数関数の片方の変数に対する微分 def function_2(x): return x[0]**2 + x[1]**2 #または return np.sum(x**2) ● 例: x0=3, x1=4のとき、x0に対する偏微分 • x1は定数→f(x0, x1=4)を定義 • fについて、x0=3 に対し微分 → 出力: 6 def function_tmp1(x0): return x0*x0 + 4.0**2.0 numerical_diff(function_tmp1, 3.0) 6
4.4 勾配法 7
4.4 勾配 ● 勾配:全てのパラメータ(重み等)の偏微分をベクトルにまとめたもの ● 勾配が示す方向:その地点で関数の値を最も減らす方向 →損失関数の最小値へと移動する *参考:https://daily-tech.hatenablog.com/entry/2018/05/04/060346 8
4.4 勾配 ● 勾配法:勾配方向への繰り返し移動で、関数の値を最小化する ● η:学習率(パラメータを更新する度合い) • 適切な値を設定することが重要 • • ηが大きい: 損失関数の値が大きく発散する→最小値から乖離 ηが小さい: パラメータがほぼ更新されない 9
4.4 勾配 ● 実装例: 初期値 (-3,4) から最小値 (0,0) に勾配法で近づける def gradient_descent(f, init_x, lr=0.1, step_num=100): x = init_x #init_xは初期値のベクトル、lrは学習率(learning rate),step_numはステップ数 for i in range(step_num): grad = numerical_gradient(f,x) x -= lr * grad return x def function_2(x): return x[0]**2 + x[1]**2 init_x = np.array([-3.0, 4.0]) #初期値の2次元ベクトル, x[0]=-3.0, x[1]=4.0 gradient_descent(function_2, init_x=init_x, lr=0.1, step_num=100) 10
4.4 勾配 ● ● ニューラルネットワーク上での学習: W:重み(形状が m × n) L:損失関数 として、勾配は 出力結果:m × n 次元行列, hだけ増加した時の値 • 値が負:プラス方向に更新 • • ex) = -0.4のとき, h増加→0.4h減少, 最小値に向かうにはh増加で更新 値が正:マイナス方向に更新 • ex) = 0.4のとき, h増加→0.4h増加, 最小値に向かうにはh減少で更新 11
4.4 勾配 ● 実装例: import sys, os sys.path.append(os.pardir) import numpy as np from common.functions import softmax, cross_entropy_error #ソフトマックス関数と交差エントロピー誤差関数をインポートします。 from common.gradient import numerical_gradient #数値勾配関数をインポートします。 class simpleNet: # simpleNet クラスを定義します。 def __init__(self): # 初期化メソッドを定義します。 self.W = np.random.randn(2,3) # 重み行列 W をガウス分布で初期化します。 def predict(self, x): # 予測メソッドを定義します。 return np.dot(x, self.W) # 入力 x と重み W のドット積を計算して返します。 def loss(self, x, t): # 損失計算メソッドを定義します。 z = self.predict(x) # 予測結果を計算します。 y = softmax(z) # ソフトマックス関数を適用して予測確率を計算します。 loss = cross_entropy_error(y, t) # 予測確率と正解ラベル t との交差エントロピー誤差を計算します。 return loss # 損失を返します。 x = np.array([0.6, 0.9]) # 入力データの 2次元ベクトルを定義します。 t = np.array([0, 0, 1]) # 正解ラベルの 3次元ベクトルを定義します。 net = simpleNet() # simpleNet クラスのインスタンスを作成します。 f = lambda w: net.loss(x, t) # 損失関数を引数に取る無名関数(ラムダ関数)を定義します。 dW = numerical_gradient(f, net.W) # 数値勾配を計算します。 print(dW) # 勾配を出力します。 12
4.3-4.4まとめ ここまでの流れ 4.2 損失関数 モデルの精度を高めるため、ニューラルネットワークの重みを最適化 →ミニバッチでの損失関数(誤差)の最小化 4.3 数値微分法 誤差の最小値、およびその近似値を測定する方法 4.4 勾配法 勾配:各重みでの損失関数(誤差)を最も減らす方向を示す →パラメータ更新により、損失関数を最小化 13
参考文献 @Negelon, 数値微分における3つの差分とその誤差について, 2019, https://qiita.com/Negelon/items/fafec9b0d33ab96d1446 ● rkoichi2001, 関数の最適化 ~勾配法~, 2018, https://daily-tech.hatenablog.com/entry/2018/05/04/060346 ● @ponponnsan, ゼロつくDeepLearning_cp4, 2024, https://qiita.com/ponponnsan/items/321670629c15aea21fd2 ● 14
15