目录
- 一、从 Self-Attention 到 Multi-Head Attention:一个头为什么不够?
- 二、什么是 Multi-Head Attention?
- 三、每一个 Head 都有自己的 Q、K、V
- 四、为什么一定要“分头”?
- 五、为什么不直接做一个更大的 Attention?
- 六、Concat 到底在做什么?
- 七、为什么 Concat 之后还要乘一个
W
O
W^O
WO? - 八、从矩阵角度看整个 Multi-Head Attention
- 九、Multi-Head Attention 真正解决了什么?
- 十、一个更直观的例子
- 十一、Head 越多是不是越好?
- 十二、Multi-Head Attention 为什么不会让计算量暴涨?
- 十三、Multi-Head Attention 和 Self-Attention 是什么关系?
- 十四、为什么 Transformer 选择 Multi-Head,而不是只用一个 Head?
- 十五、从 Transformer 的角度重新理解它
- 十六、最后总结
在上一篇文章中,我们已经把 Self-Attention 从头到尾拆开了。我们知道,一个输入序列经过三个不同的线性变换之后,可以得到 Query、Key 和 Value:
Q
=
X
W
Q
Q = XW_Q
Q=XWQ
K
=
X
W
K
K = XW_K
K=XWK
V
=
X
W
V
V = XW_V
V=XWV
然后通过 Query 和 Key 的相似程度计算注意力分数,再经过 Softmax 得到注意力权重,最后对 Value 进行加权求和:
A
t
t
e
n
t
i
o
n
(
Q
,
K
,
V
)
=
s
o
f
t
m
a
x
(
Q
K
T
d
k
)
V
Attention(Q,K,V) =softmax \\left( \\frac{QK^{T}}{\\sqrt{d_{k}}} \\right)V
Attention(Q,K,V)=softmax(dk
QKT)V
到这里,我们已经知道 Self-Attention 能够让一个词去“关注”其他词。但是 Transformer 还有一个非常重要的设计:为什么不能只做一次 Attention,而是要同时做很多次 Attention? 这就是今天要解决的问题,也是 Transformer 中非常经典的结构:Multi-Head Attention,多头注意力。
一、从 Self-Attention 到 Multi-Head Attention:一个头为什么不够?
我们先假设有这样一句话:
小明喜欢吃苹果,因为它很甜。
当我们处理“它”这个词的时候,希望模型能够知道“它”到底指代什么。通过 Self-Attention,我们可以让“它”去关注“小明”“苹果”“甜”等其他词。假设最终得到的注意力权重是:
它
│
├── 小明 0.05
├── 喜欢 0.02
├── 吃 0.03
├── 苹果 0.70
├── 因为 0.05
└── 很甜 0.15
那么我们可以发现:“它”主要关注“苹果”。这当然很好。但问题也随之而来:一个词和其他词之间的关系,真的只有一种吗? 显然不是。
例如在一句话中,不同的词之间可能存在完全不同的关系:
小明喜欢吃苹果,因为它很甜。
这里至少存在几种关系:
“它” → “苹果”
表示指代关系
“苹果” → “甜”
表示语义关系
“小明” → “喜欢”
表示主谓关系
“吃” → “苹果”
表示动作与对象关系
如果我们只使用一次 Attention,那么这一次注意力计算得到的结果,需要同时承担很多不同类型的关系。这就有点像:让一个人同时负责语法分析、语义分析、指代消解、上下文理解。当然不是完全做不到,但是如果我们能够让不同的 Attention 专门关注不同类型的关系,模型就有可能学得更充分。于是 Transformer 提出了一个非常自然的想法:既然一个 Attention 不够,那就让多个 Attention 同时工作。 这就是 Multi-Head Attention。
下面用一张 Mermaid 图来概括“一个头不够”的核心矛盾:
#mermaid-svg-QcbH014D42IacDOy{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-QcbH014D42IacDOy .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-QcbH014D42IacDOy .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-QcbH014D42IacDOy .error-icon{fill:#552222;}#mermaid-svg-QcbH014D42IacDOy .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-QcbH014D42IacDOy .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-QcbH014D42IacDOy .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-QcbH014D42IacDOy .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-QcbH014D42IacDOy .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-QcbH014D42IacDOy .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-QcbH014D42IacDOy .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-QcbH014D42IacDOy .marker{fill:#333333;stroke:#333333;}#mermaid-svg-QcbH014D42IacDOy .marker.cross{stroke:#333333;}#mermaid-svg-QcbH014D42IacDOy svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-QcbH014D42IacDOy p{margin:0;}#mermaid-svg-QcbH014D42IacDOy .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-QcbH014D42IacDOy .cluster-label text{fill:#333;}#mermaid-svg-QcbH014D42IacDOy .cluster-label span{color:#333;}#mermaid-svg-QcbH014D42IacDOy .cluster-label span p{background-color:transparent;}#mermaid-svg-QcbH014D42IacDOy .label text,#mermaid-svg-QcbH014D42IacDOy span{fill:#333;color:#333;}#mermaid-svg-QcbH014D42IacDOy .node rect,#mermaid-svg-QcbH014D42IacDOy .node circle,#mermaid-svg-QcbH014D42IacDOy .node ellipse,#mermaid-svg-QcbH014D42IacDOy .node polygon,#mermaid-svg-QcbH014D42IacDOy .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-QcbH014D42IacDOy .rough-node .label text,#mermaid-svg-QcbH014D42IacDOy .node .label text,#mermaid-svg-QcbH014D42IacDOy .image-shape .label,#mermaid-svg-QcbH014D42IacDOy .icon-shape .label{text-anchor:middle;}#mermaid-svg-QcbH014D42IacDOy .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-QcbH014D42IacDOy .rough-node .label,#mermaid-svg-QcbH014D42IacDOy .node .label,#mermaid-svg-QcbH014D42IacDOy .image-shape .label,#mermaid-svg-QcbH014D42IacDOy .icon-shape .label{text-align:center;}#mermaid-svg-QcbH014D42IacDOy .node.clickable{cursor:pointer;}#mermaid-svg-QcbH014D42IacDOy .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-QcbH014D42IacDOy .arrowheadPath{fill:#333333;}#mermaid-svg-QcbH014D42IacDOy .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-QcbH014D42IacDOy .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-QcbH014D42IacDOy .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-QcbH014D42IacDOy .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-QcbH014D42IacDOy .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-QcbH014D42IacDOy .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-QcbH014D42IacDOy .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-QcbH014D42IacDOy .cluster text{fill:#333;}#mermaid-svg-QcbH014D42IacDOy .cluster span{color:#333;}#mermaid-svg-QcbH014D42IacDOy div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-QcbH014D42IacDOy .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-QcbH014D42IacDOy rect.text{fill:none;stroke-width:0;}#mermaid-svg-QcbH014D42IacDOy .icon-shape,#mermaid-svg-QcbH014D42IacDOy .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-QcbH014D42IacDOy .icon-shape p,#mermaid-svg-QcbH014D42IacDOy .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-QcbH014D42IacDOy .icon-shape .label rect,#mermaid-svg-QcbH014D42IacDOy .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-QcbH014D42IacDOy .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-QcbH014D42IacDOy .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-QcbH014D42IacDOy :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
输入句子:小明喜欢吃苹果,因为它很甜
处理词:它
一个 Attention 只能得到一种注意力分布
它 → 苹果(指代关系)
苹果 → 甜(语义关系)
小明 → 喜欢(主谓关系)
吃 → 苹果(动作与对象关系)
多种关系挤在同一个表示空间,难以充分表达
结论:需要多个 Attention 并行工作
二、什么是 Multi-Head Attention?
Multi-Head Attention 的核心思想其实非常简单:把原来的一个 Attention 拆成多个独立的 Attention,让每一个 Attention Head 在不同的表示空间中学习不同的关系。
假设我们有 8 个 Head,那么原本:
Input
│
▼
Self-Attention
│
▼
Output
会变成:
Input
│
┌──────────────┼──────────────┐
▼ ▼ ▼
Head 1 Head 2 Head 3 … Head 8
│ │ │
▼ ▼ ▼
Attention Attention Attention … Attention
│ │ │
└──────────────┼──────────────┘
▼
Concat
│
▼
Linear Projection
│
▼
Output
这里最重要的地方有两个:第一,每个 Head 都独立进行 Attention;第二,所有 Head 的结果最后会拼接起来,再经过一次线性变换。所以 Multi-Head Attention 并不是简单地“重复计算很多次”。真正的关键在于:每一个 Head 都拥有自己独立的 Q、K、V 投影参数,因此可以学习不同的表示方式。
下面用 Mermaid 图展示 Multi-Head Attention 的整体结构:
#mermaid-svg-hz6HXy3cxjivgstt{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-hz6HXy3cxjivgstt .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-hz6HXy3cxjivgstt .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-hz6HXy3cxjivgstt .error-icon{fill:#552222;}#mermaid-svg-hz6HXy3cxjivgstt .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-hz6HXy3cxjivgstt .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-hz6HXy3cxjivgstt .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-hz6HXy3cxjivgstt .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-hz6HXy3cxjivgstt .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-hz6HXy3cxjivgstt .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-hz6HXy3cxjivgstt .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-hz6HXy3cxjivgstt .marker{fill:#333333;stroke:#333333;}#mermaid-svg-hz6HXy3cxjivgstt .marker.cross{stroke:#333333;}#mermaid-svg-hz6HXy3cxjivgstt svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-hz6HXy3cxjivgstt p{margin:0;}#mermaid-svg-hz6HXy3cxjivgstt .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-hz6HXy3cxjivgstt .cluster-label text{fill:#333;}#mermaid-svg-hz6HXy3cxjivgstt .cluster-label span{color:#333;}#mermaid-svg-hz6HXy3cxjivgstt .cluster-label span p{background-color:transparent;}#mermaid-svg-hz6HXy3cxjivgstt .label text,#mermaid-svg-hz6HXy3cxjivgstt span{fill:#333;color:#333;}#mermaid-svg-hz6HXy3cxjivgstt .node rect,#mermaid-svg-hz6HXy3cxjivgstt .node circle,#mermaid-svg-hz6HXy3cxjivgstt .node ellipse,#mermaid-svg-hz6HXy3cxjivgstt .node polygon,#mermaid-svg-hz6HXy3cxjivgstt .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-hz6HXy3cxjivgstt .rough-node .label text,#mermaid-svg-hz6HXy3cxjivgstt .node .label text,#mermaid-svg-hz6HXy3cxjivgstt .image-shape .label,#mermaid-svg-hz6HXy3cxjivgstt .icon-shape .label{text-anchor:middle;}#mermaid-svg-hz6HXy3cxjivgstt .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-hz6HXy3cxjivgstt .rough-node .label,#mermaid-svg-hz6HXy3cxjivgstt .node .label,#mermaid-svg-hz6HXy3cxjivgstt .image-shape .label,#mermaid-svg-hz6HXy3cxjivgstt .icon-shape .label{text-align:center;}#mermaid-svg-hz6HXy3cxjivgstt .node.clickable{cursor:pointer;}#mermaid-svg-hz6HXy3cxjivgstt .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-hz6HXy3cxjivgstt .arrowheadPath{fill:#333333;}#mermaid-svg-hz6HXy3cxjivgstt .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-hz6HXy3cxjivgstt .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-hz6HXy3cxjivgstt .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-hz6HXy3cxjivgstt .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-hz6HXy3cxjivgstt .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-hz6HXy3cxjivgstt .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-hz6HXy3cxjivgstt .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-hz6HXy3cxjivgstt .cluster text{fill:#333;}#mermaid-svg-hz6HXy3cxjivgstt .cluster span{color:#333;}#mermaid-svg-hz6HXy3cxjivgstt div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-hz6HXy3cxjivgstt .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-hz6HXy3cxjivgstt rect.text{fill:none;stroke-width:0;}#mermaid-svg-hz6HXy3cxjivgstt .icon-shape,#mermaid-svg-hz6HXy3cxjivgstt .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-hz6HXy3cxjivgstt .icon-shape p,#mermaid-svg-hz6HXy3cxjivgstt .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-hz6HXy3cxjivgstt .icon-shape .label rect,#mermaid-svg-hz6HXy3cxjivgstt .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-hz6HXy3cxjivgstt .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-hz6HXy3cxjivgstt .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-hz6HXy3cxjivgstt :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
Input
Head 1
Head 2
Head 3
… Head 8
Attention 1
Attention 2
Attention 3
Attention 8
Concat
Linear Projection
Output
三、每一个 Head 都有自己的 Q、K、V
上一篇文章中,我们已经知道:
Q
=
X
W
Q
Q = XW_Q
Q=XWQ
K
=
X
W
K
K = XW_K
K=XWK
V
=
X
W
V
V = XW_V
V=XWV
现在有多个 Head,那么每一个 Head 都会拥有自己的一组参数。例如第
i
i
i 个 Head:
Q
i
=
X
W
i
Q
Q_i = XW_i^Q
Qi=XWiQ
K
i
=
X
W
i
K
K_i = XW_i^K
Ki=XWiK
V
i
=
X
W
i
V
V_i = XW_i^V
Vi=XWiV
然后每一个 Head 独立计算 Attention:
h
e
a
d
i
=
Attention
(
Q
i
,
K
i
,
V
i
)
head_i= \\operatorname{Attention}(Q_i,K_i,V_i)
headi=Attention(Qi,Ki,Vi)
也就是:
h
e
a
d
i
=
softmax
(
Q
i
K
i
T
d
k
)
V
i
head_i= \\operatorname{softmax} \\left( \\frac{Q_iK_i^T}{\\sqrt{d_k}} \\right)V_i
headi=softmax(dk
QiKiT)Vi
如果我们一共有
h
h
h 个 Head,那么就会得到:
h
e
a
d
1
,
h
e
a
d
2
,
⋯
,
h
e
a
d
h
head_1,head_2,\\cdots,head_h
head1,head2,⋯,headh
最后把它们拼接起来:
Concat
(
h
e
a
d
1
,
h
e
a
d
2
,
⋯
,
h
e
a
d
h
)
\\operatorname{Concat}(head_1,head_2,\\cdots,head_h)
Concat(head1,head2,⋯,headh)
再经过一个输出投影:
MultiHead
(
Q
,
K
,
V
)
=
Concat
(
h
e
a
d
1
,
…
,
h
e
a
d
h
)
W
O
\\operatorname{MultiHead}(Q,K,V)= \\operatorname{Concat}(head_1,\\ldots,head_h)W^O
MultiHead(Q,K,V)=Concat(head1,…,headh)WO
这就是 Transformer 中 Multi-Head Attention 最核心的公式。完整写出来就是:
MultiHead
(
Q
,
K
,
V
)
=
Concat
(
head
1
,
…
,
head
h
)
W
O
\\operatorname{MultiHead}(Q,K,V)= \\operatorname{Concat} \\left( \\operatorname{head}_1, \\ldots, \\operatorname{head}_h \\right) W^O
MultiHead(Q,K,V)=Concat(head1,…,headh)WO
其中:
head
i
=
Attention
(
Q
W
i
Q
,
K
W
i
K
,
V
W
i
V
)
\\operatorname{head}_i= \\operatorname{Attention} \\left( QW_i^Q, KW_i^K, VW_i^V \\right)
headi=Attention(QWiQ,KWiK,VWiV)
把上一篇文章的 Attention 公式代进去:
head
i
=
softmax
(
(
Q
W
i
Q
)
(
K
W
i
K
)
T
d
k
)
V
W
i
V
\\operatorname{head}_i= \\operatorname{softmax} \\left( \\frac{ (QW_i^Q)(KW_i^K)^T }{ \\sqrt{d_k} } \\right) VW_i^V
headi=softmax(dk
(QWiQ)(KWiK)T)VWiV
现在我们就可以看到:Multi-Head Attention 本质上就是多个不同参数的 Attention 并行工作,最后再把它们的信息融合起来。 这里需要稍微说明一下记号:在 Self-Attention 中,
Q
,
K
,
V
Q,K,V
Q,K,V 可以看作来自同一个输入
X
X
X;在多头结构中,每个头又会拥有自己的投影矩阵。因此从输入
X
X
X 出发,可以写成
Q
i
=
X
W
i
Q
Q_i=XW_i^Q
Qi=XWiQ、
K
i
=
X
W
i
K
K_i=XW_i^K
Ki=XWiK、
V
i
=
X
W
i
V
V_i=XW_i^V
Vi=XWiV;而从一般形式 $ \\operatorname{MultiHead}(Q,K,V)$ 出发,则写成
head
i
=
Attention
(
Q
W
i
Q
,
K
W
i
K
,
V
W
i
V
)
\\operatorname{head}_i=\\operatorname{Attention}(QW_i^Q,KW_i^K,VW_i^V)
headi=Attention(QWiQ,KWiK,VWiV)。两种写法描述的是同一件事,只是记号层次不同。
四、为什么一定要“分头”?
这里是 Multi-Head Attention 最值得理解的地方。我们假设模型的隐藏维度是:
d
m
o
d
e
l
=
512
d_{model}=512
dmodel=512
如果我们使用:
h
=
8
h=8
h=8
个 Head,那么每一个 Head 通常使用:
d
k
=
d
v
=
d
m
o
d
e
l
h
=
64
d_k=d_v=\\frac{d_{model}}{h}=64
dk=dv=hdmodel=64
也就是说:
原始表示
512维
│
├── Head 1 → 64维
├── Head 2 → 64维
├── Head 3 → 64维
├── Head 4 → 64维
├── Head 5 → 64维
├── Head 6 → 64维
├── Head 7 → 64维
└── Head 8 → 64维
每一个 Head 都不是直接在完整的 512 维空间中进行 Attention,而是先把信息投影到一个更小的空间中。这意味着:不同 Head 可以从不同的角度重新组织和理解输入信息。 可以把它理解成几个人一起研究同一篇文章:
一篇文章
│
┌──────────────┼──────────────┐
▼ ▼ ▼
Head 1 Head 2 Head 3
│ │ │
关注语法 关注语义 关注指代
│ │ │
└──────────────┼──────────────┘
▼
综合理解
当然,这只是帮助我们理解的直觉。实际训练过程中,我们并不会人为规定:Head 1 必须学习语法,Head 2 必须学习语义。而是通过训练,让不同 Head 自己学习到不同的模式。所以更准确的说法应该是:Multi-Head Attention 为模型提供了多个独立的表示子空间,使模型有机会同时学习不同类型、不同位置尺度的依赖关系。
下面用 Mermaid 图展示“分头”的维度分配:
#mermaid-svg-3pkYRGHow6E3cghp{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-3pkYRGHow6E3cghp .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-3pkYRGHow6E3cghp .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-3pkYRGHow6E3cghp .error-icon{fill:#552222;}#mermaid-svg-3pkYRGHow6E3cghp .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-3pkYRGHow6E3cghp .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-3pkYRGHow6E3cghp .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-3pkYRGHow6E3cghp .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-3pkYRGHow6E3cghp .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-3pkYRGHow6E3cghp .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-3pkYRGHow6E3cghp .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-3pkYRGHow6E3cghp .marker{fill:#333333;stroke:#333333;}#mermaid-svg-3pkYRGHow6E3cghp .marker.cross{stroke:#333333;}#mermaid-svg-3pkYRGHow6E3cghp svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-3pkYRGHow6E3cghp p{margin:0;}#mermaid-svg-3pkYRGHow6E3cghp .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-3pkYRGHow6E3cghp .cluster-label text{fill:#333;}#mermaid-svg-3pkYRGHow6E3cghp .cluster-label span{color:#333;}#mermaid-svg-3pkYRGHow6E3cghp .cluster-label span p{background-color:transparent;}#mermaid-svg-3pkYRGHow6E3cghp .label text,#mermaid-svg-3pkYRGHow6E3cghp span{fill:#333;color:#333;}#mermaid-svg-3pkYRGHow6E3cghp .node rect,#mermaid-svg-3pkYRGHow6E3cghp .node circle,#mermaid-svg-3pkYRGHow6E3cghp .node ellipse,#mermaid-svg-3pkYRGHow6E3cghp .node polygon,#mermaid-svg-3pkYRGHow6E3cghp .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-3pkYRGHow6E3cghp .rough-node .label text,#mermaid-svg-3pkYRGHow6E3cghp .node .label text,#mermaid-svg-3pkYRGHow6E3cghp .image-shape .label,#mermaid-svg-3pkYRGHow6E3cghp .icon-shape .label{text-anchor:middle;}#mermaid-svg-3pkYRGHow6E3cghp .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-3pkYRGHow6E3cghp .rough-node .label,#mermaid-svg-3pkYRGHow6E3cghp .node .label,#mermaid-svg-3pkYRGHow6E3cghp .image-shape .label,#mermaid-svg-3pkYRGHow6E3cghp .icon-shape .label{text-align:center;}#mermaid-svg-3pkYRGHow6E3cghp .node.clickable{cursor:pointer;}#mermaid-svg-3pkYRGHow6E3cghp .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-3pkYRGHow6E3cghp .arrowheadPath{fill:#333333;}#mermaid-svg-3pkYRGHow6E3cghp .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-3pkYRGHow6E3cghp .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-3pkYRGHow6E3cghp .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-3pkYRGHow6E3cghp .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-3pkYRGHow6E3cghp .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-3pkYRGHow6E3cghp .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-3pkYRGHow6E3cghp .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-3pkYRGHow6E3cghp .cluster text{fill:#333;}#mermaid-svg-3pkYRGHow6E3cghp .cluster span{color:#333;}#mermaid-svg-3pkYRGHow6E3cghp div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-3pkYRGHow6E3cghp .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-3pkYRGHow6E3cghp rect.text{fill:none;stroke-width:0;}#mermaid-svg-3pkYRGHow6E3cghp .icon-shape,#mermaid-svg-3pkYRGHow6E3cghp .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-3pkYRGHow6E3cghp .icon-shape p,#mermaid-svg-3pkYRGHow6E3cghp .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-3pkYRGHow6E3cghp .icon-shape .label rect,#mermaid-svg-3pkYRGHow6E3cghp .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-3pkYRGHow6E3cghp .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-3pkYRGHow6E3cghp .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-3pkYRGHow6E3cghp :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
原始表示 512 维
Head 1 → 64 维
Head 2 → 64 维
Head 3 → 64 维
…
Head 8 → 64 维
关注语法
关注语义
关注指代
关注其他模式
综合理解
五、为什么不直接做一个更大的 Attention?
看到这里可能会产生一个问题:既然我们希望模型学习更多关系,那为什么不直接把一个 Attention 做得更大?例如:
一个超大的 Attention
│
▼
同时学习所有关系
而不是:
Head 1
Head 2
Head 3
…
Head 8
原因就在于:不同 Head 使用的是不同的投影矩阵。 假设只有一个 Attention,那么它会使用:
Q
=
X
W
Q
Q = XW_Q
Q=XWQ
K
=
X
W
K
K = XW_K
K=XWK
V
=
X
W
V
V = XW_V
V=XWV
所有信息都在同一个表示空间里进行匹配。而 Multi-Head Attention 会学习多组不同的投影:
W
1
Q
,
W
1
K
,
W
1
V
W_1^Q,W_1^K,W_1^V
W1Q,W1K,W1V
W
2
Q
,
W
2
K
,
W
2
V
W_2^Q,W_2^K,W_2^V
W2Q,W2K,W2V
⋯
\\cdots
⋯
W
h
Q
,
W
h
K
,
W
h
V
W_h^Q,W_h^K,W_h^V
WhQ,WhK,WhV
因此不同 Head 可以把同一个输入
X
X
X 投影到不同的子空间。例如:
X
│
┌─────────┼─────────┐
▼ ▼ ▼
投影空间A 投影空间B 投影空间C
│ │ │
▼ ▼ ▼
关系A 关系B 关系C
所以真正重要的并不是“Attention 数量变多了”,而是:模型拥有了多个不同的表示空间,可以从多个角度计算 token 之间的关系。
六、Concat 到底在做什么?
每个 Head 完成 Attention 后,会得到一个输出。假设:
h
e
a
d
1
∈
R
n
×
d
v
head_1\\in\\mathbb{R}^{n\\times d_v}
head1∈Rn×dv
h
e
a
d
2
∈
R
n
×
d
v
head_2\\in\\mathbb{R}^{n\\times d_v}
head2∈Rn×dv
一直到:
h
e
a
d
h
∈
R
n
×
d
v
head_h\\in\\mathbb{R}^{n\\times d_v}
headh∈Rn×dv
那么我们把它们沿着最后一个维度拼接:
Concat
(
h
e
a
d
1
,
…
,
h
e
a
d
h
)
∈
R
n
×
h
d
v
\\operatorname{Concat}(head_1,\\ldots,head_h) \\in \\mathbb{R}^{n\\times hd_v}
Concat(head1,…,headh)∈Rn×hdv
如果:
d
v
=
64
d_v=64
dv=64
h
=
8
h=8
h=8
那么拼接之后:
h
d
v
=
8
×
64
=
512
hd_v=8\\times64=512
hdv=8×64=512
于是又重新回到了:
512
512
512
维。可以把这个过程理解成:
Head 1:64维 ─┐
Head 2:64维 ─┤
Head 3:64维 ─┤
Head 4:64维 ─┤
Head 5:64维 ─┤──→ Concat → 512维
Head 6:64维 ─┤
Head 7:64维 ─┤
Head 8:64维 ─┘
这样做的目的,就是把不同 Head 学到的信息放到一起。但是这时候还有一个问题:不同 Head 的信息只是简单拼在一起,它们之间还没有进行统一融合。 所以 Transformer 又加入了一个输出线性层。
七、为什么 Concat 之后还要乘一个
W
O
W^O
WO?
Concat 只是把不同 Head 的结果放在一起,它并没有真正学习:“Head 1 的信息和 Head 2 的信息应该如何组合?”所以需要再经过一个线性变换:
Output
=
Concat
(
h
e
a
d
1
,
…
,
h
e
a
d
h
)
W
O
\\operatorname{Output}= \\operatorname{Concat}(head_1,\\ldots,head_h)W^O
Output=Concat(head1,…,headh)WO
其中:
W
O
∈
R
h
d
v
×
d
m
o
d
e
l
W^O\\in\\mathbb{R}^{hd_v\\times d_{model}}
WO∈Rhdv×dmodel
如果:
h
d
v
=
d
m
o
d
e
l
=
512
hd_v=d_{model}=512
hdv=dmodel=512
那么:
W
O
∈
R
512
×
512
W^O\\in\\mathbb{R}^{512\\times512}
WO∈R512×512
这个线性层可以进一步学习不同 Head 之间的信息组合方式。所以整个过程可以理解成:
Input
│
┌────────┼────────┐
▼ ▼ ▼
Head 1 Head 2 Head 3 …
│ │ │
▼ ▼ ▼
64维 64维 64维
│ │ │
└────────┼────────┘
▼
Concat
│
512维
│
▼
W^O
│
▼
Output
这一步非常重要。因为 Multi-Head Attention 并不是:“多个 Head 各算各的,算完就结束。”而是:多个 Head 分别提取不同信息 → 拼接 → 再统一融合。
八、从矩阵角度看整个 Multi-Head Attention
我们现在把整个过程完整串起来。首先输入:
X
∈
R
n
×
d
m
o
d
e
l
X\\in\\mathbb{R}^{n\\times d_{model}}
X∈Rn×dmodel
对于第
i
i
i 个 Head:
Q
i
=
X
W
i
Q
Q_i=XW_i^Q
Qi=XWiQ
K
i
=
X
W
i
K
K_i=XW_i^K
Ki=XWiK
V
i
=
X
W
i
V
V_i=XW_i^V
Vi=XWiV
然后计算:
h
e
a
d
i
=
softmax
(
Q
i
K
i
T
d
k
)
V
i
head_i= \\operatorname{softmax} \\left( \\frac{Q_iK_i^T}{\\sqrt{d_k}} \\right)V_i
headi=softmax(dk
QiKiT)Vi
所有 Head 得到结果后:
H
=
Concat
(
h
e
a
d
1
,
…
,
h
e
a
d
h
)
H= \\operatorname{Concat}(head_1,\\ldots,head_h)
H=Concat(head1,…,headh)
最后:
Y
=
H
W
O
Y=HW^O
Y=HWO
所以整体流程就是:
X
│
├── XW₁Q → Q₁ ─┐
├── XW₁K → K₁ ─┤
├── XW₁V → V₁ ─┘
│ │
│ Attention
│ │
│ head₁
│
├── XW₂Q → Q₂
├── XW₂K → K₂
├── XW₂V → V₂
│ │
│ Attention
│ │
│ head₂
│
│ …
│
└── XWₕQ/K/V
│
Attention
│
headₕ
│
▼
Concat
│
▼
Wᴼ
│
▼
Y
这就是 Multi-Head Attention 的完整计算过程。
下面用 Mermaid 图展示从矩阵角度看整个 Multi-Head Attention 的完整流程:
#mermaid-svg-g7gqJYWY3awrVoKY{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-g7gqJYWY3awrVoKY .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-g7gqJYWY3awrVoKY .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-g7gqJYWY3awrVoKY .error-icon{fill:#552222;}#mermaid-svg-g7gqJYWY3awrVoKY .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-g7gqJYWY3awrVoKY .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-g7gqJYWY3awrVoKY .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-g7gqJYWY3awrVoKY .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-g7gqJYWY3awrVoKY .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-g7gqJYWY3awrVoKY .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-g7gqJYWY3awrVoKY .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-g7gqJYWY3awrVoKY .marker{fill:#333333;stroke:#333333;}#mermaid-svg-g7gqJYWY3awrVoKY .marker.cross{stroke:#333333;}#mermaid-svg-g7gqJYWY3awrVoKY svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-g7gqJYWY3awrVoKY p{margin:0;}#mermaid-svg-g7gqJYWY3awrVoKY .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-g7gqJYWY3awrVoKY .cluster-label text{fill:#333;}#mermaid-svg-g7gqJYWY3awrVoKY .cluster-label span{color:#333;}#mermaid-svg-g7gqJYWY3awrVoKY .cluster-label span p{background-color:transparent;}#mermaid-svg-g7gqJYWY3awrVoKY .label text,#mermaid-svg-g7gqJYWY3awrVoKY span{fill:#333;color:#333;}#mermaid-svg-g7gqJYWY3awrVoKY .node rect,#mermaid-svg-g7gqJYWY3awrVoKY .node circle,#mermaid-svg-g7gqJYWY3awrVoKY .node ellipse,#mermaid-svg-g7gqJYWY3awrVoKY .node polygon,#mermaid-svg-g7gqJYWY3awrVoKY .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-g7gqJYWY3awrVoKY .rough-node .label text,#mermaid-svg-g7gqJYWY3awrVoKY .node .label text,#mermaid-svg-g7gqJYWY3awrVoKY .image-shape .label,#mermaid-svg-g7gqJYWY3awrVoKY .icon-shape .label{text-anchor:middle;}#mermaid-svg-g7gqJYWY3awrVoKY .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-g7gqJYWY3awrVoKY .rough-node .label,#mermaid-svg-g7gqJYWY3awrVoKY .node .label,#mermaid-svg-g7gqJYWY3awrVoKY .image-shape .label,#mermaid-svg-g7gqJYWY3awrVoKY .icon-shape .label{text-align:center;}#mermaid-svg-g7gqJYWY3awrVoKY .node.clickable{cursor:pointer;}#mermaid-svg-g7gqJYWY3awrVoKY .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-g7gqJYWY3awrVoKY .arrowheadPath{fill:#333333;}#mermaid-svg-g7gqJYWY3awrVoKY .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-g7gqJYWY3awrVoKY .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-g7gqJYWY3awrVoKY .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-g7gqJYWY3awrVoKY .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-g7gqJYWY3awrVoKY .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-g7gqJYWY3awrVoKY .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-g7gqJYWY3awrVoKY .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-g7gqJYWY3awrVoKY .cluster text{fill:#333;}#mermaid-svg-g7gqJYWY3awrVoKY .cluster span{color:#333;}#mermaid-svg-g7gqJYWY3awrVoKY div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-g7gqJYWY3awrVoKY .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-g7gqJYWY3awrVoKY rect.text{fill:none;stroke-width:0;}#mermaid-svg-g7gqJYWY3awrVoKY .icon-shape,#mermaid-svg-g7gqJYWY3awrVoKY .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-g7gqJYWY3awrVoKY .icon-shape p,#mermaid-svg-g7gqJYWY3awrVoKY .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-g7gqJYWY3awrVoKY .icon-shape .label rect,#mermaid-svg-g7gqJYWY3awrVoKY .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-g7gqJYWY3awrVoKY .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-g7gqJYWY3awrVoKY .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-g7gqJYWY3awrVoKY :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
X
XW₁Q → Q₁
XW₁K → K₁
XW₁V → V₁
Attention
head₁
XW₂Q → Q₂
XW₂K → K₂
XW₂V → V₂
Attention
head₂
…
XWₕQ/K/V
Attention
headₕ
Concat
Wᴼ
Y
九、Multi-Head Attention 真正解决了什么?
现在我们可以回答最开始的问题:为什么需要多个注意力头? 因为一个 Attention 很难同时在一个表示空间里充分表达所有类型的关系。Multi-Head Attention 允许模型:
同一个输入
│
├── 从空间 A 看
├── 从空间 B 看
├── 从空间 C 看
├── 从空间 D 看
└── …
│
▼
综合信息
因此,一个 token 最终得到的表示,不再只是:“我应该关注谁?”而是:“从不同角度来看,我应该关注谁,以及这些信息分别意味着什么?”这也是 Transformer 强大表达能力的重要来源之一。
十、一个更直观的例子
我们再看一句:
The animal didn’t cross the street because it was too tired.
当模型处理:
it
的时候,需要理解:
it → animal
但是同时还存在其他关系:
animal → cross
cross → street
it → tired
假设不同 Head 学到了不同的关系,那么可能出现类似这样的情况:
Head 1
it ─────────→ animal
指代关系
Head 2
cross ──────→ street
动作对象关系
Head 3
it ─────────→ tired
语义关联
Head 4
animal ─────→ cross
主体与动作关系
最后把这些信息全部融合起来。那么“it”的最终表示就不再只包含一个简单的关系,而是同时包含多个维度的信息。再次强调:这不是我们人为指定每个 Head 学什么。 实际训练过程中,模型会通过损失函数和反向传播自动调整参数,让不同 Head 逐渐形成对任务有用的表示。所以我们看到某些 Head 在训练完成之后似乎更关注某种关系,但这属于模型训练出来的结果,而不是 Multi-Head Attention 的硬编码规则。
十一、Head 越多是不是越好?
看到这里可能又会产生一个问题:那是不是 Head 越多越好? 当然不是。假设:
d
m
o
d
e
l
=
512
d_{model}=512
dmodel=512
如果:
h
=
8
h=8
h=8
那么每个 Head 大约有:
d
k
=
64
d_k=64
dk=64
维。如果我们把 Head 数量提高到:
h
=
64
h=64
h=64
那么每个 Head 的维度就会变成:
d
k
=
8
d_k=8
dk=8
这样每一个 Head 能够使用的表示空间就非常小。所以 Head 数量和每个 Head 的维度之间存在一个平衡。通常会让:
d
k
=
d
v
=
d
m
o
d
e
l
h
d_k=d_v=\\frac{d_{model}}{h}
dk=dv=hdmodel
也就是说:Head 数量增加的同时,每个 Head 的维度会降低。 因此并不是简单地增加 Head 数量就一定能够提升模型能力。
十二、Multi-Head Attention 为什么不会让计算量暴涨?
如果真的把一个完整的 Attention 复制 8 次,看起来计算量应该直接变成 8 倍。但实际上,Transformer 的设计非常巧妙。假设:
d
m
o
d
e
l
=
512
d_{model}=512
dmodel=512
h
=
8
h=8
h=8
那么每个 Head 只使用:
d
k
=
64
d_k=64
dk=64
维。因此原本一个 512 维的大 Attention,被拆成了 8 个 64 维的小 Attention。粗略来看:
一个大 Attention
512维
↓
8个小 Attention
64维 × 8
总的表示维度仍然保持在相近的规模。更重要的是,现代硬件非常擅长执行这种矩阵运算,因此这些 Head 可以高度并行地计算。所以从实现角度来看,我们通常不会真的写:
for each head
{
计算 Attention
}
然后一个 Head 算完再算下一个。实际实现通常会把多个 Head 的计算组织成更大的张量操作,让 GPU 一次完成大量矩阵运算。这也是 Transformer 非常适合 GPU 并行计算的重要原因之一。
十三、Multi-Head Attention 和 Self-Attention 是什么关系?
这里一定要区分清楚。Self-Attention 和 Multi-Head Attention 不是两个完全平级、互相独立的东西。 更准确地说:Self-Attention 是 Attention 的一种使用方式,而 Multi-Head Attention 是把 Attention 并行做多组的一种结构。 例如:
Self-Attention
│
▼
Q、K、V 都来自同一个 X
而 Multi-Head Self-Attention 就是:
X
│
┌───────┼───────┐
▼ ▼ ▼
Head 1 Head 2 Head 3 …
│ │ │
▼ ▼ ▼
Self-Attention
│ │ │
└───────┼───────┘
▼
Concat
│
▼
Wᴼ
所以我们在 Transformer Encoder 中看到的:
Multi-Head Self-Attention
实际上就是:多个 Self-Attention 并行计算,再把结果融合。
十四、为什么 Transformer 选择 Multi-Head,而不是只用一个 Head?
现在可以把整个逻辑串起来了。上一篇文章中,我们解决了第一个问题:Self-Attention 如何让一个 token 动态关注其他 token? 答案是:
Attention
(
Q
,
K
,
V
)
=
softmax
(
Q
K
T
d
k
)
V
\\operatorname{Attention}(Q,K,V)= \\operatorname{softmax} \\left( \\frac{QK^T}{\\sqrt{d_k}} \\right)V
Attention(Q,K,V)=softmax(dk
QKT)V
但是我们又发现:一个 Attention 只能在一个表示空间中计算这种关系。而自然语言中的关系非常复杂。一个句子里可能同时存在:
语法关系
语义关系
指代关系
位置关系
长距离依赖
局部依赖
于是 Transformer 再进一步:让多个 Attention 在不同的表示子空间中同时学习。 于是就得到了:
MultiHead
(
Q
,
K
,
V
)
=
Concat
(
h
e
a
d
1
,
…
,
h
e
a
d
h
)
W
O
\\operatorname{MultiHead}(Q,K,V)= \\operatorname{Concat} \\left( head_1,\\ldots,head_h \\right)W^O
MultiHead(Q,K,V)=Concat(head1,…,headh)WO
其中:
h
e
a
d
i
=
Attention
(
Q
W
i
Q
,
K
W
i
K
,
V
W
i
V
)
head_i= \\operatorname{Attention} \\left( QW_i^Q, KW_i^K, VW_i^V \\right)
headi=Attention(QWiQ,KWiK,VWiV)
这就是 Multi-Head Attention。
十五、从 Transformer 的角度重新理解它
到这里,我们已经可以把 Transformer 的一个核心模块理解成下面这样:
输入 X
│
┌───────────┼───────────┐
│ │ │
▼ ▼ ▼
Head 1 Head 2 Head 3 …
│ │ │
▼ ▼ ▼
Attention Attention Attention
│ │ │
└───────────┼───────────┘
▼
Concat
│
▼
Wᴼ
│
▼
Multi-Head
Attention
而在真正的 Transformer Block 中,它还会继续经过:
Multi-Head Attention
│
▼
Residual Add
│
▼
Layer Normalization
│
▼
FFN
│
▼
Residual Add
│
▼
Layer Normalization
所以 Multi-Head Attention 只是 Transformer Block 中非常核心的一部分。后面我们还会继续看到:Attention 负责“从其他 token 那里拿信息”,那么拿完信息以后,Transformer 又是怎么进一步加工这些信息的?这就会涉及另一个非常重要的模块:Feed Forward Network,也就是 FFN。
十六、最后总结
这一篇我们重点解决了一个问题:为什么 Transformer 不只使用一个 Attention,而是要使用多个 Attention Head? 核心原因可以概括成一句话:因为语言中的关系非常复杂,不同的注意力头可以在不同的表示子空间中学习不同类型的依赖关系,然后再把这些信息融合起来。
整个 Multi-Head Attention 的过程可以浓缩成:
输入 X
│
├──→ Head 1 → Attention ──┐
├──→ Head 2 → Attention ──┤
├──→ Head 3 → Attention ──┤
│ … ├──→ Concat → Wᴼ → 输出
└──→ Head h → Attention ──┘
数学上:
h
e
a
d
i
=
Attention
(
Q
W
i
Q
,
K
W
i
K
,
V
W
i
V
)
head_i =\\operatorname{Attention} \\left( QW_i^Q, KW_i^K, VW_i^V \\right)
headi=Attention(QWiQ,KWiK,VWiV)
MultiHead
(
Q
,
K
,
V
)
=
Concat
(
h
e
a
d
1
,
…
,
h
e
a
d
h
)
W
O
\\operatorname{MultiHead}(Q,K,V)= \\operatorname{Concat} \\left( head_1,\\ldots,head_h \\right)W^O
MultiHead(Q,K,V)=Concat(head1,…,headh)WO
而最值得记住的并不是这些公式本身,而是背后的思想:一个 Attention 是一个观察角度,Multi-Head Attention 则是让模型同时拥有多个观察角度。
到这里,我们已经理解了 Transformer 中最核心的 Attention 机制。但是还有一个非常明显的问题:Self-Attention 本身并不知道“谁在前面、谁在后面”。 例如:
我 喜欢 你
和:
你 喜欢 我
如果只把三个词交给 Self-Attention,它们本身都可以互相计算 Attention。那么 Transformer 到底是怎么知道:
“我喜欢你”
和:
“你喜欢我”
不是同一个意思的?
别急,我们以后再说明。
最后,用一张 Mermaid 图把整个 Multi-Head Attention 浓缩起来:
#mermaid-svg-B6mGs19AO3xPXcrb{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-B6mGs19AO3xPXcrb .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-B6mGs19AO3xPXcrb .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-B6mGs19AO3xPXcrb .error-icon{fill:#552222;}#mermaid-svg-B6mGs19AO3xPXcrb .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-B6mGs19AO3xPXcrb .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-B6mGs19AO3xPXcrb .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-B6mGs19AO3xPXcrb .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-B6mGs19AO3xPXcrb .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-B6mGs19AO3xPXcrb .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-B6mGs19AO3xPXcrb .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-B6mGs19AO3xPXcrb .marker{fill:#333333;stroke:#333333;}#mermaid-svg-B6mGs19AO3xPXcrb .marker.cross{stroke:#333333;}#mermaid-svg-B6mGs19AO3xPXcrb svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-B6mGs19AO3xPXcrb p{margin:0;}#mermaid-svg-B6mGs19AO3xPXcrb .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-B6mGs19AO3xPXcrb .cluster-label text{fill:#333;}#mermaid-svg-B6mGs19AO3xPXcrb .cluster-label span{color:#333;}#mermaid-svg-B6mGs19AO3xPXcrb .cluster-label span p{background-color:transparent;}#mermaid-svg-B6mGs19AO3xPXcrb .label text,#mermaid-svg-B6mGs19AO3xPXcrb span{fill:#333;color:#333;}#mermaid-svg-B6mGs19AO3xPXcrb .node rect,#mermaid-svg-B6mGs19AO3xPXcrb .node circle,#mermaid-svg-B6mGs19AO3xPXcrb .node ellipse,#mermaid-svg-B6mGs19AO3xPXcrb .node polygon,#mermaid-svg-B6mGs19AO3xPXcrb .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-B6mGs19AO3xPXcrb .rough-node .label text,#mermaid-svg-B6mGs19AO3xPXcrb .node .label text,#mermaid-svg-B6mGs19AO3xPXcrb .image-shape .label,#mermaid-svg-B6mGs19AO3xPXcrb .icon-shape .label{text-anchor:middle;}#mermaid-svg-B6mGs19AO3xPXcrb .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-B6mGs19AO3xPXcrb .rough-node .label,#mermaid-svg-B6mGs19AO3xPXcrb .node .label,#mermaid-svg-B6mGs19AO3xPXcrb .image-shape .label,#mermaid-svg-B6mGs19AO3xPXcrb .icon-shape .label{text-align:center;}#mermaid-svg-B6mGs19AO3xPXcrb .node.clickable{cursor:pointer;}#mermaid-svg-B6mGs19AO3xPXcrb .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-B6mGs19AO3xPXcrb .arrowheadPath{fill:#333333;}#mermaid-svg-B6mGs19AO3xPXcrb .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-B6mGs19AO3xPXcrb .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-B6mGs19AO3xPXcrb .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-B6mGs19AO3xPXcrb .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-B6mGs19AO3xPXcrb .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-B6mGs19AO3xPXcrb .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-B6mGs19AO3xPXcrb .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-B6mGs19AO3xPXcrb .cluster text{fill:#333;}#mermaid-svg-B6mGs19AO3xPXcrb .cluster span{color:#333;}#mermaid-svg-B6mGs19AO3xPXcrb div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-B6mGs19AO3xPXcrb .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-B6mGs19AO3xPXcrb rect.text{fill:none;stroke-width:0;}#mermaid-svg-B6mGs19AO3xPXcrb .icon-shape,#mermaid-svg-B6mGs19AO3xPXcrb .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-B6mGs19AO3xPXcrb .icon-shape p,#mermaid-svg-B6mGs19AO3xPXcrb .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-B6mGs19AO3xPXcrb .icon-shape .label rect,#mermaid-svg-B6mGs19AO3xPXcrb .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-B6mGs19AO3xPXcrb .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-B6mGs19AO3xPXcrb .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-B6mGs19AO3xPXcrb :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
输入 X
Head 1 → Attention
Head 2 → Attention
Head 3 → Attention
…
Head h → Attention
Concat
Wᴼ
输出


