NLP发展-从语言模型到预训练模型

NLP发展-从语言模型到预训练模型

原文来自https://zhuanlan.zhihu.com/p/50443871 《NLP的巨人肩膀》,本文是对此文的提炼和总结,另外对一些模型加了细节。首先NLP的发展可以从如下title得出,重点是word2vec、glove、fastText、elmo、gpt和bert。

下面是NLP从语言模型到预训练模型的总结表:

NLP发展历程论文备注源码源码
1.语言模型---
2.神经网络语言模型A Neural Probabilistic Language Model2003年-
3.word2vec1.Efficient estimation of word representations in vector space
2.Distributed Representations of Words and Phrases and their Compositionality
word2vec主要是CBOW和skip-gram
第2篇论文是讲了skip-gram的训练优化
2013年
code.google.com/p/word2vec/
4.GloveGloVe:Global Vectors for Word Representation2014年http://nlp.stanford.edu/projects/glove/
5.fasttext1.Enriching Word Vectors with Subword Information
2.Bag of Tricks for Efficient Text Classification
2篇文章,一个是分类,一个是词分布 2016年https://github.com/facebookresearch/fastText
以上是词向量级别的,下面是句子级别的向量
6.PV-DM&PV-DBOWDistributed Representations of Sentences and Documents2014年-
7.Skip-ThoughtSkip-Thought Vectors2015年https://github.com/ryankiros/skip-thoughts
8.Quick-ThoughtAn efficient framework for learning sentence representations2018年https://github.com/tensorflow/models/tree/master/research/skip_thoughts
9.InferSentSupervised Learning of Universal Sentence Representations from Natural Language Inference Data2017年https://www.github.com/facebookresearch/InferSent
10.GPSELearning General Purpose Distributed Sentence Representations via Large Scale Multi-task Learning2018年https://github.com/maluuba/gensen
11.USEUniversal Sentence Encoder2018年
下面部分是目前常见的预训练模型
12.CoveLearned in Translation: Contextualized Word Vectors2017年
13.ELMODeep contextualized word representations2018年http://allennlp.org/elmo
14.ULMFitUniversal Language Model Fine-tuning for Text Classification2018年http://nlp.fast.ai/ulmfit
15.GPTImproving Language Understanding by Generative Pre-Training2018年
16.BERTBERT: Pre-training of Deep Bidirectional Transformers for Language Understanding2018年https://github.com/google-research/bert
17.预训练模型XLNet/ALBERT…

1.语言模型

对于一段自然语言的文本 S i S_{i} Si,语言模型的本质就是计算该文本序列的概率 P ( S i ) P(S_{i}) P(Si) 。根据大数定律中频率对于概率无限逼近的思想,求这个概率的大小,自然需要使用这个文本序列在人类历史上产生过的所有文本集合,那么这个文本的频率 P ( S i ) P(S_{i}) P(Si)可以通过下面这个公式得到:
P ( S i ) = c ( S i ) ∑ j = 0 ∞ c ( S j ) P(S_{i})=\frac{c(S_{i})}{\sum^{\infty}_{j=0}c(S_{j})} P(Si)=j=0c(Sj)c(Si)
很显然,这种语料的统计是无法实现。为了可实现,有人讲文本拆散成一个个的词,通过每个词之间的概率关系,从而求得整个文本的概率大小。假设文本句子的长度为 T T T,词用 x x x表示,因此上述公司可以表示为:
P ( X i ) = P ( x 0 , x 1 , . . . , x T ) = P ( x 0 ) P ( x 1 ∣ x 0 ) . . . P ( x T ∣ x 0 , x 1 , . . . , x T − 1 ) P(X_{i})=P(x_{0},x_{1},...,x_{T})=P(x_{0})P(x_{1}|x_{0})...P(x_{T}|x_{0},x_{1},...,x_{T-1}) P(Xi)=P(x0,x1,...,xT)=P(x0)P(x1x0)...P(xTx0,x1,...,xT1)
但是对于上式的计算依然很复杂,一般会引入马尔科夫假设:假定一个句子中的词只与它前面n个词有关,当n=1的时候,句子的概率计算公式最为简洁:
P ( X i ) = P ( x 0 , x 1 , . . . , x T ) = P ( x 0 ) P ( x 1 ∣ x 0 ) . . . P ( x T ∣ x T − 1 ) = P ( x 0 ) ∏ i = 0 T − 1 P ( x i + 1 ∣ x i ) P(X_{i})=P(x_{0},x_{1},...,x_{T})=P(x_{0})P(x_{1}|x_{0})...P(x_{T}|x_{T-1})=P(x_{0})\prod _{i=0}^{T-1}P(x_{i+1}|x_{i}) P(Xi)=P(x0,x1,...,xT)=P(x0)P(x1x0)...P(xTxT1)=P(x0)i=0T1P(xi+1xi)
并且可以把词频的统计用来估计这个语言模型的条件概率,如下公式:
P ( x i + 1 ∣ x i ) = c ( x i + 1 , x i ) c ( x i ) P(x_{i+1}|x_{i})=\frac{c(x_{i+1}, x_{i})}{c(x_{i})} P(xi+1xi)=c(xi)c(xi+1,xi)
通过如上的步骤使得语言模型的计算变得可行。但是,这种基于统计的语言模型也有很多问题,如下:

  • c ( x i + 1 , x i ) c(x_{i+1},x_{i}) c(xi+1,xi)会遇到很多零值,当n取值很大的时候,由于数据稀疏导致的计算为0的现象特别严重
  • 计算复杂度随着n指数上升,一般3-gram比较常见
  • 统计的语言模型无法表征词语之间的相似性

