跳到主要内容

下山与记账 — 训练到底是怎么一步步发生的

这一章讲三件事: 第 01 章留下一个口子——除了基函数回归那种特例, 「把损失调到最小」没有一步到位的公式,这一章讲一般做法:下山; 几百层、几亿个参数各自的「该往哪挪」,靠一套叫反向传播的记账法一次算清; 最后回答书名里那个词:为什么「深」值钱。 这是全书的技术地基,后面每一章都站在这章上。

1. 顶层全景:下山 + 记账

第 01 章的基函数回归有特权:损失是碗状的二次曲面,碗底一步算出来。 一般模型没这个特权——参数要穿过好几层「带弯的」变换才影响输出 (带弯的意思是:输出不是输入的直线比例,行话叫非线性), 损失面不再是碗,最优解没有闭式公式1

于是只剩一个朴素策略,它由两个动作组成:

动作一(下山):站在当前位置,看哪个方向下降最快,往那边挪一小步,重复;
动作二(记账):高效地算出「每个参数各自该往哪挪」——这就是反向传播。

图说:下山决定「往哪走」,记账负责「把这笔方向账算出来」。
训练 = 两个动作循环几百万次。

2. 下山(主走查·上)

「哪个方向下降最快」有精确的数学答案:损失的梯度(gradient)—— 损失对每个参数各求一个变化率,凑成的那一串数。它的方向是「损失上升最快」的方向。

所以要减掉它的一小部分,这就是梯度下降(gradient descent)2:

新的参数 = 旧的参数 − η × 梯度

那一小步的步长 η 叫学习率(learning rate)。它是全书第一个要紧的超参数, 两种死法原书都点了名3:

  • 太小: 下山慢,而且容易早早陷进一个浅坑爬不出来——损失面上比全局最低点 高出一截的坑洼叫局部极小(local minimum);
  • 太大: 在最优点附近来回弹跳,永远落不进谷底。

拿一个能算到底的玩具走完它。假设损失是 L(w) = (w − 3)², 碗底在 w = 3,我们从 w₀ = 10 出发,学习率取 0.3(这些数是为演示编的):

第 0 步: w = 10.00 梯度 = 2(w−3) = 14.0 → w = 10 − 0.3×14.0 = 5.80
第 1 步: w = 5.80 梯度 = 5.6 → w = 5.80 − 1.68 = 4.12
第 2 步: w = 4.12 梯度 = 2.24 → w = 4.12 − 0.67 = 3.45
第 3 步: w = 3.45 ……收敛到 3 附近

图说:每步把离碗底的距离砍到原来的四成(7 → 2.8 → 1.12 → …)。
同一架机器,放到几亿个参数上,每步就是「算一次梯度、全体挪一点」。

真实训练和这个玩具的差别只有两个:参数不止一个而是几亿个(梯度是一串几亿长的数), 以及每一步的方向只用一小批数据来估——这就是下一节。

3. 一次用一小批:SGD 与 Adam

理论上,梯度该对全部训练数据求平均再下山。但原书给了一个算账的观察: 数据内部有大量冗余,所以随便抽一小批算出来的方向,虽然带噪声, 却是全量方向的无偏估计(不系统性跑偏);同样的计算预算下, 「小步走很多次」比「精确方向走一次」下得快得多4

回忆第 02 章的事实:一批和一条几乎一样快。所以标准做法是: 把训练集切成一小批一小批,每批估一个方向、挪一步参数。这个做法叫 随机梯度下降(stochastic gradient descent, SGD;「随机」指每次抽哪批是随机的, 「小批量随机梯度下降」是它的全名)5

给两个量感6:

  • 这个过程极其渐进:小批的个数、下山的步数,通常以几百万计。 几百万步,每步挪一点点——这就是「训练」在时间轴上的真实样子;
  • 直觉会说「这么瞎摸肯定老掉坑里」。原书明说高维下直觉失效: 参数多到一定程度,加上数据的随机性,局部极小其实困不住它—— 「它的效率远比看上去高」。

