BERT 原理解析

BERT(Bidirectional Encoder Representations from Transformers)是一个使用了 Transformer Encoder 的双向语言模型,类似于 GPT,BERT 也是一个两阶段模型,通过上游的无监督预训练,对下游的监督任务进行简单改造以微调参数。
论文:BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding

模型架构

参数

  • L:Transformer blocks;
  • H:hidden size;
  • A:self-attention heads;

无监督预训练深度双向语言模型

模型输入

  • 最大支持长度为 512;
  • 每个句子第一个 token 总是 “special classification embedding”,用 [CLS] 表示;
  • 如果输入的是两个句子,则用 [SEP] 分隔;
  • Segment Embeddings:使用可学习的 A 和 B 表示两个句子的嵌入。当只有一个句子时,全部都是 A。

预训练任务

Task1: Masked LM

为了构建一个深层的真双向语言模型,但是标准的语言模型是使用了马尔可夫链进行的单向编码,即使使用 LTR 与 RTL,但也是假的双向编码,性能会受到极大的影响。使用完形填空机制可以避免标准的语言模型的编码瓶颈。
完形填空策略:随机的 mask 掉 15% 的单词,然后使用编码器最后的 hidden state 过一层 softmax 进行完形填空预测。
但是这种策略会有两个缺点,以下是内容和解决方案:

Downside 1: mismatch

这样做构造了一种 mismatch:因为 [MASK] 永运不会出现在 fine-tuning 阶段,所以 pre-training 与 fine-tuning 出现了 mismatch。
缓解方案:对于随机选择的 15% 待 mask 单词,不是直接将它替换为 [MASK],而是再做一次随机:

  • 80%:将该词替换为 [MASK]
  • 10%:将该词替换为一个随机的词语
  • 10%:不替换

原因:Transformer Encoder 不知道哪个单词被要求做预测,哪个单词被随机替换掉了,所以对于每个输入的单词,它都必须保持上下文嵌入;而且,现在这种策略下随机替换掉的单词只有 1.5%,几乎不会影响模型的语言建模能力。(其实这部分解释有点牵强,有待深刻理解)

Downside 2: slower

现在使用的 MLM 模型,每个 batch 只有 15% 的单词被预测,所以收敛速度确实慢了。但是效果带来的提升却很大。

Task2: Next Sentence Prediction

NLP 中有很多句子关系性的任务,这部分的能力不能通过 Task1 的 MLM 来俘获到,所以加入了一个二分类任务进行多任务学习。
策略:50% 的句子对,将第二句替换为随机的句子来构建负样本。

其他细节

  • 训练语料:BooksCorpus (800M words) + English Wikipedia (2,500M words)
  • batch size:256
  • Adam:$\gamma=1e-4, \beta_1=0.9, \beta_2=-.999$,warmup
  • dropout:0.1
  • GELU
  • loss:两个任务的 loss 和

下游监督任务微调

  • 单句/句子对分类任务:直接使用 [CLS] 的 hidden state 过一层 softmax 进行预测;
  • QA 任务:将问题和答案所在的段拼接起来,使用最后的答案段的 hidden state 向量来计算某个单词是答案开始单词和结束单词的概率,进而进行预测。其中,$S$ 和 $E$ 是需要下游 fine-tuning 阶段训练的开始向量和结束向量。在推断阶段,会强行限制结束的位置必须在开始的位置之后。
  • 序列标注任务:直接将序列所有 token 的最后一层 hidden state 喂进一个分类层(没有使用自回归、CRF)

参考

官方 GitHub:https://github.com/google-research/bert
快速上手工具包:https://github.com/hanxiao/bert-as-service