Press "Enter" to skip to content

Attention Is All You Need 论文解读

图解实现一个self-attention

 

self attention 是很多bert框架,或者说是transformer框架的共同点,它的提出颠覆了之前在进行“语言理解”任务中深度神经网络基本都要使用RNN进行循环串行计算的弊端,取而代之的是获取全局视野,并行计算全局注意力。

 

(这部分参考参考https://towardsdatascience.com/illustrated-self-attention-2d627e33b20a一文)

以下为python实现:

 

最下层绿色的input为:

 

input = [
    [1., 0., 1., 0.],
    [0., 2., 0., 2.],
    [1., 1., 1., 1.]
]

 

q、k、v的w分别为:

 

w_key = [
    [0, 0, 1],
    [1, 1, 0],
    [0, 1, 0],
    [1, 1, 0]
]
w_query = [
    [1, 0, 1],
    [1, 0, 0],
    [0, 0, 1],
    [0, 1, 1]
]
w_value = [
    [0, 2, 0],
    [0, 3, 0],
    [1, 0, 3],
    [1, 1, 0]
]

 

将input和q、k、v的w相乘,得到图中从下往上数第二层的keys、querys和values

 

keys = np.dot(input, w_key) #[[0,1,1],[4,0,0],[2,3,1]]
querys = np.dot(input, w_query) #[[1,0,2],[2,2,2],[2,1,3]]
values = np.dot(input, w_value) #[[1,2,3],[2,8,0],[2,6,3]]

 

将querys和keys相乘,并进行softmax得到图中从下往上数第三层的 attention scores

 

attn_scores = np.dot(querys, keys.T)
attn_scores_softmax = tf.nn.softmax(attn_scores)# [[0,0.5,0.5],[0,1,0],[0,0.9,0.1]]

 

将attention scores和values相乘,得到从下往上数第四层的 weighted values

 

weighted_values = values[:, None] * attn_scores_softmax.T[:,:,None]
# attn_scores_softmax.T[:,:,None] = 
# [[[0. ]
#  [0. ]
#  [0. ]]
# [[0.5]
#  [1. ]
#  [0.9]]
# [[0.5]
#  [0. ]
#  [0.1]]]
# values[:, None] = 
#[[[1 2 3]]
# [[2 8 0]]
# [[2 6 3]]]

 

将 weighted values拼接(sum)起来得到outputs

 

outputs = weighted_values.sum(axis=0) # [[2,7,1.5],[2,8,0],[2,7.8,0.3]]

 

attention框架和多头attention

正如上面的动图图解和python步骤实现,attention的框架如上图左边所示,公式如下:

其中除以根号下dk起到soft调节的作用,使得内积不随纬度的变大而无限太大(太大的话 softmax 后就非 0 即 1 了,不够“soft”了)。

 

在这种attention中,W权重矩阵的单一的,只能关注到某一未知的信息。如果使用多个W权重矩阵,则可以通过多头注意使模型共同关注来自不同位置的不同表示子空间的信息,最后再用WO平均多头信息。公式如下:

其中,本文选取8头注意力机制,即h=8;模型纬度选取dmodel = 512,每一头的维度为:

 

由于每个头部的维数减小,其总计算代价与全维数的单头注意相似。

 

接着,来看transformer的整体结构

上图是一个seq2seq结构,可以分为左右两部分,左边是N个encoder曾,右边是N个decoder层,每个encoder都输出给每个decoder,本文选取N=6,故上图可以抽象为以下结构:

每个encoder和decoder的内部结构

 

每个encoder和decoder的内部除了注意力attention子层外,每个层还都包含一个完全连接的前馈网络,由两个线性变换组成,一个ReLU激活层和一个线性激活层。其中,X是Attention(Q,K,V)。

另外,每个decoder层还多了encoder-decoder之间的 Attention,与上述的Self-Attention层不同,Encoder-Decoder Attention是获得当前decoder和encoder的特征向量之间的关系,而Self-Attention则是获得encoder内部输入词之间的关系。

 

在Encoder-Decoder Attention中,query来自前面的Decoder层,key和value来自Encoder层的输出,这允许Decoder层中的每个位置都注意到输入序列中的所有位置。

 

位置信息

到目前为止,模型还不能捕捉序列的顺序。也就是说如果将 K,V 按行打乱顺序(相当于句子中的词序打乱),那幺 Attention 的结果还是一样的。这样的模型在翻译任务中只能学习出要翻译的每一个词却学不出句子中词的顺序,于是本文提出了Position Embedding来记录位置(绝对位置)信息,他的维度和input embedding相同,在encoder和decoder的底部来和input embedding想加,绝对位置公式如下:

其中pos是单词的位置,i是维度,也就是说,位置编码的每个维度都对应于一个正弦曲线。一个位置有dmodel个维度的映射,波长从2π至10000·2π。

 

之所以选择sin和cos函数,是因为sin(α+β)=sinα cosβ+cosα sinβ 、 cos(α+β)=cosα cosβ−sinα sinβ,相对位置可以线性变换。

Be First to Comment

发表回复

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