誤差逆伝播法
誤差逆伝播法
前回までは、勾配の計算は数値微分で行いました。数値微分は、実行に時間がかかるため、より早い誤差逆伝播法を使います。
加算ノード
定義
入力x,yで出力zのとき、順伝播は
逆伝播は
なので、上位層からの出力をEとすると、
コード
class AddLayer: def __init__(self): pass def forward(self, x, y): out = x + y return out def backward(self, dout): dx = dout*1 dy = dout*1 return dx,dy
乗算ノード
定義
順伝播
逆伝播
ひっくり返る。
出力をEとすると
コード
class MulLayer: def __init__(self): self.x = None self.y = None def forward(self, x, y): self.x = x self.y = y out = x * y return out def backward(self, dout): dx = dout * self.y dy = dout * self.x return dx,dy
Affineノード
定義
順伝播
逆伝播
出力をEとすると
コード
class Affine: def __init__(self, W, b): self.W = W self.b = b self.x = None self.dW = None self.db = None def forward(self, x): self.x = x out = np.dot(x, self.W) + self.b return out def backward(self, dout): dx = np.dot(dout, self.W.T) self.dW = np.dot(self.x.T, dout) self.db = np.sum(dout, axis=0) return dx #必要なのは入力xの逆伝播のみ
ReLU
定義
順伝播
y = x (x > 0)
y = 0 ( x <= 0)
逆伝播
∂y/∂x = 1 (x > 0)
∂y/∂x = 0 (x <= 0)
コード
class Relu: def __init__(self): self.mask def forward(self, x): self.mask = (x <= 0) out = x.copy() out[self.mask] = 0 return out def backward(self, dout): dout[self.mask] = 0 dx = dout return dx
SoftmaxWithLoss
コード
class SofmaxWithLoss: def __init__(self): self.y = None self.t = None def forward(self, x, t): self.y = sofmax(x) self.t = t loss = cross_entropy_error(self.y, self.t) return loss def backward(self, dout=1): batch_size = self.t.shape[0] dx = (self.y - self.t) / batch_size #データ1個当たりの誤差 return dx
レイヤの生成
from collections import OrderedDict self.layers = OrderedDict() self.layers['Affine1'] = Affine(self.params['W1'], self.params['b1']) self.layers['Relu1'] = Relu() self.layers['Affine2'] = Affine(self.params['W2'], self.params['b2']) self.lastLayer = SoftmaxWithLoss()
順伝播
def predict(self, x): for layer in self.layers.values(): x = layer.forward(x) #それぞれのレイヤの順伝播を実行 return x def loss(self, x): y = self.predict(x) return self.lastLayer.forward(y, t) def gradient(self, x, t): #forward self.loss(x, t)
逆伝播を追加
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 = layers.backward(dout) grads = {} grads['W1'] = self.layers['Affine1'].dW grads['b1'] = self.layers['Affine1'].db grads['W2'] = self.layers['Affine2'].dW grads['b2'] = self.layers['Affine2'].db return grads