模块 05 · 约 25 分钟 · 核心模块

注意力机制:Transformer 的灵魂

这是整门课最重要的一节。「Attention is All You Need」(2017)这篇论文一口气把循环神经网络拍到墙上, 从此所有大模型都是 Transformer。而 Transformer 的核心 — 就是这一节要讲的注意力。 看完这节你应该能回答:什么是 Q、K、V?为什么是 softmax(QKᵀ/√d) V?为什么要 mask?

① 直觉:读一句话时,眼睛会"回头看"

读这句英文:

The animal didn't cross the street because it was tired.

你读到 it 的瞬间,眼睛会回头看「animal」—— 你必须知道 it 指代谁, 才能理解整句话。但读同一句的另一个版本:"…because it was too wide" 时,it 又指代 street。

这种"读当前词时,要不要回头看哪些词、看多重"的能力,就是注意力。 Transformer 把这件事数学化了 —— 让模型在算每个 token 的表示时,根据需要"加权聚合"前面所有 token 的信息。

② 互动:看真实的注意力热力图

下面这张表叫注意力热力图。每行是一个 token 在「算自己」时,对其他 token 的加权关注程度(颜色越深 = 关注越多)。 切换到代词指代那个例句,看 it 那一行 — 它强烈关注 animal, 这就是模型在做共指消解

句子:
100
20
80
5
55
40
10
40
48
5
25
30
38
8
40
10
22
17

怎么读这张图:每行代表一个 token「主动看」其他 token 的程度。比如第 N 行第 M 列的颜色越深, 表示"算 token N 的表示时,token M 的贡献越大"。每行加起来等于 1。

留意右上角三角形是灰的 —— 这就是 causal mask(因果遮罩):自回归语言模型只能看自己和前面的 token,不能"偷看"未来。

关键观察:(1)每一行的权重加起来等于 1(softmax 的结果); (2)右上三角是灰的 — 这是 GPT 类自回归模型的 causal mask,禁止"看未来"; (3)真实模型有几十层 × 几十个 head,每个 head 学到不同的关注模式(指代、句法、远距离依赖...)。

③ Q、K、V:图书馆的类比

核心公式来了:

Attention(Q,K,V)=softmax ⁣(QKdk)V\mathrm{Attention}(Q, K, V) = \mathrm{softmax}\!\left(\frac{QK^\top}{\sqrt{d_k}}\right) V
↓ 对应的 Python 实现(可以直接改、直接运行)

Q、K、V 这三个字母让很多人犯怵。其实用一个图书馆的类比就一目了然:

  • Q (Query, 查询):你现在站在书架前,心里想找的东西。 比如「我在算位置 7(it)的表示,我想找谁来解释我自己」。
  • K (Key, 关键字):每本书书脊上贴的标签。 每个 token 都贴一个:「我是名词」「我是动词」「我是 animal 这个词」。
  • V (Value, 内容):每本书翻开后的实际内容。 也是每个 token 一份。你要的最终信息存在这里。

过程:

  1. 找匹配:你的 Query 和每本书的 Key 做点积,越像分越高 → QKQK^\top
  2. 缩放 + softmax:把分数归一化成"看每本书的概率"
  3. 加权读 Value:按概率取对应 Value 的加权平均,就是你这次查询的"答案"

关键的关键:Q、K、V 不是天上掉下来的,它们都是从同一个输入 X经过三个不同的线性投影算出来的:

python
直接编辑这段代码即可。输入 np. 看自动提示,⌘/Ctrl + Enter运行。

所以模型实际学习的,就是这三个投影矩阵 WQ,WK,WVW_Q, W_K, W_V。 训练让它们"长出能用"的样子 — 学到怎么从一个 token 抽出合适的 query、合适的 key、合适的 value。

④ 公式逐项拆解

把公式 softmax(QK/dk)V\mathrm{softmax}(QK^\top / \sqrt{d_k}) V 一项一项过:

4.1 QKQK^\top:算"相似度矩阵"

