什么是Transformer?
Transformer架构擅长处理文本数据,这些数据本身是有顺序的。他们将一个文本序列作为输入,并产生另一个文本序列作为输出。例如,讲一个输入的英语句子翻译成西班牙语。
Transformer的核心部分,包含一个编码器层和解码器层的堆栈。
为了避免混淆,我们把单个层称为编码器或解码器,并使用编码器堆栈或解码器堆栈分别表示一组编码器与一组解码器。
在编码器堆栈和解码器堆栈之前,都有对应的嵌入层。而在解码器堆栈后,有一个输出层来生成最终的输出。
编码器堆栈中的每个编码器的结构相同。解码器堆栈也是如此。其各自结构如下:
- 编码器:一般有两个子层:包含自注意力层self-attention,用于计算序列中不同词之间的关系;同时包含一个前馈层feed-forward。
- 解码器:一般有三个子层:包含自注意力层self-attention,前馈层feed-forward,编码器-解码器注意力层Decoder-Encoder self attention。
- 每个编码器和解码器都有独属于本层的一组权重。
注意,编码器与解码器的自注意力层self-attention、前馈层feed-forward,以及解码器中的编码器-解码器注意力层Decoder-Encoder self attention 均有残差连接以及正则化层。
基于Transofrmer的变体有许多。一些Transformer构架甚至没有Decoder结构,而仅仅依赖Encoder。
Transformer训练过程
Transformer的训练和推理有一些细微差别。
首先来看训练。每一条训练数据都包括两部分内容:
- 输入序列,或称为“源序列”(例如对于一个翻译问题,“you are welcome” 是一个输入序列)
- 输出序列,或称为“目标序列”(上述的翻译问题“De nada”即为"you are welcome"的西班牙语翻译,为输出序列)
而Transformer训练的目标就是,通过对训练数据中源序列与目标序列之间规律的学习,在测试或实际的任务中,给定原序列,生成目标序列。
如上图所示,Transformer在训练过程中,模型对数据的处理过程如下,大体可以分为6个步骤:
- 在送入第一个编码器之前,输入序列(src_seq)首先被转换为嵌入(同时带有位置编码),产生词嵌入表示(src_position_embed),之后送入第一个编码器。
- 由各编码器组成的编码器堆栈按照顺序对第一步中的输出进行处理,产生输入序列的编码表示(enc_outputs)。
- 在右侧的解码器堆栈中,目标序列首先加入一个句首标记,被转换成嵌入(带位置编码),产生词嵌入表示(tgt_position_embed),之后送入第一个解码器。
- 右各解码器组成的解码器堆栈,将第三步的词嵌入表示(tgt_position_embed),与编码器堆栈的编码表示(enc_outputs)一起处理,产生目标序列的解码表示(dec_outputs)。
- 输出层将其转换为词概率和最终的输出序列(out_seq)。
- 损失函数将这个输出序列(out_seq)与训练数据中的目标序列(tgt_seq)进行比较。这个损失被用来产生梯度,在反向传播过程中训练模型。
词嵌入层与位置编码
Transformer的输入需要关注每个词的两个信息:该词的含义和它在序列中的位置。
- 第一个信息,可通过嵌入层对词的含义进行编码。
- 第二个信息,可通过位置编码层表示该词的位置。
Transformer通过添加两个层来完成两种不同的信息编码。
1.嵌入层(Embedding)
Transformer的编码器和解码器各有一个嵌入层(Embedding)。
在编码器中,输入序列被送入编码器的嵌入层,被称为输入嵌入(input Embedding)。
在解码器中,目标序列右移一个位置,然后在第一个位置插入一个Start token后被送入解码器的嵌入层。
注意,在推理过程中,我们没有目标序列,而是循环地将输出序列送入解码器的嵌入层,此过程为输出嵌入(Output Embedding)。
每个文本序列在输入嵌入层之前,都已被映射成词汇表中单词ID的数字序列。
嵌入层再将每个数字序列映射成一个嵌入向量,这是该词含义一个丰富的表示。
2.位置编码层(Position Encoding)
RNN在循环过程中,每个词按顺序输入,因此隐含地知道每个词的位置。
然而,Transformer一个序列中的所有词都是并行输入的。这是其相对于RNN架构的主要优势;但同时也意味着位置信息会丢失,必须单独添加回来。
解码器堆栈和编码器堆栈各有一个位置编码层。
位置编码的计算是独立于输入序列的,是固定值,只取决于序列的最大长度。
- 第一项是一个常熟代码,表示第一个位置。
- 第二项是一个表示第二位置的常量代码。
pos是该词在序列中的位置,d_model是编码向量的长度(与嵌入向量相同),i是这个向量的索引值。公式表示的是矩阵第pos行、第2i列和(2i+1)列上的元素。
换句话说:位置编码交织了一系列正弦曲线和一系列余弦曲线,对于每个位置pos,当i为偶数时,使用正弦函数计算;当i为奇数时,使用余弦函数计算。
三、矩阵维度(Matrix Dimensions)
深度学习模型一次梳理一批训练样本。
嵌入层和位置编码层对一批序列样本的矩阵进行操作。
嵌入层接受一个(samples, sequence_length)形状为二位单词ID矩阵,将每个单词ID编成一个单词向量,其大小为embedding_size,从而得到一个(samples, sequence_length, embedding_size)形状的三维输出矩阵。
位置编码使用的编码尺寸等于嵌入尺寸,它产生一个类似矩阵,能添加到嵌入矩阵中。
由于嵌入层和位置编码层产生的(samples, sequence_length, embedding_size)形状在模型中被保留下来,随数据在编码器和解码器堆栈中流动,知道它被最终的输出层改变形状。
[实际上变成了(samples, sequence_length, vocab_size)]
以上对Transformer中的矩阵维度有了一个形象的认识。为了简化可视化,从这里开始,暂时放弃第一个维度(samples维度),并使用单个样本的二维表示。