论文地址:https://arxiv.org/pdf/1609.04747.pdf
《An overview of gradient descent optimization algorithms》梯度下降优化算法综述是2017年收录于cs.LG的论文,文章深入浅出地介绍了当前主流的深度学习优化算法的原理和使用场景。
开发者常常将梯度下降优化器作为黑盒使用,对每一种具体方法的原理和优缺点不甚了解,此文旨在详述各种主流算法,便于开发者更好地使用优化算法。
梯度下降法的目的是最小化目标函数J(θ)(也叫误差函数/损失函数,它描述预测值和真实值之间的差距,该值越小说明模型越好),其中θ是模型参数,向目标函数梯度的相反方向更新模型参数∇θJ(θ);一般用η表示学习率,也就是按一定步长(程度)修改模型参数。调参过程犹如小球沿着目标函数所产生的表面坡度的方向往下山滚,直致到达一个山谷底部。
举个比较粗糙的例子,请大家领会精神:输入数据x经过模型参数θ计算出y’=2,而实际真实的y值为5,J(θ)=y-y’=5-2=3,于是向相反方向调整参数θ,即-3方向(使下一次计算的结果更靠近真实值),如果学习率为0.1,则调节-3*0.1,也就是每次只调一点点。
梯度下降法
Batch gradient descent(Vanilla gradient descent)
批量梯度下降是一种最简单的梯度下降方法,它用整个数据集的预测结果调整网络参数,公式如下:
每次更新参数需要计算所有数据,速度很慢,如果数据集很大,则会占用大量内存。使用这种方法不能随着新数据的加入逐步更新模型(在线学习online)。
对于凸误差曲面,该方法能使误差收敛到全局最小值,对于非凸误差曲面,则只能保证收敛到局部最小值。
Stochastic gradient descent(SGD)
随机梯度下降法,针对每一个实例计算误差,并修改参数,公式如下:
它是对上一方法的改进,支持在线学习,并在每一步更新模型,使模型快速训练,但是使用这种方法时模型对每个实例都非常敏感,特殊实例容易带偏模型。一方面,实例引发的波动可能使模型跳过皱褶,找到更好的局部最小值,另一方面,也造成了收敛中的不稳定,来回波动。实验证明,如果使用逐步缩减学习率的方法精调,它能达到与批量梯度下降一样的效果:对于非凸优化和凸优化,分别收敛到局部或全局最小值。
Mini-batch gradient descent
更进一步的方法是小批量梯度下降法,它结合了上述两者的优势,每次训练n个实例并更新参数,该方法是当前梯度下降的主流方法。
它既快速又能保持稳定收敛,mini-batch大小视数据集而定,一般使用4,8,16,256……
梯度下降的优化算法
上面介绍了基本的梯度下降方法,这些方法有时仍不能保证很好地收敛,可能存在以下问题:
- 不容易选择学习率,太小则收敛缓慢,太大又产生波动,甚至无法收敛。
- “Learning rate schedules”学习率表是一种调整学习率的方法,一般在训练的不同阶段选择不同的学习率,或者通过判断阈值调节学习率(比如当误差一段时间内不再变化,则降低学习率),但是这些条件也需要根据不同数据集事先定义,不能适应所有情况。
- 当数据比较稀疏,各种特征出现的频率不同时,最好能对不同的参数使用不同的学习率更新,如对较少出现的特征给予更大的更新幅度。
- 梯度下降法容易在非凸误差曲面上,陷入局部最优解,Dauphinet还提出了鞍点(saddle)问题:某点在一个维度向上倾斜,另一个维度向下倾斜。当该点被一个具有相同误差的平台所包围,梯度在所有维度上都接近于零。
下面介绍解决上述问题的一些常用方法。
动量Momentum
SGD遇到峡谷地带,常见的问题是,当一个维度比另一个维度倾斜更厉害时(这种情况在局部最优解附近很常见),它沿着斜坡两边震荡,向着最优解方向缓慢前进。如下图中(a)所示:
这是一个等高线图,假设颜色越深位置越低,图(a)延箭头方向收敛时,由于y方向上坡度更大,因此它在山坡两面斜坡上滚来滚去,虽然也向最低的中间洼地移动,但在x方向上变化非常缓慢。
Momentum动量方法在当前变化时也考虑了之前变化的方向,公式如下:
当前的变化vt由两部分组成,一部分是当前的误差,一部分是之前的变化vt-1,用参数γ设置它对当前变化的影响强度。如上图中b所示,当本次移动的方向与前一次一致时,加速移动(如在x方向),不一致时,减速移动(如在y方向),这样就加快了收敛,减少了波动。
Nesterov accelerated gradient (NAG,Nesterov加速梯度)
梯度下降就像是一个球从山上向下滚(最低点是最终目标),使用之前的算法时,球在每一步都不知道它下一步的方向。最好球能提前预知下一步,如果是向上滚,就将滚动速度降下来。
NAG提供了这样一种预测的方法,由于知道参数θ将前一步的vt−1计算在内,那么用θ−γvt−1
则可以估计下一步的参数,于是有:
如下图所示,其中蓝色线为简单的动量方案,其中左侧的短蓝线为误差引发的梯度变化,长蓝线为之前累积的梯度变化γvt−1,二者相加得到新的参数θ;棕线为先用当前θ和之前累积变化估计出下一步的参数,将它作为模型参数,计算误差并用于本次调参,最终实现的效果如绿色线所示。该方法改进了RNN等很多任务的性能。
以上两种方法都是在调参速度方面的优化。
Adagrad
Adagrad的主要贡献在于针对不同的参数使用不同的学习率,对于高频更新的参数使用较低的学习率,而对不常更新的参数使用较高的学习率,主要对稀疏的数据进行了优化(如自然语言处理中的生僻词),它还能提高SGD的鲁棒性,常用于训练大规模的神经网络。
其公式如下:
它将θ细化成第t步的各个参数θt,i,其中gt,i是误差引发的梯度变化,G是一个对角矩阵,其中ii是截至第t步之前梯度的平方和,e是为避免被除数是0而加入的平滑项。
该方法的主要优势是不需要手动调节学习率,一般使用0.01的学习率,再进一步的调整由模型完成。它的问题是在分母上积累了梯度的平方和,当积累得非常巨大时,学习率将变得很小导致后期的训练失效。
Adadelta
Adadelta是对Adagrad的改进,它将积累之前所有梯度变为设定一个时间窗口w,累积窗口之内的梯度,不是简单地求梯度平方和,而是递归地计算所有平方梯度的衰减平均值,其第t步的均值定义如下:
其中g表示梯度,γ用于控制前期梯度与当前梯度的比例。下面换一种写法,将参数变化写作∆θt:
它的分母刚好是梯度的平方根(root mean squared,RMS)。
作者注意到更新中的单位不匹配问题:更新应具有与参数相同的单位。为了实现这一点,他定义了另一个指数衰减平均值,这里更新的不是平方梯度而是平方参数:
同样也可以表示为平方根:
用之前的时间步更新该值,并用它代替了设定的学习率,最终产生如下公式。
使用Adadelta方法就无需再指定学习率。
RMSprop
RMSprop的也是为了解决Adagrad学习率衰减问题所做的改进。它与Adadelta非常相似。
它将学习率除以平方梯度的指数衰减平均值。
Adaptive Moment Estimation(Adam)
Adam自适应矩估计是另一种计算各个参数学习率的算法,可将其看作RMSprop(vt)与动量Momentum(mt)二者的结合。
它包含两个参数β1和β2,分别设定之前梯度与当前梯度对调参的贡献度,最终公式如下:
可以看到,它同时兼顾了之前的调参方向mt,以及之前参数调整的频率vt。
AdaMax
Adamax是Adam的一种变体,计算Adam的vt时,使用它的前项vt-1以及梯度的2范数。
将2范数推广到p范数,同时调整了β2的计算方法:
大值范数往往造成不稳定,这也是一般都使用1范数和2范数的原因,但当p趋近无穷时,p范数变成了取最大值操作,也能收敛到稳定的值。该方法的其它操作与Adam一致,只是将2范数变成了可以计算最大值的无穷范数,因此叫做AdaMax。
Nadam
Nadam类似于带有Nesterov动量的Adam,它在Adam中引入了Nesterov 加速效果。
从图中可以看到,各种不同算法的收敛情况:
图片来自论文中的链接如何选择优化器
如果输入数据是离散的,尽量选择自适应学习率算法(adaptive learning-rate),在使用默认值,不调参的情况下也能达到较好的学习效果,RMSprop, Adadelta, Adam都是非常相似的算法,Adam常常是默认的选项。
尽管自适应学习优化算法很方便,但仍有很多人选择SGD优化器,简单的SGD优化器往往能得到很好的调参效果,且便于控制优化过程,但是花费时间较长,且对鞍点处理不佳。
在使用Pytorch训练模型时,最常使用的是SGD和Adam两个优化器,其中SGD并不只是简单的SGD优化器,也支持设置动量,weight decay等等参数。大多数论文都使用SGD优化器训练模型。SGD和Adam就像是单反相机和全自动相机。
附加策略
打乱顺序
通常训练时,在每一次迭代训练(epoch)打乱数据的顺序是一个很好的方法;但对于某些高难度训练,也需要将数据按一定顺序逐步训练模型,这被称为Curriculum Learning课程训练。
批量规范化
为了便于训练,常使用零均值和单位方差初始化参数,随着网络训练,参数更新差异,使参数不再规范化,从而减缓了训练速度,网络越深训练时间越长,问题越明显。
批量规范化batch normalization(BN)可有效解决该问题,它根据每批训练数据做规范化,该操作也可以反向传播。加入了BN操作之后可以使用更大的学习率,并且可以更少的关注初值。BN有时还可实现正则化(regularizer)功能,减少Dropout的使用。
提前结束训练
在训练过程中,持续关注验证集上误差的变化,当误差不再变小时,可以提前结束训练。即节省了时间,也避免了模型过拟合。一般用程序实现这一功能。
梯度噪声
给梯度加入高斯分布的噪声:
并随着训练过程逐步减小σ
加入噪声增加了模型的鲁棒性,常用于训练深而复杂的网络,原因可能是它让模型跳出了局部最佳值,复杂网络常常使用该技巧。
网友评论