GPT-2是基于海量数据集上训练的基于Transformer的巨大模型。本文探索GPT-2模型架构,重点阐述其中关键的自注意力(self-attention)层。
Part1 GPT2和语言模型
GPT应用与语言模型上理解为根据前面的词推理出后一个要写的词。
GPT各版本模型 | 参数量 |
---|---|
gpt-2 small | 117M parameters |
gpt-2 medium | 345M parameters |
gpt-2 large | 762M parameters |
gpt-2 extra large | 1,542M parameters |
读者可以用DEMO AllenNLP 体验下GPT-2模型,根据给定输入文本输出后一个预测词的top5。
1.1使用Transformer进行语言建模
NLP中由encoder和decoder组成的语言模型,二者其实都是由Transformer模块的部分堆叠而成。这种架构在机器翻译任务中是成功证明了有效性。该任务最好方法目前也是基于encoder-decoder架构的。Transformer后续的展开工作是尝试去掉编码器或解码器,也就是只使用一套堆叠的transformer模块,然后使用海量文本,耗费大量的算力进行训练。比如GPT是只用Decoder的堆叠,BERT则主要是Encoder的堆叠,Transformer XL采用Recurrent Decoder的堆叠。
然后堆叠深度的不同,就是各个模型架构下不同模型的因素之一。GPT-2 small堆叠了12层,medium 24层,larger 36层,extra-large 48层
1.2GPT2与BERT的区别
GPT使用[Transformer解码器模块]构建的,BERT则是通过[Transformer编码器模块] 构建的。GPT类似传统语言模型,一次只输出一个单词,其效果好的原因也是每次新生成单词会接在之前生成的单词序列后面,这个序列会成为模型下一步的新输入,该机制为自回归(auto-regression),这个也是rnn模型的思想。其中TransfomerXL和XLNet本质上都是auto-regression。而Bert不是,但是Bert获得了上下文信息的能力。
1.3 Transformer模块的演进
1.3.1 编码器(encoder)模块
以下继续分析每个encoder的详细结构,在 transformer的encoder中,数据经过一个self-attention模块,得到一个加权后的特征向量Z, 这个Z就是论文公式1中的Attention.
得到 以后会传递给encoder的下一个模块, 即FeedForward Neural Network, 这个全连接由两层,第一层是
, 第二层是线性激活函数,可以表示为:
1.3.2 解码器(decoder)模块
Decoder模块和encoder不同地方在于Decoder中多了一个Encoder-Decoder Attention, 两个Attention分别用于计算输入和输出的权值:
① Self-attention: 当前翻译和已经翻译的前文之间的关系;
② Encoder-Decoder Attention: 当前翻译和编码的特征向量之间的关系。
(以上为Transformer的主要框架,后续会逐个介绍。)
1.3.3 PS:
关于GPT2中Masked self-attention 可以参考此篇文章介绍 图解GPT2 attention
Part2 自注意力(self-attention)
Self-Attention是Transformer最核心的内容,然而论文作者没有详细解释,以下补充和介绍细节。其核心思想是为每个单词学习一个权重,例如以下例子中,我们判断it 代指内容:
The animal don't cross the street because it was too tired.
通过加权得到类似图8的加权情况。
在self-attention中,每个单词有3个不同的向量,分别是Query向量(), Key向量()和Value向量(V), 长度都是64,通过三个不同的权值矩阵由向量乘以这三个不同的矩阵, , 得到,其中三个矩阵的尺寸都是相同的,都是 。
具体计算如上图,以下为总结的Attention的计算方法,整个过程可以分成6步:
- 输入为词嵌入向量;
- 根据词嵌入向量计算到
,
,
三个向量;
- 为每个向量计算一个score:
![]()
- 对score结果进行
激活函数处理;
- 对
点乘Value值
,得到加权后每个输入向量的评分
;
- 对结果进行相加,得到结果向量
,
![]()
在self-attention中最后强调的就是残差网络的short-cut结构,目的就是觉得退化问题和梯度消失。
在此自注意基础上,加入了多头注意力机制,更好的提高了self-attention的表现。
但是如果我们把所有head的表达都放在图片上,会比较难解释这个attention的关注点,如下图
在Decoder解码器中,多了一个encoder-decoder attention, 来源于解码器上个输出,和则来源于(encoder)编码器的输出, 这里的可以让decoder关注于输入序列的合适的位置。解码是一个顺序操作的过程,也就是在解码第个特征向量时,我们只能看到第及其之前的解码结果,论文中把这种multi-head attention叫做masked multi-head attention.
Part3 位置编码
到现在Transformer并没有捕捉到顺序序列能力,因此引入位置编码(Position Embedding)的特征。位置编码在词向量中加入位置信息,这样Transformer就能区分不同位置的单词了。位置编码的方法不只有这一种。需要注意的是,编码方法需要能够处理未知长度的序列
论文给出编码公式:
pos表示单词位置,i表示单词维度,位置编码实现由Google开源的算法中 get_timing_signal_id()函数 获取对应代码。
设计原因,考虑到NLP任务中除了单词绝对位置,单词相对位置也非常重要。由公式 以及
, 这表示位置
的位置向量可以表示为位置k的特征向量的变化,这个为模型捕捉单词间相对位置提供了一定的便利。
Part4 总结
优点:
(1)虽然Transformer最终也没有逃脱传统学习的套路,Transformer也只是一个全连接(或者是一维卷积)加Attention的结合体。但是其设计已经足够有创新,因为其抛弃了在NLP中最根本的RNN或者CNN并且取得了非常不错的效果,算法的设计非常精彩,值得每个深度学习的相关人员仔细研究和品位。
(2)Transformer的设计最大的带来性能提升的关键是将任意两个单词的距离是1,这对解决NLP中棘手的长期依赖问题是非常有效的。
(3)Transformer不仅仅可以应用在NLP的机器翻译领域,甚至可以不局限于NLP领域,是非常有科研潜力的一个方向。
(4)算法的并行性非常好,符合目前的硬件(主要指GPU)环境。
缺点:
(1)粗暴的抛弃RNN和CNN虽然非常炫技,但是它也使模型丧失了捕捉局部特征的能力,RNN + CNN + Transformer的结合可能会带来更好的效果。
(2)Transformer失去的位置信息其实在NLP中非常重要,而论文中在特征向量中加入Position Embedding也只是一个权宜之计,并没有改变Transformer结构上的固有缺陷