注意力机制的引入

Attention 是注意力的意思,从它的命名方式看,很明显借鉴了人类的注意力机制,因此,首先介绍人类的视觉注意力。

首先先看一个非常经典的图片,基本上每个讲解注意力机制的文章视频都会用到这个图片:

img

这个图片是一个热力图,颜色越靠近红色说明被关注到的越多,也就是人在看到这个图片的时候会更多的关注图片中的人物,尤其是人物的脸;会看图片中的标题;会看文章的的开头等。根据人的经验认知来说这些地方往往会存在更多地信息,更有价值

视觉注意力机制是人类视觉所特有的大脑信号处理机制。人类视觉通过快速扫描全局图像,获得需要重点关注的目标区域,也就是一般所说的注意力焦点,而后对这一区域投入更多注意力资源,以获取更多所需要关注目标的细节信息,而抑制其他无用信息。人类视觉注意力机制极大地提高了视觉信息处理的效率与准确性。

深度学习中引入的注意力机制就是模仿人类的这一特点,核心目标就是从众多的信息中提取出对当前任务更有用的信息,而忽略掉一些不重要的信息

Attention模型的思想

Q,K,V的引入

首先先建立一个概念,Attention中常用的三个“变量”:Query,Key,Values。一张原始图片,默认的信息就是原始图片的Values。而Keys是与Values有着对应关系的,例如上图可能存在的对应关系为:婴儿(Key)-10(Value);标题(Key)-8(Value);文章开头(Key)-9(Value)。而Query就是查询,就是我感兴趣的东西,也就是对应的任务目标。

注意:一般都是会有原始信息的。即初始的Value不会是0。

那Attention的本质工作就是,基于已有的Keys-Values,我去查询一个新的Key对应的Value;或者从这些Key中筛选出来满足要求的Key,并得到其Value。简单来说其实就是Query->Values的过程,也就是计算Query 和 Values 中每个信息的相关程度

或许上面的描述还有一点抽象,再换一个更加具体的描述:

对于身高和体重假设有一个对应关系:

Key(身高/cm) Values(体重/KG)
160 55
165 60
170 65
175 70

现在我想要查询一个身高为172cm对应体重。那么Query就是172,Keys和Values就是上面的表格内容。

到这里应该能够理清楚Q,K,V了。

架构解释

img

上图就是Attention计算的一个模型图。

就还是用上面的身高体重的例子来解释(这个例子你能很容易看出来有函数关系,但是假设机器没看出来​😂​)。

如果要求计算172的身高,就要先判断,172和各个key谁更相似,得出来一个权重的关系,假设172和160的相似度为0.1,和165的相似度为0.15,和170的相似度为0.45,和175的相似度为0.3(相似度的值是我乱举例的)。那么在计算172身高对应体重时就可以根据这个相似度来计算对应的体重,当然是相似度越高,影响越大。也就是说172身高最终得出的体重更多是看170身高对应的体重。

但是总是会有一些时候会存在很大的偏差,例如Key的分布很离散,计算出来的权重的价值会很小,因此一般还需要对这个相似度进行处理,让其分布更加集中一点。

最后就是利用权重计算最终结果,例如计算出来权重为:160-0.1,165-0.15,170-0.45,175-0.3。那么最终172对应的体重就应该是:0.1*55+0.15*60+0.45*65+0.3*70=64.75。因此得到新的Key-Value:172-64.75。

上述例子只是简单解释,数值也是随意写的,接下来根据模型讲解公式。

计算公式

阶段一就是计算Query和Keys之间的相似度关系。

Query与Key1通过函数F(Q,K)计算出两者的相似度关系。

这里F()函数一般有以下几种选择:点乘(Transformer使用),权重,拼接权重,感知器。

在实际任务中都是利用矩阵进行计算,那么计算公式为:

  1. 点乘:$F(Q, K_i) = Q^T K_i$​(对于向量来说就是对应位置相乘相加最终结果为一个标量,对于两个矩阵相乘就是最基本的矩阵乘法)
  2. 权重:$F(Q, K_i) = Q^TWK_i$
  3. 拼接权重:$F(Q, K_i) = W[Q^T \; ; K_i]$
  4. 感知器:$F(Q, K_i) = V^T tanh(WQ+UK_i)$

阶段二就是对的到的相似度再进行一步处理,求出一个权重,利用softmax函数进行归一化。归一化之后的结果类似于概率分布,值在[0,1]之间,所有相似度结果之和刚好为1。

为什么用softmax函数进行归一化,而不用其他归一化方法?

我个人认为softmax函数的图像和sigmoid函数的图像很像,其实我认为softmax函数就是sigmoid函数在多项分布中的数据中使用的一种变体。

