selfattention

 

1.self-attention

在之前处理序列问题的时候,用的是rnn,现在我们把rnn层换成self-attention层。

selfattention
图1 任何用rnn的都可以被替换成self-attention层标题

那么具体是怎么做的呢?我们首先以上图为例讲解。

a1,a2,a3,a4是一个sequence(序列),我们首先为每一个input a1,a2,a3,a4 乘以一个矩阵,通过embedding变成 x1,x2,x3,x4。然后我们把 x1,x2,x3,x4丢进self-attention layer. 

每一个input(x1,x2,x3,x4)分别乘三个不同的矩阵,产生三个不同的向量,我们把三个向量分别命名为q k v。

selfattention 

q代query,是要去match其他人的。k代表key,被query match。v是被抽取出来的信息。其中:

selfattention

现在,我们每一个a 都有不同的q k v。接下来,拿每一个不同的query q去对每一个不同的key k 做attention(attention的式子可以采用很多不同的方法,这里我们采取图片中的式子,先内积再除根号d。d是k和v的维度,因为k和v可以做内积,因此k和v的维度是一样的。至于为什么除以根号d,论文中有证明,这里不再细说。为什么要内积呢?因为我们做attention的目的就是衡量两个向量的相似度,而内积的几何意义就是:两个向量越相似,则两个向量的内积越大)。attention的过程是把q和k做匹配,看一下两个向量有多相似,衡量两个向量相似程度的是selfattentionselfattentionselfattention,该数越大,两个向量越相似。比如:狗和猫和梨分别做匹配,我们发现狗和猫更相似一些。

selfattention

 

接下来我们把得到的selfattention经过一个softmax层,得到selfattention,然后我们把selfattention跟每一个对应的selfattention相乘,然后累加,就得到一个向量,该向量就是输出序列的第一个向量。如下图所示:

selfattention
sotfmax变换
selfattention
α^与v相乘之后累加,得到输出向量b1

 注意:我们在产生b1的时候,用了整个sequence(a1,a2,a3,a4)的信息,意思就是当你产生b1之后,你就看到了a1到a4的信息。如果你整个序列很长(a1a2…a1000),你不想考虑整个句子的信息,你只想考虑局部的信息,只需要把不想考虑的部分所产生的α变成0即可。

截至到目前为止,我们算出来了b1,其实再同一时间,我们还可以计算b2b3b4,b1-b4计算是可以进行的。下图展示一下b2的计算过程:

selfattention
q2和每一个k做attention,得出的α,α经过softmax得到α^,α^与相乘然后累加得到b2

大体来说,输入序列a1 a2 a3 a4,得到输出序列b1 b2 b3 b4。 该过程和rnn是一样的,只是attention-layer可以使得b1 b 2 b3 b4同时运算。

接下来我们把刚刚一连串的过程用矩阵表示。

  1. 首先,我们知道selfattentionselfattentionselfattention
  2. selfattentionWq乘以a1得到q1
  3. selfattentionWq乘以a2得到q2
  4. selfattentionWq乘以a3,a4分别得到q3,q4
  5. selfattention把a1 a2 a3 a4拼起来变成一个矩阵,用I表示,我们用Wq*I 就可以得到Q,Q里面的第i列,就代表selfattention
  6. selfattention selfattention同理,我们可以得到:K = Wq*I 、V = Wq*I
  7. selfattention、 selfattention 、selfattention 、selfattention
  8.   为了简便计算,我们先忽视根号d
    selfattention
    K的转置乘以Q得到矩阵A,矩阵A经过softmax得到A^
  9.  
    selfattention
    输出矩阵O = V*A

             b1 = v1*a11+v2*a12+v3*a13+v4*a14,同理算出b2,b3,b4,b1—b4构成输出矩阵O

我们再把刚刚的过程简化以下:

selfattention 

2.muti-head-self-attention

selfattention

以head=2为例 ,在self-attention中,每一个ai都会得到一个qi,ki,vi。在有两个head的前提下,会把每个qkv分裂,变成两个。以q为例,做法可以是把qi乘上两个不同的矩阵,得到qi1和qi2。接下来做跟刚才一样的self-attention。只是qi1只会对跟他同样是第一个的k做attention(看图就能明白)。q和k相乘得attention之后,与各自的v相乘、累加。得到bi1,bi2。然后我们把bi1和bi2 concat起来,然后把他乘以一个矩阵进行降维得到bi。设置多个head的好处就是,不同的head关注的点是不同的,举个例子,有的head关注局部信息,而有的head关注全局信息,当你有muti-head的之后,每个head的关注的点不一样,他们各司其职。

3.positional encoding

如果我们仔细回顾一下刚才的两个过程就会发现,对于self-attenton来说,我们输入的序列的顺序是不重要的,因为对于input来说,只需要跟每个人都做self-attention,所以对于每个input的来说,无论其他input的距离是近还是远,对他来说,作用都是一样的。但是我们希望把input的顺序考虑到self-attention里面,原始的论文里采用positional encoding方法。

当原始输入xi经过embedding得到ai之后,需要再加上一个和ai的维度相等的ei,ei是人手设的,ei表示ai的位置。接下来就跟前面两个过程一样。