词向量表示:
one-hot 形式:
缺点:维度灾难、无法捕捉词之间的相似度
分布式表示:
通过训练将每个词表示成一个n维的向量
优点:一定程度上避免维度灾难、使得词义相似的词在距离上更小
目前主要是通过训练语言模型的方式,顺便得到词的向量表示。语言模型是计算出一段序列在某种语言中出现的概率,或者说预测一下个词的概率
给定一段文本序列,它出现的概率可以表示为如下形式:
例子:“大家喜欢吃苹果”分4个词“我”,“喜欢”,“吃”,“丑橘”
P(我,喜欢,吃,苹果)=P(我)P(喜欢|我)P(吃|我,喜欢)P(丑橘|我,喜欢,吃)
P(我)表示语料库中“我”这个词出现的概率
P(丑橘|我,喜欢,吃)表示语料库这个“丑橘”这个词出现在“我喜欢吃”后面的概率
只考虑前n-1个字符的影响
p ( w t ∣ w 1 , w 2 , w 3 , . . . . , w T ) = p ( w t ∣ w t − n + 1 , w t − n , . . . w t − 1 ) p(w_t|w_1,w_2,w_3,....,w_T) = p(w_t|w_{t-n+1},w_{t-n},...w_{t-1}) p(wt∣w1,w2,w3,....,wT)=p(wt∣wt−n+1,wt−n,...wt−1)
常见的情况下n=2或n=3
缺点:只能处理n<4的短序列,但n太小时考虑的信息过少,依旧影响预测的准确率。
语言模型存在的问题
(1)单个概率计算时搜索规模会逐渐增大,例子:P(吃|我,喜欢)
(2)有多少词,需要扫描多少次语料库
试图使用神经网络的办法训练语言模型,输入一个词序列,输出这个词序列下一个词的概率分布
输入一个词序列 w t − n + 1 , . . . . . w t − 1 w_{t-n+1},.....w_{t-1} wt−n+1,.....wt−1, 在查询表 C C C中转换成k维向量 C ( w t − n + 1 ) C(w_{t-n+1}) C(wt−n+1)
输出是通过一个全连接层 t a n h ( W C + b ) tanh(WC+b) tanh(WC+b)
该模型可分为特征映射和计算条件概率分布两部分:
特征映射:通过映射矩阵 C C C 将输入的每个词映射为一个特征向量,特征向量的维度为m,该过程将通过特征映射得到的 C ( w t − n + 1 ) , . . . , C ( w t − 1 ) C(w_{t-n+1}),...,C(w_{t-1}) C(wt−n+1),...,C(wt−1)合并成一个(n-1)m维的向量
计算概率分布:通过一个函数 g g g将词序列输出为一个概率分布,这里的 g g g是一个神经网络
f ( i , w t − 1 , . . . , w t − n + 2 , w t − n + 1 ) = g ( i , C ( w t − n + 1 ) , . . . , C ( w t − 1 ) ) f(i,w_{t−1},...,w_{t−n+2},w_{t−n+1})=g(i,C(w_{t−n+1}),...,C(w_{t−1})) f(i,wt−1,...,wt−n+2,wt−n+1)=g(i,C(wt−n+1),...,C(wt−1))
网络的输出再经过个softmax层得到概率分布:
p ( w t ∣ w t − n + 1 , . . . . . . , w t − 1 ) = e y w t ∑ e y i p(w_t|w_{t-n+1},......,w_{t-1})= \frac{e^{y_{w_{t}}}}{\sum{e^{y_{i}}}} p(wt∣wt−n+1,......,wt−1)=∑eyieywt
其中 y = W x + b + U t a n h ( H x + d ) y = Wx+b + Utanh(Hx+d) y=Wx+b+Utanh(Hx+d)
注: 由于需要利用训练语言模型得到词的向量表示,因此在梯度下降过程中对输入(词向量表示)进行更新
NNLM 的问题:
可以将n提升到5 ,但是缺少灵活性
计算耗时
这里主要讲两个魔性一个是连续词袋模型(CBOW)和skip-gram模型:
CBOW:
上边的NNLM模型在预测一个位置词时,只考虑了它前边的n-1个词,CBOW希望可以利用某个词的上下文输出中间词的分布
(1)输入层:上下文单词的onehot. {假设单词向量空间dim为V,上下文单词个数为C}
(2)所有onehot分别乘以共享的输入权重矩阵 W V ∗ N W_{V*N} WV∗N,(N为自己设定的数,初始化权重矩阵W)
(3)所得的向量相加求平均作为隐层向量, size为1*N.
(4)乘以输出权重矩阵 W N ∗ V ′ W' _{N*V} WN∗V′
(5)得到向量 1 ∗ V 1*V 1∗V,利用激活函数处理得到V-dim概率分布
(6)概率最大的index所指示的单词为预测出的中间词(target word)与true label的onehot做比较,误差越小越好,根据误差更新权重矩阵
总结
(1)移除前向反馈神经网络中非线性的hidden layer,直接将中间层的embedding layer与输出层的softmax layer连接;
(2)忽略上下文环境的序列信息:输入的所有词向量均汇总到同一个embedding layer;
(3)将future words纳入上下文环境
skip-gram 模型:
主要做法是:给定一个中心词,预测它的上下文
例子“The dog barked at the mailman”,选取“dog”作为input word
?如何得到训练数据
(1)skip_window:代表从当前input word 的一层(左侧或右侧)选取词的数量。例如,skip_window=2,最终获得的窗口中的词为(包括input word在内)[“The”,“dog”,“barked”,“at”]
(2)num_skips:代表从整个窗口中选取多少个不同的词作为output word,基于上个窗口,当num_skips=2时,将会得到两组形式为(input word,output word)的训练数据,例如(“dog”,“barked”),(“dog”,“the”)
?输出的概率代表含义
代表词典中每个词有多大可能性同input word同时出现,即词典中每个词是output word的可能性。例如
假设input word为“中国”,相对于“苹果”、“蝈蝈”等词,“英国”、“俄罗斯”这样的词更容易同中国在窗口中同时出现,基于这样的词对进行训练,在输出概率中“葡萄牙”、“韩国”等词的值会更高。
Skip-Gram最大化目标
基于Skip-Gram模型定义
V i V_i Vi为embedding层矩阵里的列向量, w i w_i wi的input vector, U j U_j Uj是softmax层矩阵里的行向量, w j w_j wj的output vector。
模型的本质是计算输入word的input vector与目标word的output vector之间的余弦相似度,并进行softmax归一化。
2018年提出来的论文《deep contextualized word representation》中提出ELMO算法,一种基于特征的语言模型,用训练好的语言模型得到更好的特征。
他们认为一个预训练的词表示应该能够包含丰富的句法和语义信息,并且能够对多义词进行建模。而传统的词向量(例如word2vec)是上下文无关的。例如下面"apple"的例子,这两个"apple"根据上下文意思是不同的,但是在word2vec中,只有apple一个词向量,无法对一词多义进行建模。
所以他们利用语言模型来获得一个上下文相关的预训练表示,称为ELMo,并在6个NLP任务上获得了提升。
方法:
在EMLo中,他们使用的是一个双向的LSTM语言模型,由一个前向和一个后向语言模型构成,目标函数就是取这两个方向语言模型的最大似然。
在预训练好这个语言模型之后,ELMo就是根据下面的公式来用作词表示,其实就是把这个双向语言模型的每一中间层进行一个求和。最简单的也可以使用最高层的表示来作为ELMo。
然后在进行有监督的NLP任务时,可以将ELMo直接当做特征拼接到具体任务模型的词向量输入或者是模型的最高层表示上。总结一下,不像传统的词向量,每一个词只对应一个词向量,ELMo利用预训练好的双向语言模型,然后根据具体输入从该语言模型中可以得到上下文依赖的当前词表示(对于不同上下文的同一个词的表示是不一样的),再当成特征加入到具体的NLP有监督模型里。
2.3 实验
这里我们简单看一下主要的实验,具体实验还需阅读论文。首先是整个模型效果的实验。他们在6个NLP任务上进行了实验,首先根据目前每个任务搭建了不同的模型作为baseline,然后加入ELMo,可以看到加入ELMo后6个任务都有所提升,平均大约能够提升2个多百分点,并且最后的结果都超过了之前的先进结果(SOTA)。
在下面的分析实验中,我们可以看到使用所有层的效果要比只使用最后一层作为ELMo的效果要好。在输入还是输出上面加EMLo效果好的问题上,并没有定论,不同的任务可能效果不一样。
来源于OPEN AI的《Improving Language Understanding by Generative Pre-Training》
他们的目标是学习一个通用的表示,能够在大量任务上进行应用。这篇论文的亮点主要在于,他们利用了Transformer网络代替了LSTM作为语言模型来更好的捕获长距离语言结构。然后在进行具体任务有监督微调时使用了语言模型作为附属任务训练目标。最后再12个NLP任务上进行了实验,9个任务获得了SOTA。
3.2 方法
首先我们来看一下他们无监督预训练时的语言模型。他们仍然使用的是标准的语言模型目标函数,即通过前k个词预测当前词,但是在语言模型网络上他们使用了google团队在《Attention is all your need》论文中提出的Transformer解码器作为语言模型。Transformer模型主要是利用自注意力(self-attention)机制的模型,这里我就不多进行介绍,大家可以看论文或者参考我之前的博客(https://blog.csdn.net/damuge2/article/details/88987851)。
然后再具体NLP任务有监督微调时,与ELMo当成特征的做法不同,OpenAI GPT不需要再重新对任务构建新的模型结构,而是直接在transformer这个语言模型上的最后一层接上softmax作为任务输出层,然后再对这整个模型进行微调。他们额外发现,如果使用语言模型作为辅助任务,能够提升有监督模型的泛化能力,并且能够加速收敛。
由于不同NLP任务的输入有所不同,在transformer模型的输入上针对不同NLP任务也有所不同。具体如下图,对于分类任务直接讲文本输入即可;对于文本蕴涵任务,需要将前提和假设用一个Delim分割向量拼接后进行输入;对于文本相似度任务,在两个方向上都使用Delim拼接后,进行输入;对于像问答多选择的任务,就是将每个答案和上下文进行拼接进行输入。
下面我简单的列举了一下不同NLP任务上的实验结果。
语言推理任务:
问答和常识推理任务:
语义相似度和分类任务:
可以看到在多项任务上,OpenAI GPT的效果要比ELMo的效果更好。从下面的消除实验来看,在去掉预训练部分后,所有任务都大幅下降,平均下降了14.8%,说明预训练很有效;在大数据集上使用语言模型作为附加任务的效果更好,小数据集不然;利用LSTM代替Transformer后,结果平均下降了5.6%,也体现了Transformer的性能。
《BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding》。这篇论文把预训练语言表示方法分为了基于特征的方法(代表ELMo)和基于微调的方法(代表OpenAI GPT)。而目前这两种方法在预训练时都是使用单向的语言模型来学习语言表示。
作者们证明了使用双向的预训练效果更好。其实这篇论文方法的整体框架和GPT类似,是进一步的发展。具体的,他们BERT是使用Transformer的编码器来作为语言模型,在语言模型预训练的时候,提出了两个新的目标任务(即遮挡语言模型MLM和预测下一个句子的任务),最后在11个NLP任务上取得了SOTA。
4.2方法
在语言模型上,BERT使用的是Transformer编码器,并且设计了一个小一点Base结构和一个更大的Large网络结构。
对比一下三种语言模型结构,BERT使用的是Transformer编码器,由于self-attention机制,所以模型上下层直接全部互相连接的。而OpenAI GPT使用的是Transformer解码器,它是一个需要从左到右的受限制的Transformer,而ELMo使用的是双向LSTM,虽然是双向的,但是也只是在两个单向的LSTM的最高层进行简单的拼接。所以作者们任务只有BERT是真正在模型所有层中是双向的。
而在模型的输入方面,BERT做了更多的细节,如下图。他们使用了WordPiece embedding作为词向量,并加入了位置向量和句子切分向量。并在每一个文本输入前加入了一个CLS向量,后面会有这个向量作为具体的分类向量。
在语言模型预训练上,他们不在使用标准的从左到右预测下一个词作为目标任务,而是提出了两个新的任务。第一个任务他们称为MLM,即在输入的词序列中,随机的挡上15%的词,然后任务就是去预测挡上的这些词,可以看到相比传统的语言模型预测目标函数,MLM可以从任何方向去预测这些挡上的词,而不仅仅是单向的。但是这样做会带来两个缺点:1)预训练用[MASK]提出挡住的词后,在微调阶段是没有[MASK]这个词的,所以会出现不匹配;2)预测15%的词而不是预测整个句子,使得预训练的收敛更慢。但是对于第二点,作者们觉得虽然是慢了,但是效果提升比较明显可以弥补。
对于第一点他们采用了下面的技巧来缓解,即不是总是用[MASK]去替换挡住的词,在10%的时间用一个随机词取替换,10%的时间就用这个词本身。
而对于传统语言模型,并没有对句子之间的关系进行考虑。为了让模型能够学习到句子之间的关系,作者们提出了第二个目标任务就是预测下一个句子。其实就是一个二元分类问题,50%的时间,输入一个句子和下一个句子的拼接,分类标签是正例,而另50%是输入一个句子和非下一个随机句子的拼接,标签为负例。最后整个预训练的目标函数就是这两个任务的取和求似然。
在微调阶段,不同任务的模型如下图,只是在输入层和输出层有所区别,然后整个模型所有参数进行微调。
4.3 实验
下面我们列出一下不同NLP上BERT的效果。
GLUE结果:
QA结果:
实体识别结果:
SWAG结果:
可以看到在这些所有NLP任务上,BERT都取得了SOTA,而且相比EMLo和GPT的效果提升还是比较大的。
在预训练实验分析上,可以看到本文提出的两个目标任务的作用还是很有效的,特别是在MLM这个目标任务上。
作者也做了模型规模的实验,大规模的模型效果更好,即使在小数据集上。
此外,作者也做了像ELMo当成特征加入的实验,从下图可以看到,当成特征加入最好效果能达到96.1%和微调的96.4%差不多,说明BERT对于基于特征和基于微调这两种方法都是有效的。
5. 总结
最后进行简单的总结,和传统的词向量相比,使用语言模型预训练其实可以看成是一个句子级别的上下文的词表示,它可以充分利用大规模的单语语料,并且可以对一词多义进行建模。而且从后面两篇论文可以看到,通过大规模语料预训练后,使用统一的模型或者是当成特征直接加到一些简单模型上,对各种NLP任务都能取得不错的效果,说明很大程度上缓解了具体任务对模型结构的依赖。在目前很多评测上也都取得了SOTA。ELMo也提供了官网供大家使用。但是这些方法在空间和时间复杂度上都比较高,特别是BERT,在论文中他们训练base版本需要在16个TGPU上,large版本需要在64个TPU上训练4天,对于一般条件,一个GPU训练的话,得用上1年。还有就是可以看出这些方法里面都存在很多工程细节,一些细节做得不好的话,效果也会大大折扣。
这里有一个讲的不错的文章
从Word Embedding到Bert模型——自然语言处理预训练技术发展史