训练神经网络本质上是在做一件事最小化损失函数其中 (\theta) 是模型参数权重、偏置等。优化算法决定了你怎么更新参数(\eta) 是学习率learning rate(g) 是梯度或其变体。这篇把李沐常讲的“基础优化方法”按直觉 公式 PyTorch 用法 常见坑梳理一遍。1. 为什么需要“优化算法”因为深度学习的损失函数通常维度极高百万/十亿参数非凸有山谷、鞍点、噪声数据量大无法每一步用全量数据所以最常见策略是小批量随机梯度下降mini-batch SGD。2. 梯度下降家族BGD / SGD / Mini-batch假设损失是样本损失的平均2.1 批量梯度下降Batch GD每步用全部 n 个样本计算梯度稳定但慢。2.2 随机梯度下降SGD每步只用 1 个样本快但抖动大。2.3 小批量 SGDMini-batch SGD每步用一小批 B深度学习默认选择兼顾效率与稳定。更新式最常见3. 学习率lr最重要的超参数没有之一lr 太大loss 震荡、发散lr 太小收敛慢像“挪着走”常见技巧学习率衰减schedule比如训练后期逐步变小实战感受你调参 80% 的时间都在调 lr。4. 动量法Momentum让下降方向“更有惯性”SGD 会在狭长山谷里左右抖动某个方向梯度大来回震动量可以抑制抖动加速沿主方向前进。典型形式直觉方向一致的梯度会累积 → 加速来回震荡的方向会互相抵消 → 稳定PyTorch 用法torch.optim.SGD(params, lr0.1, momentum0.9)5. 自适应学习率方法AdaGrad / RMSProp / Adam这些方法核心思想不同参数用不同“有效学习率”。5.1 AdaGrad越学越“保守”累积平方梯度问题(s_t) 一直增大 → 后期学习率趋近 0 → 可能“提前停滞”。PyTorchtorch.optim.Adagrad(params, lr0.1)5.2 RMSProp解决 AdaGrad 过早衰减把“累积”换成“滑动平均”这样不会无限增大。PyTorchtorch.optim.RMSprop(params, lr0.001, alpha0.99)5.3 Adam动量 RMSProp最常用默认优化器Adam 同时维护一阶矩梯度平均动量二阶矩平方梯度平均自适应 lrPyTorchtorch.optim.Adam(params, lr0.001, betas(0.9, 0.999))经验结论工程常识线性模型/凸问题SGD(momentum) 很强深层网络Adam 作为默认 baseline 很省心最终追极致泛化很多任务会 Adam 预热 → SGD 精调看领域6. 小实验同一线性回归任务对比 SGD vs Momentum vs Adam下面代码跑一个合成线性回归记录每个 epoch 的 loss你写博客可以直接贴输出截图。import torch torch.manual_seed(0) # 数据y Xw b noise n, d 2000, 2 true_w torch.tensor([[2.0], [-3.4]]) true_b 4.2 X torch.randn(n, d) y X true_w true_b torch.randn(n, 1) * 0.01 def train(optim_namesgd, lr0.03, momentum0.9, epochs10, batch_size64): w torch.randn(d, 1, requires_gradTrue) b torch.zeros(1, requires_gradTrue) params [w, b] if optim_name sgd: opt torch.optim.SGD(params, lrlr) elif optim_name momentum: opt torch.optim.SGD(params, lrlr, momentummomentum) elif optim_name adam: opt torch.optim.Adam(params, lr0.001) # Adam 通常更小 lr else: raise ValueError(unknown optimizer) def data_iter(): idx torch.randperm(n) for i in range(0, n, batch_size): j idx[i:ibatch_size] yield X[j], y[j] losses [] for epoch in range(epochs): for Xb, yb in data_iter(): y_hat Xb w b loss ((y_hat - yb) ** 2).mean() / 2 opt.zero_grad() loss.backward() opt.step() with torch.no_grad(): full_loss (((X w b) - y) ** 2).mean().item() / 2 losses.append(full_loss) return losses print(SGD:, train(sgd, lr0.03, epochs8)) print(Momentum:, train(momentum, lr0.03, epochs8)) print(Adam:, train(adam, epochs8))你通常会观察到Momentum 比纯 SGD 更稳、更快Adam 很快把 loss 拉下去对超参数更不敏感7. 常见坑优化器用错导致“训练假努力”忘了清梯度手写更新w.grad.zero_()用优化器opt.zero_grad()学习率不匹配SGD 常用1e-1 ~ 1e-2 ~ 1e-3看任务Adam 常从1e-3起步更稳batch_size 变了但 lr 不调整batch 变大梯度更稳定lr 往往可以适当增大不是绝对但常见loss 降不下去就怪模型先查lr、数据标准化、梯度是否为 None、是否进入no_grad了结语怎么选优化器李沐风格的“够用策略”学习/作业/小项目Adam省心 baseline想要更稳的 SGDSGD momentum经常更泛化lr 是第一优先级调对 lr比换优化器更有效