当前位置:   article > 正文

Transformer Decoder_transformer decoder

transformer decoder

这是一篇主要讲解decoder的博客,由于第一次写博客,所以以翻译别人的为主,加上自己的见解(原文https://medium.com/dissecting-bert/dissecting-bert-appendix-the-decoder-3b86f66b0e5f),如果不了解encoder部分,建议先可以看https://zhuanlan.zhihu.com/p/54356280

 

本文主要讲解Transformer中的Decoder部分,后续其他部分可能会补充

首先,我们先定义几个常用的变量(以翻译为例):

emb_dim:表示词嵌入的维度

input_length:表示input单词的个数

target_length:表示target_sequence的个数 + 1,为什么会加1会在后面详细说明

vocab_size:表示所有target单词的总个数,其实就是词库的意思


1.Problem

由于NLP涉及的方面较多,在本文中我们主要利用transformer解决翻译方面的问题。为了将一种语言翻译为另一种语言,我们希望我们的模型可以完成以下任务:

  1. 能够获取输入语言中各个单词之间的联系,也就是类似分析语言中主谓宾、定状补成分等等。这一部分其实在transformer中的encoder已经实现。
  2. 能够将输入语言中所包含的信息和每一步中已翻译的信息进行结合(输入语言中所包含的信息其实就是encoder的输出,而decoder进行预测的时候是一个单词一个单词预测的)。这一部分其实就是decoder所需要进行的处理。

encoder和decoder是transformer中两个主要组成部分,如下图所示:

图1 Encoder与Decoder

2.主要流程

信息在transformer结构中的传递主要如下所示:

1.首先将输入序列的每一个单词每一个单词转化为词嵌入向量,词嵌入向量的维度为(emb_dimb),一句话中总共的单词长度为input_length,因此可以得到一个input_length * emb_dimb大小的矩阵,其中每一行代表的是一个单词。

2.将1中得到的结果加入位置信息(positional encoding),得到的仍然是一个input_length * emb_dimb大小的矩阵。

3.然后将2中得到的结果传入N个encode块中,我们得到的仍然是一个input_length * emb_dimb大小的矩阵,至于为什么会是矩阵大小一致可以参照图7,此时的矩阵其实已经包含了输入序列中各个单词之间的关系。

4.接着将目标序列同样进行1、2的操作,并在此基础上进行mask(如何mask下面会讲到)以防其看到未来信息从而导致过拟合。由于目标序列单词的长度为target_length,所以我们得到了一个(target_length * emb_dimb)大小的矩阵。

5.将4中的结果输入到N个decoder块中,每一个decoder块同时也使用了3中的结果,如下图2所示,每一个decoder块输出的矩阵大小为target_length * emb_dimb,正是因为矩阵的输入和输出大小一样,所以我们才可以进行迭代的输入到N个decoder块中。

6.最后将5中的结果输入到一个全连接层中,得到一个(target_length * vocab_size)大小的矩阵,然后对每一行进行softmax,每一行中最大的值即代表了每个输入对应的输出结果。

图2 encoder与decoder对应的关系

 

3.输入

本文所描述的算法主要是利用目标序列和输入序列对网络进行训练。在本节中我们主要讨论的是怎样将一个目标序列(例如: “Hola, como estás ?”)变成一个矩阵的从而可以输入到decorder块中。这个过程其实是和encoder类似:1.进行embeding,将每一单词转化为一个向量形式。2.进行位置编码,添加位置信息。但是和encoder不同之处在于目标序列是有偏移的,例如:[“Hola”, “, “, “como”, “estás”, “?”]→[“<SS>”, “Hola”, “, “, “como”, “estás”, “?”] 

为什么要这样做呢?我们可以想到在测试的时候我们是没有target sequence的,但是我们需要给定一个decoder的输出才能让它进行预测,这个时候我们只能给定一个开始标记,即<SS>。由于进行了位置编码,相当于我们告诉decoder“让我们根据encoder的编码信息开始预测第一个target sequence的输出吧”。这就解释了为什么target_length需要+1。

 

4.Decoder(train and test)

在这一节中主要讨论的是Decoder与Encoder不同的地方

图3 decoder

在测试阶段(没有真实标签):

1.从input sequence中计算embeding,通过N个Encoder块得到各个单词之间关系。

2.使用一个开始的标志进行预测,例如上面的<SS>输入到decoder块中,并结合从Encoder中得到输入序列的关系,从而得到一个输出,即<SS>的下一个单词“Hola”。

3.将["<SS>", "Hola"]作为输入,重复上述过程,直到输出一个结束的提示,如<EOS>

我们可以看到在测试阶段是一个单词一个单词输出,而不是所有单词一起输出,这一点和RNN很类似

 

在训练阶段:

由于在训练阶段我们有target sequence,但是target sequence是存在偏移的,所以我们希望通过一个有偏移的target sequence去预测一个没有偏移的target sequence:

例如[‘<SS>’,’Hola’, ‘,’, ‘ como’, ‘estas’, ‘?’] ----> [’Hola’, ‘,’, ‘ como’, ‘estas’, ‘?’,’<EOS>’]

在训练阶段我们希望并行训练,类似于上面给的例子,一次性给出全部input sequence,然后一次性预测所有target sequence,而不是像测试过程一样,只能用上一个单词的输出来预测下一个,因此会产生一个问题:由于我们是直接将全部目标序列输入进行训练的,因此模型很容易看到未来信息,例如当我们想要预测estas时,模型可能看到como右边就是estas,因此它很有可能在下一次看到como这个单词的时候就直接输出estas。 所以我们需要修改一些注意层,防止右侧看到信息的模型,同时可以让它使用已经预测出来的信息(左侧信息)即Masked multi-head attention,如下图所示,我们利用<SS>对Hola进行预测,利用[<SS>、‘’Hola’]对‘,’进行预测,预测‘estas‘’时,我们使用的是绿色区域的信息,当然我们可以在像在测试的时候一样一个一个进行预测,然后利用反向传播进行修正,但是这样会奇慢无比(我个人的理解),因此我们需要进行并行训练:

Masked multi-head attention其实和multi-head attention很类似,唯一不同的就是将未来信息给Mask掉了。我们直接通过例子来进行说明:

首先我们先计算target sequence的 embeding 向量,然后分别产生Q、V、K向量,再通过(Q*K)/\sqrt{d}计算各个word之间的attention程度大小,产生一个target_length * target_length维度的矩阵,如下图4所示:

图4 target attention

由上图我们可以清晰的看到target sequence中各个单词之间的attention,但是在训练阶段我们应该避免看到未来信息,例如在上述矩阵第一行中我们分别计算了<SS>与<SS>、<Hola>、<,>、<como>、<estas>、<?>之间的attention大小,但是在测试阶段我们只有<SS>这个单词的embeding,因此我们只能计算<SS>与<SS>自己的attention,而没办法计算<SS>与其他单词的attention大小,所以在训练阶段我们应该将<SS>与<Hola>、<,>、<como>、<estas>、<?>之间的attention给mask掉。同理在<Hola>这一行中我们应该将其与<,>、<como>、<estas>、<?>的注意力mask掉,如下图5所示:

图5 mask attention

为什么我们要将这些注意力设置为-Inf呢?继续往下我们可以看到,当我们将这些未来的注意力设置为-Inf的时候,如果我们再对每一行其进行softmax,那么-Inf位置的attention就是为0的,正好满足我们不给未来信息任何注意力的要求,所以我们得到了一个严格的下三角矩阵,如下图6所示:

图6 attention softmax

上面这个矩阵有一些地方是有问题的(第4行第4列应该接近1.0)。后续步骤其实就和multi-head attention一模一样了。现在我们重新捋一遍矩阵大小,来了解一下它的来龙去脉。如下图所示,先将target sequence进行embeding,将其转化为target_length * embeding_length大小的矩阵(embeding_length=512),每一行代表一个单词,每一行都会产生一个Q、K、V向量,d_{q},d_{k},d_{v}的维度都是64,通过Q、K可以得到各个单词之间的attention,维度为:target_length * target_length。将attention矩阵乘以V矩阵,得到target_length * 64维度的矩阵,由于使用的是multi-head attention,因此需要将每个每一个attention的结果进行拼接,从而得到target_length * embeding_length大小的矩阵,进一步证明了输出维度与输入维度是相同的,如下图7所示。

图7 矩阵大小

经过mask multi-head attention之后产生的矩阵大小和target_length*embeding_length一样,只不过它仅仅是是融合了之前的信息(即已翻译的单词)。例如下图,我们输入[a、b、c、d] -----> [e、f、g、h],其中各个字母分别对应的是一维向量,我们选取其中的g来举例,它分别融合了a、b、c向量的信息,而没有融合d之间的信息(即未来信息),并且[e、f、g、h]和[a、b、c、d]的矩阵维度是一致的,如下图8所示:

图8 mask attention

 

5.Multi-Head Attention — Encoder output and target

由上一节可以知道通过mask multi-head attention可以得到一个target_length * embeding_length维度的矩阵,我们依然能将这个矩阵的每一行(即每一个单词)输出对应的Q、K、V向量,但是在这里我们仅仅只使用了它的Q向量,而K、V向量则来自于encoder的输出,各个矩阵的维度如下所示:

Q: target_length * d_{v}

K: input_length *  d_{v}

V: input_length *  d_{v}

接下来我们依然通过attention计算公式(Q*K^{T})/\sqrt{d_{v}}来计算对应的attention,这个attention矩阵维度为:target_length * input_length,即input sequence和target sequence之间的联系,为了便于理解,我们直接给出一个例子,如下图所示:

input & target relationship

再将上述attention矩阵与V矩阵相乘,由于是multi attention,因此有多个attention矩阵,最后再将结果按列concat起来得到一个target_length * embeding_legnth矩阵,以便于保证作为下一个deconder块的输入,下图以一个attention为例进行介绍:

6.linear and softmax

通过上述可知,由decoder块输出的矩阵维度大小为target_length * embeding_length,但是我们想得到的是target sequence。例如在上面的例子将英语翻译成西班牙语,我们需要做的是从所有的西班牙语单词中找到与之匹配的单词,而在本篇博客的开头我们就设vocab_size表示所有目标单词的总个数,因此我们需要一个linear层,将target_length * embeding_length ----> target_length * vocab_size,再对每一行进行softmax,每一行中最大概率的位置即代表了其预测的下一个单词。

 

参考资料:

1.Dissecting BERT Appendix: The Decoder  https://medium.com/dissecting-bert/dissecting-bert-appendix-the-decoder-3b86f66b0e5f

2.Dissecting BERT Part 1: The Encoder  https://medium.com/dissecting-bert/dissecting-bert-part-1-d3c3d495cdb3

3.Attention Is All You Need; Vaswani et al., 2017.

4.BERT大火却不懂Transformer?读这一篇就够了   https://zhuanlan.zhihu.com/p/54356280


这是本人的第一篇博客,如果有什么问题希望大家多多见谅,只是想在这记录一下自己学到的东西,能帮助大家更好~

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/348344
推荐阅读
相关标签
  

闽ICP备14008679号