人工神经网络小史

从感知机到推理模型

2026

感知机:从形式神经元到第一次寒冬

一切从一个想把大脑写成逻辑公式的精神病学家,和一个流落街头、自学逻辑学的少年开始。1943 年的 McCulloch 与 Pitts 把神经元化简成一个“全或无”的阈值开关,证明这样的开关连成网络就能算任何逻辑命题;十五年后 Rosenblatt 给这个开关装上了“会学习”的旋钮,造出第一台真正能从数据里自己调参数的机器。然后,1969 年的两页代数把它按进了水里——一个连“异或”都算不出来的模型,凭什么承载智能的梦想?这一章讲清楚感知机怎么来的、它的更新规则为什么一定收敛、以及它到底败在哪里。


要理解人工神经网络这条线路的起点,得先理解一个奇怪的转译动作:把“神经元放电”翻译成“逻辑命题为真”。

1943 年,神经生理学家 Warren McCulloch 和当时只有十八岁、没有任何正式学位的逻辑天才 Walter Pitts,在《数理生物物理学通报》上发表了《神经活动中内在思想的逻辑演算》(A Logical Calculus of the Ideas Immanent in Nervous Activity)1。他们抓住了真实神经元的一个粗糙但关键的特征:神经元的放电是“全或无”(all-or-none)的——要么发放一个动作电位,要么不发放,没有中间状态。

既然输出只有 0 和 1,McCulloch 和 Pitts 就把神经元当成一个逻辑命题的真值:放电=真,静息=假。一个神经元接收若干输入,每个输入要么兴奋要么抑制,当兴奋输入的总和超过某个阈值、且没有抑制输入被激活时,它就放电。他们随后用纯粹的命题逻辑证明:把这种单元按合适的方式连接起来,可以实现任意逻辑函数——与、或、非,以及它们的任意组合2

这是一个分水岭式的论断。它意味着大脑的“思维”原则上可以被还原为一张逻辑电路图,也意味着“计算”和“神经活动”在数学上是同一种东西。冯·诺依曼后来在设计存储程序计算机时引用了这篇论文;自动机理论、计算神经科学、人工智能都把它当作奠基文献之一1

McCulloch-Pitts 神经元(下称 M-P 神经元)的数学形式极简。给定输入 x1,,xn{0,1}x_1, \dots, x_n \in \{0,1\},权重 w1,,wnw_1, \dots, w_n(在最初的版本里是固定的 ±1\pm 1),阈值 θ\theta,输出为

y={1,i=1nwixiθ0,否则 y = \begin{cases} 1, & \sum_{i=1}^{n} w_i x_i \ge \theta \\ 0, & \text{否则} \end{cases}

写成一个阶跃函数(Heaviside step)就是 y=H(iwixiθ)y = H\!\left(\sum_i w_i x_i - \theta\right)

它能算逻辑“与”:两个输入、权重都为 1、阈值设为 2,只有两个输入都为 1 时和才达到 2。它能算“或”:阈值设为 1。它能算“非”:用一个抑制性输入。把这些拼起来,理论上任意布尔函数都能搭出来。

但 M-P 神经元有一个致命的留白:权重和阈值是人手工设定的,模型本身不会学习。它是一台需要工程师拧螺丝的逻辑机器,不是一台能从经验里自己拧螺丝的机器。让神经元“会学习”的那一步,要等到 Hebb 和 Rosenblatt。


1949 年,心理学家 Donald Hebb 在《行为的组织》里提出了一条后来被反复引用的学习原则,常被概括成一句口诀:“一起放电的神经元,会连在一起”(neurons that fire together, wire together)。用数学语言说,如果突触前神经元 xx 和突触后神经元 yy 经常同时激活,它们之间的连接权重 ww 就应该增强:

Δwxy \Delta w \propto x \cdot y

Hebb 规则第一次把“学习”定义成“权重的局部修改”,而且是一条只依赖局部信息(前后两个神经元的活动)的规则。这正是后来所有神经网络学习算法的雏形:学习 = 调权重。但 Hebb 规则本身是无监督的、没有“目标”的,它只会让经常共现的连接变强,不会朝某个任务目标去优化。

把“目标”引进来、并给出第一台真正可训练的机器的,是 Frank Rosenblatt。


Rosenblatt 是康奈尔大学训练出来的心理学家,1956 年拿到博士学位后进入康奈尔航空实验室(Cornell Aeronautical Laboratory)3。1957 年他做出第一个感知机(Perceptron)原型,1958 年在《心理学评论》(Psychological Review,第 65 卷 386–408 页)发表《感知机:大脑中信息存储与组织的概率模型》34

感知机与 M-P 神经元的根本区别在于:权重不再是手工设定的,而是从数据里学出来的。Rosenblatt 把它描述为第一个“精确指定、面向计算”的神经网络模型,并配上了一套受物理系统启发的可调参数与训练数学4。它不是一个纯软件概念——Mark I Perceptron 是一台真实的硬件机器,用一个 20×20 的光电管阵列做“视网膜”,用电位器(可变电阻)的旋转角度物理地存储权重,靠电机自动调节。这是历史上第一台“看着学”的机器。

感知机的前向计算和 M-P 神经元几乎一样,只是把阈值 θ\theta 挪到左边、记成偏置 b=θb = -\theta,并把权重并进一个向量 𝒘\mathbf{w}

ŷ={1,𝒘𝒙+b00,否则 \hat{y} = \begin{cases} 1, & \mathbf{w}^\top \mathbf{x} + b \ge 0 \\ 0, & \text{否则} \end{cases}

真正的新东西是学习规则。给定一批带标签的样本 (𝒙i,yi)(\mathbf{x}_i, y_i)yi{0,1}y_i \in \{0,1\},感知机逐个看样本,每看一个就比较自己的预测 ŷi\hat{y}_i 和真实标签 yiy_i,按误差修正权重:

𝒘𝒘+η(yiŷi)𝒙i,bb+η(yiŷi) \mathbf{w} \leftarrow \mathbf{w} + \eta\,(y_i - \hat{y}_i)\,\mathbf{x}_i, \qquad b \leftarrow b + \eta\,(y_i - \hat{y}_i)

其中 η>0\eta > 0 是学习率。这条规则的直觉非常清楚:

每一次“犯错”都把决策边界朝正确方向推一点。这就是“从错误中学习”最朴素的数学化身。


感知机最迷人的地方,是它带着一个理论保证:只要数据是线性可分的,这个朴素的纠错规则一定会在有限步内停下来,而且能算出停下来之前最多犯多少次错。这就是 1962 年由纽约大学数学家 Albert Novikoff 证明的感知机收敛定理56

把标签换成 {1,+1}\{-1, +1\} 更方便表述。假设存在一个单位向量 𝒘*\mathbf{w}^*𝒘*=1\|\mathbf{w}^*\| = 1)能以间隔(margin)γ>0\gamma > 0 把数据分开,即对所有样本

yi(𝒘*𝒙i)γ>0 y_i\,(\mathbf{w}^{*\top}\mathbf{x}_i) \ge \gamma > 0

再设所有数据点的范数有界,𝒙iR\|\mathbf{x}_i\| \le R。那么感知机(η=1\eta = 1、从零权重开始)犯错的总次数 MM 满足

M(Rγ)2 M \le \left(\frac{R}{\gamma}\right)^2

证明只用到两个简单的不等式,思路非常优雅,值得完整走一遍。设 𝒘k\mathbf{w}_k 是犯了第 kk 次错之后的权重,每次犯错都做 𝒘k=𝒘k1+yi𝒙i\mathbf{w}_{k} = \mathbf{w}_{k-1} + y_i \mathbf{x}_i

下界(投影在增长):考察 𝒘k\mathbf{w}_k 在理想方向 𝒘*\mathbf{w}^* 上的投影。每犯一次错,

𝒘*𝒘k=𝒘*𝒘k1+yi(𝒘*𝒙i)𝒘*𝒘k1+γ \mathbf{w}^{*\top}\mathbf{w}_k = \mathbf{w}^{*\top}\mathbf{w}_{k-1} + y_i\,(\mathbf{w}^{*\top}\mathbf{x}_i) \ge \mathbf{w}^{*\top}\mathbf{w}_{k-1} + \gamma

从零开始累加 MM 次,得到 𝒘*𝒘MMγ\mathbf{w}^{*\top}\mathbf{w}_M \ge M\gamma。由柯西-施瓦茨,𝒘M𝒘*𝒘MMγ\|\mathbf{w}_M\| \ge \mathbf{w}^{*\top}\mathbf{w}_M \ge M\gamma

上界(范数长得慢):考察 𝒘k\mathbf{w}_k 自身的长度平方。每次犯错(犯错意味着 yi(𝒘k1𝒙i)0y_i(\mathbf{w}_{k-1}^\top\mathbf{x}_i) \le 0),

𝒘k2=𝒘k12+2yi(𝒘k1𝒙i)+𝒙i2𝒘k12+R2 \|\mathbf{w}_k\|^2 = \|\mathbf{w}_{k-1}\|^2 + 2 y_i(\mathbf{w}_{k-1}^\top\mathbf{x}_i) + \|\mathbf{x}_i\|^2 \le \|\mathbf{w}_{k-1}\|^2 + R^2

累加 MM 次得 𝒘M2MR2\|\mathbf{w}_M\|^2 \le M R^2,即 𝒘MMR\|\mathbf{w}_M\| \le \sqrt{M}\,R

合并Mγ𝒘MMRM\gamma \le \|\mathbf{w}_M\| \le \sqrt{M}\,R,两边整理得 M(R/γ)2M \le (R/\gamma)^2。证毕。

这个界为什么重要?它说明收敛次数完全不依赖于数据的维度,也不依赖于样本的数量,只依赖于“几何上数据分得有多开”(间隔 γ\gamma)和“数据有多大”(半径 RR)。间隔越大、越好分,犯错越少。这是机器学习里第一个把“可学习性”量化成几何量的结果,是后来支持向量机(最大化间隔)和统计学习理论的思想先声。


理论保证带来了第一波过度乐观。Rosenblatt 本人和当时的媒体都对感知机做了大胆预言,《纽约时报》报道说海军期待这种机器未来能行走、说话、看、写、自我复制并意识到自己的存在。一时间感知机被当成通向人工智能的康庄大道。

但收敛定理有一个被乐观情绪盖住的前提,藏在那个 if 里:只要数据线性可分。如果数据不是线性可分的呢?定理什么都不保证——事实上,对线性不可分的数据,感知机的权重会永远来回震荡,不会停。

而“线性可分”这个前提,远比人们想象的脆弱。


1969 年,麻省理工学院的 Marvin Minsky 和 Seymour Papert 出版了《感知机》(Perceptrons)一书,用严密的代数和几何分析,系统地刻画了单层感知机能算什么、不能算什么7。其中最著名、杀伤力最大的一个例子,是逻辑“异或”(XOR)。

XOR 的真值表是:(0,0)0(0,0)\to 0(0,1)1(0,1)\to 1(1,0)1(1,0)\to 1(1,1)0(1,1)\to 0。把这四个点画在平面上,标签为 1 的两个点 (0,1)(0,1)(1,0)(1,0) 落在一条对角线上,标签为 0 的两个点 (0,0)(0,0)(1,1)(1,1) 落在另一条对角线上。没有任何一条直线能把“1 类”和“0 类”分到两边——这就是线性不可分8

而单层感知机的决策边界 𝒘𝒙+b=0\mathbf{w}^\top\mathbf{x} + b = 0 恰恰就是一条直线(高维里是一个超平面)。所以单层感知机在数学上不可能学会 XOR。这不是训练不够久或学习率没调好的问题,是表达能力的硬上限。

更要命的是,Minsky 和 Papert 还分析了一类需要“全局”信息的几何谓词(比如判断一个图形是否连通),论证了某些问题所需的感知机规模会随问题规模爆炸式增长。书的整体基调,给当时方兴未艾的神经网络研究泼了一盆冷水。

历史叙述里常说《感知机》一书“直接引发了第一次 AI 寒冬”——这个因果应当谨慎对待。这本书出版后不久,神经网络研究的资助和热情确实显著下降,进入了从 1970 年代初到 1980 年代初的低潮期8。但把整场寒冬归因于一本书,是把复杂的资助政治、学术派系、技术瓶颈简化成了一个戏剧性的转折点。比较稳妥的说法是:《感知机》给出了单层模型局限的权威论证,与当时本就存在的过度承诺落空、算力不足等因素叠加,共同促成了那段低潮。

值得强调的是另一个常被忽略的事实:Minsky 和 Papert 批判的是单层感知机。他们也清楚,多层网络原则上能突破线性局限——把多个感知机叠起来,第一层先把 XOR 变换到一个线性可分的新空间,第二层就能分开。书里对多层网络能否被有效训练持悲观态度,而这恰恰是问题的真正关键:缺的不是多层结构的想法,而是训练多层网络的算法。这个算法,就是反向传播——它的核心思想其实在《感知机》出版前后就已被一些人独立发现,却要等到 1986 年才真正改变历史。那是下一章的故事。


把这一章的数学落到能跑的代码上,最能体会“收敛”与“不收敛”的分野。下面是用纯 NumPy 写的感知机,逐样本在线更新,完全对应第三节的更新规则(完整文件见配套代码 code/01_perceptron.py,可直接运行):

import numpy as np

def perceptron_train(X, y, lr=1.0, max_epochs=100):
    n, d = X.shape
    w = np.zeros(d); b = 0.0; mistakes = 0
    for epoch in range(max_epochs):
        errors = 0
        for i in range(n):
            y_hat = 1 if (X[i] @ w + b) >= 0 else 0
            update = lr * (y[i] - y_hat)          # 误差项 (y - y_hat)
            if update != 0:
                w += update * X[i]                # w <- w + eta*(y-y_hat)*x
                b += update                       # b <- b + eta*(y-y_hat)
                errors += 1; mistakes += 1
        if errors == 0:                            # 一整轮无错 => 收敛
            return w, b, epoch + 1, mistakes
    return w, b, max_epochs, mistakes

X = np.array([[0,0],[0,1],[1,0],[1,1]], dtype=float)
print(perceptron_train(X, np.array([0,0,0,1])))   # AND
print(perceptron_train(X, np.array([0,1,1,0])))   # XOR

实际运行的输出是:

[AND ] 收敛于 6 epoch, 共 11 次错误更新, w=[2. 1.], b=-3.0
[OR  ] 收敛于 4 epoch, 共 5 次错误更新, w=[1. 1.], b=-1.0
[XOR ] 100 epoch 仍未收敛, 错误更新累计 398 次 —— 线性不可分,感知机无解

AND 和 OR 是线性可分的,感知机分别在 6 轮和 4 轮内停下,权重 𝒘=[2,1],b=3\mathbf{w}=[2,1], b=-3 给出的边界 2x1+x23=02x_1 + x_2 - 3 = 0 确实把 (1,1)(1,1) 单独分到正侧。而 XOR 跑满 100 轮也停不下来,错误更新累计近四百次还在震荡——这正是 Novikoff 定理的反面:前提(线性可分)不成立,保证(有限步收敛)就消失。代码把 1969 年那个抽象的代数结论,变成了屏幕上一行永不收敛的计数。


用一张图把这一章的几何直觉钉死。下面是 XOR 四个点的布局(o 为类别 0,x 为类别 1):

 x2
  1 |  x(0,1)        o(1,1)
    |
    |       (任何一条直线都无法
    |        把 x 和 o 分到两侧)
  0 |  o(0,0)        x(1,0)
    +-------------------------- x1
       0              1

AND 的布局则是线性可分的——只有 (1,1)(1,1) 是类别 1,一条直线(如 2x1+x2=32x_1+x_2=3)就能把它从其余三点里切出来:

 x2
  1 |  o(0,1)        x(1,1)      边界 2*x1 + x2 = 3
    |             /              (右上角单独划出)
  0 |  o(0,0)  / o(1,0)
    +-------------------------- x1

配套的 manim 动画 assets/manim/ch01_perceptron.py(含 PerceptronLineXORImpossible 两个 Scene)把这件事演成几何:在 AND 上,一条分隔直线随权重更新而旋转、平移,最终把两类点干净分开;在 XOR 上,同一条直线无论怎么转、怎么移,总有一个点被切到错误的一侧。两段动画并排,就是感知机一生的隐喻——在它能分开的世界里,它优雅、可证明、必然收敛;在它分不开的世界里,它再努力也只是徒劳地震荡。

这台 1958 年的机器,第一次让“学习”成为可被数学保证的事,也第一次让我们看清:单一线性决策面的表达能力是有硬边界的。突破这个边界需要两样东西——更深的结构,和训练更深结构的算法。前者的想法早已存在,后者,将在十七年后以“反向传播”之名,把整个领域从寒冬里拉出来。


本质

感知机真正的贡献不是“模仿神经元”,而是把“学习”这件模糊的事变成了一个可证明的几何操作:在特征空间里找一个分隔超平面,并给出一条一定能找到它的更新规则。它的伟大与它的局限是同一件事——它只会画一条直线。能用一条直线分开的世界,它必然学得会且必然收敛;分不开的世界(哪怕简单如异或),它再努力也只是徒劳地震荡。此后六十年的整部神经网络史,本质上是在回答感知机留下的那一个问题:当一条直线不够用时,怎么把许多条直线叠成任意复杂的曲面。


参考文献

  1. McCulloch, W. S., & Pitts, W. (1943). A Logical Calculus of the Ideas Immanent in Nervous Activity. Bulletin of Mathematical Biophysics, 5, 115–133. 原文 PDF(CMU 镜像):https://www.cs.cmu.edu/~epxing/Class/10715/reading/McCulloch.and.Pitts.pdf ;Springer 记录:https://link.springer.com/article/10.1007/BF02478259

  2. “A Logical Calculus of the Ideas Immanent in Nervous Activity” — 综述与影响(含 von Neumann 引用、Pitts 生平)。Wikipedia:https://en.wikipedia.org/wiki/A_Logical_Calculus_of_the_Ideas_Immanent_in_Nervous_Activity

  3. Rosenblatt, F. (1958). The Perceptron: A Probabilistic Model for Information Storage and Organization in the Brain. Psychological Review, 65(6), 386–408. Cornell Aeronautical Laboratory. PsycNet 记录:https://psycnet.apa.org/record/1959-09865-001

  4. Rosenblatt 1958 原文 PDF(UIC 镜像):https://homepages.math.uic.edu/~lreyzin/papers/rosenblatt58.pdf ;MIT Press Ideas That Created the Future 评注:https://ieeexplore.ieee.org/document/9357585

  5. Novikoff, A. B. J. (1962). On Convergence Proofs for Perceptrons. 原始技术报告(DTIC AD0298258):https://apps.dtic.mil/sti/tr/pdf/AD0298258.pdf

  6. 感知机收敛定理证明(教学整理,含 (R/γ)² 界)。University of Waterloo CS480/680 讲义:https://cs.uwaterloo.ca/~y328yu/teaching/480/480-note-per.pdf ;Perceptron 综述:https://en.wikipedia.org/wiki/Perceptron

  7. Minsky, M., & Papert, S. (1969). Perceptrons: An Introduction to Computational Geometry. MIT Press. 综述:https://en.wikipedia.org/wiki/Perceptrons_(book)

  8. “Perceptrons, XOR, and the first AI winter”(XOR 线性不可分性与寒冬背景,二手综述,含史料梳理)。Sean Trott:https://seantrott.substack.com/p/perceptrons-xor-and-the-first-ai ;“The Perceptron Controversy”(优先权与争议梳理):https://yuxi-liu-wired.github.io/essays/posts/perceptron-controversy/

反向传播:把误差送回去

多层网络能突破单层感知机的线性局限,这件事 1969 年就有人知道。真正缺的不是“叠几层”的想法,而是一个能把“最终输出错了多少”高效地、逐层地分摊回每一个权重的算法——告诉网络深处每一个旋钮:你该往哪个方向、拧多少。这个算法叫反向传播(backpropagation),它的数学内核只是微积分课本里的链式法则,却前后被至少三拨人独立发现,又被一篇 1986 年的《自然》论文真正推上历史舞台。这一章讲清楚梯度怎么反向流动、为什么这个流动是高效的、以及“谁发明了它”这个问题为什么至今仍有争论。


回到上一章结尾的困境。单层感知机画不出能分开 XOR 的直线,但只要在输入和输出之间加一层“隐藏单元”,让第一层先把四个点变换到一个新的坐标系里、在那里它们变得线性可分,第二层就能轻松分开。多层网络的表达能力远超单层——1989 年 Cybenko 对 sigmoid 激活、以及 Hornik 等人随后的工作,更是证明了只要一个隐藏层、足够多的单元,就能以任意精度逼近任意连续函数(通用逼近定理)1。结构上的潜力是确定的。

问题出在训练。感知机的学习规则只对单层有效:它直接比较“输出层的预测”和“标签”,用两者的差去修正权重。可一旦有了隐藏层,麻烦就来了——隐藏单元没有“标签”。我们知道最终输出错了多少,却不知道隐藏层里那个具体的权重“该为这个错误负多少责任”。这个“功劳/过错分配问题”(credit assignment problem)才是训练多层网络的真正拦路虎。

反向传播就是这个问题的解。它的答案,藏在一条所有理科生都学过的法则里:链式法则。


先把一个多层网络的前向计算写清楚。以最简单的两层网络(一个隐藏层)为例,输入 𝒙\mathbf{x},第一层权重 W(1)W^{(1)}、偏置 𝒃(1)\mathbf{b}^{(1)},激活函数 σ\sigma

𝒛(1)=W(1)𝒙+𝒃(1),𝒂(1)=σ(𝒛(1)) \mathbf{z}^{(1)} = W^{(1)}\mathbf{x} + \mathbf{b}^{(1)}, \qquad \mathbf{a}^{(1)} = \sigma(\mathbf{z}^{(1)}) 𝒛(2)=W(2)𝒂(1)+𝒃(2),𝒚̂=σ(𝒛(2)) \mathbf{z}^{(2)} = W^{(2)}\mathbf{a}^{(1)} + \mathbf{b}^{(2)}, \qquad \hat{\mathbf{y}} = \sigma(\mathbf{z}^{(2)})

再定义一个损失函数 LL 衡量预测 𝒚̂\hat{\mathbf{y}} 与真实标签 𝒚\mathbf{y} 的差距,比如均方误差 L=12𝒚̂𝒚2L = \tfrac{1}{2}\|\hat{\mathbf{y}} - \mathbf{y}\|^2。训练的目标是调整所有的 W,𝒃W, \mathbf{b} 使 LL 最小。

最小化一个可微函数的标准武器是梯度下降:沿着损失对参数的负梯度方向走一小步,

WWηLW W \leftarrow W - \eta\,\frac{\partial L}{\partial W}

所以全部问题归结为一件事:怎么算出 LL 对每一个权重的偏导数 L/W\partial L / \partial W。网络可能有几百万个权重,深处的权重和最终损失之间隔着层层非线性变换。这正是链式法则登场的地方。


链式法则说:复合函数的导数等于各层导数的乘积。如果 LL 依赖 𝒛(2)\mathbf{z}^{(2)}𝒛(2)\mathbf{z}^{(2)} 依赖 𝒂(1)\mathbf{a}^{(1)}𝒂(1)\mathbf{a}^{(1)} 依赖 𝒛(1)\mathbf{z}^{(1)}𝒛(1)\mathbf{z}^{(1)} 依赖 W(1)W^{(1)},那么

LW(1)=L𝒛(2)𝒛(2)𝒂(1)𝒂(1)𝒛(1)𝒛(1)W(1) \frac{\partial L}{\partial W^{(1)}} = \frac{\partial L}{\partial \mathbf{z}^{(2)}} \cdot \frac{\partial \mathbf{z}^{(2)}}{\partial \mathbf{a}^{(1)}} \cdot \frac{\partial \mathbf{a}^{(1)}}{\partial \mathbf{z}^{(1)}} \cdot \frac{\partial \mathbf{z}^{(1)}}{\partial W^{(1)}}

反向传播的全部精髓,是观察到这条乘积链可以从右到左(从损失端到输入端)逐项复用,而不必为每个权重从头乘一遍。定义一个关键的中间量——第 ll 层的“误差信号” 𝜹(l)=L/𝒛(l)\boldsymbol{\delta}^{(l)} = \partial L / \partial \mathbf{z}^{(l)},它表示“该层的加权输入对最终损失的敏感度”。

输出层,误差信号直接来自损失:

𝜹(2)=L𝒚̂σ(𝒛(2)) \boldsymbol{\delta}^{(2)} = \frac{\partial L}{\partial \hat{\mathbf{y}}} \odot \sigma'(\mathbf{z}^{(2)})

\odot 是逐元素乘。对均方误差,L/𝒚̂=𝒚̂𝒚\partial L/\partial \hat{\mathbf{y}} = \hat{\mathbf{y}} - \mathbf{y}。)

关键的递推是:上一层(更靠近输入)的误差信号,可以由下一层(更靠近输出)的误差信号“反传”得到:

𝜹(1)=(W(2)𝜹(2))σ(𝒛(1)) \boldsymbol{\delta}^{(1)} = \left( {W^{(2)}}^\top \boldsymbol{\delta}^{(2)} \right) \odot \sigma'(\mathbf{z}^{(1)})

读这个公式:W(2)𝜹(2)W^{(2)\top}\boldsymbol{\delta}^{(2)} 把输出层的误差按权重“摊回”到隐藏层各单元——一个隐藏单元如果通过大权重强烈影响了输出,它就该为输出的误差承担更多责任;再乘上本层激活函数的导数 σ(𝒛(1))\sigma'(\mathbf{z}^{(1)}),因为误差要穿过这层的非线性。

有了每层的 𝜹(l)\boldsymbol{\delta}^{(l)},对应的权重梯度就是一个外积:

LW(l)=𝜹(l)𝒂(l1),L𝒃(l)=𝜹(l) \frac{\partial L}{\partial W^{(l)}} = \boldsymbol{\delta}^{(l)}\,{\mathbf{a}^{(l-1)}}^\top, \qquad \frac{\partial L}{\partial \mathbf{b}^{(l)}} = \boldsymbol{\delta}^{(l)}

整个算法就是一次前向传播(算出各层 𝒛,𝒂\mathbf{z}, \mathbf{a} 并缓存),再一次反向传播(从输出层开始,逐层用上面的递推算出 𝜹\boldsymbol{\delta} 和梯度)。


为什么这件事是个突破,而不是“显然的链式法则练习”?因为效率

朴素地算梯度,可以用数值微分:把每个权重轻轻扰动一点 ϵ\epsilon,看损失变化多少,L/w(L(w+ϵ)L(w))/ϵ\partial L/\partial w \approx (L(w+\epsilon) - L(w))/\epsilon。但这要求每个权重都跑一次完整的前向传播。一个有 PP 个参数的网络,算一次完整梯度就要跑 PP 次前向,对百万参数的网络是灾难。

反向传播的魔法在于:算完整梯度的代价,和算一次前向传播的代价是同一个量级。一次前向、一次反向,就拿到了所有 PP 个参数的偏导数。这正是“反向模式自动微分”(reverse-mode automatic differentiation)的核心性质——前向与反向的计算成本相当,而一次反向就能得到一个标量输出对所有输入的全部梯度2。现代深度学习框架(PyTorch 的 autograd、TensorFlow 的计算图)本质上就是把这套反向模式自动微分通用化、自动化2。把训练上亿参数的模型变得可行,靠的就是这个 O(1)O(1) 倍而非 O(P)O(P) 倍的效率。


“谁发明了反向传播”是技术史里最著名的优先权公案之一,值得分层并陈,而不是简单归给某一个名字。

1970 年,Seppo Linnainmaa。芬兰人 Linnainmaa 在硕士论文里第一次描述了“在任意、离散、可能稀疏连接的类神经网络中,显式而高效的误差反向传播”——也就是反向模式自动微分。他的论文甚至附带了实现该方法的 FORTRAN 代码,后来于 1976 年发表在 BIT 期刊上2。Schmidhuber 据此主张,今天 TensorFlow 这类软件包所基于的,正是 Linnainmaa 1970 年的方法2

1974 / 1982 年,Paul Werbos。美国人 Werbos 在 1974 年的博士论文(5.5.1 节)里初步讨论了反向传播,但当时并未专门把它应用到神经网络上;按 Schmidhuber 的考据,首次把高效反向传播明确用于神经网络的,是 Werbos 1982 年一篇关于非线性敏感度分析的会议论文2。Werbos 的工作在当时几乎无人理会——那正是第一次 AI 寒冬,神经网络研究本就处于低潮,他这些后来被证明革命性的想法,在整个 1970 年代被学界基本忽略3

1986 年,Rumelhart、Hinton、Williams。这三人 1985 年对“已知的方法”做了实验分析,并于 1986 年在《自然》上发表《通过反向传播误差学习表示》(Learning representations by back-propagating errors)4。这篇论文的历史地位,不在于发明了算法(它甚至没有引用该方法的来源2),而在于令人信服地展示了反向传播能让多层网络的隐藏层自动学到有用的内部表示——它把一个被忽视的数学技巧,变成了一个能解决实际问题、能产生可解释中间特征的工具。这篇论文与 1980 年代神经网络研究的复苏同步,被引爆性地传播,把整个领域从寒冬里拉了出来35

Schmidhuber 对这段历史给出了一个值得记住的区分原则:发明一个重要方法的人,应当因发明而获得荣誉;她未必是让它流行起来的人,那么让它流行的人应当因普及而获得荣誉——但不是因发明2普及不等于发明。把反向传播简单说成“Hinton 发明的”,是把普及之功误记成了发明之功;而把它说成“Linnainmaa 一个人的”,又抹掉了 Werbos 首次用于神经网络、以及 RHW 让它真正可用并改变历史的贡献。三方各有其不可替代的位置。


