Transformer网络可以利用数据之间的相关性,最近需要用到这一网络,在此做一些记录。

1、Transformer网络概述

Transformer网络最初被设计出来是为了自然语言处理、语言翻译任务,这里解释的也主要基于这一任务展开。

在 Transformer 出现之前,递归神经网络(RNN)是自然语言处理的首选解决方案。当提供一个单词序列时,递归神经网络(RNN)将处理第一个单词,并将结果反馈到处理下一个单词的层。这使它能够跟踪整个句子,而不是单独处理每个单词。但是这种方法只能顺序的处理单词,同时对于长序列的文本无法有效处理,当两个单词距离过远时会出现梯度消失的问题。

Transformer使并行处理整个序列成为可能,从而可以将顺序深度学习模型的速度和容量扩展到前所未有的速度。其次引入了“注意机制”,可以在正向和反向的非常长的文本序列中跟踪单词之间的关系。

Transformer 架构是以encoder/decoder架构为基础,整体结构如下图所示,在Encoder和Decoder中都使用了Self-attention, Point-wise和全连接层。Encoder和decoder的大致结构分别如下图的左半部分和右半部分所示。

Transformer网络-LMLPHP

1.1 编码器

编码组件部分由N个编码器(encoder)构成,每个编码器的结构均相同(但它们不共享权重),每层有两个子层:自注意力层(self-attention) 和 全连接的前馈网络层(feed-forward)。

从编码器输入的句子首先会经过一个自注意力层,这层帮助编码器在对每个单词编码时关注输入句子的其他单词。自注意力层的输出会传递到前馈神经网络中。每个位置的单词对应的前馈神经网络都完全一样(另一种解读就是一层窗口为一个单词的一维卷积神经网络)。

每两个子层中外都套了一个残差连接(residual connections),然后是层归一化(layer normalization)。为了实现残差(输入x与输出可以直接相加),模型中的所有子层以及嵌入层都会产生维度512的输出。

1.2 解码器

解码组件也由N个相同的解码器堆叠而成,也有自注意力(self-attention)层和前馈(feed-forward)层。除此之外,这两个层之间还有一个注意力层,用来关注输入句子的相关部分(和seq2seq模型的注意力作用相似)。
Transformer网络-LMLPHP

修改解码器中的Self-attention子层以防止当前位置Attend到后续位置。这种Masked的Attention是考虑到输出Embedding会偏移一个位置,确保了生成位置i的预测时,仅依赖小于i的位置处的已知输出,相当于把后面不该看到的信息屏蔽掉。

2、nn.transformer函数

pytorch提供了对应的transformer函数 nn.Transformer:

CLASS torch.nn.Transformer(d_model=512, nhead=8, num_encoder_layers=6, 
   num_decoder_layers=6, dim_feedforward=2048, dropout=0.1, activation=<function relu>, 
   custom_encoder=None, custom_decoder=None, layer_norm_eps=1e-05, batch_first=False, 
   norm_first=False, device=None, dtype=None)

对应的输入参数:

transformer的输入包含两部分:

inputs: 原句子对应的tokens,且是完整句子。一般0表示句子开始(​​​​​),1表示句子结束(​​​​​),2为填充(​​​​)。填充的目的是为了让不同长度的句子变为同一个长度,这样才可以组成一个batch。在代码中,该变量一般取名src。

**outputs(shifted right):**上一个阶段的输出。虽然名字叫outputs,但是它是输入。最开始为0(​​​​​),然后本次预测出“我”后,下次调用Transformer的该输入就变成​​ 我​​。在代码中,该变量一般取名tgt。Transformer的输出是一个概率分布。

Transformer网络-LMLPHP

后续逐步进行推理:
Transformer网络-LMLPHP
在Transformer推理时,我们是一个词一个词的输出,但在训练时这样做效率太低了,所以我们会将target一次性给到Transformer(当然,你也可以按照推理过程做),如图所示:
Transformer网络-LMLPHP
Transformer的训练过程和推理过程主要有以下几点异同:

源输入src相同:对于Transformer的inputs部分(src参数)一样,都是要被翻译的句子。

目标输入tgt不同:在Transformer推理时,tgt是从​​​​​开始,然后每次加入上一次的输出(第二次输入为​​ 我​​​)。但在训练时是一次将“完整”的结果给到Transformer,这样其实和一个一个给结果上一致(可参考​ ​该篇​​​的Mask Attention部分)。这里还有一个细节,就是tgt比src少了一位,src是7个token,而tgt是6个token。这是因为我们在最后一次推理时,只会传入前n-1个token。举个例子:假设我们要预测​​ 我 爱 你 ​​​(这里忽略pad),我们最后一次的输入tgt是​​ 我 爱 你​​​(没有​​​​),因此我们的输入tgt一定不会出现目标的最后一个token,所以一般tgt处理时会将目标句子删掉最后一个token。

输出数量变多:在训练时,transformer会一次输出多个概率分布。例如上图,​​我​​​就的等价于是tgt为​​​​​时的输出,​​爱​​​就等价于tgt为​​ 我​​​时的输出,依次类推。当然在训练时,得到输出概率分布后就可以计算loss了,并不需要将概率分布再转成对应的文字。注意这里也有个细节,我们的输出数量是6,对应到token就是​​我 爱 你 ​​​,这里少的是​​​​​,因为​​​​​不需要预测。计算loss时,我们也是要和的这几个token进行计算,所以我们的label不包含​​​​​。代码中通常命名为​​tgt_y​​

12-14 06:48