autograd 自动微分:计算图与反向传播
本教程共 60 篇 · 第 6 篇 · 更新于 2026-08-17 · 约 2 分钟阅读
本节目标:理解 PyTorch 的自动微分(autograd)引擎——它怎么记录你的运算、怎么反向算出梯度。学完你会用
backward()求任意表达式的导数,并知道梯度存到哪里。
训练神经网络说到底就一件事:反复求梯度、更新参数。一个十几层的网络,用手推导数能推到你怀疑人生。PyTorch 的 autograd 引擎就是来救你的——你只管写前向计算,导数它全自动搞定。
先看一个 30 秒的例子
import torch
x = torch.tensor(2.0, requires_grad=True)
y = torch.tensor(3.0, requires_grad=True)
z = x ** 2 + y * 3 # z = x² + 3y
z.backward()
print(x.grad) # tensor(4.) dz/dx = 2x = 4
print(y.grad) # tensor(3.) dz/dy = 3
就三步:创建张量时声明 requires_grad=True,正常写运算,最后对结果调用 backward()。梯度就躺在 .grad 里了,和手推的结果分毫不差。
计算图:PyTorch 的”草稿纸”
autograd 能算梯度,靠的是一张动态计算图(computational graph)。你可以把它想成一张草稿纸:你做一步运算,它就记一笔。
x = torch.ones(2, 2, requires_grad=True)
y = x + 2
z = y * y * 3
out = z.mean()
print(out) # tensor(27., grad_fn=<MeanBackward0>)
每个运算产生的张量,身上都带一个 grad_fn 属性,指向”是谁造出了我”:
print(y.grad_fn) # <AddBackward0 object at 0x...>
print(z.grad_fn) # <MulBackward0 object at 0x...>
用户自己创建的张量没有 grad_fn,它是 None——它就是这张图的起点。这些起点也叫叶子张量(leaf tensor),我们下一章会细讲。
这里有个关键词:动态。PyTorch 是”边运行边建图”(define-by-run)的,每次前向传播都重新画一张图。好处是你的模型可以随便用 if、for 这些 Python 语句,图会跟着代码走,不用提前声明。
backward():从结果往回推
backward() 会从结果出发,沿着图往回走,用链式法则一层层算梯度,最后写进每个叶子张量的 .grad。
经典例子走一遍:
x = torch.ones(2, 2, requires_grad=True)
y = x + 2
z = y * y * 3
out = z.mean()
out.backward()
print(x.grad)
# tensor([[4.5000, 4.5000],
# [4.5000, 4.5000]])
手推验证:out = mean(3(x+2)²),对 x 求导得 3/2·(x+2),x=1 代入是 4.5,完全对上。
两个要点记住:
backward()只能对标量调用。因为损失函数最终就是一个数。结果不是标量时,先sum()或mean()聚合一下,或者给backward()传参数。- 梯度是累积的,不是覆盖。同一个张量连续调用两次 backward,
.grad里的值会翻倍。
Note梯度累积是刻意设计,不是坑你。但训练循环里每次都必须在 backward 前清零,否则参数更新就乱套了。下一章专门讲这件事。
非标量怎么处理
偶尔会遇到结果是向量的情况。这时给 backward() 传一个形状相同的 gradient 参数即可:
x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)
y = x ** 2
y.backward(torch.ones_like(y))
print(x.grad) # tensor([2., 4., 6.]) = 2x
这个参数可以理解成”上游传来的梯度”。初学阶段你几乎用不到它,知道”非标量要么传参、要么先 sum 一下”就够了。
两个省内存的开关
训练时求梯度天经地义,但推理时纯属浪费。PyTorch 提供了两个”暂停键”,下一章会展开:
with torch.no_grad():包住代码块,里面的运算不建图,省内存又提速。tensor.detach()返回一个共享数据但脱离计算图的新张量。
现在你只需要知道有这两个工具,遇到”想取出数值但不想让它参与求导”的场景就用它们。
到这里,autograd 的运转逻辑你就通了:前向建图,backward 反推,梯度进 .grad。训练循环的雏形已经看得见了。下一章我们把这套机制用得更稳:什么时候清零梯度、叶子和非叶子张量有什么区别、detach 和 no_grad 分别该用在哪儿。