Skip to content

前沿专题 · 序列建模前史:从循环网络到注意力机制 ​

前置要求:第5章 · 字符语言模型与概率目标的 bigram 计数表与 MLP 语言模型(本页的出发点),以及第4章 · 自动微分的链式法则与有限差分对拍。同读效果最佳的伙伴是第7章 · 张量反传与训练稳定性(梯度诊断与裁剪已在那里建立);第8章不是前置——本页讲的就是第8章的主角登场之前的世界。

分工声明:能力地图在课程对齐表里声明过「本课跳过其 RNN 前置要求」——22 章主线从第5章的 MLP 直接走到第8章的注意力。本页就是那半被声明跳过的前置史。读完第5章后随时可以来这里补全一块拼图:为什么 Transformer 长这个样子。它不新增实验模块、不进入 clean_room/ 合同,是纯理解性的一页;学完它,第8章的每个设计决定(因果掩码、位置编码、残差流、O(T²) 复杂度)都会从「论文这么写」变成「历史只能这么走」。

归属:本页的知识框架源自 Stanford CS230 VIP cheatsheet(Afshine Amidi & Shervine Amidi, 2018);梯度病根与门控电路的讲法装置源自 Ernest Ryu「RL of LLMs (Spring 2025)」Chapter 2。以下正文全部用自己的话重述,具体借鉴处在各节标注。


本页目标 ​

学完后你能做到:

  • 沿「零填充 → 逐层处理 → 权重共享」三步构造路径讲出循环神经网络 (Recurrent Neural Network, RNN) 为什么被发明,写出 Elman 单元方程并说明权重跨时间共享意味着什么。
  • 把沿时间反向传播 (Backpropagation Through Time, BPTT) 读成「展开即深网」,写出梯度连乘式,并用谱半径解释梯度消失与梯度爆炸这两种病根的机理——不只是两个名词。
  • 复述消失梯度的语义翻译:梯度传不回去,等价于模型在第 L 步忘掉了第 l 步的输入、且梯度更新本身修不好这件事。
  • 推导遗忘门最小电路 cl=fl⊙cl−1+gl 的一行求导(∂cl/∂cl−1=fl),并说明它与残差连接的对偶关系。
  • 对照 GRU 与 LSTM 的门控方程,说出四个门各自的职责;解释 LSTM 名字的正确读法是「更长的短期记忆」。
  • 讲出 seq2seq 的固定向量信息瓶颈为什么直接催生了注意力机制,并复述束搜索误差归因表。
  • 用血缘对照表把 RNN 隐藏状态、循环深度、顺序依赖与 第10章的 KV Cache、固定层数、全序列并行逐一配对。

本页的因果链一图流——每一环都是上一环的「显式缺陷修复」:


阶段一:序列依赖与变长输入——循环结构的构造路径 ​

1. 第5章留下的断点 ​

第5章的 MLP 语言模型已经解决了计数表的两个死穴:embedding 让相似上下文获得相似向量,参数量不再随上下文长度指数爆炸。但它留下一个更根本的约束:上下文窗口是固定的。表格里那行 context 长度必须固定或显式 padding 不是实现细节——它是架构级的天花板。想看前 20 个 token,就要把窗口开到 20;语料里出现更长的依赖,窗口之外的一切对模型不存在。第8章那句「它们的上下文是死的」说的正是这件事。

语言对上下文的要求是任意长的:代词可以回指五十个词之前的名词,段落主题句管住后面十句话。让「看多远」不再是一个超参数,就是序列建模要解的第一个问题。

2. 三步构造:每一步只修上一步的显式缺陷 ​

讲法源自 Ernest Ryu, RL of LLMs (Spring 2025) Chapter 2 的构造式推导——循环网络不是灵光一现,而是三次「构造-失败」循环的产物:

步骤做法修好了什么留下的显式缺陷
1. 零填充把所有序列补零到最大长度 Tmax,当作定长向量喂给 MLP能跑了长度被 Tmax 封死,超过就得重训;绝大多数位置是无意义的零
2. 逐层处理第 t 层只吃第 t 个输入,逐层往后传状态想多长就加多少层,信息有了「沿时间流动」的通道每个位置一套独立权重,参数量随 Tmax 线性增长,位置之间不共享任何统计
3. 权重共享每一步用同一套权重更新状态参数量与长度解耦,任意长度可处理——这就是 RNN状态必须逐步串行计算,且梯度要沿时间连乘(阶段二的病根)

第3步得到的循环单元(Elman, 1990)写成方程:

a⟨t⟩=g1(Waaa⟨t−1⟩+Waxx⟨t⟩+ba),y^⟨t⟩=g2(Wyaa⟨t⟩+by)

其中 a⟨t⟩∈Rd 是隐藏状态 (hidden state)——到目前为止所有输入的有损压缩摘要;x⟨t⟩ 是第 t 步输入;g1 通常取 tanh,g2 视任务取 softmax 或恒等。全部要点压在 Waa 一个记号上:同一组权重在时间上反复使用。参数不随序列长度增长,代价是计算图里出现了一条长度为 T 的串行链。

优劣对照(知识框架源自 Stanford CS230 VIP cheatsheet, Amidi & Amidi, 2018):

内容
优势任意长度输入;模型规模不随输入长度增长;计入全部历史;权重跨时间共享(统计高效)
代价计算沿时间串行,无法并行;久远信息难以访问(阶段二的病根);当前状态无法利用未来输入

第三条代价此时只是清单上一行,但它埋着第8章的伏笔:单向 RNN 只看过去。想让每个位置同时看过去与未来,要么等输入完再算(阶段四的双向 RNN),要么把「谁能看谁」做成一个显式矩阵约束——那就是第8章因果掩码 (causal mask) 的前身:信息流向从「架构天然如此」变成「设计者显式控制」。

3. 五种输入输出形态 ​

