Abstract
自然语言理解包括各种不同的下游任务。尽管大型未标记的文本语料库很丰富,但用于学习这些特定任务的标号数据很少,这使得训练分辨(判别)模型比较难。
作者的解决方法就是:通过在未标号的文本语料库进行语言模型,然后在有标号的数据上对每个特定任务进行分辨性微调。
和以前的方法相比,在微调的时候,构造跟任务相关的输入,从而使得我们只需要很少地改动模型架构就行了。
1 Introduction
怎样利用好无监督的文本,即未标号的数据。以无监督的方式学习良好的表示也可以显着提高性能,当时最成功的模型还是word embedding。
然而,从未标记的文本中利用更多的单词级信息有两个困难。
- 在文本表示中用什么类型的优化目标函数是最有效的
- 怎样把学习到的文本表示传递到下游子任务上
探索使用半监督的方式,使用无监督的预训练和有监督微调组合来完成语言理解任务。
采用两阶段的训练流程:
- 首先,我们对未标号的数据使用语言建模目标来学习神经网络模型的初始参数。
- 随后,我们使用相应的有标号的数据监督微调将这些参数调整为目标任务。
作者在本文使用Transformer架构,与RNN等相比,这个模型具有更结构化的记忆来处理文本中的长期依赖关系,从而在不同任务之间实现强大的迁移性能。在迁移阶段,使用任务相关的输入表示,将结构化文本输入处理为单个连续的token序列。
评估了我们对四种语言理解任务的方法——自然语言推理、问答、语义相似性和文本分类,并展示了结果。
2 Related Work
2.1 Semi-supervised learning for NLP
在没有标号的数据上进行无监督训练
2.2 Unsupervised pre-training
在有标号的数据上进行有监督的微调
2.3 Auxiliary training objectives
怎样使用多个目标函数
3 Framework
gpt的模型框架取自原生的transformer的decoder模型,但是由于没有encoder的存在,和transformerdecoder的内容还是有一些不同的,少了一个multi-head attention层。
其架构主要是4层
- masked attention
- layernorm
- MLP
-
layernorm
从模型展示的的层数如下
GPT1代码展示层数
第一阶段是在大型文本语料库上学习高容量语言模型。接下来是微调阶段,我们将模型调整为具有标记数据的判别任务。
3.1 Unsupervised pre-training
给定无监督语料库token,我们使用标准语言建模目标函数来最大化以下似然估计:
其中 k 是上下文窗口的大小,条件概率 P 使用参数为 Θ 的神经网络进行建模。这些参数是使用随机梯度下降训练的。给定k和Θ,目标函数是每个i的概率相乘,由于这里是取对数,就变成了相加,从0一直到最后。即L1为第一个目标函数。
从神经网络的角度来看,k就是输入序列的长度,k越大,网络看到的文本越长,模型越复杂。
本文使用的是Transformer的Decoder,因为只能看到前面的信息,而encoder会看到所有的信息包括前面和后面的,所以gpt只能使用decoder来进行训练
是token的上下文向量,n 是层数(transformer块的个数),We是token的嵌入矩阵,Wp 是位置嵌入矩阵。公式解释为:上下文向量对应的embedding加上位置向量矩阵得到h0,hl代表对h0经过n个transformer块,最后一层的h_n 和We的转置进行相乘,再进行softmax得到概率分布。
3.2 Supervised fine-tuning
在使用公式 1 中的目标函数训练模型后,我们将上面模型的参数调整为监督目标任务。我们假设一个标号数据集 C,其中每个实例由一系列输入tokens组成,以及一个标签 y。输入通过我们的预训练模型以获得最终 transformer 块的
,即最后一层最后一个token对应的向量表示,然后将其输入到带有参数 Wy 的附加线性输出层中以预测 y:
这为我们提供了以下最大化目标函数:
在上面所有带标号的序列对,把x1到xm输入进去,计算真实标号的概率,最大化这个概率。
并且额外发现:把L1目标函数加入和L2一起作为目标函数微调,有助提升模型的泛化性能,并且能加速收敛
λ是可以调的超参数。
总的来说,我们在微调期间唯一需要的额外参数是 Wy 和分隔符token的embedding。
3.3 Task-specific input transformations
注意图中虽然写的start、extract、delim,但是在实际上是不能这么加这些单词的,因为这些词可能在文本中出现,这三个token必须是特殊token,不能和模型词表里的词一样,否则模型就会混淆了。
- 分类任务
在需要分类的文本前面和后面加上start 和 extract两个特殊token,然后放入transformer,获得最后一层的extract对应的向量表示,接入线性层做线性变换,最后进行softmax得到相应的概率分布。训练的 - 蕴含
任务解释是,给定一个前提,再给你一个假设,问你前面的前提是否蕴含后面的假设。可以是支持这个假设、不支持这个假设以及无关中立,是一个三分类的问题。
简单来说就是给你两段文本做一个三分类问题。跟前面的分类问题也是相似的一个操作方式。 - 相似
对于相似性任务,被比较的两个句子没有固有的顺序,即A相似于B,B也相似于A。因此在这里构造了两个序列,并独立处理每个序列以产生两个序列表示 hm,这两个序列最后的表示按元素相加,再进入线性层,得到是相似还是不是相似的二分类问题。 - 问答和常识推理
对于这些任务,我们得到了一个上下文文档 z、一个问题 q 和一组可能的答案集合{ak} 。我们将文档上下文z和问题q与每个可能的答案连接起来,在两者之间添加一个分隔符标记以获得 [z;q;$;ak]。构造多个序列,这些序列中的每一个都使用我们的模型独立处理,输出大小为1,也就是每个序列算一个标量。然后通过 softmax 层进行归一化,以产生可能答案的输出分布。
4 Experiment
4.1 Setup
Unsupervised pre-training
dataset:BooksCorpus dataset for training the language model,包含来自各种类型的 7,000 本独特的未出版书籍。
Model specifications
12层的 decoder-only transformer with masked self-attention heads
(768 dimensional states and 12 heads)
对于位置前馈网络(MLP),我们使用了 3072 维内部状态(768 * 4),dk = 64(768/12 = 64)
(ps:原生的transformer是512维,dff = 2048,head是8个,dk = 512/8 = 64)
优化器:Adam
学习率
学习率设置: 最大是2.5e-4.
学习率设置策略:线性升温余弦退火策略。前2000步从0线性升温到2.5e-4,后面使用余弦函数退火到0,让学习率随时间按余弦曲线平滑衰减。
为什么需要学习率调度?
固定学习率的训练存在明显缺陷:
- 初始学习率过大会导致模型震荡,难以收敛;
- 后期学习率过小会导致收敛速度缓慢,甚至陷入局部最优。
学习率调度的核心思想是:在训练过程中动态调整学习率—— 前期用较大的学习率快速探索参数空间,后期用较小的学习率精细优化。
余弦退火公式为:
其中:η t是第t步的学习率,η{min}最小学习率(通常是0),η{max}最大学习率,一般都是手动设置的,T_t当前步数,T{max}单个周期总步数。
整个学习率线性升温和余弦退火在gpt1的公式如下
分词器:bytepair encoding (BPE)
dropouts with a rate of 0.1
L2 regularization:w = 0.01
activation function:Gaussian Error Linear Unit (GELU)
positional embedding:learned position embeddings
Fine-tuning details
dropout to the classifier with a rate of 0.1
learning rate of 6.25e-5 and a batchsize of 32.
3 epochs
linear learning rate decay schedule with warmup over 0.2% of training.
λ = 0.5, 微调的目标函数是L2 + λL1
4.2 Supervised fine-tuning
介绍了在几个任务上的实验结果