2.NNLM

使语言模型变得困难的基本问题是维度灾难(curse of dimensionality),为了解决这个问题2003年Bengio在其论文《A Neural Probabilistic Language Model》首次在语言模型中应用了深度学习的思想。

NNLM的模型结构图(图片出自原论文):

在这里插入图片描述

其训练目标函数如下:
L = 1 T ∑ t l o g P ( w t ∣ w t − 1 , . . . , w t − n + 1 ; θ ) + R ( θ ) L=\frac{1}{T}\sum_{t}logP(w_{t}|w_{t-1},...,w_{t-n+1};\theta)+R(\theta) L=T1tlogP(wtwt1,...,wtn+1;θ)+R(θ)

P ( w t ∣ w t − 1 , . . . , w t − n + 1 ; θ ) = e y w t ∑ i e y i P(w_{t}|w_{t-1},...,w_{t-n+1};\theta)=\frac{e^{y_{wt}}}{\sum_i{e^{yi}}} P(wtwt1,...,wtn+1;θ)=ieyieywt

其中 y i y_{i} yi 是每一次输出单词 i i i的非归一化的概率大小,其计算公式如下:
y = b + W x + U t a n h ( d + H x ) y=b+Wx+Utanh(d+Hx) y=b+Wx+Utanh(d+Hx)

x = ( C ( w t − 1 ) , C ( w t − 2 ) , . . . , C ( w t − n + 1 ) ) x=(C(w_{t-1}),C(w_{t-2}),...,C(w_{t-n+1})) x=(C(wt1),C(wt2),...,C(wtn+1))

其中, x x x实际上式通过矩阵 C C C映射为 m m m维的单词特征向量,然后将这 n − 1 n-1 n1个词的向量concat起来,组合成一个 ( n − 1 ) ∗ m (n-1)*m (n1)m 维的向量。

这里可以将NNLM的网络结构拆分为三个部分: 第一部分,从词到词向量的映射,通过C矩阵完成映射,参数个数为 |V| * m(V是词表的大小); 第二部分,从x到隐藏层的映射,通过矩阵H(H是隐藏层单元数大小),这里的参数个数为 |H| * m * (n-1); 第三部分,从隐藏层到输出层的映射,通过矩阵U,参数个数为|V| * |H| 第四部分,从x到输出层的映射,通过矩阵W,参数个数为|V| * m * (n-1);

因此,如果算上偏置项的参数个数(其中输出层为|V|,输入层到隐藏层为|H|)的话,NNLM的参数个数为:
∣ V ∣ ( 1 + m n + ∣ H ∣ ) + ∣ H ∣ ( 1 + n m − m ) |V|(1+mn+|H|)+|H|(1+nm-m) V(1+mn+H)+H(1+nmm)
可以看出的是NNLM模型的参数个数取决于窗口大小n,原论文的实验设置n=5,而且论文中用了40块CPU,在含有1400万个词的数据集(词表大小是17964)上训练5个epoch耗时超过3周。

缺点:

  • n大小是5,虽然比之前的统计语言模型好,但是还是不能解决长依赖
  • 训练依旧很耗时

3.word2vec

在NNLM提出后,相继有其他的类似和改进模型出现,如2007年Mnih和Hinton提出的LBL以及后续的一系列相关模型,省去了NNLM中的激活函数,直接把模型变成了一个线性变换,尤其是后来将Hierarchical Softmax引入到LBL后,训练效率进一步增强,但是表达能力不如NNLM这种神经网络的结构。2008年Collobert和Weston 提出的C&W模型不再利用语言模型的结构,而是将目标文本片段整体当做输入,然后预测这个片段是真实文本的概率,所以它的工作主要是改变了目标输出,由于输出只是一个概率大小,不再是词典大小,因此训练效率大大提升,但由于使用了这种比较“别致”的目标输出,使得它的词向量表征能力有限。2010年Mikolov提出的RNNLM主要是为了解决长程依赖关系,时间复杂度问题依然存在。

  • 2007年LBL模型,并引入层次softmax
  • 2008年C&W模型
  • 2010年 RNNLM模型

2013年,Mikolov相继放出两篇重要的论文,《Efficient estimation of word representations in vector space》首次提出了CBOW和Skip-gram模型,进一步的在《Distributed Representations of Words and Phrases and their Compositionality》中,又介绍了几种优化训练的方法,包括Hierarchical Softmax、Negative Sampling和Subsampling技术。

word2vec其实是一种工具,背后的模型是CBOW和Skip-gram模型,并且使用了Hierarchical Softmax、Negative Sampling和Subsampling技术优化了训练方法。下面具体介绍CBOW和Skip-gram模型。

CBOW(Continuous Bag of Words):连续词袋模型,其思想是在给定背景词序列情况下某中心词的概率

其模型结构如下(原图出自作者weizier):

在这里插入图片描述

其目标函数:
1 T ∑ t = 1 T l o g P ( w t ∣ c t ) \frac{1}{T}\sum_{t=1}^{T}logP(w_{t}|c_{t}) T1t=1TlogP(wtct)

