BERT原理理解

参考博客

https://wmathor.com/index.php/archives/1456/

https://blog.csdn.net/sunhua93/article/details/102764783,非常详细

预训练模型

用巨大的数据来训练一个泛化能力很强的模型,当我们需要在特定场景使用时,例如做文本相似度计算,那么,只需要简单的修改一些输出层,再用我们自己的数据进行一个增量训练,对权重进行一个轻微的调整

预训练的好处在于在特定场景使用时不需要用大量的语料来进行训练,节约时间效率高效,bert就是这样的一个泛化能力较强的预训练模型。

BERT

BERT 全称为 Bidirectional Encoder Representation from Transformer,是 Google 以无监督的方式利用大量无标注文本「炼成」的语言模型,其架构为 Transformer 中的 Encoder(BERT=Encoder of Transformer)

从创新的角度来看,bert其实并没有过多的结构方面的创新点,其和GPT一样均是采用的transformer的结构,相对于GPT来说,其是双向结构的,而GPT是单向的,如下图所示:

 

 BERT的两个常用版本:

 

L是transformer的层数,H是输出的维度,A表示multi-head attention中头的个数。

从模型的层数来说其实已经很大了,但是由于transformer的残差(residual)模块,层数并不会引起梯度消失等问题,但是并不代表层数越多效果越好,有论点认为低层偏向于语法特征学习,高层偏向于语义特征学习。

BERT的预训练过程

接下来我们看看BERT的预训练过程,BERT的预训练阶段包括两个任务,一个是Masked Language Model,还有一个是Next Sentence Prediction。

MLM(Masked Language Model)

MLM可以理解为完形填空,作者会随机mask每一个句子中15%的词,用其上下文来做预测,之后做 Loss 的时候也只计算被遮盖部分的 Loss.其余部分不做损失,其余部分无论输出什么东西,都无所谓。

这样做的好处是,BERT 并不知道 [MASK] 替换的是哪一个词,而且任何一个词都有可能是被替换掉的,比如它看到的 apple 可能是被替换的词。这样强迫模型在编码当前时刻词的时候不能太依赖当前的词,而要考虑它的上下文,甚至根据上下文进行 "纠错"。

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

  • 有 80%的几率是采用[mask]
  • 有 10% 的几率被替换成任意一个其它的 token
  • 有 10% 的几率原封不动

那么为啥要以一定的概率使用随机词呢?

这是因为transformer要保持对每个输入token分布式的表征,否则Transformer很可能会记住这个[MASK]就是"hairy"。

至于使用随机词带来的负面影响,文章中解释说,所有其他的token(即非"hairy"的token)共享15%*10% = 1.5%的概率,其影响是可以忽略不计的。Transformer全局的可视,又增加了信息的获取,但是不让模型获取全量信息。

NSP(Next Sentence Prediction)

我们首先拿到属于上下文的一对句子,也就是两个句子,之后我们要在这两个句子中加一些特殊的 token:[CLS]上一句话[SEP]下一句话[SEP]。也就是在句子开头加一个 [CLS],在两句话之间和句末加 [SEP],具体地如下图所示

 

 

Token Embedding 就是正常的词向量,即 PyTorch 中的 nn.Embedding()

Segment Embedding 的作用是用 embedding 的信息让模型分开上下句,我们给上句的 token 全 0,下句的 token 全 1,让模型得以判断上下句的起止位置

Position Embedding 和 Transformer 中的不一样,不是三角函数,而是学习出来的

NSP任务:

选择一些句子对A与B,其中50%的数据B是A的下一条句子,剩余50%的数据B是语料库中随机选择的,学习其中的相关性,添加这样的预训练的目的是目前很多NLP的任务比如QA和NLI都需要理解两个句子之间的关系,从而能让预训练的模型更好的适应这样的任务。

BERT的优缺点

优点:

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

缺点:

  • MLM的随机遮挡策略略显粗犷
  • [MASK]标记在实际预测中不会出现,训练时用过多[MASK]影响模型表现,与fine-tune阶段会出现gap。
  • 每个batch只有15%的token被预测,所以BERT收敛得比left-to-right模型要慢(它们会预测每个token)
  • BERT对硬件资源的消耗巨大(大模型需要16个tpu,历时四天;更大的模型需要64个tpu,历时四天。

BERT的Fine-tuning过程

BERT 的 Fine-Tuning 共分为 4 种类型,以下内容、图片均来自台大李宏毅老师 Machine Learning 课程(以下内容 图在上,解释在下)

分类问题(一个句子):

 

如果现在的任务是 classification,首先在输入句子的开头加一个代表分类的符号 [CLS],然后将该位置的 output,丢给 Linear Classifier,让其 predict 一个 class 即可。整个过程中 Linear Classifier 的参数是需要从头开始学习的,而 BERT 中的参数微调就可以了。

关键问题:为什么要用CLS?

因为 BERT 内部是 Transformer,而 Transformer 内部又是 Self-Attention,所以 [CLS] 的 output 里面肯定含有整句话的完整信息。

但是 Self-Attention 向量中,自己和自己的值其实是占大头的,现在假设使用 w1 的 output 做分类,那么这个 output 中实际上会更加看重 w1,而 w1 又是一个有实际意义的字或词,这样难免会影响到最终的结果。但是 [CLS] 是没有任何实际意义的,只是一个占位符而已,所以就算 [CLS] 的 output 中自己的值占大头也无所谓。就相当于将所有词的 output 进行 concat,作为最终的 output。

slot filling问题(一个句子)

 

如果现在的任务是 Slot Filling,将句子中各个字对应位置的 output 分别送入不同的 Linear,预测出该字的标签。

其实这本质上还是个分类问题,只不过是对每个字都要预测一个类别。

句子匹配(两个句子,例如NLI问题)

 

 

如果现在的任务是 NLI(自然语言推理)。即给定一个前提,然后给出一个假设,模型要判断出这个假设是 正确、错误还是不知道。这本质上是一个三分类的问题,和 Case 1 差不多,对 [CLS] 的 output 进行预测即可。

问答问题,阅读理解

 

 如果现在的任务是 QA(问答),举例来说,如上图,将一篇文章,和一个问题(这里的例子比较简单,答案一定会出现在文章中)送入模型中,模型会输出两个数 s,e,这两个数表示,这个问题的答案,落在文章的第 s 个词到第 e 个词。

 

 还需要额外训练两个向量。

首先将问题和文章通过 [SEP] 分隔,送入 BERT 之后,得到上图中黄色的输出。

还要训练两个 vector,即上图中橙色和蓝色的向量。首先将橙色和所有的黄色向量进行 dot product,然后通过 softmax,看哪一个输出的值最大,例如上图中 d2 对应的输出概率最大,那我们就认为 s=2。

 

同样地,我们用蓝色的向量和所有黄色向量进行 dot product,最终预测得 d3 的概率最大,因此 e=3。最终,答案就是 s=2,e=3。

 

posted @ 2021-07-28 23:30  永远是个小孩子  阅读(891)  评论(0编辑  收藏  举报