Bootstrap

BERT详解:概念、原理与应用

一、什么是BERT?
BERT是一种预训练语言模型(pre-trained language model,PLM),其全称是Bidirectional Encoder Representations from Transformers。BERT翻译成中文通常被称为“双向编码器表征法”或简单地称为“双向变换器模型”。在自然语言处理领域,BERT以其出色的性能和广泛的应用而著称,为多种语言理解任务提供了强大的预训练模型基础。它由Google于2018年推出,并在多个NLP任务中取得了突破性的成绩,包括在机器阅读理解、GLUE基准测试和MultiNLI准确度等多个测试中超越人类的表现。BERT模型的主要特点是使用了Transformer的encoder部分进行堆叠构建,通过预训练和微调两个阶段来生成深度的双向语言表征,这种结构有助于模型更好地理解和处理语言任务。

BERT是一种基于Transformer架构的预训练语言模型,它通过在大规模文本数据上的预训练来捕捉语言的深层双向表征,然后再针对不同的自然语言处理(NLP)任务进行微调(fine-tuning)。BERT的出现标志着NLP领域的一个重要进步,因为它能够更好地理解语言的上下文和语义关系。具体如下:

1)预训练阶段:BERT通过预训练任务来学习语言的深层表示。这些任务通常包括“遮蔽语言模型”(Masked Language Model,MLM)(类似于完形填空)和“下一句预测”(Next Sentence Prediction,NSP)。在MLM任务中,模型被训练来预测输入句子中被遮蔽的词;而在NSP任务中,模型需要判断两个句子是否是连续的文本序列。

2)微调阶段:预训练完成后,BERT模型可以通过添加任务特定的输出层来进行微调,以适应不同的NLP任务,如情感分析、问答、命名实体识别等。微调过程利用了预训练阶段学到的语言表征,使得模型能够快速适应新的任务并取得优异的性能。

3)模型结构:BERT模型是由多层的Transformer编码器堆叠而成,每一层都包含自注意力机制(Self-Attention)和前馈神经网络。这种深层结构使得BERT能够捕捉从浅层语法特征到深层语义特征的不同级别的语言信息。

4)性能表现:BERT在多个NLP任务上取得了当时的最先进结果,显著推动了自然语言处理技术的发展。它的成功也催生了许多后续的研究工作,包括对BERT结构的改进以及在不同语言和领域中的应用。

总的来说,BERT不仅是一个强大的语言表征模型,也是自然语言处理领域一个重要的里程碑,它的出现极大地推动了深度学习在语言理解和生成方面的应用。

那么什么是 BERT 呢? 我们先从字面上解释一下什么是 BERT,我们将词分开来一个一个地看来解读什么是 BERT。​

Bidirectional:是双向神经网络,这个在学习 RNN 时候我们就了解到如何使用双向 RNN 让每一个词视野更加广阔,不但可以看到其前面词还能看到其后面的词。

Encoder:说明 BERT 是编码器。

Representations:BERT 是完成词的表征的任务的模型,之前我们已经学过了了 word2vec。

Transformer:其实 BERT 就是 transform 解码器部分,表示 BERT 结构没有采用 LSTM 这样。 RNN 结构,而是采用了 Transformer 这样结构来实现双向循环神经网,Transformer 对象 LSTM 的优势是并行计算。

接下来我们来解释这句话中涉及的一些点:

Q1:什么是语言模型?什么又是预训练语言模型?

语言模型是这样一个模型:对于任意的词序列,它能够计算出这个序列是一句话的概率。比如词序列A:“知乎|的|文章|真|水|啊”,这个明显是一句话,一个好的语言模型也会给出很高的概率,再看词序列B:“知乎|的|睡觉|苹果|好快”,这明显不是一句话,如果语言模型训练的好,那么序列B的概率就很小很小。

——以上摘自 语言模型的概念

