bert学习笔记

预训练模型的对比

Posted by yangwf on May 10, 2019

预训练

  • Feature-based:将训练出的representation作为feature用于任务,从词向量、句向量、段向量、文本向量都是这样的。新的ELMo也属于这类,但迁移后需要重新计算出输入的表征。
  • Fine-tuning:这个主要借鉴于CV,就是在预训练好的模型上加些针对任务的层,再对后几层进行精调。新的ULMFit和OpenAI GPT属于这一类。

ELMo

ELMo是从双向语言模型(BiLM)中提取出的Embedding。训练时使用BiLSTM,给定N个tokens (t1, t2,…,tN), 目标为最大化:

ELMo对于每个token $t_k$ , 通过一个L层的biLM计算出2L+1个表示:

其中$h_{k,0}^{LM}$ 是对token进行直接编码的结果(这里是字符通过CNN编码),

$h_{k,j}^{LM} = [\overrightarrow{h}{k,j}^{LM}; \overleftarrow{h}{k, j}^{LM}]$ 是每个biLSTM层输出的结果。

应用中将ELMo中所有层的输出R压缩为单个向量,$ELMo_k = E(R_k;\Theta \epsilon)$ , 最简单的压缩方法是取最上层的结果做为token的表示:$E(R_k) = h_{k,L}^{LM}$ , 更通用的做法是通过一些参数来联合所有层的信息:

其中$s_j$ 是softmax出来的权重,$\gamma$是一个任务相关的scale参数,在优化过程中很重要,同时因为每层BiLM的输出分布不同,$\gamma$可以对层起到normalisation的作用。

优点

效果好,在大部分任务上都较传统模型有提升。实验正式ELMo相比于词向量,可以更好地捕捉到语法和语义层面的信息。

传统的预训练词向量只能提供一层表征,而且词汇量受到限制。ELMo所提供的是character-level的表征,对词汇量没有限制。

缺点

速度较慢,对每个token编码都要通过language model计算得出。

OpenAI GPT

Unsupervised pre-training

第一阶段的目标是预训练语言模型,给定tokens的语料$U = {u_{1}, …, u_{n}}$ ,目标函数为最大化似然函数:

该模型中应用multi-headed self-attention,并在之后增加position-wise的前向传播层,最后输出一个分布

Supervised fine-tuning

有了预训练的语言模型之后,对于有标签的训练集$C$ ,给定输入序列 $x^{1}, …, x^{m}$ 和标签 $y$,可以通过语言模型得到$h_{l}^{m}$,经过输出层后对 $y$进行预测:

则目标函数为:

整个任务的目标函数为:

优点

循环神经网络所捕捉到的信息较少,而Transformer可以捕捉到更长范围的信息。

计算速度比循环神经网络更快,易于并行化

实验结果显示Transformer的效果比ELMo和LSTM网络更好

缺点

对于某些类型的任务需要对输入数据的结构作调整

双向

这种「双向」的来源在于 BERT 与传统语言模型不同,它不是在给定所有前面词的条件下预测最可能的当前词,而是随机遮掩一些词,并利用所有没被遮掩的词进行预测。

结合优势

ELMo 使用两条独立训练的 LSTM 获取双向信息,而 OpenAI GPT 使用新型的 Transformer 和经典语言模型只能获取单向信息。BERT 的主要目标是在 OpenAI GPT 的基础上对预训练任务做一些改进,以同时利用 Transformer 深度模型与双向信息的优势。

对比OpenAI GPT,BERT是双向的Transformer block连接;就像单向rnn和双向rnn的区别,直觉上来讲效果会好一些。

对比ELMo,虽然都是“双向”,但目标函数其实是不同的。ELMo是分别以$P(w_i| w_1, …w_{i-1})$和$P(w_i|w_{i+1}, …w_n)$作为目标函数,独立训练处两个representation然后拼接,而BERT则是以$P(w_i|w_1, …,w_{i-1}, w_{i+1},…,w_n)$作为目标函数训练LM。

输入

Token Embeddings是词向量,第一个单词是CLS标志,可以用于之后的分类任务

Segment Embeddings用来区别两种句子,因为预训练不光做LM还要做以两个句子为输入的分类任务

Position Embeddings和之前文章中的Transformer不一样,不是三角函数而是学习出来的

  1. Did you use pre-trained WordPiece embedding or just use a model to segment words to pieces and learn the embedding in your model?

  2. What is Sentence A embedding and Sentence B embedding? Did you use pre-trained sentence emedding or use another structure to learn a sentence emdedding or just learn a vector for difference parts of the concatenated sentence which is independent of the content?

  3. Wordpiece is just a way of breaking down rare words into word fragments that are more frequent, so that you have more signals during training. It is similar to the unigrams idea used in Fasttext.

    The word embeddings are not pre-trained, i.e. they don’t use any Word2vec or GloVe. They’re trained during the BERT training process.

    These embeddings can of course be used in a similar way as Word2Vec or GloVe, but it was recommended to use not only the embedding layer, but an average/concatenation of the embedding + some of the later Transformer feature layers.

  4. example

    image-20190425112611760

