Word2vec

在聊 Word2vec 之前,先聊聊 NLP (自然语言处理)。NLP 里面,最细粒度的是 词语,词语组成句子,句子再组成段落、篇章、文档。所以处理 NLP 的问题,首先就要拿词语开刀。

举个简单例子,判断一个词的词性,是动词还是名词。用机器学习的思路,我们有一系列样本(x,y),这里 x 是词语,y 是它们的词性,我们要构建 f(x)->y 的映射,但这里的数学模型 f(比如神经网络、SVM)只接受数值型输入,而 NLP 里的词语,是人类的抽象总结,是符号形式的(比如中文、英文、拉丁文等等),所以需要把他们转换成数值形式,或者说——嵌入到一个数学空间里,这种嵌入方式,就叫词嵌入(word embedding),而 Word2vec,就是词嵌入( word embedding) 的一种。

2013年,Google开源了一款用于词向量计算的工具——word2vec。word2vec可以在百万数量级的词典和上亿的数据集上进行高效地训练;其次,该工具得到的训练结果——词向量(word embedding),可以很好地度量词与词之间的相似性。随着深度学习(Deep Learning)在自然语言处理中应用的普及,很多人误以为word2vec是一种深度学习算法。其实word2vec算法的背后是一个浅层神经网络。另外需要强调的一点是,word2vec是一个计算word vector的开源工具。当我们在说word2vec算法或模型的时候,其实指的是其背后用于计算word vector的CBoW模型和Skip-gram模型。

 

NLP词的表示方法类型

  1、词的独热表示one-hot

  2、词的分布式表示 distributed representation

      词的分布式表示主要可以分为三类:基于矩阵的分布表示、基于聚类的分布表示和基于神经网络的分布表示

  

基于神经网络的分布表示又称为词向量或者词嵌入。 2001年, Bengio 等人正式提出神经网络语言模型( Neural Network Language Model ,NNLM),该模型在学习语言模型的同时,也得到了词向量。所以请注意一点:词向量可以认为是神经网络训练语言模型的副产品。通过神经网络训练语言模型可以得到词向量,那么,究竟有哪些类型的神经网络语言模型呢?个人所知,大致有这么些:

  a) Neural Network Language Model ,NNLM
  b) Log-Bilinear Language Model, LBL
  c) Recurrent Neural Network based Language Model,RNNLM
  d) Collobert 和 Weston 在2008 年提出的 C&W 模型
  e) Mikolov 等人提出了 CBOW( Continuous Bagof-Words)和 Skip-gram 模型
  如今我们主要用到的是CBOW和Skip-gram模型。

要想得到一个词的向量表达方法,并且这个向量的维度很小,而且任意两个词之间是有联系的,可以表示出在语义层面上词语词之间的相关信息。我们就需要训练神经网络语言模型,即CBOW和Skip-gram模型。这个模型的输出我们不关心,我们关心的是模型中第一个隐含层中的参数权重,这个参数矩阵就是我们需要的词向量。它的每一行就是词典中对应词的词向量,行数就是词典的大小。

  • 如果是用一个词语作为输入,来预测它周围的上下文,那这个模型叫做『Skip-gram 模型』
  • 而如果是拿一个词语的上下文作为输入,来预测这个词语本身,则是 『CBOW 模型』

 

CBOW
  CBOW(Continuous Bag-of-Word Model)又称连续词袋模型,是一个三层神经网络。如下图所示,该模型的特点是输入已知上下文,输出对当前单词的预测。

 

 

 


其学习目标是最大化对数似然函数:

 

 

 

 

其中,w表示语料库C中任意一个词。
下面上一个更细节的一个图:

 

 

 [C,V]*[V,N]=[C,N]------->[1,N]

[1,N]*[N,V]=[1,V]

