《PyTorch 深度修炼》优化器:参数到底是怎么被更新的

梯度不是参数更新。梯度只是方向,优化器才是真正踩油门的人。

1. 模型参数不会自己变好

模型训练不是"算出 loss 就结束"。loss 只是告诉我们错了多少。

backward 会把错误沿计算图传回去,写到每个参数的 grad 里。

但 grad 还不是更新。grad 只是一个方向提示。真正修改 weight 和 bias 的,是 optimizer.step()。

Autograd 负责算梯度,Optimizer 负责改参数。

2. Optimizer 在训练循环中的位置

一轮训练可以拆成五步:forward、loss、backward、step、zero_grad。

forward 负责预测。loss 负责衡量错误。backward 负责计算梯度。step 负责更新参数。zero_grad 负责清理旧梯度。

这里最容易误解的是 step。step 不会重新计算 loss,也不会自动 backward。它只读取已有的 param.grad,再按算法更新参数。

3. 梯度给方向,学习率给步长

参数更新的最小动作,就是从当前参数出发,沿着让 Loss 下降的方向挪一点。

梯度告诉你坡往哪边陡。学习率告诉你每步走多远。

学习率太小,训练慢。学习率太大,容易震荡,甚至 loss 爆炸。

记忆:梯度是方向盘,学习率是油门,优化器是驾驶策略。

4. SGD:最朴素的更新规则

SGD 的直觉很简单:当前参数减去学习率乘以梯度。

梯度指向 Loss 上升最快的方向。要让 Loss 下降,就反方向走。

SGD 的优点是简单、透明、泛化能力经常不错。缺点是调参比较敏感,训练可能抖。

5. Momentum:让更新带一点惯性

普通 SGD 每一步只看当前梯度。当前梯度有噪声,方向就会左右晃。

Momentum 会维护一个 momentum_buffer。它把历史梯度方向和当前梯度混合起来。

这样可以减少无意义抖动,在长期正确的方向上走得更快。

Nesterov Momentum 更进一步:它像是先看一步前方的坡度,再做修正。

6. Adam:每个参数都有自己的步长

Adam 可以理解成 Momentum 的升级版。

它同时维护两个状态:exp_avg 和 exp_avg_sq。

exp_avg 记录梯度方向的滑动平均,类似动量。exp_avg_sq 记录梯度平方的滑动平均,用来衡量这个参数的梯度尺度。

梯度经常大的参数,步子自动变小。梯度稀疏或较小的参数,步子可以相对变大。

这就是 Adam 在 NLP、Transformer、稀疏梯度场景里常用的原因。

7. AdamW:大模型时代的默认选择之一

Adam 里如果直接把 weight_decay 加进梯度,会被 Adam 的自适应缩放影响。

AdamW 的关键是解耦。它把权重衰减从梯度更新里拆出来。

先让参数按 weight_decay 轻微衰减,再执行 Adam 的自适应更新。

这让 weight_decay 更像真正的正则化,而不是混在梯度里的另一个项。

大模型经验:AdamW 常作为默认起点,但 bias 和 norm 参数通常不做 weight decay。

8. 怎么选优化器

不要把优化器当玄学。先看任务,再看模型,再看训练稳定性。

传统 CNN 可以从 SGD + Momentum 开始,尤其追求最终泛化时。

Transformer、NLP、大模型微调,通常优先 AdamW。

快速验证想法时,Adam 或 AdamW 往往更省心。

9. param_groups:不是所有参数都该一样更新

优化器可以把参数分成多组。每一组可以有自己的 lr、weight_decay、betas 或 momentum。

这在微调里很常见:预训练 backbone 用小学习率,新加分类头用大学习率。

这在 AdamW 里也很常见:weight 参数做 weight_decay,bias 和 norm 参数不做。

参数分组不是技巧,而是工程基本功。

10. optimizer.state_dict:优化器也有记忆

模型的 state_dict 保存 weight 和 bias。优化器的 state_dict 保存更新过程中的历史状态。

