目录

写在前面

一、torch.optim.Adadelta

Adadelta代码

Adadelta算法解析

Adadelta总结

二、torch.optim.RMSprop

RMSprop代码

RMSprop算法解析

RMSprop总结

三、torch.optim.Adam(AMSGrad)

Adam代码

Adam算法解析

Adam总结

四、torch.optim.Adamax

Adamax代码

Adamax算法解析

Adamax总结

五、torch.optim.AdamW

AdamW代码

AdamW算法解析

        1.adam+L2正则化

        2.adam+权重衰减

AdamW总结

六、orch.optim.NAdam

NAdam代码

NAdam算法解析

NAdam总结

七、torch.optim.SparseAdam

SparseAdam代码


优化器系列文章列表

Pytorch优化器全总结(一)SGD、ASGD、Rprop、Adagrad

Pytorch优化器全总结(二)Adadelta、RMSprop、Adam、Adamax、AdamW、NAdam、SparseAdam

Pytorch优化器全总结(三)牛顿法、BFGS、L-BFGS 含代码

Pytorch优化器全总结(四)常用优化器性能对比 含代码

写在前面

        这篇文章是优化器系列的第二篇,也是最重要的一篇,上一篇文章介绍了几种基础的优化器,这篇文章讲介绍一些用的最多的优化器:Adadelta、RMSprop、Adam、Adamax、AdamW、NAdam、SparseAdam。这些优化器中Adadelta和RMSprop是对上一篇中Adagrad的优化;Adam结合了Momentum 和 RMSprop;Adamax、AdamW、NAdam又是对Adam的改进,可以看到优化器一步一步升级的过程,所以我们放在一篇文章中。

一、torch.optim.Adadelta

        该类实现 Adadelta 优化方法。Adadelta 是 Adagrad 的改进。Adadelta 分母中采用距离当前时间点比较近的累计项,这可以避免在训练后期,学习率过小。   

         论文地址:https://arxiv.org/pdf/1212.5701.pdf

         Pytorch说明文档:Adadelta — PyTorch 1.12 documentation

Adadelta代码

'''
params (iterable) – 待优化参数的iterable或者是定义了参数组的dict
rho (float, 可选) – 用于计算平方梯度的运行平均值的系数(默认:0.9)
eps (float, 可选) – 为了增加数值计算的稳定性而加到分母里的项(默认:1e-6)
lr (float, 可选) – 在delta被应用到参数更新之前对它缩放的系数(默认:1.0)
weight_decay (float, 可选) – 权重衰减(L2惩罚)(默认: 0)
'''
class torch.optim.Adadelta(params, lr=1.0, rho=0.9, eps=1e-06, weight_decay=0)

Adadelta算法解析

        为了解决AdaGrad算法中存在的缺陷,AdaGrad算法提出两点修改:

        1.为了解决AdaGrad多次迭代后,学习率将逐渐下降至0的问题,AdaGrad在一个窗口w中对梯度进行求和,而不是对梯度一直累加。因为存放 w 之前的梯度是低效的,所以可以用对先前所有梯度均值(使用RMS即均方根值实现)的一个指数衰减作为代替的实现方法。

参数更新公式如下:

        ​                (1)

        ​                                        (2)

         2.上式其实还是依赖于全局学习率的,但是作者做了一定处理,经过近似牛顿迭代法之后,不再需要全局学习率。以下为推导过程:

        首先根据牛顿法求解函数极值点:

        对于f(x)的泰勒展开式,若取到二阶来近似,则:

        ​        (3)

         两边对​求导,有:

        ​                (4)

        函数 gif.latex?f%28%5Ctheta%20%29​的极值点满足gif.latex?%7Bf%7D%27%28%5Ctheta%20%29%3D0​,代入上式中,有:

        ​                                                (5)

        由此得到牛顿法求解函数极值点的迭代式:

        ​                                                (6)

      以上为二阶情况,下面引申到高阶,而高阶的牛顿法迭代的步长为Hessian矩阵。AdaDelta算法正是采用了这种思想,采用Hessian矩阵的对角线近似Hessian矩阵。公式如下:

​                                (7)

 ​                                (8)

         而更新公式为:

