跳到主要内容

训练到底是怎么发生的 — 梯度、链式法则、反向传播

这一章讲三件事: 「调权重」这件第 01 章一笔带过的事,到底是怎么调的; 为什么几百上千亿个权重能一起调(链式法则);以及框架替你做了什么。 读完这一章,第 01 章那张训练循环图(权重→损失→优化器)里的每一步, 你都能用具体的数复述出来。

1. 顶层全景

训练循环的完整版是四步,每抓一小批量数据就转一圈1:

① 抽一小批量数据 x 和对应的真实答案 y_true
② 前向传播:让模型对 x 做出预测 y_pred
③ 损失函数比较 y_pred 与 y_true,得到一个损失值
④ 算出「损失对每个权重的梯度」,把每个权重往损失减小的方向挪一点

└─► 回到 ①

图说:第 ② 步是第 02 章讲过的张量运算;本章讲清第 ④ 步——
「梯度」是什么、怎么算、怎么用它挪权重。

本章的主走查是书里那张最小的计算图,只有三个数: 输入 x=2、权重 w=3、偏置 b=1、真实答案 y_true=4。 正向算出来:x1 = x·w = 6,x2 = x1 + b = 7,loss_val = |4 − 7| = 3。 然后反向:grad(loss, w) = 1×1×2 = 2,grad(loss, b) = 1×1 = 1—— 这两个数就是「w 该往哪调、调多大」2。全章的机制都会落在这条走查上。

2. 先看笨办法:为什么它行不通

想知道「每个权重该往哪边调」,最直觉的办法是逐个试: 把一个系数从 0.3 改成 0.35,重新跑一遍前向传播,看损失是涨是跌;跌了说明方向对,涨了说明方向反—— 书里给了一串这样的试验:0.5 → 改 0.35 变 0.6(方向反了)→ 改 0.25 变 0.4(方向对了)→ 再改 0.3 附近细调3

这条路的问题是一道乘法:每个系数要试两次前向传播,系数有多少个就要试多少轮。 今天的网络有几千上万、甚至几千亿个系数——逐一试完,宇宙都凉了4

所以必须找到一种办法:一次就把所有系数的「方向」都算出来。 这个办法存在的前提是,网络里所有运算都是光滑的——微小地动一下输入,输出也只微小地动, 而且这种微小变化是可以预测的。这样的函数叫可微函数(可以求导的函数); 把可微的运算组合在一起,得到的还是可微的5

3. 导数与梯度:「该往哪边挪」的方向指示

3.1 导数:局部的斜率

拿一条光滑曲线 f(x) 上的一点 p。在 p 点附近把曲线放大再放大, 它会越来越像一条直线——这条直线的斜率 a,就是 f 在 p 点的导数6

它回答的正是我们要的问题:x 在 p 点附近微小变化时,f(x) 会怎么变? 斜率为正,x 往右挪 f 就涨;斜率为负,x 往右挪 f 就跌。 所以,想让 f 变小,就沿着导数的反方向挪 x。 挪多大?挪一小步—— 因为这个「直线近似」只在 p 点附近成立,挪远了斜率就变了7

3.2 梯度:张量版的导数

神经网络的「x」不是一个数,而是一整张量的权重 W。「损失对 W 的导数」, 记作 grad(loss_value, W),是一个和 W 形状完全相同的张量—— W 里每个位置上的数,就是损失对那个位置上权重的导数(叫偏导数:假定其他权重都不动,只看这一个)8

这个张量有个漂亮的几何身份:它指向最陡上升方向——沿这个方向挪 W,损失涨得最快。 所以我们要干的事自然是它的反面:沿梯度相反的方向挪一小步9:

W = W − step × grad(loss, W)

图说:所有权重一起挪,一次算完。step 是一小步的步长。

理论上还有一个「解析法」:直接解方程「导数 = 0」找到最低点。 但那是 N 元方程组(N = 权重个数),实际网络里 N 大到根本解不动——所以只能走「挪一小步、再挪一小步」的迭代路线10

3.3 小批量随机梯度下降(SGD)

把上面的零件装起来,就是书里给的五步算法11:

  1. 抽一小批量(比如 128 个样本);
  2. 前向传播,算预测;
  3. 算损失;
  4. 算损失对每个权重的梯度;
  5. 权重沿梯度反方向挪一小步,步长由学习率控制。

学习率就是那个「一小步」的步长。 它是个需要人调的量: 太小,挪得慢,而且容易卡在局部极小点出不来;太大,可能在谷底两边来回跳、永远落不下去12

