跳到正文
动手理解 · CONCEPT LAB

把一条误差沿计算图倒着分回去

反向传播不是“把答案倒放”,而是从损失的 cotangent(余切向量)开始,让每个操作用前向保存或重算的必要量计算 Vector–Jacobian Product(VJP,向量—雅可比积),再把贡献传给输入与参数。

已经发生 正在观察 接下来
01 / 03

状态传导图

x 输入
w·x 线性运算
σ 非线性
ŷ 预测
L 损失

detach() 返回与当前图分离的结果,因此从该结果继续计算的路线不会把梯度传回原图。no_grad / inference_mode 与 eval 是不同开关;下方刻度只表示本场景进度。

观察点 01

满足记录条件时,数值旁才留下依赖关系

在 PyTorch 2.13 eager mode(即时执行模式)里,只有梯度模式开启、且某个操作至少有一个输入 requires_grad=true 时,该操作才会记录 Function 节点与依赖边;反向公式需要的输入、输出或中间量会被保存。

前向阶段数值与图已建
参数更新阶段尚未发生
此刻要记住

动态图通常每轮前向重建;model.eval() 本身不会关闭 Autograd。

数学最小底座 · 04 / 04

错误怎样找到每一个参数

损失通常汇总成一个标量,模型却可能有数十亿参数。Backpropagation(反向传播)回答的是:在这次前向建立的计算图与输入批次上,损失对每个参数的局部敏感度是多少?这不是因果或道德意义的“责任分配”;它是链式法则算出的梯度,工程上通常由 Automatic Differentiation(AD,自动微分)执行。

01 · SLOPE

梯度是一张“往哪走,变化多快”的局部地图

对于一个参数,导数是局部斜率;对于很多参数,梯度是所有偏导组成的向量。对可微标量函数,在欧氏 L2 范数约束的无穷小邻域里,梯度指向增长最快方向,负梯度才是下降最快方向。有限步是否真的下降,还取决于学习率与局部曲率。

Derivative(导数)
例如 f(w)=w²,导数 f′(w)=2w。在 w=3 附近,w 增加 0.01,f 约增加 0.06。
Partial Derivative(偏导数)
函数有多个输入时,固定其他坐标,只看某一个变量的无穷小变化怎样影响输出。
Gradient(梯度)
∇L=[∂L/∂w₁,∂L/∂w₂,…]。对本页讨论的实数参数与实值标量损失,某个参数 Tensor 的梯度与该 Tensor 形状相同;它描述局部敏感度,不是参数重要性的永久排名。
Directional Derivative(方向导数)
uᵀ∇L 是沿单位方向 u 的瞬时变化率。“最陡”依赖选用的范数;下式采用最常见的欧氏 L2 几何。
DuL=uL,u2=1usteepest down=LL2D_{u}L=u^\top\nabla L,\quad \|u\|_2=1\quad\Longrightarrow\quad u_{\text{steepest down}}=-\frac{\nabla L}{\|\nabla L\|_2}

∇L=0,归一化方向没有定义;若步长不是无穷小,负梯度也不保证新位置一定更低。

最小导数:平方函数在 w=3 的斜率

LIMIT INTUITION
  1. L(w)=w²,在 w=3L=9
  2. 把 w 增加到 3.01,损失变成 3.01²=9.0601
  3. 变化率约为 (9.0601−9)/0.01=6.01;步长继续缩小会靠近精确导数 2w=6
白话先懂梯度像你脚下的坡度计:参数坐标对应地面方向,损失对应高度。类比只解释局部一阶信息;真实高维损失面没有可见山谷,换一种参数尺度或范数,“最陡方向”也会改变。
02 · BACKPROP

复杂网络先拆成小操作,再沿原路倒推

计算图把复合函数拆成基本操作。反向时,每个操作读取上游梯度和前向保存的必要量,计算对各输入的 Vector–Jacobian Product(VJP,向量—雅可比积);同一变量若经多条路径影响损失,各路径贡献相加。这正是链式法则的程序化执行。

计算图手算:x等于2、w等于3、b等于1,先算m=x乘w、z=m加b、损失为z减目标的平方;紫色反向路径给出对z、m、w、x、b的梯度
蓝色是前向数据流,紫色是反向敏感度。图中 x 是输入,w、b 是待更新参数;∂L/∂x 会继续传给更早的层,但优化器不会把本例输入 x 当参数更新。 查看原图 ↗
Lw=Lzzmmw\frac{\partial L}{\partial w}=\frac{\partial L}{\partial z}\cdot\frac{\partial z}{\partial m}\cdot\frac{\partial m}{\partial w}