公式咱们就不放了,网络计算的步骤:

  输入层:上下文单词的onehot。(假设单词向量空间dim为V,上下文单词个数为C)
  所有onehot分别乘以共享的输入权重矩阵WV*N矩阵,N为自己设定的数,初始化权重矩阵W)
  所得的向量 (注意onehot向量乘以矩阵的结果) 相加求平均作为隐层向量, size为1*N.
  乘以输出权重矩阵W’ {N*V}
  得到向量 {1*V} 激活函数处理得到V-dim概率分布 {PS: 因为是onehot嘛,其中的每一维斗代表着一个单词},概率最大的index所指示的单词为预测出的中间词(target word)
  与true label的onehot做比较,误差越小越好。loss function(一般为交叉熵代价函数)
  我们并不关心输出的内容,预测的结果不重要,重要的是训练完成后第一个全连接层的参数就是我们要的word embedding矩阵。

 

 

 

跳字模型(skip-gram)

  通过中心词来推断上下文一定窗口内的单词。

 

 

[1,V]*[V,d]=[1,d]  d为词向量的维度  [V,d]为所有词的热编码[V,V]在d维空间的映射W[V,d]

[1,d]*[d,V]=[1,V]  重复c次------>[C,V]  初始化一个d维空间的矩阵作为权重矩阵W'[d,V]

 

skip-gram神经网络包含一个巨大的权重矩阵。例如,300个特征,10000个单词字典,那么输出层和隐藏层都将有3M个权重。在一个大的数据集上进行训练是很难的,所以word2vec作者引入了一些调整来使训练变得可行。

1.负采样(negative sampling)

负采样(negative sampling)解决了这个问题,它是用来提高训练速度并且改善所得到词向量的质量的一种方法。不同于原本每个训练样本更新所有的权重,负采样每次让一个训练样本仅仅更新一小部分的权重,这样就会降低梯度下降过程中的计算量。

随机采样的方法即,假设现在共有N个unique样本,我们统计这N个样本的频率,从小到大得到(n1, n2, ..., nN),将频率进行累计归一化,则归一化的结果为(n1/sum, (n1+n2)/sum, ..., 1),归一化到(0,1)上。然后,在(0,1)上生成随机数,通过判断该随机数所属的区间,得到样本,若这个样本不为正样本,则保留下来作为负样本。这样采样即可以保证随机抽取,同时可以保证频率高的样本被抽到的可能性高。

negative sampling的是NCE(Noise-Constrastive Estimation)噪声对比估计的一种简化版本,感兴趣的读者可以去谷歌阅读一下原文。我们知道在softmax中,输出是WWW维的向量C,每个分量cic_ici表示预测为第iii个词的概率,我们选择概率最大的词作为当前的输出值,negative sampling 的思想是只需要按照一定的概率分布P(w˜)P( \tilde{w})P(w~) 抽取K个负样本,比如在skip-gram的例子中,输入“fox”,抽出的负样本可能是“two”,“mother”等等,与正样本放在一起,将多分类问题转换成K+1个二分类问题,从而减少计算量,加快训练速度。为了解释这种思想,我们首先定义一些概念。 

2.层序softmax --------Hierarchical Softmax

Huffman Tree

中文名叫霍夫曼树/霍夫曼编码,是个二叉树(注意不是二叉搜索树),这部分内容比较简单,维基百科上也说的非常清楚,下面搬运一下维基百科上的例子
示例:
霍夫曼树常处理符号编写工作。根据整组数据中符号出现的频率高低,决定如何给符号编码。如果符号出现的频率越高,则给符号的码越短,相反符号的号码越长。假设我们要给一个英文单字"F O R G E T"进行霍夫曼编码,而每个英文字母出现的频率分别列在Fig.1。

 

演算过程:

(一)进行霍夫曼编码前,我们先创建一个霍夫曼树。

  1. 将每个英文字母依照出现频率由小排到大,最小在左,如Fig.1。
  2. 每个字母都代表一个终端节点(叶节点),比较F.O.R.G.E.T六个字母中每个字母的出现频率,将最小的两个字母频率相加合成一个新的节点。如Fig.2所示,发现F与O的频率最小,故相加2+3=5。
  3. 比较5.R.G.E.T,发现R与G的频率最小,故相加4+4=8。
  4. 比较5.8.E.T,发现5与E的频率最小,故相加5+5=10。
  5. 比较8.10.T,发现8与T的频率最小,故相加8+7=15。
  6. 最后剩10.15,没有可以比较的对象,相加10+15=25。