P ( w t ∣ c t ) = e x p ( e ′ ( w t ) T x ) ∑ i = 1 ∣ V ∣ e x p ( e ′ ( w i ) T x ) , x = ∑ i ∈ c e ( w i ) P(w_{t}|c_{t})=\frac{exp(e'({w_{t}})^{T}x)}{\sum_{i=1}^{|V|}exp(e'({w_{i}})^{T}x)},x=\sum_{i\in c}e(w_{i}) P(wtct)=i=1Vexp(e(wi)Tx)exp(e(wt)Tx),x=ice(wi)

从模型结构图和目标函数可以看出,CBOW没有多余的隐藏层,本质上只有两层结构,输入层将目标词语境c中的每一个词向量简单求和(或求平均)后得到语境向量,然后直接与目标词的输出向量求点积,目标函数也就是让这个与目标词向量的点积取得最大值。

需要注意的是,这里每个词对应两个词向量, e ( w t ) e(w_{t}) e(wt)是词的输入向量,而 e ′ ( w t ) e'(w_{t}) e(wt)则是词的输出向量。其实这里的两个词向量,对应着模型结构图中的两个权重矩阵 W W W W ′ W' W分别和输入词和输出词的位置索引值相乘。

模型特点:

  • 取消了NNLM中的隐藏层,直接将输入层和输出层相连
  • 求语境context相连的时候,语境中的词序已经被丢弃
  • 最终的目标函数仍是语言模型的目标函数,仍遍历语料中的每个词

Skip-gram:跳词模型,其思想是给定中心词生成背景词的概率

其模型结构图如下(原图出自作者weizier):

在这里插入图片描述

其目标函数:
1 T ∑ t = 1 T ∑ j ∈ c l o g P ( w j ∣ w t ) \frac{1}{T}\sum_{t=1}^{T}\sum_{j\in c}logP(w_{j}|w_{t}) T1t=1TjclogP(wjwt)

P ( w j ∣ c t ) = e x p ( e ′ ( w j ) T e ( w t ) ) ∑ i = 1 ∣ V ∣ e x p ( e ′ ( w i ) T e ( w t ) ) P(w_{j}|c_{t})=\frac{exp(e'({w_{j}})^{T}e(w_{t}))}{\sum_{i=1}^{|V|}exp(e'({w_{i}})^{T}e(w_{t}))} P(wjct)=i=1Vexp(e(wi)Te(wt))exp(e(wj)Te(wt))

可以看出目标函数中有两个求和符号,最里面的求和符号的意义便是让当前的输入词分别和该词对应语境中的每一个词都尽量接近,从而便可以表现为该词与其上下文尽量接近。

和CBOW类似,Skip-gram本质上也只有两层:输入层和输出层,输入层负责将输入词映射为一个词向量,输出层负责将其经过线性映射计算得到每个词的概率大小。再细心一点的话,其实无论CBOW还是Skip-gram,本质上都是两个全连接层的相连,中间没有任何其他的层。因此,这两个模型的参数个数都是 2 × ∣ m ∣ × ∣ V ∣ 2\times |m|\times |V| 2×m×V ,其中|m|和|V|分别是词向量的维度和词典的大小,相比上文中我们计算得到NNLM的参数个数 ∣ V ∣ ( 1 + m n + ∣ H ∣ ) + ∣ H ∣ ( 1 + n m − m ) |V|(1+mn+|H|)+|H|(1+nm-m) V(1+mn+H)+H(1+nmm)已经大大减小,且与上下文所取词的个数无关了,也就是终于避免了N-gram中随着阶数N增大而使得计算复杂度急剧上升的问题。

3.1word2vec的优化

暂时略过(层次softmax、负采样、二次抽样)todo


4.Glove

GloVe的全称叫Global Vectors for Word Representation,它是一个基于全局词频统计(count-based & overall statistics)的词表征(word representation)模型方法(和LSA有点像,本质上相同)。

Glove的目标函数(损失函数):

J = ∑ i , j = 1 V f ( X i j ) ( w i T w j + b i + b j − l o g X i j ) 2 J=\sum_{i,j=1}^{V}f(X_{ij})(w_{i}^{T}w_{j}+b_{i}+b_{j}-logX_{ij})^{2} J=i,j=1Vf(Xij)(wiTwj+bi+bjlogXij)2
这个目标函数是如何推出来的呢?文中以一个简单的例子来介绍如何从共现概率中得到单词的特定意义。

首先定义一些符号:

  • X X X:统计共现矩阵

  • X i j X_{ij} Xij:单词j在单词i的上下文出现的次数

  • X i = ∑ k X i k X_{i}=\sum_kX_{ik} Xi=kXik:表示任何单词出现在单词i的上下文次数

  • P i j = P ( j ∣ i ) = X i j / X i P_{ij}=P(j|i)=X_{ij}/X_{i} Pij=P(ji)=Xij/Xi:表示单词j出现在单词i的上下文的概率

如下图(图片出自原论文),考虑两个在某些方面比较类似的词:i代表ice,j代表steam。这两个词的关系可以通过研究它们与某个词k的共现概率之比来得到。例如,k是某个和ice相关但是和steam无关的词,比如k = solid,那么 P i k / P j k P_{ik}/P_{jk} Pik/Pjk将会很大;而当k和steam相关但是和ice无关时,比如k = gas,这个比值将会很小。还有k和两个词都相关(k=water)或者和两个词都不相关(k=fashion),这个比值将接近于1。