标量链上把三个局部导数相乘;张量程序通常直接计算 VJP,而不是显式构造每一层巨大的 Jacobian(雅可比矩阵)。

把图中 w 的梯度完整推一次

x=2 · w=3 · b=1 · y=5
  1. 前向:m=xw=6z=m+b=7L=(z−y)²=4
  2. 损失对 z:∂L/∂z=2(z−y)=4
  3. z 对 m:∂z/∂m=1,所以 ∂L/∂m=4×1=4
  4. m 对 w:∂m/∂w=x=2,所以 ∂L/∂w=4×2=8;同理 ∂L/∂b=4∂L/∂x=4×w=12
  5. 若学习率 0.01,同时更新参数可得 w′=2.92b′=0.96;x 是输入,不由优化器改写。
  6. 重新前向:z′=2×2.92+0.96=6.8L′=(6.8−5)²=3.24,本例确实从 4 降低;这不构成任意模型、任意步长都下降的保证。

为什么反向模式适合训练大模型

训练通常是“很多输入参数 → 一个标量损失”。对 f:ℝⁿ→ℝ,Reverse-Mode AD(反向模式自动微分)从标量输出种下 1,一次反向遍历即可得到当前图中所有与损失连通、且要求梯度的叶子参数梯度;Forward-Mode AD 若用 n 个基方向拼出同一完整梯度,则需 n 次方向传播。这个优势不表示反向零开销或零显存:它仍要保存或重算反向所需量。

分叉为什么要相加

若同一变量 x 同时走两条路进入 L=f(x)+g(x),则 dL/dx=f′(x)+g′(x)。这次“图内求和”是数学链式法则;它与多次调用 backward() 后叶子 Tensor 的 .grad 缓冲继续累加是两件事。

03 · AUTODIFF

自动微分没有替你猜导数,它把链式法则做成了运行时

以 PyTorch 2.13 eager mode(即时执行模式)的反向自动微分为例:在梯度模式开启,且某个操作至少有一个输入需要梯度时,该操作才会被记入反向图;调用 backward() 后再反向遍历。它按基本操作的导数规则和链式法则求值,不是有限差分;误差仍会来自浮点舍入和算子在不可微点采用的约定。

1. 前向时记录什么

PyTorch 记录 Function 节点和边,输出 Tensor 的 grad_fn 是进入反向图的入口;eager 模式下一般每轮前向从头建立执行到的图。反向公式需要哪些 Tensor,就保存哪些输入、输出或中间量。若 retain_graph=False,反向所需的保存量通常会被释放,再对同一图反向通常报错;这不等于所有仍被 Python 引用的 Tensor 对象立即消失。

2. 反向从哪里开始:VJP,不是完整 Jacobian

若输出是单元素 Tensor,起始上游梯度可省略并理解为 1。若输出有多个元素,PyTorch 的 backward 需要与各输出结构、形状匹配的上游 cotangent(余切向量)v,并计算各输出加权和对输入的 VJP;一次调用通常不会物化完整 Jacobian。

f:Rn ⁣Rm,JfRm×nVJP(v)=Jf(x)vRn,JVP(u)=Jf(x)uRm\begin{gathered}f:\mathbb{R}^n\!\to\mathbb{R}^m,\quad J_f\in\mathbb{R}^{m\times n}\\\operatorname{VJP}(v)=J_f(x)^\top v\in\mathbb{R}^n,\qquad \operatorname{JVP}(u)=J_f(x)u\in\mathbb{R}^m\end{gathered}

这里采用列向量约定。当 v=∇ᵧL 时,Jᵀv=∇ₓL。Reverse mode 适合 n 很大、m 很小;Forward-Mode AD 直接算 JVP,常更适合 n 很小、m 很大。完整 Jacobian 通常仍需多次乘积或批量化组合。

3. 两种“累加”必须分开

一次反向里,多条路径汇入同一节点时会先按链式法则求和;反向结束后,backward() 又会把结果加到要求梯度的叶子 Tensor 已有的 .grad,不会默认覆盖。非叶子 Tensor 默认不保留 .grad,除非调用 retain_grad()torch.autograd.grad() 则返回指定输入的 VJP,通常不写入这些输入的 .grad。因此应在每个新的累积窗口前清理梯度,除非正在有意跨 micro-batch 累积。

4. 不可微点不是凭空出现“解析真值”

ReLU 在 0 没有普通导数,sqrt(0) 的斜率极限则是正无穷。PyTorch 2.13 的顺序规则是:可微处用导数;局部凸/凹时取最小范数次/上梯度;否则尽量按连续性定义(可能得到 Inf),未定义输入还可能得到 NaN、任意值或报错。自动微分执行的是框架为基本算子定义的反向规则,并不让不可微函数突然拥有唯一解析导数。

