一、BERT介绍

论文:BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding 

简介:BERT是基于Transformer的深度双向语言表征模型,基本结构如图所示,本质上是利用Transformer结构构造了一个多层双向的Encoder网络。Transformer是Google在2017年提出的基于自注意力机制(Self-attention)的深层模型,在包括机器翻译在内的多项NLP任务上效果显著,超过RNN且训练速度更快。

  从上图可见,Bert其实和ELMO及GPT存在千丝万缕的关系,比如如果我们把GPT预训练阶段换成双向语言模型,那么就得到了Bert;而如果我们把ELMO的特征抽取器换成Transformer,那么我们也会得到Bert。与GPT不同之处:在预训练阶段采用了类似ELMO的双向语言模型;另外一点是语言模型的数据规模要比GPT大。

  Bert最关键两点:

  1. 特征抽取器采用Transformer;
  2. 预训练的时候采用双向语言模型。

二、BERT模型结构

  上图中$E_i$是指的单个字或词, $T_i$指的是最终计算得出的隐藏层, Transformer中的注意力矩阵和注意力加权, 经过这样的操作之后, 序列里面的每一个字, 都含有这个字前面的信息和后面的信息, 这就是双向的理解, 在这里, 一句话中每一个字, 经过注意力机制和加权之后, 当前这个字等于用这句话中其他所有字重新表达了一遍, 每个字含有了这句话中所有成分的信息.

  根据参数设置的不同,Google 论文中提出了Base和Large两种BERT模型。

三、预训练

  BERT预训练过程包含两个不同的预训练任务,分别是Masked Language Model和Next Sentence Prediction任务。

1.Masked Language Model(MLM)

  随机把一些单词变为[Mask],然后预测这些被遮盖的词来训练双向语言模型,并且使每个词的表征参考上下文信息。假设输入里面的第二个词汇是被盖住的,把其对应的embedding输入到一个多分类模型中,来预测被盖住的单词。之后做Loss的时候只计算被遮盖部分的Loss。

实际操作方式如下:

【1】随机把一句话中15%的token替换成以下内容:

  1. 这些token中有80%的几率被替换成[mask];
  2. 有10%的几率被替换成任意一个其他的token;
  3. 有10%的几率原封不动

【2】之后让模型预测和还原被遮盖掉或替换掉的部分,模型最终输出的隐藏层的计算结果的难度是:

$X_{hidden}$: [batch size, seq len, embedding dim]
我们初始化一个映射层的权重$W_{vocab}$:
$W_{vocab}$: [embedding dim, vocab size] 
我们用$W_{vocab}$完成隐藏维度到字向量数量的映射, 只要求$X_{hidden}$和$W_{vocab}$的矩阵乘(点积):
$X_{hidden}W_{vocab}$: [batch size, seq len, vocab size] 
之后把上面的计算结果在vocab size(最后一个)维度做$softmax$归一化, 是每个字对应的vocab size的和为1, 我们就可以通过vocab size里概率最大的字来得到模型的预测结果, 就可以和我们准备好的$Label$做损失($Loss$)并反传梯度了. 注意做损失的时候, 只计算在第1步里当句中随机遮盖或替换的部分, 其余部分不做损失, 对于其他部分, 模型输出什么东西, 我们不在意.

这样做会产生两个缺点

  1. 会造成预训练和微调时的不一致,因为在微调时[MASK]总是不可见的;
  2. 由于每个Batch中只有15%的词会被预测,因此模型的收敛速度比起单向的语言模型会慢,训练花费的时间会更长。

解决方法:

  1. 对于第一个缺点的解决办法是,把80%需要被替换成[MASK]的词进行替换,10%的随机替换为其他词,10%保留原词。由于Transformer Encoder并不知道哪个词需要被预测,哪个词是被随机替换的,这样就强迫每个词的表达需要参照上下文信息。
  2. 对于第二个缺点目前没有有效的解决办法,但是从提升收益的角度来看,付出的代价是值得的。

2.Next Sentence Prediction(NSP)

