语言模型与词向量
自然语言处理中一个很核心的基本任务就是语言模型与词向量,这一篇文章我主要回顾了一下自然语言处理中语言模型与词向量的发展历程,总结一下这一条线的一些经典的idea。
一. 语言模型
什么叫做语言模型?语言模型其实就是对一种语言打分的方法。自然语言处理中经常把语言的“得分”通过概率来体现,这就叫做概率语言模型(PLM),或者叫做统计语言模型(SLM)。
具体来说,概率语言模型计算的是一个序列作为一句话可能的概率,例如:
上面的过程一般可以形式化表示,设一个句子序列
则它的概率可以表示为:
由联合概率的计算方法,有:
其中每个条件概率就是模型的参数;如果这个参数都是已知的,那么就能得到整个句子的概率了。
然而这样表示有两个非常大的缺陷:
1.参数空间过大: 设词表的大小为
V
V
V,考虑长度为
T
T
T的句子,理论上有
V
T
V^T
VT种可能的句子,每个句子中有
T
T
T个参数,那么参数的数量将达到
T
V
T
TV^T
TVT ,条件概率为
但是无法估算,没有用。
2. 数据稀疏严重,对于非常多的词的组合,在语料库中都没有出现,依据极大似然估计的概率会是0。
二. N-gram语言模型
为了解决参数空间过大的问题,引入了马尔科夫假设,得到N-gram语言模型。N-gram语言模型是基于马尔可夫假设(Markov),也就是说未来的事件只取决于有限的历史。基于马尔可夫假设,N-gram 语言模型认为一个词出现的概率只与它前面的 n-1 个词相关,用式子表示就是:
如果一个词的出现与它周围的词是独立的,那么我们称之为
u
n
i
g
r
a
m
unigram
unigram,也就是一元语言模型
如果一个词的出现仅仅依赖于它前面一个词,那么我们称之为
b
i
g
r
a
m
bigram
bigram,也就是二元语言模型
如果一个词的出现仅仅依赖于它前面的两个词,那么我们称之为
t
r
i
g
r
a
m
trigram
trigram,也就是三元语言模型
依此类推。
根据条件概率公式与大数定律,当语料的规模足够大时,有
所以可以通过统计大规模的语料库的方法来进行计算。
以 n = 2 n=2 n=2 的 b i g r a m bigram bigram 为例,有
n = 3 n=3 n=3 的 t r i g r a m trigram trigram,有
除了 u n i g r a m unigram unigram,N-gram语言模型可以get到词语之间的关系信息。例如对于句子“he eats pizza”和"he drinks pizza",很明显,前面的句子的概率应该更大。但是如果使用unigram 语言模型,将看不出两个句子的概率差别,而 b i g r a m bigram bigram就可以,因为p(pizza|eats)比p(pizza|drinks)的概率大。在看另外一些实际的例子可以看到:
N-gram语言模型参数量是随着 n n n的增大猛增。假设词表的规模N=200000(汉语的词汇量),模型参数与 n n n的关系表如下:
随着 n n n的增大,模型参数量增多,模型的性能增大却不显著;模型参数越多,模型的可区别性越好,但是可靠性却在下降——因为语料的规模是有限的,导致 c o u n t ( w ) count(w) count(w) 的实例数量不够,从而降低了可靠性。
在实践中用的最多的就是 b i g r a m bigram bigram和 t r i g r a m trigram trigram了,高于四元的用的非常少,因为训练它须要更庞大的语料,并且数据稀疏严重,时间复杂度高,精度却提高的不多。
另外这里由于是统计N-gram,某些词在语料库中可能不会同时出现,因此会遇到 c o u n t ( w ) = 0 count(w) =0 count(w)=0 的情况, 此时就需要做平滑处理,常见的平滑处理方法包括
Add-one Smoothing (Laplace)
Add-k Smoothing (k<1)
Back-off (回退)
Interpolation (插值法)
Absolute Discounting (绝对折扣法)
Kneser-Ney Smoothing (KN)
Modified Kneser-Ney
具体详见自然语言处理中N-Gram模型的Smoothing算法,这里就不细说。
三.神经概率语言模型 (NPLM)
随着深度学习的发展,2003年Bengio发表论文A Neural Probabilistic Language Model (Bengio, et al., 2003),首次使用神经网络训练语言模型,这个神经网络是什么样的呢?这个神经网络训练好之后,以后输入一句话的前面几个词,这个神经网络就可以输出后面紧跟的单词应该是哪个?这就是有名的神经概率语言模型(NPLM)。
接下来讲讲它的具体思路。首先说训练过程,学习是输入单词 w t w_t wt的前面句子的n-1个单词,要求网络能够正确的预测单词 w t w_t wt,即最大化
前面任意单词 w i w_i wi用one-hot进行编码(例如:00010000)作为原始输入,之后乘以矩阵C获得单词的词向量(虽然当时并没有这么叫),也就是单词的word embedding的值。接着,将前面句子的几个词的词向量拼接起来,再过一个**函数为tanh的隐藏层,最后过一个 s o f t m a x softmax softmax 输出层(如上图所示),得到此表中每个词作为下一个词的概率分布,并使用交叉熵损失函数。
得到词表中每个词作为C矩阵一般是V行m列,V代表词汇表的大小,m代词向量的纬度,只不过矩阵C的内容也是参数,需要学习获得,训练刚开始时用随机初始化矩阵C,当这个神经网络训练好之后,矩阵C的内容就会被正确赋值,每一行即对应一个单词的词向量值。所以,通过这个网络学习语言模型任务,这个网络不仅能够根前面句子几个词预测后接单词是什么,同时获得一个副产品词向量,也就是矩阵C。
因此,神经概率语言模型依然是一个概率语言模型,它是通过神经网络来计算概率语言模型中的每个参数。
相比于N-gram语言模型,神经概率语言模型有以下优点:
1.单词之间的相似性可以通过词向量来体现(相比神经语言模型本身,作为其副产品的词向量反而是更大的惊喜)
2.自带平滑处理
神经概率语言模型中也会出现OOV问题,常用的处理方法如下:
在预处理语料阶段,将不满足某一个频率阈值的词全部替换为UNK
为 UNK 分配一个随机初始化的 embedding,并参与训练(最终得到的 embedding 会有一定的语义信息,但具体好坏未知)
把 UNK 都初始化成 0 向量,不参与训练(UNK 共享相同的语义信息)
每次都把 UNK 初始化成一个新的随机向量,不参与训练(常用的方法——因为本身每个 UNK 都不同,随机更符合对 UNK 基于最大熵的估计)
基于Char-level的方法:PaperWeekly 第七期 – 基于Char-level的NMT OOV解决方案
四. word2vec
神经网络在NLP沉寂10年,真正的正式进入NLP领域,引起人们关注,应该是2013年,这一年出现了用语言模型做word embedding的word2vec,下面就是这两篇有名的两篇word2vec论文。
原始论文:Efficient Estimation of Word Representations in Vector Space(Tomas Mikolov, Kai Chen, Greg Corrado, Jeffrey Dean 2013)
Distributed Representations of Words and Phrases and their Compositionality(Tomas Mikolov, Ilya Sutskever, Kai Chen, Greg Corrado, Jeffrey Dean 2013)
word2vec的网络结构其实和神经概率语言模型(NPLM)是基本类似的,只是这个图长得清晰度差了点,看上去像。不过这里需要指出:尽管网络结构接近,而且也是做语言模型任务,但是其训练方法不太一样。word2vec有两种训练方法,一种叫CBOW,核心思想是把一个句子里面的词扣掉,然后用这个词的上文和下文去预测这个被抠掉的这个词;第二种叫做Skip-gram,和CBOW正好反过来,输入某个单词,要求网络预测它的上下文单词。而NPLM是怎么干的?是输入一个单词的上文,去预测这个词。这是有显著差异的!
为什么word2vec这么处理?原因很简单,因为word2vec和NPLM不一样,NNLM的主要任务是学习一个解决语言模型任务的网络结构,语言模型就是要看到上文预测下文,而word embedding只是一个无心插柳的副产品,是个bonus。但是啊,word2vec的目标不一样,说白了,它单纯就是要获得word embedding的,这是主产品,所以它完全可以这么随性地去训练网络。
所以,word2Vec 本质上也是一个神经概率语言模型,但是它的目标并不是语言模型本身,而是词向量;因此,其所作的一系列优化,都是为了更快更好的得到词向量。
接下来,我们来具体看看,word2vec提供的两套模型:CBOW和Skip-Gram,其基本思想如下:
CBOW在已知
c
o
n
t
e
x
t
(
w
)
context(w)
context(w)的情况下,预测
w
w
w
Skip-Gram在已知
w
w
w的情况下预测
c
o
n
t
e
x
t
(
w
)
context(w)
context(w)
下面分别进行两个模型的讲解。
Skip-Gram模型
Skip-Gram模型输入是一个词,输出是该词的上下文。设上下文窗口大小
c
o
n
t
e
x
t
_
w
i
n
d
o
w
n
=
5
context\_windown=5
context_windown=5 或者说
s
k
i
p
_
w
i
n
d
o
w
n
=
2
,
因
为
skip\_windown=2,因为
skip_windown=2,因为context_windown=skip_windown*2+1。一个句子序列可以表示为
Skip-Gram的训练样本为:
比如对于原始样本“达观数据是一家做人工智能的公司”,并且假设窗口为2,则对训练样本进行分词后,可表示为:
ok,得到了这么多的word pairs,应该怎么输入到模型中呢?答案就是one-hot向量。为了得到one-hot向量,首先对语料库进行统计,得到词表。假设词表长度为10000,词向量为300维,则skip-gram模型可表示为下图:
基本思路是通过一个词(一般叫做中心词)来预测它的上下文,即输入一个词 I I I 的one-hot vector,通过第一层线性层 W W W得到词 I I I的词向量,再过一个线性层 W ′ W' W′ ,然后做一个 s o f t m a x softmax softmax ,得到一个词表 V V V大小的概率分布。
具体详细推导见:Skip-Gram模型详细推导。
可以看到最后的梯度更新公式,
每次更新梯度都需要计算整个词表 V V V上的一个和,这个计算代价很大,因此这就有了一些加速技术包括hierarchical softmax和negative sampling。
2.CBOW-模型
CBOW的基本思想输入是一个词的上下文,输出是该词。和Skip-Gram类似,CBOW的训练样本是:
比如对于原始样本“达观数据是一家做人工智能的公司”,并且假设窗口为2,则对训练样本进行分词后,可表示为:
则可以得到训练样本有:({是,一家}, 达观数据)、({达观数据,一家,做},是)、({达观数据,是,做,人工智能},一家)、({是,一家,人工智能,的},做).
CBOW的基本模型结构如下图,可以看到模型首先输入中心词 w ( t ) w(t) w(t)的上下文,然后做一个线性映射,即得到每个词的词向量的表示,然后求和取平均,再过一个线性层,最后过一个 s o f t m a x softmax softmax计算输出中心词 w ( t ) w(t) w(t) 的概率分布。
CBOW的详细推导见:CBOW模型的详细推导。
可以看到CBOW的权重更新公式为:
仍然需要计算整个词表的和,效率很低。
- 分层softmax(hierarchical softmax)
Skip-Gram模型和CBOW模型计算softmax的时候都需要整个词表 V V V,当词表特别大的时候,计算效率很低。
分层softmax是计算softmax问题的一种有效的方法。该模型用二叉树来表示词表 V V V中的所有单词。
V个单词必须存储于二叉树的叶子单元。可以被证明一共有V-1个内单元。对于每个叶子节点,有一条唯一的路径可以从根节点到达该叶子节点;该路径被用来计算该叶子结点所代表的单词的概率。
这样计算的复杂度最终变为 O ( l o g V ) O(logV) O(logV) ,相比于原来的 O ( V ) O(V) O(V) 有很大的提升。
具体详细推导见:word2vec之分层Softmax。
- 负采样技术(negative sampling)
相比分层softmax,负采样的思想更加直观:为了解决数量太过庞大的输出向量的更新问题,我们就不更新全部向量,而只更新他们的一个样本。
显然正确的输出单词(也就是正样本)应该出现在我们的样本中,另外,我们需要采集几个单词作为负样本(因此该技术被称为“负采样”)。
那么具体是怎么采样的呢?实际上是根据一个词在语料中出现的概率,概率越大的越有可能被选中,具体计算公式为:
其中 f ( w ) f(w) f(w)表示词 w w w 出现的概率。
具体使用负采样技术的详细参数更新公式见:word2vec之负采样。
- 欠采样(subsample)
语料库中可能有很多停用词,如中文中的“是”、“的”这种词在任何场景中都可能出现,它们并不包含多少语义,而且出现的频率特别高,如果不加处理会影响词向量的效果。
欠采样就是为了应对这种现象,它的主要思想是对每个词都计算一个采样概率,根据概率值来判断一个词是否应该保留。概率计算方法为:
其中
f
(
w
o
r
d
)
f(word)
f(word)表示word出现的概率,0.001为默认值,具体函数走势如下图所示,可以看出,词语出现的概率越高,其被采样到的概率就越低。这里有一点IDF的味道,不同的是IDF是为了降低词的特征权重,欠采样是为了降低词的采样概率。
五. Glove词向量
Glove模型是基于共现矩阵构建的,认为共现矩阵可以通过一些统计信息得到词之间的关系,这些关系可以一定程度上表达词的含义。具体看下表:
Glove模型的基本思想是:
假设词向量已知,如果这些词向量通过某个函数(目标函数)可以拟合共现矩阵中的统计信息,那么可以认为这些词向量也拥有了共现矩阵中蕴含的语义
模型的训练过程就是拟合词向量的过程
Glove模型的目标函数是:
其中 w i w_i wi和 w j w_j wj为词向量, x i , j xi,j xi,j 为 w i w_i wi和 w j w_j wj 的共现次数, f ( x ) f(x) f(x) 是一个权重函数,为了限制高频词和防止 x i , j xi,j xi,j=0 。
具体详细数学推导见:Glove模型推导
Glove的特点:
(1)Glove和word2vec本质上都是神经网络,都利用了反向传播来更新词向量,但是结构要更简单,所以Glove的速度更快。
(2)从效果上看,虽然 GloVe 的训练速度更快,但是词向量的性能在通用性上要弱一些:
在一些任务上表现优于 Word2Vec,但是在更多的任务上要比 Word2Vec 差。
六.FastText
FastText是从word2vec的CBOW模型演化而来,从网络的角度看,两者模型基本一致,区别仅在于两者的输入和目标函数不同。
注意:此架构图没有展示词向量的训练过程。可以看到,和CBOW一样,fastText模型也只有三层:输入层、隐含层、输出层(Hierarchical Softmax),输入都是多个经向量表示的单词,输出都是一个特定的target,隐含层都是对多个词向量的叠加平均。不同的是,CBOW的输入是目标单词的上下文,fastText的输入是多个单词及其n-gram特征,这些特征用来表示单个文档;CBOW的输入单词被onehot编码过,fastText的输入特征是被embedding过;CBOW的输出是目标词汇,fastText的输出是文档对应的类标。
什么是字符级别的n-gram呢?
word2vec把语料库中的每个单词当成原子的,它会为每个单词生成一个向量。这忽略了单词内部的形态特征,比如:“apple” 和“apples”,“达观数据”和“达观”,这两个例子中,两个单词都有较多公共字符,即它们的内部形态类似,但是在传统的word2vec中,这种单词内部形态信息因为它们被转换成不同的id丢失了。
为了克服这个问题,fastText使用了字符级别的n-grams来表示一个单词。对于单词“apple”,假设n的取值为3,则它的trigram有
其中,<表示前缀,>表示后缀。于是,我们可以用这些trigram来表示“apple”这个单词,进一步,我们可以用这5个trigram的向量叠加来表示“apple”的词向量。
这带来两点好处:
(1)对于低频词生成的词向量效果会更好。因为它们的n-gram可以和其它词共享。
(2)对于训练词库之外的单词,仍然可以构建它们的词向量。我们可以叠加它们的字符级n-gram向量。(完美解决OOV问题,perfect,想放个烟花庆祝以下!!!)
我们再来仔细观察模型的后半部分,即从隐含层输出到输出层输出,会发现它就是一个softmax线性多类别分类器,分类器的输入是一个用来表征当前文档的向量;模型的前半部分,即从输入层输入到隐含层输出部分,主要在做一件事情:生成用来表征文档的向量。那么它是如何做的呢?叠加构成这篇文档的所有词及n-gram的词向量,然后取平均。叠加词向量背后的思想就是传统的词袋法,即将文档看成一个由词构成的集合。
所以fastText的核心思想就是:将整篇文档的词及n-gram向量叠加平均得到文档向量,然后使用文档向量做softmax多分类。这中间涉及到两个技巧:字符级n-gram特征的引入以及分层Softmax分类。
这里做个小结,FastText有以下特点:
(1)fastText本身是用于文本分类的,词向量属于副产品。
(2)在文本分类任务中,fastText(浅层网络)往往能取得和深度网络相媲美的精度,却在训练时间上比深度网络快许多数量级。
(3)字符级n-gram特征的引入对文本分类效果会有一些提升,而且完美的解决了OOV问题
小结:这一部分主要是总结一下语言模型与词向量的一些基础idea,方便以后查阅,中间参考了很多其他讲解的更详细的资料。
文章来源:https://zhuanlan.zhihu.com/p/59802406?utm_source=wechat_session