Adam

将优化算法的框架搬来. 首先定义符号. ww为待优化参数, f(w)f(w)为目标函数, α\alpha为初始学习率.

在每步tt中:

  1. 计算目标函数关于当前参数wtw_t的梯度: gt=f(wt)g_{t}=\nabla f\left(w_{t}\right)

  2. 根据历史梯度g1,g2,,gtg_{1}, g_{2}, \cdots, g_{t}计算一阶动量和二阶动量: mt=ϕ(g1,g2,,gt)m_{t}=\phi\left(g_{1}, g_{2}, \cdots, g_{t}\right); Vt=ψ(g1,g2,,gt)V_{t}=\psi\left(g_{1}, g_{2}, \cdots, g_{t}\right)

  3. 计算当前时刻的下降梯度: ηt=αmt/Vt\eta_{t}=\alpha \cdot m_{t} / \sqrt{V_{t}}

  4. 根据下降梯度更新参数: wt+1=wtηtw_{t+1}=w_{t}-\eta_{t}

Adam

Adam(Adaptive Moment Estimation)将一阶动量和二阶动量集合起来, Adam即Adaptive + Momentum.

一阶动量和二阶动量分别为:

mt=β1mt1+(1β1)gtm_{t}=\beta_{1} \cdot m_{t-1}+\left(1-\beta_{1}\right) \cdot g_{t}

Vt=β2Vt1+(1β2)gt2V_{t}=\beta_{2} * V_{t-1}+\left(1-\beta_{2}\right) g_{t}^{2}

引入了两个超参数β1\beta_1β2\beta_2, 分别控制一阶动量和二阶动量的影响. 实际使用过程中, 参数的经验值是:

β1=0.9,β2=0.999\beta_{1}=0.9, \beta_{2}=0.999

为防止在训练起始阶段一阶二阶动量失真, 一般使用偏差修正过的指数移动平均值:

m~t=mt/(1β1t)V~t=Vt/(1β2t)\begin{aligned} &\tilde{m}_{t}=m_{t} /\left(1-\beta_{1}^{t}\right)\\ &\tilde{V}_{t}=V_{t} /\left(1-\beta_{2}^{t}\right) \end{aligned}

Adam的优点

Adam继承了Adagrad自适应学习率的特性, 对于稀疏梯度处理较好. 对于大多情况, 可以使用Nadam取得更好的效果.

Adam的问题

显存占用过多

因为要计算一阶动量和二阶动量, 根据平滑更新的方法, 要保存当前时刻对应的值. 因此Adam占用的显存实际上是纯参数占用量的三倍. 这对于一些包含很多参数的大模型来说, 将会造成显存溢出.

可能不收敛

论文On the Convergence of Adam and Beyond探讨了Adam算法的收敛性, 通过反例证明了Adam在某些情况下可能会不收敛.

这是由于会发生学习率震荡的现象. 考虑优化算法的学习率为α/Vt\alpha / \sqrt{V_{t}}, 只有在两种情况下, 学习率是单调递减的:

  • SGD结合采用学习率衰减策略

  • AdaGrad, 其二阶动量不断累积, 单调递增, 导致学习率单调递减

学习率是单调递减的, 最终收敛到0, 模型也得以收敛(虽然这种递减可能会引起训练提前停止的问题). 但Adam中的学习率主要是由二阶动量控制的, 二阶动量是固定时间窗口内的累积, 随着时间窗口的变化, 遇到的数据可能发生巨变, 使得VtV_t可能会时大时小, 不是单调变化. 这就可能在训练后期引起学习率的震荡, 导致模型无法收敛.

修正的方法, 对二阶动量的变化进行控制, 避免上下波动, 保证VtVt1\left\|V_{t}\right\| \geq\left\|V_{t-1}\right\|, 使得学习率单调递减:

Vt=max(β2Vt1+(1β2)gt2,Vt1)V_{t}=\max \left(\beta_{2} * V_{t-1}+\left(1-\beta_{2}\right) g_{t}^{2}, V_{t-1}\right)

可能错过全局最优解

论文The Marginal Value of Adaptive Gradient Methods in Machine Learning讲到具有自适应学习率的优化算法, 可能会对前期出现的特征过拟合, 后期才出现的特征很难纠正前期的拟合效果.