SGD with Momentum 会保存 momentum_buffer。

Adam 和 AdamW 会保存 step、exp_avg、exp_avg_sq。

如果断点续训只保存模型,不保存优化器,恢复后参数虽然在,但优化器的历史记忆没了,训练曲线可能突然变差。

断点续训:model.state_dict 和 optimizer.state_dict 要一起保存。

11. zero_grad:为什么每轮都要清梯度

PyTorch 的梯度默认是累加的。

这很有用,因为它支持梯度累积。但普通训练里,如果不清空上一轮梯度,下一轮 backward 会把新旧梯度加在一起。

所以标准顺序是:清梯度、算 loss、backward、step。

zero_grad 默认 set_to_none=True。它会把 grad 设成 None。这样更省内存,也让没有收到梯度的参数在 step 时被跳过。

12. 源码级讲解:step 背后的主线

Optimizer 基类在初始化时,会把传入的 model.parameters() 包装成 param_groups。

每个优化器都有自己的 step 方法。SGD.step 会遍历 param_groups,收集 params、grads、momentum_buffer,然后调用 functional sgd。

Adam.step 会收集 params、grads、exp_avg、exp_avg_sq、state_steps,然后调用 functional adam。

AdamW 继承自 Adam。它在初始化时把 decoupled_weight_decay 固定为 True。

functional 层会根据设备、dtype、foreach、fused 等条件选择实现路径。最后底层算子对参数做原地更新。

源码主线:Optimizer 管参数组和状态,step 收集梯度,functional 选择实现,底层算子原地改参数。

13. 实战常见坑

第一个坑:忘记 zero_grad。表现是梯度越来越怪,loss 抖动。

第二个坑:学习率太大。表现是 loss 爆炸、NaN、指标突然崩。

第三个坑:weight_decay 误伤 bias 和 norm。大模型微调里尤其常见。

第四个坑:断点续训只保存 model,不保存 optimizer。Adam 的历史状态会丢。

第五个坑:grad 是 None。说明这个参数没有参与计算,或者 requires_grad 被关掉。

14. 总结

优化器是训练闭环里真正修改参数的组件。

SGD 简单直接,适合追求可控和泛化。

Momentum 用历史方向减少震荡。

Adam 用一阶矩和二阶矩给每个参数自适应步长。

AdamW 把 weight_decay 从梯度更新里解耦出来,是 Transformer 和大模型训练里的常见默认选择。

源码上,Optimizer 管理 param_groups 和 state;具体 step 收集 grad 和状态,再下沉到 functional 与底层算子。


内容来源:《PyTorch 深度修炼》优化器:参数到底是怎么被更新的:功能变化与行业影响解析_热闻岛

相关推荐
GEO索引未来1 小时前
AIIA可信GEO专题研讨会召开/AI全面加入618“大战”/谷歌重拳治理“AI投毒”
大数据·人工智能·gpt·chatgpt
朱大喜1 小时前
可视化图表选型:如何选对图,不让数据“撒谎”
人工智能
子豪-中国机器人1 小时前
Python 阶段性综合强化训练(新版)
开发语言·python·语音识别
意图共鸣1 小时前
意图共鸣科技《历史的韵脚》:从第一次能力下放到第三次,AI浪潮背后的技术普及逻辑
人工智能·科技
大数据魔法师1 小时前
AI Agent(六)- Dify 自定义工具实战 - 基于百度天气 API 搭建天气查询 Agent(天气智查助手)
人工智能
lijgvnns1 小时前
使用AI工具作为量化盯盘助手的信息处理与研究辅助方法
大数据·人工智能
杨先生哦1 小时前
【2026热端攻防系列 3/12】反射型&存储型XSS全解:AI批量免杀、WAF绕过与企业级防御
前端·人工智能·笔记·web安全·xss
杰杰7981 小时前
DRF的分页讲解-入门篇 三个基础分页类介绍
python·django
清水白石0081 小时前
让对象像函数一样工作:深入理解 Python `__call__` 的作用与实战场景
开发语言·python