Improving Language Understanding by Generative Pre-Training
文章目录
- Improving Language Understanding by Generative Pre-Training
- Abstract
- 1 Introduction
- 2 Related Work
- Semi-supervised learning for NLP
- Unsupervised pre-training
- Auxiliary training objectives
- 3 Framework
- 3.1 Unsupervised pre-training
- 3.2 Supervised fine-tuning
- 3.3 Task-specific input transformations
- 4 Experiments
- 4.1 Setup
- Unsupervised pre-training
- 数据集
- 模型细节
- 微调细节
- 4.2 Supervised fine-tuning
- Natural Language Inference
- Question answering and commonsense reasoning
- Semantic Similarity
- Classification
- 5 Analysis
- Impact of number of layers transferred
- Zero-shot Behaviors
- Ablation studies
- 6 Conclusion
- 补充部分
- 1. 遍历式方法 (traversal-style approach)
- 2. 字节对编码 (Byte Pair Encoding)
- Sub-word-based tokenization
- Encoding and Decoding
- Final Part
- 3. 高斯误差线性单元 (Gaussian Error Linear Unit, GELU)
- 15
Abstract
背景:自然语言理解包括广泛的不同任务,如文本蕴涵、QA问答、语义相似性评估和文档分类。
问题:尽管大型未标记文本语料库(corpora)非常丰富;但用于学习特定任务的标记数据却很少,这使得采用传统的有监督深度学习方法训练得到的模型表现较差。
解决:通过对多样未标记文本语料库进行语言模型的生成式预训练,再对每个特定任务进行针对性微调,可以在这些具体特定任务上具有良好表现。这也说明在早期 GPT 中还是强调 “预训练+微调” 范式的,还没有涉及到提示学习这方面的内容。
优势:与以前的方法相比,GPT-1 在微调过程中利用有任务针对性(task-aware)的输入信息变换来实现有效的下游任务迁移,同时只需要对模型架构进行极小的更改。
实验:通用任务无关的预训练模型的性能优于经过针对性训练的模型,这些针对性训练的模型专门为每个任务设计独特的网络架构。在所研究的 12 个任务中,有 9 个任务显著超越了现有模型,达到 SOTA (2018年)。在常识推理(Stories Cloze Test)上实现了8.9%的绝对提升;在问题回答(RACE)上实现了5.7%的绝对提升;在文本隐含题(MultiNLI)上实现了1.5%的绝对提升。
1 Introduction
模型具有从原始文本中有效学习的能力,对于减轻自然语言处理中对有监督学习的依赖至关重要。大多数深度学习方法都需要大量的手动标记数据,这是耗时和昂贵的,这限制了这些深度学习方法在许多缺乏注释资源的领域中的适用性。无监督范式的学习相对更好,经过无监督范式的学习模型可以利用未标记文本中的语言信息,还可以学习良好的表征显著提高性能。作者给出的无监督范式的例子就是预训练词嵌入,它提升了多个NLP任务能力。
从未标记的文本中利用更多的单词级信息是具有挑战性的,主要有两个原因。首先,还不清楚哪种类型的优化目标在学习对特定任务迁移有效的文本表征时最有效(当时调研是:语言模型、机器翻译和话语连贯性)。其次,对于将这些学习到的表征迁移到目标任务中的最有效的方法是什么(当时调研是:修改模型结构、使用复杂学习方案以及增加辅助学习目标),目前还没有达成共识。
本文中探索了一种半监督的语言理解任务方法,使用无监督预训练和监督微调,目标是学习一种普遍的文本表征,它只需要很少的调整就能适应到广泛的任务。假设存在大量的未标记文本语料库和若干手动注释的特定目标的有监督训练样本。论文设置不要求这些 目标任务 与 未标记的语料库 在相同的 任务领域 中。
论文的工作主线:采用了一个两阶段的训练程序。首先,在未标记数据上使用语言建模目标来学习神经网络模型的初始参数。随后,使用相应的有监督目标将这些参数调整为适应目标任务的参数。
接下来作者提到了模型选择:使用 Transformer 。它已经被证明在各种任务上表现出色。与循环神经网络等方案相比,这个模型提供了更结构化的记忆/文本处理能力,用于处理文本中的长距离依赖关系,从而能在下游不同任务中表现出鲁棒的迁移性能。在下游特定任务迁移过程中,源于遍历式方法,使用任务特定的的输入适应,该方法将结构化文本的输入处理为单个连续的标记序列。这些适应性处理能有效地对预训练模型架构进行最小的调整。
2 Related Work
Semi-supervised learning for NLP
论文的工作广泛地属于自然语言处理的半监督学习的范畴。最早的方法使用未标记数据来计算单词级或短语级统计数据,然后将其作为有监督学习模型的特征,例如词嵌入模型。这些方法主要是传递单词级的信息,而作者的目标是捕获更高级别的语义。更高级别的语义信息也有人在研究,也出现了从未标记的数据中学习和利用更多的词级语义的方法。短语级或句子级嵌入可以使用未标记语料库进行训练,已被用于将文本编码为各种目标任务的向量表征。
Unsupervised pre-training
无监督预训练是半监督学习的一种特殊情况,其目标是找到一个好的初始化点,而不是修改有监督的学习的目标。预训练作为一种正则化方案,使深度神经网络能够更好的泛化。无监督预训练方法已被用于帮助训练深度神经网络的各种特定任务,如图像分类、语音识别、实体消歧和机器翻译。
作者的工作主线是无标记的语料库使用语言建模目标进行预训练+下游任务有标签样本使用监督目标进行微调。之前也有学者做出相关的工作,但是这些学者对 LSTM 模型的使用无监督预训练,将其预测能力限制在较短的句子长度范围内。作者使用 Transformer 架构很好地处理文本中的长距离依赖关系,在自然语言推理,释义检测和故事完成等比较考验长距离依赖的任务实验中展现了高效性。
其他方法使用预训练的语言或机器翻译模型的表征信息作为特定任务有监督学习训练模型的辅助特征。这种方法的侧重点还是在特定任务的从 0 开始的有监督式训练,这涉及到每个单独的目标任务的大量新的参数的处理。而作者的 GPT-1 只需要对模型体系结构进行最小的更改。
Auxiliary training objectives
添加辅助无监督训练的目标是半监督学习的另一种形式。早期的工作使用了多样的辅助 NLP 任务,如 POS 标记、分块、命名实体识别和语言建模来改进语义角色标记任务,也有工作在特定任务的目标中添加了一个辅助的语言建模目标。作者实验也尝试使用了一个辅助目标,但结果表明无监督的预训练已经学习到了与目标任务相关的几个语言方面的潜在知识。
3 Framework
3.1 Unsupervised pre-training
给定一个无监督标签的 token 形式的语料库 U = { u 1 , ⋯ , u n } U = \{u_1,\cdots ,u_{n}\} U={u1,⋯,un} 使用一个标准的语言建模目标来最大化以下似然函数:
L 1 ( U ) = ∑ i log P ( u i ∣ u i − 1 , ⋯ , u i − k ; Θ ) (1) L_{1}(U)=\sum\limits_{i}\log P(u_{i}|u_{i-1},\cdots,u_{i-k};\Theta) \tag{1} L1(U)=i∑logP(ui∣ui−1,⋯,ui−k;Θ)(1)
其中, k k k 为上下文窗口(context window)的大小,条件概率 P P P 使用参数为 Θ \Theta Θ 的神经网络建模(也就是搭建一个参数为 Θ \Theta Θ 的神经网络,输入为 { u i − 1 , ⋯ , u i − k } \{u_{i-1},\cdots,u_{i-k}\} {ui−1,⋯,ui−k} 的 token 序列,输出是 u i u_{i} ui )。参数为 Θ \Theta Θ 的神经网络采用随机梯度下降法进行训练。
GPT-1 是一个多层 Transformer 解码器的语言模型,这是原来 Transformer 的一个变体。该模型对输入上下文 token 序列进行多端自注意力计算,然后进行位置级 FFNN 计算,以产生目标 token 在总 token 列表上的输出分布。
{ h 0 = U W e + W p MaskedAttention ( Q , K , V ) = softmax ( Mask ( Q K T d k ) ) V h i = transformer block ( h i − 1 ) , ∀ i = 1 ⋯ n P ( U ) = softmax ( h n W e T ) (2) \begin{cases} h_{0} &= UW_{e}+W_{p} \\ \text{MaskedAttention}(Q,K,V) &= \text{softmax}\big(\text{Mask}(\frac{QK^{T}}{\sqrt{d_{k}}})\big)V \\ h_{i} &= \text{transformer block}(h_{i-1}),\forall i=1\cdots n \\ P(U) &= \text{softmax}(h_{n}W_{e}^{T}) \\ \end{cases} \tag{2} ⎩ ⎨ ⎧h0MaskedAttention(Q,K,V)hiP(U)=UWe+Wp=softmax(Mask(dkQKT))V=transformer block(hi−1),∀i=1⋯n=softmax(hnWeT)(2)
其中 U ⃗ = ( u : − k , ⋯ , u : − 1 ) \vec{U}= (u_{:−k},\cdots, u_{:−1}) U=(u:−k,⋯,u:−1) 是 token 的上下文向量, n n n 是层数
W e W_{e} We 是 token 的嵌入矩阵, W p W_{p} Wp 是位置嵌入矩阵(位置编码)。
3.2 Supervised fine-tuning
After training the model with the objective in ( 1 ) (1) (1), we adapt the parameters to the supervised target task. We assume a labeled dataset C C C, where each instance consists of a sequence of input tokens, x 1 , ⋯ , x m x_1,\cdots ,x_m x1,⋯,xm along with a label y y y. The inputs are passed through our pre-trained model to obtain the final transformer block’s activation h l m h^{m}_{l} hlm , which is then fed into an added linear output layer with parameters W y W_y Wy to predict y y y.
在 ( 1 ) (1) (1) 的目标预训练模型后,根据下游特定任务调整参数。假设一个有标签的数据集 C C C,其中每个实例由一系列输入token x 1 , ⋯ , x m x_1,\cdots ,x_m x1,⋯,xm 以及标签 y y y 组成。输入 token 输入到预先训练的模型,以获得最终 transformer 解码器块的激活函数输出 h l m h^{m}_{l} hlm ,然后将 h l m h^{m}_{l} hlm 输入到添加的带有参数 W y W_y Wy 的线性输出层以预测 y y y。
P ( y ∣ x 1 , ⋯ , x m ) = softmax ( h l m W y ) (3) P(y|x_{1},\cdots,x_{m})=\text{softmax}(h_{l}^{m}W_{y}) \tag{3} P(y∣x1,⋯,xm)=softmax(hlmWy)(3)
这就衍生出了监督学习阶段的训练目标:
L 2 ( C ) = ∑ ( x 1 , ⋯ , x m ; y ) log P ( y ∣ x 1 , ⋯ , x m ) (4) L_{2}(C)=\sum\limits_{(x_{1},\cdots,x_{m};y)}\log P(y|x_{1},\cdots,x_{m}) \tag{4} L2(C)=(x1,⋯,xm;y)∑logP(y∣x1,⋯,xm)(4)
此外作者发现,将语言建模目标作为微调的辅助目标(也就是额外增加类似 ( 1 ) (1) (1) 的目标只是把 ( 1 ) (1) (1) 中的上下文向量换成标签数据集的 x 1 , ⋯ , x m x_1,\cdots ,x_m x1,⋯,xm )有助于学习、改进有监督学习下的模型泛化程度,以及加速有监督学习的收敛。感觉也强化了在下游特定数据集上的语言建模,更深入一点的想法就是将预训练的语言知识对齐到了下游特定数据集的语言知识,所以辅助目标可以加强下游本质知识的学习(自我发散一下hhhh)。
L 3 ( C ) = L 2 ( C ) + λ L 1 ( C ) (5) L_{3}(C)=L_{2}(C)+\lambda L_{1}(C) \tag{5} L3(C)=L2(C)+λL1(C)(5)
这个涉及到了一点点多目标优化方面, L 1 ( C ) L_{1}(C) L1(C) 是额外的语言建模目标,可以设置优先级程度,来评判是 “特定数据集标签学习” 优先还是 “特定数据集的语言知识学习” 优先,靠的是 λ \lambda λ 参数的调节。
总的来说,在微调过程中唯一需要的额外添加的参数是 W y W_y Wy 和分隔符标记的嵌入 W e W_{e} We 。
还要注意一点是,GPT-1 的微调过程,对特定数据集的句子是经过处理的,具体是每个句子前后都增加了特殊的 token ,以及多个句子之间的衔接 token 。这在论文的 3.3 部分提及。
3.3 Task-specific input transformations
对于一些任务,比如文本分类,可以直接微调如上所述的模型。某些其他任务,如问题回答或文本蕴含,都有结构化的输入,如:有序的句子对,或三元组文档、问题和答案。由于预训练模型是在连续的文本序列上进行训练的,所以需要进行一些修改来将其应用于这些特定的任务。
作者使用了一种遍历风格的方法,将结构化的输入转换为一个有序的序列,这样便可以在预训练过的模型中处理。这些输入转换避免了跨任务对模型结构进行大量的更改。所有的输入转换都包括添加随机初始化的开始和结束 token (<s>,<e>)
。
task name | description |
---|---|
Textual entailment | 将前提 p p p 和假设 h h h token 序列连接起来,中间有一个分隔符标记($ ) |
Similarity | 对于相似性任务,被比较的两个句子没有固有的排序。作者修改了输入序列,以包含两个可能的句子顺序(中间有一个分隔符,也就是 “前” + “后” 和 “后” + “前” ,组成两个序列),并独立处理每个序列,以生成两个序列表示 h l , 1 m h_{l,1}^{m} hl,1m 和 h l , 2 m h_{l,2}^{m} hl,2m,在输入线性输出层之前按元素添加。 |
Question Answering and Commonsense Reasoning | 对于这些任务,有一个上下文文档 z z z 、一个问题 q q q 和一组可能的答案 a k {a_k} ak 。将文档上下文、问题和每个可能的答案连接起来,在中间添加一个分隔符标记,以获得 [ z ; q ; [z;q; [z;q;$ ; a k ] ;a_k] ;ak] 。这些序列中的每一个都用单独的一个模型独立处理,然后通过一个 softmax 层进行归一化,以产生一个可能答案的输出分布。 |
4 Experiments
4.1 Setup
Unsupervised pre-training
数据集
使用 BooksCorpus 数据集来训练语言模型。它包含 7000 多本独特的未出版书籍,涵盖 冒险、奇幻和浪漫 等多种类型。它包含长段的连续文本,这使得生成模型具有长序列文本的学习条件。作者给出了不选择其他数据集的原因: the 1B Word Benchmark 在句子级就被打乱了,破坏了长序列文本的结构。GPT-1 语言模型在这个 1B Word Benchmark 上实现了非常低的 token 级别 18.4 困惑度。
模型细节
GPT-1 模型在很大程度上遵循了原始的 Transformer 工作。
训练了一个 12 层堆叠解码器的、具有多端自注意力机制的 Transformer 解码器( d m o d e l = d_{model}= dmodel= 768 维嵌入维度和 12 个注意头,如果按照 Transformer 分端但是不改变总维度的话,每个端分到 768 12 = 64 \frac{768}{12}=64 12768=64 维度的子空间)。
位置级 FFNN 中间层是 3072 维,也就是 768 → 3072 = 768 × 4 → 768 768\rightarrow 3072=768\times 4\rightarrow 768 768→3072=768×4→768 。
使用了 Adam 优化方案,最大学习率为 2.5 e − 4 2.5e^{-4} 2.5e−4 。在前 2000 次更新中,学习率从 0 线性增加,随后使用余弦函数方案退火到 0 ,根据原始 Transformer 的论文, w a r m u p _ s t e p = 2000 warmup\_step=2000 warmup_step=2000 。
在 64 个随机采样的、包含 512 个 token 的连续序列的小批量上训练 100 个 epoch。
layernorm 归一化处理在整个模型中被广泛使用,所以需要一个简单的服从 N ( 0 , 0.02 ) N(0,0.02) N(0,0.02) 正态分布的权重初始化。
使用了一个包含 40000 个的字节对编码(Byte Pair Encoding)词汇表。将嵌入和注意力机制用 dropout=0.1 进行正则化。对所有非偏置参数或权值采用了 w = 0.01 w=0.01 w=0.01 的 L2 正则化。
对于激活函数,使用高斯误差线性单元(Gaussian Error Linear Unit, GELU)。
使用了学习到的位置嵌入,而不是在原始工作中提出的正弦版本。
使用 ftfy 库来清理 BooksCorpus 数据集中的原始文本,标准化一些标点符号和空格,使用 spaCy 标记器获得 token 。
微调细节
除非特别指定,否则将重用来自无监督的预训练的超参数设置。
对于分类任务以 dropout=0.1 正则化。对于大多数任务,使用的学习率为 6.25 e − 5 6.25e^{-5} 6.25e−5 ,批量大小为32。
模型微调 3 个 epoch 对于大多数情况下是足够的。
使用一个线性学习率衰减计划。
( 5 ) (5) (5) 中的 λ λ λ 被设置为 0.5 ,也就是用于特定任务的微调的工作优先级高于特定数据集语义理解的两倍
4.2 Supervised fine-tuning
在各种监督任务上进行实验,包括自然语言推理、问题回答、语义相似性和文本分类。其中一些任务可以作为最近发布的 GLUE 多任务基准测试的一部分使用。
Natural Language Inference
自然语言推理的任务,也称为识别文本蕴含,包括阅读一对句子,从蕴含、矛盾或中性来判断它们之间的关系。这项任务仍然具有挑战性是因为存在各种各样的现象,如词汇隐含、共引用、词汇和句法歧义。实验中对 5 个来源不同的数据集进行了评估,包括图像标题(SNLI)、转录演讲、流行小说和政府报告(MNLI)、维基百科文章(QNLI)、科学考试(SciTail)或新闻文章(RTE),括号里面都是数据集名称。
GPT-1 在 5 个数据集中的 4 个显著优于基线,在政府报告(MNLI)数据集上,达到 5%,在维基百科文章(QNLI)上达到 5.8%,在图像标题(SNLI)上达到 0.6%。这表明了 GPT-1 能够更好地推理多个句子,并处理语言歧义的各个方面。在新闻文章(RTE)上,评估一个较小的数据集(2490个例子),GPT-1 实现了 56% 的准确率,低于多任务biLSTM模型报告的 61.7% 。
Question answering and commonsense reasoning
另一个需要单句和多句推理方面的任务是回答问题。使用最近发布的 RACE 数据集,包括英语段落和中学考试的相关问题。与其他数据集如 CNN 或 SQuaD 相比,这个语料库包含了更多的推理类型问题,适合训练 GPT-1 来处理长上下文。
还对 Story Cloze Test 进行了评估,它涉及到从两个选项中选择多句故事的正确结尾。在这些任务上, GPT-1 再次显著地超过了之前的最佳结果——在 Story Cloze Test 上高出 8.9% ,在 RACE 上高达 5.7% 。这证明了 GPT-1 能够有效地处理长上下文。
Semantic Similarity
语义相似性(或释义检测)任务包括预测两个句子在语义上是否相等。挑战在于识别概念的重新措辞,理解否定和处理句法歧义。使用三个数据集来完成这个任务——从新闻来源收集的微软释义语料库(MRPC)、Quora问题对(QQP)数据集和语义文本相似度基准(STS-B)。在三个语义相似性任务中的两个任务上获得了最好的结果,在语义文本相似度基准(STS-B)上,该任务的绝对涨点为 1 分。Quora问题对上的性能增量是显著的,比单任务BiLSTM + ELMo + Attn
有 4.2% 的绝对改进。
Classification
评估了两种不同的文本分类任务。语言可接受性语料库(CoLA)包含了对一个句子是否符合语法要求的专家判断,并测试了训练模型的先天语言偏见。斯坦福情绪 Treebank(SST-2)是一项标准的二元分类任务。 GPT-1 在 CoLA 上得到了 45.4 分,比之前 35.0 的最佳结果有一个巨大的飞跃,显示了 GPT-1 所学到的先天语言偏差。 GPT-1 在 SST-2 上也达到了 91.3% 的准确率。在 GLUE 基准测试上也获得了 72.8 分的总分,这明显优于之前最好的 68.9 分。
总的来说, GPT-1 在评估的 12 个数据集中有 9 个实现了新 SOTA ,在许多情况下优于模型的集成版本。 GPT-1 在不同大小的数据集上也有良好表现,从较小的数据集,如语义文本相似度基准(STS-B)数据集( ≈ 5.7 k \approx 5.7k ≈5.7k 训练示例)到最大的一个图像标题(SNLI)数据集( ≈ 550 k \approx 550k ≈550k 训练示例)。
5 Analysis
Impact of number of layers transferred
观察了将可变数量的解码器层从无监督的预训练结果迁移到有监督的目标任务的影响。图2左半部分说明了 GPT-1 在文本隐含题(MultiNLI)数据集和 RACE 数据集上的精度性能,作为传输层数的函数。观察到标准结果是:传输嵌入提高性能,每个 Transformer 的解码器层在文本隐含题(MultiNLI)数据集上完全迁移可提供高达 9% 的好处。没有迁移层则说明是预训练模型直接用于特定数据集的推理,也有 50-60% 的效果。这表明,预先训练过的模型中的每一层都包含了用于解决目标任务的有用功能。
Zero-shot Behaviors
这部分主要是回答为什么 Transformer 的语言模型预训练是有效的。
一个假设是,底层生成式模型在微调过程中学会了执行评估的许多任务,以进一步提高其语言建模能力,并且与 LSTM 相比,Transformer 内在的更结构化的注意力记忆有助于迁移。‘
作者进一步设计了一系列启发式解决方案,使用底层生成式模型来执行任务,而无需监督微调。
结果发现:这些启发式方法的性能是稳定的,并且在训练过程中稳步增加,这表明生成式预训练语言模型支持各种任务相关功能的进一步/持续地学习,此外,LSTM 在其 zero-shot 性能上表现出更高的方差,这表明 Transformer 架构的内在偏差(自身学习到了更 meta-wise 的语言知识,有种 “以不变应万变” 的感觉,因此更加稳定)有助于迁移。
Ablation studies
作者进行了三种不同的消融研究。
首先,在微调过程中检验了没有辅助语言模型训练目标方法的性能。结果显示,辅助目标有助于自然语言理解任务和特定的 Quora 问题对(QQP)数据集。这表明,较大的数据集受益于辅助目标,但较小的数据集却没有。
其次,通过与单层 2048 单元 LSTM 进行比较来分析 Transformer 的效果。结果显示,当使用 LSTM 而不是 Transformer 时,平均分数下降了 5.6 分。LSTM 只在一个数据集——微软释义语料库(MRPC)特定数据集的性能优于 Transformer 。
最后,还比较了用 Transformer 架构直接训练的监督目标任务,没有预先训练。结果显示,训练的缺乏损害了所有任务的表现,导致与我们的完整模型相比下降了14.8%。
6 Conclusion
这篇论文引入了一个基于 Transformer 的框架,通过生成式预训练和微调,获得了一个任务无关的语言模型来实现强大的自然语言理解能力。通过在不同的语料库与长的连续文本中预训练一个语言模型获得重要的世界知识和处理长句子的能力,并成功地迁移到特定任务,如问题回答、语义相似性评估、文本蕴含和文本分类,在 12 个特定任务中的 9 个达到领先水平。
使用无监督(预)训练来提高针对性任务的性能,长期以来一直是机器学习研究的一个重要目标。作者工作表明,实现显著的性能提升确实是可能的,并提供了关于哪些模型(Transformer 还是 LSTM)和数据集(具有长期依赖关系的文本)最适合这种方法的方案。
补充部分
1. 遍历式方法 (traversal-style approach)
参考这篇博客。
For some tasks, like text classification, we can directly fine-tune the model by adding a linear+softmax layer. Other tasks, like question answering or textual entailment, have structured inputs such as ordered sentence pairs, or triplets of document, question, and answers. GPT model uses a traversal-style approach, where we convert structured inputs into an ordered sequence that our pre-trained model can process. These input transformations allow us to avoid making extensive changes to the architecture across tasks. All transformations include adding initialized start token, a delimiter to separate multiple sentence inputs and end tokens (Extract). For example, for textual entailment or question answering, the inputs are transformed as one sequence, with premise and hypothesis separated by the delimiter and surrounded by the Start and Extract tokens. We can also use multiple transformers and merge the outputs in the last layer for multiple choice tasks.
对于某些任务,比如文本分类,可以通过添加 “线性 + softmax 层” 来直接微调模型。其他任务(例如QA问答,或文本蕴涵任务)具有结构化输入,例如有序句子对或文档、问题和答案的三元组。 GPT 模型使用遍历式方法,将结构化输入转换为预训练模型可以处理的有序序列。这些输入转换能够避免迁移到不同任务时对架构进行大量更改。所有转换过程包括:添加初始化的开始标记、用于分隔多个句子输入的分隔符和结束标记。例如,对于文本蕴涵或QA问题回答,输入的多个小句子被转换为一个序列,前提和假设由分隔符分开,并由开始和提取标记包围。还可以使用多个 Transformer 并合并最后一层的输出以进行多项选择任务(有点像模型集成)。
2. 字节对编码 (Byte Pair Encoding)
参考这篇博客。
理解人类语言的主要部分之一是由 分词器(tokenizers) 发挥的。 分词(Tokenization) 算法可以是基于单词、子词或字符的。每种类型的分词器都帮助机器以不同的方式处理文本,分词器各自具有优势。
单词(word)和子词(sub-word)是语言学中常用的术语。单词是语言中最小的、能够独立使用的单位,具有独立的意义。而子词是指构成单词的更小的单元,通常是指单词中的前缀、后缀或者词根等部分。子词通常不能独立使用,需要依附在其他单词上才能发挥作用。在自然语言处理和计算机领域,子词也指的是单词的部分,常用于分词(tokenization)和词嵌入(word embedding)等任务中。总的来说,单词是语言的基本单位,而子词是构成单词的更小部分。
在这些分词器中,最流行的是基于子词的分词器。大多数 SOTA 的 NLP 模型都使用该分词器。
Sub-word-based tokenization
基于子词的 tokenization 是基于单词和基于字符(character)的 tokenization 之间的解决方案。主要思想是解决基于单词的 tokenization 存在非常大的词汇量、大量的词汇分布外的 tokenization 以及非常相似的单词的不同含义(比如 known
和 unknown
之间);以及基于字符的 tokenization 存在非常长的序列和意义不大的单个 token 所面临的问题。
基于子词的 tokenization 算法不会将频繁使用的单词分割成更小的子词。它将罕见的单词分成更小的、有意义的子词。boy
不被拆分,但 boys
被拆分为 boy
和 s
。这有助于模型了解到单词 boys
是由单词 boy
组成的,含义略有不同,但词根相同。
一些流行的子词 tokenization 算法是 WordPiece、字节对编码 (Byte Pair Encoding, BPE)、Unigram 和 SentencePiece。字节对编码用于 GPT-2、RoBERTa、XLM、FlauBERT 等语言模型。其中一些模型使用空间标记化(Space tokenization)作为 预标记化(pre-tokenization) 方法,而少数模型使用 Moses、spaCY、ftfy 提供的更高级的预标记化方法。
字节对编码 BPE 是一种简单的数据压缩算法,它将数据中最常见的一对连续字节替换为该数据中不出现的字节。它首次在 1994 年发表的文章 “A New Algorithm for Data Compression” 中被描述。
假设有需要编码压缩的数据
aaabdaaabac
。字节对aa
出现的频率最高,因此用Z
代替字节对aa
,因为Z
不会出现在原来数据中。因此,现在有了ZabdZabac
,其中Z = aa
。下一个常见的字节对是ab
,因此用Y
来替换它。现在有ZYdZYac
,其中Z = aa
,Y = ab
。剩下的唯一字节对是ac
,它只出现一次,所以不对它进行编码。可以使用 递归字节对编码(recursive byte pair encoding) 将ZY
编码为X
。现在,数据已转换为XdXac
,其中X = ZY
,Y = ab
,Z = aa
。由于转换后的数据XdXac
没有出现超过一次的字节对,因此无法进一步压缩。以相反的顺序进行替换,对数据进行解压缩。
BPE 确保 最常见的单词 表示为在词汇表中的 单个 token ,而 生僻单词 被分解为 两个或多个子词 token ,这与基于子词的 tokenization 算法的功能一致。
假设有一个包含若干单词的语料库(在 Space pre-tokenization 之后):
old
、older
、finest
和loweast
。然后计算这些单词在语料库中出现的频率。假设这些词,在每个单词后面增加一个 token</w>
,其频率如下:{“old</w>”: 7, “older</w>”: 3, “finest</w>”: 9, “lowest</w>”: 4}
在每个单词的末尾添加</w>
token 以标识单词边界,以便算法知道每个单词的结尾位置,这有助于算法查看每个字符并找到频率最高的字符配对。接下来,将每个单词拆分为字符并计算它们的出现次数。初始 token 将是所有字符和
</w>
标记。
由于总共有 23=7+3+9+4 个单词,因此有 23 个
</w>
token ;第二高频率的 token 是e
;总共有 12 种不同的 token 。The next step in the BPE algorithm is to look for the most frequent pairing, merge them, and perform the same iteration again and again until we reach our token limit or iteration limit.
BPE 算法的下一步是寻找最频繁的配对,合并它们,并一次又一次地执行相同的迭代,直到达到令牌限制或迭代限制。合并操作可以用最少数量的 token 表示语料库,这是 BPE 算法的主要目标,即数据压缩。为了进行合并操作,BPE 会查找最常表示的字节对。BPE 概念中将字符(character)视为与字节(byte)相同,这是英语的情况,在其他语言中可能会有所不同。现在,将合并最常见的字节对以形成一个 token ,并将它们添加到 token 列表中,并重新计算每个 token 的出现频率。这意味着频率计数将在每个合并步骤后发生变化。将继续执行此合并步骤,直到达到迭代次数或达到令牌限制大小。
迭代 1:将从第二个最常见的标记
e
开始(这就意味着不会找de
而是会找er
或es
)。在语料库中,最常见的带有e
的字节对是e
和s
(在finest
和loweast
的单词中),它们出现了 9 + 4 = 13 次。将它们合并以形成一个新的 tokenes
,并将其频率记为 13。还将从单个 token (e
和s
)中减少计数 13。这将使我们知道剩余的e
或s
token。可以看到,s
根本不单独出现,e
出现了 3 次。以下是更新后的表格:迭代 2:现在将合并
es
和t
这两个词,因为它们在语料库中出现了 13=9+4 次。这样,就有了一个频率为 13 的新标记词est
,将es
和t
的频率降低 13。迭代 3:现在来处理
</w>
token 。est
和</w>
这对字节在语料库中出现了 13 次。注意:合并停止 token
</w>
非常重要。这有助于算法理解estimate
和highest
等词之间的区别。这两个词都有est
的共同点,但一个在末尾有一个est
token,一个在开头有一个est
token。因此,像est
和est</w>
这样的 token 将以不同的方式处理。如果算法看到est</w>
,它将知道它是单词highest
的 token ,而不是单词estimate
的 token 。
经过多轮合并后,得到的表格是这样的:
如果我们现在查看表格,会发现
f
、i
和n
的频率是 9,但只有一个单词包含这些字符,因此不会将它们合并。为了本文的简单起见,现在停止迭代并仔细查看 token 。从表格中可以发现:频率计数为 0 的标记已从表中删除;现在可以看到总标记数为 11,这比最初的计数少 12 个。这是一个很小的语料库,但在实践中,大小减少了很多。这个包含 11 个 token 列表将作为词汇表。
当添加 token 时,每个 token 的计数频率会增加或减少或保持不变。实际上, token 数量先增加然后减少。停止标准可以是 token 的计数计数频率或迭代的次数。选择合适的停止标准,以便数据集可以以最有效的方式分解为 token 。
Encoding and Decoding
如何解码?要解码,必须简单地将所有 token 连接在一起以获得整个单词。例如,编码序列 [“the</w>”, “high”, “est</w>”, “range</w>”, “in</w>”, “Seattle</w>” ]
将被解码为 [“the”, “highest”, “range”, “in”, “Seattle”]
而不是 [“the”, “high”, “estrange”, “in”, “Seattle ”]
。请注意 est</w>
中存在 </w>
标记。
新数据的编码过程也很简单。但是,编码本身的计算成本很高。假设词序列为 ["the", "highest", "range", "in", "Seattle"]
。将遍历我们在语料库中找到的从最长到最短的所有 token ,并尝试使用这些 token 替换给定词序中的子串。最后,将遍历所有 token ,子串将被 token 列表中已有的 token 所替换。如果还剩下一些子串(模型在训练中没有看到的单词),将用 unknown token 来替换它们。一般来说,词汇量很大,但仍然有可能出现未知单词。在实践中,将 pre-tokenization 的单词保存在字典中。对于未知(新)单词,应用上述编码方法对新单词进行 tokenize ,并将新单词的 token 添加到词典中以供将来参考。这有助于未来建立更强大的词汇量。
Final Part
为了以最有效的方式表示语料库,BPE 通过查看其频率来遍历每个潜在的选项,以便在每次迭代时进行合并。BPE 遵循贪婪的方法来优化最佳可能的解决方案。BPE 是最广泛使用的子词 tokenization 算法之一,尽管算法本身是贪婪的,但它仍具有良好的性能。
3. 高斯误差线性单元 (Gaussian Error Linear Unit, GELU)
参考这篇博客。
- ReLU、ELU 和 PReLU 等激活函数比 sigmoid 函数更能使神经网络更快更好地收敛。
- Dropout 正则化能将一些激活神经元随机乘以 0 来正则化模型。
- 一个名为 Zoneout 的新 RNN 正则化器会将输入随机乘以 1。
上述方法共同决定神经元的输出;然而,都是相互独立工作的。
GELU 激活函数旨在将这些技术结合起来。
之所以选择这个分布,是因为神经元的输入遵循正态分布,尤其是在批量归一化之后。
但任何激活函数的输出都应该是确定的,而不是随机的。由于 ϕ ( x ) \phi(x) ϕ(x) 是高斯分布的累积分布(正态分布从负无穷到当前值的积分),通常用误差函数计算,因此我们将高斯误差线性单元(GELU)定义如下:
ϕ ( x ) \phi(x) ϕ(x) 是高斯分布的累积分布,通常用误差函数计算。
这篇博客介绍了 GELU 的一些优势:
- 平滑度:GELU 是一个平滑函数,这意味着它是连续可微的,与 ReLU 不同,ReLU 的不连续性为零。平滑属性有助于在训练期间进行基于梯度的优化。
- 恒等逼近:对于较小的 x x x 值( x < − 2 x<-2 x<−2 的情况),GELU 类似于恒等函数,这使得它即使对于较小的激活也可以保留网络中的信息,当 x < − 2 x<-2 x<−2 时候,基本就是数值 0 ,这相当于小的激活函数被抑制了??。
- 非线性:GELU 向网络引入了非线性,这对于捕获数据中的复杂关系至关重要。
- Sigmoid 和 Tanh 组件:GELU 使用 sigmoid 和双曲正切 (tanh) 函数的组合,这有助于有效地对负值( x ∈ ( − 2 , 0 ) x\in(-2,0) x∈(−2,0) 的情况)和梯度进行建模。
- 归一化:GELU 包含归一化项 2 π \sqrt{\frac{2}{\pi}} π2 ,以确保输出的标准差接近 1,这有助于稳定深度神经网络的训练。