核心要点

  • 能说清前向时动态建有向无环图,每个可微运算记一个 Function 节点,张量 .grad_fn 指向创建它的运算

  • 能讲反向:loss.backward() 按拓扑序遍历图,逐节点用链式法则 grad_input = grad_output × 局部雅可比,把梯度累加到叶子张量 .grad

  • 能区分这是反向模式 AutoDiff(解析求导),不是数值差分,也不是符号微分

  • 能说明 torch.no_grad() 禁建图、detach() 切断梯度、.grad 累加需手动 zero_grad

标准回答

PyTorch Autograd 实现自动微分(AutoDiff),支撑 反向传播

前向(建图)

  • 每个可微运算创建 Function 节点,记录 inputsoutputs
  • 张量 .grad_fn 指向创建它的运算
  • 叶子节点(用户输入、Parameter)grad_fn is None

反向(求导)

  • loss.backward() 从 loss 启动
  • 拓扑序遍历图,每个节点调用 grad_fn.backward(grad_output)
  • 链式法则:grad_input = grad_output × local_jacobian
  • 累加到叶子 .grad

特点

  • 动态图:每轮前向可不同结构(if/for)
  • 仅保存必要中间值 供反向(可 checkpoint显存
python
x = torch.tensor(2.0, requires_grad=True)
y = x ** 2
y.backward()
print(x.grad)  # 4.0

torch.no_grad() 禁用建图;detach() 切断梯度。详见 反向传播原理

常见误区

⚠️ 常见踩坑

对一个 requires_grad 的张量做 inplace 操作(x += 1 或 relu_()),覆盖了反向需要的中间值,backward 时报 "a variable needed for gradient computation has been modified by an inplace operation";另一个是误以为 .grad 会自动清零,循环里不调 optimizer.zero_grad() 导致梯度跨 batch 累加、训练发散。

追问

追问 1动态图和静态图 Autograd 区别?

动态图(PyTorch、TF2 eager)边执行边建图,每次前向可走不同分支/循环,调试直观、适合变长输入和控制流;静态图(TF1、torch.compile/JIT)先定义后执行,编译期可做算子融合、常量折叠等优化,部署性能更好但灵活性差。现代框架多以动态为默认、按需编译换性能。

追问 2为什么有些操作用不了 backward?

常见原因:该操作不可微(如 argmax、取整、整数索引产生的离散输出局部梯度为 0 或未定义);或运算在 torch.no_grad() 下、张量被 detach() 切断;或张量 requires_grad=False、dtype 是整型。对不可微环节常用 STE、Gumbel-Softmax 等可微近似绕过。

追问 3梯度检查点(checkpoint)原理?

用 torch.utils.checkpoint 在前向时不保存中间激活,只记录输入;反向需要时再重算一遍前向得到激活。以额外约 30% 计算换显存大幅下降,让大模型/长序列能在有限显存上训练,是常见的显存优化手段。

延伸学习

与本题相关的知识库文章、术语、工具与行业资讯。

🛠️ AI 工具

  • Pytorch

    Meta 开源的深度学习框架,100K+ stars。以动态计算图和 Pythonic 风格著称,在学术界和工业界都有广泛应用,支持分布式训练、移动端部署和 ONNX 导出

  • Tensorflow

    全球最流行的机器学习框架之一,195K+ stars。Google 开源的端到端 ML 平台,支持 TensorFlow、Keras 等多种 API,覆盖深度学习、强化学习、移动端部署等全场景,是 AI 工程师的必备工具