把理论落到能跑的代码上。下面这段纯 NumPy 程序,训练一个 2-2-1 的小网络去学 XOR——正是上一章里单层感知机永远学不会的那个函数(完整文件 code/02_backprop_xor.py,可直接运行):

def sigmoid(z): return 1/(1+np.exp(-z))
def sigmoid_grad(a): return a*(1-a)        # 输入是激活值 a

for epoch in range(20000):
    # 前向
    a1 = sigmoid(X @ W1 + b1)              # 隐藏层
    a2 = sigmoid(a1 @ W2 + b2)             # 输出层
    # 反向(链式法则)
    dz2 = (a2 - Y) * sigmoid_grad(a2)      # 输出层误差信号 delta^(2)
    dW2 = a1.T @ dz2
    dz1 = (dz2 @ W2.T) * sigmoid_grad(a1)  # 反传到隐藏层 delta^(1)
    dW1 = X.T @ dz1
    # 梯度下降
    W2 -= lr*dW2; W1 -= lr*dW1; b2 -= lr*dz2.sum(0); b1 -= lr*dz1.sum(0)

代码里 dz1 = (dz2 @ W2.T) * sigmoid_grad(a1) 这一行,就是第三节那条反传递推 𝜹(1)=(W(2)𝜹(2))σ\boldsymbol{\delta}^{(1)} = (W^{(2)\top}\boldsymbol{\delta}^{(2)}) \odot \sigma' 的逐字翻译。运行结果是:

epoch     0  loss=0.27990
epoch 16000  loss=0.00017
最终预测 (应接近 0,1,1,0):
  XOR(0,0) -> 0.013   XOR(0,1) -> 0.989
  XOR(1,0) -> 0.989   XOR(1,1) -> 0.011

损失从 0.28 一路降到接近 0,四个 XOR 样本的预测分别收敛到 0、1、1、0。十七年前 Minsky 和 Papert 划下的那条“单层不可逾越”的线,被“多层 + 反向传播”干净地跨了过去。把第 01 章那段永不收敛的感知机日志,和这一段一路下降的 loss 并排放,就是神经网络从寒冬走向复兴的最小完整叙事。


理解反向传播,最好的图像是想象误差像水一样“倒流”。前向传播时,信号从输入流向输出,每一层做一次“加权求和 + 非线性”;反向传播时,误差从输出流回输入,每经过一层就被该层的权重转置 WW^\top 重新分配、再被该层激活函数的导数 σ\sigma' 调制一次。

前向:   x ──W1──► z1 ──σ──► a1 ──W2──► z2 ──σ──► ŷ ──► L(ŷ,y)
                                                          │
反向:  δ1 ◄─W2ᵀ── δ2 ◄────────────────────── ∂L/∂ŷ ◄──────┘
        │           │
       (×σ'(z1))   (×σ'(z2))
        │           │
     ∂L/∂W1      ∂L/∂W2     ← 每层用 δ 和前一层激活的外积得到权重梯度

配套的 manim 动画 assets/manim/ch02_backprop.pyBackprop Scene)把这件事演成几何:先看前向的值沿计算图从左流到右算出预测,再看误差从输出端逆着同一张图的边反向流回,每条边携带一个“局部梯度”,链式法则就是这些局部梯度沿路径逐边相乘、累积到每个参数上。一次前向加一次反向,就拿到了所有参数的梯度——这正是“误差倒流”的全部内容。

这个“误差倒流”的机制,从此成了几乎所有神经网络训练的引擎。但它也带着一个隐患——误差每反传一层,都要乘一次 WW^\top 和一次 σ\sigma'。如果这些乘子持续小于 1,误差信号在深层网络或长序列里会指数衰减到几乎为零,深处的层根本收不到有效的学习信号。这个被称为“梯度消失”的问题,将在 1991 年被一位叫 Hochreiter 的学生第一次形式化地剖开,并在很大程度上塑造了此后二十年神经网络架构的演化方向。那是关于循环网络与 LSTM 的故事。


本质

反向传播不是一个新算法,而是对一个老定理(链式法则)的一次极其高效的组织方式:它发现,只要按计算顺序的逆序走一遍,就能用一次遍历的代价算出损失对每一个参数的偏导,而不必对每个参数单独求一次导。它把“训练一个任意深的网络”从指数级的不可能,压缩成了与前向计算同量级的可行操作。多层之所以有用,也在这里第一次变得可操作——每一层都在把数据重新表示一次,把上一层里分不开的东西,变换成下一层里分得开的东西,而反向传播让这一连串变换能被同一个误差信号一致地调整。它的强大与它的脆弱同源:既然信号要沿着一长串乘法传播,那么这串乘子是大于一还是小于一,就决定了深层网络是能学还是学不动。


参考文献

  1. Cybenko, G. (1989) 对 sigmoid 激活的通用逼近证明;Hornik, K., Stinchcombe, M., & White, H. (1989/1991) 多层前馈网络是通用逼近器。综述:https://en.wikipedia.org/wiki/Universal_approximation_theorem ;Hornik et al. 原文 PDF(CMU 镜像):https://www.cs.cmu.edu/~epxing/Class/10715/reading/Kornick_et_al.pdf

  2. Schmidhuber, J. “Who Invented Backpropagation?”(含 Linnainmaa 1970 reverse-mode AD、FORTRAN 代码、1976 BIT 发表、Werbos 1982 首次 NN 应用、reverse-mode 效率性质、“发明 vs 普及”原则)。IDSIA:https://people.idsia.ch/~juergen/who-invented-backpropagation.html

  3. Backpropagation 历史综述(Werbos 1974 博论被寒冬忽视、1986 复兴)。Wikipedia:https://en.wikipedia.org/wiki/Backpropagation ;“The Backstory of Backpropagation”(二手史料梳理):https://yuxi-liu-wired.github.io/essays/posts/backstory-of-backpropagation/

  4. Rumelhart, D. E., Hinton, G. E., & Williams, R. J. (1986). Learning representations by back-propagating errors. Nature, 323, 533–536. https://www.nature.com/articles/323533a0

  5. 反向传播终结第一次寒冬的影响综述(RHW 1986 与 1980s 神经网络复兴)。Backpropagation Wikipedia(历史小节):https://en.wikipedia.org/wiki/Backpropagation

卷积网络:向视觉皮层借来的结构

把一张图片的每个像素都接到全连接网络的每个神经元上,参数会瞬间爆炸,而且模型学不会“猫挪到画面右边还是猫”这件最基本的事。卷积神经网络的全部聪明,在于把两条来自生物视觉的先验——局部感受野与平移不变——直接焊进网络结构里:用一个在整张图上滑动的小卷积核共享权重,既砍掉了天文数字的参数,又让“在哪儿”和“是什么”解耦。这一章讲清楚卷积这个算子的数学、它怎么从 Hubel 与 Wiesel 的猫脑实验一路长成 Fukushima 的 Neocognitron 和 LeCun 的 LeNet、以及“谁发明了 CNN”这个问题的两个源头。


先算一笔账,理解 CNN 要解决什么问题。一张 200×200 的灰度图有 4 万个像素。如果用上一章那种全连接网络,第一个隐藏层哪怕只有 1000 个神经元,光这一层就有 40000×1000=400040000 \times 1000 = 4000 万个权重。彩色图三通道再翻三倍。参数多到既算不动也学不好,而且会严重过拟合。

更深的问题是:全连接网络不理解图像的结构。对它来说,像素 (3,3) 和像素 (3,4) 是两个毫不相关的输入,和像素 (199,199) 没有任何区别。可图像不是这样的——相邻像素高度相关,一只猫无论出现在画面左上还是右下都还是一只猫。全连接网络要从零学会“空间局部性”和“平移不变性”这两件事,等于把人类视觉系统几亿年进化出的先验全部丢掉、让它重新发明。

卷积网络的思路是:不让模型从零学这些先验,而是把它们直接设计进网络的连接结构里。这两条先验,最早是从猫的大脑里看出来的。


1950 年代末到 1960 年代,神经生理学家 David Hubel 和 Torsten Wiesel 在猫的初级视觉皮层做了一系列后来获诺贝尔奖的实验。他们发现视觉皮层里的神经元有两个关键特征:第一,每个神经元只对视野中一小块区域(它的“感受野”)里的刺激有反应——这是局部感受野;第二,皮层里存在分工——“简单细胞”(simple cells)对特定朝向的边缘、线条敏感,而“复杂细胞”(complex cells)对同样的朝向敏感、但对刺激的精确位置有一定容忍,即便边缘稍微移动它仍然响应1

简单细胞负责“检测局部特征”,复杂细胞负责“对位置做一定的平移容忍”——把这两类细胞分层堆叠,就能从局部边缘逐步组合出更复杂、更有位置不变性的特征。这套生物结构,正是卷积网络的蓝本。

第一个把它搬进人工神经网络的,是日本计算机科学家 Kunihiko Fukushima。


1979/1980 年,Fukushima 在 NHK 广播科学技术研究所工作期间提出了 Neocognitron(新认知机)——一个分层多层的人工神经网络,直接用人工单元实现了 Hubel-Wiesel 的简单细胞与复杂细胞2。Neocognitron 交替堆叠两类层:S 层(对应简单细胞,做局部特征检测)和 C 层(对应复杂细胞,做下采样、提供平移容忍)。这个“特征检测 + 下采样”交替的骨架,几乎就是后来所有 CNN 的结构原型。

但 Neocognitron 有一个和那个时代相称的局限:它不用反向传播训练。在 Fukushima 设计它的时候,反向传播作为多层网络训练方法还没有被广泛知晓(参见上一章的优先权年表)。Neocognitron 用的是一种无监督的自组织学习方法2。结构对了,但缺少一个高效的、由任务目标驱动的训练引擎。

补上这块拼图的,是 Yann LeCun。


1989 年,当时在 AT&T 贝尔实验室的 Yann LeCun 发表了《反向传播应用于手写邮政编码识别》(Backpropagation applied to handwritten zip code recognition)3。这篇工作的历史意义在于:它第一次把反向传播用到了卷积结构上,并把这套学习方法数学形式化——既继承了 Neocognitron 的局部感受野与权重共享思想,又用上一章那个高效的梯度算法,让卷积核的权重能直接从带标签的数据里端到端地学出来,而不再依赖手工设计或无监督自组织34

到 1990 年代,LeCun 在 AT&T 的团队把这套架构发展成著名的 LeNet(最成熟的版本是 1998 年的 LeNet-5)。它在手写数字识别上达到了 99.3% 的准确率,并被实际部署用于自动读取美国 10–20% 的支票上的数字4。这是神经网络第一次大规模工业落地——不是 demo,是每天处理千万张真实支票的生产系统。

所以“谁发明了 CNN”这个问题,答案是分层的:Fukushima(1980)贡献了受生物启发的卷积式分层结构(局部感受野、特征检测与下采样交替),LeCun(1989)贡献了用反向传播端到端训练这种结构的方法、并将其数学形式化与工业化23。把 CNN 简单归给任何一方都不完整:没有 Fukushima 的结构,LeCun 的训练无处施加;没有 LeCun 的训练,Fukushima 的结构发挥不出威力。


现在把卷积这个核心算子的数学讲清楚。卷积层做的事,是用一个小小的卷积核(kernel,也叫 filter)在整张图上滑动,每滑到一个位置,就把核与其覆盖的图像块做逐元素相乘再求和,得到该位置的输出。对二维图像 IIkh×kwk_h \times k_w 的核 KK,输出特征图为

O[i,j]=u=0kh1v=0kw1I[i+u,j+v]K[u,v] O[i,j] = \sum_{u=0}^{k_h-1}\sum_{v=0}^{k_w-1} I[i+u,\, j+v]\,K[u,v]

(严格的数学卷积要把核翻转,工程实现里普遍用不翻转的“互相关”,因为核是学出来的,翻不翻转只是参数的镜像,对学习没有本质影响。)

这一个简单公式里藏着三个决定性的设计:

局部感受野:每个输出 O[i,j]O[i,j] 只看输入里一个 kh×kwk_h \times k_w 的小窗口,而不是整张图。这对应 Hubel-Wiesel 的局部感受野,也契合“图像里相邻像素才相关”的先验。

权重共享:同一个核 KK 在所有位置滑动时用的是同一组权重。这是参数量暴跌的关键——不管图多大,一个 3×33\times3 的核只有 9 个参数(外加一个偏置)。前面那个 4000 万参数的全连接层,换成若干个 3×33\times3 卷积核,参数量降到几百。权重共享还隐含了一个强假设:一个特征(比如竖直边缘)在图像任何位置都用同样的方式检测——这正是平移不变性的来源。

平移等变与不变:因为同一个核在每个位置都做同样的检测,当输入里的物体平移时,输出特征图里的响应也跟着平移(这叫平移等变);再叠加上池化(pooling,通常是取局部窗口的最大值),对小范围的位置变化产生容忍,逐步走向平移不变5。池化对应的正是 Hubel-Wiesel 的复杂细胞、Neocognitron 的 C 层。


用一段纯 NumPy 代码把这三件事一次看清(完整文件 code/03_convolution.py,可直接运行)。构造一张左暗右亮、中间有一条竖直边缘的小图,用 Sobel 竖直边缘核去卷它:

sobel_x = np.array([[-1,0,1],[-2,0,2],[-1,0,1]], dtype=float)
def conv2d(img, kernel):
    kh, kw = kernel.shape; H, W = img.shape
    out = np.zeros((H-kh+1, W-kw+1))
    for i in range(out.shape[0]):
        for j in range(out.shape[1]):
            out[i,j] = np.sum(img[i:i+kh, j:j+kw] * kernel)   # 局部相乘求和
    return out

运行结果:

输入图像 (左暗右亮):        卷积后 (竖直边缘响应):
[0 0 0 1 1 1]               [0 4 4 0]
[0 0 0 1 1 1]      ──►      [0 4 4 0]
...                          [0 4 4 0]

原图里 0/1 交界处(第 3 列附近),卷积输出冒出了大值 4——这个 Sobel 核检测到了竖直边缘,而在均匀区域(全 0 或全 1)输出为 0。这就是“局部特征检测”。

再看平移不变:把边缘右移一列,用同一个核

边缘右移后的卷积响应:
[0 0 4 4]   ← 同样的边缘模式,响应整体右移,核不变、检测能力不变

权重共享让同一个核在新位置自动检测出同样的边缘;池化(max_pool,代码里也实现了)再把局部最强响应保留下来、做下采样。一个核 9 个数,在整张图上反复使用——这就是 CNN 用极少参数捕捉视觉结构的全部秘密。真实的 CNN 只是把这件事堆叠很多层、每层很多个核:浅层的核学出边缘、纹理,中层组合成形状、部件,深层组合成“猫脸”“车轮”这样的语义概念。而且这些核不是手工设计的 Sobel,是反向传播从数据里自己学出来的——这正是 LeCun 1989 那一步的意义。


用一张结构图把 LeNet 式 CNN 的数据流钉住:

输入图像        卷积层(多核)        池化层         卷积层        池化       全连接      输出
 28x28x1  ──►  conv 3x3 ──► ReLU ──► maxpool ──► conv ──► ... ──► flatten ──► fc ──► softmax
              [边缘/纹理]   [非线性]  [下采样]   [部件]            [向量]          [10类概率]
   感受野: 小 ───────────────────────────────────────────────► 大
   语义:   像素/边缘 ──► 纹理 ──► 部件 ──► 物体
   空间分辨率: 高 ──────────────────────────────────► 低(被池化逐步压缩)
   通道数(特征种类): 少 ────────────────────────────► 多(每层学更多种特征)

这张图里有 CNN 设计哲学的全部:随着层数加深,空间分辨率被池化逐步压低,而特征通道数逐步升高——网络在用“放弃精确位置”换取“识别更抽象、更大范围的模式”。浅层每个神经元只看几个像素,深层每个神经元的有效感受野已经覆盖大半张图,能对应到“这是一只猫”这种全局判断。

配套的 manim 动画 assets/manim/ch03_cnn.pyConvolutionPooling 两个 Scene)把卷积的几何含义演出来:一个 3×3 的核在整张图上滑动,每滑到一处就做一次局部加权和、点亮特征图上对应的一个像素——核只有一份、复用到每个位置(权重共享),每次只看一小块(局部感受野);随后 Pooling 演示 2×2 取最大如何把分辨率减半、抽掉精确位置只留下“有没有、强不强”。

CNN 的结构在 1990 年代就基本定型,也在支票识别上证明了工业价值。但它随后陷入了一段相对沉寂——直到 2012 年,三个条件同时成熟:足够大的标注数据(ImageNet)、足够快的并行算力(GPU)、以及一组让深层网络真正训得动的工程技巧(ReLU、dropout)。这三者的合流,造就了一篇让整个领域瞬间转向的论文,AlexNet。那是引爆点的故事——但在讲它之前,得先处理另一条与图像平行的主线:当输入不是一张静止的图、而是一段会随时间展开的序列时,神经网络该怎么记住过去。那是循环网络与 LSTM。


本质

卷积网络的核心是把一条关于图像世界的先验知识直接焊进了网络结构里:一个特征(比如一条边)在图像的哪个位置出现,它的检测方式应该是一样的。基于这个假设,它用“同一个小核滑遍全图”取代了“每个位置一套独立权重”,于是参数量与图像大小脱钩、平移不变性被天然内建、局部感受野逐层堆叠成全局视野。它真正解决的问题不是“如何识别图像”,而是“如何在不靠海量数据死记硬背的前提下识别图像”——把本该由数据去学的不变性,改成由结构去保证。这也是它的代价所在:先验越强,能塞进去的灵活性就越少,这为后来“用更弱的结构先验加更大的数据/算力”的路线(如视觉 Transformer)埋下了张力。


参考文献

  1. Hubel, D. H., & Wiesel, T. N. 关于猫初级视觉皮层简单细胞/复杂细胞与局部感受野的发现(1959/1962),CNN 的生物学起源。综述见 Neocognitron 条目:https://en.wikipedia.org/wiki/Neocognitron

  2. Fukushima, K. (1980). Neocognitron: 受 Hubel-Wiesel 启发的分层多层网络,S 层/C 层交替,无监督自组织训练(非反向传播)。Wikipedia:https://en.wikipedia.org/wiki/Neocognitron

  3. LeCun, Y., et al. (1989). Backpropagation applied to handwritten zip code recognition. 首次将反向传播用于卷积结构。IEEE Milestone “Convolutional Neural Networks, 1989”:https://ethw.org/Milestones:Convolutional_Neural_Networks,_1989

  4. LeNet 谱系与 LeNet-5(1998)、手写数字 99.3%、用于读取美国 10–20% 支票(理论与实现综述)。Pablo Insente, “The Convolutional Network: LeNet-5 and AlexNet”:https://pabloinsente.github.io/the-convolutional-network

  5. 卷积、权重共享、池化与平移不变性的机制综述(教学材料)。ml4a “Convolutional neural networks”:https://ml4a.github.io/ml4a/convnets/

循环网络与 LSTM:给神经网络装上记忆

图像是静止的,可语言、语音、股价、传感器读数是随时间一个接一个到来的序列,理解第十个词常常要靠记得第一个词。循环神经网络通过一条把“上一刻的隐藏状态”喂回“这一刻”的回路,第一次让网络拥有了记忆。但这条回路有一个致命缺陷:误差沿时间反向传播时会指数级地消失或爆炸,使它根本记不住远处的信息。1991 年一篇硕士论文第一次把这个缺陷剖析清楚,1997 年的 LSTM 用一条“恒定误差传送带”加三道门把它修好。这一章讲清楚循环结构的数学、梯度为什么会消失、以及门控机制如何让记忆能跨越上百个时间步。


前面两章的网络都假设输入是一次性、固定大小的(一张图、一个向量)。但世界上大量数据是序列:一句话是词的序列,一段语音是声学帧的序列,一支股票是价格的序列。序列有两个特点让前馈网络无能为力——长度可变,且当前的理解依赖之前的内容。“他把行李放进了___”这个空,要填什么取决于前文。

循环神经网络(Recurrent Neural Network, RNN)的想法直截了当:给网络一个隐藏状态 𝒉t\mathbf{h}_t 当作“记忆”,每读入一个新元素 𝒙t\mathbf{x}_t,就用上一刻的记忆 𝒉t1\mathbf{h}_{t-1} 和当前输入一起算出新的记忆:

𝒉t=tanh(Whh𝒉t1+Wxh𝒙t+𝒃) \mathbf{h}_t = \tanh\!\left(W_{hh}\,\mathbf{h}_{t-1} + W_{xh}\,\mathbf{x}_t + \mathbf{b}\right)

𝒚t=Why𝒉t \mathbf{y}_t = W_{hy}\,\mathbf{h}_t

注意一个关键细节:每个时间步用的是同一组权重 Whh,WxhW_{hh}, W_{xh}——这和 CNN 的权重共享异曲同工,只不过 CNN 在空间上共享,RNN 在时间上共享。把这个循环按时间“展开”(unroll),它就变成一个深度等于序列长度的前馈网络:每个时间步是一层,层与层之间共享权重,记忆 𝒉\mathbf{h} 像一条河流从第一个时间步流到最后一个。

训练 RNN 用的还是反向传播,只不过要沿着时间轴反向传,叫随时间反向传播(Backpropagation Through Time, BPTT)。误差从最后一个时间步出发,沿着隐藏状态的链条一步步往回流。问题就出在这条往回流的链条上。


1991 年,Sepp Hochreiter 在他的硕士学位论文《动态神经网络研究》(Untersuchungen zu dynamischen neuronalen Netzen)里,第一次对一个困扰循环网络的现象给出了正式的数学分析。这就是后来被称为梯度消失问题(vanishing gradient problem)的东西,Schmidhuber 称之为“深度学习的根本问题”1

机制是这样的。误差沿时间反传时,从时间步 TT 传到时间步 tt,要连续乘过 (Tt)(T-t) 个雅可比矩阵——每跨一个时间步,梯度就要乘一次 WhhW_{hh}^\top,再乘一次激活函数的导数 tanh\tanh'。把这些乘子的“有效大小”记为 λ\lambda,那么传播 kk 个时间步后,梯度的量级大约正比于 λk\lambda^k

Hochreiter 证明的正是这一点:BPTT 的梯度会随跨越的时间步数(或层数)呈指数衰减12。Bengio 等人 1994 年也从另一个角度论证了用梯度方法学习长程依赖的根本困难。这个分析的杀伤力在于:它说明 RNN 记不住远处信息,不是没训练够,而是优化机制本身的数学性质决定的——就像第 01 章感知机学不会 XOR 是表达力的硬限制一样,这是训练动力学的硬限制。

把它跑出来看最直观(配套代码 code/04_lstm_cell.py):

乘子=0.6 [衰减]  T=5 步后梯度 ~ 7.8e-02   T=20 步 ~ 3.7e-05   T=50 步 ~ 8.1e-12
乘子=1.0 [临界]  T=5 ~ 1.0           T=50 ~ 1.0
乘子=1.3 [爆炸]  T=5 ~ 3.7           T=50 步后梯度 ~ 5.0e+05

乘子只要 0.6,传过 50 个时间步后梯度就只剩 8×10128\times10^{-12}——第一个词对第五十个词的训练信号,实际上等于零。这就是为什么朴素 RNN 记不住长句子的开头。


梯度爆炸相对好治——直接给梯度设一个上限“裁剪”(gradient clipping)即可。真正难的是梯度消失。Hochreiter 和他的导师 Schmidhuber 给出的解法,是 1997 年发表的长短期记忆网络(Long Short-Term Memory, LSTM)3

LSTM 的核心洞察可以一句话概括:与其让记忆每一步都被一个会衰减的乘法变换碾过,不如开辟一条让记忆能近乎无损地直接流过去的“高速公路”,再用几道闸门精确控制什么时候写入、什么时候擦除、什么时候读出。

这条高速公路就是 LSTM 引入的第二条状态——细胞状态(cell state)𝒄t\mathbf{c}_t,与隐藏状态 𝒉t\mathbf{h}_t 并行。Hochreiter 称这条让误差恒定流动的通路为恒定误差传送带(Constant Error Carousel, CEC)3。它的关键在于细胞状态的更新主要是加法而非反复的矩阵乘法——加法的梯度是 1,不会指数衰减,于是误差可以沿着细胞状态这条线几乎无衰减地传回很远的过去。

控制这条传送带的是三道门(gate),每道门都是一个取值在 0 到 1 之间的 sigmoid 输出,像阀门一样逐元素地调节信息流。记 𝒛t=[𝒉t1;𝒙t]\mathbf{z}_t = [\mathbf{h}_{t-1}; \mathbf{x}_t] 为上一刻隐藏状态与当前输入的拼接:

𝒇t=σ(Wf𝒛t+𝒃f)遗忘门:决定旧记忆擦掉多少 \mathbf{f}_t = \sigma(W_f \mathbf{z}_t + \mathbf{b}_f) \quad \text{遗忘门:决定旧记忆擦掉多少} 𝒊t=σ(Wi𝒛t+𝒃i)输入门:决定新信息写入多少 \mathbf{i}_t = \sigma(W_i \mathbf{z}_t + \mathbf{b}_i) \quad \text{输入门:决定新信息写入多少} 𝒄̃t=tanh(Wc𝒛t+𝒃c)候选记忆:本步想写入的内容 \tilde{\mathbf{c}}_t = \tanh(W_c \mathbf{z}_t + \mathbf{b}_c) \quad \text{候选记忆:本步想写入的内容} 𝒐t=σ(Wo𝒛t+𝒃o)输出门:决定记忆读出多少 \mathbf{o}_t = \sigma(W_o \mathbf{z}_t + \mathbf{b}_o) \quad \text{输出门:决定记忆读出多少}

细胞状态的更新——LSTM 的心脏:

𝒄t=𝒇t𝒄t1+𝒊t𝒄̃t \mathbf{c}_t = \mathbf{f}_t \odot \mathbf{c}_{t-1} + \mathbf{i}_t \odot \tilde{\mathbf{c}}_t

读这个式子:遗忘门 𝒇t\mathbf{f}_t 逐元素地决定旧细胞状态 𝒄t1\mathbf{c}_{t-1} 保留多少(接近 1 = 几乎全留,接近 0 = 擦除);输入门 𝒊t\mathbf{i}_t 决定候选记忆 𝒄̃t\tilde{\mathbf{c}}_t 写入多少。当遗忘门接近 1、输入门接近 0 时,𝒄t𝒄t1\mathbf{c}_t \approx \mathbf{c}_{t-1}——记忆原封不动地传到下一步,误差也就原封不动地传回上一步。这就是 CEC 让长程梯度存活的数学原因。

最后,隐藏状态(也是对外的输出)由输出门过滤后的细胞状态给出:

𝒉t=𝒐ttanh(𝒄t) \mathbf{h}_t = \mathbf{o}_t \odot \tanh(\mathbf{c}_t)


把一个 LSTM cell 跑起来,看门控如何工作(code/04_lstm_cell.py,可运行):

def lstm_step(x, h_prev, c_prev, Wf, Wi, Wc, Wo, bf, bi, bc, bo):
    z = np.concatenate([h_prev, x])
    f = sigmoid(Wf @ z + bf)            # 遗忘门
    i = sigmoid(Wi @ z + bi)            # 输入门
    g = np.tanh(Wc @ z + bc)           # 候选记忆
    o = sigmoid(Wo @ z + bo)            # 输出门
    c = f * c_prev + i * g             # 细胞状态:门控加法更新(CEC)
    h = o * np.tanh(c)
    return h, c

一个常用且重要的工程技巧体现在初始化里:遗忘门的偏置 𝒃f\mathbf{b}_f 初始化为正值(代码里设为 1)。这让训练初期遗忘门默认接近 1,即默认“记住一切”——给梯度一条畅通的传送带先用着,再让网络慢慢学会该忘什么。运行可以看到,三道门的开合随输入变化,细胞状态 𝒄\mathbf{c} 沿时间累积演化,而不是被反复碾平。

g * i(候选记忆乘输入门)这一项用 tanh\tanh 而非 sigmoid,是因为写入细胞的内容需要有正有负(增减记忆),而门控阀门需要的是 0 到 1 的“开合比例”,所以用 sigmoid。每个非线性的选择都对应一个明确的语义角色——这是 LSTM 设计的精巧之处。


LSTM 的影响怎么强调都不为过。1997 年发表后,它一度并不显眼,但随着 2000 年代中期在多项序列预测竞赛中夺冠,它逐渐成为序列学习的主力架构。从 2011 年到 2017 年 Transformer 崛起之前,LSTM 几乎是序列建模的默认选择——语音识别、手写识别、机器翻译、语言建模,背后大多是 LSTM 或它的变体4。谷歌的语音转写、苹果的 Siri、机器翻译系统,都曾建立在 LSTM 之上。

2014 年 Cho 等人提出的门控循环单元(GRU)是 LSTM 的一个简化:把遗忘门和输入门合并成一个“更新门”,去掉独立的细胞状态,参数更少、训练更快,性能在很多任务上与 LSTM 相当。LSTM 和 GRU 一起,构成了“门控循环网络”这个大家族。


用一张图把“朴素 RNN 为什么记不住、LSTM 为什么记得住”并排钉死:

朴素 RNN(记忆每步被矩阵乘碾过,梯度 ~ λ^k 指数衰减):
  h0 ─×W─► h1 ─×W─► h2 ─×W─► ... ─×W─► hT
  ↑ 误差反传时每步乘 W·tanh',|λ|<1 则到 h0 时已衰减为 ~0

LSTM(细胞状态走加法高速路 CEC,遗忘门≈1 时梯度≈1 不衰减):
  c0 ──+──► c1 ──+──► c2 ──+──► ... ──+──► cT     ← 加法通路:梯度恒定
        ↑f,i      ↑f,i      ↑f,i              (门只调节流量,不反复相乘碾压)
  h0        h1        h2                  hT