为什么叫「随机」?因为每一小步只用一小批量数据,而不是全部数据—— 每批数据给出的梯度都带点「噪声」,恰是这种噪声有时反而帮算法跳出小坑。 严格用全部数据算梯度的做法叫批量梯度下降,反而又慢又容易卡死13

书里还有一个诚实的提醒:损失曲面是几百万维的空间,没法画出来看, 所以「小球下山」这类画面只是低维直觉,高维里未必全对——这个直觉在第 06 章还会被再次修正(那里会给出高维空间到底有多大的实感:一张 28×28 的手写数字图,所有可能的像素组合比宇宙里的原子还多,而有效的数字只挤在其中极小的一块上)14

3.4 动量:为什么不卡在小坑里

小学习率的 SGD 有一个真实的麻烦:局部极小点——某个位置向左右挪损失都变大, 算法以为到底了,其实真正的最低点(全局极小点)在别处15

动量是给这个小球加上「速度」的办法:每一步不只看当前坡度, 还带上之前积累的速度,像小球滚下山——动量足够大时,它不会卡在浅坑里,能冲过去16。 RMSprop、Adam 这些常用优化器,都是在这个思路上做的变体(第 01 章的算法东风里出现过它们的名字)。

4. 反向传播:一次算出所有权重方向的机制

4.1 链式法则

第 3 节说了「算梯度」,但还没说怎么算。一个神经网络是一串函数套娃: y = f4(f3(f2(f1(x))))。微积分里有一条处理套娃的恒等式,叫链式法则17:

grad(y, x) = grad(y, x1) × grad(x1, x)

图说:「y 对 x 的变化率」= 沿链条每一环的变化率逐个相乘。

4.2 计算图:把计算变成数据

把前向传播的每一步运算画成节点、数据流向画成边,得到一张有向无环图—— 这就是计算图,它是 TensorFlow 这类框架的核心数据结构。 它的意义是:计算本身变成了可以操作的数据——可以遍历、可以求导、可以优化18

回到那张小图:主走查全程

现在把三个零件(链式法则、计算图、梯度)在主走查上拼起来。 那张小图的正向是:x=2 →(×w=3)→ x1=6 →(+b=1)→ x2=7 →(|4−x2|)→ loss=32

反向传播从损失出发,沿图的边往回走,每经过一条边,就问一句:「下游变化 epsilon 时,我变化多少?」19

正向(自下而上算值) 反向(自上而下算导数)
───────────── ─────────────
x=2, w=3 grad(x1, w) = 2 ← w 动 1,x1 动 2(因为 x1=2·w)
x1 = x·w = 6 grad(x2, x1) = 1 ← x1 动 1,x2 动 1
b = 1 grad(x2, b) = 1 ← b 动 1,x2 动 1
x2 = x1 + b = 7 grad(loss, x2) = 1 ← x2 动 1,loss 动 1
loss = |4 − 7| = 3

链式法则:沿路径把各边的导数连乘
grad(loss, w) = 1 × 1 × 2 = 2 → w 往梯度的反方向挪一点
grad(loss, b) = 1 × 1 = 1 → b 同样

图说:损失对 w 的影响是对 b 的两倍(因为还要过 ×3 那一关被放大),
所以 w 要挪得更小心。

如果两个节点之间有多条路径,把各条路径的值相加——这是链式法则在图上的完整形态20

到这里,书里有句话值得单独引出来,因为它是整章的落点21:

反向传播就是将链式法则应用于计算图,仅此而已。

4.3 框架替你做的:自动微分

手写这套反向求导,曾是入行门槛。作者的自述很有时代感: 他在 21 世纪头十年用 C 语言写了第一个神经网络,当时不得不手算梯度; 而今天的框架做自动微分——你只要写出前向传播,梯度自动就有,「你真幸运!」22

TensorFlow 里这个机制叫 GradientTape(梯度带): 在一个作用域里做张量运算,它默默把每一步记上磁带;放完之后, 你问它「损失对这些变量的梯度是多少」,它就把磁带倒回去放一遍,给你全部答案23。 第 04 章会用它亲手写训练循环。

原书这一章的收尾,是把第 02 章的 MNIST 例子完全手写了一遍: NaiveDense、NaiveSequential、批量生成器、单步训练、fit 循环,全部不用 Keras 的内置层—— 5 轮训练、每轮 469 次、共 2345 次梯度更新,精度和用 Keras 时一致24。 这个练习的用意不是让你以后都这么写,而是证明:前面三章讲的每一个零件,拼起来就是全部,没有藏起来的魔法。

