一、什么是优化?什么是优化器?
1、机器学习中的优化:
优化是应用数学的一个分支,其也是机器学习的核心组成部分
为什么这么说呢,因为实际上,机器学习 = 模型表征 + 模型评估 + 优化算法
举两个例子:
- 逻辑回归LR
- 模型表征 → 线性分类模型
- 评估指标 → 交叉熵
- 支持向量机SVM
- 模型表征 → 线性分类模型
- 评估指标 → 最大间隔
总结来说就是:优化的目的就是找到一个最优解,让模型表征能够完美的表征对应的数据
而在深度学习过程中,优化问题大多是非凸的,并且数据量极大,因此,很多优化问题并不存在解析解
为了求得最小化目标函数的数值解,我们将通过优化算法有限次迭代模型参数来尽可能降低损失函数的值
这些优化算法,就是优化器
二、常见的优化器:
- 梯度下降和随机梯度下降
- 小批量梯度下降
- 动量法
- AdaGrad
- RMSProp
- AdaDelta
- Adam
- Nadam
- ...
1、梯度下降和随机梯度下降
带着思考:为什么梯度下降算法可能降低目标函数值
以一维梯度下降为例
目标函数:f(x),给定绝对值足够小的数ϵ,根据泰勒展开式,可以得到如下公式:
其中,由于ϵ足够小,高阶项被省略,因此:
这里f′(x)是函数f在x处的梯度。一维函数时,也就是我们所说的导数
接下来,找到一个常数η>0,使得|ηf′(x)|足够小,那么可以将ϵ替换为−ηf′(x)并得到:
这里,如果导数f′(x) ≠ 0,那么ηf′(x)^2>0,因此
这意味这,如果通过 x-ηf′(x) 来迭代x,那么函数值f(x)一定会降低
因此,在梯度下降中,我们的方式就是:选取一个初始值x和常数η>0,然后通过上式不断的迭代x,知道达到停止条件,例如f′(x)^2的值已足够小或迭代次数已达到某个值
看jupyter:https://github.com/lzneu/letGo/blob/master/dive_2deep_learning.ipynb
而在深度学习里面,目标函数通常是训练数据集中有关各个样本的损失函数的平均,目标函数定义为:
目标函数在x处的梯度为:
如果使用梯度下降,每次自变量迭代的计算开销为O(n),它随着n线性增长。因此,当训练数据样本数很大时,梯度下降每次迭代的计算开销很高
随机梯度下降:每次迭代,随机均匀采样一个索引样本 i ∈ {1,...,n},计算梯度∇fi(x) 来迭代x
因此,计算开销从O(n)降低到了常数O(1)
而在统计学中,随机梯度是梯度的无偏估计
这意味着,平均来说,随机梯度是对梯度的一个良好的估计
看jupyter:https://github.com/lzneu/letGo/blob/master/dive_2deep_learning.ipynb
可以发现,SGD发生了少量学习不稳定的情况
因此,实际工作中,各个算法库的SGD 使用的都是这个,其计算开销为O(B)
同时,在实际应用中,(小批量)随机梯度下降的学习率可以在迭代过程中自我衰减。
小结
- 使用适当的学习率,沿着梯度反方向更新自变量可能降低目标函数值。梯度下降重复这一更新过程直到得到满足要求的解。
- 当训练数据集的样本较多时,梯度下降每次迭代的计算开销较大,因而随机梯度下降通常更受青睐。
2、动量法momentum
在梯度下降中,目标函数有关自变量的梯度代表了目标函数在自变量当前位置下降最快的方向
然而,如果自变量的迭代方向仅仅取决于自变量的当前位置,这可能会带来一些问题
假设,目标函数:
注意,这里x1的系数为0.1 而x2的系数为2,下面通过代码实现这个目标函数的梯度下降,并查看使用学习率0.4的自变量迭代轨迹
看jupyter:https://github.com/lzneu/letGo/blob/master/dive_2deep_learning.ipynb
因此,就有了动量法
设时间步t时的自变量为xt,学习率为η
在时间步0,动量法创建初始速度变量v0,并将其元素初始化为0
当t>0是,动量法对每次迭代的步骤做如下修改
其中,gt为小批量随机梯度(f't(x))
动量超参数γ满足0≤γ<1。当γ=0时,动量法等价于小批量随机梯度下降
在解释动量法的数学原理前,先从实验中观察梯度下降在使用动量法后的迭代轨迹
看jupyter:https://github.com/lzneu/letGo/blob/master/dive_2deep_learning.ipynb
可以看到使用较小的学习率η=0.4和动量超参数γ=0.5时,动量法在竖直方向上的移动更加平滑,且在水平方向上更快逼近最优解
使用较大的学习率η=0.6,此时自变量也不再发散
为了从数学上理解动量法,让我们先解释一下指数加权移动平均
给定超参数0≤γ<1,当前时间步t的变量yt是上一时间步t−1的变量yt−1和当前时间步另一变量xt的线性组合:
对y进行展开
由指数加权平均理解动量法
现在,我们对动量法的速度变量做变形:
由指数加权移动平均的形式可得,动量法实际上就是对vt做了指数加权平均
换句话说:相比较SGD,动量法在各个方向上的移动幅度不仅取决于当前梯度,还取决于对于过去各个梯度在各个方向上是否一致
这样,我们使用较大的学习率,就可以使得自变量向最优解更快移动
小结
- 动量法使用了指数加权移动平均的思想。它将过去时间步的梯度做了加权平均,且权重按时间步指数衰减。
- 动量法使得相邻时间步的自变量更新在方向上更加一致。
3、AdaGrad算法
在之前的优化算法中,目标函数的自变量的每一个元素都使用同一个学习率来自我迭代。
而在动量法中,我们看到当x1和x2的梯度值有较大差异时,需要选择足够小的学习率让梯度不发散
动量法依赖指数加权平均,从而降低发散的可能
本节的AdaGrad,根据自变量在每个维度上的梯度值的大小来调整各个维度上的学习率,从而避免统一的学习率难以适应的问题
算法
AdaGrad使用中间变量st,其中gt代表SGD的梯度,st为元素平方的累加变量,在时间步t,有
接着,将目标函数自变量中每个元素的学习率通过按元素运算重新调整一下:
其中η是学习率,ϵ是为了维持数值稳定性而添加的常数,如10e−6。这里开方、除法和乘法的运算都是按元素运算的。这些按元素运算使得目标函数自变量中每个元素都分别拥有自己的学习率
特点
需要强调的是,小批量随机梯度按元素平方的累加变量st出现在学习率的分母项中
因此,如果目标函数有关自变量中某个元素的偏导数一直都较大,那么该元素的学习率将下降较快
反之,如果目标函数有关自变量中某个元素的偏导数一直都较小,那么该元素的学习率将下降较慢
然而,由于st一直在累加按元素平方的梯度,自变量中每个元素的学习率在迭代过程中一直在降低(或不变)
所以,当学习率在迭代早期降得较快且当前解依然不佳时,AdaGrad算法在迭代后期由于学习率过小,可能较难找到一个有用的解。
目标函数和学习率与动量法相同,实验如下
看jupyter
可以看到,自变量的迭代轨迹较平滑。但由于st的累加效果使学习率不断衰减,自变量在迭代后期的移动幅度较小。
4、RMSProp算法
刚才我们提到,当学习率在迭代早期降得较快且当前解依然不佳时,AdaGrad算法在迭代后期由于学习率过小,可能较难找到一个有用的解
为了解决这一问题,RMSProp算法对AdaGrad算法做了一点小小的修改
RMSProp算法将AdaGrad中的梯度按元素平方做指数加权移动平均
算法
和AdaGrad算法一样,RMSProp算法将目标函数自变量中每个元素的学习率通过按元素运算重新调整,然后更新自变量
因为RMSProp算法的状态变量st是对平方项gt⊙gt的指数加权移动平均
所以可以看作是最近1/(1−γ)个时间步的小批量随机梯度平方项的加权平均
如此一来,自变量每个元素的学习率在迭代过程中就不再一直降低(或不变)
来看同样的目标函数的RMSProp的结果
看jupyter
可以发现:在同样的学习率下,RMSProp算法可以更快逼近最优解
RMSProp相比较AdaGrad算法在收敛后期迭代更快
5 AdaDelta算法
除了RMSProp算法以外,另一个常用优化算法AdaDelta算法也针对AdaGrad算法在迭代后期可能较难找到有用解的问题做了改进
AdaDelta算法没有学习率这一超参数
算法
思想是与RMSProp基本一致
与RMSProp算法不同的是,AdaDelta算法还维护一个额外的状态变量Δxt
使用Δxt-1来计算自变量的变化量,然后更新自变量
最后,使用Δxt来记录自变量变化量g′t按元素平方的指数加权移动平均
可以看到,如不考虑ϵ的影响,AdaDelta算法跟RMSProp算法的不同之处在于使用sqrt(Δxt−1)来替代学习率η
6 Adam算法
思想:在RMSProp算法基础上对小批量随机梯度也做了指数加权移动平均
所以Adam算法可以看做是RMSProp算法与动量法的结合
算法
给定超参数0≤β1<1(作者建议设置为0.9),时间步t的动量变量vt即小批量随机梯度gt的指数加权移动平均
和RMSProp算法中一样,给定超参数0≤β2<1(算法作者建议设为0.999)
将小批量随机梯度按元素平方后的项gt⊙gt做指数加权移动平均得到st
为了解决0启动问题,在Adam算法中,对变量vt和st均作了偏差修正
接下来,Adam算法使用以上偏差修正后的变量vtˆ stˆ,将模型参数中每个元素的学习率通过按元素运算重新调整
其中η是学习率,ϵ是为了维持数值稳定性而添加的常数,如10e−8。和AdaGrad算法、RMSProp算法以及AdaDelta算法一样,目标函数自变量中每个元素都分别拥有自己的学习率
最后,使用g′t迭代自变量
小结
- Adam算法在RMSProp算法的基础上对小批量随机梯度也做了指数加权移动平均
- Adam算法使用了偏差修正
三、可视化:
结束了枯燥的理论分析,我们来看一下可视化效果
实例一:
上图比较了6种优化器收敛到目标点(五角星)的运行过程,从图中可以大致看出:
① 在运行速度方面
- 两个动量优化器Momentum和NAG的速度最快,其次是三个自适应学习率优化器AdaGrad、AdaDelta以及RMSProp,最慢的则是SGD。
② 在收敛轨迹方面
- 两个动量优化器虽然运行速度很快,但是初中期走了很长的”岔路”。
- 三个自适应优化器中,Adagrad初期走了岔路,但后来迅速地调整了过来,但相比其他两个走的路最长;AdaDelta和RMSprop的运行轨迹差不多,但在快接近目标的时候,RMSProp会发生很明显的抖动。
- SGD相比于其他优化器,走的路径是最短的,路子也比较正。
实例二:
上图在一个存在鞍点的曲面,比较6中优化器的性能表现,从图中大致可以看出:
- 三个自适应学习率优化器AdaDelta、Adagrad、RMSprop没有进入鞍点
- 两个动量优化器Momentum和NAG以及SGD都顺势进入了鞍点。但两个动量优化器在鞍点抖动了一会,就逃离了鞍点并迅速地下降,后来居上超过了Adagrad和RMSProp。
- 很遗憾,SGD进入了鞍点,却始终停留在了鞍点,没有再继续下降。
四、一些经验之谈
1、对于稀疏数据,尽量使用学习率可自适应的优化方法,不用手动调节,而且最好采用默认值。
2、SGD通常训练时间更长,但是在好的初始化和学习率调度方案的情况下(很多论文都用SGD),结果更可靠。
3、如果在意更快的收敛,并且需要训练较深较复杂的网络时,推荐使用学习率自适应的优化方法。
4、Adadelta,RMSprop,Adam是比较相近的算法,在相似的情况下表现差不多 。Adam 就是在 RMSprop 的基础上加了 bias-correction 和 momentum,随着梯度变得稀疏,Adam 比 RMSprop 效果会好。整体来讲,Adam 是最好的选择。