配套的 manim 动画 assets/manim/ch04_rnn_lstm.pyVanishingGradientLSTMConveyor 两个 Scene)把两件事演成几何:前者把 RNN 沿时间展开成一条链,反向梯度每过一步乘一个小于 1 的因子,脉冲一路指数衰减,远处时间步的梯度归零——这就是“学不到长程依赖”;后者把 LSTM 的细胞态画成一条信息几乎无损直线流过的“传送带”(CEC),三个门像阀门,控制往传送带上加什么、删什么、读什么。门控让网络学会了“在正确的时刻记住正确的东西”。

LSTM 解决了“记忆能否跨越长距离”的问题,但它仍有一个结构性的代价:序列必须一步接一步顺序处理,第 tt 步必须等第 t1t-1 步算完。这在 GPU 这种大规模并行硬件上是巨大的浪费,也限制了它能处理的序列长度和训练速度。如何既能建模长程依赖、又能并行计算?答案是把“循环”彻底扔掉、改用一种叫“注意力”的机制让每个位置直接看到所有其他位置。但在抵达那个答案(Transformer)之前,得先看注意力是怎么在机器翻译里作为 RNN 的一个补丁被发明出来的——以及在此之前,词本身是怎么被变成向量的。那是 word2vec 与 seq2seq 的故事。


本质

梯度消失的根源是一个朴素的数学事实:信息沿时间反传时要连乘许多个因子,而连乘的东西若不恰好等于 1,就只会爆炸或归零。LSTM 的精妙之处不是“加了门”,而是它在网络里专门修了一条让梯度可以等于 1 地直线流过的通道——细胞态这条传送带上的信息默认原样保留(加法更新而非反复相乘),于是误差能跨越几百个时间步而不衰减;门只是叠加在这条通道上、决定何时往里写、何时清空、何时读出的旁路。它真正解决的,是“如何让记忆的保持成为默认、让遗忘成为需要主动触发的选择”。这个“默认直通、旁路调节”的思想,后来以残差连接的形式回到了前馈网络,也是一切深层结构能被训练的共同密码。


参考文献

  1. Hochreiter, S. (1991). Untersuchungen zu dynamischen neuronalen Netzen(硕士论文,首次形式分析梯度消失,BPTT 梯度指数衰减)。Schmidhuber, “Sepp Hochreiter’s Fundamental Deep Learning Problem (1991)”:https://people.idsia.ch/~juergen/fundamentaldeeplearningproblem.html

  2. 梯度消失问题机制综述(连乘雅可比、λ^k 指数衰减、与 Bengio 1994 的关系)。Vanishing gradient problem, Wikipedia:https://en.wikipedia.org/wiki/Vanishing_gradient_problem

  3. Hochreiter, S., & Schmidhuber, J. (1997). Long Short-Term Memory. Neural Computation, 9(8), 1735–1780. 恒定误差传送带(CEC)与输入/遗忘/输出门。原文(ResearchGate):https://www.researchgate.net/publication/13853244_Long_Short-Term_Memory

  4. LSTM 架构、门控数学与历史影响(2011–2017 序列建模主力、GRU 变体)综述。LSTM, Wikipedia:https://en.wikipedia.org/wiki/Long_short-term_memory ;教科书级推导:Dive into Deep Learning, “Long Short-Term Memory (LSTM)”:http://d2l.ai/chapter_recurrent-modern/lstm.html

AlexNet 与认猫:数据与算力的合流

反向传播 1986 年就有了,卷积网络 1989 年就能读支票了,为什么深度学习的“引爆”要等到 2012 年?答案不在算法,在两条非算法的暗线越过了临界点:一个由百万张标注图像组成的数据集,和一块本来用来打游戏的并行计算芯片。2012 年同一年里发生了两件事——Google Brain 用一千台机器让神经网络在没有任何标签的情况下自己长出了一个“猫脸神经元”,AlexNet 用两块游戏显卡把 ImageNet 竞赛的错误率砍掉了近十个百分点。这一章讲清楚这两件事各自做了什么、为什么是数据和算力而非新算法点燃了这场革命、以及它们背后的技术细节。


先把一个反常识的事实摆出来:让 2012 年深度学习引爆的那些核心算法,没有一个是 2012 年发明的。卷积来自 Fukushima 1980 和 LeCun 1989,反向传播来自 1970–1986,ReLU、dropout 这些技巧也都早有雏形。如果算法早就齐备,为什么 CNN 在 1990 年代读完支票之后,沉寂了将近二十年?

因为神经网络是一种对数据量算力都极度饥渴的方法。一个深层网络有几千万个参数,要把它们训练好而不过拟合,需要海量的标注样本;而在这么多样本上跑成千上万次前向-反向传播,需要巨大的计算吞吐。1990 年代两者都不具备:公开的标注数据集只有几万张小图,CPU 的算力训练一个稍大的网络要花几周。于是即便算法正确,深度网络也“训不动、喂不饱”。

转折点是这两条暗线在 2009–2012 年间几乎同时越过了临界。数据这一边,是 2009 年由李飞飞团队推动的 ImageNet——一个基于 WordNet 语义结构、规模空前的层级化标注图像数据库1。它配套的年度竞赛 ILSVRC(ImageNet 大规模视觉识别挑战赛)提供了一个公开、统一、足够难的擂台。算力这一边,是 GPU——图形处理器本为并行渲染像素而生,恰好天然适合神经网络里大量并行的矩阵乘法。当足够大的数据遇上足够快的并行算力,那些早已存在的算法,终于第一次有了施展的舞台。

2012 年,这个舞台上同时上演了两出戏。


第一出来自 Google Brain。2012 年,Quoc Le、Andrew Ng、Jeff Dean 等人发表了《用大规模无监督学习构建高层特征》2。这项工作后来因为《纽约时报》记者 John Markoff 一篇题为《要识别一只猫需要多少台计算机?16000 台》的报道而广为人知,俗称“Google 认猫”3

它的设定极端而朴素。研究者搭了一个 9 层的局部连接稀疏自编码器(locally connected sparse autoencoder),带池化和局部对比归一化,总共约 10 亿个连接2。喂给它的是从互联网上下载的 1000 万张 200×200 的图像——全部来自 YouTube 视频截帧,没有任何标签。训练用了 1000 台机器、16000 个核心,跑了三天,靠模型并行和异步随机梯度下降23

自编码器的任务很简单:把输入压缩成一个低维表示,再尽量重建回原图。重点是它完全无监督——没人告诉它什么是猫、什么是脸。训练完之后,研究者检查网络高层的单个神经元,发现了一个惊人的现象:存在某个神经元,专门对“猫脸”强烈响应;还有神经元对人脸、人体响应2。换句话说,仅仅通过“看了一千万张网络图片并试图重建它们”,网络自己涌现出了“猫”这个高层概念的检测器,而且这个检测器对平移、缩放、甚至平面外旋转都鲁棒2

这件事的意义是双重的。技术上,它证明了高层语义特征可以从纯无监督学习中浮现——不必逐张标注“这是猫”也能学出猫检测器,论文当时还用学到的特征在 ImageNet 的 2 万类识别上相对此前最佳水平取得了约 70% 的相对提升2。象征上,“机器自己从海量数据里发现了猫”这个画面,第一次让深度学习的力量进入了公众视野——它把一个技术进展变成了一个文化时刻。而它依赖的,正是那条算力暗线:16000 个核心、三天,这是 1990 年代不可想象的规模。


第二出,也是技术上更具决定性的一出,来自多伦多大学的一间卧室。

2012 年,Alex Krizhevsky、Ilya Sutskever 和 Geoffrey Hinton 以“SuperVision”为队名,向 ILSVRC-2012 竞赛提交了一个深度卷积网络,后世称之为 AlexNet4。结果是碾压性的:它把 ImageNet 分类任务的 top-5 错误率从此前最佳的 26.2% 一举降到 15.3%——近 11 个百分点的鸿沟,在那之前每年的进步都是以零点几个百分点计的45。这个断崖式的领先,让整个计算机视觉界在几个月内集体转向深度学习。

AlexNet 的网络本身是一个“加大加深的 LeNet”:5 个卷积层(部分后接最大池化),3 个全连接层,最后一个 1000 路 softmax 输出,总共约 6000 万个参数、65 万个神经元4。结构上是 CNN 的延续,但有几个让它“训得动、训得好”的关键工程选择:

把这些列出来就能看清 AlexNet 的本质:它不是一个算法发明,而是一次集成与规模化——把已有的卷积、反向传播、ReLU、dropout 拼到一起,用 GPU 在 ImageNet 这个足够大的数据集上推到了一个前所未有的规模,然后让结果自己说话。


为什么 GPU 这么关键,值得单独讲清楚,因为它是理解整个深度学习时代的钥匙。

神经网络的前向和反向传播,绝大部分计算是矩阵乘法:一层的输出是权重矩阵乘以输入向量(或一批输入组成的矩阵)。矩阵乘法的特点是高度并行——结果矩阵的每个元素都是一次独立的点积,互不依赖,可以同时算。

CPU 的设计哲学是“少数几个非常强的核心,擅长复杂的串行逻辑”,一般几个到几十个核。GPU 的设计哲学正相反:“成千上万个简单的核心,擅长同时做大量相同的简单运算”——因为它原本的工作是同时计算屏幕上几百万个像素的颜色。这种“大量并行的简单算术”恰好就是矩阵乘法需要的。在 GPU 上训练神经网络,相比 CPU 能快几十倍。

可以用第 02 章那个梯度下降的内循环来体会:每一步训练都要对一整批样本做前向矩阵乘、反向矩阵乘,成千上万步。CPU 一次只能算几个点积,GPU 一次能算几千个。AlexNet 在两块 GTX 580 上训练了大约六天——同样的工作放在当时的 CPU 上要花几个月甚至更久,根本不现实。GPU 把“训一个大网络”从科幻变成了一个研究生在卧室里几天能干完的事。从此,深度学习的进步速度在很大程度上被算力的增长速度所牵引,这条线一直延伸到后来的 TPU、千卡万卡集群,以及大模型时代的“scaling”。


把 AlexNet 的结构和数据流用一张图钉住,并标出“数据+算力”这条暗线如何贯穿其中:

ImageNet 1.2M 张标注图 (数据暗线: 2009 李飞飞)
        │
        ▼  随机裁剪/翻转/颜色扰动 (数据增强 → 等效放大数据集)
   227x227x3
        │
   ┌────┴─────────────────────────────────────────────┐
   │ conv1 11x11 ─ReLU─ maxpool ─► conv2 ─► ... ─► conv5 │  ← 5 卷积层
   │ (拆到 2 块 GTX580 上并行)  (算力暗线: 2012 GPU)      │
   └────┬─────────────────────────────────────────────┘
        ▼ flatten
   fc6 ─dropout─► fc7 ─dropout─► fc8 ─► softmax(1000类)
   (6000 万参数; dropout 防过拟合)
        │
        ▼
   top-5 error 26.2% → 15.3%   ← 引爆点

配套的 manim 动画 assets/manim/ch05_alexnet.pyFeaturePyramid Scene)把深层 CNN 的“层级特征金字塔”演出来:边缘 → 纹理 → 部件(眼、耳)→ 物体(猫),每深一层,空间分辨率缩小、语义更抽象,“猫”不是一步认出的,而是局部一层层拼成整体的;同时两根点火轴——数据(ImageNet 120 万张)× 算力(GPU)——在画面里合流,对应 2012 年的引爆。AlexNet 第一层学到的核几乎和第 03 章手设的 Sobel 核同构,只不过这些是网络从真实图片里自己学出来的——浅层确实在做和生物视觉皮层简单细胞一样的事。


把 2012 这一年放回整条主线里看,它的位置非常清楚。从感知机到反向传播,神经网络解决了“能不能学”;从 CNN 到 LSTM,它解决了“能不能把结构先验(空间、时间)编进网络”;而 2012 年解决的是“能不能在足够大的规模上把前面这些真正跑起来”——答案由数据(ImageNet)和算力(GPU)共同给出。

这也解释了一个常被误解的因果:深度学习革命常被叙述成“某个聪明算法的胜利”,但更准确的图景是一次规模的胜利。Google 认猫和 AlexNet 用的核心机制都不新,新的是它们敢于、且终于能够把网络和数据推到前所未有的规模,然后发现——在足够大的规模上,旧方法会涌现出全新的能力(无监督涌现猫神经元、监督下断崖式的精度跃迁)。“规模本身会带来质变”,这个在 2012 年初次显形的直觉,后来被 GPT 系列推到极致,并被正式写成了“scaling laws”。

但在抵达大模型与 scaling laws 之前,主线要先回到语言。图像的胜利证明了深度网络的威力,可语言有它自己的难题:词不是像素,它没有天然的数值表示;句子是变长的序列,意义依赖语序和上下文。如何把“词”变成神经网络能处理的向量,又如何把一串词映射成另一串词(比如翻译)?这两个问题的答案——word2vec 与 seq2seq——把深度学习的战火从视觉烧向了语言,并直接催生了注意力机制。那是下一章。


本质

2012 年发生的不是一次算法突破,而是一次相变。AlexNet 与“认猫”用的机制——卷积、反向传播、梯度下降——在 1990 年代就已齐备;真正改变的是规模:足够大的标注数据让网络有东西可学,足够快的并行算力让深网络第一次能在合理时间里训到收敛。当这两根轴同时到位,旧方法在新规模上涌现出旧规模下根本看不到的能力。这一章真正确立的,是此后整个领域的隐性信条——许多看似需要更聪明算法才能解决的问题,其实是规模不够;把同样的方法推到足够大,质变会自己发生。这个直觉在这里第一次显形,十年后被 GPT 系列推到极致,并被正式写成“scaling laws”。

参考文献

  1. Deng, J., Dong, W., Socher, R., Li, L.-J., Li, K., & Fei-Fei, L. (2009). ImageNet: A Large-Scale Hierarchical Image Database. IEEE CVPR 2009. 基于 WordNet 的大规模层级图像数据库。引用记录:https://www.scirp.org/reference/referencespapers?referenceid=2859779 ;Princeton 出版页:https://collaborate.princeton.edu/en/publications/imagenet-a-large-scale-hierarchical-image-database/

  2. Le, Q. V., Ranzato, M., Monga, R., Devin, M., Chen, K., Corrado, G. S., Dean, J., & Ng, A. Y. (2012). Building high-level features using large scale unsupervised learning. ICML 2012. 9 层稀疏自编码器、10 亿连接、1000 万张图、1000 机 16000 核 3 天、涌现猫脸/人脸神经元、ImageNet 2 万类相对提升 70%。arXiv:https://arxiv.org/abs/1112.6209

  3. Markoff, J. “How Many Computers to Identify a Cat? 16,000.”(《纽约时报》报道,公众认知引爆)。History of Information 收录:https://www.historyofinformation.com/detail.php?id=3913

  4. Krizhevsky, A., Sutskever, I., & Hinton, G. E. (2012). ImageNet Classification with Deep Convolutional Neural Networks. NeurIPS 2012. 6000 万参数、5 conv+3 fc、2× GTX580、ReLU/dropout/GPU 卷积。NeurIPS 论文页:https://papers.nips.cc/paper/4824-imagenet-classification-with-deep-convolutional-neural-networks ;原文 PDF:https://courses.csail.mit.edu/6.803/pdf/2012%20hinton.pdf

  5. AlexNet 综述与影响(top-5 26.2%→15.3%、SuperVision 队、对计算机视觉的转向)。AlexNet Wikipedia:https://en.wikipedia.org/wiki/AlexNet ;IEEE Spectrum, “How AlexNet Transformed AI and Computer Vision Forever”:https://spectrum.ieee.org/alexnet-source-code

word2vec:把词变成几何

神经网络只会算数,可词是符号——“猫”和“狗”对它来说不过是两个无意义的编号。怎么让模型知道猫和狗很像、巴黎之于法国正如东京之于日本?2013 年的 word2vec 给出一个朴素到惊人的答案:让模型反复做一个填空游戏——根据一个词去猜它周围会出现哪些词。仅仅这个训练目标,就足以把每个词压进一个几百维的连续向量,使得语义相近的词在这个空间里彼此靠近,甚至让“国王−男人+女人≈王后”这样的类比变成纯粹的向量加减。这一章讲清楚 word2vec 的两种结构、它的训练数学、负采样这个让它跑得飞快的技巧、以及“词向量的平行四边形”背后的几何。


图像天生是数值的——每个像素就是一个亮度值,CNN 可以直接吃。语言不是。一个词是一个离散符号,“国王”和“王后”在计算机里最朴素的表示是两个独立的编号,或者两个独热向量(one-hot):词表里第 ii 个词,就是一个除了第 ii 位是 1、其余全是 0 的长向量。

独热表示有两个致命问题。第一是维度灾难:词表动辄几十万词,每个词就是一个几十万维、几乎全是 0 的稀疏向量。第二、也是更根本的——任意两个不同词的独热向量都是正交的,相似度恒为零。“猫”和“狗”的距离,与“猫”和“民主”的距离,在独热空间里一模一样。这个表示里没有任何语义结构,神经网络拿到它等于拿到一堆毫无关系的编号。

我们真正想要的,是一种分布式表示(distributed representation):用一个稠密的低维向量(比如 200 维实数)表示每个词,让向量之间的几何关系编码语义关系——相似的词向量相近,相关的词在某些方向上对齐。问题是,这样的向量从哪来?word2vec 的答案根植于一个古老的语言学直觉。


这个直觉叫分布假说(distributional hypothesis),常被概括成 J.R. Firth 1957 年的一句话:“你可以通过一个词的同伴来认识它。”(You shall know a word by the company it keeps.)意思是:一个词的意义,很大程度上由它经常和哪些词一起出现来决定。“咖啡”和“茶”意思相近,因为它们出现的上下文高度重叠——“喝一杯___”“___加糖”“早上来杯___”。如果两个词总在相似的语境里出现,它们的意义就相近。

word2vec 把这个语言学假说变成了一个自监督的预测任务:不需要任何人工标注,只用海量原始文本,让模型反复练习“根据上下文猜词”或“根据词猜上下文”,在练习中把词的意义压进向量。2013 年,Google 的 Tomáš Mikolov 等人在《在向量空间中高效估计词表示》里提出了两种具体做法1

CBOW(连续词袋):给定一个词周围的上下文词,预测中间这个词。比如看到“喝一杯 ___ 加糖”,预测中间是“咖啡”。

Skip-gram:反过来,给定中间这个词,预测它周围会出现哪些上下文词。给“咖啡”,预测它周围可能有“喝”“杯”“糖”。

两者是镜像关系。Skip-gram 在罕见词上表现更好、更常用,下面以它为主讲数学。


Skip-gram 的结构异常简单——简单到它其实只是一个没有隐藏层非线性的“浅”网络。模型给每个词配两个向量:当它作中心词时用的向量 𝒗w\mathbf{v}_w(输入向量),当它作上下文词时用的向量 𝒖w\mathbf{u}_w(输出向量)。

给定中心词 cc 和一个上下文词 oo,模型用两个向量的点积衡量“oo 出现在 cc 周围的可能性”,并通过 softmax 归一化成一个概率分布:

P(oc)=exp(𝒖o𝒗c)w=1Vexp(𝒖w𝒗c) P(o \mid c) = \frac{\exp(\mathbf{u}_o^\top \mathbf{v}_c)}{\sum_{w=1}^{V} \exp(\mathbf{u}_w^\top \mathbf{v}_c)}

分子是中心词向量和真实上下文词向量的点积(越对齐、点积越大、概率越高),分母对整个词表 VV 个词求和做归一化。训练目标是最大化所有真实出现的“中心词-上下文词”对的对数概率,等价于最小化负对数似然:

L=(c,o)logP(oc) L = -\sum_{(c,o)} \log P(o \mid c)

用第 02 章的反向传播对 𝒗c\mathbf{v}_c𝒖w\mathbf{u}_w 求梯度、做梯度下降即可。softmax + 交叉熵的梯度有一个干净的形式:对得分向量的梯度是“预测分布减去真实的独热目标”𝒑𝒆o\mathbf{p} - \mathbf{e}_o。直觉是:把真实上下文词的向量往中心词向量拉近,把所有其他词的向量推远一点。反复在海量文本上做这件事,几何结构就慢慢浮现了。


上面那个 softmax 有个要命的代价:分母要对整个词表求和。词表几十万词,每处理一个训练对就要算几十万次点积——而语料里有几十亿个训练对。直接算,根本跑不动。

word2vec 能在 2013 年用普通机器在十亿级语料上训练,靠的是一个关键加速技巧:负采样(negative sampling)。它的思想是把“在整个词表上做多分类”换成“做若干个二分类”。对每个真实的(中心词,上下文词)正样本对,随机从词表里采样少数几个(通常 5–20 个)词作为“负样本”,然后只要求模型:把正样本对的点积推高(判为“真的是上下文”),把这几个负样本对的点积压低(判为“不是上下文”)。目标函数变成

logσ(𝒖o𝒗c)+k=1K𝔼wkPn[logσ(𝒖wk𝒗c)] \log \sigma(\mathbf{u}_o^\top \mathbf{v}_c) + \sum_{k=1}^{K} \mathbb{E}_{w_k \sim P_n}\big[\log \sigma(-\mathbf{u}_{w_k}^\top \mathbf{v}_c)\big]

其中 σ\sigma 是 sigmoid,PnP_n 是负采样分布(实践中用词频的 3/4 次方,让高频词稍微少采、低频词稍微多采)。这样每个训练对只需算 1+K1 + K 次点积(比如 6 次),而不是几十万次。负采样把训练复杂度从“正比于词表大小”降到“正比于一个小常数”,这是 word2vec 实用化的工程关键。


word2vec 真正让世界惊艳的,是训练完之后词向量空间里浮现的几何规律。最著名的例子是线性类比:

𝒗king𝒗man+𝒗woman𝒗queen \mathbf{v}_{\text{king}} - \mathbf{v}_{\text{man}} + \mathbf{v}_{\text{woman}} \approx \mathbf{v}_{\text{queen}}

也就是说,“从国王到王后”的向量变化,和“从男人到女人”的向量变化几乎相同——“性别”这个语义维度,被编码成了向量空间里一个稳定的方向2。同样,𝒗Paris𝒗France+𝒗Italy𝒗Rome\mathbf{v}_{\text{Paris}} - \mathbf{v}_{\text{France}} + \mathbf{v}_{\text{Italy}} \approx \mathbf{v}_{\text{Rome}}——“首都”也是一个方向。这些类比可以画成平行四边形:king、man、woman、queen 四个点构成一个近似的平行四边形,对边平行且等长。

为什么填空游戏能学出这种结构?直觉是:语义关系会系统性地体现在共现统计里。“国王”和“男人”共享一批上下文(强壮、权力、他),“王后”和“女人”共享另一批(优雅、她),而“国王↔︎王后”和“男人↔︎女人”之间的上下文差异是同一种差异(性别相关的词)。当模型把这些共现规律压进低维向量时,这种“同一种差异”就自然对齐成了空间里的同一个方向。这不是被显式设计进去的,是从预测任务里涌现出来的——和第 05 章 Google 认猫里“猫神经元”的涌现是同一类现象:足够多的数据 + 一个简单的自监督目标,结构自己长出来。


用一段纯 NumPy 的迷你 skip-gram 把机制跑出来(完整文件 code/06_word2vec.py,可运行)。核心训练循环就是第三节那个 softmax-交叉熵的直接翻译:

for c, o in pairs:                  # (中心词, 上下文词)
    h = Win[c]                      # 中心词向量 v_c
    p = softmax(Wout @ h)           # P(·|c),对每个词的概率
    dscores = p.copy(); dscores[o] -= 1   # softmax+CE 梯度 = p - e_o
    Win[c]  -= lr * (Wout.T @ dscores)    # 拉近真实上下文,推远其他
    Wout    -= lr * np.outer(dscores, h)

在一个刻意构造的玩具语料(让 king/queen/man/woman 等词在 royal、human 等语境里共现)上训练后,近邻结构清晰浮现:

与 'woman' 最近:  princess(0.36), girl(0.25), man(0.20)
与 'king' 最近:   palace(0.21), princess(0.11), royal(0.11)
类比 king-man+woman 的近邻:  princess(0.67), palace(0.18), ...

“woman”的近邻是 princess、girl 这些语义相关词;“king−man+woman”这个类比向量落在了 princess(皇室+女性)附近。需要诚实说明:这个十几个词的玩具语料噪声很大,无法稳定复现教科书里那个干净的“queen”——线性类比的平行四边形是大规模训练(数十亿词)才稳定涌现的统计性质,玩具语料只能展示“语义相关词向量彼此靠近”这个更基本的机制。但即便在这么小的语料上,“分布假说→共现→几何”这条因果链已经看得见:模型确实把“皇室”“性别”这些语义压成了空间里的邻近与方向。


用一张图把词向量空间的几何钉住——这是 word2vec 最具标志性的可视化:

   语义空间(降到 2 维示意,真实是 200~300 维)

   queen  ●- - - - - - - - ●  king        ↑ "皇室"方向
          │                │
          │  (性别方向 →)   │
          │                │
   woman  ●- - - - - - - - ●  man

   平行四边形:  king - man ≈ queen - woman
              => king - man + woman ≈ queen

   另一组:  Rome - Italy ≈ Paris - France   ("首都"方向)

配套的 manim 动画 assets/manim/ch06_word2vec.pyParallelogram Scene)把这件事降到二维演出来:man、king、woman、queen 四个词作为平面上的点,构成一个近似平行四边形——“王权方向”(man→king 与 woman→queen)彼此平行,“性别方向”(man→woman 与 king→queen)也彼此平行,于是 king − man + woman 这个向量算术的落点恰好压在 queen 上。在真实语料训练出的 word2vec 上,这些平行四边形干净得令人吃惊——这正是它当年引发轰动的原因:意义,竟然可以是几何。

word2vec 的影响远超它本身。它确立了一个范式:用自监督的预测任务,从无标注文本里学出可迁移的稠密表示。这个范式后来被层层放大——从静态词向量(每个词一个固定向量)到上下文相关的词表示(同一个词在不同句子里有不同向量),再到 BERT、GPT 这种“整个模型就是一个巨大的、上下文敏感的表示器”。word2vec 是这条路的起点。

但 word2vec 只给了“词”的向量,它不处理“词的顺序”和“整句到整句的映射”。翻译一句话、回答一个问题,需要把一个变长序列映射成另一个变长序列。这个问题催生了 seq2seq 编码器-解码器架构,而 seq2seq 的一个致命瓶颈,又直接逼出了那个将要改变一切的机制——注意力。那是下一章。


本质

word2vec 把一句很旧的语言学直觉——“一个词的意义由它周围的词决定”——变成了一个可优化的几何目标:让经常共现的词在向量空间里彼此靠近。它真正的发现不是“词能变成向量”,而是当你只要求模型“根据上下文预测词”时,语义关系会作为副产品自动沉淀成空间里的方向:性别是一个方向、单复数是一个方向、首都与国家的关系是一个方向,于是意义的加减变成了向量的加减。这背后是一个会反复出现的母题——不必显式地教模型“什么是语义”,只要给它一个足够好的自监督预测任务和足够多的文本,结构会自己浮现。这正是后来 BERT、GPT 的全部出发点:把这个“预测周围”的任务,从一个词放大到整段上下文。


参考文献

  1. Mikolov, T., Chen, K., Corrado, G., & Dean, J. (2013). Efficient Estimation of Word Representations in Vector Space. CBOW 与 Skip-gram、负采样、连续向量空间。arXiv:https://arxiv.org/abs/1301.3781 ;PDF:https://arxiv.org/pdf/1301.3781

  2. word2vec 综述:线性类比(king−man+woman≈queen)、分布假说、负采样与训练机制。Word2vec, Wikipedia:https://en.wikipedia.org/wiki/Word2vec

seq2seq 与注意力:打破固定向量的瓶颈

把一句英文翻译成法文,是把一个变长序列映射成另一个变长序列。2014 年的 seq2seq 用两个 LSTM 优雅地做到了这件事:一个把整句话读进一个向量,另一个再把这个向量解码成译文。但这个设计有个致命的瓶颈——无论原句多长,全部信息都要被压进同一个固定大小的向量,长句子一压就丢。同一年,另一组研究者给这个瓶颈打了一个补丁:让解码器在生成每个词时,回头去“看”原句的所有位置,自动找出此刻最该关注哪几个词。这个补丁叫注意力,它本是机器翻译里的一个工程修补,三年后却长成了取代整个循环结构的主角。这一章讲清楚 seq2seq 的编码-解码、固定向量瓶颈的数学根源、以及注意力如何用一个加权平均解决它。


第 04 章的 RNN/LSTM 能处理序列,但它最自然的输出是“每个输入位置对应一个输出”——比如给每个词标词性。可很多任务不是这样的:机器翻译里,源句和目标句长度不同、语序不同,“我爱你”三个字翻成英文是“I love you”也是三个词,但“我昨天吃了饭”和它的英译词数、语序都对不上。这类任务需要把整个输入序列读完、理解,再从头生成一个长度可变的输出序列。

2014 年,Google 的 Ilya Sutskever、Oriol Vinyals 和 Quoc Le 提出了 sequence-to-sequence(seq2seq) 架构,给出了一个干净的通用解1。它由两个 LSTM 组成:

训练时用源句-目标句对,让解码器在每一步预测正确的下一个词(softmax over 词表 + 交叉熵),用反向传播端到端优化两个 LSTM。这个架构第一次证明了纯神经网络可以做出可用的机器翻译,是 NLP 从“流水线 + 人工特征”转向“端到端神经网络”的关键一步1