首先我们拿到属于上下文的一对句子, 也就是两个句子, 之后我们要在这两段连续的句子里面加一些特殊$token$: $[cls]$上一句话,$[sep]$下一句话.$[sep]$ 
  也就是在句子开头加一个$[cls]$, 在两句话之中和句末加$[sep]$, 具体地就像下图一样:

  我们看到上图中两句话是[cls] my dog is cute [sep] he likes playing [sep], [cls]我的狗很可爱[sep]他喜欢玩耍[sep], 除此之外, 我们还要准备同样格式的两句话, 但他们不属于上下文关系的情况; [cls]我的狗很可爱[sep]企鹅不擅长飞行[sep], 可见这属于上下句不属于上下文关系的情况;在实际的训练中, 我们让上面两种情况出现的比例为1:1, 也就是一半的时间输出的文本属于上下文关系, 一半时间不是.

  我们进行完上述步骤之后, 还要随机初始化一个可训练的 segment embeddings , 见上图中, 作用就是用 embeddings 的信息让模型分开上下句, 我们一把给上句全 0 的 tokentoken , 下句啊全 1 的 token , 让模型得以判断上下句的起止位置, 例如:

[cls] 我的狗很可爱 [sep] 企鹅不擅长飞行 [sep]
0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1

上面 0 和 1 就是 segment embeddings .

  注意力机制就是, 让每句话中的每一个字对应的那一条向量里, 都融入这句话所有字的信息, 那么我们在最终隐藏层的计算结果里, 只要取出$[cls]token$所对应的一条向量, 里面就含有整个句子的信息, 因为我们期望这个句子里面所有信息都会往$[cls]token$所对应的一条向量里汇总: 
模型最终输出的隐藏层的计算结果的维度是: 
$X_{hidden}$: [batch_size, seq_len, embedding_dim]$
我们要取出$[cls]token$所对应的一条向量, $[cls]$对应着seq len维度的第$0$条:

$cls\_vector = X_{hidden}[:, 0, :]$,
$cls\_vector \in \mathbb{R}^{batch\_size, embedding\_dim} $

之后我们再初始化一个权重, 完成从embedding dim维度到1的映射, 也就是逻辑回归, 之后用$sigmoid$函数激活, 就得到了而分类问题的推断. 
我们用$\hat{y}$来表示模型的输出的推断, 他的值介于$(0, 1)$之间: 
$\hat{y} = sigmoid(Linear(cls vector)) \quad \hat{y} \in (0, 1)$

3.BERT训练参数和技巧

  BERT论文中, 推荐的模型参数为: 基准模型transformer_block=12, embedding_dimension=768,  num_heads=12, Total Param eters=110M), 可见其中共有1.1亿参数, 除此之外, 还有比基准模型还大的高性能模型, 参数量为3亿, 要想训练并使用这么大参数的模型, 需要充裕的计算资源。

训练技巧:

  1. 因为我们是按单个字为单位训练BERT, 所以在Masked LM里面, 把句子中的英文单词分出来, 将英文单词所在的区域一起遮盖掉, 让模型预测这个部分;
  2. 很多句子里含有数字, 显然在Masked LM中, 让模型准确地预测数据是不现实的, 所以我们把原文中的数字(包括整数和小数)都替换成一个特殊token, #NUM#, 这样模型只要预测出这个地方应该是某些数字就可以来。

四、BERT完成下游任务

NLP四个任务:序列标注、分类任务、句子关系推断、生成式任务

1.句子关系推断

  对于句子关系类任务,和GPT类似,加上一个起始和终结符号,句子之间加个分隔符即可。对于输出来说,把第一个起始符号对应的Transformer最后一层位置上面串接一个softmax分类层即可。

举例:给定一个前提/假设,得到推论是否正确:

  为了训练一个理解句子间关系的模型,引入一个下一句预测任务。这一任务的训练语料可以从语料库中抽取句子对包括两个句子A和B来进行生成,其中50%的概率B是A的下一个句子,50%的概率B是语料中的一个随机句子。NSP任务预测B是否是A的下一句。NSP的目的是获取句子间的信息,这点是语言模型无法直接捕捉的。

  Google的论文结果表明,这个简单的任务对问答和自然语言推理任务十分有益,但是后续一些新的研究[15]发现,去掉NSP任务之后模型效果没有下降甚至还有提升。我们在预训练过程中也发现NSP任务的准确率经过1-2个Epoch训练后就能达到98%-99%,去掉NSP任务之后对模型效果并不会有太大的影响。