5. 作者的判断与证据

证据(数学事实): 链式法则、梯度的方向性质、计算图上的连乘与多路径相加—— 这些是微积分,不是观点。走查里的每个数(grad=2、=1)都可以自己拿笔复核。

作者的经验判断: 动量「可以解决局部极小点问题」;RMSprop「几乎总是好的默认选择」(第 05 章); 低维直觉在高维未必成立。这些属于工程经验,书里给了理由但给不了证明——这和第 01 章的态度一致: 这个领域大量默认值是「试出来有效」。

6. 边界与局限

  • 「梯度指向最陡上升方向」在数学上严格成立,但沿它走一小步只是局部最优策略—— 它管不了全局,这就是局部极小点问题的根源;
  • 学习率、动量这类旋钮没有理论最优值,只能试——第 06 章会把「怎么系统地试」讲成一套工作流程;
  • 这一章的图都是可微的;不可微的运算(比如离散的 if 分支)进不了这张计算图—— 这是第 14 章「深度学习缺失的那一半」的伏笔;
  • 反向传播能算,不等于算得起:大模型的训练成本是另一个故事,第 13 章讲怎么加速。

7. 可带走的

  1. 训练 = 对每个权重算「损失对它的导数」,往反方向挪一小步,重复几万次;
  2. 逐个试系数的笨办法,代价是系数个数 × 2 次前向传播,在大网络上物理不可行;
  3. 梯度是和权重同形状的张量,指向损失最陡上升方向;反方向挪就是下降;
  4. 学习率管步长:太小卡坑,太大跳过谷底;动量给小球加速度,冲出浅坑;
  5. 小批量 SGD 的「随机」来自批量抽样,这点噪声有时反而是好事;
  6. 反向传播 = 链式法则应用于计算图;每条边一个导数,沿路径连乘,多路径相加;
  7. 主走查一句话:x=2、w=3 时 grad(loss, w)=2——w 对损失的影响是 b 的两倍,所以 w 要挪得更小心;
  8. 框架的 GradientTape 替你记带倒带;作者当年用 C 手算梯度的时代已经过去了。

8. 原文地图

主题原书章原文位置
训练循环四步神经网络的数学基础text/09-ch02.txt:765(搜「训练循环」)
笨办法逐个试系数神经网络的数学基础text/09-ch02.txt:780(搜「0.35」)
可微神经网络的数学基础text/09-ch02.txt:789(搜「可微」)
导数=局部斜率神经网络的数学基础text/09-ch02.txt:821(搜「导数」)
梯度与偏导数、最陡上升方向神经网络的数学基础text/09-ch02.txt:877(搜「偏导数」) · text/09-ch02.txt:882(搜「最陡上升方向」)
解析法不可行神经网络的数学基础text/09-ch02.txt:892(搜「解析法」)
小批量 SGD 五步、学习率神经网络的数学基础text/09-ch02.txt:906(搜「学习率」) · text/09-ch02.txt:920(搜「局部极小点」)
真 SGD 与批量梯度下降、高维提醒神经网络的数学基础text/09-ch02.txt:929(搜「批量梯度下降」) · text/09-ch02.txt:257(搜「可视化」)
动量与局部极小神经网络的数学基础text/09-ch02.txt:959(搜「局部极小点和全局极小点」) · text/09-ch02.txt:741(搜「小球」)
链式法则神经网络的数学基础text/09-ch02.txt:990(搜「链式法则」)
计算图神经网络的数学基础text/09-ch02.txt:1014(搜「计算图」)
走查:x1=6、x2=7、loss=3神经网络的数学基础text/09-ch02.txt:1047(搜「x1 = 6」) · text/09-ch02.txt:1064(搜「grad(x1, w) = 2」)
多路径相加、仅此而已神经网络的数学基础text/09-ch02.txt:1108(搜「多条路径」) · text/09-ch02.txt:1110(搜「将链式法则应用于计算图」)
自动微分与「你真幸运」神经网络的数学基础text/09-ch02.txt:1115(搜「C 语言」) · text/09-ch02.txt:1116(搜「再也不必自己实现反向传播」)
GradientTape神经网络的数学基础text/09-ch02.txt:1120(搜「GradientTape」)
手写全部零件的回顾神经网络的数学基础text/09-ch02.txt:1208(搜「2345」)

