Bert原理详细笔记

1. 前言

bert 的本质是学习单词的词向量表达。那我们先来回顾 word2vec,和 bert 预训练产生词向量的不同吧!

  1. word2vec缺点:
  • 学习到的是静态词向量,与上下文无关,如 “ I like to eat Apple" 和 ”Apple is a high-tech company in the United States“, 很显然这两个apple的意思不一样,但在Word2vec看来,它们是一样的词向量。
  • 对于训练的句子,只利用了句子的单向信息:如:今天 天气 真好,要预测 ”真好“ 概率时,根据语言模型概率公式: p(真好)= p(天气 | 今天,天气),预测 p(天气) = p(天气| 今天), 就是说预测”天气“时不能利用”真好“这个信息,因为这个词在”天气“后面。

2.bert 完美的解决了这两个缺点, 可以学习动态的基于上下文的词向量;利用句子的双向信息

2. ELMO介绍

Bert原理详细笔记
为什么要说到ELMO呢?因为它首先尝试解决word2vec的缺点。
总结起来:
Bert原理详细笔记
即:

  1. 深度双向lstm,特点:deep,为什么要做深层??类似于图像识别一样,网络层越深,越能提取到图片中物体的具体信息。放到文本特征提取上,网络层越深,那么能提取的特征也依次具体化: 词特征 --> 语法特征 --> 语义特征
    Bert原理详细笔记
    Bert原理详细笔记
  2. 保留每一层lstm的隐层状态,包括正向和反向 [ →hi | hi←]
  3. 最终某个单词的词向量是 该单词位置上所有隐层状态的加权和

举个栗子:
Bert原理详细笔记

ELMO的损失函数:

Bert原理详细笔记

ELMO的核心就是深层双向的语言模型。这个模型有些致命的缺点:

  • 不完全双向:elmo虽然是双向,但是这个双向不是真正意义上的双向,它是先训练一个前向的RNN,再训练一个后向的RNN,这两个RNN本质上是独立的。对于一个序列,前向遍历一遍获得左边的LSTM隐层输出,后向遍历一遍获得右边的LSTM隐层输出,最后得到的隐层向量直接拼接(前向的hidden state + 后向的hidden state = 总的hidden state,+是concat),并且在最后的Loss function中也是前向和后向的loss function直接相加,并非完全同时的双向计算。
  • 自己看见自己:“深层”,“双向” 就容易自己看见自己。以传统RNN 为例,假如输入 A,B,C,D,我们要预测 C,则 经典语言模型公式: P(C)= P(C | A,B),可以看到 C 是用不到D 信息的。但在EMLO中,情况就不一样了,如图:
    Bert原理详细笔记
  • 从下往上看
  • 第一层:词向量层
  • 第二层,预测 C 时,前向用到了 A,B信息,后向用到了D信息,所以第二层只有 A,B|D信息,这时 没有出现自己看见自己情况,即C没有参考C的信息
  • 第三层,预测 C 时,前向用到了 BCDA|CD 信息,后向用到了 ABC 的信息,所以综合一下 第三层用到了 ABCD的信息,那么 预测C 时,就会参考到 C 的信息。

3.Bert

现在才开始介绍我们的主角:bert
Bert原理详细笔记

3.1 bert的结构

这里需要用到transformer的知识,大家可以看transformer介绍
Transformer的网络架构如图所示,Transformer是一个encoder-decoder的结构,由编码器和解码器构成。图中的左侧部分为编码器,由若干个(论文中6个)encoder堆叠而成,
右侧部分为解码器,由若干个(论文中6个)decoder堆叠而成。
Bert原理详细笔记
Bert只用到了Transformer的编码器部分,它的结构图如下:
其中Trm表示一个Transformer的编码器部分
Bert原理详细笔记
真实应用中Trm 不止图中的 2 个,通常有两种结构
Bert原理详细笔记
L表示网络的层数(即Transformer 编码器的数量),A表示Multi-Head Attention中self-Attention的头数,H 是 隐层单元的维度

3.2 masked LM

掩码语言模型的提出就是为了防止:自己看见自己
Masked Language Model(MLM)是指在训练的时候随机从输入语料上mask掉一些单词,然后通过的上下文预测该单词,该任务非常像我们在中学时期经常做的完形填空。这一点是非常不同于RNN语言模型的。比如输入 A, B,C

  1. RNN模型
    p(ABC) = P(A)*p(B|A)*p(C|AB)
  2. Bert
    假如把B给 mask掉,则 P(ABC) = P(B| AC)

为了使模型更加稳定,作者不单单是随机mask掉 15%的单词,他还增加了一点点小噪声(有点像dropout的思想),具体如下:

随机mask语料中15%的token,对于[Mask]这个符号,由于在测试集中不存在,为了减轻训练和预测之间的不匹配,作者按一定的比例在需要预测的token上动了手脚,如:my dog is hairy,则:在15%的单词当中

  • 有80%的概率用“[mask]”标记来替换——my dog is [MASK]
  • 有10%的概率用随机采样的一个单词来替换——my dog is apple
  • 有10%的概率不做替换——my dog is hairy

3.3 bert句级别任务

