Word2Vec

  • 引言解释
  • 计算方法
  • CBOW
  • skip-gram
  • 优化技巧:softmax
  • negative sampling
  • hierarchical softmax


引言解释

词嵌入即利用向量来表示单词,表示原则是一个单词的意思是由经常出现在它附近的单词给出的,即我们需要刻画单词的上下文关系。转化成数学就是,我们需要构建一个词空间,用词空间里的向量来表示单词,相似词对应的词向量在空间上距离近

如何去构建一个词向量空间呢,我们延续上文神经语言模型_逐段解读的方法,利用神经网络的方法。但是,我们并不需要进行完整的NNLM(非线性层的计算量非常大),我们只需要前面的线性部分,构造一个简单(计算量相比NNLM小)对数线性分类器(log-linear classifier)就可以。

计算方法

CBOW

词嵌入 python实现 词嵌入模型_自然语言处理

CBOW的结构是利用上下文来求中心词的线性对数分类器,最终获取从输入到Projection层的权重作为词向量矩阵(空间)。
CBOW是Continuous Bag-of-Words Model,有点类似NNLM,但是它没有非线性的隐藏层,且线性层(projection layer)是共享给词库中所有词,而不是像NNLM一样只供输入词使用。同时这里考虑上下文,而不是仅考虑上文。
之所以称之为bag of words是因为这里对上下文进行求平均组成一个向量来预测中心词。忽略了上下文的语序。continuous则是因为这里选取的上下文是连续的(虽然在后续处理中不考虑语序)
具体训练的数学推到公式如下
1)假定输入上下文分别为词嵌入 python实现 词嵌入模型_nlp_02,可以根据词库表词嵌入 python实现 词嵌入模型_词嵌入 python实现_03获取相应的one-hotting向量,进一步得到初始化词向量分别为词嵌入 python实现 词嵌入模型_自然语言处理_04,这里词向量的获取方法实际上就是one-hotting向量乘以词向量矩阵,这也是Projection层得来的原因,这里的词向量矩阵的参数实际上就是全连接的Projection层的网络权重。
词嵌入 python实现 词嵌入模型_自然语言处理_04取向量元素级平均,得到$\bar{x} $
2)对于此表中任何一个词词嵌入 python实现 词嵌入模型_自然语言处理_06,我们可以通过神经网络线性分类器的前向输出,得到这个词属于中心词的概率,为词嵌入 python实现 词嵌入模型_神经网络_07
这里的词嵌入 python实现 词嵌入模型_词嵌入 python实现_08是词b在输出矩阵(从Projection到预测层之间的权重)对应行的向量。
3) 重复上述步骤2),可以得到词库表词嵌入 python实现 词嵌入模型_词嵌入 python实现_03中每一个词属于中心词的概率,拼起来可以得到一个概率向量词嵌入 python实现 词嵌入模型_神经网络_10
4) 已知真实的中心词是词嵌入 python实现 词嵌入模型_词嵌入 python实现_11,转化成one-hotting向量是词嵌入 python实现 词嵌入模型_词嵌入 python实现_12,可以利用交叉熵作为损失函数(原因可以参见为什么交叉熵(cross-entropy)可以用于计算代价? - 微调的回答 - 知乎),这样可以得到损失函数为词嵌入 python实现 词嵌入模型_nlp_13。这一步等式的原因是词嵌入 python实现 词嵌入模型_词嵌入 python实现_12是one-hotting,这里的词嵌入 python实现 词嵌入模型_nlp_15是向量的权重,也就是神经网络的参数
5) 利用损失函数进行SGD,不断训练迭代最终可以得到最优的词嵌入 python实现 词嵌入模型_nlp_15,进而得到最优词向量矩阵,得到最优词向量。
至于为什么梯度下降法训练得到的结果,预测出来的是接近正确的上下文,可以参考梯度下降的数学解释,这里因为符号标记不一样,我就不展开说了。

skip-gram

词嵌入 python实现 词嵌入模型_自然语言处理_17


skip-gram是基于中心词预测上下文的对数线性分类器。重点的区别在Projection层到预测层。