​         (9)

        假设x附近的曲率是平滑的,则gif.latex?x_%7Bt+1%7D%20%3Dx%20_%7Bt%7D​,分子分母按照第一点修改种的方法进行处理,可以得到以下参数更新公式:

       ​        (10)

         其中为本次迭代的梯度,RMS为均方根。由于RMS永远为正,所以能保证更新的方向一直为梯度的负方向。分子作为一个加速项,作为动量在时间窗口w上积累先前的梯度。       

        最后给分子的gif.latex?%5Cbigtriangleup%20%5Ctheta​和分母的gif.latex?g_%7Bt%7D​加入动量:

​                        (11) 

​                                        (12)

  ​                   (13)

Adadelta总结

        Adadelta是对AdaGrad的改造,用梯度平方的指数加权平均代替了全部梯度的平方和,用更新量的平方的指数加权平均来动态得代替了全局的标量的学习率。

优点:

        a.对于每个维度,用梯度平方的指数加权平均代替了全部梯度的平方和,避免了后期更新时更新幅度逐渐趋近于0的问题

        b.用更新量的平方的指数加权平均来动态得代替了全局的标量的学习率,避免了对学习率的敏感

缺点:

        a.对 ϵ 很敏感,因为第一步的步长是 ​,小了的话,前期步长很小,大了的话,后期容易引起震荡。

        b.训练后期,反复在局部最小值附近抖动

推荐程度:可以试试。

二、torch.optim.RMSprop

        该类实现 RMSprop 优化方法(Hinton 提出),RMS 是均方根(root meam square)的意思。RMSprop 和 Adadelta 一样,也是对 Adagrad 的一种改进。RMSprop 采用均方根作为分母,可缓解 Adagrad 学习率下降较快的问题,并且引入均方根,可以减少摆动。    

         论文地址:https://arxiv.org/pdf/1308.0850v5.pdf

         Pytorch说明文档:RMSprop — PyTorch 1.12 documentation

RMSprop代码

'''
params (iterable) – 待优化参数的iterable或者是定义了参数组的dict
lr (float, 可选) – 学习率(默认:1e-2)
momentum (float, 可选) – 动量因子(默认:0),该参数的作用下面会说明。
alpha (float, 可选) – 平滑常数(默认:0.99)
eps (float, 可选) – 为了增加数值计算的稳定性而加到分母里的项(默认:1e-8)
weight_decay (float, 可选) – 权重衰减(L2惩罚)(默认: 0)
centered (bool, 可选) – 如果为True,计算中心化的RMSProp,并且用它的方差预测值对梯度进行归一化
'''
class torch.optim.RMSprop(params, lr=0.01, alpha=0.99, eps=1e-08, weight_decay=0, momentum=0, centered=False)

RMSprop算法解析

        RMSprop与Adadelta属于同一时期的作品,都是对Adagrad的优化,解决了Adagrad多次迭代后,学习率将逐渐下降至0的问题。RMSProp算法将AdaGrad的梯度平方和累改加为指数加权的移动平均,使得其在非凸设定下效果更好。设定参数:全局初始率 默认设为0.001,decay rate gif.latex?%5Crho​,默认设置为0.9,一个极小的常量  gif.latex?%5Cepsilon​,通常为10e-6,参数更新公式如下:

​                (14)

​             (15)

         可以看到式子(15)和Adadelta的(13)的分母是基本一样的(只是gif.latex?%5Cepsilon​的位置有所区别),两者虽然思想不一样,但是实现一样的,都是指数加权的移动平均,也算殊途同归了。

        RMSprop与AdaDelta的不同之处在分子,RMSprop还是用了全局学习率,而AdaDelta算法还维护一个额外的状态变量gif.latex?%5Cbigtriangleup%20%5Ctheta​,并且自动计算学习率。

        再说明一下torch.optim.RMSprop类中momentum参数的作用,式子(14)计算累计梯度平方的期望后,如果momentum!=0,式子(15)会变成如下形式:

​  (16)

RMSprop总结

        RMSprop算是Adagrad的一种发展,用梯度平方的指数加权平均代替了全部梯度的平方和,相当于只实现了Adadelta的第一个修改,效果趋于RMSprop和Adadelta二者之间。

优点:适合处理非平稳目标(包括季节性和周期性)——对于RNN效果很好

缺点:RMSprop依然依赖于全局学习率 

推荐程度:推荐!