预训练:预训练是一种迁移学习的概念。所谓预训练模型,举个例子,假设我们有大量的维基百科数据,那么我们可以用这部分巨大的数据来训练一个泛化能力很强的模型(一个知识渊博的人,见多识广),当我们需要在特定场景使用时,例如做医学命名实体识别,那么,只需要简单的修改一些输出层,再用我们自己的数据进行一个增量训练,对权重进行一个轻微的调整即可(增加行业知识后,这个知识渊博的人就是行业专家)。预训练语言模型有很多,典型的如ELMO、GPT、BERT等。

Q2:什么是Transformer?

Bert是基于Transformer实现的,BERT中包含很多Transformer模块,其取得成功的一个关键因素是Transformer的强大作用。

Transformer可以理解为一个神经网络模块,模块内部有其复杂的网络结构,我们可以暂且将其视为黑盒,这并不影响对Bert的理解。总之,这个模块通过自注意力机制实现快速并行,改进了RNN最被人诟病的训练慢的缺点,并且可以增加到非常深的深度,充分发掘DNN模型的特性,提升模型准确率。

PS:BERT一层层深究下去的路径是这样的:【BERT】–【Transformer】–【self-attention】–【attention机制】–【seq2seq】

Q3:什么是双向(Bidirectional)?

因为BERT之前的预训练语言模型如ELMO和GPT都是单向的(ELMO可以说是双向的,但其实是两个方向相反的单向语言模型的拼接),而结合上下文信息对自然语言处理是非常重要的。Bidirectional也是Bert的主要创新点。

BERT的优势:

1、作为一种预训练模型,在特定场景使用时不需要用大量的语料来进行训练,节约时间效率高效,泛化能力较强。

2、Bert是一种端到端(end-to-end)的模型,不需要我们调整网络结构,只需要在最后加上特定于下游任务的输出层。

3、基于Transformer,可以实现快速并行,也可以增加到非常深的深度,充分发掘DNN模型的特性,提升模型准确率。

4、和ELMO,GPT等其他预训练模型相比,BERT是一种双向的模型,结合上下文来进行训练,具有更好的性能。

以上主要是对BERT有一个感性认识,下面我们开始具体介绍BERT的原理和结构。

二、BERT的结构
BERT有两种size,base版一共有110M参数,large版有340M的参数,也就是说,不论是base还是large,BERT的参数量都是上亿的,这个量还是相当大的:

B E R T B A S E : L = 12 , H = 768 , A = 12 , T o t a l P a r a m e t e r s = 110 M BERT_{BASE}:L=12, H=768, A=12, Total Parameters=110MBERTBASE​:L=12,H=768,A=12,TotalParameters=110M

B E R T L A R G E : L = 24 , H = 1024 , A = 16 , T o t a l P a r a m e t e r s = 340 M BERT_{LARGE}: L=24, H=1024, A=16, Total Parameters=340MBERTLARGE​:L=24,H=1024,A=16,TotalParameters=340M

其中,L:Transformer blocks 层数;H:hidden size;A:the number of self-attention heads
BERT的结构没什么可说的,复杂的东西都在Transformer里了。。(可以看我另一篇讲Transformer的文章Transformer)

三、BERT的预训练
BERT的预训练阶段包括两个任务,一个是Masked LM ,还有一个是下句预测(Next Sentence Prediction,NSP)。

Task #1:Masked LM

Masked LM 可以形象地称为完形填空问题,随机掩盖掉每一个句子中15%的词,用其上下文来去判断被盖住的词原本应该是什么。举例来说,有这样一个未标注句子 my dog is hairy ,我们可能随机选择了hairy进行遮掩,就变成 my dog is [mask] ,训练模型去预测 [mask] 位置的词,使预测出 hairy的可能性最大,在这个过程中就将上下文的语义信息学习并体现到模型参数中去了。

这里需要说明,GPT使用统计语言模型,这限制了它只能是单向的,而BERT通过Masked LM能够提取上下文信息。更一般地:

AR模型,auto regressive,自回归模型。 自回归模型可以类比为早期的统计语言模型(Statistical Language Model),也就是根据上文预测下一个单词,或者根据下文预测前面的单词,只能考虑单侧信息,典型的如GPT,而ELMo 是将两个方向(从左至右和从右至左)的自回归模型进行了拼接,实现了双向语言模型,但本质上仍然属于自回归模型