预测层需要输出2m个上下文(上下文的半径为m),所以输出概率也是2m个,公式如下:

词嵌入 python实现 词嵌入模型_词嵌入 python实现_18

这里词嵌入 python实现 词嵌入模型_nlp_19是真实的上下文词,词嵌入 python实现 词嵌入模型_nlp_20该词在输出矩阵对应行的向量。

这里有2个坑:

  1. 我一开始理解预测输出的时候应该是采用topk的方法,只输出概率值最大的k(=2m)个词作为上下文,后来发现这里的skip-gram只是用于训练得到中间层作为权重,所以只需要将真实上下文对应向量做训练就好,没有输出topk的步骤
  2. 虽然输入词只有一个,但是不意味着训练好的中间层就是输入词的词向量,只有训练好的输入矩阵,才是词向量的组合。
    损失函数计算中,因为这里不考虑输出词之间的顺序,我们这边假设词之间是独立的,采用naive bayes
    词嵌入 python实现 词嵌入模型_词向量_21

优化技巧:softmax

word2vec的计算瓶颈在于softmax层的计算,因为softmax分母需要对此表中所有词都进行向量乘计算,每一次训练都需要更新迭代,计算量非常大。
为此,有两种优化方法来解决这一问题,分别是negative sampling和hierarchical softmax

negative sampling

negative sampling的方法非常直观,因为相比真实的输出值(设为正样本,输出为1),假的输出值(负样本)数量是巨大的(词嵌入 python实现 词嵌入模型_词嵌入 python实现_22),所以对负样本进行抽样选取训练,减少计算量。

Mikolov推荐使用的负样本抽样分布是词嵌入 python实现 词嵌入模型_神经网络_23,这里词嵌入 python实现 词嵌入模型_nlp_24是均匀分布

这个分布的好处是提升低频词相对被抽中的概率。详细见这个指数幂的图

词嵌入 python实现 词嵌入模型_自然语言处理_25

hierarchical softmax

分层softmax,其结构就是一个霍夫曼树,首先介绍一下霍夫曼树。

基本概念:

路径:从根节点到结点通路长度

权值:赋予结点的数值,w2v里是频数

结点带权路径:结点路径*结点权值

树的带权路径:所有叶子结点的带权路径之和

霍夫曼树:使树带权路径最小的二叉树

霍夫曼树的构造方法:

1)将词嵌入 python实现 词嵌入模型_词嵌入 python实现_26看成是n棵树的森林

2)从森林中选择根节点权值最小的两棵树合并,作为一棵新树的左右子树,且新树的根节点权值为左右子树根节点权值的和

3)从森林中删除选取的两棵树,并将新树加入森林

4)重复2),3)两步,直到森林中只剩下一棵树为止,该树即为霍夫曼树

从网上找到一个例子。以词频作为权值,可以看出,高频词离根节点最近,最容易被访问。

词嵌入 python实现 词嵌入模型_nlp_27


作为hierarchical softmax,是将隐藏层(Projection)到输出层这一部分(也就是输出矩阵)变成霍夫曼树。霍夫曼树中,根节点是隐藏层向量,叶子节点是可能输出词,大小和词库一致。

词嵌入 python实现 词嵌入模型_nlp_28


具体来说,输入利用二元逻辑回归方法分左右支流动,最终输出叶子节点。从根节点流动到叶子节点得到的路径概率就是该单词输出的概率,因此,相比原先计算每一个单词输出概率需要计算V次(softmax分母),利用这个方法仅需要计算词嵌入 python实现 词嵌入模型_自然语言处理_29次(二叉树)

词嵌入 python实现 词嵌入模型_nlp_30


这里词嵌入 python实现 词嵌入模型_神经网络_31表示内部节点,词嵌入 python实现 词嵌入模型_nlp_32表示任意一个节点,论文中默认左边节点,词嵌入 python实现 词嵌入模型_神经网络_33,结合sigmoid可以推断,词嵌入 python实现 词嵌入模型_神经网络_34,进一步,可以推断,词嵌入 python实现 词嵌入模型_词向量_35