核心

ELMo 使用两条独立训练的 LSTM 获取双向信息,而 OpenAI GPT 使用新型的 Transformer 和经典语言模型只能获取单向信息。BERT 的主要目标是在 OpenAI GPT 的基础上对预训练任务做一些改进,以同时利用 Transformer 深度模型与双向信息的优势。

next setence prediction

因为要建模句子之间的关系,BERT 有一个任务是预测 B 句是不是 A 句后面的一句话,而这个分类任务会借助 A/B 句最前面的特殊符 [CLS] 实现,该特殊符可以视为汇集了整个输入序列的表征。

最后的位置编码是 Transformer 架构本身决定的,因为基于完全注意力的方法并不能像 CNN 或 RNN 那样编码词与词之间的位置关系,但是正因为这种属性才能无视距离长短建模两个词之间的关系。因此为了令 Transformer 感知词与词之间的位置关系,我们需要使用位置编码给每个词加上位置信息。

The other thing that’s missing from an LM is that it doesn’t understand relationships between sentences, which is important for many NLP tasks. To pre-train a sentence relationship model, we use a very simple binary classification task, which is to concatenate two sentences A and B and predict whether B actually comes after A in the original text.

mask

对于 Mask 预测任务,首先整个序列会随机 Mask 掉 15% 的词,这里的 Mask 不只是简单地用「[MASK]」符号代替某些词,因为这会引起预训练与微调两阶段不是太匹配。所以谷歌在确定需要 Mask 掉的词后,80% 的情况下会直接替代为「[MASK]」,10% 的情况会替代为其它任意的词,最后 10% 的情况会保留原词。

每个输入token的上下文嵌入向量指预训练模型隐藏层生成的定长上下文表征。

注意最后 10% 保留原句是为了将表征偏向真实观察值,而另外 10% 用其它词替代原词并不会影响模型对语言的理解能力,因为它只占所有词的 1.5%(0.1 × 0.15)。此外,作者在论文中还表示因为每次只能预测 15% 的词,因此模型收敛比较慢。

we feed the input through a deep Transformer encoder and then use the final hidden states corresponding to the masked positions to predict what word was masked, exactly like we would train a language model.

预训练#1

第一步预训练的目标就是做语言模型,从上文模型结构中看到了这个模型的不同,即bidirectional。直觉上来讲我们其实想要一个deeply bidirectional的模型,但是普通的LM又无法做到,因为在训练时可能会“穿越”(关于这点我不是很认同,之后会发文章讲一下如何做bidirectional LM)。所以作者用了一个加mask的trick。

在训练过程中作者随机mask 15%的token,而不是把像cbow一样把每个词都预测一遍。最终的损失函数只计算被mask掉那个token。

Mask如何做也是有技巧的,如果一直用标记[MASK]代替(在实际预测时是碰不到这个标记的)会影响模型,所以随机mask的时候10%的单词会被替代成其他单词,10%的单词不替换,剩下80%才被替换为[MASK]。具体为什么这么分配,作者没有说。。。要注意的是Masked LM预训练阶段模型是不知道真正被mask的是哪个词,所以模型每个词都要关注。

预训练#2

因为涉及到QA和NLI之类的任务,增加了第二个预训练任务,目的是让模型理解两个句子之间的联系。训练的输入是句子A和B,B有一半的几率是A的下一句,输入这两个句子,模型预测B是不是A的下一句。预训练的时候可以达到97-98%的准确度。

注意:作者特意说了语料的选取很关键,要选用document-level的而不是sentence-level的,这样可以具备抽象连续长序列特征的能力。

微调

  • 单句分类:BERT直接取第一个[CLS]token的final hidden state $C\in\Re^H$,加一层权重 W\in\Re^{K\times H} 后softmax预测label proba ($K$为分类任务的类别数目):

  • 问答:BERT需要在微调阶段学习两个向量:开始向量(start)$S\in\Re^H$和结束向量(end)$E\in\Re^H$。另外,我们将第$i$个token从BERT中输出的最终隐向量用$T_i\in\Re^H$表示。则第$i$个token是答案区段的起点的概率为(终点同理):

​ 得分最高的区段作为最终的预测值,其训练时的目标函数为正确答案起始位置好结束位置的log似然。在推理时,由于结束符的预测不以开始符为条件先验,我们添加了结束符必须在开始符之后的约束,但没有使用其他启发规则。 tokenized的标记跨度与原始untokenized的输入对齐以进行评估。

  • 句对分类:BERT分别选取四组句对的第一个[CLS]token的final hidden state $C\in\Re^H$,加一层权重 $V\in\Re^{H}$ 后softmax取最大的proba作为最终分类结果:

优点

它还用的是Transformer,也就是相对rnn更加高效、能捕捉更长距离的依赖。对比起之前的预训练模型,它捕捉到的是真正意义上的bidirectional context信息。

缺点

  • [MASK]标记在实际预测中不会出现,训练时用过多[MASK]影响模型表现
  • 每个batch只有15%的token被预测,所以BERT收敛得比left-to-right模型要慢(它们会预测每个token)