有任何的书写错误、排版错误、概念错误等,希望大家包含指正。
在阅读本篇之前建议先学习:
【自然语言处理】Seq2Seq 讲解
【自然语言处理】Attention 讲解
【自然语言处理】ELMo 讲解
【自然语言处理】Transformer 讲解
对于 GPT 系列模型,重点在于理解思想,复现难度较大,且工程细节较多。
GPT 的论文作者没有给自己的模型起名为 GPT,这个名字来自于之后的学者。这也是论文插图中应该是 GPT 模型的地方都是用 Transformer 代替的原因。
根据发布时间和引用量可以看出,Transformer 无疑是 GPT 系列模型和 BERT 模型的技术基石。根据下面的讲解,我们将知道 GPT 仅使用 Transformer 的解码器,采用预训练与微调的方式进行训练;受此启发,BERT 的作者在一两个月的时间内就把 BERT 模型实验跑通了,并且发现效果比较理想,最后也就有了这篇经典的论文。其实,当我们了解了 GPT 和 BERT 之后,不难发现 BERT 作者大量借鉴了 GPT 模型的思想,比如 GPT 和 BERT 的主要模块都来自 Transformer,一个是解码器,一个是编码器;都采用预训练与微调的方法;都向输入中添加特殊符号等等。当然,这并不是说 BERT 没有创新性,甚至其影响力远远超过 GPT。
在详细介绍 GPT 系列模型之前,我们先简单对比一下这三个模型。三者的模型结构大同小异,都是仅对 Transformer 的解码器进行微小的调整。主要区别在于模型大小和训练方式的不同。
GPT:主要采用 BookCorpus 数据集来训练语言模型,另外可供选择的数据集是 Word Benchmark,总大小约 5GB。GPT 的模型参数总量与 BERTbase 近似,约为 1.1 亿。其训练思想与 BERT 一致,预训练加与特定下游任务相关的微调。只在少数下游任务上效果相对理想。
GPT-2:从网上收集了 40GB 的 WebText 数据集,该数据集包含 800 篇 Reddit 高赞文章,由于 Reddit 文章涉及各个领域,因此既保证了数据质量和数量,又保证了数据的多样性,训练出泛化能力更强的 GPT-2 模型。GPT-2 的模型参数总量为 15 亿,训练庞大的 GPT-2 模型耗费了 OpenAI 公司非常多资金,这也是 GPT-2 引用率不高的原因之一,但是,巨大的投入也带来比较理想的效果。GPT-2 的庞大性使得其无法在微调阶段不断更新模型参数,因为每次更新模型参数都将带来了巨大的成本消耗,因此放弃了微调方法,换成完全无监督的 Zero-shot 方法。
GPT-3:GPT-3 模型参数总量达到了惊人的 1750 亿,数据集更是高达 45TB,单单是一个 GPT-3 模型就可能需要容量为 700GB 的硬盘来存储。海量的数据来自五个不同的语料库:Common Crawl,WebText2,Books1,Books2 和 Wikipedia,每个语料库都有不同的权重,对高质量的数据集进行更频繁的采样。GPT-3 采用 Few-shot,而不是 Zero-shot,使得模型的效果进一步提升,而且即使模型参数达到 1750 亿,效果仍然呈上升趋势。另外,在许多非常困难的下游任务上,比如撰写人类难以分辨的文章,甚至是编程,都有着非常惊艳的表现。
GPT 模型由与 Transformer 的编码器结构一致的部件堆叠而成,以解码器的机制运行。习惯上,我们会说:GPT 模型由多层 Transformer 解码器堆叠而成。模型结构如图 1 1 1 所示。
图 1 GPT 模型框架
与 BERT 相比,GPT 的输入仅由词元嵌入和位置嵌入相加得到;与 Transformer 相比,GPT 的位置嵌入不再由正余弦函数给出,而是通过训练学习。
GPT 训练分为两个阶段:第一个阶段是预训练阶段,主要利用大型语料库完成非监督学习;第二个阶段是微调,针对特定任务在相应的数据集中进行监督学习。
GPT 的预训练过程本质上是自回归语言模型的训练过程,这与 Transformer 解码器的训练一致。假设某个语料的词元序列为 U = { u 1 , … , u n } \mathcal U=\{u_1,\dots, u_n\} U={u1,…,un},GPT 的预训练目标是最大化 L 1 ( U ) L_1(\mathcal U) L1(U)
L 1 ( U ) = ∑ i log P ( u i ∣ u i − k , … , u i − 1 ; Θ ) L_1(\mathcal U) = \sum_i \log P(u_i\mid u_{i-k}, \dots, u_{i-1};\Theta) L1(U)=i∑logP(ui∣ui−k,…,ui−1;Θ)
其中, k k k 为上下文窗口大小, P ( ⋅ ) P(·) P(⋅) 为由神经网络给出的条件概率, Θ \Theta Θ 为神经网络的参数。在代码实现时,窗口大小由 Sequence Mask 控制。
条件概率的具体计算过程描述如下。假设预测出的第 i i i 个位置的词元是 u u u,其之前 k k k 个位置的词元为 U = ( u − k , … , u − 1 ) U = (u_{-k}, \dots, u_{-1}) U=(u−k,…,u−1),简记 P ( u ∣ u − k , … , u − 1 ) P(u\mid u_{-k},\dots, u_{-1}) P(u∣u−k,…,u−1) 为 P ( u ) P(u) P(u)。将词元嵌入和位置嵌入的加和输入到 GPT 模型(多层 Transformer 解码器)中,经过线性映射和 Softmax 得到输出:
h 0 = U W e + W p h l = t r a n s f o r m e r _ b l o c k ( h l − 1 ) ∀ l ∈ [ 1 , N ] P ( u ) = s o f t m a x ( h N W e T ) \begin{array}{c} h_0 = UW_e+W_p \\ h_l = {\rm transformer\_block}(h_{l-1}) & ∀ \;l\in [1, N] \\ P(u) = {\rm softmax}(h_NW_e^T) \end{array} h0=UWe+Wphl=transformer_block(hl−1)P(u)=softmax(hNWeT)∀l∈[1,N]
其中, N N N 为解码器个数, W e W_e We 为词元嵌入矩阵, W p W_p Wp 为位置嵌入矩阵, h l h_l hl 为第 l l l 层解码器在第 i i i 个位置的输出向量。可见,训练模型本质上是在学习条件概率分布。
“自回归语言模型”、“Transformer 解码部件”和“以条件概率为目标函数”三部分同时出现在了 GPT 中并不是意外。
三者的关系可以通俗地描述为:应用自回归语言模型是与 Transformer 解码部件的结构相匹配的最佳选择;Transformer 解码部件采用 Sequence Mask 的运行方式决定了自回归模型的必然性。以条件概率为目标函数已经在 Transformer 中出现过,只不过没有显式地说明,Transformer 的目标函数本质上是 ∑ i f ( P ( u i ∣ u 1 , … , u i − 1 ) ) \sum_i f(P(u_i\mid u_{1},\dots, u_{i-1})) ∑if(P(ui∣u1,…,ui−1)), f ( ⋅ ) f(·) f(⋅) 的选取与具体的代码有关,不详细展开讲解。另外,自回归语言模型的定义很自然地让人们想到以条件概率为目标函数。
假设有标签的数据集 C \mathcal C C 中每个样本包含一个句子 X = { x 1 , … , x m } X=\{x^1,\dots, x^m\} X={x1,…,xm} 和对应的标签 y y y。微调阶段,将 X X X 输入到完成预训练的模型中,获得最后一层解码器在最后一个位置的输出向量 h N m h_N^m hNm,将其输入到一个额外的线性层来预测标签 y y y:
P ( y ∣ x 1 , … , x m ) = s o f t m a x ( h N m W y ) P(y\mid x^1,\dots, x^m) = {\rm softmax}(h^m_NW_y) P(y∣x1,…,xm)=softmax(hNmWy)
我们认为最后一个位置的输出向量蕴含了整个句子的语义信息。GPT 微调目标是最大化 L 2 ( C ) L_2(\mathcal C) L2(C)
L 2 ( C ) = ∑ x , y l o g P ( y ∣ x 1 , … , x m ) L_2(\mathcal C) = \sum_{x,y}log P(y\mid x^1,\dots, x^m) L2(C)=x,y∑logP(y∣x1,…,xm)
另外,论文作者发现将自回归语言模型作为微调的辅助目标有助于提高模型的泛化能力、加快模型收敛。因此,一般使用两个损失函数的加权作为微调的损失函数:
L 3 ( C ) = L 2 ( C ) + λ L 1 ( C ) L_3(\mathcal C) = L_2(\mathcal C) + \lambda L_1(\mathcal C) L3(C)=L2(C)+λL1(C)
注意,GPT 在预训练阶段不会向数据中添加特殊符号,但是当涉及特定下游任务时,不同任务的输入格式有所不同(比如单语句分类和多语句分类),因此在微调时需要添加特殊符号
、
和
,论文作者认为模型可以通过微调理解特殊符号的含义,所以不需要在预训练时引入特殊符号。三个符号分别插入到整个输入的起始位置、两段语句的中间以及整个输入的结尾位置。可见,这与 BERT 是不同的,BERT 在预训练阶段和微调阶段均向数据中添加了特殊符号。
论文作者为四个经典下游任务设计具体的处理方式,并在这些任务上对 GPT 进行评估。这四个经典的下游任务为,文本分类(Text Classification)、文本蕴涵(Textual entailment)、文本相似(Textual similarity)和问答与常识推理(Question Answering and Commonsense Reasoning)。与命名实体识别等任务不同,这些任务只要提取语句级语义向量即可,认为特殊符号
对应的输出向量包含了任务需要的语义信息。
**文本分类:**文本分类任务的微调过程如上所述,即标准微调过程。GPT 以添加特殊符号
和
的词元序列作为输入,将输出向量输入到线性映射层后 Softmax 分类。
**文本蕴涵:**文本蕴含的判断是非对称性句子关系任务,即 premise 只能作为第一段语句输入,hypothesis 只能作为第二段输入,不可交换顺序,两段语句由特殊符号
,判断是否能从 premise 得到 hypothesis。处理方式与文本分类相同。
**文本相似:**文本相似性任务是对称性句子关系任务,即交换两段语句的输入顺序,不影响二者语义相似性的判断。为了反映对称性,论文作者分别向 GPT 模型中输入两种顺序的序列以生成两个输出向量,两个向量相加后输入到线性映射层用于分类。
**问答与常识推理:**将文章 z z z,问题 q q q 和一组可能的答案 a k {a_k} ak 分别拼接,得到 [ z ; q ; < D E L I M > ; a k ] [z;q;\left<{\rm DELIM}\right>;a_k] [z;q;⟨DELIM⟩;ak]。GPT 模型独立处理每个序列,通过 Softmax 产生分布。
四个任务的处理如图 2 2 2 所示。
图 2 不同下游任务微调的输入转换
GPT-2 模型很大程度上遵循了 GPT 模型。在模型机制上,完全延续 GPT;在模型结构上,仅仅对 GPT 进行了微小调整。具体来说,将层规范化模块移至每个子模块的输入处,类似于预激活残差网络,并在最后一个自注意力模块后添加额外的层规范化模块。另外,考虑到残差会随着网络的加深而积累,采用了一种改进的初始化方法,初始化时将剩余层的权重按 1 / N 1/\sqrt{N} 1/N 的因子进行缩放, N N N 是剩余层的数量。在细节上,GPT-2 将词汇量扩大到 50,257,上下文窗口大小从 512 增加到 1024,batchsize 扩大至 512。
论文没有给出具体的模型图,具体细节不得而知。
GPT-2 的创新点在于抛弃了 GPT 微调的想法,完全使用 Zero-shot。我们知道,要想模型具备处理多个下游任务的能力,需要在微调阶段使用下游任务对应的数据集对模型进行监督训练。可是,仅仅是获取一个下游任务的数据集就已经需要消耗大量的人力资源,更不要说为模型构建多个任务对应的数据集了。同时,考虑到如果为模型提供充足的无标签语料,那么模型应该可以学会推断和执行自然语言序列中演示的任务,而不是必须依赖于有标签的样本。基于这两点原因,GPT-2 采用了非常大的数据集、非常多的模型参数,彻底抛弃有监督学习,使用无监督且不存在参数更新的 Zero-shot。具体来说,采用大量数据对 GPT-2 模型进行预训练,以自然语言的形式向模型输入任务目标和处理对象,模型便能够理解任务需求并按要求输出。可以想象,有监督训练只能保证模型可以处理学习到的任务,GPT-2 这样的无监督模型的泛化能力明显更强大,不过如果数据不够充足,无监督模型在某些任务上训练出的效果不会比监督训练出色。
这样的 GPT-2 无疑更符合我们对真正的人工智能的想象。
还有一点小细节。我们知道 GPT-2 是自回归语言模型,它可能会出现类似于持续点击输入法推荐的第一个单词,会陷入推荐同一个词的循环中,只有点击第二个或第三个推荐词才会跳出这样的循环,如图 3 3 3 所示。因此,GPT-2 有一个叫 top-k
的参数,模型会从概率前 k k k 大的单词中抽样选取下一个词。显然,之前讨论的是 top-k=1
的模型。
图 3 AllenAI GPT-2 Explorer
GPT-2 采用 BPE subword 进行分词以构建词汇表,具体算法不在这里介绍,另开一篇博客。
GPT-3 模型是结构更加庞大、采用 Few-shot 的 GPT-2,这使得它在许多任务上(如翻译、问答、填空等)都具有出众的效果。作者在 GPT-3 的论文中再次说明不使用微调的原因:微调效果好不能代表模型的泛化能力好,本身大模型已经经过了海量数据的预训练,如果再用小数据和小学习率进行微调,很容易出现过拟合的现象。作者认为基于海量数据训练的巨大模型已经具备了元学习(Meta Learning)的能力,即学会了学习、学会了推理。
相较于 GPT-2,GPT-3 不再采用极端的 Zero-shot,而是采用 Few-shot。论文中作者通过上下文学习(In-context Learning)的方式帮助模型快速推理,上下文学习总共三种:Zero-shot、One-shot 和 Few-shot。这三种上下文学习方式都不存在梯度计算,因此不会对模型的参数进行更新。顾名思义,Zero-shot 是指用模型进行推断时,仅输入对任务的自然语言描述以及操作序列;One-shot 和 Few-shot 是指除了输入任务描述和操作序列外,还要分别向模型输入一个和多个带标签的样本。如图 4 4 4 所示。
图 4 In-context Learning
ELMo、BERT 和 GPT 都解决了早期的 Word2Vec 等预训练模型无法处理一词多义的问题。
整体上来说,ELMo 采用双向 LSTM 提取特征,而 BERT 和 GPT 均采用 Transformer 模块来提取特征,其中 BERT 使用的是编码器,GPT 使用的是解码器。很多 NLP 任务都表明 Transformer 提取特征的能力强于 LSTM,LSTM 依然具有长期遗忘的特点。
三者中,只有 GPT 采用单向语言模型,ELMo 和 BERT 都采用双向语言模型。严谨来说,ELMo 实际上只是将不同方向语言模型提取的特征的拼接,这种拼接融合特征的方法显然没有 BERT 一体化特征融合的方法有效。
在训练方法上,三者都包括预训练过程。ELMO 采用并非真正意义上的微调,常将 ELMo 提取的特征作为下游任务的附加输入;而 BERT 和 GPT 主要采用微调的方法使模型适应下游任务。
相较于 BERT,作为语言模型的 GPT 能力明显更加强大。BERT 采用 Transformer 编码器使得其在语言理解的任务上具有更好的适用性,但是无法处理类似机器翻译和文章续写的生成式任务,在这类任务上 GPT 的解码器结构更有优势,带来了更多的可能。
[1] Radford A, Narasimhan K, Salimans T, et al. Improving language understanding by generative pre-training[J]. 2018.
[2] Radford A, Wu J, Child R, et al. Language models are unsupervised multitask learners[J]. OpenAI blog, 2019, 1(8): 9.
[3] Brown T, Mann B, Ryder N, et al. Language models are few-shot learners[J]. Advances in neural information processing systems, 2020, 33: 1877-1901.
[4] Vaswani A, Shazeer N, Parmar N, et al. Attention is all you need[J]. Advances in neural information processing systems, 2017, 30.
[5] Devlin J, Chang M W, Lee K, et al. Bert: Pre-training of deep bidirectional transformers for language understanding[J]. arXiv preprint arXiv:1810.04805, 2018.
[6] 《深入浅出 Embedding》吴茂贵等著
[7] GPT,GPT-2,GPT-3 论文精读【论文精读】- bilibili
[8] 李宏毅-ELMO, BERT, GPT讲解 - bilibili
[9] GPT综述-各模型之间的对比 - 知乎
[10] GPT系列模型详解 - CSDN
[11] GPT2模型详解 - CSDN
[12] The Illustrated GPT-2 (Visualizing Transformer Language Models) - jalammar.github.io
[13] 零次学习(Zero-Shot Learning)入门 - 知乎
[14] tokenizers:BPE算法 - CSDN
[15] 深入理解NLP Subword算法:BPE、WordPiece、ULM - 知乎
[16] BERT, GPT, ELMo模型对比 - CSDN