同一套循环权重,接法不同就覆盖一大类序列任务(表格译自 Stanford CS230 VIP cheatsheet, 2018):

形态结构典型任务
one-to-one无循环,即普通网络传统分类
one-to-many单个输入,展开生成序列音乐生成、图像描述
many-to-one序列进、末状态出情感分类
many-to-many(Tx=Ty)每步进一个、出一个命名实体识别、词性标注
many-to-many(Tx≠Ty)编码器读完,解码器另起生成机器翻译(阶段五的 seq2seq)

第五行最值得盯住:输入输出长度不相等,意味着必须把架构拆成「读」与「写」两段——这个形状会一路演化成第8章的 encoder-decoder Transformer。

4. RNN 语言模型:一条序列制造 L 个预测问题 ​

把 RNN 接到第5章的语言模型目标上:隐藏状态作为「到目前为止的前缀」的摘要,预测下一个 token:

uℓ+1≈hℓ=fθ(u1:ℓ),L=∑ℓ=1LL(y^⟨ℓ⟩,y⟨ℓ⟩)

hℓ 是 logits,softmax 后与 one-hot 目标比交叉熵。两个值得停一拍的细节(讲法源自 Ernest Ryu, RL of LLMs (Spring 2025) Chapter 2):

  • 不预测第一个 token。模型能拿什么信息去预测序列的第一个 token?什么都没有。下标从 u2 起算,连同结尾的 <EOS> 共 L 个预测问题——一条序列制造了 L 个预测问题,这与第9章 TinyGPT 的 shift 记账完全同构。
  • 每一步都是全窗口。MLP 看固定 n-gram,RNN 的 hℓ 理论上含 u1:ℓ 全部信息——理论上。实际能记多远,正是下一节要解剖的问题。

阶段二:BPTT 与两种病根 ​

1. 沿时间反向传播:展开即深网 ​

训练 RNN 没有新数学——把循环沿时间展开 (unroll):T 步的循环网络就是一张 T 层深的前馈网络,只是每层共享同一组权重。第4章的链式法则照常工作,唯一的新记账是每个时间步都有一条梯度路径通向同一组权重,总梯度是各步贡献之和:

∂L∂Waa=∑t=1T∂L∂Waa|(t)

这在实现上很省心——展开图的每个「层」用同一个 W 变量,自动微分引擎(第4章的 backward())会在逆拓扑序里自动累加。麻烦不在求和,在求和里的每一条路径本身有多长。

工程约定(2018 快照惯例,源自 Stanford CS230 配套讲义的时代实践):实践中常做截断 BPTT (truncated BPTT)——只往回展开 10–20 步就截断更新,用偏差(长程贡献被丢弃)换训练稳定性与显存。这个数字是那个时代的工程妥协值,不是物理常数。

2. 病根的乘积式 ​

真正决定 RNN 命运的一行式子:末状态对首状态的雅可比,是 T−1 个局部雅可比的连乘:

∂a⟨T⟩∂a⟨1⟩=∏t=2Tdiag(g1′(z⟨t⟩))Waa⊤⏟∂a⟨t⟩/∂a⟨t−1⟩

每个因子 = 「激活导数的对角阵 × 权重的转置」。语言序列长 100–1000 很平常,也就是上百个因子连乘。连乘的稳定性只看因子的乘性幅度:

  • 有效幅度系统性大于 1 → 乘积指数放大 → 梯度爆炸 (exploding gradient):训练在某一步被一个天文数字的更新掀翻,损失变 NaN。
  • 有效幅度系统性小于 1 → 乘积指数衰减 → 梯度消失 (vanishing gradient):远处的梯度贡献数值归零,模型学不到长程依赖。

注意 g1=tanh 时 tanh′≤1 且饱和区趋 0——激活饱和与权重矩阵自身的放大率两个因素都在往下压(下一节给「放大率」以精确名字:谱半径),所以实践中消失比爆炸更常见、也更难办。

3. 标量直觉先行,矩阵升级跟上 ​

讲法源自 Ernest Ryu, RL of LLMs (Spring 2025) Chapter 2。先把雅可比当标量看:序列长 1000、每步因子约一半大于一半小于 1,想象「500 个数连乘」——大部分大于 1 的乘积奔向 ∞,大部分小于 1 的奔向 0;想让乘积保持合理数量级,唯一的机会是所有因子都接近 1。矩阵情形没有本质变化,只是把「标量大小」升级成特征值 / 奇异值:Waa 的谱半径(最大特征值模)与激活导数的尺度共同决定每个因子的有效放大率。

第3级动手实验会让这个直觉变成可跑的数字。

4. 消失梯度的语义翻译 ​

爆炸是数值问题,消失是能力问题——这是全页最值得记住的一次翻译(讲法源自 Ernest Ryu, RL of LLMs (Spring 2025) Chapter 2):

∂L/∂hℓ 并不小(末状态确实依赖中间状态),但 ∂L/∂uℓ 趋于 0(改动第 ℓ 个输入 token,损失几乎不动)。

把这条链读全:RNN 在第 L 步没有记住 uℓ。更糟的是这是个死锁——「把 uℓ 记住一点」这个改进方向本身,恰好需要梯度从第 L 步传回第 ℓ 步,而那条路已经被连乘衰减堵死。模型在第 L 步忘掉了 uℓ,梯度更新也修不好「忘掉」这件事。诊断结论随之而来:这是架构病,不是优化器病。

5. 爆炸与消失:修法的不对称 ​

两种病根的严重程度与可修性恰好相反:

病根数值表现可修性一阶修法
梯度爆炸梯度范数偶发飙升、损失跳 NaN可修——梯度方向通常仍有信息,只是幅度失控梯度裁剪(阶段三)
梯度消失长程梯度贡献静默归零、模型只学短依赖裁剪救不了——信号本身没了,封顶一个不存在的量没有意义门控(阶段三)/ 换架构

