美文网首页
Transformer

Transformer

作者: 612twilight | 来源:发表于2020-04-20 00:03 被阅读0次

    more than code

    简介

    Transformer是谷歌在论文《Attention is all you need》里面提出的模型,NLP领域的经典必读论文,在论文中,谷歌利用attention的结构,在语言表征的时候编码进上下文的信息。Transformer的模型结构如图所示。

    transformer.jpg
    和大多数的seq2seq模型一样,其结构也是由encoder和decoder组成的。encoder是由多个相同的层堆叠组成的,下图中左边的代表了某一层,论文里设置了6层的重复结构。而decoder是由右边的结构组成,论文里面也是设置成为6个相同的结构去解码,接下来本文将从训练过程和预测过程中tensor的变化来介绍模型的结构。

    训练过程

    由于模型分为encoder和decoder两个部分,而他们在训练时分别接受了不同的输入,所以这里分开来描述,我们现在以一个中英翻译任务来说明,中英翻译任务输入的是中文序列,设其中有一个序列名为input,其实际长度为F_{real} ,中文源语言序列的输入需要在序列结束加一个</s>,并且给定输入语料中最大的序列长度是F,对于那些不足的序列,我们需要进行padding,使其长度也达到F。翻译任务输出的是英文,设input序列翻译结果为output,其实际长度为T_{real},同样的目标语言的语料需要在开始增加一个<s>,在结尾增加一个</s>,并且设输出语料中最大序列的长度为T+1。由于训练时数据是以batch的方式输入,这里假定每个batch的大小为B

    encoder部分训练

    encoder训练时接受的输入是shape为(B,F)的经过padding的多个序列。同时为了方便计算(也可以内部计算这个padding mask)也会输入一个padding mask的tensor,其维度和输入序列相同,在序列padding部分padding mask为0,非padding部分为1.

    Block

    embddding结构

    首先将输入的序列数据进行embedding,设embedding的维度是E,embedding分为word embedding和position embedding,两个embedding的维度相同均为E,最终的embedding有二者相加得到embedding tensor,此时向量维度为(B,F,E),可以开始输入到encoder的Block里面

    multi-head attention结构

    embedding之后,tensor首先进行了multi-head attention,这里的attention是一种self-attention.
    因为embedding和multi-head attention进行了residual connect,所以multi-head attention输出的hidden_size和输入的embedding_size都是一样的,都为E。在进行multi-head attention时,我们首先要构建query,key,value矩阵,正常情况下query是从target序列构建,key和value是从source序列构建,但这里是self-attention,所以都是从embedding tensor去构建,我们首先将embedding tensorreshape成(B*F,E)的2d矩阵,然后分别接入三个全连接激活层得到query,key,value这三个tensor,其维度均为(B*F,E),再重新transpose为(B,F,E),因为这里用的是多头注意力,所以我们还需要将E维度划分成N个头,假设N*H=E,那么query,key,value经过多头划分就变成了(B,F,N,H),之后利用这三个tensor计算attention的输出。
    计算attention的时候,首先将query,key,valuetranspose成(B,N,F,H),因为这里不同的head是进行独立的attention。然后根据计算公式可以得到一个attention得分。
    attention\_scores = \frac{{{{query*ke}}{{{y}}^T}}}{{\sqrt H }}
    我们对这个拆开来看看他具体做了什么。假设一个序列一个head的query如下, 其中q_i是序列中第i个位置词的query向量,
    \left[ {\begin{array}{*{20}{c}} {{q_{11}}}&{{q_{12}}}&{...}&{{q_{1H}}}\\ {{q_{21}}}&{{q_{22}}}&{...}&{{q_{2H}}}\\ {...}&{...}&{...}&{...}\\ {{q_{F1}}}&{{q_{F2}}}&{...}&{{q_{FH}}} \end{array}} \right] = \left[ {\begin{array}{*{20}{c}} {{q_1}}\\ {{q_2}}\\ {...}\\ {{q_F}} \end{array}} \right]
    而key则用下图表示:
    \left[ {\begin{array}{*{20}{c}} {{k_{11}}}&{{k_{12}}}&{...}&{{k_{1H}}}\\ {{k_{21}}}&{{k_{22}}}&{...}&{{k_{2H}}}\\ {...}&{...}&{...}&{...}\\ {{k_{F1}}}&{{k_{F2}}}&{...}&{{k_{FH}}} \end{array}} \right] = \left[ {\begin{array}{*{20}{c}} {{k_1}}\\ {{k_2}}\\ {...}\\ {{k_F}} \end{array}} \right]
    那么所谓的attention_score则是:
    \left[ {\begin{array}{*{20}{c}} {{q_1}{k_1}}&{{q_1}{k_2}}&{...}&{{q_1}{k_F}}\\ {{q_2}{k_1}}&{{q_2}{k_2}}&{...}&{{q_2}{k_F}}\\ {...}&{...}&{...}&{...}\\ {{q_F}{k_1}}&{{q_F}{k_2}}&{...}&{{q_F}{k_F}} \end{array}} \right]
    这里我们考虑从一般的attention来理解,而不是从self attention来理解,一般使用attention是为了建立source序列各位置对target序列各位置重要程度的attention向量,可以理解为我们在给target序列编码的时候,要增加一些source序列的信息进来。所以要从source序列构建key,value,从target语料构建query,而attention_scores第i行的元素是source序列中各位置对target序列的第i个位置的重要程度。另外考虑到source序列会有padding部分,padding部分不应当提供任何信息出来,所以需要在计算得分的时候,让key向量对应的padding部分计算得分为0,这里将key里面padding部分的位置在attention_score里面对应的地方变成-10000,这样在softmax之后,其输出的值就可以认为是0了。
    \left[ {\begin{array}{*{20}{c}} {{q_1}{k_1}}&{{q_1}{k_2}}&{...}&{{q_1}{k_F}}\\ {{q_2}{k_1}}&{{q_2}{k_2}}&{...}&{{q_2}{k_F}}\\ {...}&{...}&{...}&{...}\\ {{q_F}{k_1}}&{{q_F}{k_2}}&{...}&{{q_F}{k_F}} \end{array}} \right]padding - > \left[ {\begin{array}{*{20}{c}} {{q_1}{k_1}}&{...}&{{q_1}{k_{Freal}}}&{ - 10000...}\\ {{q_2}{k_1}}&{...}&{{q_2}{k_{Freal}}}&{ - 10000...}\\ {...}&{...}&{...}&{ - 10000...}\\ {{q_F}{k_1}}&{...}&{{q_F}{k_{Freal}}}&{ - 10000...} \end{array}} \right]
    attention_score经过softmax之后,得到attention_probs,该tensor里面的第i行,第j列的元素可以认为是在source序列中第j个位置的词附加给target序列中第i个位置词的注意力比重,最后在乘以value矩阵,可以得到target序列对source序列各位置的attention信息,因为value矩阵是从source序列构造的,所以attention可以理解为,target序列从source序列获取额外信息的过程,而self attention则是从自身序列的其他位置获取额外信息。
    我们可以令attention_probs矩阵为:
    \left[ {\begin{array}{*{20}{c}} {{w_{11}}}&{{w_{12}}}&{...}&{{w_{1F}}}\\ {{w_{21}}}&{{w_{22}}}&{...}&{{w_{2F}}}\\ {...}&{...}&{...}&{...}\\ {{w_{F1}}}&{{w_{F2}}}&{...}&{{w_{FF}}} \end{array}} \right]
    value矩阵为
    \left[ {\begin{array}{*{20}{c}} {{v_{11}}}&{{v_{12}}}&{...}&{{v_{1H}}}\\ {{v_{21}}}&{{v_{22}}}&{...}&{{v_{2H}}}\\ {...}&{...}&{...}&{...}\\ {{v_{F1}}}&{{v_{F2}}}&{...}&{{v_{FH}}} \end{array}} \right] = \left[ {\begin{array}{*{20}{c}} {{v_1}}\\ {{v_2}}\\ {...}\\ {{v_F}} \end{array}} \right]
    二者相乘,得到的attention向量如下,其中第i行代表了source序列各位置提供给target序列第i个位置的信息,因为是多头注意力,每个头输出的attention还要进行拼接,然后接一层全链接层合并这些注意力:
    \left[ {\begin{array}{*{20}{c}} {{w_{11}}{v_1} + {w_{12}}{v_2} + ... + {w_{1F}}{v_F}}\\ {{w_{21}}{v_1} + {w_{22}}{v_2} + ... + {w_{2F}}{v_F}}\\ {...}\\ {{w_{F1}}{v_1} + {w_{F2}}{v_2} + ... + {w_{FF}}{v_F}} \end{array}} \right]
    我们获取的attention是对原有信息的补充,主要是从source序列获取的,所以要讲attention矩阵加到原来的输入的embedding里面,这也就是residual connect的由来。原著论文中还在这里加入了layer normal,layer normal区别于batch normal,是对一个序列自身进行标准化,而batch normal则是对在对于一个batch内各样本的单个特征进行normal,下图左边是layer normal,右图是batch normal。

    layer normal.jpg

    Position-wise feed-forward networks

    multi-head self attention之后,我们可以还需经过Position-wise feed-forward networks,其实本质上就是一个MLP,即对于序列中的某个词,其张量为X,经过feed-forward networks之后,如下
    FFN(X) = max(0,w_{1}x+b_{1})w_{2}+b_{2}
    这里的position wise是因为序列中的每个位置上的词的embedding都是乘以同样一个w_{1}w_{2},即不同位置的线性变换是完全一样的,实际操作很简单,就是对shape为(B,F,E)的输入接一层全连接激活层即可,因为有两层变换,所以有一个中间隐藏层向量,设该向量维度为ff_{dim},由于广播机制,所以序列中不同的词都乘以同一个权值矩阵(E,ff_{dim}),然后再乘以另一个权值矩阵(ff_{dim},E),变回原来的维度E
    。所以shape的变化为:
    (B,F,E)->(B,F,ff_{dim})->(B,F,E)
    在feed-forward networks之后也要做一个residual connect与layer norm。
    之后输出的(B,F,E)就可以进入下一个block

    其余 block

    经过其余5层block之后,我们可以获得最终encoder的输出(B,F,E)

    decoder训练

    embedding结构

    训练过程中的decoder,接受的输入的是标签序列(B,T),这里输入序列要移除</s>,所以序列长度不是T+1,而是T
    首先我们也要对其进行embedding和position embedding,embedding之后的维度是(B,T,E),这里的embedding与encoder的embedding用的是同一组权值矩阵。

    Decoder Block

    Masked multi-head attention

    embedding之后进入Masked self-attention layer,这里也是一个self attention,原理上和self attention是一样的,但是,增加了一个mask矩阵,所谓的mask矩阵本质上是对未来信息的遮盖,因为我们训练时输入的是一个完整的序列T,但是在预测的时候解码序列中的某个位置是无法知道未来的信息的。所以需要加一个mask矩阵,那这个mask矩阵怎么加呢,在上述self attention矩阵中,我们有一个attention_probs矩阵
    \left[ {\begin{array}{*{20}{c}} {{w_{11}}}&{{w_{12}}}&{...}&{{w_{1F}}}\\ {{w_{21}}}&{{w_{22}}}&{...}&{{w_{2F}}}\\ {...}&{...}&{...}&{...}\\ {{w_{T1}}}&{{w_{T2}}}&{...}&{{w_{TF}}} \end{array}} \right]
    它的第i行代表了编码第i个位置的时,从自身其余位置获取信息的比重,当我们用一下左下三角矩阵对其点乘时,那第i个位置的信息只能获取它之前的序列位置的信息,其attention_probs就变成了:
    \left[ {\begin{array}{*{20}{c}} {{w_{11}}}&0&{...}&0\\ {{w_{21}}}&{{w_{22}}}&{...}&{...}\\ {...}&{...}&{...}&0\\ {{w_{T1}}}&{{w_{T2}}}&{...}&{{w_{TF}}} \end{array}} \right]
    各位置获取的attention信息就变成了:
    \left[ {\begin{array}{*{20}{c}} {{w_{11}}{v_1}}\\ {{w_{21}}{v_1} + {w_{22}}{v_2}}\\ {...}\\ {{w_{T1}}{v_1} + {w_{T2}}{v_2} + ... + {w_{TF}}{v_F}} \end{array}} \right]
    这里仍然要做padding mask,因为目标语料也是有padding的。
    之后依然需要做add&layer normal操作。

    multi-head attention(vanilla attention)

    在经过masked multi-head attention之后,decoder编码的信息还需要与encoder编码的信息进行attention,即我们需要将encoder编码的序列信息提取出有用的部分给decoder序列信息,所以需要从encoder的输出去构建key和value向量,然后从decoder内部序列变量构建query向量,以此进行attention操作。
    attention之后依然要做add&layer normal操作。

    其余的decoder Block

    将之前的decoder block的再重复五次相同的Block结构,得到最终的输出序列嵌入式表示(B,T,E)

    projection layer

    一般认为我们需要将decoder输出的(B,T,E)向量接一个全连接层转到词表的logits空间,变成(B,T,vocab_size),在实际使用的时候,可以将原先的embedding矩阵拿过来transpose一下作为全连接层。Kyubyong/transformer

    训练Loss计算

    将logits向量接一层softmax得到概率,与目标的序列使用交叉熵损失函数计算损失函数值,就可以开启参数优化过程了。这里的目标序列是最初(B,T+1)的语料移除一个开始<s>符,因此这个loss是错位的,这样预测过程可以由前一个词生成下一个词。

    预测过程

    预测过程可以简单描述一下,首先我们要将待翻译的序列输入到encoder里面得到一个encoder编码向量(F,E),然后我们在decoder里面输入开始标记<s>的单个元素序列,这个标记我们之前也有填充到训练过程的模型中,预测出下一个词T1(即最大可能词),然后我们将<s>与T1拼接起来,作为decoder的输入序列,继续预测下一个词。直到预测出来的序列有</s>为止。这里的预测过程是贪心搜索,还有beam search,暂且不提。
    遗留问题:预测过程为什么用mask self attention?

    参考文献

    Attention Is All You Need
    理解语言的 Transformer 模型

    相关文章

      网友评论

          本文标题:Transformer

          本文链接:https://www.haomeiwen.com/subject/utbhvhtx.html