Footnotes

  1. 出处:「神经网络的数学基础」第 765 段(text/09-ch02.txt:765,搜「训练循环」)。

  2. 出处:「神经网络的数学基础」第 1047 段(text/09-ch02.txt:1047,搜「x1 = 6」)、第 1055 段(text/09-ch02.txt:1055,搜「loss_val = 3」)与第 1106 段(text/09-ch02.txt:1106,搜「grad(loss_val, w) = 1 * 1 * 2 = 2」)。这是图 2-23 至图 2-25 的完整示例。 2

  3. 出处:「神经网络的数学基础」第 780 段(text/09-ch02.txt:780,搜「0.35」)。

  4. 出处:「神经网络的数学基础」第 784 段(text/09-ch02.txt:784,搜「计算代价很大」)与第 897 段(text/09-ch02.txt:897,搜「参数的个数不会少于几千个」)。

  5. 出处:「神经网络的数学基础」第 789 段(text/09-ch02.txt:789,搜「可微」)。

  6. 出处:「神经网络的数学基础」第 816 段(text/09-ch02.txt:816,搜「斜率为 a」)与第 821 段(text/09-ch02.txt:821,搜「导数」)。

  7. 出处:「神经网络的数学基础」第 833 段(text/09-ch02.txt:833,搜「可微函数」)与第 766 段(text/09-ch02.txt:766,搜「足够小」)。

  8. 出处:「神经网络的数学基础」第 848 段(text/09-ch02.txt:848,搜「局部斜率」)与第 877 段(text/09-ch02.txt:877,搜「偏导数」)。

  9. 出处:「神经网络的数学基础」第 882 段(text/09-ch02.txt:882,搜「最陡上升方向」)与第 887 段(text/09-ch02.txt:887,搜「反方向移动」)。

  10. 出处:「神经网络的数学基础」第 892 段(text/09-ch02.txt:892,搜「解析法」)。

  11. 出处:「神经网络的数学基础」第 910 段(text/09-ch02.txt:910,搜「小批量 SGD」)。

  12. 出处:「神经网络的数学基础」第 906 段(text/09-ch02.txt:906,搜「学习率」)与第 918 段(text/09-ch02.txt:918,搜「如果取值太小」)。

  13. 出处:「神经网络的数学基础」第 929 段(text/09-ch02.txt:929,搜「批量梯度下降」)。

  14. 出处:「神经网络的数学基础」第 257 段(text/09-ch02.txt:257,搜「可视化」)。原文提醒:无法可视化 100 万维空间,低维直觉不一定准确。

  15. 出处:「神经网络的数学基础」第 959 段(text/09-ch02.txt:959,搜「局部极小点和全局极小点」)与第 961 段(text/09-ch02.txt:961,搜「都会导致损失值增大」)。

  16. 出处:「神经网络的数学基础」第 741 段(text/09-ch02.txt:741,搜「小球」)与第 969 段(text/09-ch02.txt:969,搜「momentum」)。

  17. 出处:「神经网络的数学基础」第 990 段(text/09-ch02.txt:990,搜「链式法则」)与第 998 段(text/09-ch02.txt:998,搜「grad(y, x)」)。

  18. 出处:「神经网络的数学基础」第 1014 段(text/09-ch02.txt:1014,搜「计算图」)与第 1019 段(text/09-ch02.txt:1019,搜「将计算看作数据」)。

  19. 出处:「神经网络的数学基础」第 1064 段(text/09-ch02.txt:1064,搜「grad(x1, w) = 2」)至第 1071 段(text/09-ch02.txt:1071,搜「grad(loss_val, x2) = 1」)。四条边的导数各有解释。

  20. 出处:「神经网络的数学基础」第 1108 段(text/09-ch02.txt:1108,搜「多条路径」)。

  21. 出处:「神经网络的数学基础」第 1110 段(text/09-ch02.txt:1110,搜「将链式法则应用于计算图」)。

  22. 出处:「神经网络的数学基础」第 1115 段(text/09-ch02.txt:1115,搜「C 语言」)与第 1116 段(text/09-ch02.txt:1116,搜「再也不必自己实现反向传播」)。

  23. 出处:「神经网络的数学基础」第 1120 段(text/09-ch02.txt:1120,搜「GradientTape」)。

  24. 出处:「神经网络的数学基础」第 1208 段(text/09-ch02.txt:1208,搜「2345」)。原书 2.5 节:5 轮训练、每轮 469 次、共 2345 次梯度更新。