Appearance
Adam算法
Adam 是深度学习的 “全能优化器”—— 融合了动量法的 “惯性加速” 和 RMSProp 的 “自适应步长”,还解决了初始偏差的问题,就像登山者既带了登山杖(保持冲劲),又能根据路况自动调整步长(陡坡小步、平路大步),还能在起步时调整初始的小步幅,是深度学习的默认首选优化器。
一、核心逻辑:为啥 Adam 是 “全能登山法”?
1. 动量法和 RMSProp 的小痛点
动量法:只有惯性,步长固定,遇到陡坡(梯度大的方向)容易震荡,就像登山者带着惯性冲坡,遇到陡坡时容易晃得摔倒;
RMSProp:只有自适应步长,没有惯性,收敛慢,就像登山者能调步长,但没有冲劲,平路也走得很慢。
2. Adam 的解决方案
Adam 给登山者加了 “全能装备”:
带惯性:像动量法一样,记住过去的梯度方向,积累冲劲,顺坡方向加速;
自适应步长:像 RMSProp 一样,根据梯度大小自动调整步长,陡坡小步、平路大步;
偏差校正:解决初始时动量和梯度平方的估计偏差,起步时自动调整步幅,避免前期走得太慢。
简单说:Adam 让登山者 “既冲得快,又走得稳,起步还不拖沓”,是目前最实用的优化算法。
二、Adam 的核心原理
1. 核心公式
Adam 需要维护两个状态变量,加上偏差校正,共 4 个步骤:
其中:
:动量,是过去梯度的加权平均,相当于登山者的 “冲劲”;
:梯度平方的加权平均,相当于登山者的 “路况记录”;
:动量系数,常用 0.9,相当于记住最近 10 步的梯度;
:遗忘系数,常用 0.999,相当于记住最近 1000 步的梯度平方;
:全局学习率,常用 0.001,控制整体步长;
:极小常数(比如 ),防止除以 0;
和 :校正后的动量和梯度平方,解决初始时估计值太小的问题。
2. 公式解读
动量更新: 是过去梯度的加权和,越近的梯度权重越大, 时,10 步前的梯度权重只有 ,相当于慢慢遗忘更早的梯度;
梯度平方更新: 是过去梯度平方的加权和, 时,1000 步前的梯度平方权重只有 ,相当于记住很久的路况;
偏差校正:初始时 ,前几步的估计值太小,校正后能让起步时的步幅更合理,避免前期走得太慢;
参数更新:用校正后的动量和梯度平方调整步长, 相当于 “带惯性的自适应步长”,既保持冲劲,又适配路况。
3. 与动量法、RMSProp 的核心区别
| 特性 | 动量法 | RMSProp | Adam |
|---|---|---|---|
| 惯性(动量) | 有 | 无 | 有 |
| 自适应步长 | 无 | 有 | 有 |
| 偏差校正 | 无 | 无 | 有 |
| 收敛速度 | 中等 | 中等 | 快 |
| 震荡程度 | 大 | 小 | 极小 |
| 适用场景 | 凸问题、简单任务 | 非凸问题、稀疏数据 | 所有深度学习任务 |
三、实战对比:Adam vs 动量法 vs RMSProp
用二维函数 测试:
动量法:需要设置 , ,20 轮后 接近 0,但 还有震荡;
RMSProp:需要设置 , ,20 轮后 和 都接近 0,但收敛速度比动量法慢;
Adam:设置 , , ,10 轮后就收敛到最小值,且轨迹非常平滑,没有震荡。
这就像动量法登山者冲得快但容易晃,RMSProp 登山者走得稳但慢,Adam 登山者既快又稳,还能在起步时调整步幅,快速到达山脚。
四、PyTorch 实战:全能登山流程
1. 从零开始实现
手动实现 Adam 的参数更新逻辑,适合理解原理:
python
import torch
from torch import nn
from d2l import torch as d2l
# 1. 初始化Adam状态(每个参数需要两个状态变量:动量、梯度平方)
def init_adam_states(feature_dim):
v_w = torch.zeros((feature_dim, 1)) # 权重的动量
s_w = torch.zeros((feature_dim, 1)) # 权重的梯度平方
v_b = torch.zeros(1) # 偏置的动量
s_b = torch.zeros(1) # 偏置的梯度平方
return ((v_w, s_w), (v_b, s_b))
# 2. Adam更新函数
def adam(params, states, hyperparams):
beta1, beta2, eps = 0.9, 0.999, 1e-6
for p, (v, s) in zip(params, states):
with torch.no_grad():
# 计算动量的指数加权移动平均
v[:] = beta1 * v + (1 - beta1) * p.grad
# 计算梯度平方的指数加权移动平均
s[:] = beta2 * s + (1 - beta2) * torch.square(p.grad)
# 偏差校正
v_bias_corr = v / (1 - beta1 ** hyperparams['t'])
s_bias_corr = s / (1 - beta2 ** hyperparams['t'])
# 更新参数
p[:] -= hyperparams['lr'] * v_bias_corr / (torch.sqrt(s_bias_corr) + eps)
p.grad.data.zero_() # 清空梯度
hyperparams['t'] += 1 # 时间步加1
# 3. 训练函数
def train_adam(lr, num_epochs=2):
# 加载数据
data_iter, feature_dim = d2l.get_data_ch11(batch_size=10)
# 定义模型
net = nn.Sequential(nn.Linear(feature_dim, 1))
nn.init.normal_(net[0].weight, std=0.01)
# 训练(初始化时间步t=1)
d2l.train_ch11(
adam,
init_adam_states(feature_dim),
{'lr': lr, 't': 1},
data_iter, feature_dim, num_epochs
)
# 启动训练(Adam的默认学习率是0.001)
train_adam(lr=0.001)2. 框架简洁实现
用 PyTorch 内置的optim.Adam直接调用,更简洁:
python
# 直接使用框架内置的Adam
trainer = torch.optim.Adam
d2l.train_concise_ch11(
trainer,
{'lr': 0.001}, # 默认beta1=0.9,beta2=0.999
data_iter
)五、Adam 的改进版:Yogi
Adam 在某些场景下(比如梯度平方爆炸的稀疏数据)可能会发散,Yogi 是 Adam 的 “热补丁”,解决了这个问题:
核心改进:把梯度平方的更新从 改为
效果:避免了梯度平方的估计值爆炸,在稀疏数据场景下更稳定。
Yogi 的 PyTorch 实现
python
def yogi(params, states, hyperparams):
beta1, beta2, eps = 0.9, 0.999, 1e-6
for p, (v, s) in zip(params, states):
with torch.no_grad():
# 动量更新(和Adam一样)
v[:] = beta1 * v + (1 - beta1) * p.grad
# Yogi的梯度平方更新
s[:] = s + (1 - beta2) * torch.sign(torch.square(p.grad) - s) * torch.square(p.grad)
# 偏差校正(和Adam一样)
v_bias_corr = v / (1 - beta1 ** hyperparams['t'])
s_bias_corr = s / (1 - beta2 ** hyperparams['t'])
# 参数更新
p[:] -= hyperparams['lr'] * v_bias_corr / (torch.sqrt(s_bias_corr) + eps)
p.grad.data.zero_()
hyperparams['t'] += 1六、优缺点:什么时候用 Adam?
1. 优点
收敛快且稳定:既有惯性加速,又有自适应步长,还能校正初始偏差,是目前最均衡的优化器;
不需要手动调参:默认参数( , , )适合大部分任务;
适用范围广:几乎所有深度学习任务都能用,包括图像分类、自然语言处理、推荐系统等。
2. 缺点
在凸问题中可能不如 SGD:Adam 可能收敛到局部最小值,而 SGD 在凸问题中能收敛到全局最小值;
稀疏数据场景下可能过拟合:自适应步长可能让低频特征的步长太大,导致过拟合;
计算量略大:需要维护两个状态变量,比动量法和 RMSProp 的计算量略大。
3. 适用场景
大部分深度学习任务:Adam 是默认首选,尤其是复杂的非凸任务(比如 Transformer、CNN);
快速上手的场景:不想手动调参时,Adam 的默认参数就能取得不错的效果;
替代动量法和 RMSProp 的场景:当动量法震荡太大、RMSProp 收敛太慢时,用 Adam 替代。
七、常见误区:避开这 3 个坑
学习率设置太大:Adam 的默认学习率是 0.001,不要像 SGD 那样用 0.01,否则会震荡发散;
忽略偏差校正:初始几步的偏差校正很重要,去掉的话前期收敛会很慢;
在凸问题中滥用 Adam:凸问题中 SGD 可能收敛到更好的全局最小值,Adam 可能卡在局部最小值。
八、核心总结
Adam 本质:带惯性的自适应步长优化器,融合了动量法和 RMSProp 的优点,还解决了初始偏差的问题;
关键参数: (惯性大小), (遗忘系数), (全局学习率);
核心优势:收敛快、稳定,不需要手动调参,是深度学习的默认首选;
一句话记忆:登山时既带冲劲又能自动调步长,起步还能调整步幅,全能装备带你高效下山~
(注:文档部分内容可能由 AI 生成)