第7章的梯度诊断表已经给出爆炸侧的可观测信号(梯度 RMS 飙到 1e3 量级、NaN/Inf);消失侧的信号更隐蔽——训练「安静地」收敛到一个只看局部窗口的次优解。本页动手实验的两处故障注入分别把这两种信号做成可复现的数字。


阶段三:一阶修补——裁剪与门控电路 ​

1. 梯度裁剪:治爆炸的手术 ​

爆炸的修法简单粗暴且有效(Pascanu 等, 2013):梯度全局范数超过阈值就整体缩放回去,

g←min(1,τ‖g‖2)g

工程约定:τ=5.0 是常见缺省值(2018 快照惯例);第7章已给出完整推导与实现位置(loss.backward() 之后、optimizer.step() 之前),此处不重复。

裁剪的适用前提比公式更重要(讲法源自 Ernest Ryu, RL of LLMs (Spring 2025) Chapter 2 的 3D 曲面走位比喻):没有裁剪时,优化像在山谷里走路突然遇到一道悬崖状的巨梯度——一步把参数甩到完全陌生的区域,之前的优化进度作废;有裁剪则沿着方向缩幅、优雅地走回来。前提是方向本身仍有信息。如果梯度方向本身就是错的(架构性病态),裁剪只是把错误方向走得慢一点——那时的解法只有一个:换架构。

2. 一个元判断:优化难题常常是架构选择的函数 ​

「深度学习里优化问题不是固定的,它是架构选择的函数;优化困难时,好的解法常常是换架构」(Ernest Ryu 课程口述观点,此处转述)。LSTM 是这条判断在 1997 年的执行,Transformer 是它在 2017 年的执行。本页余下的内容就是把这两次执行讲清楚。

3. 梯度流动视角:问题被重述成「记多少、忘多少」 ​

门控的全部动机浓缩成一次视角切换(讲法源自 Ernest Ryu, RL of LLMs (Spring 2025) Chapter 2):

  • 阶段二说:病根是 ∏t∂a⟨t⟩/∂a⟨t−1⟩ 的连乘远离 1。
  • 换个说法:想要信息与梯度流动好,就要每步的雅可比 ≈I(单位阵)。
  • 再问一层:真的每一步都想要 ≈I 吗?

答案是「不」。我们不是在造一台记住一切的机器——处理信息不等于囤积信息,有时候正确的动作是主动遗忘不相关的旧状态。于是问题从「让梯度别消失」被重述成一个设计任务:造一个能显式控制『记住 / 遗忘』的神经电路,该 ≈I 时 ≈I(记忆),该 ≈0 时 ≈0(遗忘)。

4. 遗忘门最小电路:一行求导撑起一个架构 ​

最小可行电路只有一条加法门控的更新律:

cl=fl⊙cl−1+gl

fl∈(0,1)d 是门(逐元素,sigmoid 输出),gl 是新信息候选,⊙ 是逐元素乘。它的存在理由压在一行求导上:

∂cl∂cl−1=diag(fl)

W 从梯度路径上消失了。 对比阶段二的乘积式——朴素 RNN 每步梯度必乘一个 Waa⊤,谱半径稍偏 1 就指数失控;门控电路的梯度通路是「门值本身」:fl 全 1 时雅可比是恒等阵(全记住,梯度无损直通),全 0 时是零(全遗忘)。梯度是否流动从「权重的谱半径碰巧是多少」变成「网络自己学着决定」。两处对照把它钉死:

极端门值雅可比行为
全记住fl≈1≈I梯度与信息无损直通,跨任意距离
全遗忘fl≈0≈0旧状态清零,从新信息重新开始

这与残差连接 y=x+F(x) 的 ∂y/∂x≈I 是同一个设计思想的两代实现(第7章的 GPT 残差缩放初始化 1/2L 是它在 Transformer 侧的工程化)——给梯度修一条恒等高速公路,让学习的内容聚焦在「增量」上。


阶段四:LSTM 与 GRU——更长的短期记忆 ​

1. 四个门各自的职责 ​

把最小电路展开成完整细胞,门 (gate) 的通用形状是 Γ=σ(Wx⟨t⟩+Ua⟨t−1⟩+b)∈(0,1)d——一个逐元素的「阀门开度」。四个门的分工一句话一个(表格译自 Stanford CS230 VIP cheatsheet, 2018):

门记号职责用于
update 门Γu新信息写入多少(标准 LSTM 文献称 input 门 it)GRU、LSTM
relevance 门Γr旧状态参与生成候选前,先筛掉多少(标准文献称 reset 门)GRU
forget 门Γf旧 cell 状态保留多少(「Learning to Forget」的门)LSTM
output 门Γocell 状态向外部暴露多少LSTM

2. GRU / LSTM 方程对照表 ​

两套门控细胞的并排对照(结构译自 Stanford CS230 VIP cheatsheet, 2018,公式按标准文献记法校正,见下方勘误框):

GRU(Cho 等, 2014)LSTM(Hochreiter & Schmidhuber, 1997)
门Γu,Γr=σ(⋅)Γu,Γf,Γo=σ(⋅)
候选状态c~⟨t⟩=tanh⁡(Wc[Γr⊙a⟨t−1⟩,x⟨t⟩]+bc)c~⟨t⟩=tanh⁡(Wc[a⟨t−1⟩,x⟨t⟩]+bc)
状态更新c⟨t⟩=Γu⊙c~⟨t⟩+(1−Γu)⊙c⟨t−1⟩c⟨t⟩=Γu⊙c~⟨t⟩+Γf⊙c⟨t−1⟩
隐藏输出a⟨t⟩=c⟨t⟩a⟨t⟩=Γo⊙tanh⁡(c⟨t⟩)
状态个数1 个(cell 即 hidden)2 个(cell 状态 + 隐藏输出分离)