但它有一个结构性的隐患,藏在那个“固定维度向量 𝒄\mathbf{c}”里。


问题是:整句话的全部信息,都要被塞进同一个固定大小的向量 𝒄\mathbf{c}

不管源句是 5 个词还是 50 个词,编码器都只能交给解码器同样大小的一个向量(比如 1000 维)。短句子还好,长句子就装不下了——句首的信息在编码器逐词处理到句尾时,早已被后面的词反复覆盖、稀释(这正是第 04 章梯度消失的另一面:远处信息难以保留)。解码器拿到的 𝒄\mathbf{c} 对长句而言是一个严重有损的压缩。

实验现象很明确:seq2seq 的翻译质量随源句长度增加而显著下降。Bahdanau、Cho 和 Bengio 在 2014 年的论文里把这个诊断说得很清楚——把一个变长输入编码成定长向量,是性能随句长增长而恶化的根源2。(一个有趣的工程补丁是 seq2seq 原论文里把源句倒序输入,让句首的词离解码开始更近,缓解了一点长程问题——但这只是治标。)

真正的解法,是 Bahdanau 等人提出的:别再强迫编码器把一切压进一个向量。让编码器为每个源词都输出一个表示,解码器在生成每个目标词时,自己回头去看这些源词表示,挑出此刻最相关的那些。 这就是注意力机制。


注意力的数学,核心是一个“加权平均”。Bahdanau 2014 的版本(后称 additive attention 或 Bahdanau attention)是这样工作的2

编码器现在为源句每个位置 jj 输出一个隐藏状态 𝒉j\mathbf{h}_j(用双向 LSTM,所以 𝒉j\mathbf{h}_j 同时包含该词的左右上下文),一共 nn 个。解码器在生成第 ii 个目标词时,它当前的隐藏状态是 𝒔i1\mathbf{s}_{i-1}。注意力分三步:

第一步,打分(对齐):用一个小神经网络给“当前解码状态 𝒔i1\mathbf{s}_{i-1}”和“每个源位置 𝒉j\mathbf{h}_j”算一个相关性分数:

eij=𝒗tanh(Ws𝒔i1+Wh𝒉j) e_{ij} = \mathbf{v}^\top \tanh\!\left(W_s\,\mathbf{s}_{i-1} + W_h\,\mathbf{h}_j\right)

这个分数衡量“生成第 ii 个目标词时,第 jj 个源词有多重要”。注意它用了 tanh\tanh 和一个可学习向量 𝒗\mathbf{v}——这就是“additive”(加性)的来历:query 和 key 是相加后过非线性,而不是相乘。

第二步,归一化成权重:把分数过 softmax,得到一个在所有源位置上、和为 1 的注意力权重分布:

αij=exp(eij)k=1nexp(eik) \alpha_{ij} = \frac{\exp(e_{ij})}{\sum_{k=1}^{n}\exp(e_{ik})}

αij\alpha_{ij} 可以读成“生成第 ii 个目标词时,模型把多少注意力放在第 jj 个源词上”。

第三步,加权求和得 context:用这个权重对所有源位置的表示做加权平均,得到一个为这一步定制的 context 向量:

𝒄i=j=1nαij𝒉j \mathbf{c}_i = \sum_{j=1}^{n} \alpha_{ij}\,\mathbf{h}_j

解码器用这个 𝒄i\mathbf{c}_i(而不再是那个一成不变的全局 𝒄\mathbf{c})去生成第 ii 个词。关键在于:每生成一个目标词,𝒄i\mathbf{c}_i 都不一样——翻译到主语时注意力集中在源句主语上,翻译到动词时移到源句动词上。固定向量的瓶颈被彻底绕开了:信息不再需要全压进一个向量,解码器随时可以回到源句的任意位置去取它当下需要的部分。


注意力还带来一个意外的礼物:可解释性。把注意力权重 αij\alpha_{ij} 排成一个矩阵(目标词 × 源词)画成热图,就能看到模型在翻译每个词时“看”了源句的哪里。在英法翻译里,这个热图往往呈现出近似对角线的结构,并在语序调换处出现交叉——这等于模型自动学会了源句和目标句之间的词对齐,而没有人给过它任何对齐标注。论文标题里“jointly learning to align and translate”(联合学习对齐与翻译)说的正是这件事2

用代码看注意力如何“对齐”(完整文件 code/07_attention.py)。additive attention 的核心就是第三节那三步:

def additive_attention(query, keys, values, Wq, Wk, v):
    scores = [v @ np.tanh(Wq @ query + Wk @ k) for k in keys]  # e_ij 打分
    alpha = softmax(scores)            # alpha_ij 归一化权重
    context = alpha @ values           # c_i 加权求和
    return context, alpha

构造一个 query 故意接近第 3 个 key,运行结果:

注意力权重 alpha = [0.229 0.349 0.123 0.299]

权重在和 query 最相关的 key 上偏高——这就是“对齐”的最小演示:模型自动把更多权重分配给与当前查询最匹配的源位置。在真实翻译模型里,这个分布会尖锐得多,清晰地指向源句中对应的词。


退一步看注意力的本质,它其实是一个非常通用的“软查找”(soft lookup)操作,可以用三个角色来理解,这套术语在下一章的 Transformer 里会成为正式语言:

注意力做的事,就是用 query 和每个 key 算相似度,把相似度归一化成权重,再用权重对 value 做加权平均。它像一个“可微的、模糊的字典查找”:普通字典查找是“键完全匹配才返回唯一值”,而注意力是“按匹配程度返回所有值的加权混合”。因为它处处可微,所以能被反向传播端到端训练,让模型自己学会“什么时候该查什么”。

这个抽象一旦提炼出来,一个大胆的问题就浮现了:既然注意力这么强——它能让任意两个位置直接交互、能自动对齐、还可并行——那我们还需要那个慢吞吞、只能顺序处理的 RNN 吗?Bahdanau 的注意力是 RNN 的一个补丁,注意力坐在循环结构的肩膀上。如果把循环结构整个拆掉,只留下注意力呢?

2017 年,八位 Google 研究者给出了那个石破天惊的答案,论文标题就是宣言:《注意力就是你所需要的一切》。那是下一章。


把这一章用一张图收束——seq2seq 从“固定瓶颈”到“注意力”的演进:

【无注意力 seq2seq 2014】信息被压进单个向量 c,长句丢失
  源: x1 x2 x3 ... xn ─encoder LSTM─► [ c ] ─decoder─► y1 y2 y3 ...
                                       ▲ 固定大小,长句装不下(瓶颈)

【Bahdanau 注意力 2014】每步生成都回看全部源位置
  源:  h1   h2   h3  ...  hn      (编码器给每个源词一个表示)
        \    |    /        |
         \   |   /  α_ij(每步重算的权重)
          ▼  ▼  ▼
   生成 y_i 时: c_i = Σ_j α_ij h_j   ← 为这一步定制的 context
        注意力热图(目标×源)呈对角线 => 自动学会词对齐

配套的 manim 动画 assets/manim/ch07_attention.pyBottleneckSoftAlignment 两个 Scene)把“瓶颈”与“解法”并置:前者演示传统 seq2seq 把整句话的箭头全汇聚进一个固定大小的向量,句子越长丢的信息越多;后者演示注意力如何让解码的每一步“回头看”源句所有位置,对齐矩阵逐格点亮——生成每个目标词时聚焦的源词不同,越亮处越相关。这正是注意力可解释性的标志性图像,第一次让人“看见”了模型内部的对齐逻辑。

注意力解决了 seq2seq 的瓶颈,但此刻它还只是 RNN 的配件。把它从配件升级为整个架构的核心、彻底抛弃循环、换来大规模并行训练的能力——这一步将定义此后近十年的人工智能。


本质

注意力解决的根本问题是信息瓶颈:把一个变长序列硬塞进一个固定大小的向量,必然在长序列上丢信息。它的解法不是把瓶颈做大,而是干脆取消瓶颈——让解码端在每一步根据当前需要,去源端按相关度加权地取用信息,而不是依赖一份提前压缩好的摘要。这背后是一次表示方式的转变:从“先把全部信息压成一个东西,再用”,变成“保留全部信息,用时按需检索”。一旦想清楚这一点,“循环”就显得多余了——既然每个位置都能直接看到所有其他位置,为什么还要一步步顺序传递?这正是 Transformer 的起跳点:把这个还只是 RNN 配件的机制,提升为整个架构的唯一主角。


参考文献

  1. Sutskever, I., Vinyals, O., & Le, Q. V. (2014). Sequence to Sequence Learning with Neural Networks. NeurIPS 2014. 编码器-解码器双 LSTM、固定 context 向量、源句倒序技巧。arXiv:https://arxiv.org/abs/1409.3215 ;NeurIPS PDF:https://papers.neurips.cc/paper/5346-sequence-to-sequence-learning-with-neural-networks.pdf

  2. Bahdanau, D., Cho, K., & Bengio, Y. (2014). Neural Machine Translation by Jointly Learning to Align and Translate. additive attention、固定向量瓶颈诊断、联合对齐与翻译、注意力热图。arXiv:https://arxiv.org/abs/1409.0473

Transformer:注意力就是全部

循环网络有一个无法回避的原罪:它必须一步接一步地处理序列,第 t 步要等第 t−1 步算完,这让它在大规模并行硬件上慢得令人绝望,也限制了能学到的依赖距离。2017 年,八位 Google 研究者做了一件激进的事——把循环结构整个删掉,只留注意力。结果不仅训练快了一个数量级,效果还更好。这个叫 Transformer 的架构,用“缩放点积注意力”“多头”“位置编码”三件套,让序列里任意两个位置一步直达、且全部并行计算。它后来成了 BERT、GPT、几乎所有大模型的共同骨架。这一章把 Transformer 的每个零件——QKV、为什么除以根号 d、多头、位置编码、残差与层归一化——的数学与直觉讲透。


先把上一章的注意力抽象重述一遍,因为它是 Transformer 的全部语言。注意力是一个“软查找”:用一个查询(Query)去和一组(Key)比相似度,把相似度归一化成权重,再用权重对一组(Value)做加权平均。在 Bahdanau 那里,query 来自解码器、key/value 来自编码器,注意力是连接两个 RNN 的桥。

2017 年《注意力就是你所需要的一切》(Attention Is All You Need)做的事,是把这个机制从“RNN 的桥”提拔成“整座建筑”1。它问了一个极端的问题:如果一个序列里的每个位置,都用注意力直接去看序列里所有其他位置(包括自己),那还需要循环吗?答案是不需要。这种“序列内部各位置互相注意”的机制叫自注意力(self-attention),是 Transformer 的心脏。

抛弃循环换来一个巨大的好处:并行。RNN 的第 tt 个隐藏状态依赖第 t1t-1 个,所以必须顺序算;而自注意力里,所有位置的表示可以同时算出来——本质上就是几个大矩阵乘法,正是 GPU 最擅长的(回顾第 05 章)。这让 Transformer 能在同样的时间里训练大得多的模型、长得多的序列。论文里它在 WMT 2014 英德翻译上拿到 28.4 BLEU、英法 41.8 BLEU,超过此前包括集成模型在内的最佳结果 2 个 BLEU 以上,而训练只用了 8 块 GPU、3.5 天——比当时顶尖的循环/卷积翻译模型训练成本低得多1


自注意力的核心公式,叫缩放点积注意力(scaled dot-product attention)。把输入序列的每个位置先线性投影成三个向量——查询 QQ、键 KK、值 VV(实际是整批位置堆成矩阵 Q,K,VQ, K, V),注意力是:

Attention(Q,K,V)=softmax(QKdk)V \text{Attention}(Q, K, V) = \text{softmax}\!\left(\frac{QK^\top}{\sqrt{d_k}}\right)V

逐项拆解:

一句话:每个位置的新表示,是序列中所有位置的 value 的加权平均,权重由该位置的 query 和各位置的 key 的匹配度决定。位置 ii 想从位置 jj 取信息,只要它们的 query-key 匹配度高,一步就能取到——不管 iijj 隔了多远。这就是 Transformer 对长程依赖的解法:把 RNN 里“信息要逐步传递 |ij||i-j| 步”变成“任意两点一步直达”。


为什么要除以 dk\sqrt{d_k}?这是个值得讲清的数学细节,因为它体现了一种对“数值尺度”的精细控制。

假设 query 和 key 的每个分量是独立的、均值 0 方差 1 的随机变量。那么它们的点积 𝒒𝒌=l=1dkqlkl\mathbf{q}\cdot\mathbf{k} = \sum_{l=1}^{d_k} q_l k_ldkd_k 个独立项之和,其方差正比于 dkd_k——维度越高,点积的数值波动越大,量级约为 dk\sqrt{d_k}

如果不缩放,当 dkd_k 较大时(比如 64),点积会变得很大,送进 softmax 后会把分布推到极端——某一个权重接近 1、其余接近 0。问题在于 softmax 在这种饱和区的梯度极小(回顾第 04 章梯度消失的同源现象),训练会变得困难。除以 dk\sqrt{d_k} 恰好把点积的方差拉回 1 附近,让 softmax 工作在梯度健康的区间。一个除法,稳住了整个训练。


单一注意力有个局限:一次加权平均只能表达“一种”关注模式。但语言里一个词常常需要同时关注多种关系——句法上的(它的主语是谁)、语义上的(它指代什么)、位置上的(紧邻的修饰词)。Transformer 的解法是多头注意力(multi-head attention)。

做法是把 dmodeld_{\text{model}} 维的表示拆成 hh 个较低维的子空间(论文里 dmodel=512d_{\text{model}}=512h=8h=8 个头,每个头 dk=512/8=64d_k = 512/8 = 64 维),每个头用自己独立的 Q,K,VQ,K,V 投影矩阵,各自独立地做一次缩放点积注意力,最后把 hh 个头的输出拼接起来再做一次线性变换:

MultiHead(Q,K,V)=Concat(head1,,headh)WO \text{MultiHead}(Q,K,V) = \text{Concat}(\text{head}_1, \dots, \text{head}_h)\,W^O headi=Attention(QWiQ,KWiK,VWiV) \text{head}_i = \text{Attention}(QW_i^Q,\, KW_i^K,\, VW_i^V)

直觉是:每个头可以专注一种关系。事后分析真实 Transformer 的注意力头,确实能看到有的头专门关注相邻词、有的头追踪句法依存(如动词找它的宾语)、有的头处理指代。多头让模型在同一层并行地从多个“角度”看序列。注意计算量并不增加——把一个 512 维的注意力拆成 8 个 64 维的,总维度不变,只是切成了多个子空间。


自注意力有个先天缺陷:它是置换不变的。因为输出是 value 的加权和、权重只看 query-key 匹配度,所以打乱输入顺序,输出只会相应打乱,模型本身分不清“词的位置”。可语序对语言至关重要——“狗咬人”和“人咬狗”词一样、意思相反。RNN 天然知道顺序(它就是按顺序处理的),Transformer 删掉循环后必须显式地把位置信息注入进去

Transformer 的做法是位置编码(positional encoding):给每个位置 pospos 算一个和词向量同维度的向量,加到词向量上。论文用的是一组不同频率的正弦/余弦函数:

PE(pos,2i)=sin(pos100002i/dmodel),PE(pos,2i+1)=cos(pos100002i/dmodel) PE_{(pos, 2i)} = \sin\!\left(\frac{pos}{10000^{2i/d_{\text{model}}}}\right), \qquad PE_{(pos, 2i+1)} = \cos\!\left(\frac{pos}{10000^{2i/d_{\text{model}}}}\right)

每个维度 ii 对应一个不同波长的正弦波(从短到长跨好几个数量级),位置 pospos 在这些波上的取值组合,构成了它独一无二的“位置指纹”。用正弦/余弦的一个巧妙之处是:任意两个位置的相对偏移 kk,可以通过位置编码的线性变换表达(三角恒等式),这让模型容易学到“相对位置”关系,并且能外推到比训练时更长的序列。后来的模型发展出了可学习位置编码、相对位置编码、旋转位置编码(RoPE)等多种变体,但“必须显式注入位置”这个需求是 Transformer 架构的固有属性。


把零件组装成完整的 Transformer。原始论文是一个编码器-解码器结构,各 6 层1。一个编码器层由两个子层组成:

  1. 多头自注意力:序列内各位置互相注意。
  2. 逐位置前馈网络(FFN):对每个位置独立地过一个两层 MLP(5122048512512 \to 2048 \to 512,中间用 ReLU)。这给模型增加非线性变换能力。

每个子层都包着两样东西——残差连接层归一化

output=LayerNorm(x+Sublayer(x)) \text{output} = \text{LayerNorm}\big(x + \text{Sublayer}(x)\big)

残差连接 x+Sublayer(x)x + \text{Sublayer}(x) 直接搬用第 09 章会细讲的 ResNet 思想(恒等捷径让梯度畅通、深层可训练);层归一化(LayerNorm)则像第 09 章的 BatchNorm 一样稳定每层的数值分布、加速收敛,只是它在特征维度而非批次维度做归一化,更适合变长序列。没有这两样,6 层乃至后来几十上百层的 Transformer 根本训不动。

解码器层多一个细节:它的自注意力是带因果掩码的(masked self-attention)——生成第 ii 个词时只能看位置 i\le i 的词,不能偷看未来(否则训练时就作弊了)。掩码的实现是把注意力分数矩阵的上三角(未来位置)设成 -\infty,过 softmax 后权重变 0。这正是 GPT 这类自回归生成模型的关键。

用代码看因果掩码(完整文件 code/07_attention.py):

def scaled_dot_product_attention(Q, K, V, mask=None):
    d_k = Q.shape[-1]
    scores = Q @ K.T / np.sqrt(d_k)          # 缩放点积
    if mask is not None:
        scores = np.where(mask, scores, -1e9)  # 因果掩码:屏蔽未来
    A = softmax(scores, axis=-1)
    return A @ V, A

加上下三角掩码后运行:

下三角注意力(位置 i 只能看 <=i):
[[1.00 0.   0.   0.  ]
 [0.43 0.57 0.   0.  ]
 [0.01 0.03 0.96 0.  ]
 [0.01 0.01 0.06 0.92]]

每一行的权重只分布在对角线及左侧(过去和当前),右上方(未来)全是 0——这就是自回归生成“不能看未来”的数学实现。


用一张图把完整的 Transformer 编码器-解码器钉死:

                编码器 ×6                            解码器 ×6
   输入词 ──► 词向量 + 位置编码          输出词(右移) ──► 词向量 + 位置编码
                  │                                      │
            ┌─────▼─────┐                          ┌─────▼──────────┐
            │ 多头自注意力 │                          │ 带掩码多头自注意力 │ (不看未来)
            │ +残差+LN   │                          │ +残差+LN        │
            ├───────────┤                          ├────────────────┤
            │ 前馈FFN    │                          │ 编码器-解码器注意力│◄── 看编码器输出
            │ +残差+LN   │                          │ +残差+LN        │
            └─────┬─────┘                          ├────────────────┤
                  │  ───── 编码器输出(K,V) ───────►  │ 前馈FFN+残差+LN  │
                  ▼                                 └─────┬──────────┘
            (重复6层)                                     ▼
                                                   线性 + softmax ──► 下一个词概率
   核心: Attention(Q,K,V)=softmax(QKᵀ/√d_k)V ; 多头并行; 位置编码注入顺序

配套的 manim 动画 assets/manim/ch08_transformer.pyQKVAttentionPositionalEncoding 两个 Scene)把注意力的内核一步步演出来:某个 token 用自己的 Query 去和所有 token 的 Key 打分(点积),softmax 成权重(线条粗细就是权重大小),再去加权求和所有 token 的 Value,得到这个位置的新表示——这就是 self-attention 的全部。PositionalEncoding 则演示注意力本身不分先后,位置编码如何用不同频率的正余弦给每个位置盖一个全局唯一的“指纹”,把顺序信息加回去。


Transformer 的历史地位,不在于它在 2017 年赢了几个 BLEU 点,而在于它成了一个通用的、可无限堆叠和放大的序列处理底座。它有三个让它统治后续十年的特质:

第一,高度并行,能吃满 GPU/TPU,于是能被训练到巨大规模——这直接接上了第 05 章那条“规模即能力”的暗线,并在下一章成为 scaling laws 的物质基础。第二,任意两位置一步直达,长程依赖不再衰减,适合长文本、长上下文。第三,架构统一、模块整齐,几乎只由注意力、FFN、残差、归一化堆成,容易在不同任务、不同模态(文本、图像 ViT、语音、蛋白质)上复用——“一个架构通吃”成了现实。

正因如此,2018 年之后几乎所有有影响力的模型都建立在 Transformer 上:BERT 用它的编码器做双向预训练,GPT 用它的(带掩码的)解码器做自回归生成。把 Transformer 这个“骨架”和“大规模无监督预训练”这个“训练范式”结合起来,就诞生了我们今天所说的大语言模型。那是下一阶段——预训练、scaling laws 与对齐——的故事。

在抵达那里之前,还有一块拼图要补上:那些让“把网络堆到几十上百层、训练到收敛”成为可能的工程突破。残差连接、批归一化、更好的优化器和激活函数——它们不像 Transformer 那样耀眼,却是一切深层模型能被训练出来的隐形地基。那是下一章。


本质

Transformer 把序列建模归约成了一个极简的原语:每个位置用一个 Query 去和所有位置的 Key 算相似度,按相似度加权地聚合所有位置的 Value。它真正做对的,是把“建模任意两个位置之间的关系”从需要 O(n)O(n) 步顺序传递的循环操作,变成了一次可以完全并行的矩阵乘法——长程依赖不再随距离衰减,算力也能被现代硬件吃满。它的胜利与其说是因为注意力比循环“更聪明”,不如说是因为它更适合被放大:结构整齐、几乎只由注意力与前馈堆成、能复用到任何模态。当一个架构既能表达足够丰富的关系、又能无限并行地堆叠和训练,规模就成了唯一的变量——这正是它统治此后整个大模型时代的根本原因。


参考文献

  1. Vaswani, A., Shazeer, N., Parmar, N., Uszkoreit, J., Jones, L., Gomez, A. N., Kaiser, Ł., & Polosukhin, I. (2017). Attention Is All You Need. NeurIPS 2017. 缩放点积注意力、多头(d_model=512, 8 头)、正弦位置编码、6 层编码器-解码器、残差+LayerNorm、WMT14 英德 28.4 / 英法 41.8 BLEU、8 GPU 3.5 天。arXiv:https://arxiv.org/abs/1706.03762 ;NeurIPS PDF:https://proceedings.neurips.cc/paper/7181-attention-is-all-you-need.pdf ;综述:https://en.wikipedia.org/wiki/Attention_Is_All_You_Need

看不见的地基:让深层网络训得动的工程突破

Transformer、AlexNet 这些明星架构之所以能被训练出来,靠的是一批不那么耀眼、却不可或缺的工程突破。激活函数从 sigmoid 换成 ReLU,让梯度不再每层衰减四分之三;批归一化稳住了每一层的数值分布;残差连接用一条恒等捷径让上百层的网络梯度依然畅通;Adam 优化器让参数各自找到合适的步长。这些技术单独看都像“调参细节”,合起来却是深度学习从“几层就训不动”走向“几十上百层稳定收敛”的真正地基。这一章把这四块地基的数学讲清楚——它们解决的,都是同一个幽灵:梯度。


前面几章反复撞见同一个敌人:梯度。感知机学不会 XOR,是表达力问题;但从反向传播开始,几乎所有训练困难都能归到梯度上——梯度消失(第 04 章 RNN)、梯度爆炸、softmax 饱和区梯度小(第 08 章为什么除以根号 d)。原因在第 02 章就埋下了:反向传播是把一长串导数连乘起来,只要这些乘子系统性地偏离 1,连乘的结果就会指数级地趋零或炸开。

所以“让深层网络训得动”这个问题,本质上是“如何让梯度在很多层之间健康地流动”。本章的四项技术——ReLU、BatchNorm、残差连接、Adam——从四个不同角度回答这个问题。它们不改变网络要学的函数,只改变“能不能学到”。把它们理解为深度学习的地基,比理解为调参技巧更准确。


第一块地基是激活函数。早期网络用 sigmoid 或 tanh 做非线性,它们有一个致命缺陷藏在导数里。

sigmoid 函数 σ(z)=1/(1+ez)\sigma(z) = 1/(1+e^{-z}) 的导数是 σ(z)=σ(z)(1σ(z))\sigma'(z) = \sigma(z)(1-\sigma(z)),它的最大值在 z=0z=0 处,只有 0.25;当 zz 偏离 0(输入很大或很小)时,导数迅速趋近 0——这叫“饱和”。回忆第 02 章:误差每反传一层,都要乘一次该层激活函数的导数。如果每层都乘一个 0.25\le 0.25 的数,传过 LL 层后梯度量级至多是 0.25L0.25^L——10 层就只剩约 10610^{-6}。深层网络的前几层根本收不到学习信号。

2010 年,Nair 和 Hinton 推广了一个简单到几乎不像“函数”的激活:修正线性单元(Rectified Linear Unit, ReLU)1

ReLU(z)=max(0,z) \text{ReLU}(z) = \max(0, z)

它的导数极其干净:z>0z > 0 时导数是 1z<0z < 0 时是 0。正区间导数恒为 1 意味着——误差反传穿过激活时不衰减。把这件事跑出来对比最直观(配套代码 code/09_enablers.py):

sigmoid: 10 层导数连乘(每层最多0.25) ~ 9.54e-07   -> 梯度消失
ReLU   : 10 层导数连乘(正区间每层1.0) ~ 1.00e+00   -> 梯度保持

同样 10 层,sigmoid 把梯度压到百万分之一,ReLU 原样保留。ReLU 还有两个附带好处:计算极快(就是一个取大)、且对负输入直接输出 0,带来稀疏激活。代价是“死亡 ReLU”问题——若一个单元长期落在负区间,梯度恒 0、永不更新;后续的 Leaky ReLU、GELU 等变体对此做了改良。但 ReLU 缓解梯度消失这一条,已足以让它成为 AlexNet(第 05 章)及之后几乎所有网络的默认激活。


第二块地基是批归一化(Batch Normalization, BatchNorm),2015 年由 Ioffe 和 Szegedy 提出2

它针对的问题是:训练时,每一层的输入分布会随着前面层参数的更新而不断漂移——作者称之为“内部协变量偏移”(internal covariate shift)。下一层刚适应了某种输入分布,上一层一更新,分布又变了,下一层得重新适应,训练因此变慢、变得对学习率和初始化敏感。

BatchNorm 的做法是:在每一层(通常是激活之前),对一个小批次(mini-batch)内的数据,把每个特征维度归一化到均值 0、方差 1,再用两个可学习参数 γ,β\gamma, \beta 做缩放和平移:

x̂=xμBσB2+ϵ,y=γx̂+β \hat{x} = \frac{x - \mu_B}{\sqrt{\sigma_B^2 + \epsilon}}, \qquad y = \gamma\,\hat{x} + \beta

其中 μB,σB2\mu_B, \sigma_B^2 是当前批次该特征的均值和方差。先归一化稳住分布,再用 γ,β\gamma, \beta 让网络保留“在需要时恢复原始尺度”的自由(如果归一化不利,网络可以学 γ=σB,β=μB\gamma = \sigma_B, \beta = \mu_B 把它撤销)。

BatchNorm 的效果立竿见影:允许用大得多的学习率、对初始化不再那么敏感、训练显著加快,还附带轻微的正则化效果(因为每个样本的归一化依赖随机的批次统计,引入了噪声)。后来人们对“内部协变量偏移”这个解释本身有争议——有研究认为 BatchNorm 真正的作用是让损失曲面更平滑、优化更容易——但无论机制解释如何,它“稳住数值分布、加速深层训练”的实用价值毋庸置疑。在序列模型和 Transformer 里,因为序列变长、批统计不稳,人们更常用层归一化(LayerNorm,在特征维度而非批次维度归一化,见第 08 章)。


第三块、也是最优雅的一块地基,是残差连接(residual connection),2015 年由何恺明等人在 ResNet 里提出3

它解决一个反直觉的现象:把网络做得更深,效果反而变差——而且不是过拟合(训练误差也更高)。理论上深层网络至少能表达浅层网络能表达的一切(多出来的层学成恒等映射即可),可实践中优化器学不到这个恒等映射,深层网络退化了。

ResNet 的洞察是:与其让每一层去学一个完整的目标映射 H(x)H(x),不如让它去学“目标与输入的差” F(x)=H(x)xF(x) = H(x) - x,然后把输入直接加回来

y=F(x)+x y = F(x) + x

那条把 xx 直接加到输出的线,叫“捷径连接”(shortcut / skip connection)。它带来两个好处。其一,学恒等更容易:要表达恒等映射 y=xy = x,只需让 F(x)=0F(x) = 0(把权重压到 0),这比让一堆非线性层精确拟合出恒等容易得多。其二、也是关键——梯度有了直达通路。看残差层的梯度:

yx=1+Fx \frac{\partial y}{\partial x} = 1 + \frac{\partial F}{\partial x}

那个 +1+1 是魔法所在。即便 F/x\partial F/\partial x 很小(趋于梯度消失),梯度里永远有一个恒为 1 的直达项,误差可以沿着捷径无衰减地传回浅层。跑出来看(code/09_enablers.py):

F'(x)=0.01:  普通层 dy/dx=0.01     |  残差层 dy/dx=1+0.01=1.01
F'(x)= 0.5:  普通层 dy/dx=0.5      |  残差层 dy/dx=1+0.5=1.5

普通层在 F=0.01F'=0.01 时梯度近乎消失,残差层却稳稳保持在 1 附近。靠这条捷径,ResNet 把网络深度推到了 152 层——比当时的 VGG 深 8 倍——并以 3.57% 的 top-5 错误率赢得 ILSVRC 20153。残差连接的思想此后无处不在:第 08 章的 Transformer 每个子层都包着 x+Sublayer(x)x + \text{Sublayer}(x),正是同一个 +1+1 在让上百层的大模型梯度畅通。