5. 为什么反向吃显存,Checkpointing 又有什么条件

训练要保留反向公式所需的前向量。Activation Checkpointing(激活检查点)少存部分中间 Tensor,在反向时重跑前向片段,用额外计算换显存。PyTorch 2.13 提供 reentrant 与 non-reentrant 两套实现,要求显式传 use_reentrant,并推荐 use_reentrant=False;后者会记录区段内反向图,并可在所需量重算齐后提前停止;前者的初次前向在 no_grad 下执行,反向时会完整重算 function,且限制更多。

默认随机数保护只保存 CPU 与从参数推断出的一种其他设备类型;若区段依赖变化的全局状态、涉及未保存的多设备随机性,或在函数内把 Tensor 搬到此前未见设备,重算就不保证等价,可能报错或静默产生错误梯度。

6. model.eval() 不等于关闭自动微分

model.eval() 只切换 Dropout、BatchNorm 等模块定义的训练/评估行为,与 Autograd 是否建图正交。评估时通常还要用 torch.no_grad() 或更严格的 torch.inference_mode();后者额外关闭 view tracking 与 version counter,但其中创建的 Tensor 不能随意带回需要 Autograd 记录的区域。

四者别混反向传播是神经网络训练中应用反向模式的经典名称;自动微分是对数值程序组合局部微分规则的更一般技术;符号微分操作代数表达式;数值微分用有限扰动估计,常用于小规模梯度检查。
04 · OPTIMIZE

梯度给方向,优化器决定怎样迈步

最基础的 Gradient Descent(梯度下降)按完整目标梯度走;Stochastic Gradient Descent(SGD,随机梯度下降)用随机样本或 mini-batch(小批次)估计它。Adam 根据梯度的一阶矩与逐元素平方的未中心化二阶原始矩估计缩放更新,但这不是使用 Hessian(海森矩阵,即二阶偏导矩阵)的二阶优化。

损失函数L等于w减3的平方上的梯度下降轨迹,从w0等于0依次移动到1.2、1.92、2.352和2.6112,再继续逼近但不会一步跳到最小值3
图中 η=0.2,w₄=2.6112 而不是 3;蓝点只标出理论最小值。该一维凸例子每步下降,不能外推成任意高维非凸训练都单调下降。 查看原图 ↗
θt+1=θtηθL\theta_{t+1}=\theta_t-\eta\,\nabla_{\theta}L

θ 是参数,η>0 是学习率。该式是基础梯度下降;有限 η 过大时,即使方向是负梯度,新位置的损失也可能上升。

SGD
均匀采样且按同一目标聚合时,mini-batch 梯度可作为完整数据梯度的随机估计。噪声会改变优化轨迹,有时有益、有时有害,不是自动获得更好泛化的保证。
Momentum(动量)
维护历史梯度的指数加权累积;不同教材与框架是否乘 1−β 的记法并不完全相同。它会改变本步更新方向,不只是把当前负梯度放大。
Adaptive Moment Estimation(Adam,自适应矩估计)
维护梯度一阶矩与逐元素梯度平方的未中心化二阶原始矩,并修正零初始化偏差;ε 用于数值稳定。它没有显式构造 Hessian。
AdamW
Adam with Decoupled Weight Decay(解耦权重衰减的 Adam)把参数衰减与损失梯度的自适应缩放分开。标准 SGD 中,适当换算系数后 L2 正则与 weight decay 可等价;在 Adam 这类自适应方法中通常不等价。
Learning Rate Warmup(学习率预热)
常见做法是先逐步升高学习率,再按余弦、线性或其他计划衰减;它是配方选择,不存在适合所有模型的固定步数。
mt=β1mt1+(1β1)gt,m^t=mt1β1t,vt=β2vt1+(1β2)(gtgt),v^t=vt1β2t,θt+1=θtηm^tv^t+ϵ\begin{aligned}m_t&=\beta_1m_{t-1}+(1-\beta_1)g_t, & \hat m_t&=\frac{m_t}{1-\beta_1^t},\\v_t&=\beta_2v_{t-1}+(1-\beta_2)(g_t\odot g_t), & \hat v_t&=\frac{v_t}{1-\beta_2^t},\\\theta_{t+1}&=\theta_t-\eta\,\frac{\hat m_t}{\sqrt{\hat v_t}+\epsilon}\end{aligned}

m̂ₜv̂ₜ 是从零初始化造成的偏差修正;、平方根和除法均逐元素进行。AdamW 还会在此梯度更新之外施加解耦权重衰减。