沿着阶段三的梯度视角读这张表,三处差异都是设计语句:

  • GRU 的 (1−Γu) 与 Γu 强制互补——记住新信息的比例恰好等于遗忘旧信息的比例,一扇门管两件事。LSTM 的 Γf 与 Γu 解耦——可以同时全开(既保留旧的又写入新的,状态膨胀)或同时全关(都不动),表达力更强,多一扇门。
  • LSTM 的 tanh⁡(c⟨t⟩):cell 状态本身不饱和(可以长期线性增长以计数、计时),只在对外输出时压回 (−1,1)。
  • 两者共享阶段三的关键性质:cell 更新都是「门控加法」,∂c⟨t⟩/∂c⟨t−1⟩=diag(门值),梯度通路里没有权重矩阵连乘。

NOTE

记法勘误:Stanford CS230 cheatsheet(2018 版)把 LSTM 候选式写作带 Γr 的形式——那是 Coursera 课程「GRU 推广出 LSTM」的教学简化记法,与 Hochreiter & Schmidhuber (1997) 及 Graves (2012) 的标准记法不一致(标准式候选无 relevance 门、输出门后再过 tanh)。本表用标准式;读旧讲义遇到带 Γr 的 LSTM 时,按此对照换算即可。

3. 名字里的连字符:更长的短期记忆 ​

LSTM = Long Short-Term Memory——连字符在 short 和 term 之间:long short-term memory,「更长的短期记忆」,不是「长期记忆 + 短期记忆」两套存储。它把朴素 RNN「几个 token 就忘」的短期记忆拉长到几百步,仅此而已——真正的长期记忆是外部存储(检索、数据库、现代 LLM 的记忆功能),循环网络内部没有这个部件。另一个命名史注脚:LSTM 的 cell state 在数学角色上其实更像朴素 RNN 的隐藏状态(网络的摘要状态),「cell」这个名字只是历史行程的产物,文献既已约定,照标准讲。

对 LSTM 结构本身也值得一句坦诚评价(转述自 Ernest Ryu 课程):这套四门电路的设计「确实有点任意」——它不是唯一能修梯度流的形状。GRU 砍掉一个状态和一扇门仍然工作得差不多好,反过来证明 LSTM 的部分组件是冗余的。

4. 双向与堆叠:两个正交的扩展 ​

  • 双向 RNN (Bidirectional RNN, BRNN):一条从左到右、一条从右到左,每位置的输出拼接两个方向的隐藏状态——语言里后面的词常给前面的词提供消歧上下文(「苹果发布了新系统」里,后面的词把「苹果」钉成公司而非水果),词性标注一类的理解任务确实两头受益。但双向与因果语言模型不相容:生成第 t 个 token 时「未来」尚不存在。第8章的因果掩码把这个矛盾做成了显式开关——同一个架构,掩码下三角即因果生成(GPT 路线),掩码全开即双向理解(BERT 路线);理解与生成在 Transformer 侧是同一机制的两个配置,而在 RNN 侧是两套网络。
  • 深层堆叠 (stacked / deep RNN):把一层 RNN 的输出序列当作下一层的输入序列。工程约定(实践者经验,转述自 Ernest Ryu 课程):2 层几乎总比 1 层好;3 层不一定比 2 层好——一次加一层、当超参数调。RNN 的有效深度已经被序列长度占满(阶段二),垂直方向堆深的收益很快饱和,这与第8章 Transformer 轻松堆到几十层(残差 + 归一化的功劳,第7章)形成后来的对照。

5. 两个工程注脚 ​

  • 输出投影 (output projection):语言模型的输出维是词表大小 |V|(数万),直接让 LSTM 隐藏层(数百维)一步投影到词表会在每步付出大矩阵计算。工程做法是内部保持合理维度、末端统一投影(Sak 等, 2014 的 LSTM 结构流行版)。第10章的 tied embedding(输入输出共用一张表)是这个问题的现代后裔。
  • 末态 vs 池化:用 RNN 做句子级分类时,对全部时间步的隐藏状态做池化 (pooling),常比只取最末状态更好——末状态背负着「必须记住一切」的压力,池化让各位置的信息就地可用。

词向量:word2vec 与静态分布语义 ​

阶段四的输出投影注脚把「词的表示」推到了台前:语言模型输入端要把 token 变成向量,输出端要把向量变回词表概率。在循环结构与 seq2seq 演进的同时,还有一条平行线在回答更基础的问题:词的向量本身从哪里来。word2vec(Mikolov 等,2013)的答案——用无标注语料与极简目标学出带语义几何的静态词向量——既是本页后文编码器输入端的直接供货方,也是第8章 Transformer 第一层 embedding 查表的历史祖先(知识框架源自 Stanford CS230 VIP cheatsheet, Amidi & Amidi, 2018 的词向量条目 + 标准文献)。

1. one-hot 的语义真空 ​

「词的表示」的默认起点是 one-hot:|V|(数万)维指示向量,只有对应位为 1。它没有任何语义几何——任意两个 one-hot 向量正交、两两距离全等,「猫」与「狗」的距离和「猫」与「微积分」的完全一样。第5章的 MLP 语言模型已经用 embedding 表修掉了这一点,但那张表是跟着语言模型目标顺带学出来的;word2vec 问的是:能不能把「学好一张词向量表」单独抽出来,用更简单的目标、在更大的语料上学得更快。

2. 分布假设与两条对偶路线 ​

出发点是一句话(分布假设, distributional hypothesis):一个词的语义由它出现的上下文刻画。「猫」与「狗」共享大量「养 / 喂 / 可爱」语境,「猫」与「微积分」几乎没有——让上下文分布相近的词向量也相近,语义就进了几何。这正是第13章 embedding 检索「语义相近 → 坐标相近」的最原始版本。把它变成可优化目标有两条对偶路线:CBOW(continuous bag-of-words)用上下文预测中心词;Skip-gram 用中心词预测窗口内每个上下文词,大语料与罕见词上更优,是事实上的主线。Skip-gram 给每个词持有两个向量——中心(输入)向量 vw 与上下文(输出)向量 uw——对每个真实对 (c,o) 最大化条件概率、沿全语料滑窗求和:

