首页 / PyTorch 入门教程 / autograd 自动微分:计算图与反向传播

PyTorch 入门教程

autograd 自动微分:计算图与反向传播

本教程共 60 篇 · 第 6 篇 · 更新于 2026-08-17 · 约 2 分钟阅读

autograd自动微分计算图反向传播梯度PyTorch

本节目标:理解 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)的,每次前向传播都重新画一张图。好处是你的模型可以随便用 iffor 这些 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,完全对上。

两个要点记住:

  1. backward() 只能对标量调用。因为损失函数最终就是一个数。结果不是标量时,先 sum()mean() 聚合一下,或者给 backward() 传参数。
  2. 梯度是累积的,不是覆盖。同一个张量连续调用两次 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。训练循环的雏形已经看得见了。下一章我们把这套机制用得更稳:什么时候清零梯度、叶子和非叶子张量有什么区别、detachno_grad 分别该用在哪儿。