AE模型,auto encoding,自编码模型。 从损坏的输入数据(相当于加入噪声)中预测重建原始数据,可以使用上下文的信息。BERT使用的就是AE。劣势是在下游的微调阶段不会出现掩码词,因此[MASK] 标记会导致预训练和微调阶段不一致的问题。

所以该方法有一个问题,因为是mask15%的词,其数量已经很高了,这样就会导致某些词在fine-tuning阶段从未见过,为了解决这个问题,作者做了如下的处理:

80%的时间是采用[mask],my dog is hairy → my dog is [MASK]

10%的时间是随机取一个词来代替mask的词,my dog is hairy -> my dog is apple

10%的时间保持不变,my dog is hairy -> my dog is hairy

为什么使用这个策略?

(其实我目前还不能很好的理解,先将其他地方看到的说法放在这里)

这是因为transformer要保持对每个输入token分布式的表征,否则Transformer很可能会记住这个[MASK]就是"hairy"(这个地方的理解,强行记住了位置和masked的分布,而没有真正理解上下文),从而导致若训练样本和微调的样本mask不一致的情况下,模型预测出现很大的偏差。

如果仅使用[MASK]或者随机的词,那么模型可能学习到的信息都是错误的单词(认为这个地方的单词就是不正确的);

若仅使用正确的单词,那么模型学到的方法就是直接copy(根据学到的上下文,直接断定),从而学不到完整的上下文信息。

综上三个特点,必须在正确的信息(10%)、未知的信息(80% MASK,使模型具有预测能力)、错误的信息(加入噪声10%,使模型具有纠错能力)都有的情况下,模型才能获取全局全量的信息。

Task #2:Next Sentence Prediction

很多下游任务(QA和natural language inference)都是基于两个句子之间关系的理解,基于此项任务,为了增强模型对句子之间关系的理解能力。训练数据选择两个句子(50%情况下是真正相连的两个句子,50%是随机拼接的两个句子),判断第二个句子是不是真正的第一个句子的下文。
其输入形式是,开头是一个特殊符号[CLS],然后两个句子之间用[SEP]隔断:

Input = [CLS] the man went to [MASK] store [SEP]he bought a gallon [MASK] milk [SEP]

Label = IsNext

Input = [CLS] the man [MASK] to the store [SEP]penguin [MASK] are flight ##less birds[SEP]

Label = NotNext

实际构建预训练任务时,是首选设计好 “下句预测” 任务,生成该任务的标注信息,在此基础上构建 “Masked LM” 任务,生成掩码语言模型的标注信息。考虑到预训练涉及两个句子,BERT 采用如下的输入信息表征方案:

token embedding :将各个词转换成固定维度的向量。在BERT中,每个词会被转换成768维的向量表示。在实际代码实现中,输入文本在送入token embeddings 层之前要先进行tokenization处理。此外,两个特殊的token会被插入到tokenization的结果的开头 ([CLS])和结尾 ([SEP])

segment embedding: 用于区分一个token属于句子对中的哪个句子。Segment Embeddings 层只有两种向量表示。前一个向量是把0赋给第一个句子中的各个token, 后一个向量是把1赋给第二个句子中的各个token。如果输入仅仅只有一个句子,那么它的segment embedding就是全0

position embedding:Transformers无法编码输入的序列的顺序性,所以要在各个位置上学习一个向量表示来将序列顺序的信息编码进来。加入position embeddings会让BERT理解下面下面这种情况,“ I think, therefore I am ”,第一个 “I” 和第二个 “I”应该有着不同的向量表示。

这3种embedding都是768维的,最后要将其按元素相加,得到每一个token最终的768维的向量表示。

四、BERT的使用
BERT最终输出的就是句子中每个token的768维的向量,第一个位置是[CLS],它的向量表示蕴含了这个句子整体的信息,用于做文本分类等句子级任务;对于序列标注等token级任务,就需要使用到每一个token的向量表示。只要将768维向量通过一个线性层映射到最终的分类空间中即可。

;