2.分类任务

  如果是分类任务,在句子前面加一个标志,将其经过Bert得到的embedding输出到二分类模型中,得到分类结果。二分类模型从头开始学,而Bert在预训练的基础上进行微调(fine-tuning)。

文中还有很多其他的应用,如单词分类:

3.序列标注

  输入部分和单句分类是一样的,只需要输出部分Transformer最后一层每个单词对应位置都进行分类即可。

4.生成式任务

  对于机器翻译或者文本摘要,聊天机器人这种生成式任务,同样可以稍作改造即可引入Bert的预训练成果。只需要附着在S2S结构上,encoder部分是个深度Transformer结构,decoder部分也是个深度Transformer结构。根据任务选择不同的预训练数据初始化encoder和decoder即可。这是相当直观的一种改造方法。当然,也可以更简单一点,比如直接在单个Transformer结构上加装隐层产生输出也是可以的。

  举例:抽取式QA,抽取式的意思是输入一个原文和问题,输出两个整数start和end,代表答案在原文中的起始位置和结束位置,两个位置中间的结果就是答案。

  解决QA问题:把问题 - 分隔符 - 原文输入到BERT中,每一个单词输出一个黄颜色的embedding,这里还需要学习两个(一个橙色一个蓝色)的向量,这两个向量分别与原文中每个单词对应的embedding进行点乘,经过softmax之后得到输出最高的位置。正常情况下start <= end,但如果start > end的话,说明是矛盾的case,此题无解。

五、BERT总结

1.优点

  1. 考虑双向信息(LM只考虑单向)
  2. 长距离依赖(long-term dependence)

2.缺点

  1. 测试数据没有[mask],discrepancy,削弱了一定的泛化能力。
  2. 缺乏生成能力(LM具有生成能力)
  3. 针对每一个mask预测时,没有考虑mask间的相关性(例:w1 w2 [mask] w4 w5 [mask] w7,第一个mask为w3,第二个mask为w6,理想情况是需要考虑w3和w6间相关性的,bert里面没有考虑这点,二者是独立的)

类似于朴素贝叶斯,没有考虑特征间的相关性。

六、应用

1.获得句向量

使用BERT模型生成句子序列向量 - 不著人间风雨门 - 博客园

参考文献:

【1】美团BERT的探索和实践

【2】【NLP】李宏毅-ELMO、BERT、GPT视频笔记

【3】aespresso/a_journey_into_math_of_ml: 汉语自然语言处理视频教程-开源学习资料

【4】https://www.bilibili.com/video/av70512497?t=1195&p=1&spm_id_from=333.788.b_62696c692d6865616465722d6d.18

【5】【BERT】如何训练并使用Bert【持续更新】

【6】Dissecting BERT Part 1: The Encoder - Dissecting BERT - Medium

【7】使用BERT模型生成句子序列向量 - 不著人间风雨门 - 博客园

【8】NLP:自回归(Autoregressive LM)与自编码语言模型(Autoencoder LM)_人工智能_小马哥的博客-CSDN博客

【9】台大《应用深度学习》国语课程(2020) by 陈蕴侬

