Adam 优化器详解
Adam (Adaptive Moment Estimation) 是目前深度学习领域最流行、最常用的优化器,简直就是优化器界的"瑞士军刀"。
如果说 SGD 是一个醉汉,Momentum 是一个有惯性的铁球,那么 Adam 就是一辆装配了"自适应悬挂系统"的智能跑车。
它之所以强,是因为它结合了两大流派的优点:
- Momentum (动量):解决"方向"问题(惯性,不乱晃)
- RMSProp (自适应学习率):解决"步长"问题(根据地形自动调整刹车或油门)
1. 核心痛点:为什么需要 Adam?
在 Momentum 中,我们虽然解决了震荡问题,但还有一个大问题:所有的参数都共享同一个学习率 。
- 场景: 假设你有两个参数 和
- 对应的坡度非常陡峭(梯度很大),如果步子迈大了,容易飞出去
- 对应的坡度非常平缓(梯度很小),如果步子迈小了,走到猴年马月
- Momentum 的做法: 对不起,我也没办法,大家用一样的步长
- Adam 的做法: 看人下菜碟
- 对陡峭的参数,我自动把学习率调小一点(谨慎)
- 对平缓的参数,我自动把学习率调大一点(加速)
2. Adam 的三个核心组件
Adam 的名字来源于 "Adaptive Moment Estimation"(自适应矩估计)。它维护了两个"变量箱子"(Moment):
组件 A:一阶矩(First Moment)
这就完全等同于我们讲的 Momentum。它记录梯度的指数移动平均值(方向)。
组件 B:二阶矩(Second Moment)
这是 Adam 的精髓。它记录梯度的平方的指数移动平均值(也就是梯度的方差/能量)。
组件 C:偏差修正(Bias Correction)
因为 和 初始值都是 0,刚开始训练时,它们会趋向于 0(偏置),导致起步太慢。所以 Adam 做了一个数学上的修正。
最终更新公式
3. 参数详解
3.1 :当前梯度 (Current Gradient)
- 含义: 在第 步时,损失函数 对参数 的导数
- 物理含义: 此时此刻脚下的坡度(加速度)
- 维度: 与参数 的维度相同(如果模型有 100 万个参数,梯度就是 100 万维的向量)
- 作用: 这是每一步的"新信息源",告诉优化器当前应该往哪个方向走
3.2 :一阶矩估计 (First Moment Estimate)
- 含义: 梯度的指数移动平均值(Exponential Moving Average, EMA)
- 初始值: (全零向量)
- 物理含义: 相当于 Momentum 中的"速度",记录了历史梯度的加权平均方向
- 直觉理解:
- 如果过去几步都往东走, 就会指向东边
- 如果这一步突然要往西走, 不会立刻掉头,而是慢慢转向(惯性)
- 作用: 平滑梯度,减少噪声,保持更新方向的一致性
3.3 :二阶矩估计 (Second Moment Estimate)
- 含义: 梯度平方的指数移动平均值
- 初始值: (全零向量)
- 注意: 是逐元素平方(element-wise),不是矩阵乘法
- 物理含义: 测量每个参数的梯度有多"活跃"或"剧烈"
- 直觉理解:
- 如果某个参数的梯度一直很大(陡峭地形), 就会很大
- 如果某个参数的梯度一直很小(平坦地形), 就会很小
- 作用: 用于自适应调整学习率。 大的参数,学习率会被缩小
3.4 :一阶矩衰减率 (First Moment Decay Rate)
- 含义: 控制一阶矩 的衰减速度
- 典型值: 0.9
- 取值范围:
- 物理含义: 惯性系数,决定保留多少历史信息
- 直觉理解:
- 意味着: 中有 90% 来自历史,10% 来自当前梯度
- :完全没有惯性,,退化成普通梯度
- :惯性非常大,方向变化很慢
- 调参建议:
- 默认值 0.9 通常就够用
- 如果训练不稳定,可以尝试增大到 0.95
3.5 :二阶矩衰减率 (Second Moment Decay Rate)
- 含义: 控制二阶矩 的衰减速度
- 典型值: 0.999
- 取值范围:
- 物理含义: 路况记忆系数,决定记住多久的地形信息
- 直觉理解:
- 意味着: 有 99.9% 来自历史,只有 0.1% 来自当前
- 这使得 变化非常缓慢,是一个长期的"能量估计"
- 比 大,是因为我们希望二阶矩更稳定
- 调参建议:
- 默认值 0.999 几乎不需要改
- 如果遇到训练后期学习率过小的问题,可以尝试 0.99
3.6 :偏差修正后的一阶矩
- 含义: 对 进行偏差修正后的值
- 为什么需要修正?
- 因为 ,在训练初期, 会偏向于 0
- 例如 时:
- 这比真实的梯度 小了 10 倍!
- 修正原理:
- 当 时:分母
- ,修正回正常值
- 随时间变化:
- 随着 增大,,分母
- 修正效果逐渐消失,这正是我们想要的(只在初期起作用)
3.7 :偏差修正后的二阶矩
- 含义: 对 进行偏差修正后的值
- 修正原理: 与 相同
- 注意: 由于 比 更接近 1, 的偏差修正在更多步数内都会起作用
- ,100 步后分母才约等于 0.095
3.8 :学习率 (Learning Rate)
- 含义: 控制每一步更新的基础步长
- 典型值: 0.001(比 SGD 的 0.01 要小)
- 取值范围: ,实际一般在
- 为什么比 SGD 小?
- Adam 自带"加速"机制,学习率设太大容易发散
- 0.001 是论文作者推荐的默认值
- 调参建议:
- 初学者直接用 0.001
- 微调预训练模型时,可以用更小的值如
- 配合学习率调度器(如 Warmup)效果更好
3.9 :数值稳定项 (Epsilon)
- 含义: 防止除以零的小 常数
- 典型值: (即
1e-8) - 取值范围: ,通常是非常小的正数
- 为什么需要?
- 分母是 ,如果 ,就会除 以零
- 加上 确保分母永远不为零
- 调参建议:
- 几乎不需要调整
- 在某些精度敏感的场景(如半精度训练),可能需要增大到 或
3.10 :模型参数 (Model Parameters)
- 含义: 模型在第 步时的所有可训练参数
- 示例: 神经网络中的权重矩阵 和偏置
- 维度: 可以是数百万甚至数十亿维的向量
- 作用: 这是我们要优化的目标,通过不断更新 来最小化损失函数
3.11 :时间步 (Time Step)
- 含义: 当前是第几次参数更新(从 1 开始计数)
- 作用:
- 用于偏差修正公式中的指数计算
- 越大,偏差修正的影响越小
- 注意: 每调用一次
optimizer.step(), 就加 1
4. 公式的直觉理解
让我们用人话翻译最终更新公式:
分子 :往这个方向走!
- 基于惯性和当前坡度计算出的前进方向
- 融合了历史信息和当前梯度
分母 :根据路况调整步幅!
- 如果某个参数的梯度一直很大(陡峭), 很大 → 分母很大 → 步长变小(小心翼翼)
- 如果某个参数的梯度一直很小(平坦), 很小 → 分母很小 → 步长变大(大步流星)
为什么要开根号?
- 是梯度平方的平均,量纲是"梯度²"
- 开根号后变回"梯度"的量纲,与分子 匹配
- 这样分数的结果是一个无量纲的"调整系数"
5. 形象比喻:全地形越野车
| 优化器 | 比喻 | 特点 |
|---|---|---|
| SGD | 你的脚 | 深一脚浅一脚,完全看当前地形 |
| Momentum | 大铁球 | 有惯性,跑得快,但急转弯困难 |
| Adam | 智能越野车 | 自适应悬挂 + 强劲引擎 |
Adam 的两个核心系统:
- 引擎 (Momentum ):提供持续向前的动力,保持方向稳定
- 自适应悬挂 (RMSProp ):
- 遇到颠簸路段(梯度大),悬挂变软,减震,慢行
- 遇到平直路段(梯度小),悬挂变硬,加速冲刺
6. PyTorch 代码实现
基础用法
import torch.optim as optim
# 参数对应公式里的符号:
# lr: 学习率 (η)
# betas: 元组 (β1, β2)
# eps: (epsilon) 防止除以零
optimizer = optim.Adam(
model.parameters(),
lr=0.001, # η: 学习率
betas=(0.9, 0.999), # (β1, β2): 一阶矩和二阶矩的衰减率
eps=1e-8 # ε: 数值稳定项
)