关于反向传播中 sigmoid 导数输入的困惑
Confusion about sigmoid derivative's input in backpropagation
当使用链式法则计算成本函数相对于L
层权重的斜率时,公式变为:
d C0 / d W(L) = ... . d a(L) / d z(L) . ...
与:
z (L)
being the induced local field : z (L) = w1(L) * a1(L-1) + w2(L) * a2(L-1) * ...
a (L)
beeing the ouput : a (L) = & (z (L))
&
being the sigmoid function used as an activation function
注意L
是作为图层指标而不是索引
现在:
d a(L) / d z(L) = &' ( z(L) )
其中 &'
是 sigmoid 函数的导数
问题:
但是在 James Loy 写的关于用 python、
从头开始构建一个简单神经网络的这篇 post 中,他在进行反向传播时,没有将 z (L)
作为 &'
的输入来替换链式法则函数中的 d a(L) / d z(L)
。相反,他将 output = last activation of the layer (L)
作为 sigmoid 导数 &'
的输入
def feedforward(self):
self.layer1 = sigmoid(np.dot(self.input, self.weights1))
self.output = sigmoid(np.dot(self.layer1, self.weights2))
def backprop(self):
# application of the chain rule to find derivative of the loss function with respect to weights2 and weights1
d_weights2 = np.dot(self.layer1.T, (2*(self.y - self.output) * sigmoid_derivative(self.output)))
请注意,在上面的代码中,层 L
是层 2
,它是最后一层或输出层。
并且 sigmoid_derivative(self.output)
这是当前层的激活作为用作激活函数的 sigmoid 函数的导数的输入。
问题:
我们不应该使用这个 sigmoid_derivative(np.dot(self.layer1, self.weights2))
而不是这个 sigmoid_derivative(self.output)
吗?
您想对输出使用导数。在反向传播期间,我们仅使用权重来确定有多少误差属于每个权重,这样我们可以进一步将误差传播回各层。
教程中,sigmoid应用于最后一层:
self.output = sigmoid(np.dot(self.layer1, self.weights2))
根据你的问题:
Shouldn't we use this sigmoid_derivative(np.dot(self.layer1, self.weights2)) instead of this sigmoid_derivative(self.output)?
你不能做:
sigmoid_derivative(np.dot(self.layer1, self.weights2))
因为这里你试图在你还没有应用它的时候对 sigmoid 求导。
这就是你必须使用的原因:
sigmoid_derivative(self.output)
你是对的 - 看起来作者犯了一个错误。我将解释:当网络完成前向传递(所有激活 + 损失)时,您必须使用梯度下降根据损失函数最小化权重。为此,您需要损失函数对每个权重矩阵的偏导数。
我继续之前的一些符号:损失是 L
,A
是激活(又名 sigmoid),Z
表示净输入,换句话说,[= 的结果13=]。数字是索引,所以 A1
表示第一层的激活。
您可以使用链式法则在网络中向后移动,并将权重表示为损失的函数。要开始向后传递,首先要获得关于最后一层激活的损失的导数。这是dL/dA2
,因为第二层是最后一层。要更新第二层的权重,我们需要完成dA2/dZ2
和dZ/dW2
.
在继续之前,请记住第二层的激活是A2 = sigmoid(W2 . A1)
和Z2 = W2 . A1
。为清楚起见,我们将写为 A2 = sigmoid(Z2)
。将 Z2
视为自己的变量。因此,如果您计算 dA2/dZ2
,您将得到 sigmoid_derivative(Z2)
,即 sigmoid_derivative(W2 . A1)
或 sigmoid_derivative(np.dot(self.layer1, self.weights2))
。所以它不应该是 sigmoid_derivative(self.output)
因为 output
被 sigmoid 激活了。
原来是用了&( z(L) )
或者output
,只是为了适应sigmoid_derivative
的实现方式
这是sigmoid_derivative
的代码:
def sigmoid(x):
return 1.0/(1+ np.exp(-x))
def sigmoid_derivative(x):
return x * (1.0 - x)
sigmoid_derivative
的数学公式可以写成:&' (x) = &(x) * (1-&(x))
所以为了得到上面的公式,&(z)
而不是 z
被传递给 sigmoid_derivative
以便 return:&(z) * (1.0 - &(z))
当使用链式法则计算成本函数相对于L
层权重的斜率时,公式变为:
d C0 / d W(L) = ... . d a(L) / d z(L) . ...
与:
z (L)
being the induced local field :z (L) = w1(L) * a1(L-1) + w2(L) * a2(L-1) * ...
a (L)
beeing the ouput :a (L) = & (z (L))
&
being the sigmoid function used as an activation function
注意L
是作为图层指标而不是索引
现在:
d a(L) / d z(L) = &' ( z(L) )
其中 &'
是 sigmoid 函数的导数
问题:
但是在 James Loy 写的关于用 python、
从头开始构建一个简单神经网络的这篇 post 中,他在进行反向传播时,没有将 z (L)
作为 &'
的输入来替换链式法则函数中的 d a(L) / d z(L)
。相反,他将 output = last activation of the layer (L)
作为 sigmoid 导数 &'
def feedforward(self): self.layer1 = sigmoid(np.dot(self.input, self.weights1)) self.output = sigmoid(np.dot(self.layer1, self.weights2)) def backprop(self): # application of the chain rule to find derivative of the loss function with respect to weights2 and weights1 d_weights2 = np.dot(self.layer1.T, (2*(self.y - self.output) * sigmoid_derivative(self.output)))
请注意,在上面的代码中,层 L
是层 2
,它是最后一层或输出层。
并且 sigmoid_derivative(self.output)
这是当前层的激活作为用作激活函数的 sigmoid 函数的导数的输入。
问题:
我们不应该使用这个 sigmoid_derivative(np.dot(self.layer1, self.weights2))
而不是这个 sigmoid_derivative(self.output)
吗?
您想对输出使用导数。在反向传播期间,我们仅使用权重来确定有多少误差属于每个权重,这样我们可以进一步将误差传播回各层。
教程中,sigmoid应用于最后一层:
self.output = sigmoid(np.dot(self.layer1, self.weights2))
根据你的问题:
Shouldn't we use this sigmoid_derivative(np.dot(self.layer1, self.weights2)) instead of this sigmoid_derivative(self.output)?
你不能做:
sigmoid_derivative(np.dot(self.layer1, self.weights2))
因为这里你试图在你还没有应用它的时候对 sigmoid 求导。
这就是你必须使用的原因:
sigmoid_derivative(self.output)
你是对的 - 看起来作者犯了一个错误。我将解释:当网络完成前向传递(所有激活 + 损失)时,您必须使用梯度下降根据损失函数最小化权重。为此,您需要损失函数对每个权重矩阵的偏导数。
我继续之前的一些符号:损失是 L
,A
是激活(又名 sigmoid),Z
表示净输入,换句话说,[= 的结果13=]。数字是索引,所以 A1
表示第一层的激活。
您可以使用链式法则在网络中向后移动,并将权重表示为损失的函数。要开始向后传递,首先要获得关于最后一层激活的损失的导数。这是dL/dA2
,因为第二层是最后一层。要更新第二层的权重,我们需要完成dA2/dZ2
和dZ/dW2
.
在继续之前,请记住第二层的激活是A2 = sigmoid(W2 . A1)
和Z2 = W2 . A1
。为清楚起见,我们将写为 A2 = sigmoid(Z2)
。将 Z2
视为自己的变量。因此,如果您计算 dA2/dZ2
,您将得到 sigmoid_derivative(Z2)
,即 sigmoid_derivative(W2 . A1)
或 sigmoid_derivative(np.dot(self.layer1, self.weights2))
。所以它不应该是 sigmoid_derivative(self.output)
因为 output
被 sigmoid 激活了。
原来是用了&( z(L) )
或者output
,只是为了适应sigmoid_derivative
的实现方式
这是sigmoid_derivative
的代码:
def sigmoid(x): return 1.0/(1+ np.exp(-x)) def sigmoid_derivative(x): return x * (1.0 - x)
sigmoid_derivative
的数学公式可以写成:&' (x) = &(x) * (1-&(x))
所以为了得到上面的公式,&(z)
而不是 z
被传递给 sigmoid_derivative
以便 return:&(z) * (1.0 - &(z))