深度学习中的优化器之AdaMax算法原理与实现细节
1. 题目描述
AdaMax 是Adam优化器的一个变体,由Adam原论文作者提出。它修改了Adam算法中自适应学习率的更新规则,将Adam中基于L2范数的指数加权移动平均(用于缩放学习率的 \(v_t\) 项)替换为基于无穷范数(L-∞范数)的更新。该算法旨在为梯度幅值较大的参数提供更稳定的更新范围,并在某些场景下(尤其是梯度稀疏或呈指数分布时)具有更好的理论性质和更简洁的更新公式。
2. 背景:从Adam到AdaMax
在深入AdaMax之前,需先回顾Adam的核心步骤。Adam结合了动量(Momentum)和自适应学习率(RMSProp的思想),其更新过程如下:
- 计算梯度的一阶矩(均值,即动量)\(m_t\) 和二阶矩(未中心化的方差)\(v_t\) 的指数移动平均。
- 修正偏差(Bias Correction)。
- 参数更新时,学习率除以 \(\sqrt{v_t + \epsilon}\)(即自适应缩放)。
其中,\(v_t\) 的更新公式为:
\[v_t = \beta_2 v_{t-1} + (1 - \beta_2) g_t^2 \]
这里 \(g_t^2\) 表示逐元素平方,本质上是梯度的L2范数的平方。Adam的作者观察到,可以将这种基于L2范数的推广到基于Lp范数,并证明当 \(p \to \infty\) 时,更新规则会变得更简单且稳定,这就是AdaMax的出发点。
3. 算法原理
3.1 核心修改:用无穷范数替代L2范数
Adam中 \(v_t\) 的更新可视为以下递推式的一般化形式:
\[v_t = \beta_2^p v_{t-1} + (1 - \beta_2^p) |g_t|^p \]
当 \(p=2\) 时,就是Adam。现考虑 \(p \to \infty\) 时的极限情况:
- 对于标量 \(u\) 和 \(v\),有 \((u^p + v^p)^{1/p} \to \max(|u|, |v|)\) 当 \(p \to \infty\)。
- 将这一性质应用到向量形式的梯度更新上,定义 \(u_t = \beta_2 \cdot u_{t-1} \) 和当前梯度绝对值 \(|g_t|\) 的逐元素最大值:
\[u_t = \max(\beta_2 \cdot u_{t-1}, |g_t|) \]
此处 \(u_t\) 和 \(g_t\) 均为向量,\(\max\) 运算为逐元素取最大值。\(u_t\) 本质上是梯度绝对值的一个“衰减的最大值”。
- 在Adam中,参数更新时的步长缩放因子为 \(1 / (\sqrt{v_t} + \epsilon)\),其中 \(v_t\) 近似为梯度平方的指数平均。在AdaMax中,用 \(u_t\) 替代 \(\sqrt{v_t}\),步长缩放因子变为 \(1 / u_t\)。
3.2 算法步骤
假设待优化参数为 \(\theta\),目标函数为 \(J(\theta)\),梯度为 \(g_t = \nabla_\theta J_t(\theta_{t-1})\)。超参数包括:学习率 \(\alpha\),一阶矩衰减率 \(\beta_1\),二阶矩衰减率 \(\beta_2\),以及极小常数 \(\epsilon\)(通常可忽略,因为用 \(u_t\) 做分母不会太小)。算法步骤如下:
-
初始化:
- 一阶矩变量 \(m_0 = 0\)
- 无穷范数矩变量 \(u_0 = 0\)
- 时间步 \(t = 0\)
-
迭代更新(对于每个时间步 \(t = 1, 2, \dots\)):
a. 计算梯度 \(g_t\)。
b. 更新一阶矩(动量):
\[ m_t = \beta_1 \cdot m_{t-1} + (1 - \beta_1) \cdot g_t \]
c. 更新无穷范数矩(核心修改):
\[ u_t = \max(\beta_2 \cdot u_{t-1}, |g_t|) \]
其中 $|\cdot|$ 是逐元素绝对值,$\max$ 是逐元素取最大值。
d. 偏差修正一阶矩(可选,但通常保留以与Adam一致):
\[ \hat{m}_t = \frac{m_t}{1 - \beta_1^t} \]
e. 参数更新:
\[ \theta_t = \theta_{t-1} - \frac{\alpha}{1 - \beta_1^t} \cdot \frac{m_t}{u_t} \]
或者使用修正后的 $\hat{m}_t$ 写成:
\[ \theta_t = \theta_{t-1} - \alpha \cdot \frac{\hat{m}_t}{u_t} \]
3.3 直观理解与优势
- 稳定缩放:\(u_t\) 是梯度绝对值的一个“衰减的最大值”,因此它不会像Adam中的 \(v_t\)(平方平均)那样对极端梯度值过于敏感。这使得 \(u_t\) 作为分母时,更新步长在梯度幅值变化大时更稳定。
- 参数简化:由于 \(u_t\) 本身是绝对值尺度,不需要再开平方(Adam需要 \(\sqrt{v_t}\)),也无需添加 \(\epsilon\) 防止除零(因为 \(u_t\) 至少会从初始梯度得到非零值,除非梯度恒为零)。
- 理论性质:在假设梯度服从指数分布时,AdaMax的更新量具有更好的边界性质。
4. 实现细节
4.1 初始化
- \(m_0\) 和 \(u_0\) 初始化为与参数 \(\theta\) 同形状的零张量。
- 通常设置 \(\beta_1 = 0.9\),\(\beta_2 = 0.999\),\(\alpha = 0.002\)(或依任务调整)。
4.2 计算逐元素最大值
在代码中,步骤2c的 \(\max\) 运算需对每个参数维度独立进行:
u_t = torch.max(beta2 * u_prev, torch.abs(g_t)) # PyTorch示例
4.3 偏差修正
- 一阶矩 \(m_t\) 的偏差修正是必要的,尤其在初始步数较少时,因为 \(m_0=0\) 会引入偏差。
- 但 \(u_t\) 不需要偏差修正,因为其更新基于最大值运算,没有向零收缩的偏差。
4.4 参数更新公式
最终更新步骤可直接用向量化运算实现:
alpha = 0.002
beta1, beta2 = 0.9, 0.999
m_hat = m_t / (1 - beta1**t)
theta_t = theta_prev - alpha * m_hat / u_t
5. 与Adam的对比
| 特性 | Adam | AdaMax |
|---|---|---|
| 二阶矩估计 | 梯度平方的指数平均 (\(v_t\)) | 梯度绝对值衰减最大值 (\(u_t\)) |
| 缩放分母 | \(\sqrt{v_t} + \epsilon\) | \(u_t\)(无需 \(\epsilon\)) |
| 对极端梯度 | 较敏感(平方放大) | 较稳健(最大值抑制) |
| 超参数 | \(\beta_1, \beta_2, \epsilon\) | \(\beta_1, \beta_2\)(通常省略 \(\epsilon\)) |
| 偏差修正 | 对 \(m_t\) 和 \(v_t\) 均需 | 仅对 \(m_t\) 需要 |
6. 应用场景与局限
- 适用场景:当梯度分布稀疏或包含较大异常值时,AdaMax可能比Adam更稳定。在自然语言处理(如Transformer训练)和某些计算机视觉任务中曾有应用。
- 局限:实际中,Adam因其普适性和调参经验丰富,仍更常用。AdaMax的性能优势并非总是显著,且许多深度学习库的默认优化器仍是Adam。
7. 总结
AdaMax是Adam优化器的自然扩展,通过将L2范数替换为L-∞范数,简化了更新公式并可能在某些情况下提供更稳定的更新幅度。其核心在于用梯度绝对值的衰减最大值(\(u_t\))作为学习率的缩放因子,避免了对梯度平方平均的开方操作。实现时需注意逐元素最大值运算和动量项的偏差修正。尽管AdaMax理论上具有优势,但在实践中是否选择它仍需结合具体任务进行验证。