背景
BERT(原论文)结合了前文提到的技术(半监督学习、Transformer)。BERT的主要思路是构建一个神经网络,对大样本的数据进行无监督的训练,然后再将训练后的模型采用Fine tunning的方法去适配其它各种各样的小样本的有监督的训练场景中。以往的神经网络多是针对一个特定的场景从零开始训练出特定的模型,所以要训练出一个可靠的模型,需要耗费大量的数据获取和人工标注的工作。
经过BERT的大样本训练的神经网络相当于提供了一个“普适化”的Pre-trained的模型,AI的工程师可以直接利用这个Pre-trained的模型,经过Fine tunning,去解决各自domain specific的问题。因此,BERT的论文出现后,立刻就成为了深度学习领域关注的热点。现在网上已经有不少的Pre-trained的BERT模型可以进行利用。
BERT也有以下不足:
- Fine tunning的速度慢。因为BERT的模型可达到上亿个参数,即使用它来fine tunning小样本量的场景,也需要耗费较长的时间
- Predict的速度慢。同样也是由于BERT的参数量要更大。即使把完成fine tunning的模型应用于实际场景,仍存在着对计算资源大量耗费的问题,有可能很难满足实时的要求。因此,现在已经有文献再研究,如何能精简BERT的参数。
BERT适用的场景:
- 分类
- 命名实体识别(Named Entity Recognition)
- 词性标注(POS)
- 阅读理解的Q&A(针对一段话+问题,给出问题的答案在这段话的什么地方)
BERT不适用的场景:
- 语言模型
- 文本生成(text generation)
- 自动翻译
结构
BERT主要任务是建立一个pre trained的神经网络的模型。对于Pre-trained的模型需要有以下特征:
- 需要能对大样本进行无监督的训练。比如对整个wiki的文本进行训练。
- 模型能理解语言中的复杂的特征,以便于模型能够应用于其它的特定的场景中。
- 模型自己的loss function不需要考虑在现实中的应用
- 模型也不需要能够将自身的loss function求解的比较好,只需要能训练出够用的参数就可以。
BERT结构如图所示:
Bert实际上是对前文介绍的Transformer进行了修改,去掉了Transformer的Decoder部分,并将Transformer的
N
=
6
N=6
N=6个层替换成了
N
=
12
N=12
N=12层。
输入与输出
BERT输入输出有以下特征:
- 输入端是两个句子。其中第二个句子50%的概率是从语料库取紧跟着第一个句子的句子;50%的概率是从语料库中随机选取一个句子。第一个句子的句首标记[CLS],两个句子之间的标记是[SEP]。
- 在句子中,85%的词不变,15%的词会用于进行预测,其中12%的词会被替换成[MASK];1.5%的词会被保留;1.5%的词会从语料库中采用unigram任选一个词进行替换。(这样,语料库中出现最多的词作为替换词的可能性会最大)。
- BERT每一层的输出都是和前一层输入的向量是一一对应的。这样[CLS]对应的最终输出会用于判定“第二个句子是不是紧跟第一个句子”,其它则用于对应15%的词的预测结果。BERT的loss函数就是这两类判定的loss之和。
各层详细说明
BERT的各层参数如下所示:
The BERT model has 201 different named parameters.
==== Embedding Layer ====
bert.embeddings.word_embeddings.weight (30522, 768)
bert.embeddings.position_embeddings.weight (512, 768)
bert.embeddings.token_type_embeddings.weight (2, 768)
bert.embeddings.LayerNorm.weight (768,)
bert.embeddings.LayerNorm.bias (768,)
==== First Transformer ====
bert.encoder.layer.0.attention.self.query.weight (768, 768)
bert.encoder.layer.0.attention.self.query.bias (768,)
bert.encoder.layer.0.attention.self.key.weight (768, 768)
bert.encoder.layer.0.attention.self.key.bias (768,)
bert.encoder.layer.0.attention.self.value.weight (768, 768)
bert.encoder.layer.0.attention.self.value.bias (768,)
bert.encoder.layer.0.attention.output.dense.weight (768, 768)
bert.encoder.layer.0.attention.output.dense.bias (768,)
bert.encoder.layer.0.attention.output.LayerNorm.weight (768,)
bert.encoder.layer.0.attention.output.LayerNorm.bias (768,)
bert.encoder.layer.0.intermediate.dense.weight (3072, 768)
bert.encoder.layer.0.intermediate.dense.bias (3072,)
bert.encoder.layer.0.output.dense.weight (768, 3072)
bert.encoder.layer.0.output.dense.bias (768,)
bert.encoder.layer.0.output.LayerNorm.weight (768,)
bert.encoder.layer.0.output.LayerNorm.bias (768,)
==== Output Layer for [CLS] ====
bert.pooler.dense.weight (768, 768)
bert.pooler.dense.bias (768,)
classifier.weight (2, 768)
classifier.bias (2,)
Embedding层:
- 在BERT模型会对词进行byte-pair encoding。Byte-pair Encoding是介于字符和词之间的表示形式,即subword。Byte-Pair encoding依据在语料库中出现的频率,将单词进行切分成subword。再对subword建立词向量。下图即为BERT切分和标记预测的subword的示例。
- Embedding层此外还包括position embedding和segment embedding,示例如下:
Segment embedding是用于标注输入的两个句子,哪个是第一个句子,哪个是第二个句子;Position embedding作用和Transformer里的position embedding相同,会给词向量依据在句子中的位置和词向量不同分量的位置,加上不同的数值。 - 和Transformer不同的是,Transformer里面,position embedding是事先给定的。而BERT模型中,词向量、Segment Embedding、Position Embedding均是在Pre-train期间训练出来的。
Transformer层
Transformer层和Transformer模型类似,即包括attention和feedforword两个子层,详细的描述即为multihead attention + dense + layernorm + dense + dense + Layernorm。但是multihead attention和Transformer不同:
- Transformer: 8个heads,每个head对应的Q,K,V的“宽度”是64,这样8个heads输出的attention并列“排起来”的宽度是8*64=512,而512正好是和Transformer中输入的词向量的长度是相同的。
- BERT:12个heads,每个head对应的Q,K,V的“宽度”是64,这样12个heads输出的attention并列“排起来”的宽度是12*64=768,正好和BERT输入的词向量长度相同。
输出层
输出层会先经过dense,再将其进行softmax。其中[CLS]对应的输出向量的长度为2,而用于预测的词对应的输出向量长度为 ∣ V ∣ |V| ∣V∣,即one-hot vector。