"); //-->
在继续进行下去之前,我们需要提到一个编码器架构中的细节:在每个编码器中的每个子层(自注意力、前馈网络)的周围都有一个残差连接,并且都跟随着一个“层-归一化”步骤。
层-归一化步骤:https://arxiv.org/abs/1607.06450
如果我们去可视化这些向量以及这个和自注意力相关联的层-归一化操作,那么看起来就像下面这张图描述一样:
****的子层也是这样样的。如果我们想象一个2 层编码-解码结构的transformer,它看起来会像下面这张图一样:
解码组件
既然我们已经谈到了大部分编码器的概念,那么我们基本上也就知道****是如何工作的了。但最好还是看看****的细节。
编码器通过处理输入序列开启工作。顶端编码器的输出之后会变转化为一个包含向量K(键向量)和V(值向量)的注意力向量集 。这些向量将被每个****用于自身的“编码-解码注意力层”,而这些层可以帮助****关注输入序列哪些位置合适:
在完成编码阶段后,则开始解码阶段。解码阶段的每个步骤都会输出一个输出序列(在这个例子里,是英语翻译的句子)的元素
接下来的步骤重复了这个过程,直到到达一个特殊的终止符号,它表示transformer的****已经完成了它的输出。每个步骤的输出在下一个时间步被提供给底端****,并且就像编码器之前做的那样,这些****会输出它们的解码结果 。另外,就像我们对编码器的输入所做的那样,我们会嵌入并添加位置编码给那些****,来表示每个单词的位置。
而那些****中的自注意力层表现的模式与编码器不同:在****中,自注意力层只被允许处理输出序列中更靠前的那些位置。在softmax步骤前,它会把后面的位置给隐去(把它们设为-inf)。
这个“编码-解码注意力层”工作方式基本就像多头自注意力层一样,只不过它是通过在它下面的层来创造查询矩阵,并且从编码器的输出中取得键/值矩阵。
解码组件最后会输出一个实数向量。我们如何把浮点数变成一个单词?这便是线性变换层要做的工作,它之后就是Softmax层。
线性变换层是一个简单的全连接神经网络,它可以把解码组件产生的向量投射到一个比它大得多的、被称作对数几率(logits)的向量里。
不妨假设我们的模型从训练集中学习一万个不同的英语单词(我们模型的“输出词表”)。因此对数几率向量为一万个单元格长度的向量——每个单元格对应某一个单词的分数。
接下来的Softmax 层便会把那些分数变成概率(都为正数、上限1.0)。概率最高的单元格被选中,并且它对应的单词被作为这个时间步的输出。
这张图片从底部以****组件产生的输出向量开始。之后它会转化出一个输出单词。
既然我们已经过了一遍完整的transformer的前向传播过程,那我们就可以直观感受一下它的训练过程。
在训练过程中,一个未经训练的模型会通过一个完全一样的前向传播。但因为我们用有标记的训练集来训练它,所以我们可以用它的输出去与真实的输出做比较。
为了把这个流程可视化,不妨假设我们的输出词汇仅仅包含六个单词:“a”, “am”, “i”, “thanks”, “student”以及 “”(end of sentence的缩写形式)。
我们模型的输出词表在我们训练之前的预处理流程中就被设定好。
一旦我们定义了我们的输出词表,我们可以使用一个相同宽度的向量来表示我们词汇表中的每一个单词。这也被认为是一个one-hot 编码。所以,我们可以用下面这个向量来表示单词“am”:
例子:对我们输出词表的one-hot 编码
接下来我们讨论模型的损失函数——这是我们用来在训练过程中优化的标准。通过它可以训练得到一个结果尽量准确的模型。
比如说我们正在训练模型,现在是第一步,一个简单的例子——把“merci”翻译为“thanks”。
这意味着我们想要一个表示单词“thanks”概率分布的输出。但是因为这个模型还没被训练好,所以不太可能现在就出现这个结果。
因为模型的参数(权重)都被随机的生成,(未经训练的)模型产生的概率分布在每个单元格/单词里都赋予了随机的数值。我们可以用真实的输出来比较它,然后用反向传播算法来略微调整所有模型的权重,生成更接近结果的输出。
你会如何比较两个概率分布呢?我们可以简单地用其中一个减去另一个。更多细节请参考交叉熵和KL散度。
交叉熵:https://colah.github.io/posts/2015-09-Visual-Information/KL散度:https://www.countbayesie.com/blog/2017/5/9/kullback-leibler-divergence-explained
但注意到这是一个过于简化的例子。更现实的情况是处理一个句子。例如,输入“je suis étudiant”并期望输出是“i am a student”。那我们就希望我们的模型能够成功地在这些情况下输出概率分布:
每个概率分布被一个以词表大小(我们的例子里是6,但现实情况通常是3000或10000)为宽度的向量所代表。
第一个概率分布在与“i”关联的单元格有最高的概率
第二个概率分布在与“am”关联的单元格有最高的概率
以此类推,第五个输出的分布表示“”关联的单元格有最高的概率
依据例子训练模型得到的目标概率分布
在一个足够大的数据集上充分训练后,我们希望模型输出的概率分布看起来像这个样子:
我们期望训练过后,模型会输出正确的翻译。当然如果这段话完全来自训练集,它并不是一个很好的评估指标。注意到每个位置(词)都得到了一点概率,即使它不太可能成为那个时间步的输出——这是softmax的一个很有用的性质,它可以帮助模型训练。
因为这个模型一次只产生一个输出,不妨假设这个模型只选择概率最高的单词,并把剩下的词抛弃。这是其中一种方法(叫贪心解码)。另一个完成这个任务的方法是留住概率最靠高的两个单词(例如I和a),那么在下一步里,跑模型两次:其中一次假设第一个位置输出是单词“I”,而另一次假设第一个位置输出是单词“me”,并且无论哪个版本产生更少的误差,都保留概率最高的两个翻译结果。然后我们为第二和第三个位置重复这一步骤。这个方法被称作集束搜索(beam search)。在我们的例子中,集束宽度是2(因为保留了2个集束的结果,如第一和第二个位置),并且最终也返回两个集束的结果(top_beams也是2)。这些都是可以提前设定的参数。
我希望通过上文已经让你们了解到Transformer的主要概念了。如果你想在这个领域深入,我建议可以走以下几步:阅读Attention Is All You Need,Transformer博客和Tensor2Tensor announcement,以及看看Łukasz Kaiser的介绍,了解模型和细节。
Attention Is All You Need:https://arxiv.org/abs/1706.03762Transformer博客:https://ai.googleblog.com/2017/08/transformer-novel-neural-network.htmlTensor2Tensor announcement:https://ai.googleblog.com/2017/06/accelerating-deep-learning-research.htmlŁukasz Kaiser的介绍:https://colab.research.google.com/github/tensorflow/tensor2tensor/blob/master/tensor2tensor/notebooks/hello_t2t.ipynb
接下来可以研究的工作:
Depthwise Separable Convolutions for Neural Machine Translationhttps://arxiv.org/abs/1706.03059
One Model To Learn Them Allhttps://arxiv.org/abs/1706.05137
Discrete Autoencoders for Sequence Modelshttps://arxiv.org/abs/1801.09797
Generating Wikipedia by Summarizing Long Sequenceshttps://arxiv.org/abs/1801.10198
Image Transformerhttps://arxiv.org/abs/1802.05751
Training Tips for the Transformer Modelhttps://arxiv.org/abs/1804.00247
Self-Attention with Relative Position Representationshttps://arxiv.org/abs/1803.02155
Fast Decoding in Sequence Models using Discrete Latent Variableshttps://arxiv.org/abs/1803.03382
A****ctor: Adaptive Learning Rates with Sublinear Memory Costhttps://arxiv.org/abs/1804.04235
*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。