Autograd 自动求导:PyTorch 训练模型的发动机
写 PyTorch 的人,最常见的一句代码是 loss.backward()。 看起来很短。 但它背后不是一个函数那么简单,而是一整套动态计算图系统。 前向时,它记录每一步计算。反向时,它沿着计算图倒着走,用链式法则把梯度传回每一个参数。
写 PyTorch 的人,最常见的一句代码是 loss.backward()。
看起来很短。
但它背后不是一个函数那么简单,而是一整套动态计算图系统。
前向时,它记录每一步计算。反向时,它沿着计算图倒着走,用链式法则把梯度传回每一个参数。
这就是 Autograd。
1. 先把自动求导说成人话
模型训练,本质上是在问一个问题:
参数应该往哪个方向改,才能让 loss 变小?
这个“方向”,就是梯度。
以前手写梯度,很痛苦。模型一复杂,公式就爆炸。PyTorch 的做法很直接:你只管写前向计算,反向梯度它帮你算。
可以把 Autograd 想成一本账。
前向计算时,每一步都记账:谁参与了计算,产生了什么结果,反向时该怎么还梯度。
调用 backward() 时,它从 loss 开始倒着翻账本,一层层把梯度算回去。
2. Autograd 解决了什么问题
神经网络训练有三件事:
第一,前向计算,得到预测值。
第二,计算 loss,知道错了多少。
第三,反向传播,算出每个参数应该怎么改。
Autograd 负责第三件事。
它不负责设计模型。
它不负责更新参数。
它只负责一件事:根据前向计算过程,自动计算梯度。
3. requires_grad:自动求导的开关
Tensor 默认只是一块数据。
如果你希望 PyTorch 追踪它参与的运算,就要打开 requires_grad。
import torch
x = torch.tensor(2.0, requires_grad=True)
y = x * x + 3 * x
y.backward()
print(x.grad) # tensor(7.)
这里 x=2,y=x²+3x。
dy/dx = 2x+3。
所以当 x=2 时,梯度就是 7。
你没有手写求导公式。PyTorch 自动做了。
只要参与运算的输入里有一个 Tensor 需要梯度,输出通常也会被纳入计算图。
但如果你在 no_grad 或 inference_mode 里执行,PyTorch 就不会记录这段历史。
4. grad_fn:反向图的入口
打开 requires_grad 后,计算结果上通常会出现一个属性:grad_fn。
x = torch.tensor(2.0, requires_grad=True)
y = x * x + 3 * x
print(y.grad_fn)
# <AddBackward0 ...>
这个 grad_fn 很关键。
它不是装饰品。
它指向创建这个 Tensor 的反向函数。
比如加法产生 AddBackward0,乘法产生 MulBackward0,矩阵乘法产生 MmBackward0。
前向计算像是在搭积木,grad_fn 就是每块积木背后的拆解说明。
反向传播时,Autograd Engine 就沿着这些 grad_fn 和 next_functions 往回走。
5. 叶子节点和非叶子节点
很多人第一次学 Autograd,会被 .grad 搞晕。
为什么有的 Tensor 有 grad,有的 Tensor 没有?
答案在叶子节点。
用户直接创建、需要优化的 Tensor,通常是叶子节点。模型参数就是典型叶子节点。
由运算产生的中间结果,是非叶子节点。它们参与反向传播,但默认不会把梯度留在 .grad 字段里。
一句话记住:
Autograd 会计算中间梯度,但默认只把叶子 Tensor 的梯度保存下来。
如果你确实想查看中间节点的梯度,可以调用 retain_grad()。
6. backward() 到底做了什么
loss.backward() 不是“重新跑一遍模型”。
它是从 loss 这个根节点开始,沿计算图反向遍历。
每经过一个节点,就调用这个节点对应的 backward 逻辑。
最后,把梯度累加到叶子 Tensor 的 .grad 里。
# 典型训练片段
optimizer.zero_grad() # 清空上一轮梯度
pred = model(x) # 前向:构建计算图
loss = loss_fn(pred, y) # loss:图的根节点
loss.backward() # 反向:计算梯度
optimizer.step() # 更新:优化器修改参数
注意:backward 只负责算梯度。
参数真正被修改,是 optimizer.step() 做的。
旧梯度清空,是 optimizer.zero_grad() 做的。
7. 从 Python 进入 C++ Engine
从源码角度看,Autograd 分两层。
上层是 Python API,负责让你调用起来方便。
底层是 C++ Autograd Engine,负责真正执行计算图。
一条典型链路是:
Tensor.backward() 调用 torch.autograd.backward()。
torch.autograd.backward() 整理输出 Tensor、外部梯度、retain_graph 等参数。
然后进入 _execution_engine.run_backward()。
这里开始从 Python 切到 C++。
C++ Engine 会创建 GraphTask,分析依赖关系,把可以执行的 Node 放进 ReadyQueue,再由 worker thread 调用 evaluate_function 执行每个反向节点。
最后,AccumulateGrad 节点把梯度写到叶子 Tensor 的 .grad 里。
所以,Autograd 不是简单递归。
它是一个带任务调度、依赖分析、线程队列和梯度累加的执行引擎。
8. Saved Tensors:为什么反向要占显存
反向传播不可能凭空算梯度。
有些算子的 backward 需要用到前向阶段的中间结果。
比如 y=x²,反向公式是 dy/dx=2x。
如果反向时不知道前向的 x 是多少,就算不出梯度。
所以某些操作会在前向阶段保存必要的 Tensor。
这也是训练显存比推理显存高的重要原因。
推理只要前向结果。
训练还要保存反向所需的中间值。
后面讲混合精度、梯度检查点、FSDP 时,这个概念会反复出现。
9. detach、no_grad、retain_graph:三个容易混的点
学 Autograd,最容易踩坑的不是 backward,而是“什么时候不该记录图”。
detach() 是对某个 Tensor 切断历史。
no_grad() 是对一段代码关闭建图。
retain_graph=True 是 backward 后不释放图。
zero_grad() 是清空上一轮已经累积的梯度。
这几个东西看起来都和梯度有关,但作用完全不同。
训练代码里最常见的 bug,就是在错误的位置用了 no_grad 或 detach,导致模型不更新。
10. 为什么梯度会累加
PyTorch 的梯度默认是累加的。
也就是说,连续调用两次 backward,如果中间不清空梯度,.grad 会把两次结果加起来。
x = torch.tensor(2.0, requires_grad=True)
y = x * x
y.backward()
print(x.grad) # tensor(4.)
y = x * x
y.backward()
print(x.grad) # tensor(8.),不是 4,因为累加了
这不是 bug。
这是设计。
因为梯度累加可以支持梯度累计训练。
但普通训练中,每一轮更新前通常要清空旧梯度。
optimizer.zero_grad()
loss.backward()
optimizer.step()
11. Autograd 和动态图的关系
PyTorch 的计算图是动态生成的。
你每执行一次 forward,都会生成一张新的反向图。
这就是为什么你可以在 forward 里写 if、for、递归,甚至根据输入内容改变模型路径。
优点是灵活。
缺点是每次都要重新建图,性能上会有一定开销。
后面讲 torch.compile 时,你会看到 PyTorch 2.x 是怎么把动态图捕获成图,再交给编译器优化的。
12. 从源码角度看 Autograd 的核心对象
源码里,Autograd 的核心不是“Tensor 本身”,而是 Tensor 背后的计算历史。
可以抓住这几个对象:
Tensor:保存数据,也带着 autograd metadata。
Node:反向图里的执行节点,每个 Node 知道自己的 backward 逻辑。
Edge:连接 Node 和 Node,表示梯度往哪里流。
GraphTask:一次 backward 的任务上下文。
ReadyQueue:已经满足依赖、可以执行的反向节点队列。
AccumulateGrad:负责把梯度累加到叶子 Tensor 的 .grad。
理解这些,loss.backward() 就不再神秘。
13. 总结
Autograd 是 PyTorch 训练的发动机。
requires_grad 决定是否记录计算。
grad_fn 指向反向图入口。
backward 从 loss 出发反向遍历。
叶子 Tensor 的 .grad 会被填充。
中间节点的梯度默认不保留。
某些算子会保存前向中间值,用于反向计算。
Python API 负责入口,C++ Autograd Engine 负责真正执行。
一句话:
前向建图,反向执行,梯度累加,优化器更新。
相关推荐

