如何对使用Sigmoid激活函数的简单神经网络进行反向传播?

我是一名深度学习的初学者。目前正在努力理解反向传播算法。我在网上找到了一段关于使用Sigmoid激活函数的简单神经网络的反向传播代码。

#Step 1 Collect Datax = np.array([[0,0,1], [0,1,1], [1,0,1], [1,1,1]])y = np.array([[0], [1], [1], [0]])#Step 2 build modelnum_epochs = 60000#initialize weightssyn0 = 2np.random.random((3,4)) - 1 syn1 = 2np.random.random((4,1)) - 1def nonlin(x,deriv=False):    if(deriv==True): return x*(1-x)        return 1/(1+np.exp(-x))    for j in xrange(num_epochs): #feed forward through layers 0,1, and 2        k0 = x        k1 = nonlin(np.dot(k0, syn0))        k2 = nonlin(np.dot(k1, syn1))        #how much did we miss the target value?        k2_error = y - k2        if (j% 10000) == 0:            print "Error:" + str(np.mean(np.abs(k2_error)))        #in what direction is the target value?        k2_delta = k2_error*nonlin(k2, deriv=True)        #how much did each k1 value contribute to k2 error        k1_error = k2_delta.dot(syn1.T)        k1_delta= k1_error * nonlin(k1,deriv=True)        syn1 += k1.T.dot(k2_delta)        syn0 += k0.T.dot(k1_delta)

我无法理解这行代码:k2_delta = k2_error*nonlin(k2, deriv=True)。在计算局部梯度时,为什么使用k2_error乘以k2的导数。我们应该使用k2_error以外的其他东西吗?因为这个算法中的成本函数是绝对值,所以我应该使用一个[-1,1,1,-1]的向量作为成本函数的局部梯度吗?我假设这里使用的是解析梯度。


回答:

你可以按原样使用k2_error。我测试了你的代码(在进行格式调整后),并确认它最小化了绝对误差,这与k2_error(你算法中梯度下降的表面但非实际目标)不同。使用k2_delta = k2_error*nonlin(k2, deriv=True)是因为算法在最小化绝对误差而不是k2_error。这是如何运作的:

k2_errork2输入之间的关系

k2_error相对于k2的导数是-1。使用链式法则,k2_error相对于k2输入的导数是(-1)*(nonlin(k2, deriv=True))

因此:

  • k2_error相对于k2输入的导数总是负的。这是因为(nonlin(k2, deriv=True))总是正的。
  • 因此,k2_error的常规梯度下降最小化将始终希望将k2的输入向上推(使其更正)以使k2_error更负。

最小化绝对误差

对于k2_error = y-k2,有两种实际可能性,每种可能性都意味着不同的策略来最小化绝对误差(我们的真正目标)。(有一个不太可能的第三种可能性我们可以忽略。)

  • 情况1:y<k2,这意味着k2_error<0

    • 为了使yk2更接近(最小化绝对误差),我们需要使误差更大/更正。我们从第一部分知道,我们可以通过将k2的输入向下推来实现这一点(当k2的输入减少时,k2_error增加)。
  • 情况2:y>k2,这意味着k2_error>0

    • 为了使yk2更接近(最小化绝对误差),我们需要使误差更小/更负。我们从第一部分知道,我们可以通过将k2的输入向上推来实现这一点(当k2的输入增加时,k2_error减少)。

总结来说,如果k2_error为负(情况1),我们通过将k2的输入向下推来最小化绝对误差。如果k2_error为正(情况2),我们通过将k2的输入向上推来最小化绝对误差。

k2_delta的解释

我们现在知道,k2_error的梯度下降最小化将始终希望将k2的输入向上推,但这只有在y > k2(上面的情况2)时才会最小化绝对误差。在情况1中,将k2的输入向上推会增加绝对误差——所以我们通过在面对情况1时翻转其符号来修改k2输入处的梯度,这个梯度被称为k2_delta。情况1意味着k2_error<0,这意味着我们可以通过将k2_delta乘以k2_error来翻转梯度的符号!使用这种翻转意味着当我们看到情况1时,梯度下降希望将k2的输入向下推而不是向上推(我们强迫梯度下降放弃其默认行为)。

总结来说,使用k2_delta = k2_error*nonlin(k2, deriv=True)仅在面对情况1时翻转常规梯度的符号,这确保我们始终在最小化绝对误差(而不是最小化k2_error)。

重要说明

你的算法通过添加负梯度来修改权重。通常,梯度下降通过减去梯度来修改权重。添加负梯度是相同的事情,但这确实使我的回答有些复杂。例如,k2输入处的梯度实际上是k2_delta = k2_error*(-1)*nonlin(k2, deriv=True),而不是k2_delta = k2_error*nonlin(k2, deriv=True)

你可能想知道为什么我们使用k2_error而不是sign(k2_error),那是因为我们希望随着k2_error变小,权重移动的量也变小。

Related Posts

L1-L2正则化的不同系数

我想对网络的权重同时应用L1和L2正则化。然而,我找不…

使用scikit-learn的无监督方法将列表分类成不同组别,有没有办法?

我有一系列实例,每个实例都有一份列表,代表它所遵循的不…

f1_score metric in lightgbm

我想使用自定义指标f1_score来训练一个lgb模型…

通过相关系数矩阵进行特征选择

我在测试不同的算法时,如逻辑回归、高斯朴素贝叶斯、随机…

可以将机器学习库用于流式输入和输出吗?

已关闭。此问题需要更加聚焦。目前不接受回答。 想要改进…

在TensorFlow中,queue.dequeue_up_to()方法的用途是什么?

我对这个方法感到非常困惑,特别是当我发现这个令人费解的…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注