三、torch.optim.Adam(AMSGrad)

        该类实现 Adam(Adaptive Moment Estimation))优化方法。Adam 是一种自适应学习率的优
化方法,Adam 利用梯度的一阶矩估计和二阶矩估计动态的调整学习率。Adam 是结合了 Momentum 和 RMSprop,并进行了偏差修正。

        论文地址:https://arxiv.org/pdf/1412.6980.pdf

         Pytorch说明文档:Adam — PyTorch 1.12 documentation

Adam代码

'''
params (iterable) – 待优化参数的iterable或者是定义了参数组的dict
lr (float, 可选) – 学习率(默认:1e-3)
betas (Tuple[float,float], 可选) – 用于计算梯度以及梯度平方的运行平均值的系数(默认:0.9,0.999)
eps (float, 可选) – 为了增加数值计算的稳定性而加到分母里的项(默认:1e-8)
weight_decay (float, 可选) – 权重衰减(L2惩罚)(默认: 0)
'''
class torch.optim.Adam(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08, weight_decay=0, amsgrad=False)

Adam算法解析

        了解了Adagrad 和RMSProp之后,Adam 就很好理解了。Adam 不仅如 RMSProp 算法那样基于一阶矩均值计算适应性参数学习率,它同时还充分利用了梯度的二阶矩均值,它利用梯度的一阶矩估计和二阶矩估计动态调整每个参数的学习率。Adam的优点主要在于经过偏置校正后,每一次迭代学习率都有个确定范围,使得参数比较平稳。推导过程如下:

​          (17)

​             (18)

​                                                    (19)

​                                                         (20)

​                        (21)

        ​估计了到目前为止g_t各分量的均值,v_t估计了到目前为止g_t各分量的平方的均值。在迭代初期,m_t​​ 对g_t​​ 的估计以及 v_t​​ 对 g_{t}^{2}​​ 的估计都是有偏的,需要进行偏差修正,修正系数分别是 1-\beta _{1}^{t}​​ 和 1-\beta _{2}^{t}​​,随着迭代的进行,估计逐渐变为无偏估计,修正强度逐渐降低为1。

        式子(21)更新模型参数 ,分子表示在过去一段时间内各分量的平均值,即梯度更新的大致走向,分母表示在过去一段时间内各分量的平均大小。相当于分两步走,第一步是确定一个合适的下降方向(即分子项),第二步,对这个选定的方向上的各个子方向做一下微调(分母项),这样,推进较快的子方向会慢下来,推进较慢的子方向会加快速度,动态调整了各个子方向的学习率。因此,Adam结合了Momentum和RMSprop两种算法的优点。

Adam总结

        在adam中,一阶矩来控制模型更新的方向,二阶矩控制步长(学习率)。利用梯度的一阶矩估计和二阶矩估计动态调整每个参数的学习率。

优点:

1、结合了Adagrad善于处理稀疏梯度和RMSprop善于处理非平稳目标的优点 

2、更新步长和梯度大小无关,只和alpha、beta_1、beta_2有关系。并且由它们决定步长的理论上限

3、更新的步长能够被限制在大致的范围内(初始学习率)

4、能较好的处理噪音样本,能天然地实现步长退火过程(自动调整学习率)

推荐程度:非常推荐

四、torch.optim.Adamax

        该类实现 Adamax 优化方法。Adamax 是对 Adam 增加了一个学习率上限的概念,所以称之为 Adamax。

         论文地址:https://arxiv.org/pdf/1412.6980.pdf

         Pytorch说明文档:Adamax — PyTorch 1.12 documentation

Adamax代码

'''
params (iterable) – 待优化参数的iterable或者是定义了参数组的dict
lr (float, 可选) – 学习率(默认:2e-3)
betas (Tuple[float,float], 可选) – 用于计算梯度以及梯度平方的运行平均值的系数
eps (float, 可选) – 为了增加数值计算的稳定性而加到分母里的项(默认:1e-8)
weight_decay (float, 可选) – 权重衰减(L2惩罚)(默认: 0)
'''
class torch.optim.Adamax(params, lr=0.002, betas=(0.9, 0.999), eps=1e-08, weight_decay=0)

Adamax算法解析

        adam的梯度更新规则都是反比于梯度的L2范数,即:

              ​         (22)

        那么能否把L2范数拓展到Lp范数? 作者给出了如下假设:

​          (23)

        这种变体当p比较大时会出现不稳定的情况。但当 gif.latex?p%20%5Cto%20%5Cinfty​ 时,会有一个简单并稳定的算法,求解过程如下。

           (24)

        因为无穷范数,就是取向量的最大值,所以继续推导如下:

​   (25)

         这就对应了一个非常简单的递归公式:

        ​                (26)

         由于​依赖于max操作,所以AdaMax不像在Adam中​和​的偏差趋向于0,所以不需要计算​的偏差校正。

        比较合适的参数设置: η=0.002,β1=0.9,β2=0.999

Adamax总结

        Adamax是Adam的一种变体,此方法对学习率的上限提供了一个更简单的范围。总的来说跟Adam效果差不了多少。

推荐程度:非常推荐

五、torch.optim.AdamW

        该类实现AdamW,是Adam的进化版, 简单地说是Adam+权重衰减。

        论文地址:https://arxiv.org/pdf/1711.05101.pdf

        Pytorch说明文档:AdamW — PyTorch 1.12 documentation

AdamW代码

'''
params (iterable) – 待优化参数的iterable或者是定义了参数组的dict
lr (float, 可选) – 学习率(默认:1e-3)
betas (Tuple[float,float], 可选) – 用于计算梯度以及梯度平方的运行平均值的系数(默认:0.9,0.999)
eps (float, 可选) – 为了增加数值计算的稳定性而加到分母里的项(默认:1e-8)
weight_decay (float, 可选) – 权重衰减(L2惩罚)(默认: 1e-2)
amsgrad(boolean, optional) – 是否使用从论文On the Convergence of Adam and Beyond中提到的算法的AMSGrad变体(默认:False)
'''
class torch.optim.AdamW(params,lr=0.001,betas=(0.9,0.999),eps=1e08,weight_decay=0.01,amsgrad=False)

AdamW算法解析

        1.adam+L2正则化

        L2正则化往损失函数加入权重惩罚项 gif.latex?%5Cfrac%7B1%7D%7B2%7D%5Clambda%20%5Ctheta%20%5E%7B2%7D​ 。对于SGD,使用L2正则化后,参数更新公式变为公式(1):

​​         (27)

        因为gif.latex?1-%5Ceta%20%5Clambda%3C1​,所以随着更新, gif.latex?%5Ctheta​有趋向于零的倾向,从而选择特征变得稀疏,提高泛化能力。对于学习率自适应的Adam,使用L2正则化后,参数更新公式如下:

                            (28)

         (29)

             (30)

                      (31)

将式子(28)带入式子(29)然后再带入(31)得: 

(32)

        可以看到,最后一项分子发挥正常效果,对于大的 θ 加大惩罚;而分母使得在梯度快速变化的方向( θ 较大)更新的更少,从而削弱了L2正则的惩罚,使得L2正则效果变得不理想。

        2.adam+权重衰减

        adamW就是adam+权重衰减,对于学习率自适应的Adam,既然问题出现在正则项除以了gif.latex?%5Csqrt%7Bv_%7Bt%7D%7D+%5Cepsilon之后正则项不能很好的工作,那就不除了呗,更新变成下面的样子:

​           (33)

        其中gif.latex?%5Chat%7Bm%7D_%7Bt%7D​为式子(19),​为式子(20),可以看到这样正则项不再受到​影响,而gif.latex?%5Ctheta​相比adam多减了一个gif.latex?%5Ceta%20%5Clambda%20%5Ctheta%20_%7Bt%7Dgif.latex?%5Ctheta​有一个减小的趋势,所以叫做权重衰减。

AdamW总结

        因为Adam的学习率自适应的,而L2正则遇到自适应学习率后效果不理想,所以使用adam+权重衰减的方式解决问题。多说一句,如果epoch比较多推荐使用 SGD(无momentum) + L2正则化;poch比较少推荐使用AdamW。

优点:比Adam收敛得更快,参数更稀疏

推荐程度:可以一试,BERT使用了adamW

六、orch.optim.NAdam

        该类实现NAdam,NAdam是在 Adam 中引入 Nesterov 加速效果。

        论文地址:https://openreview.net/pdf?id=OM0jvwB8jIp57ZJjtNEZ

        Pytorch说明文档:NAdam — PyTorch 1.12 documentation

NAdam代码

'''
params (iterable) – 待优化参数的iterable或者是定义了参数组的dict
lr (float, 可选) – 学习率(默认:1e-3)
betas (Tuple[float,float], 可选) – 用于计算梯度以及梯度平方的运行平均值的系数(默认:0.9,0.999)
eps (float, 可选) – 为了增加数值计算的稳定性而加到分母里的项(默认:1e-8)
weight_decay (float, 可选) – 动量衰减
foreach(boolean, optional) – 是否使用每个优化器的实现,可以添加一些复杂的foreach逻辑
'''
class torch.optim.NAdam(params, lr=0.002, betas=(0.9, 0.999), eps=1e-08, weight_decay=0, momentum_decay=0.004, foreach=None)

NAdam算法解析

首先回顾 NAG 的公式(详情可跳转Pytorch优化器全总结(一)SGD、ASGD、Rprop、Adagrad_小殊小殊的博客-CSDN博客):

​​             (34)

​​                (35)

​​                                   (36)

        NAG 的核心在于,计算梯度时使用了[未来位置]:gif.latex?%5Ctheta%20_%7Bt%7D-%5Crho%20m_%7Bt-1%7D​。NAdam 中提出了一种公式变形的思路,大意可以这样理解:只要能在梯度计算中考虑到[未来因素],即能达到 Nesterov 的效果;既然如此,那么在计算梯度时,可以仍然使用原始公式 ​ ,但在前一次迭代计算 ​时,就使用了未来时刻的动量,即式子(36),那么理论上所达到的效果是类似的。

        这时,公式修改为:

                                  (37)

        ​        (38)

        ​            (39)

        ​                            (40)

        理论上,下一刻的动量为 gif.latex?m_%7Bt+1%7D%20%3D%20%5Crho%20*m_%7Bt%7D%20+%5Ceta%20*g_%7Bt+1%7D​,在假定连续两次的梯度变化不大的情况下,即 gif.latex?g_%7Bt+1%7D%5Capprox%20g_%7Bt%7D​,有 gif.latex?m_%7Bt+1%7D%5Capprox%20%5Crho%20*m_%7Bt%7D%20+%5Ceta%20*g_%7Bt%7D%3D%5Cbar%7Bm%7D_%7Bt%7D​。此时,即可用 gif.latex?%5Cbar%7Bm%7D_%7Bt%7D​ 近似表示未来动量加入到参数更新的迭代式中。

        类似的,在 Adam 可以加入 gif.latex?%5Chat%7Bm%7D_%7Bt%7D%5Capprox%20%5Cbar%7Bm%7D_%7Bt%7D​ 的变形,将 gif.latex?%5Chat%7Bm%7D_%7Bt%7D​ 展开有:

(41)

                    (42)

                                              (43)

          式子(39)即为NAdam的更新公式。

NAdam总结

        NAdam是在 Adam 中引入 Nesterov 加速效果。

        优点:具有Adam的优点的同时,在也兼具NAG收敛速度快、波动也小的特点。

        推荐程度:推荐,在想使用带动量的RMSprop,或者Adam的地方,大多可以使用NAdam取得更好的效果。 

七、torch.optim.SparseAdam

        该类实现SparseAdam,不是很常用,是针对稀疏张量的一种“阉割版”Adam 优化方法。

         Pytorch说明文档:SparseAdam — PyTorch 1.12 documentation

SparseAdam代码

'''
params (iterable) – 待优化参数的iterable或者是定义了参数组的dict
lr (float, 可选) – 学习率(默认:1e-3)
betas (Tuple[float,float], 可选) – 用于计算梯度以及梯度平方的运行平均值的系数(默认:0.9,0.999)
eps (float, 可选) – 为了增加数值计算的稳定性而加到分母里的项(默认:1e-8)
'''
class torch.optim.SparseAdam(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08)

推荐程度:使用的较少,处理稀疏张量的时候考虑使用。

优化器系列文章列表

Pytorch优化器全总结(一)SGD、ASGD、Rprop、Adagrad

Pytorch优化器全总结(二)Adadelta、RMSprop、Adam、Adamax、AdamW、NAdam、SparseAdam

Pytorch优化器全总结(三)牛顿法、BFGS、L-BFGS 含代码

Pytorch优化器全总结(四)常用优化器性能对比 含代码

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