第四块地基是优化器。最朴素的梯度下降对所有参数用同一个学习率 η\eta,沿负梯度走 wwηgw \leftarrow w - \eta\,g。但不同参数的梯度尺度可能差好几个数量级——有的方向梯度很大、需要小步,有的很小、需要大步,统一学习率顾此失彼。

一系列自适应优化器解决这个问题,集大成者是 2014 年 Kingma 和 Ba 提出的 Adam4。它为每个参数维护两个滑动平均:一阶矩 mm(梯度的动量,平滑掉噪声、保持方向惯性)和二阶矩 vv(梯度平方的平均,估计该方向梯度的典型大小):

mt=β1mt1+(1β1)gt,vt=β2vt1+(1β2)gt2 m_t = \beta_1 m_{t-1} + (1-\beta_1) g_t, \qquad v_t = \beta_2 v_{t-1} + (1-\beta_2) g_t^2

做偏差校正(修正初期 m,vm,v 偏向 0 的问题)后,更新为:

m̂t=mt1β1t,v̂t=vt1β2t,wwηm̂tv̂t+ϵ \hat{m}_t = \frac{m_t}{1-\beta_1^t}, \quad \hat{v}_t = \frac{v_t}{1-\beta_2^t}, \qquad w \leftarrow w - \eta\,\frac{\hat{m}_t}{\sqrt{\hat{v}_t} + \epsilon}

关键是那个 m̂/v̂\hat{m}/\sqrt{\hat{v}}:用动量做分子(稳定方向),用梯度大小做分母(自动缩放步长)。梯度一向很大的参数,分母大、步子被压小;梯度一向很小的参数,分母小、步子被放大。每个参数都得到了适合自己的有效学习率。跑出来看(code/09_enablers.py),交替喂入大梯度(10)和小梯度(0.01),Adam 的实际更新量都被归一到 0.006–0.007 这个相近的量级——尺度被自动拉平。Adam 默认参数(β1=0.9,β2=0.999\beta_1=0.9, \beta_2=0.999)鲁棒、几乎开箱即用,成了深度学习最常用的优化器,从 CNN 到 Transformer 大模型训练的默认选择。


把四块地基放在一起看,它们其实是从四个方向围剿同一个敌人——让梯度在深层网络里健康地流动

敌人: 反向传播是导数连乘 => 系统性偏离 1 就指数消失/爆炸

  ReLU        : 换掉饱和激活,正区间导数=1     → 激活这一环不衰减
  残差连接 +x  : 给梯度一条恒等捷径 dy/dx=1+F'  → 有一条永不衰减的直达通路
  BatchNorm   : 稳住每层输入分布(均值0方差1)   → 数值不漂移,可用大学习率
  Adam        : 每参数自适应步长 m̂/√v̂        → 不同尺度的梯度都走合适的步子
        └────────────── 合力 ──────────────┘
        几层就训不动  ──►  几十上百层稳定收敛

配套的 manim 动画 assets/manim/ch09_enablers.py(含 ReLUGateResidualBatchNormSceneAdamTrajectory 四个 Scene)把四块地基各自的几何直觉演出来:ReLU 是一道折线门,正区导数恒为 1、不饱和,梯度不被掐死;残差 y=F(x)+xy=F(x)+x 的 skip 像一条让梯度直达底层的高速公路;BatchNorm 把漂移的激活分布拉回标准正态;Adam 在被拉长的病态损失曲面上用自适应步长,比朴素 SGD 更直地冲向谷底。四段动画说的是同一件事:这些“工程细节”不是锦上添花,而是深层网络能否被训练出来的生死线。

这一章的技术都不像 Transformer 那样有一个戏剧性的“发明时刻”,它们是一群在 2010–2015 年间陆续到位的拼图。但正是它们的合流,加上第 05 章的数据与算力,才让“把网络堆得很深很大并训练到收敛”从奢望变成日常。地基铺好,就可以盖最高的楼了——把 Transformer 这个骨架,用海量文本做大规模预训练,造出能读会写的语言模型。那是 BERT 与 GPT 的故事,也是大模型时代的开端。


本质

这一章的四项技术看似无关,实则都在对付深层网络的同一个敌人:信号(无论是前向的激活还是反向的梯度)在层与层的反复变换中失控——要么衰减到零,要么膨胀到爆,要么分布漂移到难以优化。ReLU 让梯度有一条不饱和的通路,残差让恒等映射成为默认、给梯度修一条直达底层的近路,归一化把每层的输入分布钉在一个稳定的尺度上,自适应优化器则按每个参数自己的曲率调步长。它们的共同主题是:把深度从一个会放大病态的累赘,变成一个可以安全堆叠的资源。没有任何一项是“提升精度的技巧”,它们合起来回答的是一个更基础的问题——一个几十上百层的网络,凭什么能被训练到收敛。架构决定了模型能表达什么,而这些地基决定了它能不能真的被学出来。


参考文献

  1. Nair, V., & Hinton, G. E. (2010). Rectified Linear Units Improve Restricted Boltzmann Machines. ICML 2010. ReLU 缓解梯度消失。综述见 batch/activation 相关文献;ReLU 在 AlexNet 中的角色见 https://en.wikipedia.org/wiki/AlexNet

  2. Ioffe, S., & Szegedy, C. (2015). Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift. arXiv:https://arxiv.org/abs/1502.03167 ;ar5iv(含公式):https://ar5iv.labs.arxiv.org/html/1502.03167

  3. He, K., Zhang, X., Ren, S., & Sun, J. (2015/2016). Deep Residual Learning for Image Recognition. CVPR 2016. 残差连接、152 层、ILSVRC2015 3.57%。arXiv:https://arxiv.org/abs/1512.03385 ;官方代码:https://github.com/KaimingHe/deep-residual-networks

  4. Kingma, D. P., & Ba, J. (2014). Adam: A Method for Stochastic Optimization. 一阶/二阶矩、偏差校正、自适应步长。arXiv:https://arxiv.org/abs/1412.6980

预训练:BERT 与 GPT 两条路线

有了 Transformer 这个骨架,下一个问题是怎么喂它。监督学习需要海量人工标注,可标注昂贵且稀少;而互联网上有近乎无限的原始文本。预训练范式的核心洞察是:先用一个不需要标注的自监督任务,让模型在海量文本上学会语言的通用规律,再用少量标注数据微调到具体任务。围绕“用什么自监督任务”,2018 年分出了两条路线——BERT 用“完形填空”做双向理解,GPT 用“预测下一个词”做单向生成。前者一度主导理解类任务,后者则在规模放大后长成了今天的大语言模型。这一章讲清楚预训练为什么有效、两种自监督目标的数学、以及为什么是 GPT 那条看似更笨的路线最终通向了通用智能。


先理解预训练要解决的根本矛盾。深度学习吃数据,而最有用的那种数据——带标签的(这句话情感是正面、这个词是人名、这个问题的答案是 X)——恰恰最稀缺、最贵,每条都要人工标注。可与此同时,无标注的文本几乎免费且无穷:整个互联网、所有书籍、所有维基百科。

第 06 章的 word2vec 已经示范了破局思路:用自监督任务,从无标注文本里学有用的表示——它把“根据上下文猜词”当作免费的监督信号。预训练范式把这个思路推到极致:不只学词向量,而是预训练整个深层 Transformer,让它在海量文本上先学会语言的通用规律(语法、语义、常识、推理的雏形),形成一个强大的“语言理解/生成引擎”;然后针对具体任务,只需用少量标注数据做微调(fine-tuning),把这个通用引擎适配过去。

这套“先在大数据上自监督预训练、再在小数据上有监督微调”的范式,是 2018 年前后 NLP 的范式革命。它的两个代表,BERT 和 GPT,分歧只在一处:预训练时让模型做什么自监督任务。而这个看似技术性的选择,决定了两条截然不同的命运。


先看 GPT 这条路线,因为它更直接。GPT(Generative Pre-trained Transformer)由 OpenAI 在 2018 年推出,用的自监督任务是语言建模(language modeling)——也就是最古老、最朴素的那个任务:预测下一个词1

给定前面的词 x1,,xt1x_1, \dots, x_{t-1},模型预测下一个词 xtx_t 的概率分布。整段文本的概率被自回归地分解成每一步条件概率的连乘:

P(x1,,xn)=t=1nP(xtx1,,xt1) P(x_1, \dots, x_n) = \prod_{t=1}^{n} P(x_t \mid x_1, \dots, x_{t-1})

训练目标是最大化这个对数似然,等价于在每个位置做一次“下一个词是什么”的多分类(softmax over 词表 + 交叉熵)。这个任务的监督信号完全免费——任何一段文本,本身就提供了“前文→下一个词”的无数训练对。

架构上,GPT 用的是 Transformer 的解码器部分,关键是第 08 章讲过的因果掩码(masked self-attention):预测第 tt 个词时只能看 <t< t 的词,不能偷看未来。这保证了“预测下一个词”是个真任务而非作弊。预训练完成后,GPT 是一个强大的文本生成器,给个开头就能续写。

GPT 这条路线一开始看起来“笨”——只会接话,怎么做问答、分类、翻译这些具体任务?早期需要针对每个任务微调。但 OpenAI 押注于一个信念:只要把这个“预测下一个词”的模型做得足够大、训练数据足够多,它会自己涌现出处理各种任务的能力。这个信念在 GPT-2(2019)初现端倪,在 GPT-3(2020,1750 亿参数)得到惊人验证——下一章详谈。


再看 BERT 这条路线。BERT(Bidirectional Encoder Representations from Transformers)由 Google 在 2018 年提出2,它的出发点是对 GPT 的一个“批评”:预测下一个词是单向的,模型理解一个词时只能看它左边的上下文。但人类理解语言是双向的——“他把行李放进了___,然后锁上”这个空,右边的“锁上”和左边一样重要。BERT 想让模型在理解每个词时同时看到左右两边

可问题来了:如果允许双向,“预测下一个词”就崩溃了——模型能直接看到要预测的那个词(在它右边),等于看着答案抄。BERT 的解法是换一个自监督任务:掩码语言建模(Masked Language Model, MLM),俗称“完形填空”2

做法是:随机遮住输入里约 15% 的词(替换成特殊的 [MASK] 标记),让模型根据双向的上下文去预测被遮住的词。因为要预测的词被遮住了,模型看左右两边都不算作弊。这让 BERT 用上了 Transformer 的编码器部分(不带因果掩码的双向自注意力),每个词的表示都融合了完整的左右上下文。BERT 还配了第二个任务“下一句预测”(判断两句话是否前后相邻),用来学句子间关系。

预训练后,BERT 微调到具体任务的方式很简单:在它输出的表示上接一个小的任务头(比如分类层),用该任务的标注数据微调整个模型。BERT 一经推出就在一系列语言理解基准(如 GLUE)上大幅刷新纪录,迅速成为 2018–2020 年理解类 NLP 任务的主导模型23


把两条路线的分歧用一张表钉住,它们的每一处差异都互相咬合:

                 GPT (2018, OpenAI)          BERT (2018, Google)
Transformer 部分  解码器(decoder)             编码器(encoder)
自注意力          带因果掩码(单向)            双向(无掩码)
自监督任务        预测下一个词(自回归LM)      完形填空(掩码语言建模 MLM)
看上下文          只看左边                   同时看左右
天生擅长          生成(续写、对话)           理解(分类、抽取、问答打分)
微调              任务头 / 后来靠提示词       接任务头微调
放大后的命运      涌现通用能力 → LLM/ChatGPT  强基线,但难做开放生成

这张表里有一个深刻的对称:单向是生成的代价,也是生成的前提。GPT 只能看左边,所以做不了真正的双向理解,但也正因为它被训练成“根据前文预测下文”,它天生就是个生成器——而生成,恰恰是通向“做任意任务”的万能接口。BERT 看双向、理解更强,但它学的是“填空”,不会自回归地生成长文本,做开放式生成、对话很别扭。

2018 到 2020 年,如果只看基准分数,BERT 路线一度更风光——理解类任务它几乎通吃。但历史选择了 GPT 那条路。原因在下一节。


为什么是 GPT 而非 BERT 通向了今天的通用大模型?这是一个值得讲清的判断,它关乎“任务接口”的统一性。

GPT 的“预测下一个词”有一个 BERT 的“完形填空”不具备的性质:它是一个统一的、生成式的接口,几乎任何任务都能被表述成“续写”。翻译?输入“中文:你好 英文:”让它续写。问答?输入“问题:……答案:”让它续写。摘要、分类、写代码、解数学——全都能塞进“给定上文、生成下文”这一个框架。当模型大到一定程度,你甚至不需要为每个任务微调,只要在输入里给几个例子(few-shot)或一句指令,它就能照做。这种“一个模型、一个接口、用提示词适配万种任务”的能力,叫上下文学习(in-context learning),是 GPT-3 带来的震撼,也是下一章的主题。

BERT 的完形填空没有这种统一接口。它擅长“理解一段已给定的文本”,但它的输出是每个位置的表示,不是流畅的生成;要做不同任务,往往得为每个任务设计不同的输出头并微调。它是一个出色的“理解引擎”,却不是一个通用的“任务执行引擎”。

还有一层是规模的回报。后来的经验(scaling laws,下一章)显示,自回归语言建模这个目标随规模增长能持续、平滑地变好,并在足够大时涌现出推理、指令遵循等新能力。GPT 路线踩中了这条“越大越强且会涌现质变”的曲线,于是把全部赌注压在放大上,最终兑现。这不是说 BERT 路线错了——它在搜索、检索、文本分类等大量实际系统里至今仍在服役——而是说,在“通向通用智能”这个特定方向上,生成式、单向、可统一为续写接口的 GPT 路线,被证明是更对的那条。


用一张图把预训练范式与两条路线收束:

        海量无标注文本 (互联网/书籍/维基)
                    │ 自监督预训练 (免费监督信号)
        ┌───────────┴────────────┐
        ▼                         ▼
  GPT: 预测下一个词              BERT: 完形填空(遮15%)
  [x1 x2 x3]──►预测 x4           [x1 MASK x3 x4]──►预测 MASK
  Transformer 解码器(因果掩码)    Transformer 编码器(双向)
        │                         │
        ▼ 微调/提示词              ▼ 接任务头微调
  生成、对话、few-shot           分类、抽取、句对打分
        │                         │
        ▼  放大 → 涌现            (强基线,理解类主导 2018-20)
   GPT-2/3 → ChatGPT → LLM

配套的 manim 动画 assets/manim/ch10_pretrain.pyMaskShapes Scene)把两条路线的分野演成两块注意力掩码矩阵:GPT 是下三角(因果掩码),每个位置只能看过去,因而只能自回归地逐 token 生成;BERT 是满矩阵(双向),每个位置能看全文,但部分输入位置被 [MASK] 替换、要靠双向上下文还原。两块掩码并排,就是“单向生成”与“双向理解”在数学上的全部分野——一切后续差异都从这块掩码的形状里长出来。

预训练范式把“语言能力”从“为每个任务从零训练”变成了“先学通用引擎、再轻量适配”,这是 NLP 效率的一次飞跃。而 GPT 路线在此基础上又押注于规模,把“预测下一个词”这个朴素目标推到了千亿参数、万亿词的尺度。当规模跨过某些临界点,发生的事情超出了所有人的预期——模型开始展现出未被显式训练的能力,性能随规模的增长还呈现出可被精确预测的数学规律。把“规模”本身变成一门可量化的科学,并解决“如何让这个庞然大物听话、有用、安全”——那是 scaling laws 与 RLHF 的故事,也是这部技术史目前的最前沿。


本质

预训练真正改变的是知识的获取方式:在 BERT 和 GPT 之前,模型为每个任务从零学起,能用的只有那点稀缺的标注数据;之后,模型先在海量无标注文本上用一个自监督目标(预测被遮住的词、或预测下一个词)学一个通用的语言引擎,再用少量数据轻量适配到具体任务。它把“语言能力”从一次性消耗品变成了可复用的基础设施。而 BERT 与 GPT 的全部分歧,最后都收敛到一个工程选择——注意力能不能看到未来:看不到(因果掩码)就只能生成,看得到(双向)就擅长理解。GPT 路线之所以最终主导,是因为“逐 token 预测下一个词”这个看似最朴素的目标,恰好既能生成、又能随规模无止境地放大;当它被推到足够大,理解能力作为副产品自己长了出来。


参考文献

  1. Radford, A., et al. (2018/2019). Improving Language Understanding by Generative Pre-Training(GPT-1)/ Language Models are Unsupervised Multitask Learners(GPT-2)。自回归语言建模、Transformer 解码器、因果掩码。GPT 系列与 few-shot 范式综述见 GPT-3 论文:https://arxiv.org/abs/2005.14165

  2. Devlin, J., Chang, M.-W., Lee, K., & Toutanova, K. (2018). BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding. 掩码语言建模(MLM)、双向编码器、下一句预测、GLUE 刷新。arXiv:https://arxiv.org/abs/1810.04805

  3. BERT 与 GPT 路线对比(双向掩码 vs 单向因果 LM、few-shot 能力差异)综述。见 “Language Models are Few-Shot Learners” 对 BERT/GPT 对比的讨论:https://papers.nips.cc/paper/2020/hash/1457c0d6bfcb4967418bfb8ac142f64a-Abstract.html

规模与对齐:从 scaling laws 到 RLHF

把“预测下一个词”这个朴素目标推到极致,会发生什么?2020 年的 scaling laws 给出一个惊人的答案:模型的损失随参数量、数据量、算力的增长呈干净的幂律下降,干净到可以用小模型的曲线精确预测大模型的表现——智能的提升第一次变成了一件可以被工程化规划的事。但更大的模型只是“更会预测下一个词”,它不天然地有用、诚实、无害。要让一个能续写任何文本的庞然大物变成一个听话、有帮助的助手,需要第二步:用人类反馈去对齐它。这一章讲清楚 scaling laws 的数学、Kaplan 与 Chinchilla 之争、RLHF 的三步流程与 Bradley-Terry 偏好模型——这是这部技术史目前的最前沿,也是 ChatGPT 诞生的直接原因。


第 05 章埋下的那条暗线——“规模本身会带来能力”——在 2020 年被变成了一门精确的科学。

这一年,OpenAI 的 Jared Kaplan、Sam McCandlish 等人发表了《神经语言模型的 scaling laws》1。他们系统地训练了从很小到很大的一系列语言模型,改变参数量 NN、数据量 DD、训练算力 CC,记录每个模型的测试损失(交叉熵)。结果出乎意料地规整:损失随这三个量的增长,都呈现出幂律下降——而且这种规律横跨了七个以上的数量级1

以参数量为例,损失大致服从:

L(N)(NcN)αN+L L(N) \approx \left(\frac{N_c}{N}\right)^{\alpha_N} + L_\infty

其中 αN\alpha_N 是一个小指数(约 0.076),LL_\infty 是数据本身的不可约熵(语言固有的随机性,再大的模型也消不掉)。幂律的关键性质是:在对数-对数坐标下,它是一条直线。这意味着,你只要训练几个不同规模的小模型、拟合出这条直线,就能外推预测一个大得多的模型的损失——而不必先把它训练出来。

把它跑出来看(配套代码 code/11_scaling_rlhf.py):

参数量 N        预测损失 L
1e+06          5.706
1e+08          4.520
1e+10          3.684
1e+11          3.364     ← 规模每涨10倍, 损失稳定、可预测地下降

Kaplan 的论文还发现一件对实践极重要的事:在很宽的范围内,网络的宽度、深度等结构细节影响很小,真正决定损失的是规模(参数、数据、算力)1。这等于说:“别纠结架构调参了,把规模放大。”这个结论直接成了 GPT-3 的规划手册——OpenAI 据此预测,把模型放大到 1750 亿参数会带来什么,然后真的去训了,并在 GPT-3 上验证了少样本上下文学习的惊人能力2


scaling laws 之所以是范式级的发现,在于它把“做更强的 AI”从一门玄学变成了一门工程。

在它之前,提升模型靠的是发明新架构、调超参、试各种技巧,回报不确定。scaling laws 说:有一条平滑、可预测的曲线,沿着它放大规模,损失就会可靠地下降。于是研究策略变了——与其赌一个新点子,不如沿着这条确定的曲线投入算力。这也解释了 2020 年后 AI 竞赛为何迅速变成一场“算力与数据的军备竞赛”:当回报可预测,理性的玩家就会把资源压在放大上。

但 Kaplan 的具体配方很快被修正。2022 年,DeepMind 的 Hoffmann 等人发表了《训练计算最优的大语言模型》,即著名的 Chinchilla 工作3。他们问了一个更精细的问题:给定固定的算力预算 CC(约等于 6ND6ND),应该把它怎么分配给“更大的模型”和“更多的数据”?

Kaplan 2020 的结论偏向参数——约 73% 算力给参数、27% 给数据。Chinchilla 重新做了更细致的实验,得出相反的结论:参数量和数据量应该按相同比例缩放——模型每翻一倍,训练数据也该翻一倍,大致是 50/50 分配3。这个修正的杀伤力在于它揭示:当时几乎所有大模型都“过大而欠训练”——它们参数堆得很多,但喂的数据太少,没把参数喂饱。为证明这点,DeepMind 训了一个只有 700 亿参数、但用了 4 倍数据的 Chinchilla,在相同算力下全面超过了 2800 亿参数的 Gopher、1750 亿的 GPT-3、5300 亿的 Megatron-Turing NLG3

跑一下计算最优分配(code/11_scaling_rlhf.py):

算力 C ≈ 6*N*D ; 最优时 N 翻倍则 D 也翻倍 (约 20 tokens/参数)
C=1e+22 FLOPs -> N_opt~4.08e10 参数, D_opt~4.08e10 ...
结论: GPT-3(175B,300B tokens) 欠训练; Chinchilla(70B,1.4T tokens) 同算力更优

Chinchilla 之后,“小一点的模型 + 多得多的数据”成了新共识,直接影响了后续 LLaMA 等模型的设计哲学——用相对小的参数、海量数据,做出又强又便宜部署的模型。Kaplan 与 Chinchilla 之争,是 scaling 这门年轻科学自我修正的一个范例:两者都对幂律成立,分歧只在最优分配的系数上。


但 scaling 只解决了“能力”,没解决“有用”。一个用海量文本训练的语言模型,学会的是模仿互联网文本的分布——它会续写、会模仿任何风格,但它不天然地有帮助、诚实、无害。问它问题,它可能续写出一个更长的问题列表(因为训练数据里问题常成堆出现);它会一本正经地编造、会顺着有害请求往下写。预训练模型是个博学但不听话的“续写机器”,不是一个助手。

把它变成助手,需要对齐(alignment)——让模型的行为符合人类的意图和价值。对齐的关键技术,是基于人类反馈的强化学习(Reinforcement Learning from Human Feedback, RLHF)。

RLHF 的思想源头是 2017 年 Christiano 等人的《从人类偏好做深度强化学习》4。他们的洞察是:很多我们想要的行为,很难写成数学奖励函数,但人类一眼就能比较哪个更好。比如“什么是好的回答”无法精确定义,但给人看两个回答,他能说出更喜欢哪个。于是不去手写奖励函数,而是从人类的成对偏好里学出一个奖励函数。Christiano 等人证明,仅用不到 1% 的交互让人类提供偏好反馈,就能训练智能体解决 Atari 游戏和模拟机器人运动这类难以指定奖励的任务4

2022 年,OpenAI 的 Ouyang 等人在《训练语言模型遵循指令》(InstructGPT)里,把 RLHF 系统地用到了语言模型上5。这就是 ChatGPT 背后的核心训练方法。


InstructGPT 的 RLHF 是一个清晰的三步流程5

第一步,监督微调(SFT):先收集一批人类写的高质量示范——给定指令,人类示范应该怎么回答。用这些“指令-理想回答”对,对预训练模型做有监督微调,让它先学会“回答指令”这种格式,而不是漫无目的地续写。

第二步,训练奖励模型(RM):让 SFT 模型对同一个指令生成多个回答,请人类排序(这个比那个好)。用这些人类排序,训练一个奖励模型——它输入一个回答,输出一个标量分数,分数高低反映人类偏好。这一步的数学核心是 Bradley-Terry 偏好模型:人类偏好回答 ywy_w 胜过 yly_l 的概率,被建模为两者奖励之差的 sigmoid:

P(ywyl)=σ(r(yw)r(yl)) P(y_w \succ y_l) = \sigma\big(r(y_w) - r(y_l)\big)

训练奖励模型就是最大化所有人类偏好对的对数似然,即最小化 logσ(r(yw)r(yl))-\log \sigma(r(y_w) - r(y_l))。跑一下(code/11_scaling_rlhf.py):

P(回答A优于B) = sigmoid(r_A - r_B)
r(优)=2.0 r(劣)=1.0 -> P(选优)=0.731
r(优)=3.0 r(劣)=-1.0 -> P(选优)=0.982
r(优)=1.0 r(劣)=1.0 -> P(选优)=0.500   ← 奖励相等则各半

奖励差越大,模型对“哪个更好”越确信;这个可微的偏好模型,把离散的人类排序变成了一个连续的、可优化的奖励信号。

第三步,强化学习优化(PPO):把奖励模型当作奖励信号,用强化学习(近端策略优化, PPO)继续训练语言模型——让它生成的回答尽可能获得奖励模型给的高分。同时加一个约束(KL 惩罚),防止模型为了刷高奖励而偏离原来的语言能力太远(否则它会发现一些钻奖励模型空子的怪异输出)。

三步走完,模型从“博学的续写机”变成了“听话、有帮助的助手”。InstructGPT 的一个惊人结果是:经过 RLHF 的 13 亿参数小模型,其输出被人类偏好的程度,超过了未对齐的 1750 亿参数 GPT-35——参数小了 100 多倍,却更有用。这说明对齐带来的“有用性”提升,和单纯放大规模是两个正交的维度:规模给你原始能力,对齐把能力导向人类想要的方向。


把这两件事的关系想清楚,是理解今天大模型的关键。scaling 负责“聪明”,对齐负责“有用”——缺一不可。

只有 scaling,你得到一个能力惊人但不受控的续写引擎(GPT-3 那样,需要精心设计提示词才能驾驭)。只有对齐而没有足够规模,你得到一个听话但没什么本事的小模型。2022 年底的 ChatGPT,正是两者合流的产物:一个被 scaling 推到足够大、又被 RLHF 对齐得足够听话的模型,第一次让普通人能用自然语言流畅地使唤一个 AI。它在两个月内达到一亿用户,把这部从 1943 年开始的技术史,第一次推到了全人类的日常生活里。

值得强调的是,对齐远未“解决”。RLHF 有已知的局限:人类反馈本身有偏差和不一致,奖励模型会被钻空子(reward hacking),模型可能学会“听起来对”而非“真的对”(谄媚、自信地胡说)。如何让 AI 在变得更强的同时仍然诚实、可控、价值对齐,是一个开放的、且随能力增长而愈发紧迫的问题——它催生了 RLHF 的各种改进(如直接偏好优化 DPO、宪法式 AI、可扩展监督等)和整个 AI 安全研究领域。这部技术史在这里抵达它的现在进行时。


用一张图把规模与对齐这两条最前沿的主线收束:

【规模 (scaling) — 负责"聪明"】
  预测下一个词 + 放大(N,D,C) ──► 损失幂律下降 L(N)=(Nc/N)^α+L∞
     Kaplan 2020: 偏参数(73/27),规划了 GPT-3
     Chinchilla 2022: 参数与数据同比(50/50),多数模型"欠训练"
     => 得到强大但不听话的"续写引擎"
                          │
                          ▼
【对齐 (RLHF) — 负责"有用"】
  ① SFT: 人类示范 → 学会"回答指令"
  ② RM:  人类排序 → Bradley-Terry: P(优于)=σ(r_w−r_l) → 学出标量奖励
  ③ PPO: 用奖励模型 + KL约束 强化学习 → 优化到"人类偏好"
     => 1.3B 对齐模型 被偏好 > 175B 未对齐 GPT-3
                          │
                          ▼
              ChatGPT (2022) = 足够大 × 足够对齐

配套的 manim 动画 assets/manim/ch11_scaling_rlhf.pyScalingLawRLHFPreference 两个 Scene)把两块基石演出来:前者展示损失在 log-log 坐标下随规模下降成一条可外推的直线(幂律),散点落在线上、虚线把它延伸去预测更大的模型——规模可预测;后者展示 RLHF 的链条,人给出“A 比 B 好”的成对偏好,训出奖励模型,策略分布随之被推向高奖励区。两段动画分别对应“规模可预测”与“偏好可量化”——大模型时代的数学基石。

从 1943 年 McCulloch 和 Pitts 把神经元写成一个逻辑命题,到 2022 年 ChatGPT 用人类反馈学会对话,这条线走了将近八十年。它的每一步——可计算(M-P)、可学习(感知机)、可训练多层(反向传播)、可编码结构先验(CNN/LSTM)、可大规模运行(数据+算力+地基)、可统一为注意力(Transformer)、可大规模预训练(BERT/GPT)、可预测地放大(scaling laws)、可对齐于人(RLHF)——都是在回答同一个问题的一个侧面:如何让一台只会做加法和乘法的机器,逐步逼近“理解”与“生成”。这条感知与生成的主线走到今天的逻辑,已经清晰可辨;而另一条关于“决策与行动”的主线,将从下一章重新展开,并最终与它合流。


本质

