在汽车装配厂的质检车间里,传送带源源不断地送来零件,老质检员老张必须在一个零件经过最后一站时,凭一句话总结判断整条生产线有没有问题——这显然会漏掉大量细节。后来厂里发明了一种“回看记录”的方法:不是只看最后一句话,而是随时调取每个工位的原始质检日志,给相关工位的记录加权打分。再后来,一个质检员看不过来,厂里请来多位专家:红镜师傅专看裂纹、蓝镜师傅专看划痕、绿镜师傅专看镀层,他们同时观察、汇总意见——这就是“多头注意力”。最后,厂长干脆把传送带拆了,改成圆桌工位,每个人都能同时看到所有人的发言——这就是后来的自注意力。本文就用这条流水线的故事,讲透多头注意力在 RNN 里的来龙去脉。

岗位关联

学懂多头注意力,你就掌握了从 seq2seq 到 Transformer 的关键跳板,面试时能把“Attention 演进”讲成一条完整故事线,这是 NLP 岗位的基本功。

目录
  1. 可视化演示
  2. 源头问题:长序列的瓶颈
  3. RNN注意力:按需取用
  4. 多头机制:多位专家各看一面
  5. 单头局限与多头优势
  6. 自注意力:全员圆桌会议
  7. 演进脉络:从传话到平行对话
  8. 实践要点:别把流水线建歪了
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

本节配有交互动效(进入视口后自动加载,约 3KB)。

单头交叉注意力:Query来自解码器,Key/Value来自编码器 编码器隐藏状态 (Key/Value)解码器隐藏状态 (Query)Q: 解码器状态 | K,V: 编码器隐藏状态 | 单头只能关注一种模式Attention(Q,K,V) = softmax(QK^T/\u221Ad_k)V编码器隐藏状态 (...

源头问题:长序列的瓶颈

故事要从最初的装配线讲起。老张是流水线末端的记录员,他的工作方式很特别:每经过一个零件,就把上一句话和当前零件的情况“挤”成最新的一句话,最后只把这句话交给质检台。句子一长,“挤”的过程就不断丢细节——前面工位的一次轻微划伤,早就被后来的信息冲得无影无踪。这就是传统 seq2seq 翻译模型的困境:编码器把整句源语言压缩进最后一个隐藏状态。

在神经网络里,编码器逐个读入单词,每一步更新隐藏状态 $\mathbf{h}_i$,最后用时刻 $T$ 的状态当作整句话的摘要。解码器只能依赖这个“一句话总结”生成翻译,句子越长、信息越挤,后面的单词几乎把前面的语义都覆盖掉了。更糟的是,RNN 在长距离反向传播时梯度会指数衰减,开头单词的信息根本走不到句尾。

回到工厂,老张这种“只记最后一句话”的做法让质检部门叫苦不迭。后来厂里想通了一个道理:为什么不让质检台直接回看每个工位自己的原始记录?这正是注意力的起点——不再把整条流水线压成一句话,而是让解码器随时翻阅每一站的台账。

c=hT\mathbf{c} = \mathbf{h}_T
这条式子说明:整个句子的信息被压成了末尾一个向量,容量极其有限。
  1. RNN 隐藏状态序列编码器读入第 $i$ 个词后得到隐藏状态 $\mathbf{h}_i$,最后一个时刻 $T$ 的状态是 $\mathbf{h}_T$。
    hT∈Rd\mathbf{h}_T \in \mathbb{R}^{d}
  2. 当摘要用传统 seq2seq 把 $\mathbf{h}_T$ 直接当作编码器的上下文向量 $\mathbf{c}$,解码器每一步都只拿到这一个向量。
    c=hT\mathbf{c} = \mathbf{h}_T
  3. 信息瓶颈$T$ 越大,序列越长,定长向量 $\mathbf{c}$ 的“丢细节”问题越严重,这就是论文说的 "information bottleneck"。
    T 越大⇒丢失越多T \,\text{越大} \Rightarrow \text{丢失越多}

RNN注意力:按需取用

于是质检流程改版了。解码器每生成一个新输出,不再是干等那一句总结,而是拉出一份“全流水线历史记录”:第 3 号工位的螺丝扭矩记录、第 7 号工位的喷漆色号记录……每份记录对应一个相关性分数,相关度高的记录就用粗线标出来,相关度低的就淡化成背景。这就是 Bahdanau 在 2015 年提出的注意力机制,它让解码器在每一步都动态地决定“该看哪些工位”。

技术上,编码器不再只保留最后一个状态,而是保存每一步的隐藏状态 $\mathbf{h}_1, \mathbf{h}_2, \ldots, \mathbf{h}_T$。解码器生成第 $j$ 个词时,先用解码器的上一状态 $\mathbf{s}_{j-1}$ 与每个 $\mathbf{h}_i$ 计算一个对齐分数 $e_{ij}$,表示“源位置 i 与当前输出位置 j 的相关程度”。

光有分数还不够,分数要先变成“权重”。把第 $j$ 步的所有 $e_{1j}, \ldots, e_{Tj}$ 做一遍 softmax 归一化,得到概率分布 $\alpha_{ij}$,再对全部 $\mathbf{h}_i$ 做加权求和,得到这一步的上下文向量 $\mathbf{c}_j$。于是每次翻译“看见”的源词重点都不一样,而不是永远盯着句末。

工厂里这套“按需回看”立刻见效,翻译质量大幅提升。可老张又发现一个问题:他自己再厉害,一双眼睛只能盯着一种指标——看了扭矩就顾不上漆面。能不能多请几位各有所长的质检员,让他们同时看、最后合议?这就是多头注意力登场的契机。

eij=va⊤tanh⁡(Wahi+Uasj−1)e_{ij} = \mathbf{v}_a^\top \tanh(\mathbf{W}_a \mathbf{h}_i + \mathbf{U}_a \mathbf{s}_{j-1})
上下文向量从“固定一句话”变成了“按需调取的加权台账”。
  1. 权重归一化$\alpha_{ij}$ 是第 $j$ 个输出位置上第 $i$ 个源词的注意力权重,由 softmax 保证所有权重为正且和为 1。
    αij=exp⁡(eij)∑k=1Texp⁡(ekj)\alpha_{ij} = \frac{\exp(e_{ij})}{\sum_{k=1}^{T}\exp(e_{kj})}
  2. 加权合成$\mathbf{c}_j$ 按权重把全部编码器状态合成一个向量,权重大的源词在 $\mathbf{c}_j$ 中占主导。
    cj=α1jh1+α2jh2+⋯+αTjhT\mathbf{c}_j = \alpha_{1j}\mathbf{h}_1 + \alpha_{2j}\mathbf{h}_2 + \cdots + \alpha_{Tj}\mathbf{h}_T
  3. 动态性每一步的 $\alpha$ 分布都不同,相当于每次翻台账时眼光落在不同工位——这就是“对齐”带来的灵活。

多头机制:多位专家各看一面

厂长请来三位质检专家:红镜师傅专注检查金属裂纹,绿镜师傅监督表面镀层,蓝镜师傅盯螺丝扭矩。他们把各自看到的重点写在三张不同的台账上,最后合到一起形成一份完整报告。多头注意力就是把这个“分工合议”过程公式化:不再用一套 Q、K、V 算一次注意力,而是用 $h$ 组权重矩阵,把输入投影到 $h$ 个子空间,每组独立计算注意力,最后拼接融合。

为什么这样做有效?语言里的关系往往是多重的:翻译一个代词时,既要知道它指代哪个名词(语法关系),又要知道它处于什么语境情绪(语义关系)。单一注意力头只能捕捉一种主要的关联模式,多个头则各管一类。在 RNN 场景里,编码器的隐藏状态序列就是“流水线台账”,多头注意力可以同时从句法、语义、位置等多个角度观察这段序列。

回到工厂,三位质检员各自只写“自己的重点”,最后把三份报告钉在一起成一份综合结论。解密器拿到的不再是单一视角的加权和,而是一份多维度融合的评估报告。

MultiHead(Q,K,V)=Concat(head1,…,headh)WO\text{MultiHead}(\mathbf{Q}, \mathbf{K}, \mathbf{V}) = \text{Concat}(\text{head}_1, \ldots, \text{head}_h)\mathbf{W}^O
多头不是把注意力“多跑几遍”,而是把输入从不同“视角”投影后再并行计算,最后合议。
  1. 多头并行计算第 $i$ 个头用自己的投影矩阵变换 $\mathbf{Q}$、$\mathbf{K}$、$\mathbf{V}$,然后各自执行一次注意力运算,得到 $\text{head}_i$。
    headi=Attention(QWiQ,KWiK,VWiV)\text{head}_i = \text{Attention}(\mathbf{Q}\mathbf{W}_i^Q, \mathbf{K}\mathbf{W}_i^K, \mathbf{V}\mathbf{W}_i^V)
  2. 拼接$\text{Concat}$ 把 $h$ 个头的输出沿特征维拼接起来,维度从 $d_v$ 恢复为 $h \times d_v$。
    Concat(head1,…,headh)\text{Concat}(\text{head}_1, \ldots, \text{head}_h)
  3. 输出融合乘以输出投影矩阵 $\mathbf{W}^O \in \mathbb{R}^{h d_v \times d_{\text{model}}}$,把 $h$ 个视角的信息压缩回与输入相同的维度。
    WO:Rhdv→Rdmodel\mathbf{W}^O : \mathbb{R}^{h d_v} \rightarrow \mathbb{R}^{d_{\text{model}}}

单头局限与多头优势

如果只请一位质检员,会发生什么?他要么只能盯裂纹,要么只能盯扭矩,看多了眼睛就花。单头注意力也是如此:一整份 $\mathbf{Q}\mathbf{K}^\top$ 里的所有信息被压缩进一次 softmax 分布,模型只能学到一种占主导的对齐模式,其他关系被平均掉了。

多头注意力则不同。它把模型的表达能力拆成 $h$ 条更窄的通道,每条通道专注一种关联模式。比如一个头专门学习中英文的语序对应关系,另一个头专门学习名词和代词的同指关系,第三个头则捕捉长距离的修饰关系。正因为每个头的维度变窄,反而“被迫”学得更专一。

工厂里,三位质检员每人只看一项指标,不存在“看不全面”的问题,也不用担心请三倍的人会付三倍工资——因为他们每个人只做原来三分之一的工作量。数学模型上也正是如此:多头让“表达宽度”换成了“表达深度”,整体开销几乎持平。

dv=dmodel/hd_v = d_{\text{model}} / h
总维度不变,头的数量越多,每个头分到的维度越少,注意力就越“专注”。
  1. 总维度 $d_{\text{model}}$是输入隐藏状态和最终输出的维度,它决定了模型的表示容量。
    dmodel=h×dvd_{\text{model}} = h \times d_v
  2. 每头维度 $d_v$每个头在低维子空间 $d_v$ 中做注意力,子空间越小越容易学出“专门化”模式。
    dv=dmodel/hd_v = d_{\text{model}} / h
  3. 计算量平衡所有头总的矩阵乘法规模与单头几乎一样——相当于请了 $h$ 位专家,但每位只看一个切面,总劳动量没增加多少,覆盖的维度却广得多。
    FLOPsmulti≈FLOPssingle\text{FLOPs}_{\text{multi}} \approx \text{FLOPs}_{\text{single}}

自注意力:全员圆桌会议

故事在这里迎来转折。厂长发现,传送带式的 RNN 有个天生缺陷:信息必须一站一站往后传,第 1 站的信息传到第 20 站要拐 19 道弯,途中不断衰减。于是厂长决定开会——干脆把传送带拆了,所有人围坐一张圆桌,任何两个人之间可以直接对话。这就是 Self-Attention:句子里的每个词都跟所有其他词直接计算关联,不需要经过中间词的接力传递。

在公式上,Self-Attention 与普通注意力唯一的区别是 $\mathbf{Q}$、$\mathbf{K}$、$\mathbf{V}$ 都来自同一个序列 $\mathbf{X}$——也就是“自己和自己注意力”。RNN 里的源词序列是“别人的台账”,而 Self-Attention 里每个位置同时是查询方、被查询方和被聚合方。更妙的是,所有位置之间的计算可以写成一次矩阵乘法,整体并行完成,不再有循环依赖。

圆桌会议上,任何两个人之间的对话都是一步直达,不再有中间人传话的损耗。Self-Attention 也因为这个特性,后来被 Transformer 收为心脏,成为大语言模型的基石。

Attention(Q,K,V)=softmax(QK⊤dk)V\text{Attention}(\mathbf{Q}, \mathbf{K}, \mathbf{V}) = \text{softmax}\left(\frac{\mathbf{Q}\mathbf{K}^\top}{\sqrt{d_k}}\right)\mathbf{V}
点积衡量两个位置的相似度,缩放防止分数过大,softmax 归一化后加权求和。
  1. 点积打分$\mathbf{Q}\mathbf{K}^\top$ 算出序列中每对位置之间的相似度矩阵,第 $i$ 行第 $j$ 列表示“第 $i$ 个词应该多关注第 $j$ 个词”。
    QK⊤∈RT×T\mathbf{Q}\mathbf{K}^\top \in \mathbb{R}^{T \times T}
  2. 缩放防饱和除以 $\sqrt{d_k}$,把分数拉回适合 softmax 的尺度,避免分数过大导致梯度消失。
    QK⊤dk\frac{\mathbf{Q}\mathbf{K}^\top}{\sqrt{d_k}}
  3. 归一化加权softmax 把每行归一化成概率分布,再乘 $\mathbf{V}$ 得到加权和,这个和就是“开会后”这个位置的新表示。
    softmax(⋅) V\text{softmax}(\cdot)\,\mathbf{V}

演进脉络:从传话到平行对话

把整个故事串起来看,是一条清晰的升级路径。最初 RNN + seq2seq 只有“一句话总结”(信息瓶颈);接着 Bahdanau 引入注意力,让解码器按需回看所有源词;再后来把单头注意力扩展成多头,让多个子空间并行分工;最后 Self-Attention 彻底去掉循环,让所有位置直接互相通信。每一步都解决了上一步最痛的短板。

Transformer 之所以爆发,是因为它把这条路径推到了极致:编码器和解码器都不再用 RNN,而是层层堆叠 Multi-Head Self-Attention。在这里,$\mathbf{Q}$、$\mathbf{K}$、$\mathbf{V}$ 全部来自同一序列 $\mathbf{X}$,所以叫自注意力;每一层都用多头机制来扩展表达力。RNN 的时序依赖被彻底移除,带来了两个巨大红利:训练可以完整并行,长距离依赖不再衰减。

把时间线逆回去看,Transformer 的每一块砖都来自 RNN 时代:多头机制在 RNN 场景里已经显现优势,Self-Attention 只是把注意力从“解码器看源词”换成“每个位置看所有位置”。工厂从传送带升级为圆桌,成员没换,规则变了,效率却天翻地覆。

X′=MultiHead(XWQ,XWK,XWV)\mathbf{X}' = \text{MultiHead}(\mathbf{X}\mathbf{W}^Q, \mathbf{X}\mathbf{W}^K, \mathbf{X}\mathbf{W}^V)
输入矩阵 $\mathbf{X}$ 同时扮演查询、键、值,输出 $\mathbf{X}'$ 是融合了全局信息的同尺寸矩阵。
  1. 同源输入$\mathbf{X}$ 是序列中所有位置表示组成的矩阵,它被复制成三份,分别作为 $\mathbf{Q}$、$\mathbf{K}$、$\mathbf{V}$ 的来源——所以叫“自”注意力。
    Q=XWQ,  K=XWK,  V=XWV\mathbf{Q} = \mathbf{X}\mathbf{W}^Q,\; \mathbf{K} = \mathbf{X}\mathbf{W}^K,\; \mathbf{V} = \mathbf{X}\mathbf{W}^V
  2. 多头自注意力把这三组投影结果送进 $\text{MultiHead}$,得到全局融合后的表示,序列长度和特征维度不变。
    X′∈RT×dmodel\mathbf{X}' \in \mathbb{R}^{T \times d_{\text{model}}}
  3. 并行性$\mathbf{X}'$ 的计算不依赖上一时刻的输出,整条序列可以一次前向计算完成,这是 RNN 无法做到的。
    X′=MultiHead(X,X,X)\mathbf{X}' = \mathrm{MultiHead}(\mathbf{X}, \mathbf{X}, \mathbf{X})

实践要点:别把流水线建歪了

圆桌会议虽好,布置会场也有讲究。第一个问题是请几位专家合适?实践中 $h=8$ 是最常用的选择,有时用 16;头数太少表达力不足,太多则每个头分到的维度太少、学不到位,还容易让训练数据量需求暴涨。第二个问题是维度要整除:$d_{\text{model}} = h \times d_k$,如果 $512$ 维配 $12$ 个头,分不干净就无法实现标准的子空间分解。

第三个问题是遮罩。开会时如果要求“第 5 号工位不能偷看第 6 号工位已经写好的结论”,这就是 Mask。在解码器里,生成第 $j$ 个词时不允许看到未来词,所以要给注意力矩阵加一个上三角掩码,把未来位置的分数设成负无穷。这个技巧在 Transformer 中继承自 RNN 注意力的“只能看已生成内容”的天然约束。

第四个问题是工程上的“缩放因子 $\sqrt{d_k}$”。RNN 时代的注意力打分方式五花八门:有加法注意力(Bahdanau),也有点积注意力(Luong)。后来发现点积注意力在大维度上需要除以 $\sqrt{d_k}$ 来维持梯度稳定,这个细节被 Transformer 保留并沿用至今。工业界从机器翻译到语音识别,都在用这些经验配置。

| $d_{\text{model}}$ | 常用头数 $h$ | 每头维度 $d_k$ |

| :---: | :---: | :---: |

| 256 | 8 | 32 |

| 512 | 8 | 64 |

| 768 | 12 | 64 |

| 1024 | 16 | 64 |

回到工厂,会场布置得当,会议效率极高;布置不当——比如请一百位专家挤在一起、座位维度切分不匀、让工位偷看未来结论——会议再热闹也是空转。多头注意力也一样,真正决定效果的不是“头多”这个名头,而是对子空间、维度和遮罩这些细节的拿捏。

AI 应用场景

机器翻译:从词对齐到全局意译

阶段:模型架构设计 / 序列建模

解决的问题:传统 SMT 拆词翻译无法处理语序差异;单头注意力只能捕获一种固定的词对齐关系,遇到“他昨天把书给了我”这类涉及多重语法关系的句子容易翻错。多头注意力让翻译模型同时关注主语-谓语搭配、宾语-介词关系、代词指代等多种依赖。

具体案例:Google 的 GNMT(Google Neural Machine Translation)在 RNN 编码器-解码器中引入注意力机制,并结合多头思想扩展对齐能力。面对“猫坐在垫子上,它很舒服”这样的句子,一个头聚焦“猫-它”的同指关系,另一个头聚焦“垫子-在上面”的位置关系,翻译结果显著更自然。后来的 Transformer 正是把这一思路从 RNN 迁移到纯注意力架构。

长文档摘要:多头追踪多个主题线

阶段:信息抽取 / 摘要生成

解决的问题:长文档里往往同时存在多条话题线,单头注意力只能抓住最突出的一条主线,次重要的信息在加权平均中被抹平。多头注意力可以在同一层里并行追踪“核心事件”“人物关系”“时间线”等不同主题线索。

具体案例:在生成式摘要系统中,编码器处理一篇产品评测长文,一个注意力头聚焦“优点关键词”,另一个头聚焦“缺点关键词”,第三个头负责“结论句”。摘要生成时每一句都能从对应主题的源位置取用信息,避免摘要只围绕第一段发挥。

语音识别:声学帧与音素的对齐

阶段:声学特征编码 / 序列对齐

解决的问题:语音识别要把一段声学特征序列映射到文本音素序列,两者长度不同、没有一一对应关系;RNN 做这个任务时天然需要注意力对齐,单头注意力只能学到“帧-音素”的单一映射,遇到口音、噪声时鲁棒性不足。

具体案例:在基于 RNN 的端到端语音识别系统中,多头注意力让一个头关注音素本身的声学形态,另一个头关注发音的上下文(前后音节),第三个头关注停顿和语调边界。三个头联合对齐,歧义音素的识别准确率明显提升,这一方案后来也被 LAS(Listen, Attend and Spell)等模型采用。

Python 演示

python52 行
import numpy as np  def softmax(x):    e = np.exp(x - x.max(axis=-1, keepdims=True))    return e / e.sum(axis=-1, keepdims=True)  class MultiHeadAttention:    def __init__(self, d_model, h, seed=42):        assert d_model % h == 0, "d_model must be divisible by h"        rng = np.random.RandomState(seed)        self.d_model = d_model        self.h = h        self.d_k = d_model // h        self.wq = rng.randn(d_model, d_model) * 0.02        self.wk = rng.randn(d_model, d_model) * 0.02        self.wv = rng.randn(d_model, d_model) * 0.02        self.wo = rng.randn(d_model, d_model) * 0.02     def split(self, x):        T, d = x.shape        return x.reshape(T, self.h, self.d_k).transpose(1, 0, 2)     def attn(self, Q, K, V):        score = Q @ K.transpose(0, 2, 1) / np.sqrt(self.d_k)        weight = softmax(score)        return weight @ V     def forward(self, Q, K, V):        Q = self.split(Q @ self.wq)        K = self.split(K @ self.wk)        V = self.split(V @ self.wv)        heads = self.attn(Q, K, V)        T, _, dk = heads.shape        concat = heads.transpose(1, 0, 2).reshape(T, self.h * dk)        return concat @ self.wo  def fake_rnn_states(T=10, d=16):    rng = np.random.RandomState(0)    return np.tanh(rng.randn(T, d))  if __name__ == "__main__":    T, d_model, heads = 10, 16, 4    H = fake_rnn_states(T, d_model)    model = MultiHeadAttention(d_model, heads)    out = model.forward(H, H, H)    print("RNN hidden states shape:", H.shape)    print("Multi-Head attention output shape:", out.shape)    print("Each head dimension d_k =", model.d_k)
目的:用 NumPy 实现一个最小可运行的多头注意力,输入模拟 RNN 编码器输出的隐藏状态序列,输出多头注意力融合后的序列表示。
  1. assert d_model % h == 0保证总维度能被头数整除,这是子空间均分的前提。
  2. rng.randn(d_model, d_model) * 0.02初始化投影矩阵,小数值防止注意力分数过大。
  3. x.reshape(T, self.h, self.d_k).transpose(1, 0, 2)把矩阵拆成 $h$ 个子空间,并换成“头在前”的维度排列。
  4. score = Q @ K.transpose(0, 2, 1) / np.sqrt(self.d_k)缩放点积注意力:先算相似度矩阵,再除以 $\sqrt{d_k}$。
  5. softmax(score)对每个查询位置做归一化,得到权重分布。
  6. head.transpose(1, 0, 2).reshape(T, self.h * dk)把各头的输出从“按头分组”还原为“按位置排列”的拼接矩阵。
  7. concat @ self.wo乘以输出投影矩阵,把多头信息融合回 $d_{\text{model}}$ 维。

常见误区

误区我一直以为多头注意力是 2017 年 Transformer 论文带来的全新发明,RNN 时代根本不存在这个东西。

正解多头注意力的核心思想在 RNN 时代就已经萌芽。在引入注意力机制的 RNN 机器翻译模型里,研究者就尝试过用多个组件并行计算对齐,后来 Transformer 只是把它和 Self-Attention 组合在一起发扬光大。说白了,工厂里“多组质检员分工”早就试行过,圆桌会议只是把老办法用到了新场景。

为何常见:Transformer 太出名,主流教程把 Multi-Head 和 Self-Attention 打包讲解,大家就误以为两者同时诞生。

误区多头嘛,当然是头越多越厉害。8 个头不够就加到 16、32,效果应该像请更多专家一样越来越好吧?

正解头数增加会摊薄每个头的子空间维度,头数过多时每头分到的信息太少学不到位,还会让参数量与训练数据需求暴涨。经验上 8~16 个头表现最佳,超过这个范围收益递减甚至下降。比喻:质检团队里有一百位专家挤在同一块屏幕前,反而谁都看不清楚。

为何常见:"multi"天然让人贪多,忽略了总维度固定时,头数与每头维度是此消彼长的关系。

误区多个头嘛,就是把同一份 QKV 喂给同一个注意力函数重复跑 h 次,顶多随机初始化不一样。

正解每个头有自己的线性投影矩阵 $\mathbf{W}_i^Q, \mathbf{W}_i^K, \mathbf{W}_i^V$,作用是把 Q、K、V 变换到不同的子空间。真正让头与头不同的不是随机数,而是投影矩阵学出来的“视角”。就像同一颗螺丝,红镜看裂纹、蓝镜看镀层、绿镜看扭矩,镜片不同才叫分工。

为何常见:公式里注意力函数是同一个,初学者容易只看到“重复调用”这一层,忽略了投影才是多头的灵魂。

误区Self-Attention 和 Multi-Head Attention 是一回事,反正 Transformer 里它俩总是一起出现。

正解这是两个正交的维度。“Self“描述的是 Q、K、V 的来源相同(都来自同一序列);”Multi-Head”描述的是计算结构拆成多个子空间并行。可以有单头 Self-Attention,也可以有多头但非 Self 的注意力——比如 RNN 场景里编码器状态是 K、V,解码器状态是 Q,这是典型的非自注意力。

为何常见:Transformer 把两者焊在一起,曝光率太高,概念被捆绑记忆。

误区给 RNN 加上多头注意力之后,模型是不是就能像 Transformer 一样并行训练了?

正解多头注意力只改写了“如何聚合信息”,RNN 的循环递推结构没有变,序列方向上依然逐时刻计算,并行化的瓶颈依旧在。真正让并行成为现实的是 Self-Attention:它彻底删掉了循环依赖,整条序列的注意力矩阵一次矩阵乘法就能算完。比喻:给传送带加再多的质检站,传送带本身还是不能倒着跑。

为何常见:多头注意力的效果提升让人误以为“更强”就等于“更快”,忽略了并行性取决于计算图的依赖关系,而不是层内的表达力。

面试题

Q1. 多头注意力的“多头”设计最初主要用于解决什么问题?

单选题 · easy

  • A.显著提高单个头的运行速度
  • B.同时捕捉多种关联模式← 正确答案
  • C.大幅减少模型存储空间
  • D.替代词向量的位置编码

答案:B。多头把输入投影到多个子空间并行计算,每个头专注一种关联模式,就像多位质检员各盯一项指标,而不是加快单头速度或减少存储。位置编码是 Transformer 的配套设计,与多头无直接关系。

Q2. Bahdanau 注意力中的对齐分数 $e_{ij}$ 主要起什么作用?

单选题 · easy

  • A.计算解码器的隐藏状态向量
  • B.衡量源词与目标词的相关度← 正确答案
  • C.直接输出目标语言的词表
  • D.更新编码器的循环权重

答案:B。$e_{ij}$ 表示第 $i$ 个源词与当前目标位置 $j$ 的匹配程度,分数越高,这个词对生成当前目标词越重要。它不直接输出词表,也不负责更新 RNN 权重。

Q3. 多头注意力中各头的输出是如何合并的?

单选题 · mid

  • A.逐元素相加后非线性激活
  • B.拼接后乘输出投影矩阵← 正确答案
  • C.按词频加权取平均值
  • D.随机抽取一个头的结果

答案:B。标准做法是先把所有 head 的输出拼接起来,再乘以 $\mathbf{W}^O$ 做线性融合,把多视角信息压回原维度。直接相加或取平均会丢失各子空间的结构差异。

Q4. 缩放点积注意力中除以 $\sqrt{d_k}$ 的主要目的是什么?

单选题 · mid

  • A.缓解 softmax 饱和致梯度消失← 正确答案
  • B.加速 GPU 并行训练速度
  • C.降低模型整体参数量
  • D.消除位置编码使用需求

答案:A。当维度 $d_k$ 很大时,点积数值会很大,softmax 进入饱和区,梯度趋近于零。除以 $\sqrt{d_k}$ 把分数拉回温和区间,保证训练稳定。它与并行速度、参数数量、位置编码无关。

Q5. 为什么 Self-Attention 能在长序列上替代 RNN?

多选题 · mid

  • A.支持全序列并行计算← 正确答案
  • B.全局依赖一步可达← 正确答案
  • C.完全不需要任何参数
  • D.天然支持变长序列输入← 正确答案

答案:ABD。Self-Attention 所有位置同时参与矩阵乘法,可以并行;任意两个位置的关联只隔一次点积,不像 RNN 沿时间步传送;它天然对变长序列友好。但 Self-Attention 需要投影矩阵和位置编码等参数,C 错误。

Q6. 关于多头注意力的计算流程,下列说法正确的是?

多选题 · mid

  • A.先生成 h 组 QKV 投影再并行计算← 正确答案
  • B.所有头共享同一套投影矩阵
  • C.拼接后乘输出矩阵线性融合← 正确答案
  • D.头数越多模型效果一定越好

答案:AC。每个头有自己的 $\mathbf{W}_i^Q, \mathbf{W}_i^K, \mathbf{W}_i^V$,是“不同镜片看同一零件”,所以 B 错;各头并行算完后拼接再乘 $\mathbf{W}^O$,C 对;头数过多收益递减,D 错。

Q7. 当 $d_{\text{model}}=512$、头数 $h=8$ 时,每个头的维度是多少?

单选题 · easy

  • A.每个头的维度是 64← 正确答案
  • B.每个头的维度是 128
  • C.每个头的维度是 8
  • D.每个头的维度是 512

答案:A。$d_k = d_{\text{model}} / h = 512 / 8 = 64$。多头把总维度均分给 8 个子空间,每个头在 64 维空间里做注意力。

Q8. 从 RNN 到 Transformer 的注意力演进主线是?

单选题 · easy

  • A.RNN 注意→多头→自注意力← 正确答案
  • B.CNN→LSTM→GRU 替换
  • C.直接跃迁至 GPT 系列
  • D.RNN→CNN→全连接层

答案:A。正确顺序是 RNN + attention 打破信息瓶颈,扩展到多头增强表达力,再用 Self-Attention 去循环化,最终构成 Transformer。LSTM→GRU 是 RNN 内部结构变化,不是注意力演进路线。

Q9. 关于多头注意力在 RNN 场景中的应用,下列说法正确的是?

多选题 · hard

  • A.可对编码器状态序列做多视角聚合← 正确答案
  • B.每个头的投影矩阵各不相同← 正确答案
  • C.能替代 RNN 的循环依赖实现序列并行
  • D.头数增加总能带来效果提升

答案:AB。RNN 编码器输出隐藏状态序列后,多头注意力可以从句法、语义等角度聚合它,A 对;每个头独立投影,B 对;多头并没有去除 RNN 的循环递推,不能实现序列并行,C 错;头数过多维度太窄效果会下降,D 错。

Q10. 传统 seq2seq 把整句压缩为末状态向量作为解码依据,最主要的问题是什么?

单选题 · mid

  • A.解码端信息瓶颈难以跨越← 正确答案
  • B.显存占用超出硬件上限
  • C.训练梯度必定完全消失
  • D.词序信息彻底无法保存

答案:A。定长向量装不下长句的全部语义,句子越长、丢失越多,这就是信息瓶颈。梯度消失是 RNN 的结构性问题而非压缩的直接后果,词序信息在早期位置仍有保存,不是“彻底无法保存”。