SGD 有一堆改良版,最通行的叫 Adam:它对每个参数分别维护 「最近梯度有多大、波动有多大」的滑动统计,自动把每个参数的步幅归一—— 免得模型某些部位冲得快、某些部位不动。一个现成程序替代了人工调各层步长的麻烦, 先交代这行的用词:「优化」就是「把损失往下调」的意思。

这类「管下山策略的现成程序」统称优化器(optimizer)7

4. 记账:反向传播(主走查·下)

下山需要梯度,可模型是几百层串起来的:f = f⁽ᴰ⁾∘…∘f⁽¹⁾, 损失在最末端,参数埋在各层里。每个参数的梯度怎么算?

数学工具是微积分的链式法则(「复合函数的变化率 = 各段变化率相乘」)。 关键概念是雅可比(Jacobian):一层输出对输入(或对参数)的全部变化率 排成的一张表。链式法则在这里的意思是: 「损失对第 d−1 层输出的变化率」=「损失对第 d 层输出的变化率」×「第 d 层的雅可比」8

于是记账的顺序是倒着来的,所以叫反向传播(backpropagation)9:

前向传播(forward pass): x → f⁽¹⁾ → x⁽¹⁾ → f⁽²⁾ → … → x⁽ᴰ⁾ → 损失
沿途每一层的输出(激活)都记下来
反向传播(backward pass): 从损失端出发,倒着往回走
每到一层:手里的变化率 × 这层的雅可比 → 得到对「这层参数」和
「这层输入」的两份变化率;后者继续往上传

图说:正向算值,反向算「每个数对最终损失的贡献率」。
走完一趟,所有参数的梯度全部到手。

用一个三数玩具走一遍:模型是 ŷ = w·x,损失是 (ŷ − y)²。 取 w = 2,x = 5,真实答案 y = 12(演示数):

前向: ŷ = 2 × 5 = 10; 损失 = (10 − 12)² = 4
反向: 损失对 ŷ 的变化率 = 2(ŷ−y) = −4
ŷ 对 w 的变化率(这一层的雅可比) = x = 5
损失对 w 的梯度 = −4 × 5 = −20
下山一步(η=0.01): w = 2 − 0.01×(−20) = 2.2
检查:新 ŷ = 2.2×5 = 11,新损失 = 1。 4 → 1,确实降了。

图说:真实模型里这一步是几亿个这样的乘法,由同一条链式法则串起来。

实操上你不用手写这套:深度学习框架里的 Autograd 机制会跟踪你做过的 每个张量运算,自动搭出反向的计算图——写命令式代码,梯度自动可求10

5. 这笔账的开销与暗病

反向传播有两笔账要知道11:

  • 算力账: 计算主体是各层的矩阵乘法。前向每层一次矩阵乘; 反向要乘两次雅可比(一次给参数、一次往上传)。反向约为前向两倍价, 一趟训练步 ≈ 三倍前向;
  • 内存账: 反向要用到前向存下的激活(算雅可比要用)。所以训练时的内存占用 随模型深度线性增长——100 层就要存 100 层的中间结果。省内存的招: 只存部分层、用到时重算其余(拿计算换内存,这个技巧叫检查点(checkpointing)); 或把层设计成可逆的,反向时从输出倒推出输入。

暗病是连乘:反向每穿一层就乘一次雅可比,连乘几百次, 梯度会指数级地爆掉或归零12:

  • 爆掉有救:给梯度设一个总长度上限——一串数的总长度叫范数——超了就整体缩回来, 这叫梯度范数裁剪;
  • 归零——行话梯度消失(vanishing gradient)——曾是训练深网的历史性障碍: 浅处的层收不到任何「该往哪挪」的信号,训练停滞;轻症则是各层学习速度不一, 配合失调。

原书在这里记下了一个重要的视角转变,这是作者的判断也是史实: 与其改进通用优化方法,不如改造模型本身,让它生来可优化。 第 07 章整章(激活函数、归一化、残差连接)都是这个转变的产物13

