第四讲:优化器配置——SGD、Adam、AdamW的选择标准与超参数调优
优化器这东西,说白了就是告诉模型「往哪个方向走、走多大步」。我见过太多同学在优化器上翻车——要么模型死活不收敛,要么loss炸到天上去。今天咱们就把SGD、Adam、AdamW这三个主流优化器掰开揉碎讲清楚。
4.1 三大优化器的核心差异
先给个直观对比,你心里有个底:
| 优化器 | 核心思想 | 适用场景 | 我个人的使用频率 |
|---|---|---|---|
| SGD + Momentum | 梯度下降 + 动量累积 | CV、小批量数据、需要精细调参 | 30% |
| Adam | 自适应学习率 + 动量 | NLP、GAN、快速原型验证 | 50% |
| AdamW | Adam + 解耦权重衰减 | Transformer、大模型、需要正则化 | 20% |
嗯,这里要注意:AdamW不是Adam的简单升级版,它修正了Adam里weight_decay的实现方式。我在项目中遇到过用Adam训BERT,loss降不下去,换成AdamW立马见效——原因就是权重衰减被正确解耦了。
4.2 SGD:老派但可靠
SGD + Momentum,我习惯叫它「手动挡」。为什么?因为所有超参数都得你亲手调,调好了性能上限很高,调不好就原地踏步。
关键超参数:
- lr(学习率):典型值0.01~0.1。我一般从0.1开始试,如果loss震荡就降到0.01。
- momentum:通常取0.9。别乱改,0.9是经过大量验证的黄金值。
- weight_decay:1e-4 ~ 5e-4。太大模型欠拟合,太小过拟合。
# 我常用的SGD配置
optimizer = torch.optim.SGD(
model.parameters(),
lr=0.1,
momentum=0.9,
weight_decay=1e-4,
nesterov=True # 我习惯开Nesterov,收敛略快
)
为什么会有人坚持用SGD?因为它的泛化能力确实好。Adam有时候会「记住」训练集上的噪声,SGD反而更鲁棒。不过代价就是——你得有耐心,SGD收敛慢,经常要跑几百个epoch。
我的小技巧:用SGD时,配合余弦退火学习率调度(CosineAnnealingLR),效果比StepLR好很多。我曾经在ResNet50上对比过,余弦退火让top-1准确率提升了0.8%。
4.3 Adam:快速上手首选
Adam就像自动挡汽车——大部分情况你踩油门就走。它自适应调整每个参数的学习率,对lr不那么敏感。
但注意,这不代表你可以乱设lr。我见过有人把lr设成0.1,结果loss直接NaN。Adam的lr通常比SGD小一个数量级。
关键超参数:
- lr:典型值1e-4 ~ 3e-4。Transformer用5e-5都常见。
- betas:默认(0.9, 0.999)。第一个是动量衰减,第二个是梯度平方衰减。
- eps:1e-8。防止除零,一般不动。
# Adam的标准配置
optimizer = torch.optim.Adam(
model.parameters(),
lr=1e-4,
betas=(0.9, 0.999),
eps=1e-8,
weight_decay=0 # Adam里我通常不开weight_decay
)
这里有个坑:Adam的weight_decay实现有问题。它把权重衰减加到了梯度里,而不是直接更新参数。这会导致正则化效果变差。所以——
警告:如果你用Adam,又想加权重衰减,请直接用AdamW。别在Adam里设weight_decay,那是伪正则化。
4.4 AdamW:大模型时代的标配
AdamW解决了Adam的权重衰减问题。说白了,就是把「权重衰减」和「梯度更新」解耦了。你想想看,Adam本来就在自适应调整学习率,再把权重衰减混进去,两个机制互相打架,效果能好吗?
AdamW的做法很简单:先做Adam的梯度更新,再单独对参数做权重衰减。这样互不干扰。
# AdamW的正确用法
optimizer = torch.optim.AdamW(
model.parameters(),
lr=1e-4,
betas=(0.9, 0.999),
weight_decay=0.01 # 这里可以放心设大一点
)
我个人的经验:训练GPT、BERT这类大模型时,AdamW的weight_decay设0.01~0.1效果都不错。太小了过拟合,太大了模型学不动。
4.5 超参数调优实战指南
调优这事儿,说白了就是试错。但我们可以让试错更有章法。
4.5.1 学习率:最重要的超参数
学习率决定了模型能不能收敛。我有个「三板斧」方法:
- 先跑学习率范围测试:从1e-6到1,指数增长,看loss曲线。找到loss下降最快的区间。
- 选中间值:比如测试发现1e-4到1e-3效果最好,那就取3e-4。
- 配合warmup:前5%~10%的step线性增加lr,防止一开始就震荡。
避坑指南:我曾经在训练一个文本分类模型时,lr设成1e-3,loss一直不降。后来用学习率范围测试才发现,最佳lr是5e-5——差了20倍!所以别凭感觉设lr,跑个测试花不了几分钟。
4.5.2 betas:Adam家族的专属调节
betas控制着动量和平滑程度。默认(0.9, 0.999)对大多数任务都够用,但有些场景需要调整:
| 场景 | 建议betas | 原因 |
|---|---|---|
| 稀疏梯度(如NLP) | (0.9, 0.999) | 默认就很好 |
| 密集梯度(如CV) | (0.9, 0.99) | 减少二阶动量平滑,加速收敛 |
| 训练不稳定 | (0.95, 0.999) | 增大一阶动量,让更新更平滑 |
嗯,这里要注意:beta1越大,动量越强,模型越不容易震荡,但也可能错过最优解。我一般只在loss震荡时才调高beta1。
4.5.3 weight_decay:正则化的艺术
权重衰减说白了就是L2正则化。但不同优化器的最佳值差很多:
- SGD:1e-4 ~ 5e-4。太大模型欠拟合。
- Adam:不建议用,用AdamW代替。
- AdamW:0.01 ~ 0.1。大模型可以到0.1。
注意:weight_decay不是越大越好。我见过有人设0.5,结果模型直接学成常数——所有参数都趋近于0。一般从0.01开始试,如果验证集loss下降就继续增大,直到验证集loss开始上升为止。
4.6 我的选择策略总结
说了这么多,到底怎么选?我有个简单的决策树:
- 数据量小(<1万):用SGD + Momentum。Adam容易过拟合。
- 数据量大,任务简单:用Adam。省心,收敛快。
- 大模型、Transformer:用AdamW。别无他选。
- 不确定:先用Adam跑10个epoch看趋势,再决定要不要换。
最后说一句:没有万能优化器。我见过用SGD训出SOTA的,也见过用AdamW训崩的。关键是你得理解每个超参数在干什么,然后根据loss曲线去调。嗯,多试几次就有感觉了。