引言
这是李宏毅老师讲的机器学习视频中与自然语言处理有关的,本文主要关注Self-attention。
处理序列的模型
我们已经知道如何处理输入是一个向量的问题。假设我们遇到了更加复杂的问题。比如,输入是一系列向量。
image-20210719202951901并且输入的这一系列向量的长度不是固定的。
比如,在文字处理的场景中。输入是一个句子,将每个句子的词汇描述成一个向量,这样模型的输入就是一排向量。
image-20210719203227324如何把词汇表示成向量呢,我们知道有one-hot编码。
image-20210719203306995但是这种表示方法不能表示语义信息,并且维度还非常大。另一种表示方法是词嵌入向量。
image-20210719203402220还有图结构也可以是一系列向量。
image-20210719203607219那这些模型的输出是什么?
有三种类型:
每个输入的向量都有一个标签,比如词性标注任务。
image-20210719204104294第二种类型是整个序列的输出就是一标签。
比如情感分类任务、或者是输入一段语言,识别说话者是谁等。
image-20210719204430046最后一种类型就是,我们也不知道有多少个输出,由机器自己决定要输出多少。比如机器翻译任务。
我们今天关注第一种类型。这种任务又叫序列标注(Sequence Labeling)。
image-20210719204934142我们不能直接用全连接网络(FC)来做,因为全连接网络同样的输入会得到同样的输出。而我们上面的例子中“I saw a saw”,第一个“saw”是动词,第二个“saw”是名词。
如果能考虑到上下文就好了。这是有可能的,可以设定一个窗口大小,把窗口大小内的输入都串起来,一起丢到FC中。但是窗口大小始终是有限的,如何考虑整个句子呢,难道设定一个巨大的窗口包含整个语句?
有没有更好的考虑整个序列的模型呢?有,那便是Self-atention!
Self-attention
image-20210719205847998Self-attention可以接收一整个序列的输入,序列中有多少个输入,它就可以得到多少个输出。
比如上面输入4个向量到Self-attention中,我们就得到了4个输出向量。这4个输出向量特别之处在于,它们都是考虑了整个序列得到的结果。
在把这些特别的向量丢给FC之后,再来决定要输出什么样的东西。
image-20210719205959731Self-attention的输出还可以叠加。比如,我们得到考虑整个序列的向量后,喂给FC,得到FC的输出后,再过一次Self-attention,重新考虑FC的所有输出,再丢给另一个FC之后,得到最终的输出,如下图:
image-20210719210420886所以可以把FC和Self-attention交替使用,用Self-attention处理整个序列的信息,FC专注于处理某个位置的信息。
Self-attention的原理
那Self-attention是怎么运作的呢?
image-20210719210910693它的输入就是向量序列,这些向量可能是整个网络的输入,也可能是某个隐藏层的输出。
再强调一次,每个Self-attention的输出,都是考虑了所有的输入向量才生成出来的。
下面我们来看一下是如何生成这些向量的。
image-20210719211107497我们重点来看一下是如何产生这个向量的,其他的同理。
① 我们想要根据找出序列中其他与有关的向量。每个向量与关联程度用一个数值来表示。第一步要考虑的问题就是,Self-attention模型如何决定两个向量的关联性呢。
那么就需要一个计算关联性(注意力)的模组。
image-20210719211610744它拿两个向量作为输入,直接输出它们的相关性数值。如何计算这个数值,就有各种各样的做法。
常用的做法有使用点乘(Dot product)的方式。
image-20210719211751184点乘的方式做法如下:
- 把输入的向量分别乘上两个不同的权重矩阵,分别得到两个向量,记为和。
- 然后让就可以得到一个标量,这个标量就作为数值。
还有一种叫作Additive的方式:
image-20210719212058296也是乘上两个权重矩阵,得到之后,再拼接起来,然后输入到一个激活函数中,激活函数输出的结果通过矩阵进行线性变换得到。
我们下面的讨论基于点乘的方式。
② 计算和其他向量的关联性。
image-20210719213328027怎么做呢? 先用乘上矩阵得到,这个被称为为query。
image-20210719213522131然后乘上分别得到,这些被称为key。
image-20210719213737880接下来用与做点积得到值,表示和之间的关联性,这种记法说明query是提供的,key是提供的。这个值还被称为attention score。计算出与的关联性后,还要跟计算一下。
image-20210719214151441计算的时候也是乘以矩阵得到的,然后再与做点积得到。
image-20210719214503507实际上,我们还要利用同样的公式计算自己与自己的关联性。
③ 计算Softmax
image-20210719214621651我们还要对这些attention score做一个Softmax,得到,相当于与与各个向量的相关性系数,我们就可以知道哪些向量与相关性比较大。
④ 计算最终的
在计算之前呢,还有一个向量要计算。
image-20210719215329865这个向量就是向量,把到都乘上,得到到。这个可以看成是向量所携带的信息编码。
然后与Softmax之后的做一个加权求和就得到了:
image-20210719215531474假设与关联性较大,那么得到的权重系数就很大,在计算时,就会有很大程度的信息来自于,也就是来自于。
下面得到是一样的,虽然这里先探讨的产生,其实是可以同时产生的。
image-20210719230137343不过计算时,是以计算的作为query的。同理以得到就可以计算。
刚才我们说是可以同时计算的,是怎么回事呢。其实计算无非就是不同的向量与矩阵相乘得到的,如果把这些向量写在一起,写成一个矩阵,不就可以一次得到了吗。
image-20210719230633080把拼成一个矩阵,然后让矩阵乘以它得到矩阵,矩阵可以分解为。
剩下的也是同样的道理。
接下来,计算attention score也可以写成矩阵运算。
image-20210719231301572我们先看,它计算可以写成矩阵与向量的乘积。
image-20210719232058259同理不难理解也可以写成。
这样把拼成矩阵,然后通过得到,经过Softmax之后就得到了矩阵,矩阵中每列之和为,也被成为Attenion Matrix。
image-20210719232315344接下来看
image-20210719232902939相当于是把组成的矩阵乘以的第一列,就得到了。
image-20210719233109938那么用矩阵乘以就可以得到得到的矩阵。
image-20210719232818576总结下来,这一连串的操作,其实就是矩阵的乘法而已。我们用一个图来总结一下。
image-20210719233317789是Self-attention模型的输入组成的矩阵,是三个可以学习的权重矩阵;
用这三个矩阵乘分别得到矩阵;
然后用矩阵做个转置乘上就得到了,经过Softmax得到;
用乘上得到最终的输出。
其中需要学习的参数,就是。
Multi-head Self-attention
Multi-head Self-attention是Self-attention的一个升级版本,Multi-head指的是计算出多个矩阵。
为什么这样有意义呢? Self-attention是用query去找相关性,但是相关性可能有很多个种类,这时得到多个就分别代表不同种类。多出来的矩阵是怎么计算的呢。
image-20210719234040696 以2 head为例,我们还是用来得到,然而,此时用这个乘以一个不同的矩阵,得到;同理用乘上不同的矩阵分别得到和。
然后计算和的时候,把这些第二个上标为的进行计算,最后得到;上标为的进行计算,得到
image-20210719234420672接下来也可以拼接,然后乘以一个矩阵得到。
Positional Encoding
现在整个过程看下来,Self-attention少了一个重要的信息,即位置信息。
我们上面在进行矩阵运算的时候,对于不同的位置的输入,都是同等对待的。没有说像RNN那样后面的输入考虑了前面输入的信息。也没有考虑输入的距离远近。
本小节介绍的Positional Encoding就是用于解决这个问题的。具体就是为每个位置的输入设置一个独立的位置向量。
image-20210720075343640在Attention is all you need中用的是下图中的每一列:
image-20210720075558287即每一列代表一个位置向量,这些位置向量是通过sin和cos函数形成一个公式生成的。当然还有其他的生成方法,甚至可以当成一个可以学习的参数。
image-20210720080033193Self-attention的应用
比较出名的两个就是Transformer和BERT。
image-20210720080536933这两个家伙常年活跃在自然语言处理领域。
当然还可以应用在语音和图像上。
image-20210720080618122 image-20210720080726887对于图像来说,把每个位置的输入看成一个3维(rgb)的向量。
Self-attention vs CNN
image-20210720081024051CNN在做卷积的时候,考虑的是感受野之内的信息,而Selt-attention考虑的是整个输入的信息。
因此CNN可以看成是一个简化版的Self-attention。
这样好像是让Self-attention自己去决定感受野的形状是什么样的。
image-20210720081309703Self-attention只要设置合适的参数,就可以做到CNN能做到的事情。
image-20210720081516079Self-attention在数据量大时表现更好,而CNN在小数据量时表现更好。这样不难理解,显然Self-attention比CNN更复杂,需要的数据量显然更多。
Self-attention vs RNN
Self-attention和RNN都可以处理序列数据,RNN得到结果时必须按照时间步的顺序(正序或逆序)来生成,利用双向RNN的设计可以考虑整个序列信息。
image-20210720082041592而Self-attention每个输出都也是考虑了整个序列信息。虽然双向RNN也考虑了整个序列信息,但是如果将它俩进行对比,还是可以发现一些不同。
image-20210720082505122比如考虑上面红框框出来的(深蓝色)输入,RNN要考虑这个输入,必须保存到内存中,然后一步一步传递到最后,得到红框框出来的黄色输出。所以是很难考虑到比较远的输入。
而Self-attention就没有这个问题,只要它们的query和key比较相关,得到的相关性系数较大,不管多远,都能轻易地抽取出信息。
还有一个重要的不同就是并行化,这影响到训练效率。RNN是不能并行化的,而Self-attention可以。这样Self-attention完胜RNN。
想要了解更多Self-attention和RNN的关系,可以参考这篇论文☞Transformers are RNNs: Fast Autoregressive Transformers with Linear Attention
Self-attentioni for Graph
image-20210720083157317Self-attention还可以用在图结构上,图中每个节点看成一个输入,图结构中边的概念,可以看成有关联的向量。可以形成一个稀疏矩阵,其中白色空白区域代表无关联性。
比如上图节点1和5,6,8相连,所以我们只需要计算它们之间的attenion score。
Self-attention的变体
Self-attention有很多种变体,Self-attention最早用在Transformer上面,后来就出来了各种“xxformer”。
image-20210720083618866
网友评论