scaling laws 与 RLHF 解决的是两个截然不同、却同样根本的问题。scaling laws 把“做更大的模型值不值得”从一场昂贵的赌博,变成了一道可外推的工程预算题——损失随规模的下降是一条幂律直线,于是你能在投入巨额算力之前就预测它会换来多少性能,这是 GPT-3 之后所有大模型敢于持续投入的底气。RLHF 解决的则是另一回事:预训练让模型学会了“人类文本的分布”,但“最可能的下一个词”并不等于“人类真正想要的回答”。它的办法是把难以写成损失函数的人类偏好,转译成一个可优化的奖励信号——人只需说“A 比 B 好”,就能训出一个会打分的奖励模型,再用强化学习把策略推向高分区。一个让能力可预测地变强,一个让变强的能力对齐到人的意图;正是后者第一次把第十二章起的那条强化学习主线,借进了语言模型的世界。


参考文献

  1. Kaplan, J., McCandlish, S., Henighan, T., Brown, T. B., Chess, B., Child, R., Gray, S., Radford, A., Wu, J., & Amodei, D. (2020). Scaling Laws for Neural Language Models. 幂律 L(N)、跨 7+ 数量级、结构细节影响小、算力最优分配(~73/27)。arXiv:https://arxiv.org/abs/2001.08361

  2. Brown, T. B., et al. (2020). Language Models are Few-Shot Learners(GPT-3, 175B 参数, 上下文学习)。arXiv:https://arxiv.org/abs/2005.14165 ;NeurIPS 2020:https://papers.nips.cc/paper/2020/hash/1457c0d6bfcb4967418bfb8ac142f64a-Abstract.html

  3. Hoffmann, J., et al. (2022). Training Compute-Optimal Large Language Models(Chinchilla)。参数与数据同比缩放、多数模型欠训练、70B Chinchilla 胜 280B/175B/530B。arXiv:https://arxiv.org/abs/2203.15556

  4. Christiano, P. F., Leike, J., Brown, T. B., Martic, M., Legg, S., & Amodei, D. (2017). Deep Reinforcement Learning from Human Preferences. 从成对偏好学奖励、<1% 反馈解 Atari/机器人。arXiv:https://arxiv.org/abs/1706.03741

  5. Ouyang, L., et al. (2022). Training Language Models to Follow Instructions with Human Feedback(InstructGPT)。三步 SFT→RM→PPO、Bradley-Terry 偏好、1.3B 对齐胜 175B GPT-3、ChatGPT 技术底座。arXiv:https://arxiv.org/abs/2203.02155 ;PDF:https://arxiv.org/pdf/2203.02155

强化学习地基:从 Bellman 方程到 Q-learning

前面十一章讲的是同一件事的不同侧面:怎么让神经网络从一堆带标签的数据里学到一个函数——给图片输出类别,给句子输出下一个词。但有一类问题根本没有标签。下棋时没有人告诉你“这一步的正确答案是什么”,只有在几十步之后才知道是输是赢;机器人走路时没有人逐帧标注“这条腿应该抬多高”,只有摔倒或前进的结果。这类问题的学习对象不是“输入到输出的映射”,而是“在一连串决策中如何最大化长期回报”。它有自己的一套数学语言——马尔可夫决策过程与 Bellman 方程,自己的一支算法谱系,以及自己的巅峰时刻。这一章从最朴素的问题形式化讲起,推导出价值的递归结构,再讲清楚 Q-learning 如何在不知道环境规则的情况下,仅凭试错就逼近最优决策。这是与前十一章正交的第三条主线的起点。


把问题先摆清楚。强化学习(reinforcement learning, RL)研究的是一个智能体(agent)在一个环境(environment)中反复决策的过程。每一步,智能体观察到当前的状态 ss,选择一个动作 aa,环境根据某种规则转移到新状态 ss',并返回一个奖励(reward)rr。智能体的目标不是让某一步的奖励最大,而是让从现在到未来的累计奖励最大。

