「.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 ──┘ dzz = 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
(みかんの個数)