Appearance
前沿专题 · 序列建模前史:从循环网络到注意力机制
前置要求:第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 步的输入、且梯度更新本身修不好这件事。
- 推导遗忘门最小电路
的一行求导( ),并说明它与残差连接的对偶关系。 - 对照 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. 零填充 | 把所有序列补零到最大长度 | 能跑了 | 长度被 |
| 2. 逐层处理 | 第 | 想多长就加多少层,信息有了「沿时间流动」的通道 | 每个位置一套独立权重,参数量随 |
| 3. 权重共享 | 每一步用同一套权重更新状态 | 参数量与长度解耦,任意长度可处理——这就是 RNN | 状态必须逐步串行计算,且梯度要沿时间连乘(阶段二的病根) |
第3步得到的循环单元(Elman, 1990)写成方程:
其中
优劣对照(知识框架源自 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( | 每步进一个、出一个 | 命名实体识别、词性标注 |
| many-to-many( | 编码器读完,解码器另起生成 | 机器翻译(阶段五的 seq2seq) |
第五行最值得盯住:输入输出长度不相等,意味着必须把架构拆成「读」与「写」两段——这个形状会一路演化成第8章的 encoder-decoder Transformer。
4. RNN 语言模型:一条序列制造 L 个预测问题
把 RNN 接到第5章的语言模型目标上:隐藏状态作为「到目前为止的前缀」的摘要,预测下一个 token:
- 不预测第一个 token。模型能拿什么信息去预测序列的第一个 token?什么都没有。下标从
起算,连同结尾的 <EOS>共个预测问题——一条序列制造了 L 个预测问题,这与第9章 TinyGPT 的 shift 记账完全同构。 - 每一步都是全窗口。MLP 看固定 n-gram,RNN 的
理论上含 全部信息——理论上。实际能记多远,正是下一节要解剖的问题。
阶段二:BPTT 与两种病根
1. 沿时间反向传播:展开即深网
训练 RNN 没有新数学——把循环沿时间展开 (unroll):
这在实现上很省心——展开图的每个「层」用同一个 W 变量,自动微分引擎(第4章的 backward())会在逆拓扑序里自动累加。麻烦不在求和,在求和里的每一条路径本身有多长。
工程约定(2018 快照惯例,源自 Stanford CS230 配套讲义的时代实践):实践中常做截断 BPTT (truncated BPTT)——只往回展开 10–20 步就截断更新,用偏差(长程贡献被丢弃)换训练稳定性与显存。这个数字是那个时代的工程妥协值,不是物理常数。
2. 病根的乘积式
真正决定 RNN 命运的一行式子:末状态对首状态的雅可比,是
每个因子 = 「激活导数的对角阵 × 权重的转置」。语言序列长 100–1000 很平常,也就是上百个因子连乘。连乘的稳定性只看因子的乘性幅度:
- 有效幅度系统性大于 1 → 乘积指数放大 → 梯度爆炸 (exploding gradient):训练在某一步被一个天文数字的更新掀翻,损失变 NaN。
- 有效幅度系统性小于 1 → 乘积指数衰减 → 梯度消失 (vanishing gradient):远处的梯度贡献数值归零,模型学不到长程依赖。
注意
3. 标量直觉先行,矩阵升级跟上
讲法源自 Ernest Ryu, RL of LLMs (Spring 2025) Chapter 2。先把雅可比当标量看:序列长 1000、每步因子约一半大于一半小于 1,想象「500 个数连乘」——大部分大于 1 的乘积奔向
第3级动手实验会让这个直觉变成可跑的数字。
4. 消失梯度的语义翻译
爆炸是数值问题,消失是能力问题——这是全页最值得记住的一次翻译(讲法源自 Ernest Ryu, RL of LLMs (Spring 2025) Chapter 2):
并不小(末状态确实依赖中间状态),但 趋于 0(改动第 个输入 token,损失几乎不动)。
把这条链读全:RNN 在第 L 步没有记住
5. 爆炸与消失:修法的不对称
两种病根的严重程度与可修性恰好相反:
| 病根 | 数值表现 | 可修性 | 一阶修法 |
|---|---|---|---|
| 梯度爆炸 | 梯度范数偶发飙升、损失跳 NaN | 可修——梯度方向通常仍有信息,只是幅度失控 | 梯度裁剪(阶段三) |
| 梯度消失 | 长程梯度贡献静默归零、模型只学短依赖 | 裁剪救不了——信号本身没了,封顶一个不存在的量没有意义 | 门控(阶段三)/ 换架构 |
第7章的梯度诊断表已经给出爆炸侧的可观测信号(梯度 RMS 飙到 1e3 量级、NaN/Inf);消失侧的信号更隐蔽——训练「安静地」收敛到一个只看局部窗口的次优解。本页动手实验的两处故障注入分别把这两种信号做成可复现的数字。
阶段三:一阶修补——裁剪与门控电路
1. 梯度裁剪:治爆炸的手术
爆炸的修法简单粗暴且有效(Pascanu 等, 2013):梯度全局范数超过阈值就整体缩放回去,
工程约定: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):
- 阶段二说:病根是
的连乘远离 1。 - 换个说法:想要信息与梯度流动好,就要每步的雅可比
(单位阵)。 - 再问一层:真的每一步都想要
吗?
答案是「不」。我们不是在造一台记住一切的机器——处理信息不等于囤积信息,有时候正确的动作是主动遗忘不相关的旧状态。于是问题从「让梯度别消失」被重述成一个设计任务:造一个能显式控制『记住 / 遗忘』的神经电路,该
4. 遗忘门最小电路:一行求导撑起一个架构
最小可行电路只有一条加法门控的更新律:
| 极端 | 门值 | 雅可比 | 行为 |
|---|---|---|---|
| 全记住 | 梯度与信息无损直通,跨任意距离 | ||
| 全遗忘 | 旧状态清零,从新信息重新开始 |
这与残差连接
阶段四:LSTM 与 GRU——更长的短期记忆
1. 四个门各自的职责
把最小电路展开成完整细胞,门 (gate) 的通用形状是
| 门 | 记号 | 职责 | 用于 |
|---|---|---|---|
| update 门 | 新信息写入多少(标准 LSTM 文献称 input 门 | GRU、LSTM | |
| relevance 门 | 旧状态参与生成候选前,先筛掉多少(标准文献称 reset 门) | GRU | |
| forget 门 | 旧 cell 状态保留多少(「Learning to Forget」的门) | LSTM | |
| output 门 | cell 状态向外部暴露多少 | LSTM |
2. GRU / LSTM 方程对照表
两套门控细胞的并排对照(结构译自 Stanford CS230 VIP cheatsheet, 2018,公式按标准文献记法校正,见下方勘误框):
| GRU(Cho 等, 2014) | LSTM(Hochreiter & Schmidhuber, 1997) | |
|---|---|---|
| 门 | ||
| 候选状态 | ||
| 状态更新 | ||
| 隐藏输出 | ||
| 状态个数 | 1 个(cell 即 hidden) | 2 个(cell 状态 + 隐藏输出分离) |
沿着阶段三的梯度视角读这张表,三处差异都是设计语句:
- GRU 的
与 强制互补——记住新信息的比例恰好等于遗忘旧信息的比例,一扇门管两件事。LSTM 的 与 解耦——可以同时全开(既保留旧的又写入新的,状态膨胀)或同时全关(都不动),表达力更强,多一扇门。 - LSTM 的
:cell 状态本身不饱和(可以长期线性增长以计数、计时),只在对外输出时压回 。 - 两者共享阶段三的关键性质:cell 更新都是「门控加法」,
,梯度通路里没有权重矩阵连乘。
NOTE
记法勘误:Stanford CS230 cheatsheet(2018 版)把 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):一条从左到右、一条从右到左,每位置的输出拼接两个方向的隐藏状态——语言里后面的词常给前面的词提供消歧上下文(「苹果发布了新系统」里,后面的词把「苹果」钉成公司而非水果),词性标注一类的理解任务确实两头受益。但双向与因果语言模型不相容:生成第
个 token 时「未来」尚不存在。第8章的因果掩码把这个矛盾做成了显式开关——同一个架构,掩码下三角即因果生成(GPT 路线),掩码全开即双向理解(BERT 路线);理解与生成在 Transformer 侧是同一机制的两个配置,而在 RNN 侧是两套网络。 - 深层堆叠 (stacked / deep RNN):把一层 RNN 的输出序列当作下一层的输入序列。工程约定(实践者经验,转述自 Ernest Ryu 课程):2 层几乎总比 1 层好;3 层不一定比 2 层好——一次加一层、当超参数调。RNN 的有效深度已经被序列长度占满(阶段二),垂直方向堆深的收益很快饱和,这与第8章 Transformer 轻松堆到几十层(残差 + 归一化的功劳,第7章)形成后来的对照。
5. 两个工程注脚
- 输出投影 (output projection):语言模型的输出维是词表大小
(数万),直接让 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:
2. 分布假设与两条对偶路线
出发点是一句话(分布假设, distributional hypothesis):一个词的语义由它出现的上下文刻画。「猫」与「狗」共享大量「养 / 喂 / 可爱」语境,「猫」与「微积分」几乎没有——让上下文分布相近的词向量也相近,语义就进了几何。这正是第13章 embedding 检索「语义相近 → 坐标相近」的最原始版本。把它变成可优化目标有两条对偶路线:CBOW(continuous bag-of-words)用上下文预测中心词;Skip-gram 用中心词预测窗口内每个上下文词,大语料与罕见词上更优,是事实上的主线。Skip-gram 给每个词持有两个向量——中心(输入)向量
工程约定(2013 论文起的标准值):窗口 5–10(小窗口偏句法相似、大窗口偏主题相似),向量维度 300 是流传最广的缺省值。
3. 负采样:全词表 softmax 的逃逸
上式分母要对
逐符号读:
4. 向量空间的线性代数性质
word2vec 最广为人知的演示是类比算术:
5. 静态的极限与「从查表到计算」的谱系
一词一向量意味着多义无解:「苹果」在「发布了新系统」与「很甜」里必须是同一个静态坐标(阶段四双向 RNN 举过的正是这个消歧例子)。修补沿两级递进,构成「从查表到计算」的完整谱系:
| 表示 | 机制 | 一词一形? |
|---|---|---|
| word2vec / GloVe 静态向量 | 离线训练、查表使用,冻结 | 是——多义无解 |
| ELMo(Peters 等,2018) | 双向 LSTM 隐藏状态现场计算 | 否——上下文相关 |
| Transformer 自注意力 | 每层全序列两两交互现算 | 否——逐层动态 |
同期另一条路线 GloVe(Pennington 等,2014)不滑窗预测,而是分解全局共现计数矩阵——「预测路线 vs 计数路线」最终学出相近的几何,是分布假设同一枚硬币的两面。回看阶段六的血缘对照表:表示谱系(静态表 → ELMo → attention 动态表示)与结构谱系(RNN → 门控 → Transformer)互相咬合——结构决定了表示能被计算到什么程度。
6. 与本课主线的三个连接
- embedding 查表至今是 Transformer 第一层:第8章里每个 token 的
都从它的 embedding 向量投影而来。一笔参数账的对照值得记:word2vec 给每个词持两张表( 与 ),第10章的 tied embedding 则让输入查表与输出投影共享一张表、省掉整个 lm_head——「词向量参数怎么记账」的两种时代答案。 - 负采样思想的延续:正对拉近、负对推远的目标形状在 NCE 与后来的对比学习里一脉相承(第 3 小节)。
- RAG 检索的祖先:第13/14章的 embedding 模型(如 bge)是分布语义的现代后裔——从词级静态坐标升级为句级、上下文相关向量,但 cosine 检索的几何从 word2vec 起没有变过。
阶段五:seq2seq、解码与固定向量瓶颈
1. 条件语言模型:第5章目标的条件化
机器翻译在数学上就是第5章语言模型的条件化:给定源句
右侧依然是链式分解的自回归乘积——「生成」这个动作与第9章的逐 token 采样完全同构,多出来的只有一个条件
2. 编码器-解码器与信息瓶颈
seq2seq(Sutskever 等, 2014;Cho 等, 2014)用两段 RNN 实现它:编码器 (encoder) 读完源句,把末状态
瓶颈一眼可见:无论源句多长,全部语义必须流经一个定长向量
3. 束搜索与长度归一化
工程约定(2018 快照惯例,源自 Stanford CS230 配套讲义):束宽
没有它,
4. 束搜索归因表:用一个可计算判据定责任
翻错了一句,锅在搜索还是模型?给参考答案
| 判据 | 结论 | 修法方向 |
|---|---|---|
| 搜索背锅——更好的候选存在,束搜索没找到 | 加大束宽 | |
| 模型背锅——模型真的认为错译更好 | 换架构 / 加数据 / 正则 |
这是「用可测判据把错误归因到子系统,再选修复手段」的范式——与第7章梯度诊断表(先看梯度 RMS 与 NaN 的形态,再决定裁剪/归一化/学习率哪一层出手)是同一种思维在不同层的实例。
5. BLEU:一句话级定位
翻译质量的外部度量用 BLEU:
6. Bahdanau attention:解瓶颈的补丁,后来成了主角
Bahdanau、Cho、Bengio(2014/2015)的修补:解码器生成第
每个解码步得到专属的上下文向量
- 打分函数是加性的(两个投影进
再对齐打分)——这是 2014 年的形态。第8章的缩放点积 是它的矩阵化替身:单线性、可直接写成大矩阵乘、适合硬件并行。从加性到点积是注意力自身的一次工程化。 - 权重
经 softmax 归一、非负和为 1——「软选择」的含义就是可微的加权平均,梯度能流回每一个被选中的位置。 - 计算量对源句长
是二次的——每个解码步要对全部编码器状态打分。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章) |
| 「深度」的来源 | 循环展开深度 = 序列长度 | 固定层数 |
| 训练并行度 | 必须沿时间串行, | 因果掩码只挡信息流不挡计算流,全序列并行 |
| 长程依赖路径 | 门控衰减链, | 注意力直连,1 步 |
| 梯度病根修复 | 门控(治标:沿长链仍衰减) | 残差 + LayerNorm(路径恒等,第7章)——治本 |
| 位置信息 | 时间步递推天然内嵌 | 显式位置编码(正弦 / RoPE,第10章) |
| 对 | 每步 | 注意力 |
| 推理期每 token 成本 | 读全量 cache,显存随 |
每行都不是「新比旧好」的简单叙事——最后一行 RNN 反而占优:推理时循环网络每步只更新一个固定大小的状态,这正是它作为「状态机」的天赋。训练可并行性买来的
2. 为什么是 Transformer 赢了(训练侧)
两条决定性理由(讲法源自 Ernest Ryu, RL of LLMs (Spring 2025) Chapter 2):
- 长序列不再需要压进定长状态——每个位置的信息显式存在 K/V 里,注意力按需取用;瓶颈从架构里被拆掉了。
- 训练完全并行——同一层所有位置的计算互相独立(信息流约束在掩码矩阵里,不在计算依赖里),GPU 满载;RNN 的
步串行链在硬件层面无解。
加上第7章已论证的残差 + LayerNorm 让深度可堆(ELMo 时代 bi-LSTM 堆 2 层 vs BERT 堆 24 层),规模化的全部闸门就此打开。
3. 收束:历史语境原则
「Transformer 架构没有数学第一性原因必须如此,标准架构未来大概率会变;但历史语境告诉我们各组件的设计意图、什么肯定不行、什么新组件可能行」(Ernest Ryu 课程对 Chapter 2 的收束原则,此处转述)。本页就是这句话的展开——因果掩码是「单向 RNN 不看未来」的矩阵化,位置编码是「递推自带时间步」的补偿件,残差流是「门控修梯度」的根治版,KV Cache 是「
动手实验: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 轨迹线性坠向
第 2 级:谱半径扫描——把病根做成曲线
把标量换成
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}")预期信号:
第 3 级:最小 RNN + 手写 BPTT 对拍
写一个
预期信号:相对误差在
故障注入与预期信号
两处注入分别攻击阶段二的两种病根,观测口径统一为隐藏状态范数
注入 1:谱半径 1.5——爆炸与裁剪的对照
第 2 级实验里
- 无裁剪:梯度范数沿反向步指数放大,末端达到
量级以上——一次 optimizer.step()就能把参数掀到陌生区域。 - 有裁剪:范数封顶在
,方向保留——损失曲线继续下降。裁剪有效的前提在此直接可见:方向本身携带信息,失控的只是幅度。
注入 2:谱半径 0.5——裁剪救不了消失
同样把裁剪加到
- 预期信号:无论裁剪与否,
都在 量级以下——封顶一个本来就不存在的量没有任何效果。同时 健康。两个范数的悬殊比值就是阶段四语义翻译的数值形态:首 token 被模型忘掉了,且优化器无从得知「该去记住它」。
故障矩阵
| 注入场景 | 攻击的机制 | 预期失败信号 | 对应修法 |
|---|---|---|---|
| 连乘放大(爆炸) | 梯度范数指数飙升、损失 NaN | 梯度裁剪(第7章已有实现细节) | |
| 幅度失控、方向可用 | 范数封顶、训练继续 | 裁剪有效的适用区 | |
| 连乘衰减(消失) | 首步梯度 | 门控 / 换架构(阶段三、四) | |
| 谱半径正常仍衰减 | 梯度范数缓慢下降 | 诊断时别只看权重大小,激活饱和同罪 |
与第7章梯度诊断表的衔接:那里的信号是训练循环级的(RMS 飙升 / NaN),这里是机理级的(连乘的每一步在做什么)——两张表在第9章训练 TinyGPT 时同时可用。
本页验收
闭卷口试题(每题 5–10 分钟自测):
- 三步构造路径里,「零填充」和「逐层处理」各自的显式缺陷是什么?权重共享同时修好了哪两件事、又引入了哪两个新问题?
- 写出
的连乘式。每个因子的两个组成部分(激活导数、权重转置)分别在什么条件下把乘积往下压、往上推?为什么实践中消失比爆炸更常见? - 「
不小但 趋 0」这条链的每一环各说明什么?为什么说这是一个「梯度更新本身修不好」的死锁? - 梯度裁剪为什么对爆炸有效、对消失无效?「方向可用才裁剪」的判断标准在故障矩阵里对应哪两行对照?
- 推导
。全记住与全遗忘两个极端下雅可比各是什么?这条梯度通路与朴素 RNN 的本质区别在哪一个记号上? - GRU 的
互补约束与 LSTM 的 解耦各换来什么?LSTM 输出端的 为什么存在(提示:cell 状态的长期线性增长)? - 双向 RNN 为什么与因果语言模型不相容?第8章的因果掩码把这个矛盾变成了什么样的显式设计?
- seq2seq 的固定向量瓶颈在数学上是什么约束?Bahdanau attention 的三个组件(打分、softmax、加权和)各拆除瓶颈的哪一部分?加性打分与缩放点积的演化关系是什么?
- 束搜索归因表与本课第7章梯度诊断表共同的思维方式是什么?(提示:先用可测判据定位责任层,再选修复手段。)
- 血缘对照表的最后一行为什么 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 小矩阵运算(最大
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,看