假如我们要做一个分类任务

  • 利用RNN的话,我们只需要最后一个隐层状态,再它的基础上搭一个线性分类器就行,因为最后一个隐层状态h,就代表了整句话的意思,如图
    Bert原理详细笔记
  • 而 transformer encoder 不一样,如图:y1, y2, y3,y4只能分别代表 单词 w1,w2,w3,w4在上下文中的意思,而不能代表整句话的意思,因此我们无从搭分类器。
    Bert原理详细笔记
  • bert 是如何解决这个问题的呢??, 它在输入句子的前面加了一个 [CLS] 符号,我们可以把这个符号看做是整个输入句子的象征, 那么它对应的输出C就可以代表整句话的意思了,如图:
  • Bert原理详细笔记

假如我们要做一个问答系统,也就是输入有两句话,那么bert又做了什么呢??

–为什么要提出这个预训练任务呢,主要也是很多譬如问答、推理之类的任务,更多的是要学习句子之间的关系,这是语言模型无法做到的,因为语言模型根据token预测token,是在句子内部进行学习的。

bert在训练时会判断这两个输入句子是否是连续的,相关的,也就是它会做一个二分类任务,若两个句子是挨在一起的,那么预测为1,否则为0。每个句子的结尾以 [SEP] 作为分隔符。
Bert原理详细笔记
那么句子如何选取呢??训练的时候,输入到模型的第二个句子会以50%的可能从全部文本中随机选取,剩下50%的可能从紧挨着第一个句子的文本中选取

这样看来,模型就有两个损失函数了,一个是做完形填空时产生的,一个是做二分类时产生的,两个损失函数之就是bert总的损失函数了。源码片段:
Bert原理详细笔记

3.4 bert输入表示

Bert原理详细笔记
bert将输入句子转化为词向量,是经过了3 个Embedding 的加和, 即
input_embed = Token_embed + Sentence_embed + Position_embed.
源码是:
Bert原理详细笔记
Bert原理详细笔记
maxLen:批训练时,最大句子长度。d_model:词嵌入的维度,n_segments:表示输入多少句话,一般最大取2
用pytorch调用模型的话,我们只需要输入:

  1. input_ids:一个形状为[batch_size, sequence_length]的 torch.LongTensor,在词汇表中包含单词的token索引, 注意 在句子首尾分别加了 [cls] 和 [sep] 的 索引
  2. segment_ids :形状[batch_size, sequence_length]的可选 torch.LongTensor,在0, 1中选择token类型索引。类型0对应于句子A,类型1对应于句子B。如 [0,0,0,0,0,1,1,1,1,1], 0代表第一个句子A, 1代表第二个句子B,默认全为0
  3. input_mask:一个可选的 torch.LongTensor,形状为[batch_size, sequence_length],索引在0, 1中选择。0 是 padding 的位置,1是没有padding的字

3.5 bert常见应用

  • 情感分析: 提取 [CLS] 的输出 C,在其上搭分类器,如逻辑回归,SVM等,做fine-tuning
  • 特征提取:提取 每个单词的词向量,再运用到其他任务中。
    对于测试集中的一句话如:Help prince Meyuko ?, 我们把它放到已经训练完的Bert上面,那么我们就可以得到这句话每层的输出了, 也就是每层每个单词的上下文表达,图中每一列由黄到红就是每个单词不同层面的上下文表达。
  • Bert原理详细笔记
    至于那一层效果最好,我们有这个实验
    Bert原理详细笔记
    效果最好的是:最后四层的拼接

3.6 bert的其他应用

Bert原理详细笔记
MNLI(Multi-Genre Natural Language Inference):给定一对句子,目标是预测第二句子和第一个句子是相关的、无关的还是矛盾的。
QQP(Quora Question Pairs):判断两个问句是否是同一个意思。
QNLI (Question Natural Language Inference):样本是(question,sentence)在一段文本中sentence是否是question的答案。
STS-B(Semantic Textual Similarity Benchmark):给出一对句子, 使用1~5的评分评价两者在语义上的相似程度。
MRPC (Microsoft Research Paraphrase Corpus):句子对来源于对同一条新闻的评论. 判断这一对句子在语义上是否相同。
RTE(Recognizing Textual Entailment):是一个二分类问题, 类似于MNLI, 但是数据量少很多。

SST-2(The Stanford Sentiment Treebank):单句的二分类问题, 句子的来源于人们对一部电影的评价, 判断这个句子的情感。
CoLA (The Corpus of Linguistic Acceptability):单句的二分类问题, 判断一个英文句子在语法上是不是可接受的。

SQuAD(Standford Question Answering Dataset):给定一个问题和一个来自包含答案的Wikipedia段落,任务是预测答案在段落中所在的位置。
CoNLL-2003 NER命名实体识别任务,应该是大家最熟悉的了,预测每个字的标签是什么。

总体来说对于(a)(b)中的任务,我们取得的是最终CLS位置的输出C。对于(c)中的任务主要是预测start和end标记所在的最大值,且是start的id值小于end的id值,其中start是答案所在段落中的起始位置,end是结束位置。对于NER任务,自然是取得每一个单词的输出的表达,后面再接一个CRF。