-
本文讲解思路阐述
-
预训练模型回顾
-
语言模型两种预训练方式回顾
-
Feature-based
-
Fine-tuning
-
单向编码和双向编码回顾
-
一、BERT原文的摘要和导言
-
二、BERT 里程碑式的意义
-
三、BERT能干什么
-
四、BERT的 整体架构
-
五、文中给出的两种结构
-
六、BERT的 输入
-
6.1、Input
-
6.2、Token Embedding
-
6.3、Segment Embedding
-
6.4、Position Embedding
-
七、BERT的 预训练
-
7.1、 Masked LM
-
7.2、 Next Sentence Prediction
-
7.3、 前向传播示意图
-
八、BERT的 Fine-tuning( 下游任务改造)
-
8.1、句对分类
-
8.2、单句分类
-
九、GPT、BERT和Transformer的对比
-
十、 ELMo、GPT、BERT的对比
-
预训练语言模型总结
-
torch复现BERT示例代码
-
BERT的变种
-
References
本文 “保姆级讲解BERT” 的思路如下:
-
首先会先回顾: 什么是预训练模型、语言模型的两种预训练方式、单向编码和双向编码;
-
然后会说一下:BERT原文中作者的 摘要和导言,因为我觉得作者的这种写的思路非常值得学习;
-
然后会说一下: BERT公认的里程碑式的意义、介绍一下 BERT能干什么,让读者有一个大致的了解;
-
然后会介绍一下: BERT的整体架构、模型的输入;
-
再然后就是比较重点的: BERT的预训练 和 Fine-tuning,并贴出 前向传播流程图方便大家理解;
-
接着会:把 BERT和其它语言模型做一下对比,加深理解;
-
然后就是一个简单的总结;
-
我还会放出torch复现的代码来,大家可以看下MLM数据怎么处理的,以及多任务的损失部分是怎么来算的,当然实际主要还是用Huggingface的;
-
最后简单说一下BERT的一些 变种模型,作为本文的结尾,扩充一下知识面。
定义:
-
首先使用大量无监督语料进行语言模型的预训练(Pre-training),再使用有标注的语料进行微调(Fine-tuning),来完成具体的NLP任务,比如分类、序列标注、句间关系判断、机器阅读理解等。
优势:
-
近乎无限量的数据;
-
无需人工标注;
-
一次学习,多次复用;
-
学习到的表征可以在多个任务中进行快速迁移。
在NLP中,利用语言模型去做预训练,能显著提升许多自然语言处理任务的效果,自然语言处理任务主要包括两种:
-
sentence-level tasks(句子级别):指学习多个句子之间的关系,例如 natural language inference(自然语言推理)。
-
token-level tasks(词级别):指模型要生成 细粒度(fine-grained)的输出,fine-grained指的是类内细分,与之相对于的是 粗粒度(coarse-grained)。
-
例如在分类任务中,coarse-grained只需要分辨是猫还是狗,而fine-grained则 需要在每个类别中分辨出具体的品种,比如是拉布拉多还是罗威纳。
语言模型(Language Model)来辅助NLP任务已经得到了学术界较为广泛的探讨,通常有两种方式:
-
基于特征的(Feature-based)
-
基于微调的(Fine-tuning)
基于特征的(Feature-based)预训练方式,典型的代表就是ELMo。
Feature-based 指的是利用预训练好的语言模型的结果,也就是得到预训练好的词向量,将其作为额外的特征融入到下游任务中,参与下游任务的训练。
通常 Feature-based 的预训练方法包括两步:
-
首先是在大量的语料A上无监督的训练好语言模型,得到预训练好的语言模型;
-
然后搭建下游任务所使用的模型(task specific model),采用有标记的训练语料B来训练 task specific model,将预训练好的语言模型的 参数固定,训练语料B先经过语言模型得到预训练好的词向量;得到词向量后可以直接作为 task specific model 的输入参与训练;也可以和原始特征Embedding进行拼接,作为额外特征参与后面的训练。
需要强调的是:基于特征的预训练方法,我们只需要拿到预训练模型的词向量即可,预训练模型的参数不参与下游任务的梯度更新。
基于微调的(Fine-tuning)预训练方式,典型的代表就是GPT。
Fine-tuning 指的是利用预训练好的语言模型,在此基础上加入少量的 task-specific parameters ,例如对于分类问题,就可以在语言模型的基础上加一层FC或直接Softmax进行分类,然后在新的训练语料上进行微调。
通常 Fine-tuning 的预训练方法包括两步:
-
构建语言模型,采用大量的语料A无监督的训练语言模型;
-
在预训练好的语言模型的基础上,用下游任务的训练语料B进行有监督的训练;在语言模型之后可以直接加一层FC或者直接加Softmax来进行分类;或者常用的做法就是,在语言模型之后再接其它的模型,比如接一个TextCNN、DPCNN等,可以理解为它们 学习的就是预训练模型提取的高级语义。
需要强调的是,利用预训练语言模型在下游任务微调,模型的参数不是固定的,它仍然是 trainable variables。
BERT采用的就是基于微调的预训练方式。
我们来回顾下单向编码和双向编码的差异,比如这个例子:“今天天气很{},我们不得不取消户外运动”。
我们分别从单向编码和双向编码的角度去考虑 {} 中应该填什么词:
-
单向编码
-
这样理解:因为 没有下文,所以这里就随便填,可以填 “好”、“不错”,也可以填 “差”、“糟糕”。
-
双向编码
-
双向编码 会同时考虑上下文的信息,即除了会考虑 “今天天气很” 这五个字,还会考虑 “我们不得不取消户外运动”,来帮助模型判断,则大概率会从 “差”、“糟糕” 这一类词中选择。
接下来就正式进入BERT的讲解了。
我们先看它的标题:
-
Pre-training(预训练)的意思也重复好多遍了:在一个数据集上训练好一个模型,然后这个模型的主要目的是用在别的任务上;
-
Deep Bidirectional Transformers:预训练的 深的双向的Transformer;
-
for Language Understanding:针对的是一般的语言的理解任务。
我们来看下摘要的第一段话:
-
第一个高亮说了BERT名字的由来,意思是Transformer这个模型双向的编码器表示,后面说是跟最近的语言模型表示不一样。第一个引用的是ELMo的文章,第二个引用的是GPT的文章。
-
第二个高亮说的是,BERT是用来去设计 深的双向的表示,使用 没有标记的数据,再 联合左右的上下文信息。
-
第三个高亮说的是,BERT只需要 加一个额外的输出层就可以得到一个不错的结果,在很多的NLP任务上面。
这两句话其实就讲明白了其和ELMo、GPT的区别:
-
GPT因为掩码注意力的限制考虑的是单向的信息,即用左边的信息去预测未来;BERT这里不一样是因为它用了左侧和右侧,所以它是个双向的。
-
ELMo是一个基于RNN的架构,而BERT用的是Transformer,所以ELMo在用到一些下游的任务的时候,它需要对架构做出调整,BERT就比较简单只需要改最上层就行了,和GPT是一样的。
我感觉这样写就很好,在摘要的第一段话里说和那两个工作相关,然后再说和这两个工作的区别是什么。
我们再来看一段导言:
导言的第一段一般是交代了这篇论文关注的一个上下文关系。
说这些NLP任务包括两类,第一类是用于建模句子之间的关系,第二类是词元(token)的任务。比如对每个词去进行实体识别(NER)、比如它是不是一个人名、街道名等。(本文最上面有给出回顾)
导言的第二段和最后,是摘要的第一段的扩充版本。
它说在使用预训练模型做特征表示的时候一般有两类策略:基于特征的、基于微调的。(本文一开始回顾的)
第一类是基于特征的,代表是ELMo,对每一个下游的任务,先构造一个跟这个任务相关的网络,然后基于大量语料进行预训练,得到预训练好的词向量,预训练好的词向量表示可以作为一个额外的特征,和输入一起喂到模型里面,因为特征有了一个比较好的表示,所以导致模型训练起来比较容易。这也是NLP里面使用预训练一个常用的做法,就是把学到的特征和输入一起放进去,作为一个很好的特征的表达。
第二类是基于微调的,代表是GPT,把预训练好的模型放在下游的任务的时候不需要改太多,模型预训练好的参数会在下游数据的任务上进行微调,即所有的权重会根据新的数据进行微调。
读到这是不是感觉我的上一篇、包括本篇的前面的回顾都不是废话了吧!
如果把过去几年NLP领域里的论文做一个排序的话,BERT当之无愧的是状元的位置。在计算机视觉任务里,很早的时候就可以在一个很大的数据集,比如ImageNet训练好一个卷积网络,这个模型可以帮助一大片的cv任务来提升它们的性能。但是在NLP里,在BERT之前,一直没有一个深的神经网络,使得训练好之后能够帮助一大片的NLP任务。
也就是说在BERT之前,还是对于每个任务构造自己的神经网络,在自己的任务上做训练。BERT的出现使得我们可以在一个比较大的数据集上预训练好一个比较深的神经网络,然后应用在很多NLP任务上面。既简化了NLP任务的训练,又提升了它们的性能。所以BERT和它之后的一系列工作使得NLP在过去几年里有了一个质的飞跃。
作者的原话是:从大量无标记数据集中预训练得到的深度模型,通过下游任务微调的方式,可以显著提高各项NLP任务的准确率。
但是如果说创新的话,它其实并没有什么本质的创新,很大的创新应该是Attention 和 Transformer,BERT其实是一个集大成者:
-
参考了 ELMo 模型的 双向编码思想。
-
借鉴了 GPT 用 Transformer 作为特征提取器的思路。
-
采用了 Word2Vec 所使用的 CBOW 方法。
还可以这样说:预训练的方法其实很早就有了,只不过是BERT让它出圈了。
上面我们提到过,作为一个预训练的语言模型,BERT能够以微调的方式帮助很多NLP的下游任务。所以BERT的输出也肯定不单单是一种,如上图所示,bert具有两种输出:
-
一个是 pooler output,对应的 [CLS] 的输出;
-
一个是 sequence output, 对应的是序列中的所有字的最后一层 hidden 的输出;
-
先提取强调一下,在预训练中的MLM任务里,损失计算用的是被 mask 的输出,大家往后看就明白了。
所以BERT主要可以处理两种任务:
-
-
单句分类任务(Single Sentence Classification tasks);
-
句子对分类任务(Sentence Pair Classification tasks);
-
回归任务其实是分类任务的一种特殊形式,最后的输出是一个数值而不是具体的某个类别的概率。例如:文本相似度,可以判断两个句子是不是类似的,得到具体的分数;
-
-
命名实体识别(NER);
-
Cloze task(完形填空),这其实这就是bert预训练的一种任务;
-
问答任务;
-
序列标注任务。
我们以单句分类任务(Single Sentence Classification tasks)为例简单看下,示例图如下:
了解Transformer、ELMo、GPT的同学其实一看图bert也就明白了。
BERT的模型结构就是 Transformer Encoder 的堆叠,因为Transformer拥有比较强的特征提取能力,所以通过堆叠block能够提取到多层的信息。
因为使用 Transformer Encoder 作为block的原因,BERT是双向的语言模型,也就是说每个时刻的Attention计算都能够得到全部时刻的输入,而GPT由于Decoder的掩码注意力的限制,每个时刻的Attention计算只能依赖于该时刻前的输入,所以这里也是为什么说GPT是单向语言模型的原因。
注意这里不要混淆,BERT是对 Transformer Encoder 的堆叠,不是堆叠的Transformer。
上面重点强调了BERT就是 Transformer Encoder 的堆叠,那么我们可以将BERT结构简单的归纳为三个部分:
-
输入层,输入层和Transformer不同,图中也可以看出,它是 Token Embedding、Segment Embedding和Position Embedding 相加 得到的;
-
中间层,中间层就是 Encoder block 的堆叠;
-
输出层,为了更好的融入不同的下游任务,输出又可以分为两块,一是 [CLS] 的输出,二是 Sequence 的输出。
在模型参数选择上,论文中给出了两套大小不一致的模型:
数据量大,模型也大,就不容易过拟合,能够学到更到的东西。
BERT_base:L=12,H=768,A=12,总参数量为1.1亿
BERT_large:L=24,H=1024,A=16,总参数量为3.4亿
-
L:代表 Transformer block 的层数;
-
H:代表特征向量的维数,此处默认 Feed Forward 层中的中间隐层维数为4H;
-
A:代表 Attention 的分头个数;
使用这三个参数基本可以定义BERT的量级,训练过程也是很花费计算资源和时间的,总之表示膜拜,普通人即便有idea没有算力也只能跪着。印象中听过一个视频,里面的大神说训练下来是几百万美金...,所以我们训练不了,只能拿人家训练好的来进行微调。
之前讲的ELMo,它用的双向双层LSTM得到了单词特征、句法特征、语义特征,这些特征它可能是人为定义出来的,但人和机器相比总是狭隘的,正因为机器的强大,它能够发现更多的特征,是人类无法用语言表达的高级语义特征。
对于BERT_large,用了24层block,也就是编码了24层不同的特征信息,越高层的信息越无法用语言表达,但是机器认为它是可取的,对目标有帮助,随着训练数据的越来越大,它能够学到更多的语义逻辑关系。
其实这也是和神经网络被称为黑盒一个道理,通过BERT堆叠多层Encoder block,最终能够得到一个很好的特征向量,去准确的表达一个词、一个句子。
BERT的本质其实就是通过在海量的语料进行自监督学习,为每个 token 学习得到一个比较好的向量表征,我们可以直接使用 BERT 学习到的表征作为下游任务的嵌入特征。
所谓的自监督学习是指在没有人工标注的数据集上运行的监督学习。
所以为了使 BERT 能够适应不同的下游任务,BERT 的输入可以是单句或者句对,即:
-
[CLS] + 句子A
-
[CLS] + 句子A + [SEP] + 句子B + [SEP]
对于每一个输入 token,它的 Embedding 表征由:对应的词表征(Token Embedding)、段表征(Segment Embedding)、位置表征(Position Embedding)相加产生。
我们来看一个比较形象的图:
注意啊,找的这个图没有画位置编码,我懒得画了,大家自行想象一下即可。
首先来看 input,对于 input,我们需要重点关注两部分:
-
第一个是正常的词汇,如 'my'、 'dog'、 'is'、 'cute '、'he'、'likes'、'play';
-
第二个是 特殊词汇,如 '[CLS]'、'[SEP]';
[CLS] 表示输入句子的起始token(特殊token),对应最终的 hidden state,也就是 Encoder block 的输出,训练结束后可以表征整个句子,[CLS]其实是Classification的意思,[CLS] 输出的特征向量(pooler output)可以用于下游的分类任务。
我们前面提到过,预训练好的 BERT 可以用于多种nlp的下游任务,对于分类任务,就用 [CLS] 的输出特征向量。
如下图所示,与文本中已有的其它字词相比,这个无明显语义信息的符号感觉会更“公平”的融合文本中各个词的语义信息。
这时,句子B就为空,输入就变成了:[CLS] + 句子A
注意 [CLS] 输入的是 [CLS] 本身这个词的 Embedding。
[SEP] 就是 分隔符 的意思,这个不难理解,如果输入为两个句子的话,需要一个特殊符号 [SEP] 将两个句子分开,就是告诉模型在 [SEP] 之前的是一个句子,之后的是一个句子。
Token Embedding 就是正常的 Embedding,比如随机初始化,或加载其它预训练好的词向量。
对于英文任务,作者使用了Wordpiece模型来产生Subword,从而减小词表规模。
其中,Wordpiece是指将单词划分成一组有限的公共子词单元,能在单词的有效性和字符的灵活性之间获得一个折中的平衡。
例如图中的 “playing” 就被拆分成了 “play” 和 “ing”。
对于中文任务,作者直接训练基于字的模型,上面也提到了,模型输入需要附加一个起始token,记为 [CLS],训练结束后用它表征整个句子,参与下游的分类任务。
BERT为了更好的融入下游任务,所以输入可能会有句子对,Segment Embedding 是句子分段的嵌入张量,它的作用就是为了区分两个句子。区分的方式也很简单:第一个句子全部用0表示,后面的句子全部用1来表示(包括 [CLS] 和 [SEP]在内),即图中的。
例如我们现在有一个输入句子对:
p data-tool='mdnice编辑器'>那么其对应的 Segment Embedding 为:
span data-tool='mdnice编辑器'>
blockquote data-tool='mdnice编辑器'>
BERT的预训练里有个叫 NSP 的任务,即要做以两个句子为输入的分类任务。
那么对于单句输入,其 Segment Embedding 只有一种;对于句对输入,其 Segment Embedding 就会有两种。
/blockquote>
p data-tool='mdnice编辑器'>BERT里的位置编码和 Transformer 是不同的,Transformer 的位置编码是通过
正余弦函数实现的,而BERT是
随机初始化的,让模型自己去学。在BERT中,它假设句子最大长度为512。
figure data-tool='mdnice编辑器'>
p data-tool='mdnice编辑器'>上图为原文中给出的预训练和微调示意图,和GPT一样,BERT也采用
两阶段式训练方法:
ul data-tool='mdnice编辑器'>
-
掩码语言模型: Masked Language Model(MLM), 目的是提高模型的语义理解能力;
-
下句预测: Next Sentence Prediction(NSP), 目的是训练句子之间的理解能力;
blockquote data-tool='mdnice编辑器'>
不同于GPT等标准语言模型使用为目标函数进行训练,能看到全局信息的BERT使用为目标函数进行训练。
/blockquote>
p data-tool='mdnice编辑器'>先来解释一下为什么需要
语言掩码模型(MLM):
ul data-tool='mdnice编辑器'>
blockquote data-tool='mdnice编辑器'>
Encoder编码器,就是给它一个句子,它已经把中间词的信息提前拿到了,再让它去预测不是搞笑吗。
/blockquote>
hr data-tool='mdnice编辑器'>
p data-tool='mdnice编辑器'>为了解决这个问题,BERT 借鉴了 CBOW 思想(完形填空任务),使用
语言掩码模型(MLM )方法训练模型,具体做法为:
ul data-tool='mdnice编辑器'>
blockquote data-tool='mdnice编辑器'>
注意只有训练阶段才会这样做,测试阶段不会mask。
/blockquote>
p data-tool='mdnice编辑器'>被 mask 的词称为
掩码词,这样实际上已经不是传统的神经网络语言模型了,而是单纯作为分类问题,根据这个时刻的 hidden state 来预测这个时刻的 token 应该是什么,而不是预测下一个时刻的词的概率分布了。
p data-tool='mdnice编辑器'>利用 mask 打破文本的原有语义信息,让模型不知道。在预训练的时候,让其对有mask的文本进行重建,绞尽脑汁的从周围的上下文中学习各种信息,来让自己预测的mask的词汇更接近原本的词汇。
p data-tool='mdnice编辑器'>我们还要再强调的是,BERT的本质是提取特征向量(高级语义),通过 mask 方法只是为了让BERT提取的特征向量更准确,主要目的不是预测被 mask 的token,主要目的是
提取特征向量。
blockquote data-tool='mdnice编辑器'>
为什么说它借鉴完形填空思想呢?对于某一个被 mask 的 token 的上下文而言,模型不知道token是什么,再去预测它,就类似于完形填空了。
/blockquote>
hr data-tool='mdnice编辑器'>
p data-tool='mdnice编辑器'>但是这样设计 MLM 的训练方法会引入一个弊端:在模型微调阶段或推理阶段(测试阶段),输入的文本中没有 mask,这样会出现由
训练和预测数据偏差导致的性能损失。
p data-tool='mdnice编辑器'>作者考虑到这个弊端,并没有总用 mask 替换掩码词,而是
按照一定比例选取替换词,在随机的15%的词作为掩码词后,这些掩码词
有三类替换选项:
figure data-tool='mdnice编辑器'>
ul data-tool='mdnice编辑器'>
blockquote data-tool='mdnice编辑器'>
“地球是【mask】八大行星之一”
/blockquote>
ul data-tool='mdnice编辑器'>
blockquote data-tool='mdnice编辑器'>
“地球是太阳系八大行星之一”
/blockquote>
ul data-tool='mdnice编辑器'>
blockquote data-tool='mdnice编辑器'>
“地球是月球八大行星之一”
/blockquote>
p data-tool='mdnice编辑器'>按照存在弊端的做法,如果对这15%的词全部用 mask 来替换的话,那么模型的
全部精力就会聚焦在 mask 上,因为其它的词,比如 “地球”,它一定是正确的。
p data-tool='mdnice编辑器'>现在的做法,mask 是随机的,模型不知道那个token是 mask 的,甚至 “地球” 也可能是要被 mask 的,只不过它被错误的词代替了。
p data-tool='mdnice编辑器'>也就是说用了这个方法,所以的词都有
可能是要被mask 的词,这样模型就有了把精力放在 mask 和其它词的能力,也就是测试阶段也会去考虑
每一个词了。
hr data-tool='mdnice编辑器'>
p data-tool='mdnice编辑器'>mask的作用就是
让模型对特征向量有更好的语义理解,所以mask不能去掉,但是要考虑训练阶段和测试阶段的间隙,即上述所说的弊端。
p data-tool='mdnice编辑器'>作者在论文中提到这样做的好处是,
编码器不知道哪些词是需要训练的、哪些词是错误的,因此被迫需要学习每一个token的表示向量。
p data-tool='mdnice编辑器'>另外作者也表示双向编码器比单向编码器训练要慢,进而导致BERT的训练效率低了很多,但是实验也证明MLM训练方法可以让 BERT 获得超出同期所有预训练语言模型的
语义理解能力,牺牲训练效率是值得的。
hr data-tool='mdnice编辑器'>
p data-tool='mdnice编辑器'>15%的mask token中,三种方案代码示例如下:
p data-tool='mdnice编辑器'>
MLM提供的这种无监督的预训练方法,就是通过 mask token,让模型去预测被 mask 的 token,从而提高模型对token的理解,即提高表征能力。所以我们总结一下,理解这两点就够了:
ul data-tool='mdnice编辑器'>
p data-tool='mdnice编辑器'>在很多NLP的下游任务中,如问答(QA)和自然语言推断(NLI),都基于两个句子做逻辑推理,而语言模型并
不具备直接捕获句子之间的语义联系的能力,或者可以说成单词预测粒度的训练到不了解句子关系这个层级,为了学会
捕捉句子之间的语义联系,使得模型能够很好的
理解两个句子之间的关系,BERT 采用了
下句预测(NSP )作为无监督预训练的一部分,即第二个预训练任务。
p data-tool='mdnice编辑器'>NSP 的具体做法是:BERT 输入的语句将由两个句子构成,即句子对(A,B)作为输入,让模型来
预测句子B是不是句子A的真实的下一句话。所有参与训练的语句都可以被选中句子A:
ul data-tool='mdnice编辑器'>
-
作者的原话翻译:50% 的概率将语义连贯的两个连续句子作为训练文本;
-
作者的原话翻译:另外 50% 的概率将完全随机抽取两个句子作为训练文本。
blockquote data-tool='mdnice编辑器'>
连续句对一般选自篇章级别的语料,以此确保前后语句的语义强相关。
/blockquote>
p data-tool='mdnice编辑器'>示例如下:
figure data-tool='mdnice编辑器'>
p data-tool='mdnice编辑器'>
连续句对:[CLS]今天天气很糟糕[SEP]下午的体育课取消了[SEP],label为1p data-tool='mdnice编辑器'>
随机句对:[CLS]今天天气很糟糕[SEP]鱼快被烤焦了[SEP],label为0ul data-tool='mdnice编辑器'>
-
结果为 1,表示输入为连续句对;
-
结果为 0,表示输入为随机句对。
p data-tool='mdnice编辑器'>通过训练 [CLS] 编码后的输出标签,BERT 可以
学会捕捉两个输入句对的文本语义,在连续句对的预测任务中,BERT 的正确率可以达到 97%-98%。
hr data-tool='mdnice编辑器'>
p data-tool='mdnice编辑器'>我们还是举例来理解,[CLS] 和 NSP 任务的一个流程关系:
figure data-tool='mdnice编辑器'>
ul data-tool='mdnice编辑器'>
-
我们假设这个句子对是: [CLS] 我的狗很可爱 [SEP] 它喜欢玩耍 [SEP];
-
假设为: [CLS] 我的狗很可爱 [SEP] 企鹅不擅长飞行 [SEP];
-
实际训练中,正负样本比也是 均衡的1:1,也就是一半的时间输出的文本属于上下文关系,一半不是。
-
[CLS] 我的狗很可爱 [SEP] 它喜欢玩耍 [SEP] ---> [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1];
-
[CLS] 我的狗很可爱 [SEP] 企鹅不擅长飞行 [SEP] ---> [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1];
-
注意我没写padding和位置编码,大家看个意思就好了。
-
, ;
-
然后我们通过一层FC将emb_dim维度变为1,然后使用Sigmoid进行二分类的判断: 。
figure data-tool='mdnice编辑器'>
ol data-tool='mdnice编辑器'>
figure data-tool='mdnice编辑器'>
p data-tool='mdnice编辑器'>BERT 根据NLP下游任务的输入和输出的形式,将微调训练支持的任务分为四类,分别是
句对分类、单句分类、文本问答和单句标注,接下来我们重点介绍下 BERT 如何通过微调训练
句对分类、单句分类的任务。
p data-tool='mdnice编辑器'>对于 文本问答 和 单句标注 任务本文不做详细介绍,可粗略理解为:
ul data-tool='mdnice编辑器'>
figure data-tool='mdnice编辑器'>
p data-tool='mdnice编辑器'>句对分类任务:
ul data-tool='mdnice编辑器'>
p data-tool='mdnice编辑器'>如上图所示,句对用 [SEP] 分隔符拼接成文本序列,在句首加入标签 [CLS],将句首标签所对应的输出值作为分类标签,计算预测分类标签与真实分类标签的交叉熵,将其作为优化目标,在下游任务数据上进行微调训练。
ul data-tool='mdnice编辑器'>
p data-tool='mdnice编辑器'>下面给出句对分相似性任务的实例:
div data-tool='mdnice编辑器' data-website='https://www.mdnice.com'>
figure data-tool='mdnice编辑器'>
p data-tool='mdnice编辑器'>单句分类任务:
ul data-tool='mdnice编辑器'>
p data-tool='mdnice编辑器'>如下图所示,单句分类在句首加入标签 [CLS],将句首标签所对应的输出值作为分类标签,计算预测分类标签与真实分类标签的交叉熵,将其作为优化目标,在任务数据上进行微调训练。
p data-tool='mdnice编辑器'>同样,针对多分类任务,需要在句首标签 [CLS] 的输出特征向量后接一个全连接层和 Softmax 层,保证输出维数与类别数目一致,最后通过 argmax 操作得到相对应的类别结果。
p data-tool='mdnice编辑器'>下面给出情感类别判断任务的实例:
div data-tool='mdnice编辑器' data-website='https://www.mdnice.com'>
p data-tool='mdnice编辑器'>下面给出语义连贯性判断任务的实例:
div data-tool='mdnice编辑器' data-website='https://www.mdnice.com'>
p data-tool='mdnice编辑器'>其实这个没什么好对比的,GPT和BERT都可以说是一个集大成者,它们都是在Transformer的基础上搭建起来的,一个用了Transformer的Encoder,一个用了Transformer的Decoder。为什么这里要单独做成一个标题,主要是想分享一下我对Encoder和Decoder的理解。
p data-tool='mdnice编辑器'>我们不止一遍的提到过,编码器是做
特征提取的,也就是单词经过它会得到单词向量、图片经过它会得到图片向量,视频经过它会得到视频向量。这里我感觉它是BERT
起源的一个点,既然什么东西经过Encoder都能得到其对应的向量,那么在这个过程中,Encoder是能够
认识这个单词、这张图片、这个视频的,就是通过这种方式让计算机、让模型准确的认识客观世界的“万事万物”,从而可以得到人类无法描述和理解的
高级信息(语义特别丰富),然后可以通过BERT的
下游任务进行改造来发掘物与物之间的联系。
p data-tool='mdnice编辑器'>而解码器其实是在做一个生成的事情,因为它里面有
掩码多头注意力,所以就注定
不能发掘后面的信息。
p data-tool='mdnice编辑器'>可能会有同学不理解,我们说的再直白一些。编码器因为多头注意力的存在可以挖掘上下文的关系,而解码器的多头注意力有掩码,所以不能发掘后面的信息,它靠的是上文,既然靠的是上文,那么就可以用上文信息去预测下文,这就叫做
生成式。所以解码器有了这样的能力,它就能干BERT无法干的事情。这也就是GPT和BERT的
本质区别,BERT无法做生成式任务。
p data-tool='mdnice编辑器'>当然我们站在后来人的角度上来思考这些的时候,是无法准确的去评判BERT和GPT到底那个好那个坏,因为它们的目的是不一样的,
一个是为了更好的编码得到高级表征信息,一个是做一些生成式的任务。
blockquote data-tool='mdnice编辑器'>
我猜这个时候肯定会有人问:GPT就不能认识客观的世界吗?肯定能,只不过它是通过上文去认识的,它认识的不如BERT那也详细和准确。
/blockquote>
figure data-tool='mdnice编辑器'>
blockquote data-tool='mdnice编辑器'>
回顾双向的意思:单词考虑了上下文的语境。
/blockquote>
ul data-tool='mdnice编辑器'>
-
为什么说是伪双向编码?因为ELMO用的是LSTM:
-
比如对于 ,虽然能够获取它的上文和下文,它将获取到的上文和下文是拼成一个双向编码,但是它受限于LSTM,所以是伪双向编码,也就是说在 某一时间段,当它获取上文的时候它获取不到下文信息,当获取下文信息的时候它看不到上文信息。
-
BERT用的是 Transformer 的 Self-Attention,Self-attention 是可以 直接看到前后文的,所以说BERT的双向编码是真正意义的 双向编码,因为它考虑了上下文。这也是Self-Attention解决LSTM无法利用上下文信息的问题。
-
BERT和ELMO的区别在于使用 Transformer block 作为特征提取器,加强了语义特征提取的能力。
-
BERT和GPT的区别在于使用 Transformer Encoder 作为block,并将GPT的单向编码改为双向编码,也就是说BERT 舍弃了文本生成能力,换来了 更强的语义理解能力。
-
BERT基于 Encoder 做的是特征提取得到特征向量,用于下游任务。GPT基于 Decoder 做的是生成式任务。
-
从任务属性的角度来讲BERT和ELMO更相似,目的都是 获取特征向量。
p data-tool='mdnice编辑器'>首先我们还是回顾一下预训练这个过程本质上是在做什么事情,本质上预训练是通过设计好一个网络结构来做语言模型任务,然后把大量甚至是无穷尽的
无标注的自然语言文本
利用起来,预训练任务把大量语言学知识抽取出来编码到网络结构中,当手头任务带有标注信息的数据有限时,这些先验的语言学特征当然会对手头任务有
极大的特征补充作用,因为当数据有限的时候,很多语言学现象是覆盖不到的,泛化能力就弱,集成尽量通用的语言学知识自然会加强模型的泛化能力。如何引入先验的语言学知识其实一直是NLP尤其是深度学习场景下的NLP的主要目标之一,不过一直没有太好的解决办法,而ELMO/GPT/Bert的这种两阶段模式看起来无疑是解决这个问题自然又简洁的方法,这也是这些方法的主要价值所在。
figure data-tool='mdnice编辑器'>
p data-tool='mdnice编辑器'>最后我们可以再梳理下几个模型之间的演进关系,从上图可见,Bert 其实和 ELMO 及 GPT 存在千丝万缕的关系:
ul data-tool='mdnice编辑器'>
p data-tool='mdnice编辑器'>所以简单总结下Bert最关键的两点:
ul data-tool='mdnice编辑器'>
ul data-tool='mdnice编辑器'>
blockquote data-tool='mdnice编辑器'>
https://wangguisen.blog.csdn.net/article/details/
/blockquote>
ul data-tool='mdnice编辑器'>
blockquote data-tool='mdnice编辑器'>
https://wangguisen.blog.csdn.net/article/details/
/blockquote>
blockquote data-tool='mdnice编辑器'>
也是后续打算写的文章(应该会写的吧?...),这里说一下是扩充大家的知识面,同时也作为本文的结尾段落。
/blockquote>
p data-tool='mdnice编辑器'>
RoBERTa(Robustly Optimized BERT Pre-training Approach),其对BERT预训练做了一个优化,主要贡献如下:
ul data-tool='mdnice编辑器'>
p data-tool='mdnice编辑器'>
ALBERT(A Lite BERT),它是BERT的一个微缩版,主要贡献如下:
ul data-tool='mdnice编辑器'>
p data-tool='mdnice编辑器'>
DistillBERT(A Distilled Version of BERT),它是BERT的一个蒸馏版本,主要贡献如下:
ul data-tool='mdnice编辑器'>
blockquote data-tool='mdnice编辑器'>
knowledge distillation 知识蒸馏概述:
-
一种常用的知识迁移方法,通常由教师模型和学生模型构成;
-
该技术能够将较大的模型压缩到一个较小的模型,同时基本保持原模型的效果。
/blockquote>
p data-tool='mdnice编辑器'>https://arxiv.org/abs/1810.04805v2
p data-tool='mdnice编辑器'>https://zhuanlan.zhihu.com/p/
p data-tool='mdnice编辑器'>https://wmathor.com/index.php/archives/1456/
p data-tool='mdnice编辑器'>https://blog.csdn.net/Decennie/article/details/
p data-tool='mdnice编辑器'>https://blog.csdn.net/_/article/details/
p data-tool='mdnice编辑器'>https://blog.csdn.net/jiaowoshouzi/article/details/
p data-tool='mdnice编辑器'>https://blog.csdn.net/weixin_/article/details/
p data-tool='mdnice编辑器'>https://blog.csdn.net/weixin_/article/details/
到此这篇transformer复现(bert复现)的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!版权声明:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权、违法违规、事实不符,请将相关资料发送至xkadmin@xkablog.com进行投诉反馈,一经查实,立即处理!
转载请注明出处,原文链接:https://www.xkablog.com/rfx/41187.html