PyTorch Autograd 与计算图
前向动态记录运算,反向沿图计算并累加叶子参数梯度。
学习目标
- 两次反向显示梯度累积
- 为什么 loss.item() 不能再反向传播?
- 说明:自动微分给出程序实际目标的导数,无法判断程序是否表达了正确的任务。
为什么需要这个概念
PyTorch Autograd 是基于动态计算图的自动微分系统。requires_grad 控制是否跟踪相关张量,backward 把指定输出的梯度传回叶子张量的 grad。
学习前需要掌握
背景与问题
大型网络无法逐个手写偏导。Autograd 记录实际执行的可微运算,再按链式法则求参数梯度;理解它的生命周期能避免梯度累积和断图错误。
概念定义
PyTorch Autograd 是基于动态计算图的自动微分系统。requires_grad 控制是否跟踪相关张量,backward 把指定输出的梯度传回叶子张量的 grad。
直观理解
计算图记录的是这一次前向经过的路线。反向沿路线传递变化率,而不是重新猜测模型的数学表达式。
核心原理
标量损失 backward 默认以上游梯度 1 开始。若输出不是标量,需要先求和/求均值,或显式提供同形状的上游梯度。参数叶子的 grad 保存累积结果,重复 backward 不会自动覆盖。
默认反向后释放本次图中为求导保存的中间值,因此通常每步重新前向。retain_graph 适合确有多次求导需求的场景,不能靠始终开启它修复训练循环;那可能保留不必要内存。
detach 返回不沿原图求导的张量视图,item 把标量转成 Python 数值。二者若被错误地放进损失路径,会切断梯度。no_grad 适合临时禁用跟踪,inference_mode 则用于更严格的纯推理场景;它们与 model.eval 的职责不同。
数学表达
核心公式
PyTorch Autograd 是基于动态计算图的自动微分系统。requires_grad 控制是否跟踪相关张量,backward 把指定输出的梯度传回叶子张量的 grad。
变量含义
θ参数集合.grad叶子梯度缓冲
计算步骤
- 1第一次得到梯度 3。
- 2第二次把梯度 4 加入已有 grad,得到 7。
- 3清空 grad 后重建 4w,梯度只剩 4。
代码对应位置
示例 1两次反向显示梯度累积的最小验证:使用完整构造输入核对两次反向显示梯度累积,输出只表示本例计算。
变量解释
| 变量 | 含义 |
|---|---|
θ | 参数集合 |
.grad | 叶子梯度缓冲 |
完整数值示例
两次反向显示梯度累积
已知条件
- 叶子参数 w=2
- 先反向传播 3w,再构建新图反向传播 4w
计算步骤
- 第一次得到梯度 3。
- 第二次把梯度 4 加入已有 grad,得到 7。
- 清空 grad 后重建 4w,梯度只剩 4。
计算结果
打印梯度依次为 3、7、4,参数数值仍为 2。
处理前后对比
- 自动微分给出程序实际目标的导数,无法判断程序是否表达了正确的任务。
案例推演与判断
第二次使用的是新的前向图,因此不需要 retain_graph。两张图都把梯度写到同一片叶子参数存储,累积得到 7。这个行为支持梯度累积训练,但在普通每批更新中需要显式清理。
反向过程中 w 本身保持 2。只有优化器 step 或显式数值更新才改变它;看到 grad 不为空不能据此认定训练已经更新。
计算与实现步骤
- 第一次得到梯度 3。
- 第二次把梯度 4 加入已有 grad,得到 7。
- 清空 grad 后重建 4w,梯度只剩 4。
代码实现
示例 1
两次反向显示梯度累积的最小验证
example_01.py用途:使用完整构造输入核对两次反向显示梯度累积,输出只表示本例计算。
import torch
w = torch.tensor(2., requires_grad=True)
(3 * w).backward()
print(f"grad={w.grad.item():.0f}")
(4 * w).backward()
print(f"grad={w.grad.item():.0f}")
w.grad = None
(4 * w).backward()
print(f"grad={w.grad.item():.0f} w={w.item():.0f}")代码解析
解析始终位于完整代码下方,并按实际代码段逐项对应。
输入数据与任务
使用完整构造输入核对两次反向显示梯度累积,输出只表示本例计算。
w- 模型权重或当前待优化参数。
Step 1 · 1–9 行
导入当前步骤需要的数值计算、预处理、模型或评价工具。依赖集中写在代码开头,便于复现。
import torch
w = torch.tensor(2., requires_grad=True)
(3 * w).backward()
print(f"grad={w.grad.item():.0f}")
(4 * w).backward()
print(f"grad={w.grad.item():.0f}")
w.grad = None
(4 * w).backward()
print(f"grad={w.grad.item():.0f} w={w.item():.0f}")预期输出或运行结果
grad=3 grad=7 grad=4 w=2
常见错误 · 4 条
- 忘清梯度
- item 后 backward
- 日志保存带图 Tensor
- 滥用 retain_graph
实际应用
- 训练循环求梯度
- 排查 detach 和梯度累积问题
常见错误
- 忘清梯度
- item 后 backward
- 日志保存带图 Tensor
- 滥用 retain_graph
常见问题
为什么 loss.item() 不能再反向传播?
item 返回普通 Python 数值,已经脱离 Autograd 图;用于日志记录可以,用它替代训练损失则失去求导路径。
这个示例能说明什么边界?
自动微分给出程序实际目标的导数,无法判断程序是否表达了正确的任务。
推荐学习资料
参考库不会生成虚假资源或无效外部链接。