前两篇我们建立了注意力的动机,并理解了单头自注意力的 QKV 运算。但单头注意力有一个根本局限:一组注意力权重只能捕捉一种关系模式。同时,自注意力本身对词的先后顺序完全「失明」——交换两个词的位置,注意力分数不变。

今天这篇解决这两个问题:多头注意力为什么比单头更好,以及位置编码如何把「顺序」信息注入 Transformer。


单头注意力的瓶颈:一个观点,一次只能看一个

回顾上一篇的核心公式:

Attention(Q,K,V)=softmax ⁣(QKdk)V\mathrm{Attention}(Q, K, V) = \mathrm{softmax}\!\left(\frac{QK^\top}{\sqrt{d_k}}\right)V

对于每个词,它只产生 一组注意力权重——一个对所有其他词的软性选择。但语言是复杂的:读一个句子时,我们同时需要知道语法关系(主语-谓语)、语义关系(形容词-名词)和局部结构(介词连接)。一组权重只能算出一个综合分数,无法同时捕捉多种关系 1

举个例子。句子 "The tired cat sat on the warm mat" 中,我们想知道 "cat" 和 "sat" 的语法关系,也想捕捉 "tired" 修饰 "cat" 的语义关系。单头注意力被迫把这些关系揉成一个分数——它可能抓住了语法关系,却丢失了语义关系,反之亦然 1

这就是单头注意力的瓶颈:一个视角只能关注一个方面,其他方面就被平均掉了

多头注意力:多个视角同时工作

多头注意力的想法非常直接:与其用一组 QKV 投影,不如用 h 组不同的投影,并行计算 h 次注意力,然后把结果拼回来 2

用数学表达:

MultiHead(Q,K,V)=Concat(head1,,headh)WO\mathrm{MultiHead}(Q, K, V) = \mathrm{Concat}(\mathrm{head}_1, \ldots, \mathrm{head}_h)W^O

其中每个头:

headi=Attention(QWiQ,KWiK,VWiV)\mathrm{head}_i = \mathrm{Attention}(QW_i^Q, KW_i^K, VW_i^V)

多头注意力:多个独立的 QKV 投影并行计算,输出拼接后投影回原维度

上图来自 Jay Alammar 的经典讲解,展示了多头注意力中每个头有自己的 Q、K、V 权重矩阵,各自并行计算注意力,最后把结果拼接并通过 WOW^O 投影回原始维度 2

一个关键设计是:总参数量不变。假设模型维度 dmodel=512d_{\text{model}} = 512,头数 h=8h = 8,那么每个头工作在 dk=dv=512/8=64d_k = d_v = 512/8 = 64 维空间里。8 个头各用 64 维,总计算量与一个 512 维的单头注意力大致相同——但模型获得了 8 个不同的「视角」 3

为什么这样有效?看看训练好的 Transformer 中不同头学到的模式 1

头类型学到的模式举例
位置型关注相邻/固定偏移位置位置 i 的词总关注位置 i-1
语法型主语-谓语一致"The dogs ... are barking"
语义型词义关系"bank" 关注 "river" 或 "money"
分隔符型关注标点/特殊 token聚焦句号、逗号、[SEP]
罕见词型关注低频词专有名词获得额外关注

原始论文中,研究者在编码器第 5 层发现,一个头专注于 "making" 与远处 "more difficult" 之间的长距离依赖,另一个头则专注于指代消解——"its" 指向句子中哪个名词 3不同的头在无监督下自动学会了分工

类比:手电筒 vs 多盏探照灯

一个简单但有效的类比:单头注意力像一只手电筒,只能照亮句子的一部分;多头注意力像多盏探照灯,从不同角度同时照亮句子,每盏灯关注不同的关系 4。它们的输出拼接在一起,再经过一个投影矩阵 WOW^O 混合——这个矩阵学会如何把各头的视角整合成最终的上下文表示。


有了多头注意力,还缺什么?

现在我们已经知道多头注意力可以同时关注不同关系。但还有一个问题没有解决:自注意力本身不知道词的先后顺序

考虑两个句子:「狗咬人」和「人咬狗」。对自注意力来说,这两个序列的词嵌入集合是一样的——"狗"、"咬"、"人"——只是排列不同。但注意力分数只取决于词本身的内容,不取决于它们的位置。所以自注意力对这两个句子会产生完全相同的注意力权重 5

这显然不对。词的顺序在自然语言中至关重要。

位置编码:给每个词贴上一个「座位号」

Transformer 的解决方案很巧妙:在输入进入注意力层之前,给每个词的位置生成一个向量,加到词嵌入上 5

输入表示=词嵌入+位置编码\text{输入表示} = \text{词嵌入} + \text{位置编码}

位置编码 PEPE 与词嵌入维度相同(都是 dmodeld_{\text{model}}),所以可以直接相加。就像一个音乐会的座位号贴在门票上——同一个人的票,座位不同,票就不同。

原始 Transformer 使用的是一种 固定公式生成 的位置编码——正弦波位置编码(Sinusoidal Positional Encoding)3

PE(pos,2i)=sin(pos100002i/dmodel)PE_{(pos, 2i)} = \sin\left(\frac{pos}{10000^{2i/d_{\text{model}}}}\right)

PE(pos,2i+1)=cos(pos100002i/dmodel)PE_{(pos, 2i+1)} = \cos\left(\frac{pos}{10000^{2i/d_{\text{model}}}}\right)

其中 pospos 是位置索引(0, 1, 2, ...),ii 是维度索引。公式看起来有点复杂,但直觉其实很简单。

钟表类比:不同频率的波

想象一个钟表:秒针走得最快(高频),分针走中等速度,时针走得最慢(低频)。三个指针组合在一起,唯一地标识了任何一个时刻 5

正弦波位置编码做了同样的事情:

  • 低维度ii 小,分母小,频率大):变化快,像秒针——捕捉精细的位置差异
  • 高维度ii 大,分母大,频率小):变化慢,像时针——捕捉粗略的位置信息

每一维是一个不同频率的波,所有维度组合在一起,给每个位置一个唯一的「指纹」 6

20个位置、512维的正弦波位置编码热力图,每行是一个位置的编码向量

上图展示了 20 个位置的位置编码热力图。每行对应一个位置,从左到右是 512 个维度。可以看到低维度(左半部分)变化快,高维度(右半部分)变化慢,形成独特的条纹模式 5

两个重要性质

1. 相邻位置编码相似。 位置 2 和位置 3 的编码向量比位置 2 和位置 50 的编码更相似。这意味着模型可以学习「相对位置」模式——比如「我左边第二个词通常是动词」——这个规律在位置 5 和位置 500 都同样适用 5

2. 可以外推到更长的序列。 因为位置编码是用公式生成的,而不是训练出来的,所以模型训练时最多见过 512 个词的序列,推理时也能处理 1000 个词的输入——只需对更大的 pospos 直接计算正弦/余弦值即可 3


这两块拼图如何组合

多头注意力和位置编码是 Transformer 编码器的两个核心组件:

  1. 位置编码 把顺序信息注入每个词的表示
  2. 多头注意力 让模型在多个子空间同时关注不同关系

组合起来,一个编码器层做的事情是:先做多头注意力(让每个词吸收上下文信息),再做前馈网络(逐位置处理)。我们将在下一篇进入 完整的 Transformer 架构——编码器与解码器的堆叠、残差连接和层归一化。

References