梯度与反向传播的线代骨架
上一章的网络有几十个旋钮,7B 模型有七十亿个。训练的每一步都要回答同一个问题:每个旋钮该往哪拧、拧多少,损失才能降一点?回答它的机器叫反向传播。市面上把它讲成玄学的教程太多了,本章只想让你看清一件事:剥掉微积分的皮,反向传播的骨架全是本书的旧零件——梯度是向量,Jacobian 是矩阵,链式法则是矩阵连乘,而「为什么从后往前算」是第 07 章结合律省算力的直接续集。这一章不推公式细节,只画骨架;骨架看清了,任何 autograd 文档都是白话文。
梯度:一支指向「最陡上坡」的向量
损失 L 是一个「吃进全部参数、吐出一个数」的函数。把 L 对每个参数的偏导数(「其他旋钮不动,单拧这一个,损失变化多快」)排成一列,就是梯度 ∇L——一支和参数一样长的向量。它有一个不显然但极重要的几何身份:∇L 指向损失上升最快的方向,长度是那个方向的上升速率。证明只需第 04 章:沿单位方向 u 的变化率是方向导数 ∇L·u,点积在 u 与 ∇L 同向时最大——完毕。于是「学习」的最小配方就是反着走:
「其他旋钮不动,单拧这一个」听起来要做七十亿次实验,反向传播的全部价值就在于:一次反向,七十亿个偏导全部到手,代价只约等于两次前向。这个「批发价」不是显然的(朴素数值法要 2×参数量次前向),它是本章后半段那个括号顺序挣来的——先立此存照,一会儿兑现。
再送一条几何赠品:梯度永远垂直于等高线(沿等高线走损失不变,变化率为零,即点积为零——正交!)。第 15 章那幅「峡谷等高线」图现在全活了:梯度垂直于椭圆等高线,在峡谷壁上它几乎横着指、而不指向谷口——这就是「梯度下降在峡谷里 Z 字抖动」的几何原因,条件数的痛,根子在「垂直」这个几何宿命上。
Jacobian:向量函数的说明书,局部版
先给一维热身:f(x) 在某点的导数,是「那一点附近最贴身的直线」的斜率——导数把弯的函数逐点换成直的。升到多维,网络的每一层是「向量进、向量出」的函数,它的导数升格成矩阵:Jacobian,第 (i, j) 格 = 第 i 个输出对第 j 个输入的偏导。它就是第 08 章预告过的「本地线性替身」:在当前工作点附近,任何光滑函数的行为 ≈ 乘一次 Jacobian。微积分的全部现代意义,浓缩成一句话:在每个点上,把非线性世界近似成一个线性代数问题。本书前二十章修炼的一切,因此自动适用于「任何函数的局部」——这是线性代数配当 AI 地基的终极原因。
几个熟脸的 Jacobian,口算级:Linear 层 y = Wx 的 Jacobian 就是 W 本身(线性函数的替身是自己);逐元素激活 f 的 Jacobian 是对角矩阵 diag(f′)(每维只影响自己——第 10 章温顺组);ReLU 的更狠:对角线上只有 0 和 1,一张「谁醒着」的通行证表;残差块 x + F(x) 的是 I + J_F(第 16 章收过线的那只)。softmax 的 Jacobian 是少数「非对角」的常客(每个输出依赖所有输入——预算是零和的),这也是它在数值上要格外伺候的原因之一。
链式法则 = 矩阵连乘,方向 = 结合律
整个网络是层的复合 L = ℓ(f₃(f₂(f₁(x)))),微积分的链式法则升维后变成:复合函数的 Jacobian = 各层 Jacobian 的乘积:
现在是全章的画龙点睛。损失是标量,∂L/∂输出 是一支行向量 g;要的最终答案 g·J₃·J₂·J₁ 是一串乘法,而第 07 章教过:加括号的方式决定算力。从右往左先算 J₂·J₁?那是矩阵乘矩阵,亿维 × 亿维,宇宙尺度的浪费。从左往右——先算 g·J₃(向量乘矩阵,便宜),得到新的行向量,再乘 J₂,再乘 J₁——每一步都是「向量 × 矩阵」,从不发生「矩阵 × 矩阵」。这就是反向传播:链式法则 + 一个聪明的括号顺序。「反向」二字的全部含义:误差信号 g 从损失端出发,逆着数据流向,一层层被 Jacobian 转置搬运回来。开头许诺的「批发价 ≈ 两次前向」也在此兑现:每层的 VJP 计算量与该层前向同阶,全程加起来自然是一次前向的常数倍——七十亿个偏导,一趟回程全捎上。autograd 文档里的黑话 VJP(vector-Jacobian product,向量-雅可比积)说的就是每一小步;若目光足够毒,你会认出这正是第 09 章「A(Bx) 不 (AB)x」那笔两千倍账的亲孙子。
Linear 层的反向:转置与外积的加冕礼
把一层 y = Wx 的反向具体写出来,两位老朋友加冕。设从上游传回的误差是 δ = ∂L/∂y(行向量转成列向量记号):
第一条兑现了第 07 章欠的「转置的几何意义」最后一笔:前向用 W 把信号从 n 维送到 m 维,反向就用 Wᵀ 把误差沿原路送回去——同一套连线,反着流。第二条更妙:W 的梯度是「上游误差 ⊗ 本层输入」的外积(第 07 章的秩一薄片)!单条样本给出的权重更新天生秩一,一个 batch 的更新是 B 张薄片的叠加(秩至多 B)——「梯度天然低秩」,这既是 LoRA 直觉的又一根支柱,也是 GaLore 这类「压缩梯度再优化」方法的立足点。反向传播没有新数学:转置、外积、矩阵乘,排队干活而已。
把反向传播想成一场责任审计:损失端查出总亏损,审计组(误差向量)逆着生产流水线走访每个车间;Jacobian 转置负责「按贡献比例把责任摊派给上游」,每个车间领到自己的责任书(梯度)后按责整改(更新权重)。「链式」的会计学名字,就是逐级分摊。这个比喻还能解释第 19 章的激活账:审计时要对账,每个车间前向时的原始单据(激活值 x)必须留底——这就是「反向需要缓存前向激活」的原因,也是激活重计算(丢单据、审计时重开)省内存的原理。
写成代码:上一章网络的反向,十五行
把第 20 章那个两层网络的训练闭环补全,每一行都能对上本章的公式:
# 前向(第 20 章):Z1 = X@W1.T+b1; H1 = relu(Z1); Z2 = H1@W2.T+b2 # 损失:softmax + 交叉熵,y 是正确类别的独热矩阵 (B, c) P = softmax(Z2) # (B, c) 概率 loss = -np.log(P[range(B), y_idx]).mean() # 反向:误差从损失端逆流 dZ2 = (P - Y) / B # softmax+交叉熵的联合梯度,出奇干净 dW2 = dZ2.T @ H1 # ← 外积的批量版!形状 = W2 ✓ db2 = dZ2.sum(axis=0) dH1 = dZ2 @ W2 # ← 乘转置(行约定下写作乘 W2) dZ1 = dH1 * (Z1 > 0) # ← ReLU 的对角 Jacobian:通行证表 dW1 = dZ1.T @ X db1 = dZ1.sum(axis=0) W2 -= lr * dW2; b2 -= lr * db2 # 梯度下降,沿最陡下坡挪步 W1 -= lr * dW1; b1 -= lr * db1
三处注释箭头是本章骨架的落地:dZ2.T @ H1 是「误差 ⊗ 输入」外积的 batch 求和版;dZ2 @ W2 是误差乘转置回程(行优先约定下转置写法互换,以形状为准);(Z1 > 0) 是 ReLU 那张 0/1 通行证。第一行 P − Y 值得多看一眼:softmax 与交叉熵联手求导后,梯度就是「预测概率减真实标签」——公式干净得像预谋,这正是这对组合统治分类任务的原因之一。跑通这十五行(加上数据加载)就是完整的 MNIST 训练器,没有框架,没有魔法。
不信任何推导:梯度检查
手写反向的年代传下来一件验尸工具,今天仍是理解梯度的最好练习:数值梯度检查。导数的定义是「拨一点,看变多少」——那就真的拨:把某个参数加上 1e-5,重跑前向,看损失变了多少,除以 1e-5,和解析梯度对比。两者相对误差小于 1e-6,推导无罪;差几个数量级,某处的转置或符号写反了。它慢(每个参数两次前向),只能抽查,但「机器可以验证微积分」这件事本身,是对本章骨架的最好背书:梯度不是信仰,是可以对账的数字。PyTorch 的 gradcheck 就是它的官方化身,自定义算子上线前的必经之路。
从梯度到优化器:一瞥就好
拿到梯度后怎么用,是「优化器」的地盘,本书不深入,但用线代语言给三级台阶画个像:SGD 是裸公式 w ← w − ηg;动量(momentum) 给更新量加上指数滑动平均——数学上是给「误差的谱成分」不同的衰减节奏,能在峡谷里抵消横向震荡、累积纵向前进(第 16 章相图里的螺旋被拉直);Adam 再给每个参数除以自己梯度大小的滑动均方根——等效于一个逐参数的自适应学习率,即第 15 章说的「对角 Hessian 近似」:没钱请完整的二阶矩阵,就雇一个对角替身。你在配置文件里写下 optimizer: adamw 的那一刻,雇的就是这位替身加一根 weight decay 橡皮筋(第 05 章)。
老病历,新档案:消失与爆炸
第 16 章给 RNN 写过病理报告,现在把它归到总档案:任何深网络的梯度都要穿过 J₁ᵀJ₂ᵀ⋯Jₙᵀ 的长隧道,连乘的谱(第 16 章的判官)决定信号存亡——各层 Jacobian 谱半径普遍小于 1,梯度指数消失;大于 1,爆炸。全套现代架构的「保命装置」可以在这份档案下统一注册:残差连接(Jacobian 变 I + J,谱推向 1)、LayerNorm(把激活范数摁住,间接稳住 Jacobian)、梯度裁剪(范数超标就整体缩短——第 05 章)、门控(LSTM 给 λ≈1 留通道)、正交初始化(出厂谱半径 = 1)。五件装备,五次伏笔回收,一个谱原理。
顺路把「随机」二字也交代了:真实训练用的是随机梯度下降(SGD 的 S)——每步只用一小批样本估计梯度,而不是全数据集。用本章语言:小批梯度是真梯度的带噪声估计,噪声不全是坏事——它让优化器能晃出尖锐的窄坑、偏爱平坦的宽谷(平坦极小值通常泛化更好,这是深度学习理论的重要经验事实之一);batch 越大噪声越小、方向越准,但每步也越贵,且「太安静」的大 batch 训练反而常要配大学习率和额外技巧。batch size 不只是显存参数,它是你给梯度噪声调的音量旋钮。
fp16 时代的数值急救包
反向传播的最后一关是浮点数。训练用半精度(fp16/bf16)省显存提速,代价是表示范围和精度暴跌:fp16 最小正规数约 6×10⁻⁵,梯度里大量「小而重要」的数直接下溢成 0。急救包四件,每件都有本书出处:① loss scaling:损失先乘 2¹⁵ 再反向(梯度整体抬升离开下溢区),更新前除回来——齐次性(第 05 章范数公理②)保证无损;② softmax 减 max:e^{1000} 溢出,先逐行减去最大值再指数化,结果不变(分子分母同乘 e^{−max})——第 04 章 softmax 的标准实现细节;③ epsilon 蹲分母:LayerNorm、Adam 里的 1e-8/1e-5(第 05 章防爆);④ bf16 的取舍:牺牲精度换范围(指数位和 fp32 一样宽),大模型训练默认它——「宁可粗糙,不可溢出」。这些细节不是花边:大模型训练一次几百万美元,数值稳定性是拿真金白银写的线性代数应用题。
Autograd(PyTorch 的自动求导)在这份骨架图上只加了一层工程:前向时随手记一张计算图(谁用了谁、每个算子的 VJP 怎么算),loss.backward() 就是按图逆序执行本章的「向量×Jacobian」接力。所以 requires_grad 是「要不要进审计名单」,detach() 是「此处剪断责任链」(RLHF、EMA、stop-gradient 防塌缩——第 12 章——全靠这一剪),torch.no_grad() 是「本次不开审计」。你从此读 autograd 文档不再是背 API,而是在核对一份你已经懂的骨架。
计算图 + 反向遍历这套结构,你写过它的近亲:Compose 的重组依赖追踪——运行时记录「哪个 State 被哪个 Composable 读过」,State 变化时逆着依赖图精准失效。一个追踪「读」以便向前失效,一个追踪「算」以便向后分摊,同一族「先记账、后遍历」的架构。另外 fp16 下溢的痛你也尝过:用 float 累加几千个小数误差飘移、丢帧计时器抖动——移动端图形代码里「先放大再累加」的土办法,和 loss scaling 是同一个民间智慧的两次独立发明。
① 「梯度是行向量还是列向量」:两种排版约定(分子布局/分母布局)在教材间打架,公式抄错一半源于此——工程上以「梯度形状 = 参数形状」为锚(∂L/∂W 与 W 同形),永不迷路。② 手推梯度的时代过去了,但形状检查没有:autograd 不会错,你的模型结构会——「梯度全零」查 detach 和死 ReLU,「梯度 NaN」查除零和溢出,「某层梯度巨大」查谱与学习率,三条排障口诀覆盖日常九成。③ 二阶方法为什么稀罕:Hessian 是「梯度的 Jacobian」,7B 参数的 Hessian 有 5×10¹⁹ 个元素——存不下也算不起,所以工业界用一阶方法加各种「对角/低秩 Hessian 近似」(Adam 本质是对角近似),第 09 章「能躲就躲」哲学的最大案例。
① 为什么「沿等高线方向移动」的方向导数是零?由此推出梯度与等高线什么关系?
② ReLU 层的 Jacobian 是什么样的矩阵?输入全负时它变成什么,对上一章哪个坑?
③ y = Wx,W 是 512×768,δ = ∂L/∂y 是 512 维——∂L/∂W 的形状?它是哪两支向量的外积?
④ 用括号语言解释:为什么反向模式(backprop)适合「参数多、输出少(标量损失)」,而正向模式适合反过来的情形?
⑤ 训练日志梯度范数曲线突然跳到 1e4——按三条排障口诀,你依次检查什么?
⑥ 为什么反向传播必须缓存前向激活,而「激活重计算」能用约 30% 的额外算力换掉大半激活显存?用「审计要单据」比喻说一遍账。
小结
梯度是指向最陡上坡的向量、垂直于等高线;Jacobian 是函数的局部线性替身,微积分的现代使命就是「逐点转包给线性代数」;链式法则是 Jacobian 连乘,反向传播 = 连乘 + 结合律选的省钱括号,每步都是向量×Jacobian,审计队逆着流水线摊派责任、且必须留着前向的单据;Linear 层的反向由转置(误差回程)与外积(秩一梯度薄片)包办,softmax 加交叉熵的联合梯度干净得像预谋,数值梯度检查能给任何推导验尸;动量与 Adam 是给谱开的两副眼镜——一副抵消震荡,一副逐参配速;消失与爆炸是连乘谱的老案新档,残差、归一化、裁剪、门控、正交初始化是五件谱装备;fp16 的急救包全是范数与齐次性的应用题。随机小批的噪声是免费的正则化,batch size 是它的音量旋钮。至此,「训练」的骨架也齐了——前向是矩阵乘接力,反向是同一条流水线上的责任审计,更新是沿谱调过速的下坡。下一章走进大模型的心脏,把那句全书立了二十一章的 flag 正式兑现:Attention,就是三次矩阵乘。