BERT (Bidirectional Encoder Representation Transformers) 是在2018年由Google AI 团队发布的,虽然在此前刚发布不久的ELMo模型已经相比过去带来了很大的改善,但是BERT在各主流任务上取得的成绩仍然是一个质的飞跃。可以说,此后2-3年陆续出现了很多模型都是围绕着BERT展开进一步的改善和优化,NLP迎来了雨后春笋般的发展。
那么BERT究竟有什么样的特别之处,以至于有这么多后来者争相效仿和赶超呢?从模型设计的理念中我们可以了解到BERT模型有几个关键词:预训练、深度、双向。在当时已有的效果最好的模型中,一种是采用feature-based方法的ELMo模型,它是通过从左向右(LTR)和从右向左(RTL)两个模型的输出拼接获得词的表示;另一种是采用预训练加fine-tune的OpenAI GPT,它是通过从左向右的单向模型来训练。单向模型的主要缺点在于不能获得足够好的词表示,在句子级任务以及分词级任务的效果都是不够好的,同时模型训练的速度也会受到限制。
BERT论文主要贡献在于验证了双向预训练模型比将两个单向预训练模型拼接起来的效果更好,另外BERT也展示了一个通用的大规模预训练模型在很多句子级和分词级任务中能够取得非常好的成绩,从而避免采用许多复杂繁重的特定任务框架。目前BERT在11个NLP下游任务中均达到了最优的效果。
模型结构剖析
BERT最核心的部分是采用了Transformer架构,所以有的学者认为BERT不是一个新的模型,而是在Transformer基础上发展过来的一套流程。具体而言,BERT是一个多层Transformer的Encoder,输入的Embedding通过一层层的Encoder进行编码转换,再连接到不同的下游任务。从卷积神经网络的发展可以知道,残差的引入使得采用深层更窄的网络比浅层更宽的网络更有利于提升性能,对于图像任务,深层的网络意味着能学到不同层次的特征,从最基本的的线、面到复杂的图像。延伸到NLP领域,增加网络的层数可以理解为词、句子、文章、语义等不同级别进行特征提取。
BERT采用了双向并行输入的方式,即将句子整个输入到模型中,而不是将单词一个接着一个地输入,这样可以充分利用GPU的性能,大大提升模型的运行效率。与此同时由于并行输入会带来单词在文本中的位置信息的丢失,因此BERT模型额外需要增加了一个位置编码输入,确保位置信息不被丢失。
针对不同的下游任务,BERT在输入层引入了两个特殊符号,一个是[CLS],放在整个输入文本序列的最前面;另一个是[SEP],对于输入为句子对的任务,将[SEP]放在两个句子的中间以及第二个句子的结尾。[CLS]对应最终输出的hidden state用作分类任务的表示,如果是单句子分类,表示输入句子的类别;如果是句子对分类,表示两个句子是相关的/不相关的、相似意思/相反意思。
BERT的输入向量由三部分组成,分别是token embedding, segment embedding和position Embedding。在分词接入token embedding之前,先进行tokenization处理。这里采用WordPiece嵌入方式,将每个单词进一步拆分成更通用的sub-word,可以避免词汇表过大及减缓OOV的问题,token embedding层再将各分词转换成固定维度的向量。segment embedding是针对句子对任务设置的,只有0和1两个值,用于区分两个句子,句子A编码为0,句子B编码为1,如果是单句子任务,所有编码都为0。position embedding表示每个单词在句子中的位置,同一个单词在不同位置中它的embedding是不同的。3个embedding的size都是(batch_size, seq_length, hidden_size),最后将3个embeddings按元素值相加,即表示BERT编码层的输入。
预训练模型
BERT采用两个无监督任务进行参数预训练。第一个是MLM(Masked Language Model),简单来讲就是对句子随机挖去几个空,让模型去预测这几个空原先的单词。在BERT的预训练中采取的策略是随机抽取句子中15%的单词进行处理,其中这15%的单词又按照80%-10%-10%的比例采取不同的处理方式:80%的单词用[MASK]来替换,表示需要预测的部分,10%用随机的词来替换,10%维持原单词不变。这种训练流程可以让模型学习到单词在上下文中的分布表示,此外用1.5%的随机替换(15%中的10%)也不会损害模型的理解能力。
另外一个预训练任务是NSP(Next Sentence Prediction)。对于句子对A和B,选取B的时候50%的概率是真实的A的下一句(标签IsNext),50%的概率是从语料中随机选取的句子(标签NotNext)。通过预训练NSP任务,让模型理解到两个句子之间的关系,从而能够应用于QA和NLI等下游任务中。
两个任务进行联合训练( In addition to the masked language model, we also use a “next sentence prediction” task that jointly pretrains text-pair representations. )
BERT模型通过对Masked LM任务和Next Sentence Prediction任务进行联合训练,使模型输出的每个字/词的向量表示都能尽可能全面、准确地刻画输入文本(单句或语句对)的整体信息,为后续的微调任务提供更好的模型参数初始值。
总结
- 预测遮挡单词是一个多分类问题,logloss
- 预测下一个句子是一个二分类问题,交叉熵loss
- 合并任务的目标函数就是两个任务的目标函数之和
- 采用梯度下降方法更新合并任务模型参数
模型微调
由于Transformer采用的是自注意力机制,使得BERT模型可以应用于各种各样的下游任务。对于句子对任务,常规的做法是在计算交叉注意力之前,先单独对句子对进行编码。而BERT是将这两步合二为一,即使用自注意力机制来对句子进行编码。
对于输入是两个句子(A和B)的任务,A和B可以是意思相同的两种表述,可以是蕴涵的假设-前提对,可以是问答系统中的问题-回答对,也可以是文本分类或序列标注的文本对。而在输出侧,token表示用于分词级的分类任务,例如序列标注或问答系统;而[CLS]用于分类任务,如蕴涵分析或情感分析等。
预训练数据和参数
以下分项列出BERT预训练过程使用的所有数据和调试参数:
- 数据集:BooksCorpus (单词量 800M),English Wikipedia (单词量 2,500M)
- 主要参数:batch_size=256, epochs=40, max_tokens=512, dropout=0.1
- 优化参数:优化器Adam, lr=1e-4, β1=0.9, β2=0.999, L2 weight decay=0.01, lr_warmup=10,000
- 激活函数:gelu
- 训练损失:mean MLM likelihood + mean NSP likelihood
- 机器配置:BERT(base)使用4个云TPUs,BERT(large)使用16个云TPUs
- 训练时长:4天
- 加速方式:90%的步数按照128的文本长度训练,剩余10%的步数按照512的文本长度训练
微调参数
在fine-tune阶段,大部分模型参数与预训练阶段是一样的,只有batch_size, lr, epochs需要调整,推荐参数如下:
- batch size = 16, 32
- lr = 5e-5, 3e-5, 2e-5
- epochs = 2, 3, 4
BERT的下游任务
特定任务的模型是通过在BERT基础上增加一个额外的输出层,BERT典型的四个下游任务分别是:
- a. 句子对分类任务:如MNLI, QQP, QNLI, STS-B, MRPC, RTE, SWAG任务;
- b. 单句子分类任务:如SST-2,CoLA任务;
- c. 问答系统任务:如SQuAD v1.1任务;
- d. 单句子标注任务:如CoNLL-2003 NER任务;
单文本分类任务 - 对于文本分类任务,BERT模型在文本前插入一个[CLS]符号,并将该符号对应的输出向量作为整篇文本的语义表示,用于文本分类,如下图所示。可以理解为:与文本中已有的其它字/词相比,这个无明显语义信息的符号会更“公平”地融合文本中各个字/词的语义信息。
- 比如对于sequence-level的分类任务,BERT直接取第一个[CLS] token 的final hidden state,再加一层全连接层后进行softmax来预测最终的标签。
- 在NSP任务中,向量C虽然在CLS的位置上,但它包含的是输入的两句话的全部信息,把C作为特征向量输入分类器Binary,得到一个介于0-1之间的值f,其中,1是代表两句话true,0代表两句话毫无关联,依旧用将CrossEntropy(e,f)作为损失函数,用反向传播算出损失函数关于模型的梯度,然后作梯度下降来更新模型参数。 这样作预训练是因为:
- 相邻的两句话通常有关联,这样作二分类可以强化这种关联,让embedding层包含这种关联;
- encoder层中的self-attention层的作用恰好就是找相关性
业务应用:基于业务上的文本数据对bert进行finetune,可以得到含有每个token embedding表示的bert网络,然后将bert网络推导serving端,可以对线上的实时文本推理得到每个实时文本的语义embedding,然后文本的语义embedding进行相似物料召回。
BERT与GPT的对比
与BERT最有可比性的模型是GPT,BERT的很多设计理念是从GPT参考过来的,目的是就是为了更好比较两个模型。二者主要区别在于:
- BERT的训练语料更大,大概是GPT的3倍;
- GPT仅在微调时使用[SEP]和[CLS]符号,而BERT在预训练和Fine-tune阶段都使用[SEP]和[CLS]符号;
- BERT训练的batch_size大约是GPT的4倍;
- GPT使用固定学习率lr=5e-5,BERT根据特定任务选择lr;
两个模型结构对比:
Ref:
[1].BERT 论文详细阅读笔记
[2].Bert预训练
[3].BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding
[4].关于BERT预训练模型,你想知道的都在这~
[5].图解BERT模型