sigmoid一般适用于二分类问题(数据服从伯努利分布),softmax适用于多分类问题(数据服从多项分布)。

这两者函数都有相似的特点,就是值域在[0,1],可以很好地模拟概率。并且是非线性函数(如果是线性函数相当于是对原数据的平移,无实际作用,因此必须用非线性函数)。

但是softmax和sigmoid都有相同的缺点,就是当x的值很大或者很小是,会存在梯度消失的问题(梯度值接近为0),因此可能对于1000和10000求得的概率值基本是相同的。因此Attention在使用softmax计算中还会对相似度除以$\sqrt{d_k}$​。

计算公式为:$\alpha_i = softmax(\frac{F(Q, K_i)}{\sqrt{d_k}})$


阶段三就是根据归一化后的权重,对Values中的所有Value进行加权求和计算,最终得到向量Attention Value。

计算公式为:$Attention\; Value = \sum\limits_{i=1}^m \alpha_i V_i$

Self Attention

架构解释

Self Attention模型的架构如图所示:

img

  1. Q,K,V的获取

    这里的Q,K,V不再做介绍了。和前面提到的定义是相同的,不过这里变成了矩阵的形式(上面是向量)。并且Q,K,V又一个要求,就是规模相同,必须要求来源是相同的(后面详细讲解)。

    为什么变成了矩阵?

    前面提到的其实只是 “身高-体重”的对应关系,那么如果是“身高、胸围、腰围、臀围、肩宽-体重”,这种情况就是每一个Key都是一个向量,多个Key组成的Keys就成了矩阵,Values同理。对应的Query在查询时的输入也成了向量,如果有多个查询,那么查询也成了矩阵。

  2. MatMul就是一个多维的矩阵乘法,第一步中使用MatMul表示Self Attention中使用的计算相似度的方法就是“点乘”。

    这一步就是前面提到的阶段一。

  3. Scale顾名思义就是提前做一步处理,降低数据的范围。(目的是避免softmax出现极端情况)

  4. Softmax就是前面提到的归一化处理,计算出最终的权重。

    3和4这两步合起来就是前面提到的阶段二。

  5. 第二个MatMul就是想要将得到的权重矩阵与原始的V进行矩阵乘法,最终输出的结果就是Attention Value

    这一步就是前面提到的阶段三。

实际上,在Scale之后还可以进行一步Mask操作,Mask是机器翻译等自然语言处理任务中经常使用的环节。在机器翻译等NLP场景中,每个样本句子的长短不同,对于句子结束之后的位置,无需参与相似度的计算,否则影响Softmax的计算结果。

Q,K,V的获取

img

上图就是Q,K,V的来源。

X就是自注意力机制的真实输入,为$x_1,x_2, \dots,x_m$个词向量组成的输入矩阵。

