「.NET 開発基盤部会 Wiki」は、「Open棟梁Project」,「OSSコンソーシアム .NET開発基盤部会」によって運営されています。
勾配降下法(損失関数の勾配を計算するための数値微分)は、
計算に時間がかかるので、ニューラルネットワークを学習させる際に用い効率よく計算を行う。
誤差逆伝播法は、
によって理解する。
前者が一般的であるが、ここでは、後者を使用して視覚的に理解した上で実装する。
勾配降下法とも
勾配の示す方向は、各場所で関数の値を最も減らす方向。
df(x0, x1) df(x0, x1) ───── , ───── dx0 dx1
"""This is a test program.""" import numpy as np def numerical_gradient(f, x01): """偏微分""" h = 1e-4 # 微小な値hとして1の-4乗を用いる grad = np.zeros_like(x01) # x01と同じ形状で要素が0。 for idx in range(x01.size): tmp_val = x01[idx] # 前方差分から中心差分にして誤差減 # f(x + h) fxh1 = f(tmp_val + h) # f(x - h) fxh2 = f(tmp_val - h) # (f(x + h) - f(x - h)) / 2 * h grad[idx] = (fxh1 - fxh2) / (2 * h) return grad def function_2(x): return np.sum(x**2) print(numerical_gradient(function_2, np.array([3.0, 4.0]))) print(numerical_gradient(function_2, np.array([0.0, 2.0]))) print(numerical_gradient(function_2, np.array([3.0, 0.0])))
[ 6. 8.] [ 0. 4.] [ 6. 0.]
#ref(): File not found: "gradient_2d.png" at page "深層学習の誤差逆伝播法"
df(x0, x1) x0 = x0 - η ───── dx0 df(x0, x1) x1 = x1 - η ───── dx1
2 2 f(x0, x1) = x0 + x1
import numpy as np def numerical_gradient(f, x01): """偏微分""" h = 1e-4 # 微小な値hとして1の-4乗を用いる grad = np.zeros_like(x01) # x01と同じ形状で要素が0。 # print("x01:" + str(x01)); for idx in range(x01.size): tmp_val = x01[idx] # 前方差分から中心差分にして誤差減 # f(x + h) fxh1 = f(tmp_val + h) # f(x - h) fxh2 = f(tmp_val - h) # (f(x + h) - f(x - h)) / 2 * h grad[idx] = (fxh1 - fxh2) / (2 * h) return grad def gradient_descent(f, init_x01, lr, step_num): print("ln : step_num = " + str(lr) + " : " + str(step_num)) x01 = init_x01 for i in range(step_num): grad = numerical_gradient(f, x01) x01 -= lr * grad return x01 def function_2(x): return np.sum(x**2) init_x = np.array([-3.0, 4.0]) print(gradient_descent(function_2, init_x, 0.1, 100)) # 学習率が大きすぎる。 init_x = np.array([-3.0, 4.0]) print(gradient_descent(function_2, init_x, 10.0, 100)) # 学習率が小さすぎる。 init_x = np.array([-3.0, 4.0]) print(gradient_descent(function_2, init_x, 1e-10, 100))
ln : step_num = 0.1 : 100 [ -6.11110793e-10 8.14814391e-10] ln : step_num = 10.0 : 100 [ -1.91613251e+13 -1.26893162e+12] ln : step_num = 1e-10 : 100 [-2.99999994 3.99999992]
ニューラルネットワークの学習における勾配は、
重みパラメタに関する損失関数の勾配となる。
┌ w11 w21 vw31 ┐ W = │ │ └ w12 w22 vw32 ┘ ┌ dL dL dL ┐ │ ── ── ── │ dL │ dw11 dw21 dw31 │ ── =│ │ dW │ dL dL dL │ │ ── ── ── │ └ dw12 dw22 dw32 ┘
predict ---> softmax ---> cross_entropy_error
- predict(推論する)
- softmax(ソフトマックス関数)
- cross_entropy_error(交差エントロピー誤差)
C:\deep-learning-from-scratch-master\ch04>python Untitled-1.py
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 from gradient_simplenet import simpleNet print("==================================================") print("==================================================") net = simpleNet() print("W:" + str(net.W)) x = np.array([0.6, 0.9]) p = net.predict(x) print("p:" + str(p)) t = np.array([0, 0, 1]) l = net.loss(x, t) print("loss:" + str(l))
W:[[ 1.92087598 0.63971089 -0.26820797] [ 0.58411529 -0.04610929 -0.88999594]] p:[ 1.67822935 0.34232817 -0.96192113] loss:2.92853604814
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 from gradient_simplenet import simpleNet print("==================================================") print("==================================================") net = simpleNet() print("W:" + str(net.W)) x = np.array([0.6, 0.9]) t = np.array([0, 0, 1]) f = lambda w: net.loss(x, t) dW = numerical_gradient(f, net.W) print("dW:" + str(dW))
================================================== ================================================== W:[[ 1.83160192 0.4900981 -0.94188042] [-0.24946104 2.91410946 -0.00695892]] dW:[[ 0.06708443 0.51711391 -0.58419835] [ 0.10062665 0.77567087 -0.87629752]]
W : [[ w11 = 1.83160192 w21 = 0.4900981 w31 = -0.94188042] [ w12 = -0.24946104 w22 = 2.91410946 w32 = -0.00695892]] dL/dW : [[ dL/dw11 = 0.06708443 dL/dw21 = 0.51711391 dL/dw31 = -0.58419835] [ dL/dw12 = 0.10062665 dL/dw22 = 0.77567087 dL/dw32 = -0.87629752]]
合成関数の微分についての性質。
合成関数(関数Aと関数B)
2 z = t t = x + y
dz ─ = 2t dt
dt ─ = 1 dx
dz dz dt ─ = ─ ─ = 2t * 1 = 2t = 2( x + y) dx dt dx
によって表現される。
100 200 220 (リンゴ)--->(*2)--->(*1.1)--->(支払い)
100 200 220 (リンゴ)--->(*)--->(*)--->(支払い) ↑2 ↑1.1 (リンゴの個数)(消費税)
100 200 650 715 (リンゴ)--->(*)--------->(+)--->(*)--->(支払い) ↑2 ↑ ↑1.1 (リンゴの個数) │ (消費税) │ 150 450 │ (みかん)--->(*)-----------┘ ↑3 (みかんの個数)
100 200 4,200 4,620 (リンゴ)--->(*)------------->(+)--->(*)--->(支払い) ↑2 ↑ ↑1.1 (リンゴの個数) │ (消費税) │ │ (沢山の買い物)--->(複雑な計算)┘4000
100(1x) 200(2x) 220(2.2x) (リンゴ)--->(*)---->(*)---->(支払い) ↑2 ↑1.1 (リンゴの個数) (消費税)
100(1x) 200(2x) 220(2.2x) (リンゴ)--->(*)---->(*)---->(支払い) <--- ↑ <---- ↑ <---- 2.2 │ 1.1 │ 1.0 │2 │1.1 (リンゴの個数) (消費税)
順方向と逆向きに局所的な微分を乗算。
x y ---->(f)----> <---- <---- dy E ─ E dx
x t z --------->(+)---->(^2)----> <--------- ↑ <---- <---- dz dt │ dz dz 1 ─ ─ │ 1 ─ ─ = 1 dt dx │ dt dz │ y
x t z ------------>(+)---->(^2)----> <------------ ↑ <---- <---- │ 1 * 2(x + y) │ 2t = 2(x + y) │ │ y
z = x + y
dz ─ = 1 dx
dz ─ = 1 dy
x ──┐ dL │1 ─ │ dz ↓ z L (+) <-------------(何らかの計算)<------ ↑ dL dL │ dL ─ ─ │1 ─ dz dL y ──┘ dz
z = x * y
dz ─ = y dx
dz ─ = x dy
x ──┐ dL │y ─ │ dz ↓ z L (*) <-------------(何らかの計算)<------ ↑ dL dL │ dL ─ ─ │x ─ dz dL y ──┘ dz
これらの微分値は、
を表している。
100(1x) 200(2x) 220(2.2x) (リンゴ)---->(*)------>(*)---->(支払い) <----↑│ <------ ↑│<---- 2.2 ││ 1.1 ││ 1.0 ││ ││ 2│↓110 1.1│↓200 (リンゴの個数)(消費税)
100 200 650 715 (リンゴ)--->(*)--------->(+)--->(*)--->(支払い) <---↑│ <--------- ↑│<---↑│ <--- 2.2 ││ 1.1 ││1.1 ││ 1 2│↓110 ││ ││ (リンゴの個数) ││ 1.1││650 ││ │↓ 150 450 ││ (消費税) (みかん)--->(*)-----------┘│ <---↑│ <------------┘ 3.3 ││ 1.1 3│↓165 (みかんの個数)