在这里插入图片描述

综上,词向量的学习应该从共现概率的比值开始而不是概率本身,由于 P i k / P j k P_{ik}/P_{jk} Pik/Pjk依赖于三个词i,j和k,因此模型的一般形式如下:
F ( w i , w j , w k ~ ) = P i k P j k F(w_{i},w_{j},\tilde{w_{k}})=\frac{P_{ik}}{P_{jk}} F(wi,wj,wk~)=PjkPik
从这个一般形式到最终形式,文本有一个具体的推导过程,感兴趣的可以去翻论文,这里就不再赘述。

当然,对于共现概率Glove对其做了一些改进,增加了一个衰减系数,使得距离越远的词对共现频率越小一些, f ( X i j ) f(X_{ij}) f(Xij)是权重系数,论文中队对个权重系数有一个具体的定义过程。

可以从GloVe使用的损失函数中发现,它的训练主要是两个步骤:统计共现矩阵和训练获取词向量,这个过程其实是没有我们通常理解当中的模型的,更遑论神经网络,它整个的算法框架都是基于矩阵分解的做法来获取词向量的,本质上和诸如LSA这种基于SVD的矩阵分解方法没有什么不同,只不过SVD分解太过于耗时,运算量巨大,相同点是LSA也是输入共现矩阵,不过一般主要以词-文档共现矩阵为主,另外,LSA中的共现矩阵没有做特殊处理,而GloVe考虑到了对距离较远的词对做相应的惩罚等等。

模型特点:

  • 对比word2vec,利用了词共现信息
  • 对比LSA,对距离远的词做了惩罚

5.fastText

fastText其实有两篇论文,一篇是文本分类《Bag of Tricks for Efficient Text Classification》,另一篇是词向量《Enriching Word Vectors with Subword Information》。严格意义来说,fastText进行文本分类的同时也会产生词的embedding,即embedding是fastText分类的产物。

word2vec和GloVe都不需要人工标记的监督数据,只需要语言内部存在的监督信号即可以完成训练。而与此相对应的,fastText则是利用带有监督标记的文本分类数据完成训练,本质上没有什么特殊的,模型框架就是CBOW,只不过与普通的CBOW有两点不一样,分别是输入数据和预测目标的不同,在输入数据上,CBOW输入的是一段区间中除去目标词之外的所有其他词的向量加和或平均,而fastText为了利用更多的语序信息,将bag-of-words变成了bag-of-features,也就是下图中的输入x不再仅仅是一个词,还可以加上bigram或者是trigram的信息等等(词向量的加和求平均会丢失词顺序的信息,增加n-gram的原因)。第二个不同在于,CBOW预测目标是语境中的一个词,而fastText预测目标是当前这段输入文本的类别,正因为需要这个文本类别,因此才说fastText是一个监督模型。而相同点在于,fastText的网络结构和CBOW基本一致,同时在输出层的分类上也使用了Hierachical Softmax技巧来加速训练。

fastText模型结构图(图片出自原论文)如下:

在这里插入图片描述

fastText的目标函数:
− 1 N ∑ n = 1 N y n l o g f ( B A x n ) , x n = ∑ i = 1 l n x n , i -\frac{1}{N}\sum_{n=1}^{N}y_{n}logf(BAx_{n}),x_{n}=\sum_{i=1}^{l_{n}}x_{n,i} N1n=1Nynlogf(BAxn),xn=i=1lnxn,i
这里的 x n , i x_{n,i} xn,i是语料中第n篇文档的第i个词以及加上N-gram的特征信息,从这个损失函数便可以知道fastText同样只有两个全连接层,分别是A和B,其中A便是最终可以获取的词向量信息。

值得注意的是,为什么fastText有fast前缀,是因为其最大的特点是快,其快的原因体现在下面几点:

  • 预测的是文本的类别,K远小于词表V
  • 使用hierarchical softmax加速
  • 由于使用的是n-gram特征,其数量远大于word,使用hash桶的方式来存储,同一个桶的n-gram共享embedding
  • 训练过程采用预计算的方法,直接查表

更多的训练细节可见原论文的开源项目https://github.com/facebookresearch/fastText。


小总结:

以上均是通过训练学习到词向量的表征,自word2vec的出现极大促进了NLP领域的发展,《NLP的巨人肩膀》的作者weizier认为word2vec的贡献远不止是给每一个词赋予一个分布式的表征它带来了一种全新的NLP模型建立方法,在这之前,大多数NLP任务都要在如何挖掘更多文本语义特征上花费大量时间,甚至这一部分工作占去了整个任务工作量的绝大部分,而以word2vec为代表的distributed representation方法大量涌现后(尤其是因为大规模语料上的预训练词向量成为现实,并且被证明确实行之有效之后),算法人员发现利用word2vec在预训练上学习到的词向量,初始化他们自己模型的第一层,会带来极大效果的提升,以至于这五年以来,几乎一个业内的默认做法便是要用了无论word2vec还是GloVe预训练的词向量,作为模型的第一层。

当然除了在词级别的embedding方法上基础上,有大量基于char级别、句子级别的和段落级别的模型被提出。


6.PV-DM和PV-DBOW