P(o∣c)=exp⁡(uo⊤vc)∑w∈Vexp⁡(uw⊤vc),窗口≈5--10,d≈300

工程约定(2013 论文起的标准值):窗口 5–10(小窗口偏句法相似、大窗口偏主题相似),向量维度 300 是流传最广的缺省值。

3. 负采样:全词表 softmax 的逃逸 ​

上式分母要对 |V|(数万)个词逐个算指数——每来一个训练对就遍历一遍全词表,大语料规模下不可行。负采样 (negative sampling) 把多分类退化成 k+1 个二分类:真实对 (c,o) 是正样本,从噪声分布采 k 个负词 wi 各配成负样本对,目标变成

maxθlog⁡σ(uo⊤vc)+∑i=1kEwi∼Pn[log⁡σ(−uwi⊤vc)],k≈5--20

逐符号读:σ 是 sigmoid;第一项把正对的内积拉近,第二项把 k 个负对推远。工程约定:k≈5–20(小语料取大 k、大语料取小 k);噪声分布取 unigram 词频的 0.75 次幂——抬高低频词的被采概率,压掉超高频虚词的权重。「正对拉近、负对推远」这个目标形状是对比学习的原型,理论近亲是 NCE(noise-contrastive estimation)。

4. 向量空间的线性代数性质 ​

word2vec 最广为人知的演示是类比算术:king−man+woman≈queen,Paris−France+Italy≈Rome。语义关系被编码成空间中的平移方向——性别、时态、首都—国家各对应向量空间里一段大致稳定的位移,最近邻检索即可读出答案。比演示本身更重要的是它普及的世界观:语义即几何——第8章 attention 用 QK⊤ 量相似度、第13章用 cosine 检索,都住在这个世界观里。

5. 静态的极限与「从查表到计算」的谱系 ​

一词一向量意味着多义无解:「苹果」在「发布了新系统」与「很甜」里必须是同一个静态坐标(阶段四双向 RNN 举过的正是这个消歧例子)。修补沿两级递进,构成「从查表到计算」的完整谱系:

表示机制一词一形?
word2vec / GloVe 静态向量离线训练、查表使用,冻结是——多义无解
ELMo(Peters 等,2018)双向 LSTM 隐藏状态现场计算否——上下文相关
Transformer 自注意力每层全序列两两交互现算否——逐层动态

同期另一条路线 GloVe(Pennington 等,2014)不滑窗预测,而是分解全局共现计数矩阵——「预测路线 vs 计数路线」最终学出相近的几何,是分布假设同一枚硬币的两面。回看阶段六的血缘对照表:表示谱系(静态表 → ELMo → attention 动态表示)与结构谱系(RNN → 门控 → Transformer)互相咬合——结构决定了表示能被计算到什么程度。

6. 与本课主线的三个连接 ​

  • embedding 查表至今是 Transformer 第一层:第8章里每个 token 的 Q,K,V 都从它的 embedding 向量投影而来。一笔参数账的对照值得记:word2vec 给每个词持两张表(vw 与 uw),第10章的 tied embedding 则让输入查表与输出投影共享一张表、省掉整个 lm_head——「词向量参数怎么记账」的两种时代答案。
  • 负采样思想的延续:正对拉近、负对推远的目标形状在 NCE 与后来的对比学习里一脉相承(第 3 小节)。
  • RAG 检索的祖先:第13/14章的 embedding 模型(如 bge)是分布语义的现代后裔——从词级静态坐标升级为句级、上下文相关向量,但 cosine 检索的几何从 word2vec 起没有变过。

阶段五:seq2seq、解码与固定向量瓶颈 ​

1. 条件语言模型:第5章目标的条件化 ​

机器翻译在数学上就是第5章语言模型的条件化:给定源句 x,找

y=arg⁡maxyP(y⟨1⟩,…,y⟨Ty⟩∣x)

右侧依然是链式分解的自回归乘积——「生成」这个动作与第9章的逐 token 采样完全同构,多出来的只有一个条件 x。

2. 编码器-解码器与信息瓶颈 ​

seq2seq(Sutskever 等, 2014;Cho 等, 2014)用两段 RNN 实现它:编码器 (encoder) 读完源句,把末状态 c∈Rd 交给解码器 (decoder) 作为初始状态/条件,解码器自回归地生成目标句。

瓶颈一眼可见:无论源句多长,全部语义必须流经一个定长向量 c。十个词的句子也许装得下;一百词的段落也要压进同一个 d 维向量——每个任务都有某个长度,从那里开始固定向量成为灾难性瓶颈,翻译质量随句长骤降。这个瓶颈正是注意力机制的诞生动机:不是「注意力是个好主意所以发明了它」,而是「固定向量装不下,所以解码器必须有权回头看源句的每个位置」。

3. 束搜索与长度归一化 ​

arg⁡max 在指数大的候选空间里不可穷举,工程用束搜索 (beam search):每步保留得分最高的 B 个部分候选(束,beam)继续扩展。

工程约定(2018 快照惯例,源自 Stanford CS230 配套讲义):束宽 B≈10 是当时标准值;B=1 退化为逐步贪心。累加得分要用长度归一化 (length normalization):

Objective=1Tyα∑t=1Tylog⁡p(y⟨t⟩∣x,y⟨1⟩,…,y⟨t−1⟩),α∈[0.5,1]

没有它,log⁡p 每项为负、越长越亏,束搜索会系统性地偏爱短输出;α 软化这个偏置。与第9章的视角互补:temperature / top-k / top-p 是采样侧的随机化(要多样性的生成场景),束搜索是搜索侧的确定性解码(要单一最优输出的翻译场景)——同一个自回归分布的两种取用方式。

4. 束搜索归因表:用一个可计算判据定责任 ​

