O'Reilly Japan - ゼロから作るDeep Learning
下のような感じで書き方が変わる。
第4章のバージョンについては説明がないので、誤差逆伝播法の理解を深めるためにもRuby化してみる。
ch04/two_layer_net.py
https://github.com/oreilly-japan/deep-learning-from-scratch/blob/master/ch04/two_layer_net.py
def gradient(self, x, t):
W1, W2 = self.params['W1'], self.params['W2']
b1, b2 = self.params['b1'], self.params['b2']
grads = {}
batch_num = x.shape[0]
# 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)
da1 = np.dot(dy, W2.T)
dz1 = sigmoid_grad(a1) * da1
grads['W1'] = np.dot(x.T, dz1)
grads['b1'] = np.sum(dz1, axis=0)
return grads
ch05/two_layer_net.py
https://github.com/oreilly-japan/deep-learning-from-scratch/blob/master/ch05/two_layer_net.py
def gradient(self, x, t):
# forward
self.loss(x, t)
# backward
dout = 1
dout = self.lastLayer.backward(dout)
layers = list(self.layers.values())
layers.reverse()
for layer in layers:
dout = layer.backward(dout)
# 設定
grads = {}
grads['W1'], grads['b1'] = self.layers['Affine1'].dW, self.layers['Affine1'].db
grads['W2'], grads['b2'] = self.layers['Affine2'].dW, self.layers['Affine2'].db
return grads
dはデルタ(δ)のd。
f(x, y) = x + y
という関数があったら、
xの偏微分はδf/δx
、
yの偏微分はδf/δy
、
と書く。
Ruby化
Ruby版はこんな感じになった。
dがdeltaの頭文字ということがわかっていれば、やっていることはレイヤー版と何ら変わりないことがわかるので、あとは本を読めば良い。
sigmoid_gradはSigmoidレイヤーのbackwardメソッドと同じ意味。(レイヤー版ではself.outに保持していたものを引数で渡すようにした)
def gradient(x, t)
grads = {}
batch_num = x.shape[0]
forward = predict(x)
w2, a1, z1, a2, y = forward[:w2], forward[:a1], forward[:z1], forward[:a2], forward[:y]
dy = (y - t) / batch_num
grads[:W2] = np.dot.(z1.T, dy)
grads[:b2] = np.sum.(dy, 0)
da1 = np.dot.(dy, w2.T)
dz1 = Util.sigmoid_grad(z1) * da1
grads[:W1] = np.dot.(x.T, dz1)
grads[:b1] = np.sum.(dz1, 0)
return grads
end