上一章 《LSTM / GRU》治好了梯度消失,记忆却仍卡在一格。
Seq2Seq 让"输入一句、输出一句"成为可能,代价是把整句话压成一个固定大小的向量。
Seq2Seq(Sequence to Sequence:把一句翻成另一句)2014 年提出,结构极简:两个 RNN,中间接一个向量。 第一个 RNN 读源句(输入的那句原文),第二个 RNN 写译文。
| 角色 | 干什么 | 输入 / 输出 |
|---|---|---|
| 从左往右读完整个源句,把信息积累到最后那个隐藏状态里 | 「我 昨天 看见 一只 猫」→ 一个向量 c | |
| 上下文向量 c | 整句话的"浓缩" | 维度固定(比如 512 维),不管句子多长 |
| 拿着 c,一个词一个词地生成译文 | c → "I" → "saw" → "a" → "cat" |
c 的维度固定:源句 5 个词也好、50 个也好,都塞进同一个 512 维向量——这就是信息瓶颈:句子一长,前面的信息被后面的覆盖掉。 翻译质量因此随句长急剧下降,超过 20~30 个词就基本崩了 (BLEU = 机器翻译常用的自动打分,和人工参考译文重合越多分越高;Bahdanau 论文 Figure 2 里那条 随源句变长先升后降的曲线就是它)。
互动 · 瓶颈漏斗:真跑一遍
怎么算:下面真跑一个 16 维的编码器(真实模型 512 维,缩到 16 维只为当场算完):
每读一个词,把它的词向量 wt 加进记忆 ht = tanh(W·ht−1 + wt),
读完最后一个词,hn 就是 c;∂c/∂wj 靠反向传播算。
谁是谁:wj 是第 j 个词自己的词向量,hj 是编码器读到它时的记忆;
∂c/∂wj 是 16 个数(演示网;真实模型里是 512 个),「合起来有多大」= 对 c 的影响。
怎么看:柱子越长 = 越没被忘掉;高度按对数画,差一格 = 差 10 倍。
同一盘沙盘的第二个视角 · 句子多长会崩
横轴是源句长度 n,纵轴是下面那条曲线追踪的那个词的影响强度 ‖∂c/∂w‖,对数刻度。
ρ 是每读一个词、旧记忆被乘上的倍数:小于 1 就一步步缩小,大于 1 就一步步放大(放大过头会 梯度爆炸)。
1.25 这档短句还撑得住,句子一长,前面的词照样被压没。
灰色带(1e-2 ~ 1e2)是梯度能正常传播的数量级区间——上下一两个数量级都算健康。
曲线掉出下边缘 =
把「记忆保留率」三档依次点一遍,你会看到一件很反直觉的事:
调强记忆并不能救长句。
像一个翻译,对方说了一整段话,他必须凭记忆全部记住,
然后不许再看笔记,一口气翻译出来。
短句还行,长段落必然丢三落四。
注意力要做的事就是:允许他翻译到哪儿,就翻回去看一眼原文对应的位置。
改动只有一处:不再只用
把鼠标移到公式里有虚线的部分上——它会点亮这一章对应的那根滑杆。
这三步就是注意力的骨架。至于「分到底怎么打」——凭什么用点积、为什么除以 √dk、 为什么后来变成 Q/K/V 三组、为什么要有多个头——那是另一个问题,单独占一章。
这一章只需要记住「每一步回头看一眼原文」这个动作本身。
上面那三步背后的完整推导(从「加权平均」出发,一路推到
softmax(QKᵀ/√dk)V)、以及 Q/K/V、多头、因果掩码、O(n²) 从哪来,
全部在 3.6《注意力机制》——就是下一章。
§2 那三步只有十几个字。下面把它算一遍—— 公式里每个符号,图上都有一块东西对应它。
核心大图 · 一张图走完三步:谁被打分、分到多少、混成什么
微型图解 · 「加权求和」在几何上是这样:五支箭按 α 的比例合成一支
橙色那一支就是 c。它一定落在五支箭围成的扇形里—— 因为 α 全是正数、加起来等于 1,c 只能是一支「混合箭」,不可能跑到外面去。
先把上面那根「除以 √d 的 d」拖到 64,再拖到 1(默认是 8,三种都能拖到): 看上面读数里 e 那一行——最大的数会从 0.16 涨到 1.31,α 那一行跟着越来越尖。 这就是第 4 节那个互动说的同一件事:softmax 对分数的尺度极其敏感。
📐 看不明白 softmax?它只做一件事
把一排随便什么数变成一排正数、且加起来正好等于 1 的权重。 本来懂就跳过这一块。
下面每个词有一个手工设定的「概念向量」(8 个数;同一个意思的中英词共享一维,点积才会真的对上)。 s₁ 是解码器第 1 步的状态,hj 是编码器留下的第 j 个记忆: 把 s 和 hj 对应位置相乘再相加,就是点积——乘积越大,两边意思越匹配。 再除以 √d、过 softmax。点译文里的词,看它的注意力落在原文哪些位置上。
互动 · 真实的点积注意力
互动 · 同一例子,两种打分器各画一张对齐图
左边是 Luong 的乘性打分 s · h(点积):打分函数本身一个参数都没有——靠编码器/解码器把向量学好,权重自然对上。
右边是 Bahdanau 的加性打分 vᵀ·tanh(W₁h + W₂s),其中 W₁、W₂、v 是
TV 距离量的是两张对齐图差多少:0 = 完全一样,1 = 完全不重叠;掉到 0.05 以下就基本学会了。
右边刚开始是纯随机初始化——两张图能差多远?把下面的滑块从 0 拖到 500:每一步都是真的梯度下降
(
对于语序相同的语言对,对齐矩阵会明显偏向同一条对角线——第 i 个译文词最看重的往往就是第 i 个原文词。
但如果是"我 昨天 看见 一只 猫" → "I saw a cat yesterday",对角线会在 yesterday 处拐一下——
因为语序变了。这个"拐弯"正是注意力比固定向量强的地方:它不要求两种语言的语序一致。
两种打分器的区别只有一行公式。 「为什么最后是点积赢了」的完整推导在 《注意力机制》第 9 节, 「为什么除以 √d」的推导与实测在第 5 节。
| 对比项 | Bahdanau(加性) | Luong(乘性 / 点积) |
|---|---|---|
| 公式 | vT · tanh(W₁h + W₂s) | sT · h(或 sT·W·h) |
| 计算成本 | 较高(要过一层小网络) | 很低(就是矩阵乘法) |
| 效果 | 在隐藏维度很大时稍稳 | 维度小时和 Bahdanau 打平 |
| 谁赢了 | 2014 年提出,早期主流 | 2015 年提出,成为后来所有注意力的基础(Transformer 用的就是点积) |
| 为什么要除以 √d | 点积的方差随维度 d 线性增长。d 大时分数会变得极大,
softmax 之后就变成"只有一个位置是 1,其余全是 0"—— | |
互动 · 为什么非要除以 √d:把隐藏维度调大试试
随机生成 d 维的 s 和 5 个 h,真做点积、真过 softmax。右图取 5 次试验里最典型的一次,
左边数字是平均值(单次只有 5 个数,噪声大)。
极差 = 最大分 − 最小分;熵越大分布越平均、越小越集中在少数位置
(5 个位置完全平均时熵 = ln5 = 1.609,这是上限)。
拖动滑块看 d 从 8 涨到 512:注意「平均熵」那一列——原始点积掉向 0,除以 √d 的那行留在 1 以上。
原始点积的极差随 d 一起变大:d 个独立项相加,方差是 d 而不是 1。 极差一大,softmax 就退化成 one-hot——只有最大的那个位置拿到梯度,其余全被压成 0。
| 问题 | 注意力解决了吗 |
|---|---|
| 长句信息瓶颈 | 解决了。 |
| 长距离梯度 | 大幅改善。从"必须穿过 n 个时间步"变成"一步直达" |
| 语序不一致 | 解决了。对齐是学出来的,不要求单调 |
| 顺带一个福利:权重可以画出来看,知道模型"在看哪" | |
| 不能并行 | 完全没解决。 |
| 计算量 | 变大了。每生成一个词都要和所有源位置算一遍 |
互动 · 注意力把「要穿多少步」压成 1 步
互动 · 省下的那部分代价去哪了:比对次数从 m 涨到 m × n
2017 年那篇论文的标题就是答案:《Attention Is All You Need》——把 RNN 整个删掉。
既然注意力已经能让任意两个位置直接通信,那循环带来的"顺序感"还有什么用?
删掉 RNN 之后:所有位置可以同时计算(并行),路径长度变成 O(1),
而且注意力本身可以叠很多层。
代价是:没了循环,就没了"词序"的概念,必须另外加
这一章真正想说的只有一句: 对付“信息太多装不下”的办法,不是把盒子做大,是不要盒子。 而这背后的张力,属于第一性原理那七条线里的第一条(下面那张表是另一套问题清单:六条暗线)。
回到第 3 节第二个互动(两种打分器各画一张对齐图)。 把最下面那个「训练步数」滑块从 0 拖到 500:右边加性打分器的三个矩阵, 每一步都是真的反向传播 + SGD,TV 从 0.5 左右掉下去,学会了左边那张图的形状。
但左边那张图的成本:一个参数都没有。500 步梯度、三组矩阵和一份训练数据,换回来的只是“追平”。 这就是「表达力 vs 泛化」:当结构本身就带着正确答案的形状(“意思对得上,点积就大”), 再加参数只是给它一个变笨的机会。
| 暗线 | 这一章的回答 |
|---|---|
| A 信息流动 | 数据形状:源句 [nsrc] → [nsrc, h](这一章最大的变化:从“只要最后一个”变成“全都留着”)→
每个解码步拿 [h] 和所有源位置算分 → softmax → 加权求和 → 输出
[V]。(记号:nsrc 源句词数、ntgt 译文词数、h 记忆宽度、V 词表大小。)
信息不再被压扁,而是按需抽取——这是它和 Seq2Seq 的根本差别 |
| B 什么被牺牲了 | 牺牲了 O(n) 的成本(每步和所有源位置比对)和「相邻的词更相关」这个假设;
换回来的是任意两个位置一步直达,路径从 O(n) 降到 O(1)。
但“不能并行”没解决: |
| C 参数账本 | 注意力自己加了多少参数?加性(Bahdanau)W₁、W₂、v:h=512 时 ≈ 52 万,
和一个单层 RNN 相当;乘性(Luong 全局)一个 h×h,≈ 26 万;点积:0。 对比 Seq2Seq 原文(4 层 |
| D 跑在什么上 | 训练和推理分开看:训练时把正确译文整句喂进去(teacher forcing),
所有位置的分数能攒成一次大矩阵乘([ntgt, nsrc])——
一次大乘法比很多次小乘法快,这一步已经暗示了 Transformer;推理时每生成一个词才能算下一次注意力,只能逐字串行,最贵的是等上一个词 |
| E 它假设了什么 | ① 相关性可以用一个打分函数表示——每个位置都得分一点权重,不能干脆跳过不看(这叫软对齐)。 ② 看一眼原文 = 对原文的表示做加权平均——α 是非负、和为 1 的 softmax,c 只能是 h 的混合。 ③ 位置本身不重要——去掉 RNN 之后词序就真的一无所有了, 所以后面 |
| F 违背了哪个直觉 | “计算量更大 = 更慢”——在 GPU 上不一定:n 次小比对凑成一整块大矩阵乘,反而可能更快。 “长句就得把记忆加大”——错:救回长句的是零参数的点积。 “加模块 = 加成本”——这次它直接拆掉了瓶颈:固定向量 c 消失了 |
它接住了上一章的什么:LSTM(《LSTM / GRU》)保住了记忆,
最后还是得把它压成一个向量交给
它给下一章留了什么:注意力已经让任意两个位置直接对视,循环还剩什么用? 把 RNN 也删掉,就只剩注意力本身了——完整推导在《注意力机制》。
注意力只有三步:打分 → softmax 归一化 → 加权求和。
它解决的问题是 Seq2Seq 的固定长度瓶颈——让
它顺手解决了长距离梯度、语序不一致、
上面讲的都是「够用」的版本。想往下挖,这里有三个入口—— 它们不是必修内容,是给想再往前走一步的读者准备的。
这一章讲的注意力,工业界真的在跑——下面就是那个解码器。 注意这一段只是解码器的一步;完整的训练程序要再往后两章,在 《Transformer 自注意力》里。