updated on 2019-08-18
書籍ではch01,ch02,ch03...フォルダと同じ階層にcommonフォルダを作成し、そのフォルダにgradient.pyとして置いてある
書籍のgithubhttps://github.com/oreilly-japan/deep-learning-from-scratch/blob/master/common/gradient.py
各関数が必要な時はimportするだけで利用できるようにする。
import numpy as np
def _numerical_gradient_1d(f, x):
h = 1e-4 # 0.0001
grad = np.zeros_like(x)
for idx in range(x.size):
tmp_val = x[idx]
x[idx] = float(tmp_val) + h
fxh1 = f(x) # f(x+h)
x[idx] = tmp_val - h
fxh2 = f(x) # f(x-h)
grad[idx] = (fxh1 - fxh2) / (2*h)
x[idx] = tmp_val # 値を元に戻す
return grad
def numerical_gradient_2d(f, X):
if X.ndim == 1:
return _numerical_gradient_1d(f, X)
else:
grad = np.zeros_like(X)
for idx, x in enumerate(X):
grad[idx] = _numerical_gradient_1d(f, x)
return grad
# 中心差分で微分
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'])
while not it.finished:
idx = it.multi_index
tmp_val = x[idx]
x[idx] = float(tmp_val) + h
fxh1 = f(x) # f(x+h)
x[idx] = tmp_val - h
fxh2 = f(x) # f(x-h)
grad[idx] = (fxh1 - fxh2) / (2*h)
x[idx] = tmp_val # 値を元に戻す
it.iternext()
return grad
_numerical_gradient_1d は画像一枚が渡ってきたときの微分
x = array([0.1, 0.1, 0.9, 0.1, 0.6, 0. , 0.9, 0.7, 0. , 0.7]) みたいな状況
_numerical_gradient_2d は画像がバッチ処理(100枚とか)で渡ってきたときの微分
x = array([[0.9, 0.9, 0.2, 0. , 0.2, 0.3, 0.8, 0.2, 0.1, 0.1],
[0.3, 0.1, 0. , 0.2, 0.4, 0.1, 0.5, 0.6, 0.5, 0.7],
...
[0.2, 0.7, 0.5, 0.4, 0.7, 0.8, 0.5, 0.3, 0.4, 0. ]]) みたいな状況
numerical_gradient はxの次元数に場合分けを使わない便利な書き方
役割は _numerical_gradient_2d と同じ
補足:【Python】numpy.nditer()という関数
numpy.nditer — NumPy v1.12 Manual
オプションのop_flags=['readwrite']配下の説明参照
https://teratail.com/questions/79756
何するの、これ? と思ったけど、使ってみた。まずはコードから。
np_array = np.random.randn(2, 3) print(np_array) nditer = np.nditer(np_array, flags=['multi_index']) while not nditer.finished: print(nditer.multi_index) print(np_array[nditer.multi_index]) nditer.iternext()
結果
# 最初のprint() [[-1.74892591 -0.59628881 0.05522772] [ 1.31665726 1.22965398 -0.41140946]] # whileループ (0, 0) -1.7489259098 (0, 1) -0.596288812217 (0, 2) 0.0552277235215 (1, 0) 1.31665726393 (1, 1) 1.229653983 (1, 2) -0.411409464808
なるほどー。何が便利かわからん。。。と思ったけど、numpyの次元が増えた時、2重ループとか使わず全パターン繰り返される
画像っぽい値で。2行2列3の値(3次元)
np_array = np.random.randn(2, 2, 3) print(np_array) nditer = np.nditer(np_array, flags=['multi_index']) while not nditer.finished: print(nditer.multi_index) print(np_array[nditer.multi_index]) nditer.iternext()
[[[ 0.40570373 0.29383617 0.19770627] [-0.35118724 0.64944819 -0.85610483]] [[-0.99811347 -0.3842173 -0.40674939] [-0.28392354 1.00559893 -0.36640248]]] (0, 0, 0) 0.405703731115 (0, 0, 1) 0.293836169251 (0, 0, 2) 0.197706273648 (0, 1, 0) -0.351187235594 (0, 1, 1) 0.649448185325 (0, 1, 2) -0.856104830751 (1, 0, 0) -0.998113470526 (1, 0, 1) -0.384217298371 (1, 0, 2) -0.406749392256 (1, 1, 0) -0.283923537977 (1, 1, 1) 1.0055989324 (1, 1, 2) -0.366402477684
すばらしい!!!