2014年,Mikolov基于word2vec的CBOW和Skip-gram模型(word2vec也是他提的)基础上,提出了文档级别的向量模型分别是PV_DM和PV-DBOW,论文《Distributed Representations of Sentences and Documents》。PV-DM的全称是Distributed Memory Model of Paragraph Vectors,和CBOW类似,也是通过上下文预测下一个词,不过在输入层的时候,同时也维护了一个文档ID映射到一个向量的look-up table,模型的目的便是将当前文档的向量以及上下文向量联合输入模型,并让模型预测下一个词,训练结束后,对于现有的文档,便可以直接通过查表的方式快速得到该文档的向量,而对于新的一篇文档,那么则需要将已有的look-up table添加相应的列,然后重新走一遍训练流程,只不过此时固定好其他的参数,只调整look-up table,收敛后便可以得到新文档对应的向量了。PV-DBOW的全称则是Distributed Bag of Words version of Paragraph Vector,和Skip-gram类似,通过文档来预测文档内的词,训练的时候,随机采样一些文本片段,然后再从这个片段中采样一个词,让PV-DBOW模型来预测这个词,以此分类任务作为训练方法,说白了,本质上和Skip-gram是一样的。这个方法有个致命的弱点,就是为了获取新文档的向量,还得继续走一遍训练流程,并且由于模型主要是针对文档向量预测词向量的过程进行建模,其实很难去表征词语之间的更丰富的语义结构,所以这两种获取文档向量的方法都未能大规模应用开来。

其模型结构图(图片出自原论文)如下:

在这里插入图片描述

7.Skip-thought

2015年,多伦多大学的Kiros等人提出了一个很有意思的方法叫Skip-thought,原论文叫《Skip-Thought Vectors》,同样也是借鉴了Skip-gram的思想,但是和PV-DBOW中利用文档来预测词的做法不一样的是,Skip-thoughts直接在句子间进行预测,也就是将Skip-gram中以词为基本单位,替换成了以句子为基本单位,具体做法就是选定一个窗口,遍历其中的句子,然后分别利用当前句子去预测和输出它的上一句和下一句。对于句子的建模利用的RNN的sequence结构,预测上一个和下一个句子时候,也是利用的一个sequence的RNN来生成句子中的每一个词,所以这个结构本质上就是一个Encoder-Decoder框架,只不过和普通框架不一样的是,Skip-thoughts有两个Decoder。在今天看来,这个框架还有很多不完善或者可以改进的地方(作者也在论文中分别提到了这些future works),比如输入的Encoder可以引入attention机制,从而让Decoder的输入不再只是依赖Encoder最后一个时刻的输出;Encoder和Decoder可以利用更深层的结构;Decoder也可以继续扩大,可以预测上下文中更多的句子。

其模型结构图(图片出自原论文)如下:

在这里插入图片描述
当然Skip-thought模型有一个问题是,如果测试数据中含有未登录的词,如何表示这个词?文章中提出了一个词表扩展方法,具体是:利用预训练好的其他的词向量(如word2vec) V w 2 v V_{w2v} Vw2v,该词向量大小要比rnn输入的词向量 V r n n V_{rnn} Vrnn大,然后学习一个矩阵参数 W W W,通过word2vec到rnn输入词向量之间的映射关系 v ′ = W v v'=Wv v=Wv v ∈ V w 2 v , v ′ ∈ V r n n v\in V_{w2v}, v'\in V_{rnn} vVw2v,vVrnn)来解决未登录词的问题。


8.Quick-thought

2018年的时候,在Skip-thoughts的基础上,Google Brain的Logeswaran等人将这一思想做了进一步改进,他们认为Skip-thoughts的Decoder效率太低,且无法在大规模语料上很好的训练(这是RNN结构的通病)。所以他们把Skip-thoughts的生成任务改进成为了一个分类任务,具体说来就是把同一个上下文窗口中的句子对标记为正例,把不是出现在同一个上下文窗口中的句子对标记为负例,并将这些句子对输入模型,让模型判断这些句子对是否是同一个上下文窗口中,很明显,这是一个分类任务。

其模型结构图如下:

在这里插入图片描述


9.InferSent

除了Skip-thoughts和Quick-thoughts这两种不需要人工标记数据的模型之外,还有一些从监督数据中学习句子表示的方法,比如2017年Facebook的研究人员Conneau等人提出的InferSent框架,它的思想特别简单,先设计一个模型在斯坦福的SNLI(Stanford Natural Language Inference)数据集上训练,尔后将训练好的模型当做特征提取器,以此来获得一个句子的向量表示,再将这个句子的表示应用在新的分类任务上,来评估句子向量的优劣。

其模型结构图如下:

在这里插入图片描述

这个框架最底层是一个Encoder,也就是最终要获取的句子向量提取器,然后将得到的句子向量通过一些向量操作后得到句子对的混合语义特征,最后接上全连接层并做SNLI上的三分类任务,做过句子匹配任务的一定知道,这个框架是一个最基本(甚至也是最简陋)的句子匹配框架。对于底层的Encoder来说,论文作者分别尝试了7种模型,然后分别以这些模型作为底层的Encoder结构,然后在SNLI上进行监督训练。训练完成后,在新的分类任务上进行评估,最后发现当Encoder使用BiLSTM with max pooling结构时,对于句子的表征性能最好。


10.General Purpose Sentence Representation