这个框架的标准形式叫马尔可夫决策过程(Markov Decision Process, MDP),它由五个部分组成:状态集合 𝒮\mathcal{S}、动作集合 𝒜\mathcal{A}、转移概率 P(ss,a)P(s'\mid s,a)、奖励函数 r(s,a)r(s,a)、以及折扣因子 γ[0,1)\gamma\in[0,1)。“马尔可夫”的意思是:下一个状态只依赖当前状态和当前动作,而与更早的历史无关——当前状态已经包含了做决策所需的全部信息1

为什么需要折扣因子 γ\gamma?因为如果智能体永远活下去,累计奖励可能是无穷大,无法比较两个策略的好坏。引入 γ\gamma 后,回报(return)被定义为从时刻 tt 起所有未来奖励的折扣和:

Gt=rt+γrt+1+γ2rt+2+=k=0γkrt+k G_t = r_{t} + \gamma\, r_{t+1} + \gamma^2 r_{t+2} + \cdots = \sum_{k=0}^{\infty} \gamma^k\, r_{t+k}

γ\gamma 越接近 1,智能体越看重长远;γ\gamma 越小,越短视。这个看似技术性的选择,其实编码了一个深刻的态度:未来的奖励值多少现在的奖励。

智能体的行为由一个策略(policy)π(as)\pi(a\mid s) 描述——在状态 ss 下选择各动作的概率。强化学习的全部任务,就是找到一个能让期望回报最大的策略 π*\pi^*


直接搜索“最好的策略”是个天文数字级别的问题——策略的数量随状态和动作的数量指数爆炸。强化学习之所以可行,靠的是一个递归结构:价值函数

定义状态 ss 在策略 π\pi 下的价值 Vπ(s)V_\pi(s) 为“从 ss 出发、按 π\pi 行动,能拿到的期望回报”:

Vπ(s)=𝔼π[Gtst=s] V_\pi(s) = \mathbb{E}_\pi\!\left[\, G_t \mid s_t = s \,\right]

类似地,定义动作价值 Qπ(s,a)Q_\pi(s,a) 为“在 ss 先做动作 aa、之后按 π\pi 行动的期望回报”。

这两个量的关键性质,是它们满足一个递归方程。把回报 Gt=rt+γGt+1G_t = r_t + \gamma G_{t+1} 这条定义代进去,价值就能写成“当前一步的即时奖励,加上折扣后的下一状态价值”1

Vπ(s)=aπ(as)sP(ss,a)[r(s,a)+γVπ(s)] V_\pi(s) = \sum_a \pi(a\mid s) \sum_{s'} P(s'\mid s,a)\,\big[\, r(s,a) + \gamma\, V_\pi(s') \,\big]

这就是Bellman 期望方程。它把一个关于“无穷未来”的量,化简成了一个只涉及“当前与下一步”的自洽关系。这个递归结构,是 Richard Bellman 在 1950 年代研究动态规划(dynamic programming)时奠定的——他证明,很多看似需要枚举所有未来路径的最优化问题,都能拆解成一系列重叠的子问题,并通过这种递归关系高效求解1

我们真正想要的是最优价值。最优策略下的价值 V*V^* 满足Bellman 最优方程——它把“对所有动作求平均”换成了“取最好的那个动作”:

V*(s)=maxasP(ss,a)[r(s,a)+γV*(s)] V^*(s) = \max_a \sum_{s'} P(s'\mid s,a)\,\big[\, r(s,a) + \gamma\, V^*(s') \,\big]

对动作价值也一样:

Q*(s,a)=sP(ss,a)[r(s,a)+γmaxaQ*(s,a)] Q^*(s,a) = \sum_{s'} P(s'\mid s,a)\,\big[\, r(s,a) + \gamma\, \max_{a'} Q^*(s',a') \,\big]

最优方程的意义在于:一旦你知道了 Q*Q^*,最优策略就是平凡的——在每个状态选 Q*Q^* 最大的那个动作。问题从“搜索最好的策略”转化成了“求解这个不动点方程”。


如果环境的规则(转移概率 PP 和奖励 rr)完全已知,求解 Bellman 最优方程有现成办法——值迭代(value iteration):把方程当作一个更新规则,反复用右边算左边,价值估计会收敛到 V*V^*。这是动态规划的标准结果1

但现实里,智能体往往不知道环境的规则。一个下棋的程序也许知道规则,但一个学走路的机器人不知道“这样发力会怎样”;一个玩陌生游戏的智能体不知道每个动作会把它带到哪里。它只能——做一个动作,看环境给什么反馈,从经验里学。这就是强化学习区别于动态规划的地方:在不知道模型的情况下,仅凭采样到的经验逼近最优价值

最早把这个想法系统化的,是 Richard Sutton 在 1988 年提出的时序差分(temporal-difference, TD)学习2。Sutton 的洞察非常漂亮:传统的预测学习,是等到最终结果出来,再用“预测值与真实结果之差”去修正。但 TD 不必等到最后——它用相邻两次预测之差来学习。

具体说,假设我在状态 ss 估计价值是 V(s)V(s),走一步到 ss' 拿到奖励 rr,那么 r+γV(s)r + \gamma V(s') 是对同一个量 V(s)V(s) 的一个更新的、更靠近真相的估计(因为它多观察了一步真实奖励)。两者之差

δ=r+γV(s)V(s) \delta = r + \gamma V(s') - V(s)

TD 误差。它衡量“我原来的预测错了多少”。学习就是朝着消除这个误差的方向,微调 V(s)V(s)

V(s)V(s)+αδ V(s) \leftarrow V(s) + \alpha\,\delta

其中 α\alpha 是学习率。这个更新的妙处在于:它不需要知道环境模型(只用了实际采样到的 rrss'),也不需要等到一局结束(走一步就能更新)。Sutton 还提出了一个推广 TD(λ\lambda),用一个叫 eligibility trace 的机制,在“只看一步”(TD(0))和“看到结束”(蒙特卡洛)之间平滑插值2。这条 TD 误差,后来成了几乎所有现代强化学习算法的心跳。


TD 学的是状态价值 VV,但 VV 不足以直接做决策——知道一个状态值多少钱,还不知道该往哪走(那需要环境模型告诉你每个动作会到哪个状态)。要绕开模型直接学“该怎么做”,得学动作价值 QQ

1989 年,剑桥的 Christopher Watkins 在博士论文里提出了Q-learning3。它把 TD 的思想用到了 QQ 上,而且做了一个关键的设计——更新目标里用的是 max\max

Q(s,a)Q(s,a)+α[r+γmaxaQ(s,a)Q(s,a)] Q(s,a) \leftarrow Q(s,a) + \alpha\,\big[\, r + \gamma \max_{a'} Q(s',a') - Q(s,a) \,\big]

读懂这个式子,就读懂了价值型强化学习的核心。智能体在 ss 做了动作 aa,观察到奖励 rr 和新状态 ss'。它构造一个 TD 目标 r+γmaxaQ(s,a)r + \gamma \max_{a'} Q(s',a')——意思是“这一步实际拿到 rr,加上从 ss' 出发最好能拿到的折扣价值”。然后把 Q(s,a)Q(s,a) 朝这个目标拉近一点。

这里的 max\max 是 Q-learning 被称为 off-policy(异策略) 的原因:无论智能体实际怎么走(它可能在随机探索),它学习的目标始终瞄准“如果之后都走最优会怎样”。换句话说,它可以一边用一个充满探索的、不那么聪明的策略去收集经验,一边学出那个最优策略。这种“行为策略”与“目标策略”的分离,是 Q-learning 极其实用的原因。

Watkins 与 Peter Dayan 在 1992 年给出了完整的收敛证明:只要所有状态-动作对被反复采样、价值用离散表格表示、学习率满足标准条件,Q-learning 就以概率 1 收敛到最优动作价值 Q*Q^*3。这是强化学习史上第一批坚实的理论保证之一——它告诉人们,纯靠试错、不知道环境规则,也能可证明地学到最优。


把 Q-learning 跑出来,比公式更能说明问题。配套代码 code/12_q_learning_gridworld.py(纯 numpy)造了一个 4×4 的网格世界:起点在左上,目标(奖励 +1)在右下,右上角有个陷阱(奖励 −1),中间有两堵墙。智能体不知道任何规则——它甚至不知道哪里是陷阱、哪里是墙,只能撞上去、掉进去,从奖励里学。每走一步还有 −0.04 的小惩罚,逼它学会走捷径。

ε\varepsilon-贪婪做探索(大部分时候选当前最优动作,偶尔随机乱走以发现新路),训练四千局后:

状态价值 V(s) = max_a Q(s,a):
   +0.59  +0.67  +0.74  +0.67
   +0.67   ###   +0.82  +0.00
   +0.74   ###   +0.91  +1.00
   +0.82  +0.91  +1.00  +0.00

贪婪策略(每格最优动作箭头):
   →  →  ↓  ←
   ↓  #  ↓  T
   ↓  #  ↓  ↓
   →  →  →  G

几件事值得看。第一,价值呈现出清晰的梯度——离目标越近的格子价值越高,像一座从目标 G 向外缓降的山。这正是 Bellman 方程的几何含义:每个格子的价值,等于它能通向的最好邻居的折扣价值。第二,策略箭头形成了一条绕过墙、避开陷阱、流向目标的水流——智能体从没被告知“T 是陷阱”,它只是从一次次 −1 里学会了远离右上角。第三,平均回报从前 200 局的 +0.617 升到末 200 局的 +0.745,它确实在变好。

这个小程序里没有神经网络,QQ 就是一张 4×4×4 的表格。但它已经包含了强化学习最核心的循环:用 TD 误差,把试错得来的零散奖励,回传成一张关于“每个状态每个动作值多少”的地图


表格型 Q-learning 有一个致命的天花板:它要为每个状态-动作对单独存一个数。网格世界有 16 个格子还行,但围棋有 1017010^{170} 种局面,Atari 游戏的一帧画面有 256100000256^{100000} 种可能像素组合——表格根本存不下,更不可能每个都采样到。

这正是神经网络要登场的地方。如果把 Q(s,a)Q(s,a) 不再当作一张表,而是当作一个函数——输入状态、输出每个动作的价值——那就可以用一个神经网络去逼近它。相近的状态会被网络映射到相近的价值,于是智能体能把在一个局面学到的东西泛化到从没见过的局面。这就是从“表格型强化学习”到“深度强化学习”的跨越。

但这一步并不平凡。前面第二章讲反向传播时,监督学习的目标值是固定的标签;而在 Q-learning 里,更新目标 r+γmaxaQ(s,a)r + \gamma\max_{a'}Q(s',a') 本身就含有正在被训练的那个 QQ——你在追一个随自己移动的靶子。再加上强化学习采样到的相邻经验高度相关(连续几帧画面几乎一样),直接把神经网络塞进 Q-learning 会震荡、发散。整个 2000 年代,“用神经网络做 Q-learning”一直被认为是不稳定的。

这条暗线其实早有一个反例。1992 至 1995 年,IBM 的 Gerald Tesauro 用一个多层神经网络加 TD(λ\lambda),做出了 TD-Gammon——一个只靠和自己对弈、从零学起的西洋双陆棋程序,最终达到接近世界顶尖人类的水平,还下出了一些人类高手从未考虑、后来被证明更优的招法4。TD-Gammon 已经是“神经网络 + 时序差分 + 自我对弈”的完整配方,被后来的 DQN 和 AlphaGo 论文反复引为先声。但它当时被认为是双陆棋特有的幸运——这个游戏的骰子随机性恰好平滑了价值曲面,让神经网络好训。如何让这套配方在没有骰子、训练曲面崎岖的一般问题上也稳定工作,要再等将近二十年。

下一章讲的,就是 2013 到 2015 年 DeepMind 如何用两个朴素却关键的工程技巧——经验回放与目标网络——驯服了“神经网络 + Q-learning”,让一个智能体从原始像素学会打几十种 Atari 游戏,把这条沉睡了二十年的主线重新点燃。

配套的 manim 动画 assets/manim/ch12_q_learning.pyValueDiffusion Scene)把 Bellman 更新的几何含义演出来:在一个 5×5 网格里,价值从带 +1 奖励的目标格出发,沿 Bellman 方程一圈圈“回灌”到邻近格子,绿色越来越深、红色标出陷阱;价值场成形后,每格朝价值最高的邻居指出一支箭头——贪婪策略就这样从价值里自然涌现出来。


本质

强化学习的全部出发点,是一个监督学习里没有的难题:没有人告诉你每一步的正确答案,你只能在很久之后收到一个总的回报,还得自己把功劳分摊回沿途每一个动作。Bellman 方程给出的解法是一个递归——一个状态的价值,等于即时奖励加上后继状态价值的折扣;价值不必一次算出,可以从有奖励的地方一圈圈向外回灌(动态规划),也可以在不知道环境规则时,用实际走出来的下一步去估计、边走边修正(时序差分)。Q-learning 的精妙在于它甚至不需要先有一个好策略:它直接学每个“状态-动作”对的最优价值,因此一边用着次优策略探索、一边却朝着最优价值收敛。它真正解决的,是“如何在延迟、稀疏、且依赖自身未来估计的反馈下,仍然学到该怎么行动”——这正是把“决策”变成可学习问题的地基。


参考文献

  1. Sutton, R. S., & Barto, A. G. (2018). Reinforcement Learning: An Introduction (2nd ed.). MIT Press. ISBN 9780262039246. MDP、回报 GtG_t、价值函数、Bellman 期望/最优方程、动态规划与值迭代的标准教科书出处;Bellman 1957《Dynamic Programming》与 Samuel 1959 跳棋程序的历史脉络见该书 §1.7、§3–4。MIT Press:https://mitpress.mit.edu/9780262039246/reinforcement-learning/ ;作者官方全文:http://incompleteideas.net/book/the-book-2nd.html

  2. Sutton, R. S. (1988). Learning to Predict by the Methods of Temporal Differences. Machine Learning, 3, 9–44. TD 由相邻预测之差驱动;TD(λ) 用 eligibility trace 在 TD(0) 与蒙特卡洛之间插值。PDF:http://incompleteideas.net/papers/sutton-88.pdf ;Springer:https://link.springer.com/article/10.1007/BF00115009

  3. Watkins, C. J. C. H., & Dayan, P. (1992). Q-learning. Machine Learning, 8, 279–292. Q-learning 由 Watkins 1989 博士论文提出、本文给出完整收敛证明:所有 (s,a) 反复采样、离散表示、学习率满足标准条件时以概率 1 收敛到 Q*Q^*。PDF(Dayan 主页):https://www.gatsby.ucl.ac.uk/~dayan/papers/cjch.pdf ;Springer:https://link.springer.com/article/10.1007/BF00992698

  4. Tesauro, G. (1995). Temporal Difference Learning and TD-Gammon. Communications of the ACM, 38(3), 58–68. MLP + TD(λ) 纯自博弈(v2.1 训练 150 万局)达接近世界顶尖人类水平,下出新招;被 DQN/AlphaGo 引为早期 NN+RL 标志性成功。ACM:https://dl.acm.org/doi/10.1145/203330.203343 ;全文镜像:https://bkgm.com/articles/tesauro/tdl.html

DQN 与 Atari:让神经网络学会打游戏

上一章结尾留下一个悬念:把 Q 值从表格换成神经网络,理论上能让强化学习泛化到围棋、游戏这样天文数字级别的状态空间,但实践中这条路在 2000 年代一直被认为是不稳定的——目标在动,样本相关,网络一训就发散。2013 到 2015 年,DeepMind 一支小团队用两个朴素到几乎“工程取巧”的技巧解决了这个问题,做出了 DQN(Deep Q-Network):一个直接盯着屏幕像素、不被告知任何游戏规则、仅靠分数反馈,就学会打几十种 Atari 游戏的智能体,其中近半数达到甚至超过人类玩家水平。这是深度强化学习真正的引爆点。这一章讲清楚 DQN 的网络结构、那条把损失写成回归问题的关键公式、经验回放与目标网络各自解决了什么,以及它为什么标志着一个范式的诞生。


先把舞台搭好。2012 年前后,有一个叫 Arcade Learning Environment 的研究平台,把几十款 1970 至 80 年代的 Atari 2600 游戏(打砖块、太空侵略者、乒乓、吃豆人等)包装成统一的强化学习接口:每一帧,智能体看到的是一张 210×160 的游戏画面,能做的是几个手柄动作(上下左右、开火),环境返回的是游戏分数的变化。

这个设定的迷人之处,在于它的通用性。同一套算法、同一个网络结构,不针对任何一款游戏做特别设计,要能玩几十款规则、目标、画面完全不同的游戏。打砖块要把球弹上去,太空侵略者要躲子弹打外星人,赛车要沿赛道开——如果一个智能体只靠看像素和分数就能全部学会,那它学到的就不是某个游戏的技巧,而是某种更一般的“从感知到决策”的能力。

2013 年,Volodymyr Mnih 等人(当时在 DeepMind)发表了《用深度强化学习玩 Atari》,第一次做到了这件事1。论文标题里“直接从高维感官输入学习控制策略”这句话,是对整个领域的宣告:在此之前,强化学习要么用在状态可以手工设计成几个数字的小问题上,要么依赖人类先把原始输入加工成特征。DQN 把这两步合一了——卷积网络负责“看懂画面”,Q-learning 负责“决定怎么动”,端到端一起训练。


DQN 的网络结构,是第三章讲的卷积网络与本卷强化学习的直接嫁接。输入不是单帧,而是把最近 4 帧画面叠在一起(这样网络能感知运动方向和速度——单看一帧无法判断球在往哪飞),经过几层卷积提取空间特征,再接全连接层,最后一层输出每个动作的 Q 值1

注意这个输出设计的巧妙:网络不是输入“状态+动作”输出一个 Q 值,而是输入状态、一次性输出所有动作的 Q 值。这样选动作只需前向传播一次(取输出最大的那个动作),不必对每个动作各跑一遍网络——在动作多、要实时决策的游戏里,这个效率差别很关键。

训练目标,就是上一章那条 Q-learning 更新,被改写成了一个回归问题。对采样到的一条经验 (s,a,r,s)(s,a,r,s'),构造目标值

y=r+γmaxaQ(s,a;θ) y = r + \gamma \max_{a'} Q(s',a';\theta)

然后让网络的输出 Q(s,a;θ)Q(s,a;\theta) 去回归这个 yy,损失就是均方误差:

L(θ)=(yQ(s,a;θ))2 L(\theta) = \big(\, y - Q(s,a;\theta) \,\big)^2

θ\theta 求梯度、反向传播、梯度下降——和第二章训练任何监督网络的流程一模一样。强化学习在这里被巧妙地转化成了一连串监督回归:每一步用“即时奖励 + 下一状态的最优估值”现造一个标签,让网络去拟合。

但正是这个“现造标签”埋着两颗雷。


第一颗雷:样本相关性。强化学习的经验是一条连续的轨迹,相邻几帧画面几乎一样,连续的状态、动作、奖励高度相关。而神经网络的训练(随机梯度下降)有一个隐含假设——每个小批量的样本应该是独立同分布的。如果你按时间顺序、用连续相关的样本去训练,网络会被最近这一小段经历带偏,学了新的忘了旧的,剧烈震荡。

DQN 的解法叫经验回放(experience replay)1。智能体不立即用刚产生的经验去训练,而是把每条 (s,a,r,s)(s,a,r,s') 存进一个很大的缓冲区(buffer)。训练时,从缓冲区里随机抽取一个小批量来更新网络。随机抽样打散了时间顺序——一个批量里可能混着十分钟前和一秒前的经验、不同游戏阶段的片段——大大降低了样本间的相关性,让训练回到接近独立同分布的假设。

经验回放还附带一个好处:样本复用。一条经验进了缓冲区,会被随机抽中很多次,反复参与训练。在和真实环境交互很昂贵(每一步都要实际玩一帧游戏)的强化学习里,这种数据效率的提升非常实在。这个想法本身不是 DQN 首创(经验回放早在 1990 年代就有人提出),但 DQN 把它和深度网络结合,证明了它是稳定训练的关键一环。


第二颗雷更微妙:目标在动。回到那条损失 L=(yQ(s,a;θ))2L = (y - Q(s,a;\theta))^2,目标 y=r+γmaxaQ(s,a;θ)y = r + \gamma\max_{a'}Q(s',a';\theta) 里也含着 θ\theta。也就是说,你每更新一次网络参数 θ\theta,你正在追的那个目标 yy 自己也跟着动了。这就像你想射中一个靶子,可每当你瞄准、扣下扳机的瞬间,靶子就朝你瞄的方向挪一下——很容易陷入正反馈式的震荡或发散。

2015 年发表在《自然》上的 DQN 升级版,给出了第二个关键技巧:目标网络(target network)2。具体做法是维护两份网络:一份是不断更新的“在线网络”Q(;θ)Q(\cdot;\theta),另一份是参数被周期性冻结的“目标网络”Q(;θ)Q(\cdot;\theta^-)。计算 TD 目标时,用冻结的目标网络:

y=r+γmaxaQ(s,a;θ) y = r + \gamma \max_{a'} Q(s',a';\theta^-)

在线网络照常每步更新,但目标网络的参数 θ\theta^- 每隔固定步数(比如一万步)才从在线网络复制一次。这样,在两次同步之间,靶子是静止的——网络在追一个不动的目标,训练稳定下来;隔一段时间,把这个目标更新到当前更准的估计上,再静止一段。这个简单的“冻结—追赶—再冻结”节奏,是 DQN 从“能跑通几个游戏”到“稳定玩 49 个游戏达人类水平”的分水岭。

2015 年那篇《自然》论文的标题是《通过深度强化学习达到人类水平的控制》2。同一套网络、同一组超参数,不为任何游戏单独调整,在 49 款 Atari 游戏上测试——智能体在其中过半数的游戏里达到或超过专业人类玩家的水平,有些游戏(如打砖块)它甚至发现了人类没想到的策略:先在墙的一侧凿穿一条通道,把球送到砖块后面,让球在顶部来回弹射、自动清场。


把目标网络和经验回放这两个机制写进代码,比文字更清楚。配套的 code/14_dqn_min.py(纯 numpy,手写单隐层网络与反向传播)在上一章那个 4×4 网格世界上,搭了一个最小可运行的 DQN。状态被编码成长度 16 的 one-hot 向量喂给网络,网络输出 4 个动作的 Q 值。训练循环里两个机制清晰可见:

经验回放——每走一步,把 (s,a,r,s,done)(s,a,r,s',\text{done}) 存进 buffer,然后从缓冲区随机抽 32 条做一个小批量训练,而不是用刚刚那一步:

buffer.append((s, a, r, ns, done))
idx = rng.choice(len(buffer), batch, replace=False)   # 随机抽样去相关
...
td_target = R + gamma * np.max(target.forward(NS), axis=1) * (1 - D)

目标网络——TD 目标用一份独立的 target 网络算,它每隔 50 局才从在线网络同步一次参数:

if ep % target_sync == 0:
    target.copy_from(online)     # 周期性冻结/同步,稳住靶子

训练一千五百局后,网络学出的贪婪策略:

   ↓  ↓  ↓  ←
   ↓  #  ↓  T
   ↓  #  →  ↓
   →  →  →  G

从任何一格出发,沿箭头走都能绕开墙、避开陷阱 T、流向目标 G。这个小程序当然玩不了 Atari——真正的 DQN 网络深得多、缓冲区存上百万条经验、训练上千万帧。但它和那个登上《自然》封面的智能体共享完全相同的骨架:一个神经网络逼近 Q,经验回放喂给它去相关的批量,目标网络给它一个暂时不动的靶子


DQN 之后,研究者很快发现这个基础版本有不少可改进处,于是衍生出一整条改进谱系,几年内把 Atari 上的表现一路推高。

高估偏差。Q-learning 的更新用了 max\max,而 max\max 一个含噪声的估计会系统性地偏高——总是挑出那些“恰好被高估”的动作。2015 年的 Double DQN 用一个简单的拆分缓解这个问题:用在线网络最优动作,用目标网络评估这个动作的价值,把“选”和“评”解耦,显著减小了过度乐观3

价值与优势分离。很多状态下,做哪个动作其实差别不大,真正重要的是“这个状态本身好不好”。2016 年的 Dueling DQN 把网络拆成两个头,分别估计状态价值 V(s)V(s) 和每个动作相对的优势 A(s,a)A(s,a),再合成 Q(s,a)=V(s)+A(s,a)Q(s,a)=V(s)+A(s,a)——让网络能高效地学“这个局面值不值”,而不必为每个动作各学一遍4

不是所有经验一样重要。基础版经验回放是均匀随机抽样,但有些经验(TD 误差大的、出乎意料的)信息量更高。2015 年的优先经验回放(Prioritized Experience Replay)按 TD 误差大小给经验加权,让“意外”的经验被更频繁地回放,在 49 个游戏中的 41 个上超过均匀回放5

学分布而非期望。2017 年的 C51 提出一个更激进的视角:不要只估计回报的期望 QQ,而要估计回报的整个概率分布——同样是平均赢 10 分,“稳定赢 10 分”和“一半时候赢 20、一半输 0”是不同的,分布信息能让学习更稳健6。这开启了分布式强化学习这一支。

2018 年,DeepMind 的 Rainbow 把上述这些改进——Double、Dueling、优先回放、C51、多步回报、噪声网络——全部组合进一个智能体,在 Atari 基准上集大成,验证了这些改进大体是互补而非冲突的7。Rainbow 这个名字本身就是个隐喻:深度强化学习的进步,很多时候不是单个惊艳的新想法,而是一组朴素改进的稳健叠加。


退一步看 DQN 在这部技术史里的位置。它证明的核心命题是:第三章的卷积网络(负责感知)和第十二章的 Q-learning(负责决策)可以端到端地焊接在一起,用反向传播一并训练。 在它之前,“看懂世界”和“在世界里行动”是两个分开的研究领域;DQN 让一个智能体直接从原始像素学到了行动策略,把感知与决策第一次真正打通。

但 DQN 这一支有它的局限。它学的是动作价值 QQ,天然适合离散、有限的动作空间(Atari 手柄就那么几个键)。可现实里有大量连续控制问题——机器人的关节要转多少度、油门踩多深、方向盘打多少角度——动作是连续的实数,无法对所有动作取 max\max。对这类问题,与其费力地学一个 QQ 再从中挑动作,不如直接学一个策略:输入状态,输出动作(或动作的概率分布)。

这就把我们带回上一章末尾提过的另一条线索——策略梯度。它不绕道价值,而是直接对“策略”这个函数做梯度上升。下一章从 1992 年的 REINFORCE 讲起,经过策略梯度定理、actor-critic 架构、信赖域方法,一直讲到 PPO——那个先被用来打游戏、后来又被搬去对齐语言模型(第十一章的 RLHF)的算法。两条线,将在那里第一次交汇。

配套的 manim 动画 assets/manim/ch13_dqn.pyReplayBufferTargetNetwork 两个 Scene)把两个稳定机制演出来:前者展示智能体产生的连续经验(时间上强相关)落入回放池被打散,训练时随机抽一个 minibatch、近似独立——打破相关性;后者展示在线网络不断更新,而一份被冻结的目标网络负责给出 Bellman 目标 y=r+γmaxQ(θ)y=r+\gamma\max Q(\theta^-),在线网络去拟合这个不抖动的目标,每隔若干步才把参数复制过去——把发散的拟合变成稳定的回归。


本质

把神经网络直接塞进 Q-learning 之所以会发散,是因为它同时踩中了两个雷:一是强化学习采到的相邻样本高度相关,违背了梯度下降“样本近似独立”的隐含假设;二是它的回归目标里含着正在被训练的那个网络自己——你在追一个随自己移动的靶子。DQN 的两个机制恰好各拆一个雷:经验回放把经历存进一个池子、训练时随机抽样,把强相关的时间序列打散成近似独立的样本;目标网络冻结一份参数专门用来算目标,让靶子在一段时间内不动。它真正的贡献不是某个新的学习规则,而是让一个早已知道、却一直不稳定的组合(深度网络 + 时序差分)第一次能在一般问题上稳定收敛——并由此证明了一件更大的事:负责“看懂世界”的卷积网络和负责“在世界里行动”的 Q-learning,可以端到端地焊在一起,用同一套反向传播一并训练。感知与决策,第一次被真正打通。


参考文献

  1. Mnih, V., Kavukcuoglu, K., Silver, D., Graves, A., Antonoglou, I., Wierstra, D., & Riedmiller, M. (2013). Playing Atari with Deep Reinforcement Learning. NIPS 2013 Deep Learning Workshop. 首个从像素端到端学控制策略的深度模型;CNN 拟合 Q 值 + 经验回放;7 个 Atari 游戏,6 个超此前方法。arXiv:https://arxiv.org/abs/1312.5602

  2. Mnih, V., Kavukcuoglu, K., Silver, D., Rusu, A. A., Veness, J., Bellemare, M. G., Graves, A., Riedmiller, M., et al. (2015). Human-level control through deep reinforcement learning. Nature, 518, 529–533. 引入目标网络(周期性冻结 θ\theta^- 算 TD 目标)+ 奖励裁剪;同一套网络/超参在 49 个 Atari 游戏过半达人类水平。Nature:https://www.nature.com/articles/nature14236 ;PDF:https://web.stanford.edu/class/psych209/Readings/MnihEtAlHassibis15NatureControlDeepRL.pdf

  3. van Hasselt, H., Guez, A., & Silver, D. (2015/2016). Deep Reinforcement Learning with Double Q-learning. AAAI 2016. 用在线网络选动作、目标网络估值,拆解 max\max 导致的高估偏差。arXiv:https://arxiv.org/abs/1509.06461

  4. Wang, Z., Schaul, T., Hessel, M., van Hasselt, H., Lanctot, M., & de Freitas, N. (2016). Dueling Network Architectures for Deep Reinforcement Learning. ICML 2016. Q(s,a)=V(s)+A(s,a)Q(s,a)=V(s)+A(s,a) 双头分流,提升状态价值估计。arXiv:https://arxiv.org/abs/1511.06581 ;PMLR:https://proceedings.mlr.press/v48/wangf16.pdf

  5. Schaul, T., Quan, J., Antonoglou, I., & Silver, D. (2015). Prioritized Experience Replay. ICLR 2016. 按 TD 误差大小加权采样经验,41/49 游戏胜均匀回放。arXiv:https://arxiv.org/abs/1511.05952

  6. Bellemare, M. G., Dabney, W., & Munos, R. (2017). A Distributional Perspective on Reinforcement Learning. ICML 2017. 学回报的分布而非期望,分布式 Bellman 算子,51 个原子(C51)。arXiv:https://arxiv.org/abs/1707.06887

  7. Hessel, M., Modayil, J., van Hasselt, H., Schaul, T., Ostrovski, G., Dabney, W., Horgan, D., Piot, B., Azar, M., & Silver, D. (2018). Rainbow: Combining Improvements in Deep Reinforcement Learning. AAAI 2018. 合并 Double/Dueling/优先回放/C51/多步/噪声网络,Atari 集大成 SOTA。arXiv:https://arxiv.org/abs/1710.02298

策略梯度与 actor-critic:从 REINFORCE 到 PPO

前两章走的是“价值”这条路:先学每个状态每个动作值多少钱(Q 值),再从中挑最好的动作。但这条路对连续动作束手无策——机器人关节要转 37.2 度还是 37.3 度,你无法对无穷多个动作取最大值。还有一条更直接的路:不绕道价值,直接把“策略”本身当作一个带参数的函数,用梯度上升去调它,让能带来高回报的动作概率变大。这条路从 1992 年的 REINFORCE 算法起步,在 2000 年被 Sutton 等人提炼成一条干净的“策略梯度定理”,随后与价值方法融合成 actor-critic 架构,再经过信赖域、clip 这些为“稳定”而生的改进,最终收敛到 PPO——一个先被拿去打游戏、后来又被搬进语言模型对齐流程的算法。第十一章讲 RLHF 时一笔带过的那个“PPO”,到这一章会被完全讲清楚。两条主线,在这里第一次交汇。


先想清楚“直接学策略”是什么意思。在价值方法里,策略是隐式的——你学 QQ,策略只是“在每个状态选 QQ 最大的动作”这个附带操作。而在策略方法里,策略是显式的:用一个带参数 θ\theta 的函数 πθ(as)\pi_\theta(a\mid s) 直接表示“在状态 ss 下选各动作的概率”,这个函数可以就是一个神经网络。

这样做有几个直接的好处。对连续动作,网络可以直接输出一个高斯分布的均值和方差,从中采样出一个实数动作,根本不需要枚举或取 max\max。对需要随机性的任务(比如猜拳,确定性策略必输),策略方法天然输出概率分布。而且策略往往比价值函数更简单、更平滑——有时“该往右走”这件事很好学,但精确估计“往右走值多少钱”反而很难。

问题是:怎么训练它?我们想最大化的是期望回报

J(θ)=𝔼τπθ[G(τ)] J(\theta) = \mathbb{E}_{\tau\sim\pi_\theta}\big[\, G(\tau) \,\big]

其中 τ\tau 是一条按策略 πθ\pi_\theta 走出来的轨迹,G(τ)G(\tau) 是这条轨迹的回报。困难在于:回报依赖于环境怎么转移(这部分我们不知道、不可微),而轨迹的分布又依赖于 θ\theta。怎么对一个“采样分布本身依赖参数”的期望求梯度?


1992 年,Ronald Williams 给出了第一个答案——REINFORCE 算法1。他用了一个数学上叫“对数导数技巧”的恒等式,把对采样分布的梯度,转化成了一个可以采样估计的期望。结论极其简洁:

θJ(θ)=𝔼[θlogπθ(as)G] \nabla_\theta J(\theta) = \mathbb{E}\big[\, \nabla_\theta \log \pi_\theta(a\mid s)\, \cdot\, G \,\big]

读懂这一行,就读懂了所有策略梯度方法。它说:要让期望回报上升,就朝着 θlogπθ(as)\nabla_\theta\log\pi_\theta(a\mid s) 的方向调参数,并用这一步的回报 GG 作权重。直觉上——如果某个动作 aa 带来了高回报(GG 大且为正),就增大它的对数概率,让以后更可能选它;如果带来了负回报,就压低它的概率。回报的正负和大小,决定了“推”还是“拉”、推多用力。

而且注意:这个式子里没有环境转移的梯度。我们不需要知道环境怎么运作,只需要能采样轨迹、能对策略网络求梯度(这正是反向传播擅长的)。Williams 的原始论文标题朴素得很——《连接主义强化学习的简单统计梯度跟随算法》,并指出这类算法能“与反向传播自然结合”1。这句话在 1992 年还只是个理论提示,三十年后却成了训练每一个大模型对齐阶段的现实。

REINFORCE 有个明显的毛病:方差大。它用一整条轨迹的回报 GG 当权重,而回报受运气影响很大(同一个好动作,可能因为后面运气差而 GG 偏低),学习信号很噪。一个标准的降方差手段是引入基线(baseline):把权重从 GG 换成 Gb(s)G - b(s),其中 b(s)b(s) 是对该状态平均回报的估计。减去一个不依赖动作的基线不改变梯度的期望(数学上可证),却能大幅降低方差——它把“这个动作带来的回报”校准成“这个动作比平均好多少”。


REINFORCE 是个漂亮的直觉,但它的形式还不够一般。2000 年,Sutton、McAllester、Singh、Mansour 把它提炼成了策略梯度定理(policy gradient theorem)2。这条定理给出了策略梯度的精确、一般形式:

θJ(θ)=𝔼s,a[θlogπθ(as)Qπ(s,a)] \nabla_\theta J(\theta) = \mathbb{E}_{s,a}\big[\, \nabla_\theta \log \pi_\theta(a\mid s)\, \cdot\, Q^\pi(s,a) \,\big]

它和 REINFORCE 几乎一样,但把权重从“采样到的整条回报 GG”换成了“动作价值 Qπ(s,a)Q^\pi(s,a)”。更重要的是这条定理的一个深刻性质:梯度里不含状态分布对 θ\theta 的导数2。改变策略当然会改变你访问到哪些状态,但定理证明,那部分复杂的影响在求梯度时神奇地消失了,你只需关心“在每个状态如何调整动作概率”。这个结果让策略梯度方法有了坚实的理论地基,也允许用函数逼近(神经网络)来表示 QQ

把“用 QQ(或它的某种估计)当权重”这个思路落实下来,就得到了 actor-critic 架构——强化学习里最有生产力的设计之一。它有两个部件:

通常用的权重不是裸的 QQ,而是优势函数(advantage)A(s,a)=Q(s,a)V(s)A(s,a) = Q(s,a) - V(s)——“这个动作比该状态的平均水平好多少”。优势把价值的绝对高低剥离,只留下相对的好坏,正是降方差的基线思想的精确化。actor 朝 logπA\nabla\log\pi\cdot A 上升,critic 同时学着把 AA 估准,两者互相搀扶着进步。


用代码把策略梯度的内核走一遍。配套 code/13_reinforce_policy_gradient.py(纯 numpy)在一个长度为 7 的一维走廊上训练 REINFORCE:智能体从最左格出发,每步选“左”或“右”,走到最右格得 +1,其余每步 −0.05。策略是每个状态一组 softmax logits,参数就是这些 logits。核心更新只有几行:

adv = G[t] - (baseline[s] if use_baseline else 0.0)   # 优势 = 回报 - 基线
probs = softmax(theta[s])
grad = -probs; grad[a] += 1.0          # ∇logπ(a|s) = e_a - softmax
theta[s] += lr * adv * grad            # 策略梯度上升

grad = e_a − softmax 正是 softmax 策略的对数梯度的解析形式:被选中的动作 aa 那一项推高,其余按当前概率压低,再乘上优势作权重。跑出来:

[无 baseline] 平均回报 前100局=+0.501 -> 末100局=+0.736
       学到的贪婪策略(状态0..5): →→→→→→  (全 → = 一路向右最优)
[有 baseline] 平均回报 前100局=+0.452 -> 末100局=+0.732
       学到的贪婪策略(状态0..5): →→→→→→

两种设置最终都学到了“一路向右”这个最优策略——每个状态都把“右”的概率推到了 0.5 以上。这就是策略梯度最朴素的样子:没有 QQ 表、没有取 max\max,只是把“带来高回报的动作”的概率,一点点推高。在这么小的问题上 baseline 的方差优势看不太出来,但在动作多、轨迹长的真实任务里,优势函数对收敛速度的影响是决定性的。


朴素策略梯度有个让人头疼的实践问题:步子迈多大很难定。学习率太小,学得慢;太大,一次更新可能把策略推到一个很差的区域,而且因为后续数据都由这个变差的策略采集,可能再也爬不回来——监督学习里一次坏更新只是损失抖一下,强化学习里一次坏更新会污染之后的全部经验。

2015 年,John Schulman 等人提出 TRPO(Trust Region Policy Optimization,信赖域策略优化)来控制这个步长3。它的思想是:每次更新,在“新策略与旧策略的差异不超过一个信赖域”的约束下,最大化预期改进。差异用 KL 散度衡量:

maxθ𝔼̂[πθ(as)πθold(as)Â]s.t.𝔼̂[KL(πθoldπθ)]δ \max_\theta\ \ \hat{\mathbb{E}}\Big[\tfrac{\pi_\theta(a\mid s)}{\pi_{\theta_{\text{old}}}(a\mid s)}\,\hat A\Big] \quad \text{s.t.}\quad \hat{\mathbb{E}}\big[\mathrm{KL}(\pi_{\theta_{\text{old}}}\,\|\,\pi_\theta)\big]\le\delta

直觉是:在“离旧策略不太远”的安全范围内,尽量改进。这个约束保证了每一步都是稳健的小改进,不会一脚踏空。TRPO 在连续控制上效果很好,但代价是数学和实现都复杂——那个 KL 约束需要二阶优化(涉及 Fisher 信息矩阵的近似),又重又难调。

为了估计上式里的优势 Â\hat A,同年 Schulman 等人还提出了 GAE(Generalized Advantage Estimation,广义优势估计)4。它用一个参数 λ\lambda 把不同步数的 TD 误差加权求和:

ÂtGAE=l=0(γλ)lδt+l,δt=rt+γV(st+1)V(st) \hat A^{\text{GAE}}_t = \sum_{l=0}^{\infty} (\gamma\lambda)^l\, \delta_{t+l},\qquad \delta_t = r_t + \gamma V(s_{t+1}) - V(s_t)

λ\lambda 在偏差和方差之间插值——λ=0\lambda=0 就是单步 TD(偏差大、方差小),λ=1\lambda=1 接近蒙特卡洛(偏差小、方差大),中间值取得平衡。GAE 这个看似不起眼的工具,几乎成了之后所有策略梯度方法估计优势的标配。


TRPO 好用但太重。2017 年,Schulman 等人发表了 PPO(Proximal Policy Optimization,近端策略优化),用一个朴素得多的技巧达到了 TRPO 的大部分好处5

PPO 不再用复杂的 KL 硬约束,而是直接在目标函数里裁剪(clip)。设新旧策略的概率比 rt(θ)=πθ(atst)/πθold(atst)r_t(\theta) = \pi_\theta(a_t\mid s_t)\,/\,\pi_{\theta_{\text{old}}}(a_t\mid s_t),PPO 最大化:

LCLIP(θ)=𝔼̂t[min(rtÂt,clip(rt,1ϵ,1+ϵ)Ât)] L^{\text{CLIP}}(\theta) = \hat{\mathbb{E}}_t\Big[\ \min\big(\, r_t\,\hat A_t,\ \ \mathrm{clip}(r_t,\,1-\epsilon,\,1+\epsilon)\,\hat A_t \,\big)\ \Big]

读这个 min(,)\min(\cdot,\cdot):第一项 rtÂtr_t\hat A_t 是普通的策略梯度目标;第二项把概率比 rtr_t 强行限制在 [1ϵ,1+ϵ][1-\epsilon,\,1+\epsilon] 区间(ϵ\epsilon 通常取 0.2)。取两者的较小值,效果是:当某个动作的优势为正、模型想大幅提高它的概率时,一旦概率比超过 1+ϵ1+\epsilon,目标就被截平,再怎么推也没有额外收益——于是策略不会一步迈太远。它用一个一阶可优化(普通梯度下降就能跑)的裁剪目标,复现了 TRPO“小步快走”的稳定性,却简单到几十行就能实现5

PPO 因为这份“又稳又简单”,迅速成了强化学习的事实标准——从机器人控制到游戏智能体,到处都是它。也正因如此,当 OpenAI 在 2022 年做 RLHF、需要“用奖励模型给的分数去优化语言模型”时,他们顺手拿来的就是 PPO5。第十一章 RLHF 三步流程里的第三步——“用强化学习(PPO)优化语言模型,让它的回答尽量获得奖励模型的高分,同时加 KL 惩罚防止跑偏”——现在可以完全看懂了:那里的“策略”就是语言模型本身(在每个上下文下选下一个 token 的概率分布),“动作”是生成的 token,“奖励”来自奖励模型,“KL 惩罚防止跑偏”正是 PPO/TRPO 那条“别离旧策略太远”的信赖域思想的体现。一个 2017 年为打游戏而生的算法,五年后成了把 GPT-3 变成 ChatGPT 的关键工具。


策略梯度这一支还有两个值得一提的分支,它们和 PPO 并列,各自占住了不同的生态位。

A3C(Asynchronous Advantage Actor-Critic,异步优势 actor-critic),2016 年由 Mnih 等人提出6。它不用经验回放,而是开很多个并行的 worker,每个在自己的环境副本里跑,各自计算梯度、异步更新一个共享的全局网络。不同 worker 在不同游戏阶段、采集到的经验天然不相关——用并行性代替了经验回放来去相关。它的同步简化版 A2C 也被广泛使用。

SAC(Soft Actor-Critic,软 actor-critic),2018 年由 Haarnoja 等人提出7。它在最大化奖励之外,额外最大化策略的熵——也就是鼓励策略在能拿到好回报的前提下,尽量保持随机、多样。这个“最大熵”目标带来了更好的探索和鲁棒性,让 SAC 成为连续控制(尤其机器人)领域样本效率最高的算法之一。PPO 是 on-policy(只能用当前策略采的数据),SAC 是 off-policy(能复用历史经验,像 DQN 那样配经验回放),两者在不同场景各擅胜场。

到这里,强化学习的两大算法家族都铺好了:第十二、十三章的价值方法(TD/Q-learning/DQN 系),和这一章的策略方法(REINFORCE/PG 定理/actor-critic/PPO/SAC)。但这两家解决的,主要还是“在一个反应式环境里即时决策”的问题。有一类任务需要的更多——它需要向前搜索、推演对手的应对、在脑中模拟很多步之后再落子。把“学到的价值与策略”和“显式的前瞻搜索”结合起来,是下一章的主题,也是强化学习迄今最耀眼的成就:AlphaGo 一族。

配套的 manim 动画 assets/manim/ch14_policy_gradient.pyPolicyShapingBaselineVariance 两个 Scene)把策略方法的内核演出来:前者把策略画成动作空间上的一个概率分布,按“回报 × 对数概率梯度”更新,拿到正回报的动作概率被推高、负回报的被压低——策略分布被直接塑形;后者展示减去一个 baseline(如状态价值 VV)如何把“都偏正、彼此难分”的绝对回报,换成“有正有负、围绕 0”的相对优势 A=QVA=Q-V,期望梯度不变但方差大降——这正是 actor-critic 的核心。


本质

策略方法和价值方法的根本分歧,在于“学什么”:价值方法绕个弯,先学每个动作有多好、再从中挑最好的,因而天然只适合可以逐一比较的离散动作;策略方法则跳过这个中间量,直接把策略本身当作要优化的函数,对它的参数做梯度上升。策略梯度定理给出的,是一个看似不可能的东西——如何对一个“采样动作→获得回报”这种含随机性、不可微的过程求梯度;它的答案优雅得近乎朴素:朝着“提高那些带来高回报的动作的概率”的方向走。这把强化学习从“只能处理离散选择”解放到了连续控制的整个世界。而 actor-critic 与 baseline 解决的是它与生俱来的高方差顽疾:用一个学到的价值当参照系,让学习信号从“绝对回报”变成“比预期好还是差”。正是这一支里磨出的 PPO——一个在策略更新上加了信赖域约束、稳到可以无脑用的算法——后来被原样搬去对齐语言模型,成为两条主线交汇的桥。


参考文献

  1. Williams, R. J. (1992). Simple Statistical Gradient-Following Algorithms for Connectionist Reinforcement Learning. Machine Learning, 8, 229–256. 首个策略梯度算法 REINFORCE;权重沿期望回报梯度调整 Δθlogπr\Delta\theta\propto\nabla\log\pi\cdot r,无需显式估计梯度,可与反向传播自然结合。PDF:https://link.springer.com/content/pdf/10.1007/BF00992696.pdf ;abs:https://link.springer.com/article/10.1007/BF00992696

  2. Sutton, R. S., McAllester, D., Singh, S., & Mansour, Y. (2000). Policy Gradient Methods for Reinforcement Learning with Function Approximation. NIPS 1999/2000. 策略梯度定理 J=𝔼[logπQπ]\nabla J=\mathbb{E}[\nabla\log\pi\,Q^\pi];梯度不含状态分布对 θ\theta 的导数;可加 baseline 与函数逼近。PDF:https://web.eecs.umich.edu/~baveja/Papers/PolicyGradientNIPS99.pdf ;记录:https://www.cs.utexas.edu/~shivaram/readings/b2hd-SuttonMSM2000.html

  3. Schulman, J., Levine, S., Abbeel, P., Jordan, M., & Moritz, P. (2015). Trust Region Policy Optimization. ICML 2015. 用 KL 散度信赖域约束限制每步策略更新幅度,保证单调改进;需二阶优化。arXiv:https://arxiv.org/abs/1502.05477

  4. Schulman, J., Moritz, P., Levine, S., Jordan, M., & Abbeel, P. (2015). High-Dimensional Continuous Control Using Generalized Advantage Estimation. 用 λ\lambda 加权多步 TD 误差 ÂGAE=(γλ)lδt+l\hat A^{\text{GAE}}=\sum(\gamma\lambda)^l\delta_{t+l} 在偏差-方差间插值;成为策略梯度优势估计标配。arXiv:https://arxiv.org/abs/1506.02438

  5. Schulman, J., Wolski, F., Dhariwal, P., Radford, A., & Klimov, O. (2017). Proximal Policy Optimization Algorithms. clip 目标 min(rÂ,clip(r,1±ϵ)Â)\min(r\hat A,\mathrm{clip}(r,1\pm\epsilon)\hat A) 替代 TRPO 硬约束,一阶可优化、易实现,成事实标准;后被 RLHF(InstructGPT)用作第三步优化器。arXiv:https://arxiv.org/abs/1707.06347

  6. Mnih, V., Badia, A. P., Mirza, M., Graves, A., Lillicrap, T., Harley, T., Silver, D., & Kavukcuoglu, K. (2016). Asynchronous Methods for Deep Reinforcement Learning. ICML 2016. A3C:多 worker 并行异步更新共享网络,用并行性代替经验回放去相关。arXiv:https://arxiv.org/abs/1602.01783

  7. Haarnoja, T., Zhou, A., Abbeel, P., & Levine, S. (2018). Soft Actor-Critic: Off-Policy Maximum Entropy Deep Reinforcement Learning with a Stochastic Actor. ICML 2018. 最大熵目标(奖励 + 熵),off-policy actor-critic,连续控制样本效率 SOTA。arXiv:https://arxiv.org/abs/1801.01290

自博弈的巅峰:从 AlphaGo 到 MuZero

强化学习最广为人知的时刻,是 2016 年 3 月那个春天——一个叫 AlphaGo 的程序在首尔以 4:1 击败围棋世界冠军李世石。围棋曾被认为是 AI 难以攻克的最后堡垒:它的局面数量超过宇宙中的原子总数,且“哪一手好”极难用规则写死,长期被视为需要某种“直觉”的游戏。AlphaGo 的胜利不是靠蛮力穷举,而是把这部技术史里几条线拧成了一股绳:第三章的卷积网络负责“看懂棋盘的直觉”,前三章的强化学习负责“从自我对弈里学会评估”,再加上一种古老的前瞻搜索——蒙特卡洛树搜索。这一章讲清楚这套组合的内部机制:两个网络各自做什么、MCTS 如何被神经网络引导、PUCT 那条选择公式、自我对弈如何无中生有地越来越强,以及这条线如何从需要人类棋谱(AlphaGo)一路走到连规则都不需要给(MuZero)。


先理解围棋为什么难,才能看懂 AlphaGo 难在哪、巧在哪。

下棋本质上是一棵巨大的博弈树:当前局面是根,每一手棋是一个分叉,对手的应对又是分叉,层层展开。理论上,只要把这棵树完全展开到终局,就能算出每一手的胜负,选最优的走。国际象棋的程序(如 1997 年击败卡斯帕罗夫的“深蓝”)大致就是这么干的——靠强大的搜索加上人工设计的局面评估函数。

但围棋的树太宽太深。每一手大约有 250 种合法选择(国际象棋约 35 种),一盘棋约 150 手,完全展开是 250150250^{150} 这个量级——远超任何算力。更麻烦的是评估难:给定一个中盘局面,连职业棋手都很难说清“这局面值多少”,没有简单的子力计算能像国际象棋那样估出优劣。围棋的“好坏”高度依赖全局形势的微妙判断,长期被认为只能靠人类的“棋感”。

所以攻克围棋需要同时解决两个问题:怎么不展开整棵树也能聪明地搜索(应对宽和深),以及怎么评估一个局面的价值判断哪些手值得考虑(应对评估难)。AlphaGo 的答案,是用两个神经网络解决后者,用一种带引导的搜索解决前者。


2016 年发表在《自然》上的 AlphaGo 论文,核心是两个深度卷积网络1

策略网络(policy network)p(as)p(a\mid s):输入当前棋盘(当作一张多通道的“图像”),输出每个落点的概率——也就是“凭直觉,这些地方值得下”。它把 250 个选择缩小到少数几个候选,解决了树太宽的问题。

价值网络(value network)v(s)v(s):输入棋盘,输出一个标量——“从这个局面出发,当前方最终获胜的概率有多大”。它直接给出局面评估,解决了围棋难以估值的问题。

这两个网络怎么训练?AlphaGo 分了两步,这也是它和后续版本的关键区别。第一步,监督学习——用人类高手的几十万局棋谱,训练策略网络去模仿人类落子(这是个标准的分类问题:给棋盘,预测人类下在哪)。第二步,强化学习——让网络通过自我对弈(self-play)继续提升:两个当前策略互相下棋,赢的一方的落子被强化(这正是第十四章的策略梯度),同时用自我对弈产生的大量“局面—胜负”数据训练价值网络1

到这里 AlphaGo 有了“直觉”(策略网络)和“判断力”(价值网络)。但光有直觉还不够稳——直觉会看走眼。它还需要在落子前,真正地往前算几步、推演对手的应对。这就是搜索的部分。


AlphaGo 用的搜索叫蒙特卡洛树搜索(Monte-Carlo Tree Search, MCTS)。在讲它怎么和神经网络结合前,先说清楚 MCTS 本身。

传统的树搜索要展开所有分支,MCTS 不这样——它有选择地、逐步地生长一棵搜索树,把算力集中在最有希望的分支上。每一次模拟(simulation)走四步:

  1. 选择(selection):从根节点出发,沿着树往下走,每一步选一个“既看起来好、又没怎么试过”的动作,直到走到一个还没充分展开的节点。
  2. 扩展(expansion):在那里新增一个子节点。
  3. 评估(evaluation):估计这个新节点的价值(传统 MCTS 用随机模拟走到终局看胜负,AlphaGo 用价值网络直接给分)。
  4. 回传(backup):把这个评估值沿着刚才的路径回传上去,更新沿途每个节点的统计。

跑成千上万次模拟后,根节点下被访问次数最多的那个动作,就是 MCTS 推荐的落子——访问多意味着反复模拟都觉得它好。

第一步“选择”是 MCTS 的灵魂,它要平衡探索(试试没怎么走过的分支)和利用(多走已知好的分支)。这个平衡的理论根,是 2006 年 Kocsis 与 Szepesvári 提出的 UCT 算法——他们把多臂老虎机里的 UCB1 准则用到了树搜索上2。AlphaGo 用的是它的一个变体 PUCT,把策略网络的先验概率也加了进来:

a*=argmaxa[Q(s,a)+cP(s,a)bN(s,b)1+N(s,a)] a^* = \arg\max_a\ \Big[\ Q(s,a) + c\cdot P(s,a)\cdot \frac{\sqrt{\sum_b N(s,b)}}{1 + N(s,a)}\ \Big]

拆开看:Q(s,a)Q(s,a) 是这个动作目前模拟下来的平均价值(利用项);后一项是探索项——P(s,a)P(s,a) 是策略网络给的先验(“直觉觉得这手好”),N(s,a)N(s,a) 是访问次数。一个动作访问次数越少,探索项越大,越容易被再试;访问次数上来后,探索项衰减,决策转而由 QQ 主导。cc 调节探索的强度。这条公式让搜索被神经网络的直觉引导——策略网络先告诉搜索“往这几个方向看”,避免在 250 个选择里盲目铺开,价值网络则在叶子节点给出快速评估,不必每次都模拟到终局。


把 PUCT 引导的 MCTS 写成最小可运行的代码,能去掉很多神秘感。配套 code/15_mcts_puct.py(纯 numpy)用一个最简单的博弈“抢 21”(两人轮流报 1~3,累加,谁报到 21 谁赢)演示这套内核。它已知有必胜策略——抢到 1、5、9、13、17 的人锁定胜局,所以先手第一步应该报 1。

代码里的 PUCT 选择和四步循环:

def puct_select(node, c=1.5):
    total_N = sum(node.N.values())
    for m in node.N:
        q = node.W[m] / node.N[m] if node.N[m] > 0 else 0.0
        u = c * node.P[m] * np.sqrt(total_N + 1) / (1 + node.N[m])
        score = q + u            # PUCT = 利用 Q + 探索 c·P·√ΣN/(1+N)

把里面充当“价值网络”的叶子评估用精确解给出(演示理想化的 critic),跑 4000 次模拟,根节点各动作的访问统计:

  报 1: N= 3868  Q=+0.007
  报 2: N=   67  Q=-0.463
  报 3: N=   65  Q=-0.477
MCTS 选择的第一步: 报 1  (最优解=报1,使对手面对 20 必败)

搜索把绝大部分模拟(3868/4000)都投在了正确的那一手上——这就是 MCTS 的本事:它不均匀地展开所有分支,而是被价值评估和先验概率引导,把算力雪崩式地集中到好的方向。AlphaGo 做的事,本质上就是把这里理想化的“精确评估”换成价值网络的估计、把均匀先验换成策略网络的输出,在围棋这棵天文数字的树上跑同样的循环。代码注释里写得明白:“AlphaZero 把这里的随机 rollout 换成 value 网络,把均匀 P 换成 policy 网络。”


AlphaGo 击败李世石后,DeepMind 没有停步,而是开始做减法——一步步去掉系统里依赖人类知识的部分,看强化学习能纯靠自己走多远。

AlphaGo Zero(2017)3。它砍掉了那个最像“作弊”的部分——人类棋谱。AlphaGo Zero 完全从零开始,不看任何人类对局,只知道围棋规则,从随机乱下起步,纯靠自我对弈学习。结构也更简洁:策略和价值合并成一个网络(输出一个落子概率分布 pp 和一个价值 vv),且不再用 MCTS 之外的随机模拟,评估完全交给价值网络。

它的训练循环极其优雅,是这一章值得记住的核心:用当前网络引导 MCTS 下一盘自我对弈;MCTS 经过大量模拟后给出的落子分布,比网络自己的原始直觉 pp 更强(因为它做了前瞻搜索);于是把“网络的输出”朝“MCTS 的结果”训练——让策略去模仿搜索后的落子分布,让价值去预测这盘自我对弈的真实胜负。损失大致是:

=(zv)2𝝅log𝒑+cθ2 \ell = (z - v)^2 - \boldsymbol{\pi}^\top \log \mathbf{p} + c\lVert\theta\rVert^2

其中 zz 是自我对弈的真实结果(±1),vv 是价值网络的预测,𝝅\boldsymbol\pi 是 MCTS 给出的(更强的)落子分布,𝒑\mathbf p 是策略网络的原始输出。第一项让价值学准胜负,第二项让策略向“搜索增强后的自己”靠拢。这是一个自我提升的飞轮:网络引导搜索 → 搜索产生比网络更强的策略 → 用它来改进网络 → 更强的网络引导更强的搜索。AlphaGo Zero 从零开始训练几天,就超过了那个击败李世石的版本,且下出了许多人类几千年来未曾发现的定式3。它说明:人类棋谱不仅不是必需的,反而可能是一种束缚——纯自我对弈能探索到人类经验之外的空间。


减法还在继续。

AlphaZero(2018)4。它把 AlphaGo Zero 里任何围棋特有的处理也去掉,变成一个通用的自我对弈算法——同一套方法、同一种网络,不做任何针对性改动,分别学会了围棋、国际象棋和将棋,都达到或超过了各自领域此前最强的程序(国际象棋上击败了顶级引擎 Stockfish)。AlphaZero 证明了那个“自我对弈 + MCTS + 神经网络”的飞轮不是围棋专属,而是一个适用于一大类完美信息博弈的通用范式。

MuZero(2020)5。这是减法的极致——它连游戏规则都不给。前面所有版本都需要知道规则,因为 MCTS 要靠规则来推演“走这一手之后棋盘变成什么样”。MuZero 不知道规则,于是它自己学一个环境模型:不是去预测真实的下一帧画面(那既难又没必要),而是学一个隐空间里的动力学——给定当前隐状态和一个动作,预测下一个隐状态、即时奖励、以及策略和价值。然后 MCTS 就在这个学出来的隐空间模型里做前瞻搜索5

MuZero 的意义是把两条线接通了。前面的 AlphaGo 系是“已知模型 + 搜索”,第十三章的 DQN 系是“未知模型 + 无搜索的试错”。MuZero 是“学到的模型 + 搜索”——它在围棋、国际象棋、将棋上追平 AlphaZero,同时在 Atari 上(那里没有现成规则可用,正是 DQN 的地盘)也达到了顶尖水平。一个系统,既能下棋又能打游戏,靠的是“自己学一个够用的世界模型,然后在里面规划”。这个“学世界模型再规划”的思路,和第二十一类节点里 World Models、Dreamer 那条 model-based 强化学习的线索遥相呼应——它们都在赌一件事:智能体如果能在脑中模拟世界,就能比纯试错高效得多。


自我对弈的范式在棋类上登顶后,DeepMind 和 OpenAI 几乎同时把它推向了更难的战场——即时、不完全信息、多人的电子游戏,这里没有回合制的从容,没有完全可见的棋盘。

AlphaStar(2019)攻克了《星际争霸 II》6。这个游戏的难点叠满了:实时(每秒要做多个操作)、信息不完全(战争迷雾遮住对手)、动作空间巨大(成百上千种操作组合)、需要长达几十分钟的长程战略规划。AlphaStar 的关键创新是 league training(联盟训练)——不是让一个智能体自我对弈,而是维护一整个“联盟”里许多风格各异、相互克制的智能体,让它们彼此对抗、共同进化,避免陷入“只会一种套路、被针对就崩”的局部最优。最终 AlphaStar 达到了星际争霸的宗师(Grandmaster)段位,超过 99.8% 的人类玩家6

OpenAI Five(2019)攻克了《Dota 2》的 5v5 团队对战7。它的路线和 AlphaStar 不同——不靠精巧的联盟设计,而是靠规模:用上一章讲的 PPO,在上千块 GPU 上做大规模分布式自我对弈,每天积累相当于数百年的游戏经验,硬生生把团队配合、资源运营、长期战略从海量试错中磨出来,最终击败了 Dota 2 的世界冠军战队 OG7。OpenAI Five 是“规模本身能带来能力”这个信念(第五、十一章那条暗线)在强化学习领域的一次有力印证——同样的 PPO,喂足够多的算力和经验,就能解决曾被认为需要特殊技巧的复杂协作问题。

到这里,强化学习这条线在“和环境/对手博弈”的世界里抵达了顶峰:从 Atari 到围棋到星际到 Dota,机器在一个又一个曾被认为是人类智能堡垒的领域里登顶。但这些成就有一个共同前提——它们都活在游戏里,一个奖励明确(赢或输、分数高低)、可以无限次重来、试错不要钱的世界。当这套强大的“从奖励中学习决策”的能力,要走出游戏、回到第十、十一章那个语言模型的世界时,最棘手的问题浮现了:奖励从哪来? 现实里没有人给“一段回答”自动打分。下一章讲强化学习如何带着它在游戏里磨出的全部武器,回流到语言模型,去解决这个奖励难题——从 RLHF 的人类偏好,到 2025 年用“可自动验证的对错”重新定义奖励的推理模型。这条正交了八十年的主线,将在那里与主干合为一体。

配套的 manim 动画 assets/manim/ch15_alphago.pyMCTSGrowthSelfPlayFlywheel 两个 Scene)把两个内核演出来:前者按“选择→扩展→评估→回传”四步演示蒙特卡洛树搜索如何朝最有希望的分支生长——PUCT 选路、扩展叶子、value 网络估值、再把估值沿路径回传更新祖先;后者把自博弈画成一个三节点循环——当前最强网络自我对弈生成数据、训出更强网络、再回到自博弈,每转一圈都更强,无需任何人类棋谱。


本质

AlphaGo 一族真正的突破,是把两种各有短板的能力拧成了一股绳。神经网络(policy/value)能在一瞬间给出对局面的直觉判断,但单凭直觉会看走眼;显式的前瞻搜索(MCTS)能推演很多步、纠正直觉的错误,但若没有方向、在围棋这种天文数字的分支里盲目展开就是徒劳。把它们结合:用网络的直觉给搜索指方向、剪掉绝大多数无谓分支,再用搜索的结果回过头来纠正、提纯网络的直觉——搜索让网络变准,网络让搜索变快。而自博弈则解决了“老师从哪来”的问题:让当前最强的版本和自己对弈,产生的数据天然就比它现在的水平略高一点,用这点数据训出更强的版本,再自博弈,如此螺旋上升。它不需要人类棋谱,因为它自己持续生成着略微超出自己的目标。这套“搜索与学习互相提纯、并用自博弈自举”的机制,是强化学习迄今最干净也最有力的一次思想结晶。


参考文献

  1. Silver, D., Huang, A., Maddison, C. J., et al. (2016). Mastering the game of Go with deep neural networks and tree search. Nature, 529, 484–489. 策略网络(选点)+ 价值网络(评局)+ MCTS;监督学习人类棋谱起步 + 自我对弈强化学习;5:0 胜欧洲冠军樊麾,后 4:1 胜李世石。Nature:https://www.nature.com/articles/nature16961 ;DeepMind 博客:https://deepmind.google/discover/blog/alphago-mastering-the-ancient-game-of-go-with-machine-learning/

  2. Kocsis, L., & Szepesvári, C. (2006). Bandit Based Monte-Carlo Planning. ECML 2006, LNCS 4212, 282–293. 把 UCB1 多臂老虎机准则用于树搜索(UCT),平衡探索/利用,给出有限样本界;AlphaGo 的 PUCT 是其加策略先验的变体。Springer:https://link.springer.com/chapter/10.1007/11871842_29 ;PDF:http://ggp.stanford.edu/readings/uct.pdf

  3. Silver, D., Schrittwieser, J., Simonyan, K., et al. (2017). Mastering the game of Go without human knowledge. Nature, 550, 354–359. AlphaGo Zero:去掉人类棋谱、单一 (p,v)(p,v) 网络、纯自我对弈;自提升飞轮(网络引导搜索→搜索产生更强策略→改进网络);损失 =(zv)2𝝅log𝒑+cθ2\ell=(z-v)^2-\boldsymbol\pi^\top\log\mathbf p+c\lVert\theta\rVert^2。Nature:https://www.nature.com/articles/nature24270

  4. Silver, D., Hubert, T., Schrittwieser, J., et al. (2018). A general reinforcement learning algorithm that masters chess, shogi, and Go through self-play. Science, 362(6419), 1140–1144. AlphaZero:通用自我对弈算法,仅给规则、无领域知识,学会围棋/国象/将棋并击败各自最强程序(含 Stockfish)。Science:https://www.science.org/doi/10.1126/science.aar6404

  5. Schrittwieser, J., Antonoglou, I., Hubert, T., et al. (2020). Mastering Atari, Go, chess and shogi by planning with a learned model. Nature, 588, 604–609. MuZero:不给规则,自学隐空间环境模型(预测下一隐状态/奖励/策略/价值),在学到的模型里做 MCTS 规划;棋类追平 AlphaZero,Atari 达顶尖。Nature:https://www.nature.com/articles/s41586-020-03051-4 ;博客:https://deepmind.google/discover/blog/muzero-mastering-go-chess-shogi-and-atari-without-rules/

  6. Vinyals, O., Babuschkin, I., Czarnecki, W. M., et al. (2019). Grandmaster level in StarCraft II using multi-agent reinforcement learning. Nature, 575, 350–354. league training(多智能体相互演化策略);不完全信息、实时、长程;达宗师段位,超 99.8% 人类玩家。Nature:https://www.nature.com/articles/s41586-019-1724-z

  7. OpenAI, Berner, C., Brockman, G., Chan, B., et al. (2019). Dota 2 with Large Scale Deep Reinforcement Learning. 大规模分布式 PPO(上千 GPU、每天数百年自我对弈经验);5v5 团队博弈击败世界冠军 OG。arXiv:https://arxiv.org/abs/1912.06680 ;OpenAI 博客:https://openai.com/research/openai-five-defeats-dota-2-world-champions

强化学习回流:从 RLHF 到推理模型

这一章把两条主线合上。从第十二章起,强化学习一直是一条与语言模型平行的支线——它在 Atari、围棋、星际里登顶,但那都是奖励明确、可以无限重来的游戏世界。而第十、十一章那条语言模型主线,靠的是在海量文本上“预测下一个词”,它博学却不听话。两条线的交汇点,第十一章已经点到了:RLHF——用人类反馈把强化学习的优化能力借给语言模型,把 GPT-3 那样的续写引擎变成 ChatGPT 那样的助手。但 RLHF 也暴露了强化学习走出游戏后最棘手的问题:奖励从哪来?现实里没人给一段回答自动打分,于是只能雇人去标注偏好,又慢又贵又不一致。这一章顺着这个奖励难题往下走——从 RLHF 的人类偏好,到 DPO 把强化学习“省掉”,再到 2024、2025 年推理模型用“可自动验证的对错”重新定义奖励,让强化学习从“难以指定奖励”的困境里,绕回到一个奖励本来就现成的地方。这条正交了八十年的主线,在这里与主干彻底合为一体。


先把第十一章的 RLHF 放回强化学习的框架里,用前几章的语言重述一遍——这样它的位置就清楚了。

RLHF(Reinforcement Learning from Human Feedback)三步走:先用人类示范做监督微调(SFT),让模型学会“回答指令”这种格式;再用人类对多个回答的排序,训练一个奖励模型,把人类偏好压缩成一个标量打分函数;最后用强化学习去优化语言模型,让它生成的回答尽量获得奖励模型的高分1

把它翻译成第十二章的 MDP 语言:状态是当前的上下文(提示词加已生成的部分),动作是生成下一个 token,策略就是语言模型本身(它在每个上下文下输出下一个 token 的概率分布),奖励由奖励模型在回答结束时给出。第三步用的优化算法,正是第十四章讲透的 PPO——那个为打游戏而生的 clip 目标。RLHF 里“加 KL 惩罚防止模型偏离原语言能力太远”,就是 PPO/TRPO“别离旧策略太远”那条信赖域思想的直接应用:这里的“旧策略”是 SFT 之后的模型,KL 惩罚拉着它别为了刷奖励而胡乱漂移1

奖励模型的数学核心是第十一章已经讲过的 Bradley-Terry 偏好模型——人类偏好回答 ywy_w 胜过 yly_l 的概率被建模为奖励之差的 sigmoid:

P(ywyl)=σ(r(yw)r(yl)) P(y_w \succ y_l) = \sigma\big(r(y_w) - r(y_l)\big)

训练奖励模型就是最大化所有人类偏好对的对数似然。这一步把离散的人类排序,变成了一个连续可优化的奖励信号,让 PPO 有的放矢。RLHF 的效果第十一章也给过那个惊人数字:经过 RLHF 的 13 亿参数小模型,输出被人类偏好的程度超过了未对齐的 1750 亿参数 GPT-31。强化学习把“有用”这个维度,从“靠堆规模”里独立了出来。


RLHF 成了 ChatGPT 的技术底座,但它有一身麻烦,全都系在“奖励从哪来”这个根问题上。

人类标注又慢又贵又不一致。要训练奖励模型,得雇大量标注员对成千上万对回答排序。这既烧钱又慢,而且不同人的偏好不一致、同一个人不同时候也不一致,奖励信号本身就带噪。

奖励模型会被钻空子(reward hacking)。奖励模型只是真实人类偏好的一个近似。语言模型作为一个强大的优化器,会找到那些“奖励模型给高分、但其实并不好”的输出——比如学会用看起来自信、冗长、讨好的语气,因为这类回答在标注中常被偏好。模型优化的是奖励模型这个代理,而非真正的“好”,两者一旦错位就会被放大。

流程复杂、不稳定。RLHF 要同时维护四个模型(策略、奖励模型、价值网络、参考模型),PPO 的训练对超参数敏感、容易崩。把一套为游戏设计的在线强化学习,套到语言模型上,工程上相当娇贵。

这些问题催生了两个方向的努力:一个是简化——能不能不要那么复杂的强化学习流程?另一个是换奖励源——能不能不靠人类、找一个更可靠的奖励?这两个方向,分别通向了 DPO 和推理模型。


先看简化这条路。2023 年,Rafailov 等人提出 DPO(Direct Preference Optimization,直接偏好优化),做了一件相当漂亮的事:把强化学习从 RLHF 里整个拿掉2

DPO 的洞察是数学上的。RLHF 那个“最大化奖励、同时受 KL 约束别离参考模型太远”的优化问题,其实有一个闭式的最优解——最优策略与奖励之间存在一个解析关系。Rafailov 等人把这个关系反过来用:既然最优策略隐含地决定了奖励,那就可以用策略本身来表示奖励,从而把偏好的对数似然直接写成关于策略参数的一个损失,根本不需要先训一个显式的奖励模型、再跑 PPO。论文那个副标题点破了一切:《你的语言模型其实偷偷就是一个奖励模型》2

结果是,DPO 把 RLHF 那套“训奖励模型 + 在线 PPO”的复杂流程,压缩成了一个像监督学习一样简单的分类损失:直接在“偏好对”数据上,提高被偏好回答的相对概率、压低被拒绝回答的相对概率,用普通的梯度下降就能训。它隐式优化的目标和 RLHF 一样,却省掉了奖励模型、价值网络和强化学习的全部不稳定性。DPO 的简单和有效,让它迅速成为开源社区做偏好对齐的主流选择之一。

DPO 在这部技术史里是一个有点反讽的节点:强化学习辛苦地把优化能力借给了语言模型(RLHF),紧接着 DPO 又证明,在偏好对齐这个特定任务上,那个强化学习的外壳可以被一个等价的监督损失替换掉。这提醒我们第十五章末尾那句话的另一面——RLHF 是强化学习的一种退化使用:它的“环境”是个静态的奖励模型而非真实交互,所以它能被一个闭式解绕开。强化学习真正不可替代的威力,要在奖励来自真实、动态、可反复验证的地方才显现。而那个地方,恰恰是推理。


再看换奖励源这条路,它通向了 2024、2025 年最重要的进展——推理模型

转折点是一个观察:对于数学题和编程题,奖励其实是现成的、可自动验证的。一道数学题的答案对不对,可以直接核对标准答案;一段代码行不行,可以直接跑测试用例。不需要人类标注偏好,不需要训奖励模型——对错本身就是奖励。这类奖励有个名字叫 RLVR(Reinforcement Learning with Verifiable Rewards,可验证奖励强化学习)。

这一下就把第二节那些麻烦绕开了一大半:奖励不再昂贵(自动判定)、不再不一致(对就是对)、也很难被钻空子(答案错了就是错了,再讨好的语气也没用)。强化学习终于回到了它最舒服的设定——一个奖励明确、可以反复试错的环境,就像游戏一样。区别只是,这次的“游戏”是解数学题。

OpenAI 在 2024 年底推出的 o1 是第一个公开的此类推理模型3。它的核心能力是在回答前先进行很长的思维链(chain-of-thought)推理——在内部一步步演算、尝试、回溯、检验,然后给出答案。OpenAI 公布的方法描述是:通过大规模强化学习训练模型“学会推理”,让它在解决复杂问题时投入更多的“思考时间”,并且这种能力随着训练算力和思考时长的增加而持续提升3。需要诚实说明的是:o1 没有公开的技术论文,只有官方介绍和 system card,其具体训练配方是闭源的——这里关于它的机制描述,部分是基于官方表述和后续公开研究的推断,而非可完全复核的一手细节。

o1 真正可被复核的影响,来自它激发的开源复现。


2025 年初,DeepSeek 发布了 DeepSeek-R1,并公开了完整的技术报告——这让“用强化学习激发推理能力”这件事第一次有了可复核的一手细节4

R1 工作里最震撼的,是一个叫 DeepSeek-R1-Zero 的变体:它完全不用监督微调冷启动,直接在基础模型上做大规模强化学习,奖励就是数学/代码答案的可验证对错。结果,模型自发地涌现出了复杂的推理行为——它学会了自我验证(算完回头检查)、反思(“等等,我前面错了”)、以及生成很长的思维链来解决难题,这一切都没有任何人教它“应该这样推理”4。报告里有个被反复引用的“顿悟时刻”(aha moment):训练中模型在解题途中突然停下来,重新审视自己的解法。这强烈呼应了第十五章 AlphaGo Zero 的故事——纯强化学习、不靠人类示范,能让系统发展出超越人类直接传授的策略。在围棋里那是新定式,在语言模型里那是推理链。

R1 用的强化学习算法是 PPO 的一个变体 GRPO(Group Relative Policy Optimization,组相对策略优化)4。回想第十四章:PPO 需要一个价值网络(critic)来估计优势 A=QVA=Q-V。GRPO 的简化是去掉这个价值网络——它对同一个问题采样一回答,用这组回答奖励的组内相对高低来当优势(高于组内平均的回答被强化,低于的被压低)。这省掉了一个和策略一样大的价值网络,在训练动辄上百亿参数的语言模型时,是实打实的资源节省。它的目标函数仍保留 PPO 的 clip 结构,只是把优势的来源从“价值网络估计”换成了“组内相对排名”。

R1 的硬指标很能说明问题:在数学竞赛 AIME 2024 上,纯强化学习的 R1-Zero 把 pass@1(一次答对率)从基础模型的 15.6% 提升到了 71.0%,配合多数投票更达到 86.7%,逼近 o1 的水平4。而这一切的奖励,主要来自“答案对不对”这个自动判定,没有昂贵的人类偏好标注。


退一步,把 RLHF 和 RLVR 并排看,能看清强化学习回流语言模型时奖励来源的一次根本转变。

RLHF 处理的是没有客观对错的任务——什么是“有帮助、无害、诚实”的回答,没有标准答案,只能问人类的偏好。所以它必须把人类偏好压成奖励模型,再用 PPO 优化。这是强化学习创始论文(第十一章引的 Christiano 2017)的本意:很多想要的行为难以写成奖励函数,但人类一眼能比较好坏,于是从偏好里学奖励。

RLVR 处理的是有客观对错的任务——数学题、代码,答案可自动验证。这里奖励是现成的,不需要人类、不需要奖励模型,强化学习回到了它在游戏里的舒适区:明确奖励、海量试错。这也解释了为什么推理模型的突破来得这么猛——一旦奖励可靠又便宜,第十二到十五章那套被反复锤炼的强化学习机器,就能像在 Atari 和围棋里那样全力运转。

这两者之间还夹着一条折中的路:用 AI 反馈替代部分人类反馈。Anthropic 在 2022 年的 Constitutional AI 工作里提出 RLAIF——给模型一组成文的原则(“宪法”),让它依据这些原则自我批判、修订回答,再用模型自己产生的偏好去做对齐,从而缓解人类标注的成本与不一致5。它代表了奖励来源从“人类”向“规则/AI”迁移的一步,介于 RLHF 的人类偏好与 RLVR 的自动验证之间。

把这几条放在一起看:RLHF 让模型对齐人类的价值与品味(该不该说、怎么说得体),RLVR 让模型对齐客观的正确性(算得对不对、推得严不严),RLAIF 则试图用可扩展的 AI 反馈去补人类反馈的不足。今天最强的模型往往兼用:先用偏好对齐管住“得体”,再用可验证奖励磨利“会推理”。一条 1992 年从 REINFORCE 起步、为了让连接主义网络能“试错学习”而生的技术线,走过 Atari、走过围棋、走过 RLHF,最终在 2025 年回到了语言模型,去解决一个最古老的智能问题——如何正确地推理


这一章合上了两条主线,也让我们能回望这部从 1943 年讲起的技术史,看清它真正的形状。

它不是一条单线。一条主线是感知与生成:从感知机到反向传播,到 CNN 与 LSTM 编码结构先验,到注意力统一为 Transformer,到 BERT/GPT 大规模预训练,到 scaling laws 把“放大规模”变成可规划的工程——这条线的数学语言是最大似然,目标是拟合数据的分布,让机器学会“世界长什么样、话该怎么接”。另一条主线是决策与控制,就是这五章讲的强化学习:从 Bellman 方程到 TD 与 Q-learning,到 DQN 驯服深度网络,到策略梯度与 PPO,到 AlphaGo 一族的自我对弈巅峰——这条线的数学语言是 MDP 与 Bellman,目标是最大化长期回报,让机器学会“在世界里该怎么做”。

这两条线平行了大半个世纪,各自在 2016 年前后登顶——一边是 GPT 式预训练即将引爆,一边是 AlphaGo 震动世界。然后它们开始合流:2022 年 RLHF 让决策的优化能力服务于生成的模型,2025 年推理模型让强化学习在语言模型内部点燃了“会思考”的能力。“拟合分布”给了机器博学,“最大化回报”给了机器目的,两者交织,才有了今天既能流畅生成、又能对齐人类、还能一步步推理的系统。

这部历史远没有结束。强化学习与语言模型的结合仍在剧烈演化——过程奖励、可验证奖励的边界(数学代码之外的开放任务怎么给奖励?)、reward hacking 的新形态、用 AI 反馈替代人类反馈(RLAIF)的可靠性、把搜索(MuZero 那样的规划)真正搬进语言模型推理——每一个都是正在被书写的章节。但这部历史走到今天的逻辑已经清晰:让一台只会做加法和乘法的机器逼近“理解”与“行动”,需要两种学习——从世界学会它的样子,以及在世界里学会该怎么做。前十一章讲了前者,这五章讲了后者。它们在这里汇成同一条河。

配套的 manim 动画 assets/manim/ch16_rl_llm.pyTokenAsTrajectoryTwoLines 两个 Scene)把合流演出来:前者把生成一句话重述成一条 MDP 轨迹——每个 token 是一个动作,整条序列是轨迹 τ\tau,奖励模型在末端给出回报 R(τ)R(\tau),PPO/DPO 据此推动策略(语言模型);后者把两条主线并置——主线 A(拟合数据分布/最大似然)与主线 B(最大化回报/MDP)各自走过的里程碑,最终汇入 RLHF/DPO/RLVR 这个合流点。预训练给出会说话的策略,RL 给它一个要最大化的目标。


本质

把 RLHF 看懂的关键,是意识到“生成一句话”和“在游戏里走一局”在数学上是同一件事:每生成一个 token 就是选一个动作,整条回答就是一条轨迹,奖励模型在末尾打的分就是这条轨迹的回报——于是前面五章为游戏磨出的全部武器(策略梯度、PPO、优势估计)可以原样搬过来。这一步重述本身,就是两条主线合流的全部秘密。它解决的根本问题是预训练留下的缺口:最大似然只能让模型逼近“人类文本最可能的样子”,却无法表达“人类真正想要的样子”——而后者往往写不成一个可微的损失函数。强化学习的回答是:凡是不好直接写成损失、却能判断好坏的目标,都可以转成奖励信号去最大化。2025 年的推理模型把这一步推到极致——当奖励来自“答案对不对”这种可自动验证的信号时,模型为了多拿分,竟自己摸索出了反复检查、回溯纠错的长链思考。至此,“从世界学会它的样子”与“在世界里学会该怎么做”这两种学习合为一体:预训练给了机器博学,强化学习给了机器目的。


参考文献

  1. Ouyang, L., Wu, J., Jiang, X., et al. (2022). Training language models to follow instructions with human feedback(InstructGPT)。三步 SFT→奖励模型→PPO;Bradley-Terry 偏好 P(ywyl)=σ(r(yw)r(yl))P(y_w\succ y_l)=\sigma(r(y_w)-r(y_l));KL 惩罚即信赖域思想;1.3B 对齐模型被偏好胜 175B GPT-3;ChatGPT 技术底座。RLHF 思想源头见 Christiano et al. 2017(arXiv 1706.03741)。arXiv:https://arxiv.org/abs/2203.02155 ;PDF:https://arxiv.org/pdf/2203.02155

  2. Rafailov, R., Sharma, A., Mitchell, E., Ermon, S., Manning, C. D., & Finn, C. (2023). Direct Preference Optimization: Your Language Model is Secretly a Reward Model. NeurIPS 2023. 利用 RLHF 最优策略与奖励的闭式关系,把偏好优化写成一个监督式分类损失,省掉显式奖励模型与在线 PPO,隐式等价 RLHF 目标。arXiv:https://arxiv.org/abs/2305.18290

  3. OpenAI (2024). Learning to Reason with LLMs(o1)。通过大规模强化学习训练模型在回答前进行长思维链推理,性能随训练算力与思考时长提升。无公开技术论文,仅官方介绍与 system card——本章对其机制的描述部分为基于官方表述与后续公开研究的推断(证据等级 C,不可完全复核)。官方页:https://openai.com/index/learning-to-reason-with-llms/

  4. DeepSeek-AI (2025). DeepSeek-R1: Incentivizing Reasoning Capability in LLMs via Reinforcement Learning. R1-Zero 纯 RL(无 SFT 冷启)即涌现自我验证/反思/长链推理(“aha moment”);用 GRPO(去掉价值网络、组内相对优势)+ 可验证奖励 RLVR(数学/代码对错自动判定);AIME 2024 pass@1 由 15.6% 提升至 71.0%、多数投票 86.7%,逼近 o1。arXiv:https://arxiv.org/abs/2501.12948

  5. Bai, Y., Kadavath, S., Kundu, S., et al. (2022). Constitutional AI: Harmlessness from AI Feedback(Anthropic)。用一组原则(“宪法”)让 AI 自我批判/修订,再用 AI 偏好(RLAIF)部分替代人类反馈,缓解 RLHF 的人类标注成本与不一致;是奖励来源从“人类”向“AI/规则”迁移的代表性一步。arXiv:https://arxiv.org/abs/2212.08073