学习笔记第十二篇之word2vec

       word2vec是训练词向量的表示方法,经常会使用到,所以在此记录一下。

       2013年,Google开源了一款用于词向量计算的工具——word2vec,引起了工业界和学术界的关注。首先,word2vec可以在百万数量级的词典和上亿的数据集上进行高效地训练;其次,该工具得到的训练结果——词向量(word embedding),可以很好地度量词与词之间的相似性。随着深度学习(Deep Learning)在自然语言处理中应用的普及,很多人误以为word2vec是一种深度学习算法。其实word2vec算法的背后是一个浅层神经网络。另外需要强调的一点是,word2vec是一个计算word vector的开源工具。当我们在说word2vec算法或模型的时候,其实指的是其背后用于计算word vector的CBoW模型和Skip-gram模型。很多人以为word2vec指的是一个算法或模型,这也是一种谬误。接下来,本文将从统计语言模型出发,尽可能详细地介绍word2vec工具背后的算法模型的来龙去脉。

    1、词向量

      用词向量来表示词并不是word2vec的首创,在很久之前就出现了。最早的词向量是很冗长的,它使用是词向量维度大小为整个词汇表的大小,对于每个具体的词汇表中的词,将对应的位置置为1。比如我们有下面的5个词组成的词汇表,词"Queen"的序号为2, 那么它的词向量就是(0,1,0,0,0)(0,1,0,0,0)。同样的道理,词"Woman"的词向量就是(0,0,0,1,0)(0,0,0,1,0)。这种词向量的编码方式我们一般叫做1-of-N representation或者one hot representation。    

      One hot representation用来表示词向量非常简单,但是却有很多问题。最大的问题是我们的词汇表一般都非常大,比如达到百万级别,这样每个词都用百万维的向量来表示简直是内存的灾难。这样的向量其实除了一个位置是1,其余的位置全部都是0,表达的效率不高,能不能把词向量的维度变小呢? Dristributed representation可以解决One hot representation的问题,它的思路是通过训练,将每个词都映射到一个较短的词向量上来。所有的这些词向量就构成了向量空间,进而可以用普通的统计学的方法来研究词与词之间的关系。这个较短的词向量维度是多大呢?这个一般需要我们在训练时自己来指定。

     有了用Dristributed representation表示的较短的词向量,我们就可以较容易的分析词之间的关系了,比如我们将词的维度降维到2维,有一个有趣的研究表明,用下图的词向量表示我们的词时,我们可以发现: 

                                               King - man + woman = Queen

      可见我们只要得到了词汇表里所有词对应的词向量,那么我们就可以做很多有趣的事情了。不过,怎么训练得到合适的词向量呢?一个很常见的方法是使用神经网络语言模型。

    2、CBOW 和Skip-gram用于神经网络语言模型

      在word2vec出现之前,已经有用神经网络DNN来用训练词向量进而处理词与词之间的关系了。采用的方法一般是一个三层的神经网络结构(当然也可以多层),分为输入层,隐藏层和输出层(softmax层)。这个模型是如何定义数据的输入和输出呢?一般分为CBOW(Continuous Bag-of-Words 与Skip-Gram两种模型。

   CBOW模型的训练输入是某一个特征词的上下文相关的词对应的词向量,而输出就是这特定的一个词的词向量。比如下面这段话,我们的上下文大小取值为4,特定的这个词是"Learning",也就是我们需要的输出词向量,上下文对应的词有8个,前后各4个,这8个词是我们模型的输入。由于CBOW使用的是词袋模型,因此这8个词都是平等的,也就是不考虑他们和我们关注的词之间的距离大小,只要在我们上下文之内即可。

     这样我们这个CBOW的例子里,我们的输入是8个词向量,输出是所有词的softmax概率(训练的目标是期望训练样本特定词对应的softmax概率最大),对应的CBOW神经网络模型输入层有8个神经元,输出层有词汇表大小个神经元。隐藏层的神经元个数我们可以自己指定。通过DNN的反向传播算法,我们可以求出DNN模型的参数,同时得到所有的词对应的词向量。这样当我们有新的需求,要求出某8个词对应的最可能的输出中心词时,我们可以通过一次DNN前向传播算法并通过softmax激活函数找到概率最大的词对应的神经元即可。

   Skip-Gram模型和CBOW的思路是反着来的,即输入是特定的一个词的词向量,而输出是特定词对应的上下文词向量。还是上面的例子,我们的上下文大小取值为4, 特定的这个词"Learning"是我们的输入,而这8个上下文词是我们的输出。

  这样我们这个Skip-Gram的例子里,我们的输入是特定词, 输出是softmax概率排前8的8个词,对应的Skip-Gram神经网络模型输入层有1个神经元,输出层有词汇表大小个神经元。隐藏层的神经元个数我们可以自己指定。通过DNN的反向传播算法,我们可以求出DNN模型的参数,同时得到所有的词对应的词向量。这样当我们有新的需求,要求出某1个词对应的最可能的8个上下文词时,我们可以通过一次DNN前向传播算法得到概率大小排前8的softmax概率对应的神经元所对应的词即可。

 以上就是神经网络语言模型中如何用CBOW与Skip-Gram来训练模型与得到词向量的大概过程。但是这和word2vec中用CBOW与Skip-Gram来训练模型与得到词向量的过程有很多的不同。

  word2vec为什么不用现成的DNN模型,要继续优化出新方法呢?最主要的问题是DNN模型的这个处理过程非常耗时。我们的词汇表一般在百万级别以上,这意味着我们DNN的输出层需要进行softmax计算各个词的输出概率的的计算量很大。有没有简化一点点的方法呢?


      3、Hierarchical Softmax

    层次Softmax的方法最早由Bengio在05年引入到语言模型中。它的基本思想是将复杂的归一化概率分解为一系列条件概率乘积的形式:

p(v|context)=i=1mp(bi(v)|b1(v),...,bi1(v),context) 
      其中,每一层条件概率对应一个二分类问题,可以通过一个简单的逻辑回归函数去拟合。这样,我们将对V个词的概率归一化问题,转化成了对logVlog⁡V个词的概率拟合问题。 我们可以通过构造一颗分类二叉树来直观地理解这个过程。首先,我们将原始字典D

   D划分为两个子集D1D2,并假设在给定context下,target word属于子集D1D1的概率p(wtD1|context)p服从logistical function的形式:

p(wtD1|context)=11+eUDrootVwt
其中,UDrootUDrootVwtVwt都是模型的参数。

      接下来,我们可以对子集D1D2进一步划分。重复这一过程,直到集合里只剩下一个word。这样,我们就将原始大小为V的字典D转换成了一颗深度为logV的二叉树。树的叶子节点与原始字典里的word一一对应;非叶节点则对应着某一类word的集合。显然,从根节点出发到任意一个叶子节点都只有一条唯一路径——这条路径也编码了这个叶子节点所属的类别。

      同时,从根节点出发到叶子节点也是一个随机游走的过程。因此,我们可以基于这颗二叉树对叶子节点出现的似然概率进行计算。例如,对于训练样本里的一个target word wtwt,假设其对应的二叉树编码为{1,0,1,...,1},则我们构造的似然函数为:

p(wt|context)=p(D1=1|context)p(D2=0|D1=1)p(wt|Dk=1)
乘积中的每一项都是一个逻辑回归的函数。

     我们可以通过最大化这个似然函数来求解二叉树上的参数——非叶节点上的向量,用来计算游走到某一个子节点的概率。

     层次Softmax是一个很巧妙的模型。它通过构造一颗二叉树,将目标概率的计算复杂度从最初的VV降低到了logVlog⁡V的量级。不过付出的代价是人为增强了词与词之间的耦合性。例如,一个word出现的条件概率的变化,会影响到其路径上所有非叶节点的概率变化,间接地对其他word出现的条件概率带来不同程度的影响。因此,构造一颗有意义的二叉树就显得十分重要。实践证明,在实际的应用中,基于Huffman编码的二叉树可以满足大部分应用场景的需求。

      4、 Negative Sampling

     负采样的思想最初来源于一种叫做Noise-Contrastive Estimation的算法[6],原本是为了解决那些无法归一化的概率模型的参数预估问题。与改造模型输出概率的层次Softmax算法不同,NCE算法改造的是模型的似然函数。

以Skip-gram模型为例,其原始的似然函数对应着一个Multinomial的分布。在用最大似然法求解这个似然函数时,我们得到一个cross-entropy的损失函数:

J(θ)=1Tt=1Tcjc,j0logp(wt+j|wt)

      而在NCE算法中,我们构造了这样一个问题:对于一组训练样本,我们想知道,target word的出现,是来自于context的驱动,还是一个事先假定的背景噪声的驱动?显然,我们可以用一个逻辑回归的函数来回答这个问题:

p(D=1|w,context)=p(w|context)p(w|context)+kpn(w)=σ(logp(w|context)logkpn(w))



k是一个先验参数,表明噪声的采样频率。p(w|context)是一个非归一化的概率分布,这里采用softmax归一化函数中的分子部分。pn(w)则是背景噪声的词分布。通常采用word的unigram分布。

   通过对噪声分布的k采样,我们得到一个新的数据集:。其中,label标记了数据的来源(真实数据分布还是背景噪声分布?)。在这个新的数据集上,我们就可以用最大化上式中逻辑回归的似然函数来求解模型的参数。

而Mikolov在2013年的论文里提出的负采样算法, 是NCE的一个简化版本。在这个算法里,Mikolov抛弃了NCE似然函数中对噪声分布的依赖,直接用原始softmax函数里的分子定义了逻辑回归的函数,进一步简化了计算:

p(D=1|wo,wi)=σ(UoVi)
此时,模型相应的目标函数变为:
J(θ)=logσ(UoVi)+j=1kEwjpn(w)[logσ(UjVi)]

除了这里介绍的层次Softmax和负采样的优化算法,Mikolov在13年的论文里还介绍了另一个trick:下采样(subsampling)。其基本思想是在训练时依概率随机丢弃掉那些高频的词:

pdiscard(w)=1tf(w)

t是一个先验参数,一般取为105f(w)f(w)ww在语料中出现的频率。

实验证明,这种下采样技术可以显著提高低频词的词向量的准确度。

         4、参考资料

         (1)  https://www.jianshu.com/p/da235893e4a5?utm_campaign=maleskine&utm_content=note&utm_medium=pc_all_hots&utm_source=recommendation

         (2)http://blog.csdn.net/mytestmy/article/details/26969149

            (3)http://techblog.youdao.com/?p=915

        (4)http://www.52nlp.cn/tag/word2vec

 

猜你喜欢

转载自blog.csdn.net/zhangye_2017/article/details/79546039
今日推荐