我是深度学习的初学者。我目前正在努力使用反向传播算法。我在网上找到了这个带有S形激活函数的简单神经网络反向传播的代码。
#Step 1 Collect Data
x = np.array([[0,0,1], [0,1,1], [1,0,1], [1,1,1]])
y = np.array([[0], [1], [1], [0]])
#Step 2 build model
num_epochs = 60000
#initialize weights
syn0 = 2np.random.random((3,4)) - 1
syn1 = 2np.random.random((4,1)) - 1
def 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]
的向量作为成本函数的局部梯度吗?我假设它使用分析梯度。
答案 0 :(得分:0)
我认为此代码来自此处:http://iamtrask.github.io/2015/07/12/basic-python-network/
每一步都有很好的解释。
此处的成本函数是实际值和预期值之间的差异:
k2_error = y - k2
因此我们将它乘以激活函数的导数。
答案 1 :(得分:0)
您可以在编写时使用k2_error
。我测试了你的代码(在进行格式化更改之后)并确认它最小化了绝对误差,这与k2_error
(表示算法中的表面但不是实际的梯度下降目标)不同。 k2_delta = k2_error*nonlin(k2, deriv=True)
因为该算法最小化绝对误差而不是k2_error
。这是如何工作的:
k2_error
与k2
的输入之间的关系
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
y
和k2
更接近(最小化绝对误差),我们需要使误差更大/更积极。我们从第一部分就知道,我们可以通过推送k2
向下的输入来实现这一点(k2_error
的输入减少时k2
增加。案例2:y
> k2
,表示k2_error
> 0
y
和k2
更接近(最小化绝对误差),我们需要使误差更小/更负。我们从第一部分知道,我们可以通过推送k2
向上的输入来实现此目的(当k2_error
的输入增加时k2
减少。)总之,如果k2_error
为负(案例1),我们通过推送k2
的输入来最小化绝对错误。如果k2_error
为正(案例2),我们通过推动k2
的输入来最小化绝对错误。
k2_delta
我们现在知道k2_error
的梯度下降最小化总是希望推动k2
的输入,但这只会在y
>时最小化绝对误差。 k2
(案例2来自上文)。在案例1中,推送k2
的输入将增加绝对错误 - 因此我们在k2
的输入处修改渐变,称为k2_delta
每当我们面对案例1时,通过翻转它的符号。案例1意味着k2_error
< 0,这意味着我们可以通过将k2_delta
乘以k2_error
来翻转渐变的符号!使用此翻转意味着当我们看到案例1时,渐变下降想要将k2
的输入向下推而不是向上(我们强制梯度下降以放弃其默认行为)。
总而言之,只有当我们面对案例1时,使用k2_delta = k2_error*nonlin(k2, deriv=True)
翻转通常渐变的符号,这确保我们始终最小化绝对错误(而不是最小化k2_error
)。 / p>
重要提示
您的算法通过添加负梯度来修改权重。通常,梯度下降通过减去梯度来修改权重。添加负梯度是一回事,但它确实使我的答案复杂化了。例如,输入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
变小时将权重移动较小的数量。