首先看一个简单的梯度下降的例子:
weight = 0.5
goal_pred = 0.8
input = 0.5
for iteration in range(20):
pred = input * weight
error = (pred - goal_pred) ** 2
delta = pred - goal_pred
weight_delta = delta * input
weight = weight - weight_delta
print("Error:" + str(error) + " prediction:" + str(pred))
# 输出如下:
Error:0.30250000000000005 prediction:0.25
Error:0.17015625000000004 prediction:0.3875
Error:0.095712890625 prediction:0.49062500000000003
Error:0.05383850097656251 prediction:0.56796875
Error:0.03028415679931642 prediction:0.6259765625
Error:0.0170348381996155 prediction:0.669482421875
Error:0.00958209648728372 prediction:0.70211181640625
Error:0.005389929274097089 prediction:0.7265838623046875
Error:0.0030318352166796153 prediction:0.7449378967285156
Error:0.0017054073093822882 prediction:0.7587034225463867
Error:0.0009592916115275371 prediction:0.76902756690979
Error:0.0005396015314842384 prediction:0.7767706751823426
Error:0.000303525861459885 prediction:0.7825780063867569
Error:0.00017073329707118678 prediction:0.7869335047900676
Error:9.603747960254256e-05 prediction:0.7902001285925507
Error:5.402108227642978e-05 prediction:0.7926500964444131
Error:3.038685878049206e-05 prediction:0.7944875723333098
Error:1.7092608064027242e-05 prediction:0.7958656792499823
Error:9.614592036015323e-06 prediction:0.7968992594374867
Error:5.408208020258491e-06 prediction:0.7976744445781151
上述代码使用简单的线性公式和均方差损失函数进行演示,在上述代码中我们没有使用学习率alpha
,根据输出可以看到,在合适输入和权重前提下,所使用的模型的损失函数能够不断下降。
我们现在改变输入,破坏梯度下降;我们把input从1.1改为2,看看上述代码会输出什么结果:
weight = 0.5
goal_pred = 0.8
input = 2
for iteration in range(20):
pred = input * weight
error = (pred - goal_pred) ** 2
delta = pred - goal_pred
weight_delta = delta * input
weight = weight - weight_delta
print("Error:" + str(error) + " prediction:" + str(pred))
# 代码输出如下
Error:0.03999999999999998 prediction:1.0
Error:0.3599999999999998 prediction:0.20000000000000018
Error:3.2399999999999984 prediction:2.5999999999999996
Error:29.159999999999986 prediction:-4.599999999999999
Error:262.4399999999999 prediction:16.999999999999996
Error:2361.959999999998 prediction:-47.79999999999998
Error:21257.639999999978 prediction:146.59999999999994
Error:191318.75999999983 prediction:-436.5999999999998
Error:1721868.839999999 prediction:1312.9999999999995
Error:15496819.559999991 prediction:-3935.799999999999
Error:139471376.03999993 prediction:11810.599999999997
Error:1255242384.3599997 prediction:-35428.59999999999
Error:11297181459.239996 prediction:106288.99999999999
Error:101674633133.15994 prediction:-318863.79999999993
Error:915071698198.4395 prediction:956594.5999999997
Error:8235645283785.954 prediction:-2869780.599999999
Error:74120807554073.56 prediction:8609344.999999996
Error:667087267986662.1 prediction:-25828031.799999986
Error:6003785411879960.0 prediction:77484098.59999996
Error:5.403406870691965e+16 prediction:-232452292.5999999
通过观察上面的输出,我们发现预测的结果爆炸了!它们从负数变为正数,又从正数变为负数,来回往复,但每一步都离真正的答案越来越远。换句话说,对权重的每次更新都会造成过度修正。
到底发生了什么?误差的激增是由于输入变大了。再回顾一下我们更新权重的方法: w e i g h t = w e i g h t − ( i n p u t ∗ ( p r e d − g o a l _ p r e d ) ) weight = weight - (input*(pred-goal\_pred)) weight=weight−(input∗(pred−goal_pred))
如果输入足够大,即使误差很消息,也会使权重的增量很大。当权重增量很大而误差的量很小时,网络会桥枉过正。如果新的误差更大,网络就会尝试更多地纠正错误。这就导致我们上面看到的现象,称为发散。(有时候,神经网络的输出会爆炸,具体原因也类似)
对于上面的发散现象,我们的解决办法是将权值的增量乘以一个系数,让它变得更小。大多数情况下,这个方法表现为将权值增量乘于一个介于0和1之间的实数,称为 α ( a l p h a ) \alpha (alpha) α(alpha)。请注意,这种方法不会对核心问题产生任何影响——也就是说输入还是那个较大的值。同时也会减少那些不太大的输入所对应的权重增量。
即使最先进的神经网络,合适的alpha值也常常是靠猜测来找到的。随着时间的推移,我们会看到误差的变换,如果它逐渐开始发散(上升),那么alpha值就太高了,我们需要将其调低一些。如果学习进展太慢,那么alpha值太低,我们需要将它调高一点。
参考来源
- 《深度学习图解》 —— [美]安德鲁·特拉斯克