查看原文
其他

【模型训练】SGD的那些变种,真的比SGD强吗

言有三 有三AI 2019-12-26

言有三


毕业于中国科学院,计算机视觉方向从业者,有三工作室等创始人


作者 | 言有三

编辑 | 言有三

深度学习框架目前基本上都是使用梯度下降算法及其变种进行优化,通常意义上大家会认为原始的梯度下降算法是最弱的,但事实上并非如此。


很多的论文依然采用了原始的梯度下降算法而不采用更高级的算法,今天就以一个实践例子来给大家展示一下各类算法的比较,所有内容参考文章【An overview of gradient descent optimization algorithms】。

01


梯度下降算法

本文目标不是为了从零开始讲清楚优化算法,所以有些细节和基础就略过。


梯度下降算法,即通过梯度的反方向来进行优化,批量梯度下降(Batch gradient descent)用公式表述如下:

写成伪代码如下:

for i in range(nb_epochs):

    params_grad = evaluate_gradient(loss_function, data, params) 

    params = params - learning_rate * params_grad

上面的梯度下降算法用到了数据集所有的数据,这在解决实际问题时通常是不可能,想想imagenet1000有100G以上的图像,内存装不下,速度也很慢。


我们需要在线能够实时计算,于是一次取一个样本,就有了随机梯度下降(Stochastic gradient descent),简称sgd


公式如下:

写成伪代码如下:

for i in range(nb_epochs): 

    np.random.shuffle(data)

    for example in data:

        params_grad = evaluate_gradient(loss_function , example , params) 

        params = params - learning_rate * params_grad

sgd方法缺点很明显,梯度震荡,所以就有了后来大家常用的小批量梯度下降算法(Mini-batch gradient descent)

伪代码如下:

for i in range(nb_epochs): 

    np.random.shuffle(data)
    for batch in get_batches(data, batch_size=50):

        params_grad = evaluate_gradient(loss_function, batch, params) 

        params = params - learning_rate * params_grad

下面我们要形成共识,说sgd算法,实际上指的就是mini-batch gradient descent算法,没有人会去一次拿整个数据集或者一个样本进行优化。


当然还是要总结一下SGD算法的毛病。

(1)学习率大小和策略选择困难,想必动手经验丰富的自然懂。

(2)学习率不够智能,对所有参数一视同仁。

(3)同时面临局部极值和鞍点的问题。

可能有同学不知道鞍点怎么回事,简单来说,它就是在某一些方向梯度下降,另一些方向梯度上升,形状似马鞍,抄来一张图如下,红点就是鞍点

02


梯度下降方法改进

1.1 动量法                  

改进方法那么多,我觉得真正最有用的就是它。


前面说了梯度下降算法是按照梯度的反方向进行参数更新,但是刚开始的时候梯度不稳定呀,方向改变是很正常的,梯度就是抽疯了似的一下正一下反,导致做了很多无用的迭代。


而动量法做的很简单,相信之前的梯度如果梯度方向不变,就越发更新的快,反之减弱当前梯度。

画成图就是这样。

效果对比就这意思。

1.2 nesterov动量法                  

仍然是动量法,只是它要求这个下降更加智能。


既然动量法已经把前一次的梯度和当前梯度融合,那何不更进一步,直接先按照前一次梯度方向更新一步将它作为当前的梯度,看下面的式子就明白了。

如上图,自己领会。

nesterov的好处就是,当梯度方向快要改变的时候,它提前获得了该信息,从而减弱了这个过程,再次减少了无用的迭代。


1.3 Adagrad法                  

思路很简单,不同的参数是需要不同的学习率的,有的要慢慢学,有的要快快学,所以就给了一个权重咯,而且是用了历史上所有的梯度幅值。

1.4 Adadelta与Rmsprop                 

adagrad用了所有的梯度,问题也就来了,累加的梯度幅值是越来越大的。导致学习率前面的乘因子越来越小,后来就学不动了呀。


adadelta就只是动了一丢丢小心思,只累加了一个窗口的梯度,而且计算方法也更有效。

并且,将学习率用前一时刻参数的平方根来代替,最终更新算法变成了这样。

γ变成0.9,就是RMSprop方法了,这个方法在Hinton的课程中使用的,没有发表成论文,毕竟有adadelta了,没有发表必要。与adadelta另一个不同是还是需要学习率的,建议0.001


1.5 adam法                  

最后就是这个adam算法,作为最晚出现的,当然是集大成者。


adam对梯度的一阶和二阶都进行了估计与偏差修正,使用梯度的一阶矩估计和二阶矩估计来动态调整每个参数的学习率。

看出来了吧,与adadelta和rmsprop如出一辙,与momentum sgd也颇为相似。上面的式子根据梯度对参数更新的幅度进行了动态调整,所以adam对学习率没有那么敏感。


1.6 adamax 

将adam使用的二阶矩变成更高阶,就成了adamax算法。

1.7 nadam法                  

nag加上adam,就成了nadam方法,即带有动量项的adam,所以形式也很简单,如下,可以将其分别与adam算法和nag算法的式子比较看看。

说了这么多,对上面各种方法从一个鞍点开始优化,表现如何的预期效果图如下。

理论上,就是上面这样的。文章作者会告诉你对于数据稀疏的问题,用自适应学习率算法就好了,而且使用人家推荐的参数就好。其中,adam会最佳。

03

各种方法表现究竟如何

上面说了这么多理论,分析起来头头是道,各种改进版本似乎各个碾压SGD算法,然而根据笔者经验,仔细调优后的SGD算法绝对吊打其他算法


实验结果看下图,基础任务模型和数据集上次已经说过,此处不再赘述。

所有方法都采用作者们的默认配置,并且进行了比较,不好的结果就不拿出来了。


  • nesterov方法,与sgd算法同样的配置。

  • adam算法,m1=0.9,m2=0.999,lr=0.001。

  • rms算法,rms_decay=0.9,lr=0.001。

  • adagrad,adadelta学习率不敏感。


怎么着,好像都不如SGD算法呀。为什么呢?留言讨论吧。


如果想了解更多,欢迎关注知乎。


有三AI学院“济”划最后一个星期,明年就不会有了,寒冬已至。

有三AI“【济】划”,从图像基础到深度学习


如果想加入我们,后台留言吧

转载后台联系,侵权必究


微信

Longlongtogo

公众号内容

1 图像基础|2 深度学习|3 行业信息


往期精选

  • 不告诉你

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存