翻错了一句,锅在搜索还是模型?给参考答案 y∗ 与模型输出 y^,有一个可计算的判据(表格译自 Stanford CS230 VIP cheatsheet, 2018):

判据结论修法方向
P(y∗∣x)>P(y^∣x)搜索背锅——更好的候选存在,束搜索没找到加大束宽 B
P(y∗∣x)≤P(y^∣x)模型背锅——模型真的认为错译更好换架构 / 加数据 / 正则

这是「用可测判据把错误归因到子系统,再选修复手段」的范式——与第7章梯度诊断表(先看梯度 RMS 与 NaN 的形态,再决定裁剪/归一化/学习率哪一层出手)是同一种思维在不同层的实例。

5. BLEU:一句话级定位 ​

翻译质量的外部度量用 BLEU:BLEU=exp⁡(1n∑k=1npk),pk 是候选译文对参考译文的 clipped n-gram 精确率(匹配数封顶在参考中出现次数,防止重复词刷分),短译文另加 brevity penalty 惩罚。与困惑度的分工:困惑度(第3章 PP=2H)评估语言模型本身给语料赋概率的能力,BLEU 评估生成文本与参考文本的表面贴合度——它看不见同义改写,只数 n-gram 重合。本课不做机器翻译,认识这一定位即可。

6. Bahdanau attention:解瓶颈的补丁,后来成了主角 ​

Bahdanau、Cho、Bengio(2014/2015)的修补:解码器生成第 t 个词时,不再只依赖固定向量 c,而是对编码器全部时间步的状态做一次软选择:

e⟨t,t′⟩=va⊤tanh⁡(Wast−1+Uaht′),α⟨t,t′⟩=exp⁡(e⟨t,t′⟩)∑t″exp⁡(e⟨t,t″⟩),c⟨t⟩=∑t′α⟨t,t′⟩ht′

每个解码步得到专属的上下文向量 c⟨t⟩:生成目标词「建筑」时权重聚在源句的 "architecture" 位置,生成「风格」时聚在 "style" 位置——固定向量瓶颈就此拆除。三个细节值得标注:

  • 打分函数是加性的(两个投影进 tanh 再对齐打分)——这是 2014 年的形态。第8章的缩放点积 q⊤kdk 是它的矩阵化替身:单线性、可直接写成大矩阵乘、适合硬件并行。从加性到点积是注意力自身的一次工程化。
  • 权重 α 经 softmax 归一、非负和为 1——「软选择」的含义就是可微的加权平均,梯度能流回每一个被选中的位置。
  • 计算量对源句长 Tx 是二次的——每个解码步要对全部编码器状态打分。CS230 cheatsheet 在 2018 年就把这一条标为备注;它是固有成本而非实现瑕疵,第10章整章的 KV Cache / PagedKV 工程正是在「这笔二次账如何在推理侧摊销」上做文章——前缀的 K/V 一旦算出就不再变,缓存复用,每步只算新 token。

至此拼图完整:注意力作为 RNN 的补丁出场(治固定向量瓶颈),三年后被 Vaswani 等(2017)反问「既然每步都要对全部位置做软选择,RNN 这条串行主干还需要吗」——Attention is all you need。


阶段六:与 Transformer 的血缘对照 ​

1. 血缘对照表 ​

维度RNN / LSTM 时代Transformer 时代(第8/10章)
历史状态的载体单个定长隐藏状态,逐步压缩更新全部前缀的 K/V 显式保留;推理靠 KV Cache 摊销(第10章)
「深度」的来源循环展开深度 = 序列长度 T,随文本变长固定层数 L;任意两位置 1 步直连
训练并行度必须沿时间串行,T 步依赖链因果掩码只挡信息流不挡计算流,全序列并行
长程依赖路径门控衰减链,O(T) 步注意力直连,1 步
梯度病根修复门控(治标:沿长链仍衰减)残差 + LayerNorm(路径恒等,第7章)——治本
位置信息时间步递推天然内嵌显式位置编码(正弦 / RoPE,第10章)
对 T 的成本每步 O(d2)、总计 O(T⋅d2) 但串行注意力 O(T2) 但可并行;推理侧 KV Cache 摊销
推理期每 token 成本O(1) 状态更新,显存不随 T 增长读全量 cache,显存随 T 线性增长(第10章显存墙)

每行都不是「新比旧好」的简单叙事——最后一行 RNN 反而占优:推理时循环网络每步只更新一个固定大小的状态,这正是它作为「状态机」的天赋。训练可并行性买来的 O(T2) 账单,要在推理侧用整套缓存工程来付(第10章)。RNN 这条「推理便宜」的血统并未消失——它是后续线性注意力与状态空间模型研究重新捡起的起点。

2. 为什么是 Transformer 赢了(训练侧) ​

两条决定性理由(讲法源自 Ernest Ryu, RL of LLMs (Spring 2025) Chapter 2):

  1. 长序列不再需要压进定长状态——每个位置的信息显式存在 K/V 里,注意力按需取用;瓶颈从架构里被拆掉了。
  2. 训练完全并行——同一层所有位置的计算互相独立(信息流约束在掩码矩阵里,不在计算依赖里),GPU 满载;RNN 的 T 步串行链在硬件层面无解。

加上第7章已论证的残差 + LayerNorm 让深度可堆(ELMo 时代 bi-LSTM 堆 2 层 vs BERT 堆 24 层),规模化的全部闸门就此打开。

3. 收束:历史语境原则 ​

「Transformer 架构没有数学第一性原因必须如此,标准架构未来大概率会变;但历史语境告诉我们各组件的设计意图、什么肯定不行、什么新组件可能行」(Ernest Ryu 课程对 Chapter 2 的收束原则,此处转述)。本页就是这句话的展开——因果掩码是「单向 RNN 不看未来」的矩阵化,位置编码是「递推自带时间步」的补偿件,残差流是「门控修梯度」的根治版,KV Cache 是「O(T2) 账单」的分期付款。读完第8章再回看这张对照表,每个组件都带着它的历史理由。


