Skip to main content

6.1.5 优化器

优化器路径对比图

本节概览

梯度算出来以后,优化器决定参数怎么移动。优化器名字很重要,但学习率往往更重要。

你会做出什么

这一节会运行一个很小的 PyTorch 优化实验:

  • 在同一个简单 loss 上比较 SGD、Momentum 和 Adam;
  • 直接看到过冲;
  • 测试学习率敏感性;
  • 学会安全的优化器选择顺序。

梯度到参数更新的优化器决策图

环境准备

python -m pip install -U torch

运行完整实验

新建 optimizer_lab.py

import torch


def run_optimizer(name, optimizer_factory, steps=25):
torch.manual_seed(42)
w = torch.nn.Parameter(torch.tensor([5.0]))
optimizer = optimizer_factory([w])
for step in range(1, steps + 1):
loss = (w - 2).pow(2).mean()
optimizer.zero_grad()
loss.backward()
optimizer.step()
if step in [1, 5, 10, 25]:
print(f"{name:<8} step={step:<2} w={w.item():.3f} loss={loss.item():.4f}")


print("optimizer_comparison")
run_optimizer("sgd", lambda params: torch.optim.SGD(params, lr=0.1))
run_optimizer("momentum", lambda params: torch.optim.SGD(params, lr=0.1, momentum=0.9))
run_optimizer("adam", lambda params: torch.optim.Adam(params, lr=0.1))

print("learning_rate_check")
for lr in [0.01, 0.1, 1.1]:
torch.manual_seed(42)
w = torch.nn.Parameter(torch.tensor([5.0]))
optimizer = torch.optim.SGD([w], lr=lr)
for _ in range(10):
loss = (w - 2).pow(2).mean()
optimizer.zero_grad()
loss.backward()
optimizer.step()
final_loss = (w - 2).pow(2).item()
print(f"lr={lr:<4} final_w={w.item():.3f} final_loss={final_loss:.4f}")

运行:

python optimizer_lab.py

预期输出:

optimizer_comparison
sgd step=1 w=4.400 loss=9.0000
sgd step=5 w=2.983 loss=1.5099
sgd step=10 w=2.322 loss=0.1621
sgd step=25 w=2.011 loss=0.0002
momentum step=1 w=4.400 loss=9.0000
momentum step=5 w=0.259 loss=0.8571
momentum step=10 w=2.013 loss=0.6767
momentum step=25 w=2.475 loss=0.0200
adam step=1 w=4.900 loss=9.0000
adam step=5 w=4.502 loss=6.7648
adam step=10 w=4.014 loss=4.4535
adam step=25 w=2.739 loss=0.6569
learning_rate_check
lr=0.01 final_w=4.451 final_loss=6.0085
lr=0.1 final_w=2.322 final_loss=0.1038
lr=1.1 final_w=20.575 final_loss=345.0386

优化器实验结果图

读懂实验

这里的 loss 是:

loss = (w - 2)^2

最佳值是 w=2。所有优化器都从 w=5 出发。

在这个简单例子里,学习率合适的 SGD 表现非常好:

sgd step=25 w=2.011 loss=0.0002

Momentum 移动更快,但可能过冲:

momentum step=5 w=0.259

Adam 是深度学习里很常见的默认选择,但不是魔法。在这个小问题上,lr=0.1 的 Adam 反而比调好的 SGD 慢。重点不是“Adam 不好”,而是:

一定要看训练行为。优化器选择和学习率是一起工作的。

学习率是第一个旋钮

学习率实验故意很直接:

lr=0.01 final_w=4.451 final_loss=6.0085
lr=0.1 final_w=2.322 final_loss=0.1038
lr=1.1 final_w=20.575 final_loss=345.0386

太小:训练很慢。

合适:逐渐接近最优点。

太大:训练发散。

优化器直觉

优化器直觉适合先用在
SGD直接沿负梯度方向移动简单基线、受控实验
SGD + Momentum保留之前步骤的速度噪声方向上更平滑
Adam根据梯度历史自适应步长很多神经网络的强默认选择

真实神经网络里,Adam 或 AdamW 经常是实用起点。最终训练仍然要看任务验证指标。

实用选择顺序

  1. 神经网络基线先用 Adam 或 AdamW。
  2. 先调学习率,再争论优化器名字。
  3. 观察训练 loss 和验证 loss 曲线。
  4. 如果验证不稳定,降低 LR 或加入 schedule。
  5. 如果训练慢但稳定,尝试 LR schedule 或更换优化器。

常见排查清单

现象可能原因修复方式
loss 爆炸学习率太高降低 LR
loss 下降很慢LR 太低或输入尺度差谨慎提高 LR,归一化输入
training loss 降低但 validation 变差过拟合正则化、加数据、早停
loss 来回震荡momentum/LR 太激进降低 LR 或 momentum
Adam 能跑但最终效果弱优化器掩盖了其他问题检查数据、结构、正则化

练习

  1. 把 SGD 学习率改成 0.050.20.8
  2. 把 momentum 从 0.9 改成 0.5。过冲是否减少?
  3. AdamW 替换 Adam
  4. 每一步打印 w.grad,把梯度和更新联系起来。
  5. 为每个优化器画出 w 随 step 的变化。

过关检查

你能解释下面几点,就完成本节:

  • 梯度说明哪个方向会改变 loss;
  • 优化器决定参数走多远;
  • 学习率会让训练变慢、收敛或发散;
  • momentum 可以加速,但也可能过冲;
  • Adam 有用,但不能替代观察训练曲线。