不管是使用还是,用多了优化器封装好的函数,对其内部使用的优化算法却没有仔细研究过,也很难对其优点和缺点进行实用的解释。所以打算以这一篇论文为主线并结合多篇优秀博文,回顾和总结目前主流的优化算法,对于没有深入了解过的算法,正好借这个机会学习一下。
写在前面
当前使用的许多优化算法,是对梯度下降法的衍生和优化。在微积分中,对多元函数的参数求偏导数,把求得的各个参数的导数以向量的形式写出来就是梯度。梯度就是函数变化最快的地方。梯度下降是迭代法的一种,在求解机器学习算法的模型参数时,即无约束问题时,梯度下降是最常采用的方法之一。
这里定义一个通用的思路框架,方便我们后面理解各算法之间的关系和改进。首先定义待优化参数,目标函数,学习率为,然后我们进行迭代优化,假设当前的epoch为,则有:
其中,为下一个时刻的参数,为当前时刻参数,后面的描述我们都将结合这个框架来进行。
这里提一下一些概念:
什么是指数加权平均、偏差修正?- 郭耀华 - 博客园
(GD)
在GD中没有动量的概念,也就是说在上述框架中:,则我们在当前时刻需要下降的梯度就是,则使用梯度下降法更新参数为(假设当前样本为,每当样本输入时,参数即进行更新):
梯度下降算法中,模型参数的更新调整,与代价函数关于模型参数的梯度有关,即沿着梯度的方向不断减小模型参数,从而最小化代价函数。基本策略可以理解为”在有限视距内寻找最快路径下山“,因此每走一步,参考当前位置最陡的方向(即梯度)进而迈出下一步,更形象的如下图:
标准的梯度下降主要有两个缺点:
Batch (BGD)
BGD相对于标准GD进行了改进,改进的地方通过它的名字应该也能看出来,也就是不再是想标准GD一样,对每个样本输入都进行参数更新,而是针对一个批量的数据输入进行参数更新。我们假设批量训练样本总数为,样本为,则在第对样本上损失函数关于参数的梯度为, 则使用BGD更新参数为:
从上面的公式我们可以看到,BGD其实是在一个批量的样本数据中,求取该批量样本梯度的均值来更新参数,即每次权值调整发生在批量样本输入之后,而不是每输入一个样本就更新一次模型参数,这样就会大大加快训练速度,但是还是不够,我们接着往下看。
(SGD)
随机梯度下降法,不像BGD每一次参数更新,需要计算整个数据样本集的梯度,而是每次参数更新时,仅仅选取一个样本计算其梯度,参数更新公式为:
公式看起来和上面标准GD一样,但是注意了,这里的样本是从批量中随机选取一个,而标准GD是所有的输入样本都进行计算。可以看到BGD和SGD是两个极端,SGD由于每次参数更新仅仅需要计算一个样本的梯度,训练速度很快,即使在样本量很大的情况下,可能只需要其中一部分样本就能迭代到最优解,由于每次迭代并不是都向着整体最优化方向,导致梯度下降的波动非常大(如下图),更容易从一个局部最优跳到另一个局部最优,准确度下降。
论文中提到,当缓慢降低学习率时,SGD会显示与BGD相同的收敛行为,几乎一定会收敛到局部(非凸优化)或全局最小值(凸优化)。
SGD的优点:
SGD的缺点:
Mini-batch (MBGD,也叫作SGD)
小批量梯度下降法就是结合BGD和SGD的折中随机梯度下降算法,对于含有个训练样本的数据集,每次参数更新,选择一个大小为 $m(m
小批量梯度下降法即保证了训练的速度,又能保证最后收敛的准确率,目前的SGD默认是小批量梯度下降算法。常用的小批量尺寸范围在50到256之间,但可能因不同的应用而异。
MBGD的缺点:
算法思想:参数更新时在一定程度上保留之前更新的方向,同时又利用当前batch的梯度微调最终的更新方向,简言之就是通过积累之前的动量来加速当前的梯度。从这里开始,我们引入一阶动量的概念(在mini-batch SGD的基础之上),也就是说,在最开始说的框架中,,而不变,参数更新公式如下:
一阶动量是各个时刻梯度方向的指数移动平均值,约等于最近个时刻的梯度向量和的平均值(移动平均是啥看最上面的文章)。也就是说,时刻的下降方向,不仅由当前点的梯度方向决定,而且由此前累积的下降方向决定。
的经验值为0.9,这就意味着下降方向主要是此前累积的下降方向,并略微偏向当前时刻的下降方向。在梯度方向改变时,能够降低参数更新速度,从而减少震荡,在梯度方向相同时,可以加速参数更新, 从而加速收敛,如下图:
动量主要解决SGD的两个问题:
NAG( )算法,是动量算法的变种。保留了上一时刻的梯度,对其没有进行任何改变,NAG是的改进,在梯度更新时做一个矫正,具体做法就是在当前的梯度上添加上一时刻的动量,梯度改变为,参数更新公式如下:
加上项后,梯度在大的跳跃后,进行计算对当前梯度进行校正。下图是和的对比表述图如下:
动量梯度的计算在模型参数施加当前速度之后,因此可以理解为往标准动量中添加了一个校正因子。在凸批量梯度的情况下,动量将额外误差收敛率从(k步后)改进到,然而,在随机梯度情况下,动量对收敛率的作用却不是很大。
和都是为了使梯度更新更灵活。但是人工设计的学习率总是有些生硬,下面介绍几种自适应学习率的方法。
其实是对学习率进行了一个约束,对于经常更新的参数,我们已经积累了大量关于它的知识,不希望被单个样本影响太大,希望学习速率慢一些;对于偶尔更新的参数,我们了解的信息太少,希望能从每个偶然出现的样本身上多学一些,即学习速率大一些。而该方法中开始使用二阶动量,才意味着“自适应学习率”优化算法时代的到来。
我们前面都没有好好的讨论二阶动量,二阶动量是个啥?它是用来度量历史更新频率的,二阶动量是迄今为止所有梯度值的平方和,即,在最上面的框架中(在这里), 也就是说,我们的学习率现在是(一般为了避免分母为0,会在分母上加一个小的平滑项),从这里我们就会发现是恒大于0的,而且参数更新越频繁,二阶动量越大,学习率就越小,这一方法在稀疏数据场景下表现非常好,参数更新公式如下:
细心的小伙伴应该会发现还是存在一个很明显的缺点:
由于调整学习率变化过于激进,我们考虑一个改变二阶动量计算方法的策略:不累积全部历史梯度,而只关注过去一段时间窗口的下降梯度,即只累加固定大小的项,并且也不直接存储这些项,仅仅是近似计算对应的平均值(指数移动平均值),这就避免了二阶动量持续累积、导致训练过程提前结束的问题了,参数更新公式如下:
观察上面的参数更新公式,我们发现还是依赖于全局学习率,但是原作者在此基础之上做出了一定的处理,上式经过牛顿迭代法之后,得到最终迭代公式如下式,其中:
此时可以看出已经不依赖全局 rate了,有如下特点:
算法修改了的梯度平方和累加为指数加权的移动平均,使得其在非凸设定下效果更好。设定参数:全局初始率, 默认设为0.001,decay rate,默认设置为0.9,一个极小的常量,通常为10e-6,参数更新公式如下,其中:
(Adam)
其实有了前面的方法,Adam和Nadam的出现就很理所当然的了,因为它们结合了前面方法的一阶动量和二阶动量。我们看到,SGD-M和NAG在SGD基础上增加了一阶动量,和在SGD基础上增加了二阶动量,参数更新公式如下(按照最开始总结的计算框架):
通常情况下,默认值为、和,Adam通常被认为对超参数的选择相当鲁棒随机梯度下降算法,特点如下:
是Adam的一种变体,此方法对学习率的上限提供了一个更简单的范围,即使用无穷范式,参数更新公式如下:
通常情况下,默认值为、和
Nadam
其实如果说要集成所有方法的优点于一身的话,Nadam应该就是了,Adam遗漏了啥?没错,就是项,我们在Adam的基础上,加上项就是Nadam了,参数更新公式如下:
可以看出,Nadam对学习率有更强的约束,同时对梯度的更新也有更直接的影响。一般而言,在使用带动量的或Adam的问题上,使用Nadam可以取得更好的结果。
来张直观的动态图展示上述优化算法的效果:
总结
那种优化器最好?该选择哪种优化算法?目前还没能够达达成共识。 et al (2014)展示了许多优化算法在大量学习任务上极具价值的比较。虽然结果表明,具有自适应学习率的优化器表现的很鲁棒,不分伯仲,但是没有哪种算法能够脱颖而出。
目前,最流行并且使用很高的优化器(算法)包括SGD、具有动量的SGD、、具有动量的、和Adam。在实际应用中,选择哪种优化器应结合具体问题;同时,也优化器的选择也取决于使用者对优化器的熟悉程度(比如参数的调节等等)。
参考文献:
论文标题:An of
原文链接:
:NLP相关Paper笔记和代码复现()