前言
我们知道,“词嵌入”可以表示“语义”,但它本质上还是一个查找词,对于在不同句子中的同一个词,它的“词嵌入”向量是相同的,但在实际情况中,一个词的含义通常取决于上下文,同一个词在不同的句子中,可以有截然不同的含义。比如:“我爱吃苹果“和“我喜欢苹果手机”,这里面的“苹果”并不是同一个东西。我们需要一个方法,能够做到,同一个词,在不同的句子中,如果它们的含义不一样,那么它们的向量表示也不一样,而这就是“自注意力”。
理解自注意力
“自注意力”是 Google 团队在 2017 年发表的论文 ——《Attention Is All You Need》中提出的 Transformer 架构中提到的。它的作用是利用句子中相关词元的表示来调节某个词元的表示,从而生成上下文感知的词元表示。
从 Q/K/V 说起
想象在一个文档检索数据库中,如果要进行检索,通常需要知道:
Query:查询,要查询的东西;
Key:键,数据库中每一个文档对应的索引或标签;
Value:值,数据库中的文档内容;
在检索时,我们会将查询与键进行比对,计算出相关度得分后,将得分作用于文档排序,得到最终检索结果。
同样的,我们在理解一个句子是,我们是否先计算出每个词元与句子中其他所有词元的相关性分数,然后利用相关性分数对每个词元进行加权后求和,以得到每个词元的新表示呢?当然可以,这正是自注意力工作的基本原理。
工作原理
在自注意力中,Query、Key、Value 都来自同一个序列。其核心公式为:
$$\text{Attention}(Q, K, V) = \text{softmax}!\left(\frac{QK^\top}{\sqrt{d_k}}\right) V$$
Q/K/V 从哪来
在自注意力公式中,我们能否使用直接使用词嵌入 X 作为 Q/K/V 的输入呢?
答案是不行的,词嵌入是词元的固定表示,而自注意力机制要做的是,将词嵌入向量映射到一个具有上下文感知的新表示。为此我们需要引入 3 个可学习权重矩阵:$W_Q$、$W_K$、$W_V$。
$$Q = X W_Q, \quad K = X W_K, \quad V = X W_V$$
使其能在训练过程中自动学会:
- $W_Q$:把输入变成「想查什么」
- $W_K$:把输入变成「能被查到的标签」
- $W_V$:把输入变成「被查到后提供的信息」
计算注意力分数
$$
S = QK^\top
$$
自注意力机制中,首先要计算查询矩阵和键矩阵的点积。点积可以作为度量两个向量相似度的一种方式,点积越大,说明两个向量在多维空间中的指向越一致(夹角越小),两个向量之间的相似度也就越高。
缩放
$$
S_{\text{scaled}} = \frac{S}{\sqrt{d_k}}
$$
将S除以键向量维度的平方根,这样做的目的主要是抵消高维度带来的点积值过大而引入的缩放因子,以避免 softmax 函数的梯度消失或过大,从而获得稳定的梯度。
计算注意力权重
$$A = \text{softmax}(S_{\text{scaled}})$$
将注意力分数转为注意力权重,注意力权重分布在0到1的范围内。
加权求和
$$\text{Output} = AV$$
将注意力权重作用于词元,得到词元的新表示。
多头注意力
“多头注意力”是对自注意力机制的微调。“多头”是指:自注意力层的输出空间被分解为一组独立的子空间,对这些子空间分别进行学习,也就是说,每个 Head 拥有独立且不同的权重矩阵:$W_Q$、$W_K$、$W_V$:
$$\text{MultiHead}(X) = \text{Concat}(\text{head}_1, \ldots, \text{head}_h) W_O$$
$$\text{head}i = \text{Attention}(X W{Q_i},, X W_{K_i},, X W_{V_i})$$
使模型能够从不同的特征子空间捕捉更丰富的语义信息,进一步增强了模型的表征能力。
小结
自注意力机制解决了词嵌入的固定问题,让词元的含义能根据上下文动态变化。
核心机制(Q / K / V):
- Q(想查什么)与 K(能被查到的标签)点积算相似度;
- 经缩放和 softmax 算成注意力权重;
- 乘上 V(被查到后提供的信息)加权求和,得到融合了上下文的新词向量。
多头注意力:相当于用多组不同的 Q/K/V 从多个角度同时观察同一个句子,理解更全面。