自注意力机制终究是要用到深度学习的网络模型中的,因此必须要可以通过训练改变权重,于是在Self-Attention中引入了$W^Q、W^K、W^V$​​分别表示Q,K,V的权重。(如果不知道怎么通过训练改变权重,就无法理解这样进行一步线性空间变换的重要性,就建议先去了解一下什么是反向传播

上图中:
$q_1 = x_1W^Q, q_2=x_2W^Q;k_1 = x_1W^K, k_2 = x_2W^K; v_1 = x_1W^V,v_2 = x_2W^V$

因此转换为矩阵,模型中的$Q = XW^Q,K = XW^K,V = XW^V$​,矩阵的计算过程如下图所示:

截屏2024-03-26 17.02.23

第一个MatMul

img

上图就是一个计算示例,计算结果为举例数据,主要了解计算过程。

Score其实就是最上面的Attention架构中的$s_1, s_2, \cdots, s_m$。即经过F()计算后的结果。$s_i = F(Q, K_i)$

Self-Attention选择是点乘的方式(转换为矩阵就是矩阵乘法),因此:$s{11} = q_1*k_1 = 112, s{12} = q_1*k_2 = 96$

转换为矩阵操作就是:$S = QK^T = XW^Q (XW_K)^T$

Scale+softmax

img

这里是对计算结果的每一个对应位置都要除以一个词向量维度的根号(理由前面讲过,不再赘述)。

计算结果为:$112/8 = 14, 96/8 = 12$;

然后在到softmax函数中进行计算:
softmax函数公式为: $softmax(xi) = \dfrac{e^{x_i}}{\sum\limits{c=1}^m e^{x_c}}$

$\alpha_1 = \frac{e^{14}}{e^{14}+e^{12}} \approx 0.880797 \approx 0.88;\alpha_2 = \frac{e^{12}}{e^{14}+e^{12}} \approx 0.119202 \approx 0.12$

转换为矩阵计算就是:$A = softmax(\frac{S}{\sqrt{d_k}})$

第二个MatMul

img

这一步就是利用softmax计算好的值与v相乘再相加。

具体计算过程:

$z_1 = \alpha_1 v_1 + \alpha_1 v_2;z_2 = \alpha_2 v_1 + \alpha_2 v_2$。

这里求得的$z_1$就是单词”Thinking”的新的向量表示,$z_2$是单词”Machines”的新的向量表示。原始信息其实是”Thinking Machines”这个短语,$x_1$只是”Thinking”的词向量表示,$z_1$依然是”Thinking”的词向量表示,但同时也包含了”Thinking Machines”这个短语对”Thinking”而言那个更重要的信息。这里是注意力机制的意义,注意理解

矩阵形式:$Z = AV$

后面两步的矩阵表示:

img

Self Attention的直观作用

注意看上面的公式,$QK^T$其实就会组成一个 word2word 的 attention map!(加了 softmax 之后就是一个合为 1 的权重了)。比如说你的输入是一句话 “i have a dream” 总共 4 个单词,这里就会形成一张 4x4 的注意力机制的图:

image-20240326185224174

这样,每一个单词对应本句的每一个单词都会有一个权重,这也是 Self Attention 名字的来源,即 Attention 的计算来源于 Source(源句) 和 Source(源句) 本身,通俗点讲就是 Q、K、V 都来源于输入 X 本身。但是,原始的Q、K、V都只是自己这个单词的词矩阵表示,但经过Self-Attention计算之后得到的新的词矩阵也包含自己单词的意思,但同时也包含整个句子中对于该单词哪个更重要的信息。

还是有点抽象,再具体一点没看下面两个图,表示的是单词直接的实际联系:

截屏2024-03-26 19.13.04 截屏2024-03-26 19.14.37

看第二张图,如果不做Self Attention,那么its的词向量就还是单纯的its,没有任何附加信息。

但是经过注意力机制计算之后,its的词向量中就会包含有一定的Law和application的信息,表示its和Law或者application可能有某种关系,总之,Law和application对its的重要性相比于其他单词跟高。

Attention和Self Attention的关系

一针见血的说,满足上面Attention的计算公式的,有QKV的就是Attention,就是注意力机制,这里不用规定QKV的来源。而规定了QKV的来源是同一个输入源,才是Self Attention。

就是Attention包含了Self Attention。

除了Self Attention还有Cross Attention(交叉注意力机制)。交叉注意力机制是Q和V不同源,但是K和V同源。实际上身高体重的那个例子用来解释交叉注意力机制是最好的,因为一对身高-体重就是用一个人的特征得来的(K和V同源),然后通过另一个人的身高去查询体重(Q和V不同源)。

Self Attention和RNN、LSTM的区别

从上述两张图可以看出,Self Attention可以捕获同一个句子中单词之间的一些句法特征(例如第一张图展示的有一定距离的短语结构)或者语义特征(例如第二张图展示的 its 的指代对象为 Law 或 application)。

有了上述的讲解,可以来看看 Self Attention 和 RNN、LSTM 的区别:

  • RNN、LSTM:需要依次序列计算,对于远距离的相互依赖的特征,要经过若干时间步步骤的信息累积才能将两者联系起来,而距离越远,有效捕获的可能性越小
  • Self Attention:
    • 通过上述两幅图,很明显的可以看出,引入 Self Attention 后会更容易捕获句子中长距离的相互依赖的特征,因为 Self Attention 在计算过程中会直接将句子中任意两个单词的联系通过一个计算步骤直接联系起来,所以远距离依赖特征之间的距离被极大缩短,有利于有效地利用这些特征
    • 除此之外,Self Attention 对于一句话中的每个单词都可以单独的进行 Attention 值的计算,也就是说 Self Attention 对计算的并行性也有直接帮助作用,而对于必须得依次序列计算的 RNN 而言,是无法做到并行计算的。

从上面的计算步骤和图片可以看出,无论句子序列多长,都可以充分捕获近距离上往下问中的任何依赖关系,进而可以很好的提取句法特征还可以提取语义特征;而且对于一个句子而言,每个单词的计算是可以并行处理的

理论上 Self Attention (Transformer 50 个左右的单词效果最好)解决了 RNN 模型的长序列依赖问题,但是由于文本长度增加时,训练时间也将会呈指数增长,因此在处理长文本任务时可能不一定比 LSTM(200 个左右的单词效果最好) 等传统的 RNN 模型的效果好。

不管怎么说,当性能的缺点逐渐被弥补后,Self Attention很大可能会替代RNN、LSTM而被广泛使用。