动手实验:numpy 三级阶梯 ​

本页不新增仓库模块——RNN 前史是理解性知识,实验全部是页内 numpy 思路 + 你自己的脚本(先例:RL 基础页的「纯 numpy 可写,写清思路即可,不必追求工程完整」)。三级阶梯:

第 1 级:500 个数连乘的稳定性 ​

python
# 思路示意(numpy,任何机器秒级跑完)
import numpy as np
rng = np.random.default_rng(42)
for lo, hi, name in [(0.8, 1.2, "接近 1"), (0.0, 0.8, "小于 1"), (1.0, 1.2, "大于 1")]:
    factors = rng.uniform(lo, hi, size=500)
    log_mag = np.cumsum(np.log(np.abs(factors)))   # log|乘积| 的轨迹
    print(name, "最终 log|乘积| =", log_mag[-1])

预期信号:「接近 1」组缓慢随机漂移;「小于 1」组的 log 轨迹线性坠向 −∞(乘积数值下溢为 0);「大于 1」组线性升向 +∞。这就是阶段二标量直觉的可执行版:乘积想保持合理数量级,所有因子都得接近 1。

第 2 级:谱半径扫描——把病根做成曲线 ​

把标量换成 d×d 矩阵,走一遍真正的 BPTT 梯度通路:

python
# 思路示意
d, T = 16, 100
W0 = rng.normal(size=(d, d))
for rho in [0.5, 1.0, 1.5]:                       # 目标谱半径
    W = W0 * (rho / max(abs(np.linalg.eigvals(W0))))
    h = np.tanh(rng.normal(size=d));  gs = [h]
    for _ in range(T):                            # 前向展开
        h = np.tanh(W @ h);  gs.append(h)
    grad = np.eye(d);  norms = []
    for t in reversed(range(T)):                  # 反向沿雅可比连乘
        grad = (W.T * (1 - gs[t+1]**2)) @ grad    # diag(tanh') · W^T
        norms.append(np.linalg.norm(grad))
    print(f"rho={rho}: 首步范数 {norms[-1]:.3e}")

预期信号:ρ=1.5 的梯度范数指数放大(爆炸);ρ=0.5 指数衰减到下溢(消失);ρ=1.0 仍然衰减——因为 tanh′≤1,激活饱和在与谱半径叠加着往下压,这正是阶段二「实践中消失更常见」的数值形态。

第 3 级:最小 RNN + 手写 BPTT 对拍 ​

写一个 dh=8、dx=4、T=12 的 Elman RNN(第1节方程的直译),各步损失求和;手工沿展开图反向累积 ∂L/∂Waa;再按第4章的梯度检查纪律抽样若干权重分量做中心差分对拍:

∂L∂wij≈L(wij+h)−L(wij−h)2h,h=10−6

预期信号:相对误差在 10−6 量级——展开即深网、共享权重的梯度是各时间步贡献之和,这两件事被一个不依赖 RNN 库的对拍同时验证。


故障注入与预期信号 ​

两处注入分别攻击阶段二的两种病根,观测口径统一为隐藏状态范数 ‖ht‖ 与逐步梯度范数。

注入 1:谱半径 1.5——爆炸与裁剪的对照 ​

第 2 级实验里 ρ=1.5 的配置上,对每步反传的梯度加全局范数裁剪(τ=5.0)重跑:

  • 无裁剪:梯度范数沿反向步指数放大,末端达到 1010 量级以上——一次 optimizer.step() 就能把参数掀到陌生区域。
  • 有裁剪:范数封顶在 τ,方向保留——损失曲线继续下降。裁剪有效的前提在此直接可见:方向本身携带信息,失控的只是幅度。

注入 2:谱半径 0.5——裁剪救不了消失 ​

同样把裁剪加到 ρ=0.5 的配置上:

  • 预期信号:无论裁剪与否,‖∂L/∂x⟨1⟩‖ 都在 10−10 量级以下——封顶一个本来就不存在的量没有任何效果。同时 ‖∂L/∂x⟨T⟩‖ 健康。两个范数的悬殊比值就是阶段四语义翻译的数值形态:首 token 被模型忘掉了,且优化器无从得知「该去记住它」。

故障矩阵 ​

注入场景攻击的机制预期失败信号对应修法
ρ=1.5 无裁剪连乘放大(爆炸)梯度范数指数飙升、损失 NaN梯度裁剪(第7章已有实现细节)
ρ=1.5 + 裁剪 τ=5幅度失控、方向可用范数封顶、训练继续裁剪有效的适用区
ρ=0.5 + 裁剪连乘衰减(消失)首步梯度 ≈0,裁剪无效门控 / 换架构(阶段三、四)
ρ=1.0(tanh 饱和叠加)谱半径正常仍衰减梯度范数缓慢下降诊断时别只看权重大小,激活饱和同罪

与第7章梯度诊断表的衔接:那里的信号是训练循环级的(RMS 飙升 / NaN),这里是机理级的(连乘的每一步在做什么)——两张表在第9章训练 TinyGPT 时同时可用。


本页验收 ​

