深度学习中的优化器之Yogi算法原理与自适应学习率机制
1. 题目描述
Yogi优化器是2018年提出的一种自适应学习率优化算法,旨在改进Adam系列优化器在非凸优化问题中可能遇到的收敛性不足或性能下降的问题。它通过修改Adam中二阶矩(梯度平方)的估计更新方式,引入一个自适应矫正机制,使得算法在稀疏梯度或噪声较大的场景下具有更稳定的收敛行为。核心目标是:在保持Adam自适应学习率优点的同时,增强其鲁棒性和最终收敛精度。
2. 背景与动机
- Adam优化器的局限性:
Adam使用指数移动平均(EMA)估计梯度的一阶矩(均值)和二阶矩(未中心化的方差)。但在训练后期或梯度稀疏时,二阶矩的EMA估计可能过度累积历史平方梯度,导致学习率过小,更新停滞,从而影响收敛到更优解。 - 理论洞察:
研究发现,Adam的收敛性分析依赖于二阶矩估计的“长期记忆”特性。Yogi通过动态调整历史信息的衰减速度,在梯度较大时快速更新二阶矩,梯度较小时避免过度累积,从而平衡探索与利用。
3. 核心原理:二阶矩的自适应修正
设目标函数为 \(f(\theta)\),参数 \(\theta\),随机梯度为 \(g_t\)。Yogi的更新步骤如下:
步骤1:一阶矩估计(与Adam相同)
\[m_t = \beta_1 m_{t-1} + (1 - \beta_1) g_t \]
- \(m_t\):梯度一阶矩的指数移动平均,估计梯度方向。
- \(\beta_1\):衰减率(通常取0.9)。
步骤2:二阶矩估计(Yogi的关键创新)
Adam的二阶矩更新为:
\[v_t^{\text{Adam}} = \beta_2 v_{t-1} + (1 - \beta_2) g_t^2 \]
Yogi将其修改为:
\[v_t = v_{t-1} - (1 - \beta_2) \cdot \text{sign}(v_{t-1} - g_t^2) \cdot g_t^2 \]
或等价写作:
\[v_t = v_{t-1} + (1 - \beta_2) \cdot \left( g_t^2 - v_{t-1} \cdot \text{sign}(g_t^2 - v_{t-1}) \right) \]
- 直观解释:
- 当 \(g_t^2 > v_{t-1}\)(当前梯度平方大于历史估计),Yogi与Adam相同:\(v_t\) 增加。
- 当 \(g_t^2 < v_{t-1}\)(当前梯度平方小于历史估计),Yogi改为:\(v_t = v_{t-1} - (1-\beta_2) g_t^2\)(即减去一部分当前值),而非Adam的继续累积。
- 效果:在梯度变小时,Yogi避免 \(v_t\) 无限增长,防止学习率过早衰减;在梯度突变增大时,仍能快速响应。
步骤3:偏差校正(与Adam相同)
由于 \(m_t, v_t\) 在初始步偏向零,需进行校正:
\[\hat{m}_t = \frac{m_t}{1 - \beta_1^t}, \quad \hat{v}_t = \frac{v_t}{1 - \beta_2^t} \]
步骤4:参数更新
\[\theta_t = \theta_{t-1} - \eta \cdot \frac{\hat{m}_t}{\sqrt{\hat{v}_t} + \epsilon} \]
- \(\eta\):学习率。
- \(\epsilon\):小常数(如1e-8)防止除零。
4. 与Adam的对比分析
| 特性 | Adam | Yogi |
|---|---|---|
| 二阶矩更新 | \(v_t = \beta_2 v_{t-1} + (1-\beta_2) g_t^2\) | 引入 sign() 自适应调整增减方向 |
| 历史累积 | 始终累积 \(g_t^2\) | 梯度小时减少累积,防止 \(v_t\) 过大 |
| 学习率衰减 | 可能过快(尤其稀疏梯度) | 更平缓,后期仍保持较大更新步长 |
| 收敛性能 | 有时陷入次优解 | 更稳定,常达到更低训练损失 |
5. 实际应用细节
- 超参数设置:
- 推荐 \(\beta_1 = 0.9, \beta_2 = 0.999, \epsilon = 10^{-8}\)。
- 学习率 \(\eta\) 可比Adam略大(例如1e-2到1e-3)。
- 适用场景:
- 梯度稀疏或噪声大的任务(如自然语言处理中的嵌入层训练)。
- 非凸损失曲面复杂、Adam收敛不稳定的情况。
- 代码示例(PyTorch风格):
import torch class Yogi(torch.optim.Optimizer): def __init__(self, params, lr=1e-2, beta1=0.9, beta2=0.999, eps=1e-8): defaults = dict(lr=lr, beta1=beta1, beta2=beta2, eps=eps) super().__init__(params, defaults) def step(self): for group in self.param_groups: for p in group['params']: if p.grad is None: continue grad = p.grad.data state = self.state[p] if len(state) == 0: state['step'] = 0 state['m'] = torch.zeros_like(p.data) state['v'] = torch.zeros_like(p.data) m, v = state['m'], state['v'] beta1, beta2 = group['beta1'], group['beta2'] state['step'] += 1 t = state['step'] # 更新一阶矩 m.mul_(beta1).add_(grad, alpha=1-beta1) # 更新二阶矩(Yogi核心) v.addcmul_(grad, grad, value=-(1-beta2) * torch.sign(v - grad*grad)) # 偏差校正 m_hat = m / (1 - beta1**t) v_hat = v / (1 - beta2**t) # 参数更新 p.data.addcdiv_(m_hat, v_hat.sqrt() + group['eps'], value=-group['lr'])
6. 理论优势与实验效果
- 理论保证:
Yogi在非凸优化中满足收敛性定理,其自适应机制可证明在某些条件下比Adam有更紧的收敛界。 - 实验验证:
在图像分类(CIFAR)、语言建模(Penn Treebank)等任务中,Yogi相比Adam常取得:- 更低的最终训练损失。
- 验证集准确率小幅提升(约0.5-1%)。
- 对超参数(如初始学习率)的敏感性降低。
7. 总结
Yogi优化器通过修改二阶矩的更新策略,在梯度较小时减少历史累积,有效缓解了Adam可能存在的“学习率过早衰减”问题。它在保持自适应学习率便捷性的同时,提升了优化过程的鲁棒性和最终性能,特别适用于梯度稀疏或噪声明显的深度学习任务。实践者可将其作为Adam的替代选项,在复杂模型训练中尝试使用。