我试图关注一本关于深度学习的书,但我发现关于网络的仿射层的某些部分令人困惑。假设我有一个网络,它接受一些手写数字(0 ~ 9
(图像(mnist(,这些图像被扁平化成一维数组,例如 np.array([123, 255, 0, ...])
,它将输出每个可能输出的分数,例如 np.array([0., 0., 0.3, 0., 0., 0.6, 0., 0., 0., 0.1])
(所以图像可能是数字5
(。
这是我对仿射层的实现:
class AffineLayer(object):
...
def backward(self, dy):
dx = np.dot(dy, self._W.T)
self._dW = np.dot(self._x.T, dy) # Question related part
self._db = np.sum(dy, axis=0)
dx = dx.reshape(self._original_x_shape)
return dx
...
以下是一些解释:
-
self._W
是权重矩阵。 - 这里关注的部分是
self._dW = np.dot(self._x.T, y) # Question related part
. 此行派生自相等:
X * W + B = Y
(N,2) matrix product (2,3) (1,3) (N,3).
符号
(2,)
来自numpy.array
等的X.shape
。为了简化我的问题,我选择了这些维度数字。
术语结束,现在问题来了:
通过一些数学(省略(,我们可以得出反向传播中使用的等式,(因此代码中使用了
self._dW = np.dot(self._x.T, y)
(:
d L T d L
--- == X * ---
d W d Y
(2,3) (2,N) * (N,3).
注意,无论我怎么调整
N
,也就是批次的大小,dL/dW
的维数,L权重矩阵的部分导数,都不会改变,总是(2,3)
。这是否意味着这些
N
批次的总效果被合并/浓缩到dL/dW
中?这与我将如何实现输出层有关,例如softmax交叉熵层作为最后一层。我目前的结论是,N
批次意味着进行反向传播N
次,并且需要将梯度dL/dW
除以N
来平均/摊销该批次的总效果。但现在看来,我只需要做一次,划分应该是"第一步"。
编辑:
我还找到了似乎在最后一步划分它的版本 mnielsen/neural-networks-and-deep-learning - GitHub,供参考。
由于softmax交叉熵层类是网络的最后一层,因此在反向传播中,它将成为我上面提到的"第一步":
class SoftmaxCrossEntropy(object):
...
def backward(self, dout=1):
batch_size = self._t.shape[0]
# one-hot
if self._t.size == self._y.size:
dx = (self._y - self._t) / batch_size # <-- why divided by N here?
else: # not one-hot
dx = self._y * 1
dx[np.arange(batch_size), self._t] -= 1
dx = dx / batch_size # <-- why divided by N here?
return dx
...
由于第 i是否意味着这N批输入的效果被组合/压缩到dW中?
行X
是与第 i 个展平图像相关的一维数组。如果我将X
转置为
T
X ,
,则它是表示这些拼合图像的列。如果N
增加,尽管
结果(dW
(的维度不会改变,计算每个元素的中间步骤
T d L
dW = X * ---
d Y ,
增加,这意味着
N
dW = Sum ( pixel_info * class_scores_deriv. )
i,j n=1 i,n n,j ,
哪个N
是批次
大小。显然,每个class_scores_derivative_(n,j)
"加入"dW_(i,j)
的确定,但这意味着需要除以batch_size = N
,因为上面的总和不是该批次的平均效应,而是我需要的是dW
表示该批次的平均影响。如果我将class_scores_deriv.
的每个元素相除,即行dx = (self._y - self._t) / batch_size
,则
N 1
Sum ( pixel_info * --- class_scores_deriv. )
n=1 i,n N n,j
1 N
= --- Sum ( pixel_info * class_scores_deriv. )
N n=1 i,n n,j
1
= --- dW
N ,
这是我想要的真正dW
。
所以答案(我希望(应该是
整个批次确定 dW,但要压缩它,需要
SoftmaxCrossEntropy::backward(self, dout=1)
的划分。