word2vec算法理解和数学推导

从字面意思就可以理解word2vec是把文本转换成向量,那么文本如何转换成向量呢,最简单的方法大家都会想到独热编码,但是独热编码的缺点也很明显,首先独热编码向量是正交的,任何两个独热编码相乘都等于0,所以无法通过任何的计算来得到两个词的相似度;还有一个原因就是维度过大,比如100000个词汇用独热编码表示成向量,就会有100000个维度,简直就是维度灾难。所以一般来说,在词语向量化的时候都不使用独热编码的方法,那么我们如何通过向量来表达词语的意思呢,我们可以通过调整一个单词和这个单词上下文单词的向量,使得根据两个向量来推测出两个词语的相似度,或者根据向量来推测上下文。
word2vec是一个最常见的转词向量的框架,里面包含了Skip-grams(SG)和Continuous Bag of Words(CBOW),这两种算法的最大区别就是Skip-grams(SG)算法是通过中心词汇推测上下文,而CBOW是通过上下文预测中心词。我们来看Christopher Manning教授的SG模型:
word2vec算法理解和数学推导
我们可以看到中心词汇是banking,这个是我们的input word,m是我们词语窗口的长度,表示中心词语前后的m个词语,整个模型中只有一个条件分布,因为这是一个词袋模型,与位置是无关的,所以我们的目的就是最大化这些概率。首先我们来定义一个目标函数,我们把目标函数定义为我们预测结果的乘积:
J(θ)=t=1Tmjmj0p(wt+jwt;θ)J'(\theta ) = \prod\limits_{t = 1}^T {\prod\limits_{\mathop { - m \leqslant j \leqslant m}\limits_{j \ne 0} } {p({w_{t + j}}|{w_t};\theta )} }
这里我们就需要优化这个目标函数使其最大化,TT表示总的词数量,每一个词前后m个词的概率我们都要计算,为了方便计算,我们可以吧这个目标函数换一种形式,得到损失函数,这里我们用的是对数似然的相反数:
J(θ)=1Tt=1Tmjmj0logP(wt+jwt)J(\theta ) = - \frac{1}{T}\sum\limits_{t = 1}^T {\sum\limits_{\mathop { - m \leqslant j \leqslant m}\limits_{j \ne 0} } {\log P({w_{t + j}}|{w_t})} }
在这个公式中,我们得到的P(wt+jwt)P({w_{t + j}}|{w_t})是通过softmax得到的,那么我们将向量带入softmax公式可以得到:
P(oc)=exp(uoTvc)w=1Vexp(uwTvc)P(o|c) = \frac{{\exp (u_o^T \cdot {v_c})}}{{\sum\limits_{w = 1}^V {\exp (u_w^T \cdot {v_c})} }}
在这个公式中oo是指上下文中某一个词,cc是指中心词;uu是指对应的上下文词向量,vv是指词向量,那么uo{u_o}表示指定的那个词的上下文向量,vc{v_c}表示中心词的词向量,这么看来,损失函数就比较容易理解了。这里的softmax大家也是比较了解的,就是将得分的实数转换成一个归一化的概率分布。下图就是整个skip-grams的算法流程以及每一步的解释:
word2vec算法理解和数学推导
由上图就可以清楚地知道SG算法每一步的流程以及意义了,里面向量的数字不代表真实意思,是瞎编的,重要的是流程,最终我们的损失函数就是比对真实向量与我们计算出来的答案的差距,要最小化损失函数,最大化输出概率。那么怎么去学习这个模型呢,怎么去最小化损失函数呢?肯定是梯度下降法了,所以对损失函数的Vc求偏导,把常数去掉之后,损失函数就可以表示成:
logexp(uoTvc)w=1Vexp(uwTvc)\log \frac{{\exp (u_o^T \cdot {v_c})}}{{\sum\limits_{w = 1}^V {\exp (u_w^T \cdot {v_c})} }}
接着我们对损失函数的Vc求偏导,就可以得到:
vcJ(θ)=vclogexp(uoTvc)w=1Vexp(uwTvc)\frac{\partial }{{\partial {v_c}}}J(\theta ) = \frac{\partial }{{\partial {v_c}}}\log \frac{{\exp (u_o^T \cdot {v_c})}}{{\sum\limits_{w = 1}^V {\exp (u_w^T \cdot {v_c})} }}
对数内部的除法相当于对数外部的减法,那么这个式子可以表示成:
vclogexp(uoTvc)vclogw=1Vexp(uwTvc) \frac{\partial }{{\partial {v_c}}}\log \exp (u_o^T \cdot {v_c}) - \frac{\partial }{{\partial {v_c}}}\log \sum\limits_{w = 1}^V {\exp (u_w^T \cdot {v_c})}
然后我们再把这整个式子看成两个部分,首先是第一个部门,因为指数之后再求对数还是本身,所以第一项可以表示成:
vclogexp(uoTvc)=(uoTvc)vc=uo\frac{\partial }{{\partial {v_c}}}\log \exp (u_o^T \cdot {v_c}) = \frac{{\partial (u_o^T \cdot {v_c})}}{{\partial {v_c}}} = {u_o}
所以第一项就是uou_o,我们再来看第二部分的计算:
vclogw=1Vexp(uwTvc)\frac{\partial }{{\partial {v_c}}}\log \sum\limits_{w = 1}^V {\exp (u_w^T \cdot {v_c})}
对于这种复杂的复合函数求偏导,首先我们就会想到的是复合函数的链式求导法则,那么这个第二项求偏导可以有如下推导:
1w=1Vexp(uwTvc)x=1Vexp(uxTvc)(uxTvc)vc=1w=1Vexp(uwTvc)x=1Vexp(uxTvc)ux=x=1Vexp(uxTvc)w=1Vexp(uwTvc)ux\frac{1}{{\sum\limits_{w = 1}^V {\exp (u_w^T \cdot {v_c})} }} \cdot \sum\limits_{x = 1}^V {\exp (u_x^T \cdot {v_c})} \cdot \frac{{\partial (u_x^T \cdot {v_c})}}{{\partial {v_c}}} \\ = \frac{1}{{\sum\limits_{w = 1}^V {\exp (u_w^T \cdot {v_c})} }} \cdot \sum\limits_{x = 1}^V {\exp (u_x^T \cdot {v_c})} \cdot {u_x} = \sum\limits_{x = 1}^V {\frac{{\exp (u_x^T \cdot {v_c})}}{{\sum\limits_{w = 1}^V {\exp (u_w^T \cdot {v_c})} }}} \cdot {u_x}
然后这个式子中间的部分正好可以看成是softmax:
exp(uxTvc)w=1Vexp(uwTvc)=P(xc)\frac{{\exp (u_x^T \cdot {v_c})}}{{\sum\limits_{w = 1}^V {\exp (u_w^T \cdot {v_c})} }} = P(x|c)所以这么一来,整个第二项就可以看成是:
x=1VP(xc)ux\sum\limits_{x = 1}^V {P(x|c) \cdot {u_x}}
这整个式子可以看成是x词在中心词出现的情况下出现的概率,然后乘以x词上下文的向量,这样就是上下文向量的期望了,所以整个第二项就是所有的上下问向量的平均期望。那么整个损失函数可以表示成:
J(θ)=uox=1VP(xc)ux=observedexpectedJ(\theta ) = {u_o} - \sum\limits_{x = 1}^V {P(x|c) \cdot {u_x}} = observed - expected
就是观测值真实值减去期望值,所以我们就要最小化损失函数,让期望值和真实值尽可能接近,通过整个推导过程就很容易理解skip-grams的算法流程和数学推导,希望可以帮助大家对词向量算法的理解有所帮助,文中如有纰漏,也请各位朋友不吝指教,如有转载,也请标明出处,谢谢大家。