梯度累积的口径若损失可按独立项相加、K 个 micro-batch(微批次)的有效项分母相同,且前向没有整批统计、in-batch negatives(批内负例)等跨样本耦合,把每个 mean loss 除以 K 再 backward(),在数学上才对应同一有效大批次目标;浮点归约顺序不同仍不保证逐 bit 一致。训练态 Batch Normalization(BatchNorm,批归一化)会按各微批次分别算统计量,是典型反例。若目标是所有有效 Token 的总体均值,应累计各批 loss sum,再除以全部有效 Token 数;直接平均各批均值会错误加权短批次。
AMP 累积的时序torch.amp.GradScaler 时,同一个有效批次内的梯度必须保持缩放,scale factor 也要保持不变;等全部 micro-batch 累积完,才可对每个 optimizer 反缩放一次、检查 Inf/NaN、裁剪并 step。scaler.update() 也只在有效批次边界调用;若中途混加已反缩放与仍缩放的梯度,事后无法恢复正确总梯度。
05 · REAL SYSTEMS

这些机制在真实训练栈中怎样落地

06 · MISCONCEPTIONS

把分工说准,训练问题才好定位

“反向传播会更新参数”

backward() 计算并累积梯度;optimizer.step() 才按优化器规则更新参数。混合精度检测到 Inf/NaN 时,GradScaler 还可能跳过这次 step。

“自动微分就是符号求导”

自动微分在具体计算图上组合局部导数;它不同于把整个公式化简成符号表达式,也不同于有限差分。

“梯度为 0 就到全局最优”

驻点还可能是局部极大、局部极小或鞍点;近零梯度也可能来自平台、饱和或数值精度。不能只凭梯度为 0 判断全局最优。

“学习率越小越安全”

太小会训练极慢,也可能在有限预算内走不到好区域;太大则可能震荡或发散,需要调度与监控。

“Adam 用了二阶矩,所以是二阶优化”

Adam 的 vₜ 是逐元素梯度平方的移动平均,不是 Hessian 或其逆;它仍属于一阶梯度方法。

“Checkpointing 只省显存,结果必然完全相同”

等价依赖同一函数、实现变体与随机状态合同。全局状态、未覆盖的设备随机性或函数内设备迁移都可能破坏等价;PyTorch 2.13 还要求显式选择 use_reentrant

“调用 model.eval() 就不会建梯度图”

eval() 只改变特定模块的训练/评估行为;关闭反向图要另用 no_grad()inference_mode()。两套开关相互独立。

07 · SOURCES

一手资料与继续学习

  1. PyTorch 2.13 · Autograd mechanics — 反向图记录条件、保存量、叶子梯度、不可微点规则与梯度模式。
  2. PyTorch 2.13 · torch.autograd.backward — VJP、非标量上游向量、叶子梯度累积与图释放语义。
  3. PyTorch 2.13 · torch.autograd.grad — 返回指定输入的 VJP,且不把结果累加到这些输入的 .grad
  4. PyTorch 2.13 · torch.func transformsvjpjvpjacrevjacfwd 的当前官方入口。
  5. PyTorch 2.13 · torch.utils.checkpoint — 两种实现、显式 use_reentrant、随机数状态与等价性警告。
  6. PyTorch · Automatic Mixed Precision examples — 有效批次、loss 缩放、反缩放与跳过 step。
  7. Hugging Face Accelerate · Gradient accumulation — 普通梯度累积以及变长 Token 任务按总 loss 与非填充 Token 总数归一的官方示例。
  8. PyTorch · BatchNorm1d — 训练前向按 mini-batch 计算均值与方差,说明微批次与大批次不必等价。
  9. Automatic Differentiation in Machine Learning: a Survey — 前向/反向模式、VJP/JVP、自动微分与反向传播关系及历史。
  10. Learning representations by back-propagating errors — Rumelhart、Hinton、Williams 1986 年神经网络论文;它推广了方法,但不是反向模式最早来源。
  11. Adam: A Method for Stochastic Optimization — Adam 原始论文。
  12. Decoupled Weight Decay Regularization — AdamW 与 L2 正则、权重衰减的边界。
  13. Attention Is All You Need — 原始 Transformer 的 Adam 超参数与 4,000 步 warmup 配方。
  14. Deep Learning · Numerical Computation — 梯度优化和数值计算基础。

核查日期:2026-07-15。计算图、有限差分、同步参数更新与 w₀→w₄=2.6112 轨迹均用独立脚本复算;框架行为按 PyTorch stable 2.13 文档,历史、AD 与优化器机制按原论文或教材口径表述。