论文Improving Generalization Performance by Switching from Adam to SGD在CIFAR-10数据集上进行了实验, 发现Adam在后期的学习率太低, 影响了有效的收敛. 对Adam的学习率的下界进行控制, 发现效果好了很多.

这是两种影响Adam错过全局最优解的原因.

一个有效的改进方法是: 在训练的前期使用Adam, 享受Adam快速收敛的优势, 后期切换到SGD, 慢慢寻找最优解. 这个切换点可以根据经验人工进行, 而论文Improving Generalization Performance by Switching from Adam to SGD也给出了一种自动切换的方法.

Adam+SGD

先用Adam快速下降, 再用SGD调优. 这种思路有两个技术问题:

  • 什么时候切换优化算法

  • 切换算法以后用什么样的学习率. Adam用的是自适应学习率, SGD接着训练的话, 用什么样的学习率

切换后使用什么样的学习率?

对于第二个问题, Adam和SGD的下降方向分别为:

ηtAdam=(α/Vt)mt\eta_{t}^{A d a m}=(\alpha / \sqrt{V_{t}}) \cdot m_{t}

ηtSGD=αSGDgt\eta_{t}^{S G D}=\alpha^{S G D} \cdot g_{t}

那么ηtSGD\eta_{t}^{S G D}必定可以分解为ηtAdam\eta_{t}^{A d a m}所在方向及其正交方向上的两个方向之和:

上图中pp为Adam的下降方向, gg为SGD优化算法求得的梯度方向, γ\gamma为SGD的学习率.

ηtSGD\eta_{t}^{S G D}ηtAdam\eta_{t}^{A d a m}方向上的投影, 就意味着SGD在Adam算法决定的下降方向上前进的距离, 而在ηtAdam\eta_{t}^{A d a m}正交方向上的投影是SGD在自己选择的修正方向上前进的距离. 因此, 如果SGD要走完Adam未走完的路, 需要先沿着ηtAdam\eta_{t}^{A d a m}方向走一步, 然后沿着其正交方向上再走一步.

那么SGD的学习率(步长)可以如下参考确定. SGD在Adam下降方向上的正交投影, 应该正好等于Adam的下降方向, 即:

projηtSGD=ηtAdam\operatorname{proj}_{\eta_{t}^{S G D}}=\eta_{t}^{A d a m}

求解上面的方程, 就能得到SGD的学习率:

αtSGD=((ηtAdam)TηtAdam)/((ηtAdam)Tgt)\alpha_{t}^{S G D}=\left(\left(\eta_{t}^{A d a m}\right)^{T} \eta_{t}^{A d a m}\right) /\left(\left(\eta_{t}^{A d a m}\right)^{T} g_{t}\right)

为了减少噪声影响, 作者使用移动平均值来修正对学习率的估计:

λtSGD=β2λt1SGD+(1β2)αtSGDλ~tSGD=λtSGD/(1β2t)\begin{array}{l} \lambda_{t}^{S G D}=\beta_{2} \cdot \lambda_{t-1}^{S G D}+\left(1-\beta_{2}\right) \cdot \alpha_{t}^{S G D} \\ \tilde{\lambda}_{t}^{S G D}=\lambda_{t}^{S G D} /\left(1-\beta_{2}^{t}\right) \end{array}

这里直接复用了Adam的β2\beta_{2}超参数.

什么时候进行切换?

在整个优化过程中, 即使是使用Adam的阶段, 一直计算上式中的λ~tSGD\tilde{\lambda}_{t}^{S G D}. SGD的相应学习率的移动平均值基本不变的时候:

λ~tSGDαtSGD<ε\left|\tilde{\lambda}_{t}^{S G D}-\alpha_{t}^{S G D}\right|<\varepsilon

那么就由Adam切换到SGD, 并以λ~tSGD\tilde{\lambda}_{t}^{S G D}的学习率继续训练.

Nadam

Adam集成了一阶动量和二阶动量, 具有很好的特性. Nadam是在Adam的基础上, 进一步集成了NAG(Nesterov Accelerated Gradient), Nadam = Nesterov + Adam.

gt=f(wtαmt1/Vt1)g_{t}=\nabla f\left(w_{t}-\alpha \cdot m_{t-1} / \sqrt{V_{t-1}}\right)

参考资料

最后更新于