科大讯飞AI眼镜正式开启预售 搭载多语种翻译与全能AI助理
科大讯飞旗下讯飞AI眼镜现已登陆京东平台启动预售,这款产品定位为随身 超级 AI助理,将大模型能力融入穿戴设备,官方定价4299元,部分地区享受国家补贴后价格低至3369元,同时还可选配近视镜片,满足不同用户佩戴需求。 这款AI眼镜采用常规眼镜外观,整机重量仅40克,依托海量头模数据优化结构设计,获得专业舒适度认证,佩戴体验出色。镜片选用全贴合树脂材质,安全

AI冲击初级岗位引发技术抵触,谷歌CEO呼吁重塑“乐观视角”
谷歌首席执行官桑达尔·皮查伊(Sundar Pichai)日前在斯坦福大学毕业典礼发表演讲,反常地对其执掌的谷歌核心战略——人工智能(AI)只字未提。这一动作背景在于当前全球年轻人对AI重塑就业市场的抵触情绪日益高涨。此前,谷歌前CEO埃里克·施密特及Big Machine Records CEO斯科特·博尔切塔在其他高校谈及AI时均遭学生嘘声,而皮查伊此次

微软推出开源渲染库,为iOS端AI聊天体验注入新动力
近日,微软在GitHub上开源了一款专为iOS平台打造的渲染库——SwiftStreamingMarkdown。这一举措旨在破解当前大模型应用在聊天界面中进行Markdown文本流式渲染时的性能难题,为移动端开发者提供了一套高效的解决方案。 在移动端集成AI对话功能时,如何让模型输出的内容既流畅又保持良好的阅读体验,一直是技术团队的痛点。传统Markdown