Q 形状 (L,dk)(L, d_k)(L 个 token 各自的 query),K 形状也是 (L,dk)(L, d_k)。 转置一下 K 就是 (dk,L)(d_k, L),相乘得到 (L,L)(L, L) 矩阵。 第 i 行第 j 列 = Q[i] 和 K[j] 的点积 = 第 i 个 token 对第 j 个 token 的"相关性分数"。

4.2 /dk/\sqrt{d_k}:缩放

如果不除以 dk\sqrt{d_k},当 dkd_k 大时, 点积的量级会变成 O(dk)O(\sqrt{d_k}), 送进 softmax 后会变得极尖锐,几乎是 one-hot,梯度几乎为 0 —— 训练就卡住了。 除以 dk\sqrt{d_k} 把方差打回 1,softmax 才能正常工作。

4.3 mask:禁看未来

GPT 类自回归模型只能用"上文"预测"下文"。如果让位置 i 看到 i+1、i+2..., 训练就成了抄答案。所以在 softmax 之前,把上三角(j > i)的位置全设成 -∞, softmax 后变成 0:

maskij={0jij>i\mathrm{mask}_{ij} = \begin{cases} 0 & j \le i \\ -\infty & j > i \end{cases}
↓ 对应的 Python 实现(可以直接改、直接运行)

4.4 softmax:归一化成"概率"

沿每一行做 softmax,把分数变成"每个 token 我看多重"的权重。每行加起来 = 1。 这正是上面热力图里看到的样子。

4.5 V\cdot V:按权重把 value 加起来

权重矩阵 (L,L)(L, L) 乘 V 矩阵 (L,dv)(L, d_v),得到输出 (L,dv)(L, d_v)。 第 i 行 = 用第 i 行的权重对所有 V 加权求和 = 第 i 个 token 经过注意力后的新表示。

⑤ 代码:完整跑一遍单头注意力

把上面所有概念压成 8 行 Python,点「▶ 运行」感受一下:

python
直接编辑这段代码即可。输入 np. 看自动提示,⌘/Ctrl + Enter运行。

⑥ Multi-Head Attention:用多个角度同时看

一个 head 的注意力只能学一种"关注模式",但人类读文本时同时关注好几件事:句法依赖、共指、语义相关、距离... Transformer 的解决办法是多头注意力(Multi-Head Attention, MHA):

  • 把 d 维向量切成 h 份,每份 dk=d/hd_k = d/h 维(比如 d=768, h=12, 每份 64 维)
  • 每一份独立算一次 attention,得到 h 个 (L,dk)(L, d_k) 的输出
  • 拼起来再过一个线性层 WOW_O 混合信息
MHA(X)=Concat(head1,,headh)WOheadi=Attention(XWiQ,XWiK,XWiV)\begin{gathered} \mathrm{MHA}(X) = \mathrm{Concat}(\mathrm{head}_1, \ldots, \mathrm{head}_h) W^O \\ \mathrm{head}_i = \mathrm{Attention}(X W^Q_i, X W^K_i, X W^V_i) \end{gathered}
↓ 对应的 Python 实现(可以直接改、直接运行)

实践中不同的 head 真的会学出非常不同的关注模式 — 有些专门做"上一个名词指代谁", 有些专门做"动词找主语",有些专门做"括号配对"。 这种"分而治之"是多头比单头强的关键。

⑦ 一个常见错觉:注意力≠理解

看完热力图你可能觉得:「啊原来 it 真的"指向" animal,模型懂了!」 —— 小心:这种解释是事后的。

模型只是:算了点积,做了 softmax,加权求和。它没有「指代」「主语」「修饰」这些符号化概念。 我们看注意力图看到的"语义",是模型为了让损失最小,恰好把权重分布得像人类直觉而已。 2019 年起有大量研究表明:注意力权重可以被对抗性扰动而不影响输出,注意力不等于因果解释。

这点你以后看 Anthropic 的 "Mechanistic Interpretability" 工作时会更深体会。但学习阶段,把热力图当直觉助手就够了。

⑧ 小测验

Q1.Attention 公式里为什么要除以 √d_k?
Q2.为什么 GPT 类模型必须用 causal mask?

⑨ 延伸阅读