6. 为什么「深」值钱

书名里的 deep,值得单独一问:层数多到底买到了什么?

原书给了一个漂亮的可视实验:一个 2 维→2 维的玩具模型,8 层, 每层 = 乘一个 2×2 矩阵再过 Tanh,最后接一个线性分类器——就是最后做 「归哪一类」判决的那个部件——任务是分开两团点。 训练之后,8 层矩阵协同地把整个平面逐步「扭」开——像揉一块布, 扭到第 8 层时,两团点已经被摆成一条直线能切开的样子14

输入层:两团点互相嵌套,直线切不开
每过一层:平面被局部地拉伸/压弯一点
第 8 层:点被摆成线性可分 → 最后的线性分类器一刀切

图说:深度买到的是「逐步改造空间」的能力。每层只做一点简单的形变,
复合起来就是复杂变换。(图按原书图 3.4 重述。)

作者同时给了诚实的警告:这个例子有误导性——2 维空间里扭布看着神奇, 真实模型靠的是高维表示:维度高,自由度多,优化反而更容易15

最后是两条硬结论16:

  • 经验: 二十年积累的证据表明,各领域最好的模型都需要几十层的深度;
  • 理论: 在固定的计算量或参数个数预算下,加深能造出更复杂的映射(Telgarsky 2016)。 同样一笔钱,花在深度上比花在宽度上买到的表达能力更多。

7. 作者的判断与证据

  • 「高维下直觉失效、局部极小困不住 SGD」是作者的经验陈述,原书措辞是 「its efficiency is far greater than one might expect」,没有配定理; 「二十年来各领域最优都要几十层」同理,是实证总结。
  • 「与其改优化器不如改模型」是作者对领域史的定性判断,第 07 章是它的证据展。
  • Telgarsky 2016 的深度定理是引用他人结果,原书只给结论不给证明。
  • 反向传播「两倍于前向」是结构账(每层多两次矩阵乘),不是测量值。

8. 边界与局限

  • 本章的下山是「每步固定走法」版本;为什么大模型训练近乎单调地变好(第 01 章的悬念), 要到第 05 章才谈。
  • 学习率怎么随时间变(先大后小)在第 05 章的训练流程里讲。
  • 可逆层、检查点只给了名字与思想,实现细节超出本书范围。
  • 「梯度消失怎么办」本章只指了方向(改造模型),具体零件在第 07 章。

9. 可带走的

  1. 闭式解是特例,下山是常态:梯度下降 = 算方向、挪一小步、重复几百万次;
  2. 学习率只有两种错法:太小(慢、困浅坑)、太大(谷底弹跳)——调它先想这两种死法;
  3. 小批估方向反而更快,因为数据有冗余;一批和一条一样快,所以批是最合算的单位;
  4. Adam = 给每个参数自动归一步幅的优化器,是当今默认选项;
  5. 反向传播 = 链式法则的组织化:正向存激活,反向逐层乘雅可比,一趟算清全部梯度;
  6. 训练一步 ≈ 三倍前向的算力;训练内存随深度线性涨——这两个数是后面所有 「模型太大怎么办」讨论(第 05、12 章)的起点;
  7. 梯度消失源于连乘;现代解法是改造模型结构,不是改优化器;
  8. 深度买到的是表达能力:同样的参数预算,深的映射更复杂——但「为什么深的好训练」 仍未被理论完全解释,原书照实说了。

10. 原文地图

