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

2019-07-26 16:45:58 浏览数 (1)

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

很多的论文依然采用了原始的梯度下降算法而不采用更高级的算法,今天就以一个实践例子来给大家展示一下各类算法的比较,所有内容参考文章【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学习率不敏感。

0 人点赞