除了InferSent这种单个任务的监督学习外,最新的工作逐渐将多任务的联合学习应用到获取句子的表征中,例如Subramanian等人发表在2018年ICLR上的一篇文章《Learning General Purpose Distributed Sentence Representations via Large Scale Multi-task Learning》中就提出了利用四种不同的监督任务来联合学习句子的表征,这四种任务分别是:Natural Language Inference, Skip-thougts, Neural Machine Translation以及Constituency Parsing等,作者的出发点也特别简单,通用的句子表征应该通过侧重点不同的任务来联合学习到,而不是只有一个特定任务来学习句子表征,后来作者在论文中的实验也确实证明了这点。实验的具体做法是,先用联合学习的方法在上述四个任务上进行训练,训练结束后,将模型的输出作为句子的表征(或者把这个联合学习的模型作为特征提取器),然后直接在这个表征上接上非常简单的全连接层做分类器,并且同时保证最底层的特征提取器中参数不动(也就是只把它当做特征提取器),然后在新的分类任务上做训练(只训练最后接上的全连接层分类器),最后根据训练出来的简单分类器在各自分类任务的测试集上做评估。最后作者惊喜的发现很多任务上他们的简单分类器都要超过当时的最好结果,并且他们还发现联合训练中不同的任务对于句子表征中的不同方面有不同的贡献。


11.Universal Sentence Encoder

同样在2018年,谷歌的Daniel Cer等人在论文《Universal Sentence Encoder》中提出的思路基本和General Purpose Sentence Representation的工作一样,只不过作者提出了利用Transformer和DAN(上文提到过的和CBOW与fastText都神似的《Deep Unordered Composition Rivals Syntactic Methods for Text Classification》)两种框架作为句子的Encoder,Transformer结构更为复杂,参数更多,训练也相对比较耗时,但是一般来说效果会更好一些;对应的,DAN结构简单,只有两个隐藏层(甚至可以减小为只需要一个隐藏层),参数比较少,训练相对比较省时省资源,但是一般来说效果会差一些(并不是绝对,论文中也发现某些场景下DAN的效果甚至更好)。然后作者既在无标记数据上训练,也在监督数据上训练,最后在十个分类任务上进行迁移学习的评估。

最后作者还放出了他们预训练好的Encoder,可以供迁移学习的句子特征提取器使用。两个模型均使用TensorFlow实现,地址:https://tfhub.dev/google/universal-sentence-encoder/1


小总结:

上面介绍的几种获取句子表征的方法,他们的思路均是先训练一个句子表征的encoder,在新的任务上进行训练的时候一般都是只用一个全连接层,然后使用softmax进行分类,分类器足够简单,足够浅层,相比那些在这些分类任务上设计的足够复杂的模型来说简直不值一提,然而令人大跌眼镜的是,结果无一例外的这些简单的分类器都能够比肩甚至超越他们各自时代的最好结果,这不能不说是个惊喜。

另外值得注意的是,无论是Quick-thought还是InferSent,将训练好的encoder应用到新的任务上,其目的都是验证其句子表征的效果。


12.Cove

2017年,Salesforce的Bryan McCann和其他一些人,发表了一篇文章《Learned in Translation: Contextualized Word Vectors》,在这篇文章中,他们首先用一个Encoder-Decoder框架在机器翻译的训练语料上进行预训练,尔后用训练好的模型,只取其中的Embedding层和Encoder层,同时在一个新的任务上设计一个task-specific模型,然后将原先预训练好的Embedding层和Encoder层的输出作为这个task-specific模型的输入,最终在新的任务场景下进行训练。他们尝试了很多不同的任务,包括文本分类,Question Answering,Natural Language Inference和SQuAD等等,并在这些任务中,与GloVe作为模型的输入时候的效果进行比较,实验结果表明他们提出的Context Vectors在不同任务中不同程度的都带来了效果的提升。

其模型结构图如下:

在这里插入图片描述

和上文中提到的诸如Skip-thoughts方法有所不同的是,CoVe更侧重于如何将现有数据上预训练得到的表征迁移到新任务场景中,而之前的句子级任务中大多数都只把迁移过程当做一个评估他们表征效果的手段,因此观念上有所不同。

那么,CoVe似乎通过监督数据上的预训练,取得了让人眼前一亮的结果,是否可以进一步地,撇去监督数据的依赖,直接在无标记数据上预训练呢?


13.ELMO

2018年,AllenNLP的Matthew E. Peters等人在论文《Deep contextualized word representations》中首次提出了ELMo,它的全称是Embeddings from Language Models。ELMO基本框架是一个双层的Bi-LSTM,不过在第一层和第二层之间加入了一个残差结构(一般来说,残差结构能让训练过程更稳定)。

ELMo的基本框架便是2-stacked biLSTM + Residual的结构,不过和普通RNN结构的不同之处在于,ELMo借鉴了2016年Google Brain的Rafal Jozefowicz等人发表的一篇论文《Exploring the Limits of Language Modeling》,其主要改进在于输入层和输出层不再是word,而是变为了一个char-based CNN结构。

输入输出是char-based CNN的优势有三点:

  • CNN能够减少普通做Softmax时全连接层中的必须要有的|V|*h的参数规模,只需要保持CNN内部的参数大小即可,而一般来说,CNN中的参数规模都要比|V|*h的参数规模小得多
  • CNN可以解决OOV (Out-of-Vocabulary)问题
  • 在预测阶段,CNN对于每一个词向量的计算可以预先做好,更能够减轻inference阶段的计算压力