闭卷口试题(每题 5–10 分钟自测):

  1. 三步构造路径里,「零填充」和「逐层处理」各自的显式缺陷是什么?权重共享同时修好了哪两件事、又引入了哪两个新问题?
  2. 写出 ∂a⟨T⟩/∂a⟨1⟩ 的连乘式。每个因子的两个组成部分(激活导数、权重转置)分别在什么条件下把乘积往下压、往上推?为什么实践中消失比爆炸更常见?
  3. 「∂L/∂hℓ 不小但 ∂L/∂uℓ 趋 0」这条链的每一环各说明什么?为什么说这是一个「梯度更新本身修不好」的死锁?
  4. 梯度裁剪为什么对爆炸有效、对消失无效?「方向可用才裁剪」的判断标准在故障矩阵里对应哪两行对照?
  5. 推导 ∂cl/∂cl−1=fl。全记住与全遗忘两个极端下雅可比各是什么?这条梯度通路与朴素 RNN 的本质区别在哪一个记号上?
  6. GRU 的 (1−Γu) 互补约束与 LSTM 的 Γf,Γu 解耦各换来什么?LSTM 输出端的 tanh 为什么存在(提示:cell 状态的长期线性增长)?
  7. 双向 RNN 为什么与因果语言模型不相容?第8章的因果掩码把这个矛盾变成了什么样的显式设计?
  8. seq2seq 的固定向量瓶颈在数学上是什么约束?Bahdanau attention 的三个组件(打分、softmax、加权和)各拆除瓶颈的哪一部分?加性打分与缩放点积的演化关系是什么?
  9. 束搜索归因表与本课第7章梯度诊断表共同的思维方式是什么?(提示:先用可测判据定位责任层,再选修复手段。)
  10. 血缘对照表的最后一行为什么 RNN 反而占优?这个优势如何解释第10章 KV Cache / PagedKV 工程的存在动机?

论文与延伸 ​

  • 循环网络的起源:Elman, Finding Structure in Time, Cognitive Science 14(2), 1990——隐藏状态与跨时间权重共享的起点(无 arXiv,早于 arXiv 时代;参考 Stanford CS230 VIP cheatsheet 仓库 对该谱系的整理,MIT License)。
  • LSTM:Hochreiter & Schmidhuber, Long Short-Term Memory, Neural Computation 9(8), 1997——门控细胞与常数误差传送带的原始论文(无 arXiv)。Gers 等, Learning to Forget: Continual Prediction with LSTM, Neural Computation 12(10), 2000——forget 门的补全。
  • 病根与裁剪:Pascanu、Mikolov、Bengio, On the difficulty of training recurrent neural networks, ICML 2013, arXiv:1211.5063——梯度爆炸/消失的系统分析与梯度裁剪。
  • 词向量:Mikolov 等, Efficient Estimation of Word Representations in Vector Space, 2013, arXiv:1301.3781——静态分布语义、Skip-gram 与负采样的奠基论文;同期计数路线见 Pennington 等, GloVe: Global Vectors for Word Representation, EMNLP 2014。
  • GRU 与 seq2seq:Cho 等, Learning Phrase Representations using RNN Encoder-Decoder for Statistical Machine Translation, EMNLP 2014, arXiv:1406.1078——GRU 与编码器-解码器在同一篇出场。Sutskever 等, Sequence to Sequence Learning with Neural Networks, NeurIPS 2014, arXiv:1409.3215。
  • 注意力诞生:Bahdanau、Cho、Bengio, Neural Machine Translation by Jointly Learning to Align and Translate, ICLR 2015, arXiv:1409.0473——固定向量瓶颈的第一个解,加性打分。
  • 收束:Vaswani 等, Attention Is All You Need, NeurIPS 2017, arXiv:1706.03762——「RNN 是否必要」之问的答案,第8章的正文。
  • 课程:Ernest K. Ryu, RL of LLMs (Spring 2025) Chapter 2——本页梯度病根、门控电路与血缘叙事的讲法装置来源;讲义公开。

资源 / 成本 / 隐私 ​

三级实验与两处故障注入全部是 CPU 上的 numpy 小矩阵运算(最大 d=16、T=100),单次运行秒级,网络带宽与费用为 0。本页不依赖也不引入任何仓库 Python 模块;学习者脚本自行保存即可。


Evidence ​

学习者提交模板(待填写,不是当前机器证据) ​

复制下面模板并填写自己的真实运行结果。所有 <...> 都是未填写状态;actual 必须替换为本次运行的真实记录。

yaml
schema: learn-llm.evidence.v1
module: sequence-models-prehistory
commit: <learner-commit-sha>
verified_at: <iso-date>
environment: <sanitized-python-device>
seed: 42
commands:
  - python <your-rnn-prehistory-script>.py   # 本页三级实验 + 两处故障注入
metrics:
  - name: near_one_product_stays_bounded
    expected: true
    actual: <recorded-value>
  - name: rho_below_one_gradient_decays
    expected: true
    actual: <recorded-value>
  - name: rho_above_one_gradient_explodes
    expected: true
    actual: <recorded-value>
  - name: rho_one_tanh_saturation_still_decays
    expected: true
    actual: <recorded-value>
  - name: clipping_caps_norm_keeps_training_alive
    expected: true
    actual: <recorded-value>
  - name: clipping_does_not_rescue_vanishing
    expected: true
    actual: <recorded-value>
  - name: bptt_matches_finite_difference
    expected: relative-error-under-1e-6
    actual: <recorded-value>
artifacts:
  - <your-rnn-prehistory-script>.py
cost:
  gross_usd: 0
  credit_usd: 0
licenses:
  - source: Stanford CS230 VIP cheatsheet (Amidi & Amidi, 2018)
    license: link-only-attribution
  - source: Ernest K. Ryu, RL of LLMs (Spring 2025), Chapter 2
    license: link-only-attribution
known_failures:
  - none

本页的 numpy 数字只描述页内 toy 设定的机理演示,不构成对任何真实规模 RNN/Transformer 训练动态的外推;谱半径扫描的结论(门控修复什么、裁剪修复什么)是架构级的,具体数值不是。


下一步 ​

前史读完,回到主线的方式有两种:进第8章 · Attention 与 Transformer Block,把因果掩码、缩放点积、位置编码逐件对着本页的血缘表认亲;或先去第10章 · 现代推理与 KV Cache,看 O(T2) 的账单如何在推理侧被缓存与分页工程摊销。想继续沿理论纵深走,RL 基础页的教学法与本页同源——每个结论都带着它的构造路径。

私有学习站 · 原理从零构建 · 勿提交个人隐私或密钥