BERT: Bidirectional Encoder Representations from Transformers双向Transformer用于语言模型 NAACL 2018

    技术2022-07-16  91

    论文链接:https://arxiv.org/abs/1810.04805 tensorflow版本代码链接:https://github.com/google-research/bert pytorch版本代码链接:https://github.com/codertimo/BERT-pytorch

    导读

    这篇论文由谷歌团队发表于2018年的NAACL上《BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding》,目前引用量超 3800 次。Bert 取名来自 Bidirectional Encoder Representations from Transformers,大致可以了解到他采用的是双向的 Transformer 的 Encoder 结构。

    因此,阅读论文时我们可以关注下 Bert 模型的两个点:

    1.利用 Encoder 完成预训练后如何配合下游任务? 2.预训练过程的双向是类似 ELMo 的双向吗?如果不是的话,怎么去防止数据泄漏?

    1、引言

    通过预训练语言模型可以显著提高 NLP 下游任务,包括 NER、QA、知识推理等。目前的预训练有两种策略:feature-based 和 fine-tuning,对应着我们之前介绍过两个预训练模型:ELMo 和 GPT。基于 feature-based 的 ELMo 是针对指定任务进行预训练;而基于 fine-tuning 的 GPT 设计的是一个通用架构,并针对下游任务进行微调,两方法都是使用单向的语言模型来学习一般的语言表示。

    但是谷歌的同学认为,预训练的潜力远远不应该只有这些,特别是对于 fine-tuning 来说。限制模型潜力的主要原因在于现有模型使用的都是单向的语言模型,无法充分了解到单词所在的上下文结构(试想:我们想了解一个单词的含义,其实是会结合上下文来判断,而不是只结合单词的上文)。

    针对这一痛点:谷歌的同学提出了新的预训练方法 BERT。BERT 受完形填空(cloze task)的启发,通过使用 “Masked Language Model” 的预训练目标来缓解单向语言模型的约束。

    首先 “Masked Language Model” 会随机屏蔽(masked)一些单词,然后让模型根据上下文来预测被遮挡的单词。与 ELMo 不同的是,BERT 是真正的结合上下文进行训练,而 ELMo 只是左向和右向分别训练。

    除了 “Masked Language Model” 外,谷歌的同学还提出了 “next sentence prediction” 的任务预训练文本对。将 token-level 提升到 sentence-level,以应用不同种类的下游任务。

    2、BERT模型

    BERT 和之前的模型类似都采用两阶段的步骤:pre-training 和 fine-tuning。pre-training 阶段,BERT 在未标记的数据上进行无监督学习;而 fine-tuning 阶段,BERT 首先利用预训练得到的参数初始化模型,然后利用下游任务标记好的数据进行有监督学习,并对所有参数进行微调。所有下游任务都有单独的 fine-tuning 模型,即使是使用同样的预训练参数。下图是对 BERT 的一个概览:

    2.1、模型架构

    BERT 是由多层双向的 Transformer Encoder 结构组成,区别于 GPT 的单向的 Transformer Decoder 架构。 谷歌的同学在论文中提供了两个不同规模的 BERT:BERT Base 和 BERT Large。前者有 12 个隐藏层,768 个隐单元,每个Multi-head Attention 中有 12 个 Attention,共 1.1 亿参数,主要是为了与 OpenAI 比较性能;而后者有 24 个隐藏层,1024 个隐单元,每个 Multi-head Attention 中有 16 个Attention,共 3.4 亿参数,主要是用来秀肌肉的。 从创新的角度来看,BERT其实并没有过多的结构方面的创新点,其和GPT一样均是采用的transformer的结构,相对于GPT来说,其是双向结构的,而GPT是单向的,如下图所示: ELMo:将上下文当作特征,但是无监督的语料和我们真实的语料还是有区别的,不一定符合我们特定的任务,是一种双向的特征提取。

    OpenAI GPT就做了一个改进,也是通过transformer学习出来一个语言模型,不是固定的,通过任务 fine-tuning,用transfomer代替ELMo的LSTM。OpenAI GPT其实就是缺少了encoder的transformer。当然也没了encoder与decoder之间的attention。OpenAI GPT虽然可以进行fine-tuning,但是有些特殊任务与pre-training输入有出入,单个句子与两个句子不一致的情况,很难解决,还有就是decoder只能看到前面的信息。

    其次BERT在多方面的NLP任务变现来看效果都较好,具备较强的泛化能力,对于特定的任务只需要添加一个输出层来进行fine-tuning即可。

    总结

    2.2、输入

    为了能应对下游任务,BERT 给出了 sentence-level 级别的 Representation,包括句子和句子对。

    在 BERT 中 sequence 并不一定是一个句子,也有可能是任意的一段连续的文本;而句子对主要是因为类似 QA 问题。

    我们来看下 BERT 的输入: 分为三块:Token Embeddings、Segment Embeddings 和 Position Embeddings。

    Token Embeddings 采用的 WordPiece Embedding,共有 30000 个 token。每个 sequence 会以一个特殊的 classification token [CLS] 开始,同时这也会作为分类任务的输出;句子间会以 special token [SEP] 进行分割。

    WordPiece Embedding:n-gram 字符级 Embedding,采用 BPE 双字节编码,可以将单词拆分,比如 “loved” “loving” ”loves“ 会拆分成 “lov”,“ed”,“ing”,“es”。

    Segment Embedding 也可以用来分割句子,但主要用来区分句子对。Embedding A 和 Embedding B 分别代表左右句子,如果是普通的句子就直接用 Embedding A。

    Position Embedding 是用来给单词定位的,学习出来的embedding向量。这与Transformer不同,Transformer中是预先设定好的值。。

    BERT 最终的 input 是三种不同的 Embedding 直接相加。

    2.3、预训练Pre-training

    BERT 采用两种非监督任务来进行预训练,一个是 token-level 级别的 Masked LM,一个是 sentence-level 级别的 Next Sentence Prediction。两个任务同时训练,所以 BERT 的损失函数是两个任务的损失函数相加。

    当我们在训练语言模型时,有一个挑战就是要定义一个预测目标,很多模型在一个序列中预测下一个单词, “The child came home from ___” 双向的方法在这样的任务中是有限制的,为了克服这个问题,BERT 使用以下的两个策略:

    2.3.1、Masked LM

    我们知道语言模型只能是单向的,即从左到右或者从右到左,而使用双向的话会导致数据泄漏问题,即模型可以间接看到要预测的单词。这也是为什么 ELMo 要采用两个独立的双向模型的原因。

    为了解决这个问题,谷歌的同学提出了 Masked LM 的概念:随机屏蔽一些 token 并通过上下文预测这些 token。这种况下就解决了双向模型和数据泄漏的问题。在具体实验过程中,BERT 会随机屏蔽每个序列中的 15% 的 token,并用 [MASK] token 来代替。

    但这样会带来一个新的问题:[MASK] token 不会出现在下游任务中。为了缓解这种情况,谷歌的同学采用以下三种方式来代替 [MASK] token:

    80% 的 [MASK] token 会继续保持 [MASK];10% 的 [MASK] token 会被随机的一个单词取代;10% 的 [MASK] token 会保持原单词不变(但是还是要预测)。 最终 Masked ML 的损失函数是只由被 [MASK] 的部分来计算。

    这样做的目的主要是为了告诉模型 [MASK] 是噪声,以此来忽略标记的影响。

    这样就需要:

    在 encoder 的输出上添加一个分类层用嵌入矩阵乘以输出向量,将其转换为词汇的维度用 softmax 计算词汇表中每个单词的概率

    BERT 的损失函数只考虑了 mask 的预测值,忽略了没有掩蔽的字的预测。这样的话,模型要比单向模型收敛得慢,不过结果的情境意识增加了。

    2.3.2、Next Sentence Prediction

    部分下游任务如问答(QA)、语言推理等都是建立在句子对的基础上的,而语言模型只能捕捉 token-level 级别的关系,捕捉不了 sentence-level 级别的关系。

    为了解决这个问题,谷歌的同学训练了一个 sentence-level 的分类任务。具体来说,假设有 A B 两个句对,在训练过程 50% 的训练样本 A 下句接的是 B 作为正例;而剩下 50% 的训练样本 A 下句接的是随机一个句子作为负例。并且通过 classification token 连接 Softmax 输出最后的预测概率。 虽然很简单,但是在实际效果是非常好的。

    为了帮助模型区分开训练中的两个句子,输入在进入模型之前要按以下方式进行处理:

    在第一个句子的开头插入 [CLS] 标记,在每个句子的末尾插入 [SEP] 标记。将表示句子 A 或句子 B 的一个句子 embedding 添加到每个 token 上。给每个 token 添加一个位置 embedding,来表示它在序列中的位置。

    为了预测第二个句子是否是第一个句子的后续句子,用下面几个步骤来预测:

    整个输入序列输入给 Transformer 模型用一个简单的分类层将 [CLS] 标记的输出变换为 2×1 形状的向量用 softmax 计算 IsNextSequence 的概率

    在训练 BERT 模型时,Masked LM 和 Next Sentence Prediction 是一起训练的,目标就是要最小化两种策略的组合损失函数。

    2.4、微调Fine-tuning

    预训练好后我们看下 BERT 的 Fine-tuning 是怎么实现的。

    由于预训练的 Transformer 已经完成了句子和句子对的 Representation,所以 BERT 的 Fine-tuning 非常简单。

    针对不同的下游任务,我们可以将具体的输入和输出是适配到 BERT 中,并且采用端到端的训练去微调模型参数。BERT 可以用于各种NLP任务,只需在核心模型中添加一个层,例如:

    在分类任务中,例如情感分析等,只需要在 Transformer 的输出之上加一个分类层在问答任务(例如SQUAD v1.1)中,问答系统需要接收有关文本序列的 question,并且需要在序列中标记 answer。 可以使用 BERT 学习两个标记 answer 开始和结尾的向量来训练Q&A模型。在命名实体识别(NER)中,系统需要接收文本序列,标记文本中的各种类型的实体(人员,组织,日期等)。 可以用 BERT 将每个 token 的输出向量送到预测 NER 标签的分类层。

    如下图所示:

    a b 是 sentence-level 级别的任务,类似句子分类,情感分析等等,输入句子或句子对,在 [CLS] 位置接入 Softmax 输出 Label;c 是 token-level 级别的任务,比如 QA 问题,输入问题和段落,在 Paragraph 对应输出的 hidden vector 后接上两个 Softmax 层,分别训练出 Span 的 Start index 和 End index(连续的 Span)作为 Question 的答案;d 也是 token-level 级别的任务,比如命名实体识别问题,接上 Softmax 层即可输出具体的分类。

    3、实验

    下图是与不同模型的对比情况 下图是Masked LM与单向的LM的实验对比情况 下图为不同Mask策略下的效果

    4、结论

    BERT 采用 Pre-training 和 Fine-tuning 两阶段训练任务,在 Pre-training 阶段使用多层双向 Transformer 进行训练,并采用 Masked LM 和 Next Sentence Prediction 两种训练任务解决 token-level 和 sentence-level 的问题,为下游任务提供了一个通用的模型框架;在 Fine-tuning 阶段会针对具体 NLP 任务进行微调以适应不同种类的任务需求,并通过端到端的训练更新参数从而得到最终的模型。

    BERT 是 NLP 领域中一个里程碑式的工作,并对后续 NLP 的研究工作产生了深远影响。

    5、思考

    总结下BERT的主要贡献:

    引入了Masked LM,使用双向LM做模型预训练。为预训练引入了新目标NSP,它可以学习句子与句子间的关系。进一步验证了更大的模型效果更好: 12 --> 24 层。为下游任务引入了很通用的求解框架,不再为任务做模型定制。刷新了多项NLP任务的记录,引爆了NLP无监督预训练技术。

    BERT优点:

    Transformer Encoder因为有Self-attention机制,因此BERT自带双向功能因为双向功能以及多层Self-attention机制的影响,使得BERT必须使用Cloze版的语言模型Masked-LM来完成token级别的预训练为了获取比词更高级别的句子级别的语义表征,BERT加入了Next Sentence Prediction来和Masked-LM一起做联合训练为了适配多任务下的迁移学习,BERT设计了更通用的输入层和输出层微调成本小

    BERT缺点:

    task1的随机遮挡策略略显粗犷,推荐阅读《Data Nosing As Smoothing In Neural Network Language Models》[MASK]标记在实际预测中不会出现,训练时用过多[MASK]影响模型表现;每个batch只有15%的token被预测,所以BERT收敛得比left-to-right模型要慢(它们会预测每个token)BERT对硬件资源的消耗巨大(大模型需要16个TPU,历时四天;更大的模型需要64个TPU,历时四天。

    个人观点:

    个人并不认为文章是模型的改进,更认可为任务的设计改进。

    论文作者只比较了有没有task1的影响,并没有针对task2对比试验。提升是否来自好的预训练任务设计没有明说。

    bert对nlp领域目前已有知识的有效“整合”,在硬件配置足够的情况下能提高nlp多领域性能

    6、模型参数

    Bert模型的版本如下:

    BERT-Base, Uncased: 12-layer, 768-hidden, 12-heads, 110M parameters

    BERT-Large, Uncased: 24-layer, 1024-hidden, 16-heads, 340M parameters

    BERT-Base, Cased: 12-layer, 768-hidden, 12-heads , 110M parameters

    BERT-Large, Cased: 24-layer, 1024-hidden, 16-heads, 340M parameters

    BERT-Base, Chinese: Chinese Simplified and Traditional, 12-layer, 768-hidden, 12-heads, 110M parameters

    所有的输入长度最长为512,英文版的"vocab_size": 30522,中文版的"vocab_size": 21128

    Processed: 0.017, SQL: 9