《Efficient Estimation of Word Representations in Vector Space》(即word2vec论文)阅读心得分享
论文原文链接
《Efficient Estimation of Word Representations in Vector Space》
读完论文后的感想
背景介绍
在作者写这篇文章的时候,很多NLP系统都使用某个词在vocabulary中的索引作为这个词的特征,这样做的好处就是模型简单,鲁棒性也不错。但是带来的问题就是无法解决词与词之间的相似度的计算。在语音识别领域,模型效果取决于高质量、高数量的数据集。在机器翻译领域,也同样存在一样的情况。因此需要一些新的技术解决这些问题。最近有很多好的模型,其中分布式词向量是比较好的一个思想。
神经网络语言模型在当时几乎无法训练含有上亿个词的语料(这是由于他的模型太复杂,训练时间很长,其实就是计算复杂度太大导致的)。这篇文章提出了一种word2vec的方法,使得相近的词通过代数运算,它们的相似度会比较高。
有很多的产生词的分布式向量的模型。比如LSA、LDA以及神经网络语言模型。作者主要关注了神经网络语言模型,因为神经网络语言模型在词的线性正则化比LSA、LDA好。
作者在文中首先定义了计算复杂度(computational complexity),即
O = E × T × Q E是训练总的epochs,T是词的数量,Q是由模型定义的 O=E\times T\times Q\\ \text{E是训练总的epochs,T是词的数量,Q是由模型定义的} O=E×T×QE是训练总的epochs,T是词的数量,Q是由模型定义的
下面,我们介绍一下Feedforward Neural Net Language Model(NNLM),即前馈神经网络语言模型,和Recurrent Neural Net Language Model(RNNLM),即循环神经网络语言模型。
前馈神经网络语言模型
论文链接《A Neural Probabilistic Language Model》
语言模型
我们知道,有很多产生分布式词向量的模型,非神经网络的模型和神经网络的模型。为了训练出词向量,我们要使用到语言模型。语言模型简单来说就是计算一句话它存在的概率。拿比较传统的n-gram语言模型来说,它其实就是通过计算每个词出现的联合概率,当作是这句话存在的概率,公式如下,
P ( s e n t e n c e = w 1 w 2 . . . w n ) = P ( w 1 ) ∗ P ( w 2 ∣ w 1 ) ∗ P ( w 3 ∣ w 1 , w 2 ) ∗ . . . . ∗ P ( w n ∣ w 1 , w 2 , . . . , w n − 1 ) ( 1 ) P(sentence={w_1w_2...w_n})=P(w_1)*P(w_2|w_1)*P(w_3|w_1, w_2)*....*P(w_n|w_1,w_2,...,w_{n-1}) (1) P(sentence=w1w2...wn)=P(w1)∗P(w2∣w1)∗P(w3∣w1,w2)∗....∗P(wn∣w1,w2,...,wn−1)(1)
我们来解释下上面这个式子, s e n t e n c e = w 1 w 2 . . . w n sentence={w_1w_2...w_n} sentence=w1w2...wn代表着某句话,并且这句话由词 w 1 w_1 w1,词 w 2 w_2 w2,…,词 w n w_n wn按顺序构成。那么可以根据条件概率公式写出式子(1),然后根据大数定理,当采样足够大时, lim n → ∞ f ( 某 个 词 ) = P ( 某 个 词 ) \lim_{n \to \infty}f(某个词)=P(某个词) limn→∞f(某个词)=P(某个词),因此在语料集里计算式子(1)中各个概率的时候,其实就是统计词频数,然后计算词频率。这就是语言模型。很简单对吧?那么问题来了,即使语料非常大的时候,式子(1)的右边在计算的时候,还是会有很多稀疏项。因此有学者就提出了可以使用马尔科夫假设,那就是假设第t个词只与前面n-1个词相关,与其他词无关,那这种模型就叫做n-gram模型。
拿bi-gram模型来举例,bi-gram就是某个词只与前面1个词相关,那么此时,式子(1)就可以化简为如下式子,
P ( s e n t e n c e = w 1 w 2 . . . w n ) = P ( w 1 ) ∗ P ( w 2 ∣ w 1 ) ∗ P ( w 3 ∣ w 2 ) ∗ P ( w 4 ∣ w 3 ) . . . . ∗ P ( w n ∣ w n − 1 ) ( 2 ) P(sentence={w_1w_2...w_n})=P(w_1)*P(w_2|w_1)*P(w_3|w_2)*P(w_4|w_3)....*P(w_n|w_{n-1}) (2) P(sentence=w1w2...wn)=P(w1)∗P(w2∣w1)∗P(w3∣w2)∗P(w4∣w3)....∗P(wn∣wn−1)(2)式子(2)已经解决了式子(1)的稀疏问题,但是依旧还存在着问题,那就是参数量过大的问题。参数指的是式子(2)右边式子的每个子项。想象一下,当语料集非常大的时候,中文词语数量可能达到20万个,那么此时参数量是非常大的,因为你要提前将语料中的各种P(w_i|w_j)的情况都计算好,而当词语数量达到上万个时,这个计算量就变得非常大了。
为了解决参数量过大的问题,有学者就提出,能否使用神经网络的这种参数的方式,从而减少参数量呢?此时,神经网络语言模型就被提出来了。
前馈神经网络语言模型
神经网络语言模型是基于语言模型这个任务来训练模型,为什么呢?你可以这样思考:模型的参数一开始都是随机初始化的,那为了得到正确的词向量,那么肯定需要训练,那怎么训练呢?如何训练才可以让一个词的词向量看起来更合理呢,更符合语法和语义呢?那就是利用语言模型的这种方式来训练。然后当模型训练好后,词向量这个“副产品”就可以拿来使用了。模型是这样训练的:首先有一个滑动窗口,比如窗口设置为5,那么模型的输入就是窗口的前4个词,第5个词作为目标词,用来作为标签,计算误差,然后反向传播修改参数。
我们看一下论文中的模型对应的图,作者是怎么画的,如下图
为了让大家更能更容易理解,我自己画了一张图(和上面那张图一模一样,只不过画的更细一些),如下图,
假设我们有一个语料集,这个语料集中只有一句话,那就是“我/今天/晚上/看/了/这篇/博客”,中间用“/”分开是因为我们假设分完词的结果是这样的。然后,我们统计一下各个词,形成一个词典,也可以称为词库,如图中所示的词典,我们给每个词赋予了一个编号,比如“我”就是编号0,“今天”就是编号1。然后根据这个词典,我们给每个词赋予一个one-hot编码(大家可以看图中one-hot层)。接着,我们按照这个one-hot编码,去和embedding_table做一个矩阵相乘,这里拿“今天”这个词来举例,即, [ 0 1 0 0