浅析注意力(Attention)机制(二)-- Self-Attention自注意力机制

前面我们介绍了注意力机制的基本概念和核心思想,不难看出,注意力机制与其说是一种模块,倒不如说是一种“加权求和”的思想,通过识别各个信息元素之间的相互关系并转化为注意力分数(这个过程甚至可以用一个DNN来实现,这也是缝模块的一种思路),在解码的每一个时间步增加注意力计算得到上下文向量,让模型可以根据当前状态,从输入序列中动态选择相关信息。本节我们将介绍注意力机制的一种特殊形式--自注意力机制(Self-Attention)

2.1 什么是Self-Attention

注意力分数的计算依赖三个关键参数:查询向量(Query)、键向量(Key)和值向量(Value)。Self-Attention相比注意力机制的特别之处就在于,一般注意力机制中,\(Q, K, V\)三个参数可以来自不同的序列,而在自注意力机制中,这三个参数均是基于同一个序列来进行计算的,故称之为“自”注意力机制。

特性 注意力机制 自注意力机制
输入来源 查询、键和值可以来自不同的数据来源 查询、键和值均来自同一序列
适用场景 一般适用于跨模态或异构数据(如图像到文本) 适用于序列内部的特征建模(如文本、时间序列)
复杂性 复杂性较低,依赖于输入维度和序列长度的差异 复杂性较高,随序列长度平方增长
典型应用 图像到文本的注意力、图像区域注意力等 Transformer、BERT等基于序列的模型

简而言之,Self-Attention相比一般注意力机制更注重挖掘序列自身的特征,尤其是远距离依赖特征,一句话来说,就是对于序列中每个位置的元素,自注意力机制都会看一边整个序列,然后根据相关性重新生成自己的表示。在之前的文章中我们介绍过LSTM的序列建模思路,即每个位置的隐藏状态\(h_t\)依赖于上一个时间步的隐藏状态\(h_{t-1}\),以及当前的输入\(x_t\),而在自注意力机制中,序列中每一个元素的表示,将由其它元素共同决定,简而言之,就是将“串行”的序列建模改为“并行”,这样可以极大提升模型处理长序列的能力,因此,在之后的相关内容中,就不会在出现由时间步递推而产生的“隐藏状态”这个词,而是回到了“层级间的输入和输出”这个范畴。

2.2 运算过程

2.2.1 向量编码输入

给定一个长度为n的序列信息,经过Embedding向量编码,得到输入:

\[\mathbf{X}=[\mathbf{x}_{(1)},\mathbf{x}_{(2)},\ldots,\mathbf{x}_{(n)}] \]

其中,\(\mathbf{x}_{(i)}\)表示第\(i\)个元素的向量编码,假定每个向量编码的长度为\(d\)

2.2.2 Q、K、V的计算

以单个元素的向量编码\(\mathbf{x}_{(i)}\)为例子,首先做三次线性变换,得到三种不同语义的表示:

  1. Query查询

\[\mathbf{Q}_{(i)} = \mathbf{W}_Q\mathbf{x}_{(i)} \]

  1. K键

\[\mathbf{K}_{(i)} = \mathbf{W}_K\mathbf{x}_{(i)} \]

  1. V值

\[\mathbf{V}_{(i)} = \mathbf{W}_V\mathbf{x}_{(i)} \]

这里的\(\mathbf{W}_Q, \mathbf{W}_K, \mathbf{W}_V\)都是可学习参数,他们的矩阵维度为:

\[\mathbf{W}_Q\in\mathbb{R}^{d\times d_k}, \mathbf{W}_K\in\mathbb{R}^{d\times d_k}, \mathbf{W}_V\in\mathbb{R}^{d\times d_v} \]

其中,\(\mathbf{W}_Q\)\(\mathbf{W}_K\)维度必须相同所以只使用一个参数,\(d_k\)\(d_v\)也是超参数,但我们一般要求两者相同。

2.2.3 计算注意力分数

对于某个位置\(\mathbf{x}_{(i)}\),都要计算它相对其它元素\(\mathbf{x}_{(j)}\)的注意力分数\(score_{ij}\)

\[score_{ij} = \frac{\mathbf{q}_{(i)}.\mathbf{k}_{(j)}}{\sqrt{d_k}} \]

注意:相关性的计算包括自己!

从这个公式也可以看出来,\(d_q\)\(d_k\)必须相等来满足点积运算要求,而使用\(sqrt{d_k}\)缩放则是让梯度更稳定,防止之后的 softmax 饱和。

2.2.4 加权求和

然后进行归一化,得到注意力权重,即:

\[\alpha_{ij} = \frac{\exp{(score_{ij})}}{\sum_{j=1}^{n}\exp{(score_{ij})}} \]

随后使用之前一直没用到的\(v\)和上一步计算得到注意力权重求加权和,即:

\[\mathbf{z}_{(i)}=\sum_{j=1}^n\alpha_{ij}\mathbf{v}_{(j)} \]

到此我们完成了一次自注意力机制的计算,计算出的加权向量\(\mathbf{z}_{(i)}\)还可以输入到下一个自注意力层中,循环上述过程即可,在transformer中表现多个Block的堆叠

posted @ 2026-05-05 23:38  KevinScott0582  阅读(60)  评论(0)    收藏  举报