关于反向传播中 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)

你是对的 - 看起来作者犯了一个错误。我将解释:当网络完成前向传递(所有激活 + 损失)时,您必须使用梯度下降根据损失函数最小化权重。为此,您需要损失函数对每个权重矩阵的偏导数。

我继续之前的一些符号:损失是 LA 是激活(又名 sigmoid),Z 表示净输入,换句话说,[= 的结果13=]。数字是索引,所以 A1 表示第一层的激活。

您可以使用链式法则在网络中向后移动,并将权重表示为损失的函数。要开始向后传递,首先要获得关于最后一层激活的损失的导数。这是dL/dA2,因为第二层是最后一层。要更新第二层的权重,我们需要完成dA2/dZ2dZ/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))