word2vec有两个重要的模型:CBOW模型和Skip-gram模型。如下图所示:

这两个模型都包括输入层,投影层,输出层,如上右图CBOW模型时在已知当前词wt的上下文wt−2,wt−1,wt+1,wt+2的前提下预测当前词wt。而Skip-gram模型是在已知wt的前提下,预测其上下文wt−2,wt−1,wt+1,wt+2。
在神经网络语言模型中,目标函数通常取对数似然函数:
L=w∈C∑logp(w∣context(w))
CBOW模型的目标函数也是上式。其中的关键是条件概率函数logp(w∣context(w))的构造。
而Skip-gram模型的优化目标则是:
L=w∈C∑logp(context(w)∣w)
CBOW模型
基本结构
CBOW模型的网络结构包括三层:输入层,投影层,输出层。

(1)输入层:包含comtext(w)中的2c个词向量v(context(w)1),v(context(w)2),…,v(context(w)2c)∈Rm ,每个词向量的长度是m。
(2)投影层:将输入层的2c个词向量累加求和,即xw=∑i=12cv(context(w)i) 。
(3)输出层:输出层对应一颗二叉树,这是一颗Huffman树,其叶子结点是语料库中的所有词,叶子个数N=|D|,分别对应词典D中的词。以各词在语料中出现的次数作为权值构建出来的Huffman树。(构建过程可参考:Huffman编码 )
CBOW模型与神经网络语言模型对比,主要有三个不同 :
(1)(从输入层到投影层的操作)前者是通过拼接,后者通过累加求和.
(2)(隐藏层)前者有隐藏层,后者无隐藏层.
(3)(输出层)前者是线性结构,后者是树形结构.
神经网络语言模型中大部分计算集中在隐藏层和输出层之间的矩阵向量运算,以及输出层上的softmax归一化运算,CBOW模型对这些计算复杂度高的地方有针对性地进行了改变,首先,去掉了隐藏层,其次,输出层改用了Huffman树,从而为利用Hierarchical softmax技术奠定了基础。
梯度计算
假设2014 年世界杯期间,从新浪微博中抓取了若干条与足球相关的微博,经统计,“我”、“喜欢”、“观看”、“巴西”、“足球”、“世界杯”这六个词出现的次数分别为15, 8, 6, 5,3, 1。用这些语料构建Huffman树,并将其作为CBOW模型的输出层。如下图所示:

针对上图,规定:
pw 表示从根结点出发到达w对应叶子结点的路径,
lw 表示这个路径中包含结点的个数,
plw 表示路径 pw中的第l个结点,
djw 表示路径pw中第j个结点对应的编码(0或1),
θjw 表示路径pw中第j个结点对应向量(可以理解图中每一条边的都有一个权值向量)。
我们的目标是利用输入向量Xw 和Huffman树来定义函数p(w∣context(w))。
以图中的词w="足球"为例,从Huffman树的根结点出发到“足球”,中间经历了4个分支,每一次分支,都可以看成进行了一次二分类。那么从二分类的角度来看,对于每个非叶子结点,就需要为其左右孩子指定类别。我们规定:编码为1的结点定义为负类,编码为0的结点定义为正类。也就是说,将一个结点进行二分类,分到左边是负类,分到右边是正类。所以有:
Label(piw)=1−diw,i=1,2,…,lw
我们用逻辑斯蒂回归进行二分类,一个结点被分为正类的概率是:
σ(xwTθ)=1+e−xwTθ1
被分成负类的概率为:
1−σ(xwTθ)
这里的θ指图中每一条边的都有一个权值向量。是个待定参数。
所以,从Huffman树的根结点出发到“足球”,中间经历了4个二分类,每个分类的结果如下:
第一次:p(d2w∣xw,θ1w)=1−σ(xwTθ1w)
第二次:p(d3w∣xw,θ2w)=σ(xwTθ2w)
第三次:p(d4w∣xw,θ3w)=σ(xwTθ3w)
第四次:p(d5w∣xw,θ4w)=1−σ(xwTθ4w)
这四个概率的乘积就是p(足球∣context(足球)),即:
p(足球∣context(足球))=j=2∏5p(djw∣xw,θj−1w)
总结:对于词典D中的任意词w, Huffman树中必存在一条从根结点到词w对应结点的路径pw (且这条路径是唯一的)。路径pw上存在lw−1个分支,将每个分支看做一次二分类,每一次分类就产生一个概率, 将这些概率乘起来,就是所需的p(w∣Context(w))。
所以条件概率的定义如下:
p(w∣context(w))=j=2∏lwp(djw∣xw,θj−1w)
其中:
p(djw∣xw,θj−1w)={σ(xwTθj−1w)djw=01−σ(xwTθj−1w)djw=1
写成总体表达式如下:
p(djw∣xw,θj−1w)=[σ(xwTθj−1w)]1−djw⋅[1−σ(xwTθj−1w)]djw
所以我们的优化目标是:
L=w∈C∑logj=2∏lw{[σ(xwTθj−1w)]1−djw⋅[1−σ(xwTθj−1w)]djw}=w∈C∑j=2∑lw{(1−djw)log[σ(xwTθj−1w)]+djwlog[1−σ(xwTθj−1w)]}=w∈C∑j=2∑lwL(w,j)
其中:$ \mathcal L(w,j) = ({1-d_j^w})\log[\sigma(\mathbf x_wT\theta_{j-1}w)]+d_j^w\log[1-\sigma(\mathbf x_wT\theta_{j-1}w)]$
这就是CBOW的目标函数。采用随机梯度上升法将这个函数最大化。
注:随机梯度上升法:随机取一个样本(context(w),w),对目标函数中的所有的参数行一次更新。
(1)更新θj−1w
因为:
∂θj−1w∂L(w,j)=∂θj−1w∂{(1−djw)log[σ(xwTθj−1w)]+djwlog[1−σ(xwTθj−1w)]}=(1−djw)[1−σ(xwTθj−1w)]xw−djwσ(xwTθj−1w)xw={(1−djw)[1−σ(xwTθj−1w)]−djwσ(xwTθj−1w)}xw=[1−djw−σ(xwTθj−1w)]xw
所以 θj−1w更新公式为:
θj−1w:=θj−1w+η[1−djw−σ(xwTθj−1w)]xw
其中η为学习率。
(2)更新xw
因为L(w,j) 关于变量xw和θj−1w是对称的。所以:
∂xw∂L(w,j)=[1−djw−σ(xwTθj−1w)]θj−1w
这里存在一个问题:我们的最终目的是要求词典D中每个词的词向量,而这里的 xw 表示的是context(w)中各词词向量的累加。那么,如何利用∂xw∂L(w,j)来对v(w),w∈D 进行更新呢? word2vec中的做法很简单, 直接取
v(w):=v(w)+ηj=2∑lw∂xw∂L(w,j),w∈context(w)
注:既然xw 本身就是context(w)中各个词向量的累加,求完梯度后也应该将其贡献到每个分量上。
下面是CBOW模型中采用的随机梯度上升法伪代码:

Skip-gram模型
基本结构
Skip-gram母模型的结构也是三层,下面以样本(w,context(w))为例说明。如下图所示:

(1)输入层:只包含当前样本中心词w词向量v(w)∈Rm ,每个词向量的长度是m。
(2)投影层:恒等投影,保留是为了与CBOW对比。
(3)输出层:与CBOW类似。
对于Skip-gram模型,已知的是当前词w,需要对其上下文context(w)中的词进行预测,所以:
p(context(w)∣w)=u∈context(w)∏p(u∣w)
类似于CBOW,所以:
p(u∣w)=j=2∏lup(dju∣v(w),θj−1u)
其中:
p(dju∣v(w),θj−1u)=[σ(v(w)Tθj−1u)]1−dju⋅[1−σ(v(w)Tθj−1u)]dju
所以我们的优化目标是:
L=w∈C∑logu∈context(w)∏j=2∏lu{[σ(v(w)Tθj−1u)]1−dju⋅[1−σ(v(w)Tθj−1u)]dju}=w∈C∑u∈context(w)∑j=2∑lu{(1−dju)log[σ(v(w)Tθj−1u)]+djulog[1−σ(v(w)Tθj−1u)]}=w∈C∑u∈context(w)∑j=2∑lu L(w,u,j)
采用随机梯度上升法将这个函数最大化。
梯度更新
(1)更新θj−1u
因为:
∂θj−1u∂L(w,u,j)=∂θj−1u∂{[σ(v(w)Tθj−1u)]1−dju⋅[1−σ(v(w)Tθj−1u)]dju}=(1−dju)[1−σ(v(w)Tθj−1u)]v(w)−djuσ(v(w)Tθj−1u)v(w)={(1−dju)[1−σ(v(w)Tθj−1u)]−djuσ(v(w)Tθj−1u)}v(w)=[1−dju−σ(v(w)Tθj−1u)]v(w)
所以 θj−1w更新公式为:
θj−1u:=θj−1u+η[1−dju−σ(v(w)Tθj−1u)]v(w)
其中η为学习率。
(2)更新v(w)
因为L(w,u,j) 关于变量v(w)和θj−1w是对称的。所以:
∂v(w)∂L(w,u,j)=[1−dju−σ(v(w)Tθj−1u)]θj−1u
所以,v(w)更新公式为:
v(w):=v(w)+ηu∈context(w)∑j=2∑lw∂v(w)∂L(w,u,j),w∈context(w)
具体伪代码如下:

优缺点
使用霍夫曼树来代替传统的神经网络,避免了从隐藏层到输出的softmax层这里的计算。也避免计算所有词的softmax概率。但是如果我们的训练样本里的中心词w是一个很生僻的词,那么就得在霍夫曼树中辛苦的向下走很久了。解决这个问题则是采用基于Negative Sampling的模型。