主题原书章原文位置
一般情形无闭式解Gradient descenttext/08-fm-gradient-descent.txt:4(搜「closed-form」)
梯度下降公式与学习率Gradient descenttext/08-fm-gradient-descent.txt:14(搜「(3.1)」) · text/08-fm-gradient-descent.txt:27(搜「too small」)
SGD:部分和是无偏估计Gradient descenttext/08-fm-gradient-descent.txt:68(搜「unbiased estimator」)
步数以百万计;高维直觉失效Gradient descenttext/08-fm-gradient-descent.txt:89(搜「several million」) · text/08-fm-gradient-descent.txt:91(搜「intuition breaks down」)
AdamGradient descenttext/08-fm-gradient-descent.txt:101(搜「Adam」)
前向/反向与雅可比Backpropagationtext/09-fm-backpropagation.txt:34(搜「applying iteratively」) · text/09-fm-backpropagation.txt:50(搜「the product of the gradient」)
AutogradBackpropagationtext/09-fm-backpropagation.txt:76(搜「Autograd」)
反向两倍价;内存随深度Backpropagationtext/09-fm-backpropagation.txt:87(搜「twice as costly」) · text/09-fm-backpropagation.txt:94(搜「grows proportionally」)
梯度消失与视角转变Backpropagationtext/09-fm-backpropagation.txt:103(搜「van」) · text/09-fm-backpropagation.txt:120(搜「change in perspective」)
8 层扭空间实验The value of depthtext/10-fm-the-value-of-depth.txt:10(搜「eight layers」)
深度定理The value of depthtext/10-fm-the-value-of-depth.txt:47(搜「Telgarsky」)

Footnotes

  1. 出处:「Gradient descent」第 2–5 段(text/08-fm-gradient-descent.txt:4,搜「closed-form」)。

  2. 出处:「Gradient descent」第 5–17 段(text/08-fm-gradient-descent.txt:14,搜「(3.1)」)。原书公式 3.1:w_{n+1} = w_n − η∇ℒ。

  3. 出处:「Gradient descent」第 19–44 段(text/08-fm-gradient-descent.txt:27,搜「too small」)。

  4. 出处:「Gradient descent」第 46–74 段(text/08-fm-gradient-descent.txt:68,搜「unbiased estimator」)。

  5. 出处:「Gradient descent」第 76–86 段(text/08-fm-gradient-descent.txt:76,搜「as fast as processing」)。

  6. 出处:「Gradient descent」第 88–97 段(text/08-fm-gradient-descent.txt:89,搜「several million」;text/08-fm-gradient-descent.txt:91,搜「intuition breaks down」)。

  7. 出处:「Gradient descent」第 99–104 段(text/08-fm-gradient-descent.txt:101,搜「Adam」)。Adam 论文:Kingma and Ba, 2014。

  8. 出处:「Backpropagation」第 29–57 段(text/09-fm-backpropagation.txt:50,搜「the product of the gradient」)。

  9. 出处:「Backpropagation」第 59–67 段(text/09-fm-backpropagation.txt:25,搜「backward」)。原文:「The combination of this computation with the procedure of gradient descent is called backpropagation」。

  10. 出处:「Backpropagation」第 69–80 段(text/09-fm-backpropagation.txt:76,搜「Autograd」)。引 Baydin et al., 2015。

  11. 出处:「Backpropagation」第 81–101 段(text/09-fm-backpropagation.txt:87,搜「twice as costly」;text/09-fm-backpropagation.txt:94,搜「grows proportionally」)。检查点引 Chen et al., 2016;可逆层引 Gomez et al., 2017。

  12. 出处:「Backpropagation」第 103–117 段(text/09-fm-backpropagation.txt:103,搜「van」)。梯度裁剪引 Pascanu et al., 2013。

  13. 出处:「Backpropagation」第 119–123 段(text/09-fm-backpropagation.txt:120,搜「change in perspective」)。原文:「instead of trying to improve generic optimization methods, the effort shifted to engineering the models themselves to make them optimizable」。

  14. 出处:「The value of depth」第 9–35 段(text/10-fm-the-value-of-depth.txt:10,搜「eight layers」;图 3.4 题注 text/10-fm-the-value-of-depth.txt:30,搜「the deformation of the」)。

  15. 出处:「The value of depth」第 22–38 段(text/10-fm-the-value-of-depth.txt:23,搜「partially misleading」)。

  16. 出处:「The value of depth」第 40–47 段(text/10-fm-the-value-of-depth.txt:40,搜「Empirical evidence」;text/10-fm-the-value-of-depth.txt:47,搜「Telgarsky」)。