OpenAI斥资1. 5 亿美元启动合作伙伴网络,全面加速企业AI转型
全球人工智能巨头OpenAI今日正式宣布推出“OpenAI合作伙伴网络”计划。该项目旨在携手全球合作伙伴,共同构建、销售并交付基于OpenAI技术的创新解决方案,协助各大企业将AI雄心转化为实际成果。为了全力支持这一生态系统的蓬勃发展,OpenAI率先投入了1. 5 亿美元的巨额资金。官方计划通过该网络提供全方位的资源、赋能渠道和技术支持,并在 2026 年

情感陪伴新物种?优必选U1 人形机器人预售破纪录
近日,优必选旗下主打情感陪伴的U1系列人形机器人开启预售,短短10天内便收获了超过3800台的预订订单,定金总额突破千万元。对于去年人形机器人年度销量仅为1079台的优必选而言,这一数字无疑是该领域商业化进程中一次意义非凡的突破。 U1系列目前提供男女两款定制机型:男款身高183厘米,体重42公斤;女款身高168厘米,体重35.2公斤。在硬件配置方面,该机型

MiniMax陷入增长困境:一场关于涨价、解禁与市场信任的风暴
近日,AI独角兽MiniMax因为一次模型升级后的定价调整,意外卷入了舆论漩涡。新一代旗舰模型M3 发布的同时,公司将计费模式由传统的按次调整为按Token计费,且月租套餐价格大幅上调。由于缺乏前期沟通与缓冲期,这一变动直接导致大量开发者在毫无准备的情况下遭遇额度骤减,甚至测算出实际成本涨幅高达257%,不少用户直指公司此举无异于背刺。 这场涨价风波并非单一
阅读补充
一句话看懂
写 PyTorch 的人,最常见的一句代码是 loss.backward()。 看起来很短。 但它背后不是一个函数那么简
事件背景
这篇内容围绕“Autograd”展开,热闻岛基于公开信息整理事件背景、主要进展与可继续关注的方向。
事件时间线
发布
相关信息进入公开传播
更新
热闻岛对内容进行整理与补充。
看点
- · Autograd的最新进展是什么
- · 相关信息对用户或行业会带来哪些影响
- · 后续是否会有新的回应或处理结果
后续关注
- · 后续官方回应或权威通报
- · 相关主体的进一步说明
- · 事件对普通用户和平台传播的持续影响
免责声明:本文仅代表作者观点,不构成投资建议、法律建议、医疗建议。财经类内容尤其需要注意风险;爆料类信息请以权威通报为准。
评论 (0)
登录后即可发表评论
去登录