word2vector:NPLM、CBOW、Skip-gram

近年来,基于神经网络来得到词表示的模型备受青睐。这类模型所得到的词的向量表示是分布式表示distributed representation,通常被称为word embedding(词嵌入;词向量)。这种基于预测(predict)的模型的超参数往往要多于基于计数(count)的模型,因此灵活性要强一些。下面就简要介绍利用神经网络来得到词表示的开山之作——神经概率语言模型(NPLM, Neural Probabilistic Language Model),通过训练语言模型,同时得到词表示。

语言模型是指一个词串 是自然语言的概率 。 词的下标 表示其是词串中的第 个词。根据乘法公式,有

因此要想计算出这个概率,那就要计算出 :

count()是指词串在语料中出现的次数。暂且抛开数据稀疏(如果分子为零那么概率为零,这个零合理吗?如果分母为零,又怎么办?)不谈,如果词串的长度很长的话,这个计算会非常费时。n-gram模型是一种近似策略,作了一个马尔可夫假设:认为目标词 的条件概率只与其之前的 个词有关:

神经概率语言模型NPLM延续了n-gram的假设:认为目标词 的条件概率与其之前的 个词有关。但其在计算 时,则使用的是机器学习的套路,而不使用上面count()的方式。那么它是如何在训练语言模型的同时又得到了词表示的呢?

word2vector:NPLM、CBOW、Skip-gram

图片来源:参考资料[1],加了几个符号

设训练语料为 ,提取出的词表为 。词 的下标 表示其是词表中的第 个词,区别于不带下划线的下标。大致说来,NPLM将语料中的一个词串 的目标词 之前的 个词的词向量(即word embedding,设维度为 )按顺序首尾拼接得到一个“长”的列向量 ,作为输入层(也就是说共 个神经元)。然后经过权重矩阵 来到隐层(神经元数为 ),并用tanh函数激活。之后再经过权重矩阵 来到输出层(神经元数当然为 ),并使用softmax()将其归一化为概率。另外存在一个从输入层直连输出层的权重矩阵 。所以网络的输出如下(隐层和输出层加了偏置):

表示目标词是词表中第 个词 的概率。

表示前 个词对词表中第 个词 的能量聚集。

词表中的每个词的词向量都存在一个矩阵 中,look-up操作就是从矩阵中取出需要的词向量。由此可以看出,NPLM模型和传统神经网络的区别在于,传统神经网络需要学习的参数是权重和偏置;而NPLM模型除了需要学习权重和偏置外,还需要对输入(也就是词向量)进行学习。

那么,模型的参数就有: 。

对于目标词 ,模型对它的损失为(使用对数损失函数时,经验风险最小化等价于极大似然估计;在本处,对数损失是交叉熵损失的一种特殊情况)

那么模型的经验风险为(省略了常系数)

所以接下来就可以使用梯度下降等方法来迭代求取参数了。这样便同时训练了语言模型和词向量。

word2vec:CBOW / Skip-gram

上面介绍的NPLM以训练语言模型为目标,同时得到了词表示。2013年的开源工具包word2vec则包含了CBOW和Skip-gram这两个直接以得到词向量为目标的模型。

这里先介绍两种模型的没有加速策略的原始形式(也就是输出层是softmax的那种。对于Skip-gram模型,作者在paper中称之为“impractical”),两种加速策略将在下篇文中介绍。

与NPLM不同,在CBOW / Skip-gram模型中,目标词 是一个词串中间的词而不是最后一个词,其拥有的上下文(context)为前后各 个词: 。NPLM基于n-gram,相当于目标词只有上文。后文中,“目标词”和“中心词”是同一概念,“周围词”和“上下文”是同一概念。

在CBOW / Skip-gram模型中,任一个词 将得到两个word embedding(设维度为 ):作为中心词时的词向量,也称为输出词向量 ;以及作为周围词时的词向量,也称为输入词向量 。词向量的下标和词的下标相对应,比如说目标词 的词向量就对应为 和 。

与NPLM类似,词表中每个词的词向量都存在一个矩阵中。由于存在两套词向量,因此就有两个矩阵:输入词矩阵 ,其每一列都是一个词作为周围词时的词向量;输出词矩阵 ,其每一行都是一个词作为中心词时的词向量。比如说若想取出词作为周围词时的词向量,只要知道词在词表中的编号即可,取出的操作相当于用输入词矩阵乘以词的one-hot representation。

(一)CBOW(Continuous Bag-of-Words)

不带加速的CBOW模型是一个两层结构,通过上下文来预测中心词——

输入层: 个节点,上下文共 个词的词向量的平均值;

输入层到输出层的连接边:输出词矩阵 ;

输出层: 个节点。第 个节点代表中心词是词 的概率。

如果要“看做”三层结构的话,可以认为——

输入层:个节点,上下文共 个词的one-hot representation

输入层到投影层到连接边:输入词矩阵 ;

投影层:: 个节点,上下文共 个词的词向量的平均值;

投影层到输出层的连接边:输出词矩阵 ;

输出层: 个节点。第 个节点代表中心词是词 的概率。

这样表述相对清楚,将one-hot到word embedding那一步描述了出来。但个人认为投影层不宜称为“隐层”,因为我觉得隐层可能往往有加非线性的意思,而这里没有。

word2vector:NPLM、CBOW、Skip-gram

图片来源:参考资料[5],把记号都改成和本文一致

首先,将中心词 的上下文 : 由one-hot representation( )转为输入词向量( ):

进而将上下文的输入词向量 求平均值,作为模型输入:

这一步叫投影(projection)。可以看出,CBOW像词袋模型(BOW)一样抛弃了词序信息。丢掉词序看起来不太好,不过开个玩笑的话:“研表究明,汉字的序顺并不定一能影阅响读,事证实明了当你看这完句话之后才发字现都乱是的”。

与NPLM不同,CBOW模型没有隐藏层,投影之后就用softmax()输出目标词是某个词的概率,进而减少了计算时间:

那么模型的参数就是两个词向量矩阵: 。

对于中心词 ,模型对它的损失为

所以模型的经验风险为

下面开始是非常无聊的求导练习。。。

如果用SGD来更新参数的话,只需求出模型对一个样本的损失的梯度。也就是说上式的求和号可以没有,直接对 求梯度,来更新参数。

I. 首先是对输出词矩阵 :

因为 ,所以 (这里的 有点像BP算法中的 ),那么先求 :

(1) 对 ,有 ,那么

(2) 对 ,有 ,那么

可见两种情形的结果是统一的。

因此有

那么对于词表中的任一个词 ,其输出词向量的更新迭代式为:

从整体上看,有

II. 接下来是对输入词矩阵 :

因为 ,所以 ,那么求 :

因此有

那么对于中心词 的上下文的任一个词 ,其输入词向量的更新迭代式为:

(三)word analogy

word analogy是一种有趣的现象,可以作为评估词向量的质量的一项任务。

word2vector:NPLM、CBOW、Skip-gram

图片来源:参考资料[6]

word analogy是指训练出的word embedding可以通过加减法操作,来对应某种关系。比如说左图中,有 。那么评测时,则是已知这个式子,给出king、queen和man三个词,看与 最接近的是否是 。右图则表示,word analogy现象不只存在于语义相似,也存在于语法相似。

CBOW / Skip-gram模型的加速策略(一):Hierarchical Softmax

拿原始模型来说,计算 的一个分量 时,由于使用的是softmax()函数,时间复杂度为 ,因此计算代价很大,对大规模的训练语料来说,非常impractical。

Hierarchical Softmax是一种对输出层进行优化的策略,输出层从原始模型的利用softmax计算概率值改为了利用Huffman树计算概率值。

以词表中的全部词作为叶子节点,词频作为节点的权,构建Huffman树,作为输出。Huffman树是二叉树,在叶子节点及叶子节点的权给定的情况下,该树的带权路径长度最短(一个节点的带权路径长度指根节点到该节点的路径长度乘以该节点的权,树的带权路径长度指全部叶子节点的带权路径长度之和)。直观上可以看出,叶子节点的权越大,则该叶子节点就应该离根节点越近。因此对于模型来说就是,词频越高的词,距离根节点就越近。

从根节点出发,到达指定叶子节点的路径是唯一的。Hierarchical Softmax正是利用这条路径来计算指定词的概率,而非用softmax来计算。

word2vector:NPLM、CBOW、Skip-gram

图片来源:参考资料[2],记号改成和本文一致

上图是一个已根据词频构建好的Huffman树,各叶子节点代表词表中的各个词,非叶子节点共 个。以词 为例,从根节点到该叶子节点的路径长度 ,各个节点依次被记为 、 、 和 。对于每个非叶子节点 ,虽然不是词表中的词,但也引入所谓的“输出词向量” ,是需要学习的参数,为什么要引入它?下面讲述。

从根节点出发,走到指定叶子节点 的过程,就是一个进行 次二分类的过程:路径上的每个非叶子节点都拥有两个孩子节点,从当前节点 向下走时共有两种选择,走到左孩子节点 就定义为分类到了正类,走到右孩子节点就定义为分类到了负类。

以CBOW模型为例,即输入层是 。用二项Logistic回归模型对每一次分类过程建模:从当前节点 走到下一节点,那么走到左孩子节点的概率为

走到右孩子节点的概率为

将上面两个式子统一起来,那就是

word2vector:NPLM、CBOW、Skip-gram

(双线括号的意思是,当括号内为真则输出1,为假则输出0。)

现在计算输出词为 的概率:这对应于一条从根节点 走到叶子节点 的路径,概率计算式为下式:

word2vector:NPLM、CBOW、Skip-gram

平均时间复杂度为 ,相比于使用softmax()函数有很大提高。

对于Skip-gram模型,表达式类似:

word2vector:NPLM、CBOW、Skip-gram

可以证明,这样计算的结果满足概率和为1:

模型对语料中的全部词串计算概率值做连乘得到似然函数,再取对数得到对数似然 ,进而用极大似然估计来求取参数。使用SGD更新参数(求取梯度时,由于是SGD,所以 的求和号可以去掉)。易知在Hierarchical Softmax的情况下每个词只会得到一个词表示(输入词向量)。梯度求取比较简单,参考资料[3]写的非常详细并给出了参数更新过程的伪代码(Skip-gram部分写反了,应改为“各个周围词预测中心词再做连乘”,而非“中心词预测各个周围词再做连乘”)。

CBOW / Skip-gram模型的加速策略(二):Negative Sampling

第二种加速策略是Negative Sampling(NEG,负采样),这是Noise-Contrastive Estimation(NCE,噪声对比估计)的简化版本:把语料中的一个词串的中心词替换为别的词,构造语料 中不存在的词串作为负样本。因此在这种策略下,优化目标变为了:最大化正样本的概率,同时最小化负样本的概率。对于一个词串 ( 表示 的上下文),用二项Logistic回归模型对其是正样本的概率建模:

所以全部正样本的似然函数为

同理,全部负样本的似然函数为

需要最大化前者同时最小化后者,也就是最大化下式:

取对数得到对数似然:

由于使用SGD,所以只需要知道对一个正样本 的目标函数。式中 指 的负样本的中心词集合: