1. 先区分两个概念:多头和多层
Multi-Head Attention 和多层 Transformer Block 不是一回事。
一句话区分:
text
Multi-Head Attention:同一层里,多个 attention head 并行看上下文。
多层 Transformer Block:很多层 block 串行堆叠,一层处理完再传给下一层。
更短地记:
text
多头 = 横向多视角
多层 = 纵向深加工
图示如下:
flowchart TD X"输入 hidden states X0" --> B1"Transformer Block 1" B1 --> B2"Transformer Block 2" B2 --> B3"Transformer Block 3" B3 --> Y"最终 hidden states" subgraph S1"Block 1 内部:Multi-Head Attention" H1"Head 1" H2"Head 2" H3"Head 3" HC"合并多个 head" H1 --> HC H2 --> HC H3 --> HC end
Block 之间是串行的:
text
X1 = Block1(X0)
X2 = Block2(X1)
X3 = Block3(X2)
因为第 2 层必须等第 1 层输出之后才能计算。
但在一个 Block 内部,多个 head 可以并行计算:
text
Head 1 ┐
Head 2 ├─ 同时计算 → 合并 → 输出
Head 3 ┘
2. 为什么需要 Multi-Head Attention
Self-Attention 的核心问题是:
当前 token 应该关注上下文里的哪些 token?
如果只有一个 head,它只能产生一套注意力分布。
例如句子:
text
小明 把 苹果 放进 书包 因为 它 太小 了
模型处理"它"时,需要同时理解很多关系:
text
1. "它"指代谁?
2. "太小"描述的是哪个物体?
3. "苹果"和"书包"之间是什么动作关系?
4. 句子的主语是谁?
5. 哪些词是局部搭配?
如果只有一个 head,它可能给出一套注意力权重:
text
书包: 0.70
苹果: 0.15
小明: 0.05
其他: 0.10
这套权重主要解决了"它指代书包"这个问题。
但同一层里,模型还可能需要同时关注动作关系、语法关系、局部搭配等。一个 head 只有一套 softmax 权重,很难同时清晰表达多种关系。
Multi-Head Attention 的目的就是:
让同一个 token 在同一层里,从多个子空间、多个角度同时理解上下文。
可以把多个 head 想成多个小专家:
text
Head 1:关注指代关系
Head 2:关注动作关系
Head 3:关注局部搭配
Head 4:关注语法结构
Head 5:关注长距离依赖
同一个 token "它",不同 head 可能关注不同位置:
text
Head 1,看指代:
书包: 0.80, 苹果: 0.10
Head 2,看动作链:
放进: 0.50, 苹果: 0.20, 书包: 0.20
Head 3,看局部搭配:
太小: 0.70, 了: 0.20
Head 4,看主语结构:
小明: 0.40, 把: 0.30, 放进: 0.20
最后这些 head 的结果合并起来,"它"的表示就会带着更丰富的信息:
text
它 ≈ 指代书包
+ 和"太小"形成属性关系
+ 处在"苹果放进书包"的动作结构中
+ 受前面"小明把..."句法结构影响
3. 多层 Transformer Block 不能替代多头吗
不能完全替代。它们解决的问题不同。
如果只有单头但有很多层,模型当然也能逐步加工信息:
text
第 1 层:用一套注意力看上下文
第 2 层:再用一套注意力看上一层结果
第 3 层:继续加工
这像:
text
一个人反复读文章很多遍。
Multi-Head Attention 像:
text
一组人同时从语法、语义、指代、位置等角度读同一句话。
两者互补:
text
多头:同一层内提供多视角并行理解
多层:层与层之间逐步抽象、深化、整合
图示:
flowchart LR A"同一层内" --> B"多个 head 并行捕捉多种关系" C"多层之间" --> D"上一层输出作为下一层输入,逐步深化表示" B --> E"横向多视角" D --> F"纵向深加工" E --> G"共同提升模型表达能力" F --> G
所以,多头不是单纯为了加速,而是为了增强表达能力。
它让模型在同一层里拥有多套"关注谁"的方案,而不是把所有关系挤进一套注意力权重里。
4. 每一层都有相同的多头吗
通常,标准 LLM 中每一层 Transformer Block 都有 Multi-Head Attention。
例如一个模型配置可能是:
text
num_layers = 32
hidden_size = 4096
num_attention_heads = 32
head_dim = 128
这意味着:
text
一共有 32 层 Transformer Block
每层都有 32 个 attention heads
每个 head 的维度是 128
但是要注意:
每层结构通常相同,但参数不共享。
也就是说:
text
Block 1:
32 个 heads
使用 Wq1, Wk1, Wv1, Wo1
Block 2:
32 个 heads
使用 Wq2, Wk2, Wv2, Wo2
Block 3:
32 个 heads
使用 Wq3, Wk3, Wv3, Wo3
第 1 层的 Head 1 和第 20 层的 Head 1 不是同一个 head。它们只是编号相同,参数不同,输入也不同。
因为不同层处理的表示阶段不同:
text
第 1 层输入:更接近原始 token embedding
第 10 层输入:已经融合了一些上下文关系
第 30 层输入:更接近高级语义和预测任务
所以不同层需要不同的 Q/K/V 参数来处理不同阶段的信息。
可以粗略理解为:
text
低层 head:更偏局部位置、相邻 token、标点、短语搭配
中层 head:更偏语法关系、实体关系、指代关系
高层 head:更偏任务意图、长距离依赖、输出预测相关信息
这不是人工规定,而是训练后自然形成的倾向。
5. 一个大矩阵如何一次性算出所有 head 的 Q/K/V
这是多头注意力最容易卡住的地方。
先记住一句话:
大矩阵负责一次性算出所有 head 的 Q/K/V;reshape 负责把"混在一起的 head 维度"重新分组,让程序知道哪一段属于哪个 head。
假设:
text
seq_len = 3
hidden_size = 8
num_heads = 2
head_dim = 4
因为:
text
hidden_size = num_heads × head_dim = 2 × 4 = 8
输入 X 的形状是:
text
X shape = [seq_len, hidden_size] = [3, 8]
可以理解为 3 个 token,每个 token 是 8 维向量:
text
token1: [8 维]
token2: [8 维]
token3: [8 维]
如果不用大矩阵,你可以想象成分别计算两个 head:
text
Q_head1 = X Wq_head1 → [3, 4]
Q_head2 = X Wq_head2 → [3, 4]
但工程实现不会一个 head 一个 head 地算,而是把两个 head 的投影矩阵拼成一个大矩阵:
text
Wq shape = [8, 8]
一次性计算:
text
Q = X Wq
Q shape = [3, 8]
这个 [3, 8] 的最后一维其实可以理解为:
text
前 4 维:Head 1 的 Q
后 4 维:Head 2 的 Q
例如:
text
Q token1 = [h1_1, h1_2, h1_3, h1_4, h2_1, h2_2, h2_3, h2_4]
reshape 就是把它从:
text
[3, 8]
变成:
text
[2, 3, 4]
含义变成:
text
2 个 head
3 个 token
每个 token 在每个 head 里是 4 维
6. reshape 的意义是什么
reshape 不改变数值,只改变数据的组织方式。
reshape 前:
text
Q shape = [3, 8]
可以看成:
text
token1: [a1 a2 a3 a4 b1 b2 b3 b4]
token2: [a5 a6 a7 a8 b5 b6 b7 b8]
token3: [a9 a10 a11 a12 b9 b10 b11 b12]
reshape 后:
text
Q shape = [2, 3, 4]
变成:
text
Head 1:
token1: [a1 a2 a3 a4]
token2: [a5 a6 a7 a8]
token3: [a9 a10 a11 a12]
Head 2:
token1: [b1 b2 b3 b4]
token2: [b5 b6 b7 b8]
token3: [b9 b10 b11 b12]
所以 reshape 的意义是:
把原来连在一起的 hidden_size 维向量,拆成
num_heads × head_dim,让每个 head 拿到属于自己的那一段 Q/K/V。
K 和 V 也一样:
text
K = X Wk → [3, 8] → reshape 为 [2, 3, 4]
V = X Wv → [3, 8] → reshape 为 [2, 3, 4]
于是每个 head 都有自己的:
text
Head 1: Q1, K1, V1,shape 都是 [3, 4]
Head 2: Q2, K2, V2,shape 都是 [3, 4]
7. reshape 后每个 head 如何计算 attention
对 Head 1:
text
Q1 shape = [3, 4]
K1 shape = [3, 4]
V1 shape = [3, 4]
先计算注意力分数:
text
scores1 = Q1 K1^T
形状是:
text
[3, 4] × [4, 3] = [3, 3]
这个 [3, 3] 是一张注意力图:
text
每个 query token 对每个 key token 的关注分数。
例如:
text
key token1 key token2 key token3
query token1 0.8 0.1 0.1
query token2 0.2 0.6 0.2
query token3 0.3 0.2 0.5
然后缩放并做 softmax:
text
weights1 = softmax(scores1 / sqrt(head_dim))
再用权重加权 V:
text
out1 = weights1 V1
形状是:
text
[3, 3] × [3, 4] = [3, 4]
Head 2 同理:
text
out2 shape = [3, 4]
最后把两个 head 的输出拼回去:
text
concat(out1, out2) → [3, 8]
再经过输出投影矩阵:
text
output = concat_heads Wo
最终输出形状仍然是:
text
[3, 8]
这样它就可以继续进入残差连接、MLP、下一层 Transformer Block。
完整流程如下:
flowchart TD X"X: \[seq_len, hidden_size = 3, 8"] --> Q"Q = X Wq: \[3, 8"] X --> K"K = X Wk: \[3, 8"] X --> V"V = X Wv: \[3, 8"] Q --> QR"reshape Q: \[num_heads, seq_len, head_dim = 2, 3, 4"] K --> KR"reshape K: \[2, 3, 4"] V --> VR"reshape V: \[2, 3, 4"] QR --> A1"Head 1 Attention" KR --> A1 VR --> A1 QR --> A2"Head 2 Attention" KR --> A2 VR --> A2 A1 --> C"concat heads: \[3, 8"] A2 --> C C --> WO"输出投影 Wo" WO --> O"Attention 输出: \[3, 8"]
8. 加上 batch 后的真实形状
真实模型中通常有 batch。
输入形状:
text
X shape = [batch, seq_len, hidden_size]
例如:
text
batch = 2
seq_len = 3
hidden_size = 8
num_heads = 2
head_dim = 4
那么:
text
X shape = [2, 3, 8]
一次性计算 Q:
text
Q = X Wq
Q shape = [2, 3, 8]
reshape:
text
Q shape = [2, 3, 2, 4]
通常还会 transpose 一下,把 head 维度提前:
text
Q shape = [2, 2, 3, 4]
含义是:
text
[batch, num_heads, seq_len, head_dim]
也就是:
text
2 个样本
2 个 head
3 个 token
每个 head 4 维
K 和 V 同理:
text
K shape = [2, 2, 3, 4]
V shape = [2, 2, 3, 4]
然后批量计算:
text
scores = Q @ K.transpose(-2, -1)
形状变化:
text
[2, 2, 3, 4] @ [2, 2, 4, 3]
= [2, 2, 3, 3]
含义是:
text
每个 batch、每个 head,都有一张 seq_len × seq_len 的注意力图。
再做:
text
weights = softmax(scores / sqrt(head_dim))
out = weights @ V
形状:
text
[2, 2, 3, 3] @ [2, 2, 3, 4]
= [2, 2, 3, 4]
最后转置并 reshape 回:
text
[2, 2, 3, 4]
→ [2, 3, 2, 4]
→ [2, 3, 8]
这就回到了:
text
[batch, seq_len, hidden_size]
9. 为什么这样能并行
reshape 后,head 维度变成了张量中的一个独立维度:
text
[batch, num_heads, seq_len, head_dim]
GPU 可以把:
text
batch 维度
head 维度
token 维度
一起打包成大规模矩阵运算。
它不是在 Python 里慢慢循环:
python
for head in heads:
attention(head)
而是一次性执行:
text
所有 batch 的所有 head 的 QK^T
所有 batch 的所有 head 的 softmax
所有 batch 的所有 head 的 weights @ V
这就是多头注意力中的"并行"。
图示:
flowchart LR A"Q/K/V: \[batch, num_heads, seq_len, head_dim"] --> B"批量矩阵乘法 QK\^T" B --> C"scores: \[batch, num_heads, seq_len, seq_len"] C --> D"softmax" D --> E"weights @ V" E --> F"head outputs: \[batch, num_heads, seq_len, head_dim"] F --> G"合并 heads: \[batch, seq_len, hidden_size"]
10. 为什么不是直接用一个更大的 head
一个常见疑问是:
如果总维度一样,为什么不用一个大 head,而要拆成多个小 head?
例如:
text
一个 head,维度 12
和:
text
三个 head,每个维度 4
总维度看起来一样。
关键区别在于:
一个大 head 通常只有一套注意力分布;多个 head 有多套独立的注意力分布。
一个 head:
text
只有一张 attention map
多个 head:
text
Head 1 一张 attention map
Head 2 一张 attention map
Head 3 一张 attention map
这意味着,多头不是简单拆维度,而是让模型同时拥有多套"关注谁"的方案。
对同一个 token "它":
text
Head 1:关注"书包",解决指代
Head 2:关注"太小",解决属性
Head 3:关注"放进",解决动作关系
Head 4:关注"小明",解决主语结构
如果只有一个大 head,这些关系要挤在一张注意力图里,表达会更受限。
11. 多头注意力完整流程总结
完整流程可以压缩成:
text
1. 输入 X: [batch, seq_len, hidden_size]
2. 用大矩阵一次性算 Q/K/V
3. Q/K/V reshape 成 [batch, num_heads, seq_len, head_dim]
4. 每个 head 独立计算 attention map
5. 每个 head 得到自己的输出
6. 把所有 head 的输出 concat 回 hidden_size
7. 经过输出投影 Wo
8. 得到 Multi-Head Attention 输出
图示:
flowchart TD X"X: \[B, S, H"] --> QKV"线性投影得到 Q/K/V: \[B, S, H"] QKV --> R"reshape + transpose: \[B, heads, S, head_dim"] R --> SCORE"QK\^T / sqrt(head_dim): \[B, heads, S, S"] SCORE --> MASK"可选 causal mask" MASK --> SOFT"softmax 得到注意力权重" SOFT --> VOUT"weights @ V: \[B, heads, S, head_dim"] VOUT --> MERGE"transpose + reshape 合并 heads: \[B, S, H"] MERGE --> WO"输出投影 Wo" WO --> OUT"Attention 输出: \[B, S, H"]
其中:
text
B = batch
S = seq_len
H = hidden_size
head_dim = H / num_heads
12. 面试回答模板
Q1:Multi-Head Attention 和多层 Transformer Block 是一回事吗?
不是。Multi-Head Attention 是同一层内部的多个 attention head 并行计算,用于从多个子空间捕捉不同关系;多层 Transformer Block 是多个 block 串行堆叠,后一层依赖前一层输出,用于逐层深化表示。
Q2:为什么需要多头注意力?
一个 attention head 只有一套注意力分布,很难同时表达指代、语法、局部搭配、实体关系等多种关系。多头注意力允许模型在同一层中并行学习多套注意力模式,再合并成更丰富的上下文表示。
Q3:多层 Transformer Block 能替代多头吗?
不能完全替代。多层提供纵向的逐步抽象,多头提供横向的多视角信息交互。单头多层像一个人反复读文章,多头像多人同时从不同角度读文章,两者是互补关系。
Q4:每一层都有相同的多头吗?
多数标准 LLM 中,每一层通常有相同数量的 attention heads,例如每层 32 个 head。但不同层的 Q/K/V/O 参数不共享,因此第 1 层的 Head 1 和第 20 层的 Head 1 不是同一个东西,它们会学习不同层次的关系。
Q5:reshape 的意义是什么?
大矩阵一次性算出的 Q/K/V 形状通常是 [batch, seq_len, hidden_size]。reshape 把最后的 hidden_size 维拆成 num_heads × head_dim,变成 [batch, num_heads, seq_len, head_dim],让每个 head 拿到自己对应的 Q/K/V 子空间并独立计算 attention。
Q6:为什么这种实现可以并行?
reshape 后,head 维度成为张量的批处理维度之一。GPU 可以同时计算所有 batch、所有 head 的矩阵乘法、softmax 和加权求和,而不是一个 head 一个 head 地循环执行。
13. 最短记忆版
text
Multi-Head Attention:
同一层里多个 head 并行计算多套注意力。
多层 Transformer Block:
多个 block 串行堆叠,逐层深化表示。
为什么需要多头:
一个 head 只有一套注意力分布,多头可以同时关注指代、语法、动作、局部搭配等关系。
每层是否相同:
通常每层 head 数量相同,但参数不共享,学到的功能也不同。
大矩阵算 QKV:
一次性算出所有 head 的 Q/K/V,提高计算效率。
reshape:
把 hidden_size 拆成 num_heads × head_dim,让每个 head 拿到自己的子空间。
并行:
GPU 同时计算所有 batch、所有 head 的 attention。
一句话总结:
Multi-Head Attention 是 Transformer 在同一层里进行多视角上下文理解的机制。它通过大矩阵一次性生成所有 head 的 Q/K/V,再 reshape 成多个 head 独立计算多套注意力图,最后合并输出;多层 Transformer Block 则是在纵向上逐层深化这些表示,二者共同构成 LLM 的强大表达能力。