最后产生的树状图就是霍夫曼树,参考Fig.2。


 
  1. 给霍夫曼树的所有左链接'0'与右链接'1'。
  2. 从树根至树叶依序记录所有字母的编码,如Fig.3。

 

 

上图输出层的树形结构即为Hierarchical Softmax。

每个叶子节点代表语料库中的一个词,于是每个词语都可以被01唯一的编码,并且其编码序列对应一个事件序列,于是我们可以计算条件概率 [公式]

在开始计算之前,还是得引入一些符号:

1. [公式] :从根结点出发到达w对应叶子结点的路径

2. [公式] :路径中包含结点的个数

3. [公式] :路径 [公式] 中的各个节点

4. [公式] :词w的编码, [公式] 表示路径 [公式] 第j个节点对应的编码(根节点无编码)

5. [公式] :路径 [公式] 中非叶节点对应的参数向量

于是可以给出w的条件概率:

[公式]

这是个简单明了的式子,从根节点到叶节点经过了 [公式] 个节点,编码从下标2开始(根节点无编码),对应的参数向量下标从1开始(根节点为1)。

其中,每一项是一个逻辑斯谛回归:

[公式]

考虑到d只有0和1两种取值,我们可以用指数形式方便地将其写到一起:

[公式]

我们的目标函数取对数似然:

[公式]

将 [公式] 代入上式,有:

[公式]

[公式]

这也很直白,连乘的对数换成求和。不过还是有点长,我们把每一项简记为:

[公式]

怎么最大化对数似然函数呢?分别最大化每一项即可(这应该是一种近似,最大化某一项不一定使整体增大,具体收敛的证明还不清楚)。怎么最大化每一项呢?先求函数对每个变量的偏导数,对每一个样本,代入偏导数表达式得到函数在该维度的增长梯度,然后让对应参数加上这个梯度,函数在这个维度上就增长了。这种白话描述的算法在学术上叫随机梯度上升法,详见更规范的描述

每一项有两个参数,一个是每个节点的参数向量 [公式] ,另一个是输出层的输入 [公式] ,我们分别对其求偏导数:

[公式]

因为sigmoid函数的导数有个很棒的形式:

[公式]

于是代入上上式得到:

[公式]

合并同类项得到:

[公式]

于是 [公式]的更新表达式就得到了:

[公式]

其中, [公式] 是学习率,通常取0-1之间的一个值。学习率越大训练速度越快,但目标函数容易在局部区域来回抖动。

再来 [公式] 的偏导数,注意到 [公式] 中 [公式] 和 [公式] 是对称的,所有直接将 [公式] 的偏导数中的 [公式] 替换为 [公式] ,得到关于 [公式] 的偏导数:

[公式]

于是 [公式] 的更新表达式也得到了。

不过 [公式] 是上下文的词向量的和,不是上下文单个词的词向量。怎么把这个更新量应用到单个词的词向量上去呢?word2vec采取的是直接将 [公式] 的更新量整个应用到每个单词的词向量上去:

[公式]

计算过程:
  将所有词放入Huffman Tree中,假设树有n+1个结点,那么每个单词就能n个0或1唯一表示(后面补0)记为NUM
  对于CBow,  [C,V]*[V,N]=[C,N]------->[1,N]
          [1,N]---sigmoid-->[1,NUM]
 
        使得概率相乘最大化,更新参数

 


总结
最后强调一下,word2vec一个NLP工具,它可以将所有的词向量化,这样词与词之间就可以定量的去度量他们之间的关系,挖掘词之间的联系。word2vec主要包含两个模型Skip-gram和CBOW。以及两种高效的训练方法负采样,层序softmax。
关于Word2Vec的详细介绍终于结束了,相信看完本文章你会理解Word2Vec的来龙去脉。下面读者可以查看下面的章节用TensorFlow来实现Word2Vec。

 

posted @ 2020-05-02 15:52  CeasonCing  阅读(277)  评论(2)    收藏  举报