1 自注意力机制概述
有时候我们期望网络能够看到全局,但是又要聚焦到重点信息上。比如在在做自然语言处理时,句子中的一个词往往不是独立的,和它上下文相关,但是和上下文中不同的词的相关性是不同的,所以我们在处理这个词时,在看到它的上下文的同时也要更加聚焦与它相关性更高的词,这就要用到常说的自注意力机制。比如下面这两幅图,通过自注意力机制处理后,计算出了词间的相关性,可以看到第一个图的it与animal的相关性很强,第二个图it与street的相关性很强。那么如何实现自注意力机制呢?
2 向量相关性计算
自注意力机制的核心是捕捉向量之间的相关性。比如下面这幅图,输出一个向量不只看本身,还要看、、,但是看它们的程度不一样。这就需要分别计算与、、之间的相关性,越大,相关性越高,给予的重视程度就越高。那么如何让网络自动计算出两个向量之间的相关性呢?
计算两个向量之间的相关性的常见方法是求点积(dot-product),如下图所示。具体的做法是左边的向量乘以一个变换矩阵得到向量,右边的向量乘以一个变换矩阵得到向量,然后将向量和向量点积就可以得到相关性。由点积的性质可知,两个向量的相似度越高,点积的值就会越大。当然,计算向量相关性的方法不只点积这一种,也有其他方式,但是点积这种是最常见的。
基于点积计算,我们就可以向量两两之间的关联性了,比如首先分别计算与、、之间的相关性。我们首先将乘以变换矩阵得到向量,这里的向量有个专门的名字,叫做 “query” 。然后将、、、分别乘以变换矩阵得到向量,这里的向量也有个专门的名字,叫做 “key”。然后将和这四个key分别做点积,就得到四个相关性数值。求出这四个相关性的值后,然后通过一个Soft-max层进行归一化,得到,这是最后输出的相关性值,我们将这些值又称为“注意力分数”。现在我们得到了对、、、之间的注意力分数,那么如何做到考虑全局又聚焦重点呢?
3 基于注意力分数抽取向量信息
通过上面计算出的注意力分数,我们已经知道要给予、、、的关注程度了,接下来我们抽取这些向量中重要的信息以输出了。具体的做法如下图所示。首先我们再将、、、乘以一个新的变换矩阵得到向量,这里的向量也有个专门的名字,叫做 “value”。然后将向量分别乘以对应的注意力分数,并进行求和,输出向量。从这里可以看出,所有向量都有参与计算,这样就做到了看全局。但是各向量参与计算的程度不一样,就相当权重值,权重值越大的,对应向量参与计算的程度就越大,最后得到的输出向量就和该向量越相似。这样就做到了看全局又聚焦重点。通过上述同样的计算方式,也可以计算得到,而且是可以并行计算的。以上就是自注意力机制的全部了,但是对自注意力机制的解析并没有结束,下面从矩阵计算的角度来看自注意力机制。
4 自注意力机制中的矩阵计算
4.1 计算矩阵
前面提到将、、、分别乘以变换矩阵得到向量。我们将输入向量、、、拼在一起,得到一个矩阵用表示,即,将key向量、、、拼在一起得到一个矩阵用表示,即,用矩阵相乘表示矩阵的计算过程即,同理,query向量拼成的矩阵等于,value向量拼成的矩阵等于,。下图展示了上述计算过程。
4.2 计算注意力分数矩阵
前面提到将和四个key向量分别做点积,得到四个相关性数值。注意这里的向量都是列向量,所以点积可以写成,
用矩阵计算表示上述计算过程为 将与相乘可以得到相似的结果,即, 矩阵通过softmax层归一化后得到 。上述计算过程如下图所示。
4.3 计算输出矩阵
前面讲到将向量分别乘以对应的注意力分数,并进行求和,输出向量,这个过程用矩阵计算可表示为,
通过相似的计算,也可以得到,即,
4.4 自注意力矩阵计算总结
综上,自注意力机制的计算过程可总结为,
(1)计算矩阵
(2)计算注意力分数矩阵
(3)计算输出矩阵
可以看出,自注意力机制看起来比较复杂,其实计算过程并不复杂,需要学习的参数只有。
5 多头自注意力机制
自注意力机制还有一个进阶版,叫多头自注意力机制(multi-head self-attention)。为什么要多头呢?自注意力机制实质上是用过向量去找相关的向量,但是相关性可能有多种,一个只能找到一种相关的向量,因此就要引入多个向量和向量来捕捉多种相关性。多头自注意力机制很简单,设置多组矩阵,每一组只进行内部计算,得到相应的输出,如下图所示。
在得到不同的输出后,再将其拼到一起,形成一个大的矩阵。如果是2头,就将这2个输出直接拼到一起。然后通过一个转换矩阵将拼接的矩阵转换成原输出的长度的向量,即,
因此,多头注意力机制要多一个参数矩阵,即。