来自 | 知乎   作者 | TianMin
链接丨https://zhuanlan.zhihu.com/p/85998950
编辑 | 深度学习这件小事公众号
本文仅作学术交流,如有侵权,请联系删除
【前言】word2vec是一个被广泛应用的word embedding方法,由于最近研究需要,将算法模型研究了一下由于word2vec内容很多,这里尽量讲解核心内容,有不足之处还请指出!
word2vec是轻量级的神经网络,其模型仅仅包括输入层、隐藏层和输出层,模型框架根据输入输出的不同,主要包括CBOW和skip-gram模型,CBOW模型是通过上下文的内容预测中间的目标词,而skip-gram则相反,通过目标词预测其上下文的词,通过最大化词出现的概率,我们训练模型可得到各个层之间的权重矩阵,我们所说的得到的word embedding vector就是从这个权重矩阵里面得来的。
 1、CBOW
(1)Simple CBOW model
为了更好的了解模型深处的原理,我们先从Simple CBOW model(仅输入一个词,输出一个词)框架 说起。
Simple CBOW model 框架
如图:
a. input layer输入的X是单词的one-hot representation(考虑一个词表V,里面的每一个词wi都有一个编号i∈{1,...,|V|},那么词wi的one-hot表示就是一个维度为|V|的向量,其中第i个元素值非零,其余元素全为0,例如:w2=[0,1,0,...,0]T);
b. 输入层到隐藏层之间有一个权重矩阵W,隐藏层得到的值是由输入X乘上权重矩阵得到的(细心的人会发现,0-1向量乘上一个矩阵,就相当于选择了权重矩阵的某一行,如图:输入的向量X是[0,0,1,0,0,0],W的转置乘上X就相当于从矩阵中选择第3行[2,1,3]作为隐藏层的值);
c. 隐藏层到输出层也有一个权重矩阵W',因此,输出层向量y的每一个值,其实就是隐藏层的向量点乘权重向量W'的每一列,比如输出层的第一个数7,就是向量[2,1,3]和列向量[1,2,1]点乘之后的结果。
d. 最终的输出需要经过softmax函数(不懂可以百度一下),将输出向量中的每一个元素归一化到0-1之间的概率,概率最大的,就是预测的词。
了解了Simple CBOW model的模型框架之后,我们来学习一下其目标函数。
输出层softmax,u代表的是输出层的原始结果
这个公式学过高数的应该都懂
通过上一个公式,我们的目标函数可以转化为现在这个形式
加上负号之后,就变成最小化损失函数
训练方法就是经典的反向传播和梯度下降(不是本章重点,不展开说了)
(2)CBOW
了解了Simple CBOW model之后,扩展到CBOW就很容易了,只是把单个输入换成多个输入罢了(划红线部分)。
对比可以发现,和simple CBOW不同之处在于,输入由1个变成了C个,每个输入Xik到达隐藏层都会经过相同的权重矩阵W,隐藏层h的值变成了多个词乘上权重矩阵之后加和求平均值。
2、skip-gram model
有了CBOW的介绍,对于skip-gram model 的理解应该会更快一些。
如图所示:
skip-gram model是通过输入一个词去预测多个词的概率。输入层到隐藏层的原理和simple CBOW一样,不同的是隐藏层到输出层,损失函数变成了C个词损失函数的总和,权重矩阵W'还是共享的。
3、word2vec模型训练机制(优化方法)
一般神经网络语言模型在预测的时候,输出的是预测目标词的概率,也就是说我每一次预测都要基于全部的数据集进行计算,这无疑会带来很大的时间开销。不同于其他神经网络,word2vec提出两种加快训练速度的方式,一种是Hierarchical softmax,另一种是Negative Sampling。
(1)hierarchical softmax
预备知识:哈夫曼编码,如图所示:
哈夫曼树
哈夫曼编码
原始神经网络模型的输入输出框架
word2vec hierarchical softmax结构
和传统的神经网络输出不同的是,word2vec的hierarchical softmax结构是把输出层改成了一颗哈夫曼树,其中图中白色的叶子节点表示词汇表中所有的|V|个词,黑色节点表示非叶子节点,每一个叶子节点也就是每一个单词,都对应唯一的一条从root节点出发的路径。我们的目的是使的w=wO这条路径的概率最大,即: P(w=wO|wI)最大,假设最后输出的条件概率是W2最大,那么我只需要去更新从根结点到w2这一个叶子结点的路径上面节点的向量即可,而不需要更新所有的词的出现概率,这样大大的缩小了模型训练更新的时间。
我们应该如何得到某个叶子结点的概率呢?
假设我们要计算W2叶子节点的概率,我们需要从根节点到叶子结点计算概率的乘积。我们知道,本模型替代的只是原始模型的softmax层,因此,某个非叶子节点的值即隐藏层到输出层的结果仍然是uj,我们对这个结果进行sigmoid之后,得到节点往左子树走的概率p,1-p则为往右子树走的概率。关于这棵树的训练方式比较复杂,但也是通过梯度下降等方法,这里不详述,感兴趣的可以阅读论文word2vec Parameter Learning Explained
(2)Negative Sampling 负采样
传统神经网络在训练过程中的每一步,都需要计算词库中其他词在当前的上下文环境下出现的概率值,这导致计算量十分巨大。
然而,对于word2vec中的特征学习,可以不需要一个完整的概率模型。CBOW和Skip-Gram模型在输出端使用的是一个二分类器(即Logistic Regression),来区分目标词和词库中其他的 k个词(也就是把目标词作为一类,其他词作为另一类)。下面是一个CBOW模型的图示,对于Skip-Gram模型输入输出是倒置的。
此时,最大化的目标函数如下:
其中,Qθ(D=1|w,h)为二元逻辑回归的概率,具体为在数据集 D中、输入的embedding vector θ、上下文为 h的情况下词语 w 出现的概率;公式后半部分为 k 个从 [噪声数据集] 中随机选择 kk个对立的词语出现概率(log形式)的期望值。可以看出,目标函数的意义是显然的,即尽可能的 [分配(assign)] 高概率给真实的目标词,而低概率给其他 k 个 [噪声词],这种技术称为负采样(Negative Sampling)
这种想法来源于噪声对比评估方法(NEC),大致思想是:假设X=(x1,x2,⋯,xTd)是从真实的数据(或语料库)中抽取样本,但是样本服从什么样的分布我们不知道,那么先假设其中的每个xi服从一个未知的概率密度函数pd。这样我们需要一个相对可参考的分布反过来去估计概率密度函数pd,这个可参考的分布或称之为噪音分布应该是我们知道的,比如高斯分布,均匀分布等。假设这个噪音分布的概率密度函数pn,从中抽取样本数据为Y=(y1,y2,⋯,yTn)Y=(y1,y2,⋯,yTn),而这个数据称之为噪声样本,我们的目的就是通过学习一个分类器把这两类样本区别开来,并能从模型中学到数据的属性,噪音对比估计的思想就是“通过比较而学习”。
具体来说,word2vec里面的负采样:将输出层的V个样本分为正例(Positive Sample)也就是目标词对应的项,以及剩余V−1个负例(Negative Samples)。举个例子有个样本phone number,这样wI=phone, wO=number, 正例就是number这个词,负例就是不太可能与phone共同出现的词。负采样的思想是每次训练只随机取一小部分的负例使他们的概率最小,以及对应的正例概率最大。随机采样需要假定一个概率分布,word2vec中直接使用词频作为词的分布,不同的是频数上乘上0.75,相比于直接使用频次作为权重,取0.75幂的好处可以减弱不同频次差异过大带来的影响,使得小频次的单词被采样的概率变大。
采样权重
负采样定义的损失函数如下:
损失函数,一部分是正样本(期望输出的词),另一部分是负采样随机抽取出来的负样本集合,V'wo是输出向量
如果大家理解的还不是很深的话,接下来将通过谷歌发布的tensorflow官方word2vec代码解析加深理解。
代码链接:
https://github.com/tensorflow/tensorflow/blob/master/tensorflow/examples/tutorials/word2vec/word2vec_basic.py
之后我会对代码进行详细剖析,欢迎跟踪~谢谢
  推荐阅读相关论文
继续阅读
阅读原文