本文来源公众号“江大白”,仅用于学术分享,侵权删,干货满满。
原文链接:基于Pytorch框架,从零实现Transformer模型实战
以下文章来源于微信公众号:小喵学AI
作者:郭小喵
链接:https://mp.weixin.qq.com/s/XFniIyQcrxambld5KmXr6Q
本文仅用于学术分享,如有侵权,请联系后台作删文处理
导读
Transformer作为深度学习进入大模型时代的标志性模型,其强大的性能被广泛应用于各个领域。本文基于Pytorch框架从零开始搭建Transformer模型,不仅有详细的脚本说明,还涵盖了丰富了模型分析,希望对大家有帮助。
2017年Google在论文《Attention is All You Need》中提出了Transformer模型,并成功应用到NLP领域。该模型完全基于自注意力机制Attention mechanism实现,弥补了传统的RNN模型的不足。
本文笔者将详解使用Pytorch从零开始逐步实现Transformer模型。
0 回顾
首先我们先回顾一下Transformer原理。宏观层面,Transformer可以看成是一个黑箱操作的序列到序列(seq2seq)模型。例如,在机器翻译中,输入一种语言,经Transformer输出翻译后的另一种语言。
拆开这个黑箱,可以看到模型本质就是一个Encoders-Decoders结构。
-
每个Encoders中分别由6层Encoder组成。(所有Encoder结构完全相同,但是训练参数不同,每个参数是独立训练的,循环执行6次Encode,而不是只训练了一个Encoder然后复制5份)。
-
Decoders同理。
-
这里每个Encoders包含6层Encoder,只是论文中Nx=6,实际可以自定义。
Transformer整体架构如下图所示。
其中,
-
编码端:经过词向量层(Input Embedding)和位置编码层(Positional Encoding),得到最终输入,流经自注意力层(Multi-Head Attention)、残差和层归一化(Add&Norm)、前馈神经网络层(Feed Forward)、残差和层归一化(Add&Norm),得到编码端的输出(后续会和解码端进行交互)。
-
解码端:经过词向量层(Output Embedding)和位置编码层(Positional Encoding),得到最终输入,流经掩码自注意力层(Masked Multi-Head Attention,把当前词之后的词全部mask掉)、残差和层归一化(Add&Norm)、交互注意力层(Multi-Head Attention,把编码端的输出和解码端的信息进行交互,Q矩阵来自解码端,K、V矩阵来自编码端的输出)、残差和层归一化(Add&Norm)、前馈神经网络层(Feed Forward)、残差和层归一化(Add&Norm),得到解码端的输出。
注:编码端和解码端的输入不一定等长。
1 Encoder
下面还是以机器翻译("我是学生"->"I am a student")为例说明。
对于上图中,整个模型的输入即为"我是学生",目标是将其翻译为"I am a student",但是计算机是无法识别"我是学生"的,需要将其转化为二进制形式,再送入模型。
将中文转换为计算机可以识别的向量通常有两种方法:
-
One Hot编码:形成高维向量,对于中文来说,汉字的数量就是向量的维度,然后是哪个字就将对应位置变为1,其它位置变为0,以此来表示一句话。
-
Embedding词嵌入:通过网络进行训练或者通过一些训练好的模型将其转化成连续性的向量。
一般来说第二种方法使用较多,因为第一种有几个缺点,第一个就是每个字都是相互独立的,缺少语义联系信息,第二就是汉字数量太多,会导致生成的维度过大,占用系统内存。
1.1 输入Input
输入Inputs维度是[batch size,sequence length],经Word2Vec,转换为计算机可以识别的Input Embedding,论文中每个词对应一个512维度的向量,维度是[batch_size,sequence_length,embedding_dimmension]。batch size指的是句子数,sequence length指的是输入的句子中最长的句子的字数,embedding_dimmension是词向量长度。
如上图所示,以机器翻译("我是学生"->"I am a student")为例,首先对输入的文字进行Word Embedding处理,每个字(词)用一个连续型向量表示(这里定义的是4维向量),称为词向量。这样一个句子,也就是嵌入后的输入向量input Embedding就可以用一个矩阵表示(4*4维,序列长度为4,每个字用4维向量表示)。input Embedding加上位置信息得到编码器的输入矩阵。
「为什么需要在input Embedding加上位置信息?」 与RNN相比,RNN是一个字一个字输入,自然可以保留每个字的顺序关系信息,而Transformer使用的是自注意力机制来提取信息,一个句子中的每个字/词是并行计算,虽然处理每个字的时候考虑到了所有字对其的影响,但是并没有考虑到各个字相互之间的位置信息,也就是上下文。所以需要引入位置信息。
Transformer中使用Positional Encoding表示每个字/词的位置信息。定义如下:
这样就即可实现让自注意力机制考虑词的顺序,同时又可以输入所有的词。
1.2 输入Input代码实现
1.2.1「Word Embedding」
Word Embedding在Pytorch中通常用nn.Embedding实现。
class Embeddings(nn.Module):
"""
类的初始化
:param d_model: 词向量维度,512
:param vocab: 当前语言的词表大小
"""
def __init__(self, d_model, vocab):
super(Embeddings, self).__init__()