上一章节完成了单头注意力的计算:一组 Q、K、V,产生一个注意力分布,融合上下文信息。
但一组注意力只能捕捉一种关系。在自然语言中,两个词之间的关系是多层次的:
- 「她开心地笑了」——「笑」和「她」之间有主谓关系。
- 同一句话里,「笑」和「开心」之间有状语修饰关系。
- 「笑」和「了」之间有时态标记关系。
一个注意力头只能学习其中一种关系——它的 Q、K、V 权重矩阵被训练来识别某种特定的匹配模式。要同时捕捉多种关系,需要多个注意力头并行工作。
怎么做到多头
多头注意力(Multi-Head Attention)的思路很直接:把维度分成多份,每份独立做一次注意力,最后把结果拼起来。
Sophia 有 16 个注意力头。隐藏维度是 1,536,分成 16 份,每份 96 维(1,536 ÷ 16 = 96)。
具体步骤:
第一步:生成 Q、K、V(和单头一样)。
Q = X × W_Q (序列长度 × 1536)
K = X × W_K (序列长度 × 1536)
V = X × W_V (序列长度 × 1536)
第二步:拆分成 16 个头。
把每个向量的 1,536 维切成 16 段,每段 96 维:
Q 的第 1 个头: 前 96 维
Q 的第 2 个头: 第 97-192 维
Q 的第 3 个头: 第 193-288 维
...
Q 的第 16 个头: 第 1441-1536 维
K 和 V 也同样拆分。
第三步:每个头独立计算注意力。
16 个头各自在自己的 96 维空间里计算:分数 = Q_i × K_i 的转置 / √96,softmax,然后乘以 V_i。每个头得到一个 序列长度 × 96 的输出。
第四步:把 16 个头的输出拼起来。
把 16 个 96 维的输出沿维度方向拼接,恢复成 1,536 维:
拼接后 = [头1输出 | 头2输出 | ... | 头16输出] (序列长度 × 1536)
第五步:最后一次矩阵乘法。
通过一个输出投影矩阵 W_O,把拼接后的结果再做一次线性变换:
最终输出 = 拼接后 × W_O (序列长度 × 1536)
为什么要分成多个头
你可能会问:直接用一个 1,536 维的注意力不行吗?为什么要费力拆成 16 份?
多头让模型能同时学习多种关系。 每个头的 96 维 Q、K、V 权重矩阵是独立训练的,会自然地学到不同的匹配模式。
研究者对训练好的多头注意力做过分析,发现不同的头确实学到了不同的功能:
- 有的头专注于位置关系:关注固定距离之外的 token(比如总是关注前两个词)。
- 有的头专注于语法关系:主语关注谓语,修饰语关注被修饰的词。
- 有的头专注于语义相关性:关注含义相近或相关的词。
- 有的头似乎在做复制:当需要重复某个词时,这个头会强烈关注那个词的位置。
这种分工不是人为设计的——模型在训练中自己学会了用不同的头做不同的事。
多头的另一个好处是计算效率。 16 个头各自在 96 维空间里计算注意力,总计算量和一个 1,536 维的注意力几乎一样——因为计算量主要取决于维度的平方,而 16 × 96² = 16 × 9,216 = 147,456,和 1,536² = 2,359,296 不同?
等等,这样算不对。实际上,16 个头的计算量确实和单头差不多——关键在于 QK 的矩阵乘法。单头是 (n×1536) × (1536×n) = n² × 1536 次乘法。多头是 16 × (n×96) × (96×n) = 16 × n² × 96 = n² × 1536 次乘法。一样。
所以多头注意力并没有增加计算量,但增加了表达能力——从一种关注模式变成了 16 种。这是一个免费的能力提升。
Sophia 的注意力配置
Sophia 的 28 层采用了一种特殊的排列:每四层为一组,前三层使用 KDA(一种线性注意力变体),第四层使用 MLA(Multi-head Latent Attention)。
这两种注意力都使用多头设计,但内部的计算方式不同——KDA 和 MLA 分别是第 17 和第 22 章节的主题。现在只需要知道:多头注意力是所有这些变体的基础框架,区别只在于每个头内部怎么计算 Q、K、V 以及怎么处理历史信息。
下一章节来看一个实际工程问题:当模型在推理时(已经训练完,正在和你对话),它需要把之前看过的每一个 token 的 K 和 V 向量存起来——这就是 KV cache。它为什么必须存在,以及为什么它会消耗大量显存。