梯度下降-Momentum


总结:
梯度下降算法中,学习率太大,函数无法收敛,甚至发散,如下图。学习率足够小,理论上是可以达到局部最优值的(非凸函数不能保证达到全局最优),但学习率太小却使得学习过程过于缓慢,合适的学习率应该是能在保证收敛的前提下,能尽快收敛。对于深度网络中,参数众多,参数值初始位置随机,同样大小的学习率,对于某些参数可能合适,对另外一些参数可能偏小(学习过程缓慢),对另外一些参数可能太大(无法收敛,甚至发散),而学习率一般而言对所有参数都是固定的,所以无法同时满足所有参数的要求。通过引入Momentum可以让那些因学习率太大而来回摆动的参数,梯度能前后抵消,从而阻止发散。
 
改进:不能的参数,设置不同的学习率??Nesterov算法...
怎么避免局部最优??
                                            
 
 
作者:冯超
链接:https://zhuanlan.zhihu.com/p/21475880
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

为了保证完整性,今天再扯一下另外一个在梯度下降中十分重要的东西,那就是冲量——momentum。

这是一个十分神秘的变量,我也只能以最简单的方式理解它,于是在这里班门弄斧了。正如它的中文名字一样,在优化求解的过程中,冲量扮演了对之前优化量的持续发威的推动剂。一个已经完成的梯度+步长的组合不会立刻消失,只是会以一定的形式衰减,剩下的能量将继续发挥余热。我们先不加解释的给出基于冲量的梯度下降的代码:

def momentum(x_start, step, g, discount = 0.7):   
    x = np.array(x_start, dtype='float64')
    pre_grad = np.zeros_like(x)
    for i in range(50):
        grad = g(x)
        pre_grad = pre_grad * discount + grad
        x -= pre_grad * step
        
        print '[ Epoch {0} ] grad = {1}, x = {2}'.format(i, grad, x)
        if abs(sum(grad)) < 1e-6:
            break;
    return x
可以看出这个算法和之前的梯度下降法相比,唯一不同的就是多了一个pre_grad*discount,这就是冲量发挥余热的地方。

那么冲量究竟有什么作用呢?今天主要扯它其中的一个作用,那就是帮助你穿越“山谷”。怎么来理解穿越“山谷”呢?先来一个待优化函数。这次的问题相对复杂些,是一个二元二次函数:

def f(x):
    return x[0] * x[0] + 50 * x[1] * x[1]
def g(x):
    return np.array([2 * x[0], 100 * x[1]])
xi = np.linspace(-200,200,1000)
yi = np.linspace(-100,100,1000)
X,Y = np.meshgrid(xi, yi)
Z = X * X + 50 * Y * Y

上面这个函数在等高线图上是这样的:

其中中心的蓝色点表示了最优值。我们根据这个图发挥下想象,这个函数在y轴十分陡峭,在x轴相对平缓些。好了话说完我们赶紧拿朴素梯度下降来尝试下:

gd([150,75], 0.016, g)

经过50轮的迭代,他的优化过程图如下所示:

可以看出我们从某个点出发,整体趋势向着最优点前进,这个是没有问题的,但是前进的速度似乎有点乏力,是不是步长又设小了?有了之前的经历,这一回我们在设置步长时变得小心了许多:

res, x_arr = gd([150,75], 0.019, g)
contour(X,Y,Z, x_arr)

好像成效不是很明显啊,而且优化的过程中左右来回抖是怎么回事?看着这个曲线让我想起了一个极限运动:

(来自网络,如有侵权立即删除)

没错,其实算法眼中的这个函数很这张图很像,而算法也果然没有让大家“失望”,选择了一条艰难的道路进行优化——就像从一边的高台滑下,然后滑到另一边,这样艰难地前进。没办法,这就是梯度下降法。在它的眼中,这样走是最快的,而事实上,每个优化点所对应的梯度方向也确实是那个方向。

大神们这时可能会聊起特征值的问题,关于这些问题以后再说。好吧,现在我们只能继续挑步长,说不定步长再大点,“滑板少年”还能再快点呢!

res, x_arr = gd([150,75], 0.02, g)
contour(X,Y,Z, x_arr)

好吧……我们的滑板少年已经彻底玩脱了……这已经是我们能设的最大的步长了(上一次关于步长和函数之间的关系在这里依然受用),再设大些我们的滑板少年就飞出去了。对于这个问题,由于两个坐标轴方向的函数属性不同,为了防止在优化的过程中发散,步长只能够根据最陡峭的方向设定。当然,解决快速收敛这个问题还有其他的办法,这里我们看看冲量如何搞定这位滑板少年。

