Transformer中lf-attention以及mask操作的原理以及代码解析
chivas笔者最近在梳理⾃然语⾔预训练模型的有关内容。在看到Bert的时候,突然发现Bert之后的预训练模型都与Transformer结构有关。该结构的⼀个为⼈所知的重点是lf-attention,但是其另外⼀个重点mask操作却被⼈了解的很少,笔者借鉴了其他博主的优质内容,加上⾃⼰的理解整理了⼀下,希望从原理以及代码的⾓度来学习⼀下这两个知识点。
**
lf-attention
**
一对一雅思外教
Self-attention可以说是整个Transformer模型的核⼼思想。本章关于Self-attention的公式图⽚均来源于Vaswani 的⽂章attention is all you need以及博主adam-liu 的,或者本⼈⼿绘.该篇博客在Self-attention的讲述上⾮常精彩,建议初学者去看⼀下其原博客内容。
lf-attention的出现是为了摆脱循环神经⽹络不能并⾏计算的缺点⽽提出的,它的设计模式可以通过当前单词去查看其输⼊序列中的其他单词,以此来寻找编码这个单词更好的线索。
在学习Self-Attention的过程中,⾸先学习的是⼀个attention的普遍形式(⽂章中称之为Scaled Dot-Product Attention),看过Attention is all your need ⽂章的同学肯定知道其计算其计算⽅式就是通过构造三个矩阵Q,K,V来计算Scaled Dot-Product
Attention矩阵,具体的计算流程以及以及计算公式如下图所⽰:
图1
图2
Vaswani⽂章第⼀次对attention提出了⼀个归纳化的公式。在NMT领域当中,我们对⽐传统attention的计算⽅式,很容易看出以上Q是来源于Encoder端的隐藏层状态,⽽K,V是来源于Decoder端的隐藏曾状态。
⽽Transformer使⽤的Self-attention。顾名思义即句⼦中的每⼀个词都要和该句⼦当中的所有词进⾏⼀个attention计算,⽬的是学习句⼦内部的词依赖关系,获取词的内部结构。因此,从这个特点当中我们可以其实也能推测出Self-attention计算的信息来源都是来源于其句⼦本⾝。
故在上述attention的计算公式当中,可以看出lf-attention即Q=K=V。下⾯⽤Transformer的部分代码(Tensorflow)来进⼀步的了解Q,K,V在lf-attention中的构成(以Encoder端为例)。
以下是train.py的部分代码
1with tf.variable_scope("num_blocks_{}".format(i)):
renice2 lf.enc = multihead_attention(,
3 ,
4 num_units=hp.hidden_units,
5 num_heads=hp.num_heads,
6 dropout_rate=hp.dropout_rate,
7 is_traing=is_traing,
8 causality=Fal)
以下是module.py的部分代码
1def multihead_attention(queries,
stranger in the night
2 keys,
3 num_units=None,
4 num_heads=8,
5 dropout_rate=0,
6 is_training=True,
7 causality=Fal,
8 scope='multihead_attention',
abate
9 reu=None):trapezoid
10
11with tf.variable_scope(scope,reu=reu):
佛山cad培训12if num_units is None:
13 num_units = _shape().as_list[-1]
14
15 Q = tf.layers.den(queries,num_units,lu)
16 K = tf.layers.den(keys,num_units,lu)
17 V = tf.layers.den(keys,num_units,lu)
train.py中的 lf.enc代表的就是 encoder端经过word_embedding以及position_embedding之后的句⼦信息,之后⽤X来代替。
根据其传⼊ multihead_attention 函数中的参数来看,在机器翻译领域当中,Transformer当中的queries以及Keys都是其输⼊信息x。⽽在module.py⽂件当中,我们从矩阵Q,K,V的计算公式中我们可以发现:
Q是将queries输⼊进⼀个节点数为num_units的前馈神经⽹络之后得到的矩阵
⽽K,V则是将keys输⼊进⼀个节点数为num_units的前馈神经⽹络之后得到的矩阵。
结合所有的信息,在机器翻译领域当中,Q,K,V的所有来源就是encoder端的输⼊X。即可以看成Q=K=V
具体计算过程如下图所⽰:
图3强度英文
从图中我们可发现,当中使⽤了三个权重矩阵(WQ,WK,WV)来右乘输⼊信息矩阵X获得K,Q,V。之后我们便可以使⽤上述的attention 公式来计算lf-attention的矩阵。
在这⾥也顺便提⼀下muilti_head的概念,Multi_head lf_attention的意思就是重复以上过程多次,论⽂当中是重复8次,即8个Head,使⽤多套(WQ,WK,WV)矩阵(只要在初始化的时候多稍微变⼀下,很容易获得多套权重矩阵)。获得多套(Q,K,V)矩阵,然后进⾏attention计算时便能获得多个lf_attention矩阵。
lf-attention之后紧接着的步骤是前馈神经⽹络,⽽前馈神经⽹络接受的是单个的矩阵向量,⽽不是多个矩阵,因此需要把计算得到的多个lf-attention矩阵采⽤某种⽅式进⾏合并。因此⽂章中给出的思路是将这多个连接在⼀起(可能是简单就是好,No free lunch原则)再和⼀个矩阵W0相乘。步骤如下图:
图四
综合上述说法,multi_layer_lf-attention的整体计算流程如下图所⽰:
图5
lf-attention在神经机器翻译实际的操作设计当中,不仅仅是由上⾯lf-attention计算公式那般设计,其中还要加⼊Mask操作。
其中在Encoder端和Decoder端都需要使⽤的Mask操作,称之为PADDING MASK。
⽽仅仅在Decoder段使⽤的Mask操作,则被称之为Sequence MASK。下⾯将结合代码分别对其进⾏介绍。
成都军训
PADDING MASK
我们在训练的过程中,⾃然语⾔数据往往都是以Batch的形式输⼊进的模型,⽽⼀个batch中的每⼀句话不能保证长度都是⼀样的,所以需要使⽤PADDING的⽅式将所有的句⼦都补全到最长的长度,⽐如拿0进⾏填充,但是我们知道这种⽤0填充的位置的信息是完全没有意义的,因此我们希望这个位置不参与后期的反向传播过程。以此避免最后影响模型⾃⾝的效果,因此提出了在训练时将补全的位置给Mask掉的做法。⽽在Self-attention的计算当中,我们⾃然也不希望有效词的注意⼒集中在这些没有意义的位置上,因此使⽤了PADDING MASK 的⽅式.
PADDING MASK在attention的计算过程中处于softmax之前(图1中的opt表⽰optional即该层可加可不加,若是不想使⽤PADDING MASK操作,则直接Softmax就完事了),通过PADDING MASK的操作,使得补全位置上的值成为⼀个⾮常⼤的负数(可以是负⽆穷),这样的话,经过Softmax层的时候,这些位置上的概率就是0。以此操作就相当于把补全位置的⽆⽤信息给遮蔽掉了(Mask掉了)。具体操作见如下代码(请和注释⼀起⾷⽤):
>中学英语教学论文