Affineレイヤを実装。
class Affine: def __init__(self, W, b): self.W = W self.b = b self.x = None def forward(self, x): self.x = x return np.dot(self.x, self.W) + self.b def backward(self, dy): dx = np.dot(dy, self.W.T) self.dW = np.dot(self.x.T, dy) self.db = np.sum(dy, axis=0) return dx
Affine変換とかあるじゃないですか。Affineで変な響きだし、Affineてなによ、と思ったら、一次関数のようです。
Ax+b
線形変換かよ。
ただ、ニューラルネットワークでは良く使うようです。
Wはウエイト(傾き)、xは入力、bはバイアス(切片)に対応します。
全て多次元配列ですので要素数の一致が大事ですね。
クラスAffineの中に、forward関数を定義します。
xを引き数にして、xとWの内積にbを足しますので、xの列数、Wの列数、xとWの内積がbの行列数と一致している必要があります。
同様にbackward関数は誤差逆伝播法で使うので定義します。
dL/dx = dL/dy dot W.T dL/dW = X.T dot dL/dy dL/db = sum(dL/dy)
ですね。
早速試してみます。
x = np.array([[1, 2]]) W = np.array([[4, 5, 6], [7, 8, 9]]) b = np.array([[10, 11, 12]]) affine = Affine(W, b) print("forward=", affine.forward(x)) dy = np.array([[1, 2, 3]]) dx = affine.backward(dy) print("dx=", dx) forward= [[28 32 36]] dx= [[32 50]]
forwardはx dot W + bなので、
(1×4+2×7+10, 1×5+2×8+11, 1×6+2×9+12) = (28, 32, 36)
でOK。
backwardはdyとして(1, 2, 3)が返ってきた場合、
(1×4+2×5+3×6, 1×7+2×8+3×9) = (32, 50)
なのでOKですかね。