很自然地,我们在想,要是少年能把行动的力量集中在往前走而不是两边晃就好了。这个想法分两个步骤:首先是集中力量向前走,然后是尽量不要在两边晃。这时候,我们的冲量就闪亮登场了。我们发现滑板少年每一次的行动只会在以下三个方向进行:

  • 沿-x方向滑行
  • 沿+y方向滑行
  • 沿-y方向滑行

我们可以想象到,当使用了冲量后,实际上沿-y和+y方向的两个力可以相互抵消,而-x方向的力则会一直加强,这样滑板少年会在y方向打转,但是y方向的力量会越来越小,但是他在-x方向的速度会比之前快不少!

好了,那我们看看加了冲量技能的滑板少年的实际表现:

momentum([150,75], 0.016, g)

总算没有让大家失望,尽管滑板少年还是很贪玩,但是在50轮迭代后,他还是来到了最优点附近。可以说是基本完成了我们的任务吧。当然由于冲量的问题,前面几轮迭代他在y轴上玩得似乎比以前还欢乐,这个问题我们后面会提。但不管怎么说,总算完成目标了。

后来,又有高人发明了解决前面冲量没有解决的问题的算法,干脆不让滑板少年愉快地玩耍了,也就是传说中的Nesterov算法。这里就不细说了,有时间详细聊下。直接给出代码和结果:

def nesterov(x_start, step, g, discount = 0.7):   
    x = np.array(x_start, dtype='float64')
    pre_grad = np.zeros_like(x)
    for i in range(50):
        x_future = x - step * discount * pre_grad
        grad = g(x_future)
        pre_grad = pre_grad * 0.7 + grad 
        x -= pre_grad * step
        
        print '[ Epoch {0} ] grad = {1}, x = {2}'.format(i, grad, x)
        if abs(sum(grad)) < 1e-6:
            break;
    return x
nesterov([150,75], 0.012, g)

好了,滑板少年已经哭晕在厕所……

费了这么多话,我们总算把穿越“山谷”这件事情说完了,下面还要说一个数值上的事情。在CNN的训练中,我们的开山祖师已经给了我们冲量的建议配置——0.9(刚才的例子全部是0.7),那么0.9的冲量有多大量呢?终于要来点公式了……

我们用G表示每一轮的更新量,g表示当前一步的梯度量(方向*步长),t表示迭代轮数,表示冲量的衰减程度,那么对于时刻t的梯度更新量有:





那么我们可以计算下对于梯度g0对从G0到GT的总贡献量为


我们发现它的贡献是一个等比数列,如果=0.9,那么跟据等比数列的极限运算方法,我们知道在极限状态下,它一共贡献了自身10倍的能量。如果=0.99呢?那就是100倍了。

那么在实际中我们需要多少倍的能量呢?

本文相关代码详见:https://github.com/hsmyy/zhihuzhuanlan/blob/master/momentum.ipynb

等比数列的极限运算方法,我们知道在极限状态下,它一共贡献了自身10倍的能量。如果 =0.99呢?那就是100倍了。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
神经网络中常用的梯度下降算法包括批量梯度下降(BGD),随机梯度下降(SGD),Mini-batch梯度下降,Momentum梯度下降,RMSProp梯度下降和Adam梯度下降。 - 批量梯度下降(BGD)是最基本的梯度下降算法,它在每次迭代中计算所有训练样本的梯度,并取平均值作为更新梯度的方向[2]。 - 随机梯度下降(SGD)是在每次迭代中只使用一个训练样本来计算梯度和更新参数,这样可以大大降低计算量,但可能会导致参数更新的不稳定性。 - Mini-batch梯度下降是在每次迭代中使用一个小批量的训练样本来计算梯度和更新参数,它是批量梯度下降和随机梯度下降的折中方案,可以兼顾计算效率和参数更新稳定性。 - Momentum梯度下降是在梯度更新中引入了动量项,它可以加速梯度下降的速度,并且可以帮助跳出局部极小值。 - RMSProp梯度下降是在Momentum梯度下降的基础上加以改进的,它通过引入一个衰减系数来调整历史梯度的权重,以减少梯度更新的摆动程度。 - Adam梯度下降是结合了Momentum和RMSProp的优点,它适用于大多数神经网络模型,并且能够自适应地调整学习率,同时兼顾了梯度下降的速度和参数更新的稳定性。 总结起来,批量梯度下降适用于小数据集,随机梯度下降适用于大数据集,而Mini-batch梯度下降、Momentum梯度下降、RMSProp梯度下降和Adam梯度下降是在这两者之间的折中方案,可以根据具体问题选择合适的算法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值