Transformer---BERT模型的更多相关文章

  1. attention、self-attention、transformer和bert模型基本原理简述笔记

    attention 以google神经机器翻译(NMT)为例 无attention: encoder-decoder在无attention机制时,由encoder将输入序列转化为最后一层输出state ...

  2. 从Word Embedding到Bert模型—自然语言处理中的预训练技术发展史(转载)

    转载 https://zhuanlan.zhihu.com/p/49271699 首发于深度学习前沿笔记 写文章   从Word Embedding到Bert模型—自然语言处理中的预训练技术发展史 张 ...

  3. BERT模型介绍

    前不久,谷歌AI团队新发布的BERT模型,在NLP业内引起巨大反响,认为是NLP领域里程碑式的进步.BERT模型在机器阅读理解顶级水平测试SQuAD1.1中表现出惊人的成绩:全部两个衡量指标上全面超越 ...

  4. 想研究BERT模型?先看看这篇文章吧!

    最近,笔者想研究BERT模型,然而发现想弄懂BERT模型,还得先了解Transformer. 本文尽量贴合Transformer的原论文,但考虑到要易于理解,所以并非逐句翻译,而是根据笔者的个人理解进 ...

  5. zz从Word Embedding到Bert模型—自然语言处理中的预训练技术发展史

    从Word Embedding到Bert模型—自然语言处理中的预训练技术发展史 Bert最近很火,应该是最近最火爆的AI进展,网上的评价很高,那么Bert值得这么高的评价吗?我个人判断是值得.那为什么 ...

  6. 图示详解BERT模型的输入与输出

    一.BERT整体结构 BERT主要用了Transformer的Encoder,而没有用其Decoder,我想是因为BERT是一个预训练模型,只要学到其中语义关系即可,不需要去解码完成具体的任务.整体架 ...

  7. BERT模型

    BERT模型是什么 BERT的全称是Bidirectional Encoder Representation from Transformers,即双向Transformer的Encoder,因为de ...

  8. 使用BERT模型生成token级向量

    本文默认读者有一定的Transformer基础,如果没有,请先稍作学习Transormer以及BERT. 相信网上有很多方法可以生成BERT向量,最有代表性的一个就是bert as service,用 ...

  9. NLP学习(3)---Bert模型

    一.BERT模型: 前提:Seq2Seq模型 前提:transformer模型 bert实战教程1 使用BERT生成句向量,BERT做文本分类.文本相似度计算 bert中文分类实践 用bert做中文命 ...

  10. Pytorch | BERT模型实现,提供转换脚本【横扫NLP】

    <谷歌终于开源BERT代码:3 亿参数量,机器之心全面解读>,上周推送的这篇文章,全面解读基于TensorFlow实现的BERT代码.现在,PyTorch用户的福利来了:一个名为Huggi ...

随机推荐

  1. 求数组前K个大的数

    我们举例,假若从10000万个数里选出前100个最大的数据. 首先我们先分析:既然要选出前100个最大的数据,我们就建立一个大小为100的堆(建堆时就按找最大堆的规则建立,即每一个根节点都大于它的子女 ...

  2. CSP2019许愿贴

    CSP2019RP++

  3. [LeetCode] 179. Largest Number 最大组合数

    Given a list of non negative integers, arrange them such that they form the largest number. Example ...

  4. skip connections

    deep learning初学者,最近在看一些GAN方面的论文,在生成器中通常会用到skip conections,于是就上网查了一些skip connection的博客,虽然东西都是人家的,但是出于 ...

  5. C#程序只允许运行一个实例的解决方案

    最近在做winform的程序中,需要只能打开一个程序,如果已经存在,则激活该程序的窗口,并显示在最前端.在网上google了一哈,找到了很多的解决方案.这里我整理了3种方案,并经过了测试,现和朋友们分 ...

  6. Zuul的高级使用

    原文链接:https://blog.csdn.net/u011820505/article/details/79373594

  7. 【转】PyQt弹出式对话框的常用方法及标准按钮类型

    pyQt之弹出式对话框(QMessageBox)的常用方法及标准按钮类型 一.控件说明 QMessageBox是一种通用的弹出式对话框,用于显示消息,允许用户通过单击不同的标准按钮对消息进行反馈,且每 ...

  8. AtomicReference示例

    对引用类型的原子性操作 /** * *对引用变量的原子操作 note: *在java中对引用类型的变量,赋值是原子性的,为什么还要有atomicReference,假如要对一个引用类型进行比较,设置等 ...

  9. sql server锁表、查询被锁表、解锁被锁表的相关语句

    MSSQL(SQL Server)在我的印象中很容易锁表,大致原因就是你在一个窗口中执行的DML语句没有提交,然后又打开了一个窗口对相同的表进行CRUD操作,这样就会导致锁表.锁表是一种保持数据一致性 ...

  10. 在Windows10 安装 Linux 子系统

    在工作中我们经常需要在Windows中安装Linux系统来完成一些工作,通常使用VMware.virtualpc,Hyper-V等虚拟化技术来实现,Now,我们有了更便利的方法来实现,这就是Windo ...