400-123-4657
深度学习的优化目标都是最小化目标函数,方式为bp算法,深度学习框架如tensorflow,pytorch一般通过封装的优化器实现这一过程,本文详细总结了现有的优化器。
目录:
[toc]
待优化参数:$ heta$,目标函数:$f( heta)$,学习率:$\eta$
第t个时刻参数的梯度:$g_t=\bigtriangledown f( heta_t)$
tips:倒三角符号常用来表示梯度,也会用于表示散度和旋度,这里表示梯度。
tips:动量概念来自物理类比,假设是单位质量,速度向量(累积到t时刻的梯度)可以看作动量。
根据历史梯度计算的二阶动量:$V_t=\psi(g_1^2,g_2^2,…,g_t^2)$
优化通式:$ heta_t= heta_{t-1}-q(g_t)$
其中,$q(g_t)$是梯度的函数。每个优化器都是根据 梯度大小和学习率大小 迈向最优解,区别就是在于如何定义q函数。
现在的随机梯度下降(Stochastic Gradient Descent,SGD)一般都是指 mini-batch gradient descent。SGD的学习率 $\eta$ 不变,每次计算一个batch内的数据的梯度并进行更新。
SGD的梯度下降过程,类似于一个小球从山坡上滚下,它的前进方向只与当前山坡的最大倾斜方向一致(最大负梯度方向),每一个时刻的初速度都为0。
SGD的 $q(g_t)=\eta*g_t$
###1.2 缺点
Momentum 即动量,该改进是在SGD的基础上考虑了动量的因素,通过动量值来克服SGD易于震荡的缺点: 这里 $q(g_t)=\mathbb{momentum} * m_{t-1} + \eta * g_{t}$,$m_{t-1}$(动量)是指数衰减的梯度平均。
通常momentum会取一个较大的值,如0.9。
理解指数衰减的加权平均:
假设momentum=0.9,$\eta$=0.01,有:
$m_5=0.9m_4+0.01g_5$
$m_4=0.9m_3+0.01g_4$
$m_3=0.9m_2+0.01g_3$
$m_2=0.9m_1+0.01g_2$
则:$m_5=0.01*(g_5+0.9g_5+0.9^2g_3+0.9^3g_2+0.9^4g_1)$
可以看到第5次更新的梯度包含了前4次的梯度,且是一个指数衰减的过程。
SGD Momentum的梯度下降过程,类似于一个小球从山坡上滚下,它的前进方向由当前山坡的最大倾斜方向与之前的下降方向共同决定,小球具有初速度(动量)。
Nesterov Accelerated Gradient 在 Momentum 的基础上进行改进,用于解决SGD容易陷入局部最优的缺点。
NAG的思想先用一个形象的事例来说明:当你走到一个盆地,四周都是略高的小山,你找不到下坡的方向,就只能呆这里了,但其实外面的世界很广阔,还有更低的地方可以去;所以如果你在进入盆地之前,看的更远一些,不光从当前的位置去审视下坡,还从未来的角度去审视下坡,就可以不进入这个盆地,从而下降的更多。
在Momentum算法中,由于历史累积动量的权值很大,t时刻的下降方向主要由累积动量$?m_{t-1}$决定。那么在计算t时刻的梯度时,可以多看一步,看看下一时刻的梯度(即如果跟着累积动量走了一步以后的梯度),用下一时刻的梯度与历史累积动量结合。
所以NAG计算梯度时,不是在当前位置,而是未来的位置上:
关于 $V_t$, 后面会在Adagrad解释
图示可以很好的解释momentum和NAG的区别:
目前为止,我们可以做到,在更新梯度时顺应 loss function 的梯度来调整速度,并且对 SGD 进行加速。
我们还希望可以根据参数的重要性而对不同的参数进行不同程度的更新。
自适应梯度算法(Adaptive Gradient Algorithm,Adagrad)通过以往的梯度自适应更新学习率 $\eta$,使得不同的 $ heta_i$ 具有不同的学习率:常出现的特征学习率低,不常出现的特征学习率高,比SGD更容易处理稀疏数据,解决SGD的第三个问题。
从Adagrad开始,引入了二阶动量,也意味着“自适应率”优化算法的到来。我们希望根据参数的更新频率来对参数的学习率进行调整,如何去度量一个参数的历史更新频率呢?就是二阶动量(历史梯度平方和): 所以学习率变成了:$\eta_t=\frac{\eta}{\sqrt{V_t}}$,一般为了避免分母为零,会加一个较小的平滑项epsilon,即:$\eta_t=\frac{\eta}{\sqrt{V_t}+\epsilon}$
需要说明的是,网上关于epsilon在根号下还是根号外写法不一致,虽然一个epsilon为极小值影响不大,但我还是去看了keras的源码,所有优化器的epsilon都是在外部的,而且因为是要个极小值,在外部也更加合理。
分母是个单调递增的值,会不断积累,学习率就会变得非常小,最终趋于0,提前停止学习。
Adagrad中二阶动量不断增加,学习率单调递减的策略过于激进,因此RMSProp提出了一个时间窗口策略:
不累加全部的历史梯度,而只关注于过去一段时间的下降梯度。至于窗口,可以使用指数加权平均的方式,从而避免二阶动量的持续累积。
RMSProp修改后的二阶动量的计算公式:
通常,$\rho=0.9$。
如果RMSProp想添加momentum的话,式为: 这样,既考虑了一阶动量来缓解loss震荡,又考虑了二阶动量来自适应学习率。
Adam(Adaptive Moment Estimation)相当于 RMSProp + Momentum,是前述方法的集大成者,将一阶动量和二阶动量都进行了使用。Adam的一个改进点是Adam对一阶矩估计和二阶矩估计进行了校正,使其近似为对期望的无偏估计。
校正方式为:$\hat m_t=\frac{m_t}{1-\beta_1^t}$
偏差修正解释:
以一阶动量为例,初始化 $m_0=0$,$m_1=0.9m_0+0,1g_1=0.1g_1$,远小于期望值$g_1$;$m_2=0.9m_1+0.1g_2=0.09g_1+0.1g_2$,远小于期望值$0.9g_1+0.1g_2$。在迭代初期,这个偏差很大,当t足够大时,$\hat m_t=m_t$。
所以对一阶动量做修正:当t=1时,$\frac{m_1}{1-\beta_1}=\frac{m_1}{0.1}$,此时$m_1= heta_1$,去除了偏差;当t很大的时候,$\beta^t$接近于0,偏差修正几乎没有作用。
同理,也可以对二阶动量进行修正:$\hat V_t=\frac{V_t}{1-\beta_2^t}$
通常,$\beta_1=0.9,\beta_2=0.999,\epsilon=1e-7$
Adam有很多的优点,但是在很多数据集上的最好效果还是用SGD with Momentum细调出来的。可见Adam的泛化性并不如SGD with Momentum。AdamW指出一个重要原因就是Adam中L2正则化项并不像在SGD中那么有效。
L2正则化:通过在损失中添加l2正则项来降低训练的过拟合
SGD中的l2正则化是通过weight_decay实现,推导如下:
假设$L=J(\hat y,y)+\frac{wd\sum_{k}( heta_k^2)}{2}$,即最终损失由损失项+所有参数的正则项两部分组成,wd为l2超参数,则可以得到$g_t=f_t( heta)+ wd heta_{t-1}$,所以权重更新为: 可以看到,每次更新时,正则项损失等价于减去参数的一小部分,因此称为衰减。
但在Adam这种自适应学习率优化器中,L2正则和Weight Decay并不等价。
思考:调研优化器是因为在增量学习中遇到Adagrad比Adam效果好的情况,最终对Adam在稀疏数据上的表现进行调研,魔改了基于Adam的LazyAdam和mAdam进行实验,最终取得了更好的效果。
总结:对于Adam的改进优化器有很多,主要改进集中在两方面,一是对Adam存在的问题,二是对Adam的收敛进行加速。建议学习(常用)的有:
表面:调一个参数/换一个优化器(调参)
背后:对于所有优化器的原理,推导,源码有清晰的认识和实践,才能够根据实验结果,从容的更换参数,达到更好的效果。