注意力机制
注意力机制的引入
在生物学中,注意力受到非自主性提示恶化自主性提示有选择地引导。
非自主性提示是基于环境中物体的突出性和易见性。比如,对于五个物品:一份报纸、一篇研究论文、一杯咖啡、一本笔记和一本书,所有纸制品都是黑白印刷的,但咖啡杯是红色的。这个咖啡杯在这种视觉环境中是显眼和突出的,人本的注意力被不由自主地被吸引,所以我们会把视力最敏锐的地方放到咖啡上。
如果我们的主观意愿是读一本书,那么此时我们会自主地将视线注意力放到书本上,
在深度学习中,我们将非自主性提示称为Key
(键),自主性提示成为Query
(查询),而所有的信息内容称为Value
(值)
以机器翻译为例,比如英译中,Key
是源语言(英语)中每个词的“特征索引”,Query
是目标语言(中文)生成当前位置内容的需求,Value
是源语言中每个词的实际语义。
在深度学习中,”特征索引“、”需求“、”实际语义“并不是由人们显示提取的,而是通过模型自主学习到的:
比如,\(\mathbf{X}\)表示经过Embedding后的小批量文本数据,维度为[batch_size, seq_length, embed_size]
,
1 |
|
由此计算出来的K
的维度为[batch_size, seq_length, d_k]
,Q
的维度为[batch_size, seq_length, d_q]
,V
的维度为[batch_size, seq_length, d_v]
对于一个样本,对于第\(\tau\)个时间步的查询\(\mathbf{q}\in\mathbb{R}^{1\times
d_q}\),该样本的Key为\(\mathbf{k}\in\mathbb{R}^{m\times
d_k}\),Value为\(\mathbf{v}\in\mathbb{R}^{m\times
d_v}\),其中\(m\)表示seq_length
,也就是序列长度,对于第\(i\)个时间步的key和value:\(\mathbf{k}_i\in\mathbb{R}^{1\times
d_k}\),\(\mathbf{v}_i\in\mathbb{R}^{1\times
d_v}\),则注意力机制可以表示为函数: \[
f(\mathbf{q}) = \sum_{i=1}^m \alpha(\mathbf{q},
\mathbf{k}_i)\mathbf{v}_i
\] 其中,\(f(\mathbf{q})\in\mathbb{R}^{1\times
d_v}\)
\(\alpha(\mathbf{q}, \mathbf{k}_i)\)的公式为: \[ \alpha(\mathbf{q}, \mathbf{k}_i) = \mathrm{softmax}\Big(a(\mathbf{q}, \mathbf{k}_i)\Big) = \frac{\exp(a(\mathbf{q}, \mathbf{k}_i))}{\sum_{j=1}^m \exp(a(\mathbf{q}, \mathbf{k}_j))}\in\mathbb{R} \] \(a(\mathbf{q}, \mathbf{k}_i)\)是注意力评分函数,\(\alpha(\mathbf{q}, \mathbf{k}_i)\)则是注意力评分函数经过softmax运算变成概率得到的
注意力评分函数可以认为是当前位置的查询\(\mathbf{q}\),对不同时间步的信息进行打分,评价不同时间步信息的重要程度,而注意力机制就是根据注意力评分函数对所有的信息\(\mathbf{v}\)进行加权平均。
注意力评分函数
加性注意力
一般来说,当查询和键是不同长度的向量时,可以使用加性注意力作为评分函数。给定查询\(\mathbf{q}\in\mathbb{R}^{q}\)和键\(\mathbf{k_i}\in\mathbb{R}^{k}\),加性注意力(additive attention)的评分函数为 \[ a(\mathbf{q}, \mathbf{k}_i) = \mathbf{w}_v^\top\tanh(\mathbf{W}_q\mathbf{q} + \mathbf{W}_k\mathbf{k}_i)\in\mathbb{R} \] 其中可学习的参数是\(\mathbf{W}_q\in\mathbb{R}^{h\times q}\)、\(\mathbf{W}_k\in\mathbb{R}^{h\times k}\)和\(\mathbf{w}_v\in\mathbb{R}^h\)。即将查询和键连结起来后输入到一个多层感知机(MLP)中,感知机包含一个隐藏层,其隐藏单元数是一个超参数\(h\)。通过使用\(\tanh\)作为激活函数,并且禁用偏置项。
1 |
|
上面代码中的queries
是第\(\tau\)个时间步的小批量的查询,因此返回的注意力context
维度为[batch_size, value_size]
缩放点积注意力
使用点积可以得到计算效率更高的评分函数,但是点积操作要求查询和键具有相同的长度\(d\)。假设查询和键的所有元素都是独立的随机变量,并且都满足零均值和单位方差,那么两个向量的点积的均值为0,方差为\(d\)。为了确保无论向量长度如何,点积的方差在不考虑向量长度的情况下仍然是1,我们再将点积除以\(\sqrt{d}\),则缩放点积注意力评分函数为:
\[
a(\mathbf{q}, \mathbf{k}_i) = \mathbf{q}^\top\mathbf{k}_i/\sqrt{d}
\]
在实践中,我们通常从小批量的角度来考虑提高效率(此处的小批量是只查询的小批量,依旧只有一个文本序列),例如基于\(n\)个查询和\(m\)个键-值对计算注意力(\(m\)即时间步的数量),其中查询和键的长度为\(d\),值的长度为\(v\)。查询\(\mathbf{Q}\in\mathbb{R}^{n\times
d}\)、键\(\mathbf{K}\in\mathbb{R}^{m\times
d}\)和值\(\mathbf{V}\in\mathbb{R}^{m\times
v}\)的缩放点积注意力是: \[
\mathrm{softmax}\left(\frac{\mathbf{Q}\mathbf{K}^\top}{\sqrt{d}}\right)\mathbf{V}\in\mathbb{R}^{n\times
v}
\] 其中 \[
\frac{\mathbf{Q}\mathbf{K}^\top}{\sqrt{d}} = \left[
\begin{matrix}
a(\mathbf{q}_1, \mathbf{k}_1)&a(\mathbf{q}_1,
\mathbf{k}_2)&\cdots&a(\mathbf{q}_1, \mathbf{k}_m)\\
a(\mathbf{q}_2, \mathbf{k_1})&a(\mathbf{q}_2,
\mathbf{k}_2)&\cdots&a(\mathbf{q}_2, \mathbf{k}_m)\\
\vdots&\vdots& &\vdots\\
a(\mathbf{q}_n, \mathbf{k_1})&a(\mathbf{q}_n,
\mathbf{k}_2)&\cdots&a(\mathbf{q}_n, \mathbf{k}_m)
\end{matrix}
\right]
\] 因此,\(\mathrm{softmax}\)是对每行的数据进行处理,需要加入参数dim=-1
1 |
|
使用缩放点积注意力的优点:
- 高效:无额外参数,计算速度优于加性注意力。
- 可并行化:矩阵乘法适合 GPU 加速。
- 理论保障:缩放因子有效缓解梯度消失问题
与加性注意力机制对比:
特性 | 缩放点积注意力 | 加性注意力 |
---|---|---|
计算方式 | 直接点积 + 缩放 | 神经网络融合 Query 和 Key |
参数数量 | 无额外参数(仅需 \(\mathbf{Q}\),\(\mathbf{K}\),\(\mathbf{V}\) 的投影矩阵) | 需额外参数(\(\mathbf{W}_q\),\(\mathbf{W}_k\),\(\mathbf{w}_v\)) |
计算复杂度 | \(O(n⋅m⋅d_k)\) | \(O(n⋅m⋅h)\)(\(h\)为隐藏层大小) |
适用场景 | Query 和 Key 维度相同且较大时高效 | Query 和 Key 维度不同或需非线性交互时更灵活 |
常用模型 | Transformer、BERT、GPT | Seq2Seq(如早期机器翻译) |
上面代码中mask
的作用:
在注意力机制中,mask
的作用是控制模型对输入序列不同位置的访问权限,常用于屏蔽无效位置(如填充符<PAD>
)或防止未来信息泄露(如自回归生成)。
Mask的两种主要类型:
Padding Mask(填充掩码)
- 场景:处理变长序列时,短序列会被填充符(如
<PAD>
)补齐到相同长度 - 作用:防止模型关注填充符(无效位置)
- 实现:将填充符位置的注意力分数设为极小数(如
-1e9
),使Softmax后权重趋近于0
示例:
输入序列为
["I", "love", "nlp", "<pad>", "<pad>"]
,则对应的mask
为[1, 1, 1, 0, 0]
,表示前三个位置有效,后两个位置需要屏蔽。- 场景:处理变长序列时,短序列会被填充符(如
Sequence Mask(序列掩码):
- 场景:自回归任务(如机器翻译的解码器),防止当前位置关注到未来位置。
- 作用:确保生成第\(t\)个词时,仅依赖前\(t-1\)个词
- 实现:使用上三角矩阵(对角线及以上为0,下三角为1)屏蔽未来位置
mask
的维度应该为[batch_size, n, m]
,如果维度为[batch_size, 1, m]
,会自动广播到对应维度示例:
输入序列为
[["I", "love", "deep", "learning", "<pad>"]]
,则对于\(\mathbf{q}_1, \cdots, \mathbf{q}_5\):1
2
3
4
5
6
7[
[1, 0, 0, 0, 0],
[1, 1, 0, 0, 0],
[1, 1, 1, 0, 0],
[1, 1, 1, 1, 0],
[1, 1, 1, 1, 0]# 忽略填充<pad>
]