实施一般反向传播
Implementing general back-propagation
我正在尝试为具有任意激活函数的全连接层实现反向传播方法。我理解算法背后的一般思想和数学,但我在理解矢量化形式时遇到了困难...
我需要帮助了解元素的预期尺寸
已知尺寸:
- 输入 - self.X 是大小 (N,128)
- 重量 - self.W 尺寸 (128,10)
- 偏差 - self.b 是大小 (128,10)
- 输出 - self.y 是大小 (N,10)
- 线性输出(激活前)- self.z 是大小 (N,10)
未知尺寸:
对于 N=1(示例数)
- dy - 下一层的渐变 - 应该是多少?
- dz - 激活函数的导数 - 它的大小应该是多少?
- self.d - 当前层的渐变 - 应该是多少?
这是我的代码:
def backward(self, dy):
if self.activator == 'relu':
dz = np.zeros((self.z.shape[0], self.z.shape[1]))
dz[self.z>0] = 1
elif self.activator == 'sigmoid':
dz = self.z * (1 - self.z)
elif self.activator == 'soft-max':
s = self.z.reshape(-1, 1)
dz = np.diagflat(s) - np.dot(s, s.T)
elif self.activator == 'none':
dz = 1
self.d = np.dot((dz * dy), self.W.T) # the error of the layer
self.W_grad = np.dot(self.X.T, dy) # The weight gradient of the layer
self.b_grad = np.sum(dy, axis=0).reshape(1, -1) # The bias gradient of the layer
我相信,您的代码中有一点混乱:您写的 self.z
是线性输出 before 激活,但出于某种原因用它来计算你称之为 dz
的激活导数。它应该使用激活值。然后,假设您计算了该值(我称它为 prime
不与我的另一个 dz
混合),试试这个:
dz = dy * prime
dW = np.dot(dz, self.z.T)
db = np.sum(dz, axis=1, keepdims=True)
d = np.dot(self.W.T, dz)
几个错误:
self.b
的大小应该是 self.b is size (10, )
而不是 (128, 10)
(因为偏差是按单位计算的,而不是按单位对计算的)。
self.W_grad
应该是 np.dot(self.X.T, (dz * dy))
,而不是 np.dot(self.X.T, dy)
。 self.b_grad
相同 - 应该是 np.sum(dz * dy, axis=0)
至于剩下的
dy := dL/dy
应该是 (N, 10)
,因为它包含关于 y 中每个元素的损失梯度。
dz := df(z)/d(z)
对于元素激活函数应该是 (N, 10)
,因为 dz[i]
包含 df(z[i])/dz[i]
。
self.d := dL/dX
应该是 (N, 128)
因为它包含关于 X 中每个元素的损失梯度。
我正在尝试为具有任意激活函数的全连接层实现反向传播方法。我理解算法背后的一般思想和数学,但我在理解矢量化形式时遇到了困难...
我需要帮助了解元素的预期尺寸
已知尺寸:
- 输入 - self.X 是大小 (N,128)
- 重量 - self.W 尺寸 (128,10)
- 偏差 - self.b 是大小 (128,10)
- 输出 - self.y 是大小 (N,10)
- 线性输出(激活前)- self.z 是大小 (N,10)
未知尺寸: 对于 N=1(示例数)
- dy - 下一层的渐变 - 应该是多少?
- dz - 激活函数的导数 - 它的大小应该是多少?
- self.d - 当前层的渐变 - 应该是多少?
这是我的代码:
def backward(self, dy):
if self.activator == 'relu':
dz = np.zeros((self.z.shape[0], self.z.shape[1]))
dz[self.z>0] = 1
elif self.activator == 'sigmoid':
dz = self.z * (1 - self.z)
elif self.activator == 'soft-max':
s = self.z.reshape(-1, 1)
dz = np.diagflat(s) - np.dot(s, s.T)
elif self.activator == 'none':
dz = 1
self.d = np.dot((dz * dy), self.W.T) # the error of the layer
self.W_grad = np.dot(self.X.T, dy) # The weight gradient of the layer
self.b_grad = np.sum(dy, axis=0).reshape(1, -1) # The bias gradient of the layer
我相信,您的代码中有一点混乱:您写的 self.z
是线性输出 before 激活,但出于某种原因用它来计算你称之为 dz
的激活导数。它应该使用激活值。然后,假设您计算了该值(我称它为 prime
不与我的另一个 dz
混合),试试这个:
dz = dy * prime
dW = np.dot(dz, self.z.T)
db = np.sum(dz, axis=1, keepdims=True)
d = np.dot(self.W.T, dz)
几个错误:
self.b
的大小应该是self.b is size (10, )
而不是(128, 10)
(因为偏差是按单位计算的,而不是按单位对计算的)。self.W_grad
应该是np.dot(self.X.T, (dz * dy))
,而不是np.dot(self.X.T, dy)
。self.b_grad
相同 - 应该是np.sum(dz * dy, axis=0)
至于剩下的
dy := dL/dy
应该是 (N, 10)
,因为它包含关于 y 中每个元素的损失梯度。
dz := df(z)/d(z)
对于元素激活函数应该是 (N, 10)
,因为 dz[i]
包含 df(z[i])/dz[i]
。
self.d := dL/dX
应该是 (N, 128)
因为它包含关于 X 中每个元素的损失梯度。