Self Attention和Multi-Head Attention的原理

Self Attention原理

    self attention有什么优点呢,这里引用谷歌论文《Attention Is All You Need》里面说的,第一是计算复杂度小,第二是可以大量的并行计算,第三是可以更好的学习远距离依赖。Attention的计算公式如下:

0.png

    下面一步步分解self attention的计算过程(图来自https://jalammar.github.io/illustrated-transformer/):

  1. 输入单词表示向量,比如可以是词向量
  2. 把输入向量映射到q、k、v三个变量,如下图:1.png比如上图X1和X2分别是Thinking和Machines这两个单词的词向量,q1和q2被称为查询向量,k称为键向量,v称为值向量。Wq,Wk,Wv都是随机初始化的映射矩阵。
  3. 计算Attention score,即某个单词的查询向量和各个单词对应的键向量的匹配度,匹配度可以通过加法或点积得到。图如下:2.png
  4. 减小score,并将score转换为权重。3.png其中dk是q k v的维度。score可以通过点积和加法得到,当dk较小时,这两种方法得到的结果很相似。但是点积的速度更快和省空间。但是当dk较大时,加法计算score优于点积结果没有除以dk^0.5的情况。原因可能是:the dot products grow large in magnitude, pushing the softmax function into regions where it has extremely small gradients。所以要先除以dk^0.5,再进行softmax。
  5. 权重乘以v,并求和。4.png最终的结果z就是x1这个单词的Attention向量。当同时计算所有单词的Attention时,图示如下:1. 将输入词向量转换为Q、K、V.5.png2. 直接计算Z6.png 

Self Attention代码实现

    使用Keras自定义self attention层,代码如下:

from keras import initializersfrom keras import activationsfrom keras import backend as Kfrom keras.engine.topology import Layer class MySelfAttention(Layer):        def __init__(self,output_dim,kernel_initializer='glorot_uniform',**kwargs):        self.output_dim=output_dim        self.kernel_initializer = initializers.get(kernel_initializer)        super(MySelfAttention,self).__init__(**kwargs)            def build(self,input_shape):        self.W=self.add_weight(name='W',             shape=(3,input_shape[2],self.output_dim),             initializer=self.kernel_initializer,             trainable=True)        self.built = True            def call(self,x):        q=K.dot(x,self.W[0])        k=K.dot(x,self.W[1])        v=K.dot(x,self.W[2])        #print('q_shape:'+str(q.shape))        e=K.batch_dot(q,K.permute_dimensions(k,[0,2,1]))#把k转置,并与q点乘        e=e/(self.output_dim**0.5)        e=K.softmax(e)        o=K.batch_dot(e,v)        return o            def compute_output_shape(self,input_shape):        return (input_shape[0],input_shape[1],self.output_dim)

Multi-Head Attention原理

    不同的随机初始化映射矩阵Wq,Wk,Wv可以将输入向量映射到不同的子空间,这可以让模型从不同角度理解输入的序列。因此同时几个Attention的组合效果可能会优于单个Attenion,这种同时计算多个Attention的方法被称为Multi-Head Attention,或者多头注意力。

    每个“Head”都会产生一个输出向量z,但是我们一般只需要一个,因此还需要一个矩阵把多个合并的注意力向量映射为单个向量。图示如下:

7.png

Multi-Head Attention代码实现

    还是使用Keras实现multi-head attention,代码如下:

from keras import initializersfrom keras import activationsfrom keras import backend as Kfrom keras.engine.topology import Layer  class MyMultiHeadAttention(Layer):    def __init__(self,output_dim,num_head,kernel_initializer='glorot_uniform',**kwargs):        self.output_dim=output_dim        self.num_head=num_head        self.kernel_initializer = initializers.get(kernel_initializer)        super(MyMultiHeadAttention,self).__init__(**kwargs)            def build(self,input_shape):        self.W=self.add_weight(name='W',           shape=(self.num_head,3,input_shape[2],self.output_dim),           initializer=self.kernel_initializer,           trainable=True)        self.Wo=self.add_weight(name='Wo',           shape=(self.num_head*self.output_dim,self.output_dim),           initializer=self.kernel_initializer,           trainable=True)        self.built = True            def call(self,x):        q=K.dot(x,self.W[0,0])        k=K.dot(x,self.W[0,1])        v=K.dot(x,self.W[0,2])        e=K.batch_dot(q,K.permute_dimensions(k,[0,2,1]))#把k转置,并与q点乘        e=e/(self.output_dim**0.5)        e=K.softmax(e)        outputs=K.batch_dot(e,v)        for i in range(1,self.W.shape[0]):            q=K.dot(x,self.W[i,0])            k=K.dot(x,self.W[i,1])            v=K.dot(x,self.W[i,2])            #print('q_shape:'+str(q.shape))            e=K.batch_dot(q,K.permute_dimensions(k,[0,2,1]))#把k转置,并与q点乘            e=e/(self.output_dim**0.5)            e=K.softmax(e)            #print('e_shape:'+str(e.shape))            o=K.batch_dot(e,v)            outputs=K.concatenate([outputs,o])        z=K.dot(outputs,self.Wo)        return z            def compute_output_shape(self,input_shape):        return (input_shape[0],input_shape[1],self.output_dim)

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注