其char-based-CNN结构如下(图片来自https://blog.csdn.net/magical_bubble/article/details/89160032):

在这里插入图片描述

ELMO的模型结构如下(图片来自https://blog.csdn.net/magical_bubble/article/details/89160032,原论文并未给出模型结构图):

在这里插入图片描述


14.ULMFit

同样是2018年,Jeremy Howard等人发表的论文《Universal Language Model Fine-tuning for Text Classification》中,他们提出了ULMFit,本质上他们提出的是一个方法,而不是具体的某种结构或模型,如标题,他们主要把它应用在文本分类的问题上。ELMo相同的地方在于,ULMFit同样使用了语言模型,并且预训练的模型主要也是LSTM,基本的思路也是预训练完成后去具体任务上进行finetune,但是不同的地方也有很多,分别来讲讲。

(1)ULMFit的预训练和finetune过程主要可以分为三个阶段:在大规模语料集上(比如Wikitext 103,有103million个词)先预训练,然后再将预训练好的模型在具体任务的数据上重新利用语言模型来finetune一下(这是第一次finetune,叫做LM finetune,其实就是在具体任务数据上继续pre-train),再根据具体任务设计的一个模型上,将预训练好的模型当做这个任务模型的多层,再一次finetune(这是第二次finetune,如果是分类问题的话可以叫做Classifier finetune)。其过程如下:

在这里插入图片描述

(2)所使用的模型来自于2017年salesforce发表的一篇论文《Regularizing and Optimizing LSTM Language Models》,在这篇文章中,他们提出了AWD-LSTM(Averaged SGD and Weight-Dropped LSTM),这个框架更多的是一种训练方法,主要思想分为两大块,其中Averaged SGD是指先将模型训练到一定epoch,然后再将其后的每一轮权值进行平均后,得到最终的权值。

(3)作者提出了几种微调的技巧,discriminative fine-tuning, slanted triangular learning rates, 以及gradual unfreezing

  • discriminative fine-tune的基本思想是针对不同的层在训练更新参数的时候,赋予不同的学习率。这里的出发点是对于NLP的深度学习模型来说,不同层的表征有不同的物理含义,比如浅层偏句法信息,高层偏语义信息,因此对于不同层的学习率不同,自然就是比较合理的了。具体公式是: θ t l = θ t − 1 l + η l ▽ θ l J ( θ ) \theta_{t}^{l}=\theta_{t-1}^{l}+\eta ^{l}\triangledown _{\theta^{l}}J(\theta) θtl=θt1l+ηlθlJ(θ) 这里的 η l \eta ^{l} ηl就是不同层 l l l的不同学习率,原文也给出了具体的选择:先指定最后一层的学习率,然后根据 η l − 1 = η l 2.6 \eta^{l-1}=\frac{\eta^{l}}{2.6} ηl1=2.6ηl得到前面层的学习率,基本思想是让浅层的学习率更小一点。
  • slanted triangular learning rates主要思想是在finetune的第一阶段,希望能够先稳定住原来已经在大规模语料集上已经预训练好的参数,所以选择一个比较小的finetune学习率;尔后希望能够逐步加大学习率,使得学习过程能够尽量快速;最后,当训练接近尾声时,逐步减小学习率,这样让模型逐渐平稳收敛(这个思想,个人觉得大概借鉴了2017年谷歌提出Transformer时用到的warm up的学习率调节方法,这个方法也是在训练的时候先将学习率逐步增大,尔后再逐步减小)。
  • gradual unfreezing主要思想是把预训练的模型在新任务上finetune时,逐层解冻模型,也就是先finetune最后一层,然后再解冻倒数第二层,把倒数第二层和最后一层一起finetune,然后再解冻第三层,以此类推,逐层往浅层推进,最终finetune整个模型或者终止到某个中间层。这样做的目的也是为了finetune的过程能够更平稳。

15.GPT

2018年6月,OpenAI发表一篇《Improving Language Understanding by Generative Pre-Training》,在论文中应用了Transformer框架(详细见论文《Attention is All You Need》)中的Decoder。

具体来说,GPT参考了2018年早些时候的一篇论文《Generating Wikipedia by Summarizing Long Sequences》,这篇论文中提到的T-DMCA(Transformer Decoder with Memory-Compressed Attention),实际上就是一个Decoder,只不过这篇文章中要做超长的序列输入(可以长达11000个词),为了能够高效节省时间和内存的处理如此长的序列,做了一些Memory-Compressed的工作,主要是两方面:一方面是把一个batch内部的序列按长度进行分组,然后分别在每个组内部进行self-attention操作,这样可以避免将一些很短的句子也padding到整个语料的最大长度;另一方面,通过CNN的操作,把K和V压缩到序列长度更小的一个矩阵,同时保持Q不变,这样也能相当程度上减少计算量。

GPT本质上就是用了语言模型的目标函数来优化和训练Transformer-Decoder,利用语言模型的目标函数预训练完成后,进阶这便可以在具体的任务上进行finetune,和ULMFiT中的finetune分为两个阶段的方法不一样的是,GPT直接把这两个过程糅合到一个目标函数中。
L 3 ( C ) = L 2 ( C ) + λ L 1 ( C ) L_{3}(C)=L_{2}(C)+\lambda L_{1}(C) L3(C)=L2(C)+λL1(C)
其中 L 2 L_{2} L2是task-specific的目标函数, L 1 L_{1} L1是语言模型的目标函数。论文中说这种联合学习的方式能够让训练效果更好。而在具体如何做迁移学习的方面,GPT大概也同样借鉴了上面提到的《Generating Wikipedia by Summarizing Long Sequences》论文中的做法,非常巧妙的将整个迁移学习的框架做到非常的精简和通用。主要如下:

  • 分类问题,直接在原序列的开始和末尾添加表示开始和末尾的符号,在Text Entailment问题中(比如Natural Language Inference),将Premise和Hypothesis通过一个中间分隔符“$”连接起来成为一个序列,尔后同样在开头和末尾添加标记符号
  • 文本相似问题,因为序列1和序列2没有先后关系,因此将先后关系相反的两个序列作为输入
  • QA问题,将query和每一个候选的answer都分别连接成一个序列作为输入,最后按各自的打分进行排序

这套输入的表示方法,基本可以使用同一个输入框架来表征许多文本问题(以至于后来的BERT直接借用了这套做法)。除此之外,在输出层,只需要接入一个很简单的全连接层或者MLP便可以,根本不需要非常复杂的模型设计。而整个finetune阶段,新加入的参数极少,只有输出层以及输入层中添加的一些特殊标记(比如分隔符)。

其模型结构如下:

在这里插入图片描述


16.Bert

在GPT发布4个月后,Google AI的Jacob Devlin等发表了《BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding》。随后在Twitter上引发了一波浪潮,同样是Google AI团队的Thang Luong在其Twitter上直言这项工作是一个划时代的工作(原话“A new era of NLP has just begun a few days ago.”)

和GPT不同的是,BERT利用了Transformer的Encoder框架(主要是self_attention机制)。其模型结构图如下:

在这里插入图片描述

BERT的几个主要特点:

  • 引入Masked Language Model(MLM)预训练目标,能够获取上下文相关的双向特征表示,还可以避免self-attention信息泄露问题
  • 引入Next Sentence Prediction(NSP)预训练目标,擅长处理句子或段落的匹配任务
  • 引入强大的特征抽取机制Transformer(多种机制并存),Multi-Head self attention:多头机制类似于“多通道”特征抽取,self attention通过attention mask动态编码变长序列,解决长距离依赖(无位置偏差)、可并行计算;Feed-forward :在位置维度计算非线性层级特征;Layer Norm & Residuals:加速训练,使“深度”网络更加健壮
  • 引入大规模、高质量的文本数据

作者weizier认为BERT是站在前人的肩膀上发展起来的,比如:

  • 双向功能是Transformer Encoder自带的,因此这个“巨人肩膀”是Transformer
  • Masked-LM的巨人肩膀是语言模型,CBOW以及Cloze问题
  • Next Sentence Prediction的“巨人肩膀”是Skip-gram,Skip-thoughts和Quick-thoughts等工作
  • 输入层和输出层的改造,借鉴了T-DMCA以及GPT的做法

在数据上,ELMo使用的是1B Word Benchmark数据集,词数为10亿,然而句子间的顺序是随机打乱的,无法建模句子级别的依赖关系,所以GPT和BERT都弃用这个数据集;GPT使用的是BooksCorpus,词数为8亿;BERT除了使用BooksCorpus之外,还加入了25亿级别的Wikipedia数据集,因此整体使用的数据集为33亿个词。可见BERT使用的数据集是最大的。

在模型上,ELMo使用的是一个Bi-LSTM结构,输入层和输出层使用CNN来进行建模。而GPT使用了12个block,隐藏层节点数为768,多头为12,这也是BERT的base版本(因为base版本就是为了跟GPT做对比的),参数量按照BERT base版本估计为110M。而BERT再一次把模型变得更大了,使用24个block,并且隐藏层节点数与多头都有相应扩大,按照Jacob在论文中自己的说法,言下之意似乎想要表明他们设计的这个模型应该是有史以来的最大的模型之一。

Benchmark数据集,词数为10亿,然而句子间的顺序是随机打乱的,无法建模句子级别的依赖关系,所以GPT和BERT都弃用这个数据集;GPT使用的是BooksCorpus,词数为8亿;BERT除了使用BooksCorpus之外,还加入了25亿级别的Wikipedia数据集,因此整体使用的数据集为33亿个词。可见BERT使用的数据集是最大的。

在模型上,ELMo使用的是一个Bi-LSTM结构,输入层和输出层使用CNN来进行建模。而GPT使用了12个block,隐藏层节点数为768,多头为12,这也是BERT的base版本(因为base版本就是为了跟GPT做对比的),参数量按照BERT base版本估计为110M。而BERT再一次把模型变得更大了,使用24个block,并且隐藏层节点数与多头都有相应扩大,按照Jacob在论文中自己的说法,言下之意似乎想要表明他们设计的这个模型应该是有史以来的最大的模型之一。

在计算资源上,GPT模型在8块GPU上预训练了一个月时间(参数规模和GPT差不多的BERT base版本,在16块TPU上只花了4天时间,为此BERT在论文中提到这个训练时间的时候,还不失时机的给它们家的TPU放了个链接,打了一波广告),对于参数规模为GPT三倍之多的BERT large版本,在64块TPU上训练耗时也依然达到4天之久。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值