本文章基于论文《Efficient estimation of word representations in vector space》(2013,Tomas Mikolov等)、《word2vec Parameter Learning Explained 》(2016,Xin Rong)和《word2vec Explained: Deriving Mikolov et al.’s Negative-Sampling Word-Embedding Method 》(2014,Yoav Goldberg and Omer Levy)等进行讲解,内容包括CBOW和Skip-gram算法,以及分层softmax和负采样优化算法。
一、为什么要提出CBOW和Skip-gram算法
1.1 稀疏表示问题
在自然语言处理中,需要将文本中的单词转化为计算机能够处理的数值向量形式,即词向量。传统的词表示方法,如独热编码,存在维度灾难、无法捕捉语义信息等问题。
1.2 提升计算效率
早期的神经网络语言模型,如前馈神经网络语言模型(NNLM),存在计算瓶颈。
NNLM用于预测一句话下一个词语出现的概率:例如,输入10个词语,预测第11个词。模型架构如下:
模型包含四层:输入层—>投影层—>隐藏层—>输出层。
(1)输入层:假设输入N个词,每个词的独热编码是V维(V为词汇量)。输入层无显示计算。
(2)投影层:将N个词的的独热编码(V维)映射为D维度的稠密向量(NxD维)。计算复杂度为NxD。
(3)隐藏层:将投影层输出(NxD维)通过全链接层映射到H维隐藏层。计算复杂度为NxDxH。
(4)输出层:隐藏层输出(H维)通过全连接层映射到V维概率分布(Softmax)。计算复杂度为HxV。
因此,NNLM总的计算复杂度为N×D+(N×D)×H+H×V。NNLM的主要瓶颈在于投影层到隐藏层的计算((N×D)×H)及隐藏层到输出层的计算(H×V)。
1.3 有效利用上下文信息
自然语言中,单词的含义往往与其周围的上下文紧密相关。CBOW 算法根据上下文单词来预测目标单词,Skip - gram 算法则根据目标单词来预测上下文单词,它们都能够有效地利用文本中的上下文信息来学习单词的表示,从而更好地理解单词在不同语境中的语义。
二、CBOW算法
CBOW的网络架构与NNLM比较类似,但CBOW去掉了隐藏层,并且所有上下文词共享同一投影矩阵(词嵌入矩阵),而非每个词独立映射。为了便于理解,我们从上下文单词数为1个的简单场景开始学习。
2.1 One-word context
上图为上下文单词数为1的CBOW网络结构图。假设词库大小为V(共有V个单词),因此输入层one-hot向量的维度为V;隐藏层神经元个数为N;输入层到隐藏层,隐藏层到输出层均为全链接,且无激活函数。输入层到隐藏层之间的权重矩阵为。
的每一行都是一个N维的向量,用
表示。
1、从输入层到隐藏层:
给定一个上下文(一个单词),假设这个单词的one-hot向量中第k个元素,其他
的元素
。因此,我们有:
(1)
其中:h为隐藏层向量 x为输入层向量
表示输入单词
的词嵌入向量。
2、从隐藏层到输出层:
从隐藏层到输出层的权重矩阵用表示,
。从隐藏层到输出层的计算公式为
。假设
为
的第j列,
(2)
表示得到词库中第j个单词(
)的得分(输出层第j个神经元的输入)。然后经过softmax后将得分进行归一化:
。 (3)
表示输出层的第j个神经元的输出。这也是给定上下文单词
的情况下,得到单词
的概率,即
将公式(1)和公式(2)带入公式(3)后,得到公式:
(4)
可以看出和
均为单词
的词嵌入向量,
来自于
,
来自于
,我们将
叫做输入向量,
叫做输出向量。
3、隐藏层到输出层的权重更新
根据公式(4),对于给定的上下文,实际输出的词为
,因此我们要使条件概率
值最大,即
(6)
因为,所以
(7)
就是我们的损失函数,需要进行最小化。
根据E的公式,先对求偏导:
当时,
;当
时,
因此,可以统一写成 (8)
当时,
;否则
为0。
下面,对进行求偏导:
(9)
采用梯度下降法,权重更新公式为: (10)
或者 其中j=1,2,3,...V (11)
上述公式(10)和(11)中,为学习率,
为隐藏层的第i个神经元的输出。
是
的输出向量。
4、输入层到隐藏层的权重更新
更新完后,我们接着更新
。我们将损失函数对隐藏层第i个神经元的输出
进行求导:
(12)
由于在隐藏层未使用激活函数,因此隐藏层第i个神经元的输入和输出均为。那么:
(13)
因此, (14)
(15)
上述公式(15)是一个VxN的矩阵。由于向量x为one-hot向量,仅有一个元素是非零的。因此,中仅有一行是非零的,非零值就是
(一个N维的向量)。因此,我们可以得到W的更新公式为:
(16)
上述公式(16)中,是W的一行,也是W的唯一一个导数不为0的行,是上下文单词的输入向量。这次迭代后,W的其他行保持不变,因为他们的导数为0。
2.2 Multi-word context
上图为上下文为多个的单词的CBOW网络架构。假设上下文单词为C个,每次单词仍然用V维的one-hot向量表示。在隐藏层中神经元个数仍为N个,输出层神经元个数为V个。此时,变为了通过某个目标单词的C个上下文单词去预测该目标单词。
在计算隐藏层h的输入时,我们采用了上下文单词向量的平均值:
(17)
(18)
上述公式(18)中,C是上下文单词的个数,是上下文单词,
是单词
的输入向量。参照公式(3)可得,
损失函数E可表示为: (19)
(20)
(21)
上述公式和公式(7)一样,只不过就是h的计算不一样了。
1、隐藏层到输出层之间权重更新
隐藏层到输出层之间权重更新公式与公式(11)一样:
(22)
2、输入层到隐藏层之间的权重更新
输入层到隐藏层之间的权重更新公式与公式(12)类似,只不过公式(16)是更新一个上下文单词的输入向量,现在是需要更新所有c个上下文单词的输入向量,更新公式为:
(23)
就是上下文中第c个单词,下标中的
仅仅是表示输入。
三、Skip-Gram算法
上图为Skip-Gram算法的网络结构,与CBOW算法正好相反:目标单词在输入层,上下文单词在输出层。我们仍然使用来表示这唯一输入单词的输入向量,用
表示隐藏层输出,与上文中公式(1)的定义一样:
(24)
在输出层,就不是像CBOW一样计算一个多项式分布,而是计算C个多项式分布,每一个多项式的计算公式为: (25)
上述公式(25)中,中的下标c表示是输出层第c个单词(假设共输出C个单词),j表示第c个单词one-hot向量中的第j个元素。
表示真实输出的就是第c个单词。为此,这个多项式分布的目标就是使得第c个单词的one-hot向量中对应的表示是单词c的那个元素最大。
根据Skip-Gram算法的网络结构图可知,每个多项式输出都共享权重矩阵,输出层的输入
其实都是一样的。因此,输出层的输入
可以统一写为:
(26)
Skip-Gram的损失函数可以表示为: (27)
假设单词相互独立,那么
(28)
对公式(28)展开可得: (29)
公式中的就是真实的第c个输出上下文在词库中的单词索引。
先将E对进行求导,参照公式(8)的推导过程,可得:
(30)
为了简化符号表示,我们定义一个V维的向量作为上下文预测误差的总和:
(31)
接下来,我们对隐藏层到输出层的权重矩阵进行求导:
(32)
权重更新公式为: (33)
或者
(34)
输入层到隐藏层的权重矩阵更新公式: (35)
这个更新公式与公式(16)一致,只不过将公式(12)中的变为了
。
(36)
四、层次softmax
4.1 为什么要提出优化方法
根据公式(3)可知,softmax函数中涉及到对输入值进行指数计算以及归一化计算。假设词汇表中的单词量为V,当V数量很大时,会极大增加开销、复杂度、降低模型的训练效率,此时的算法复杂度为O(V)。为此,提出了层次softmax和负采样优化算法。本节先讲解层次softmax算法。
4.2 哈夫曼树
4.2.1 构建哈夫曼树
层次softmax通过构建一个哈夫曼树,将类别映射到树的叶子节点,将概率计算转化为树路径上的二分类问题,从而极大降低计算复杂度(O(logV))。我们先从构造哈夫曼树开始讲解。
假设:我们有四个类别A,B,C,D,权重分别为:5,7,2,13。
1、将所有类别根据权重从小到大排序(2,5,7,13)<==>(C,A,B,D)
2、取出权重最小的两个类别,较小的作为左子节点,较大的作为右子节点
3、两个类别权重的和作为父节点,并增加到列表中(7,7,13)<==>(未知,B,D)
4、重复2-3步,直到列表为空。
5、此时,哈夫曼树构建完成
上图构建的哈夫曼树中,每个非叶子节点都包含参数,它是一个sigmoid二分类问题,因此需要进行参数训练。在实际基于词汇构造哈夫曼树,每次单词的权重大小就是该词在语料库中出现的频率。
4.2.2 基于哈夫曼树获取每个类别的概率
1、输入向量与每个非叶子节点参数计算得出概率值:
每个非叶子节点对应一个逻辑回归分类器,参数为向量(向量
的维度与投影层输出向量
维度相同,因为采用分层softmax后,投影层就直接连接了多个sigmoid分类器),当从根节点到目标叶子节点的路径经过该节点时,需计算向该节点左/右子树分支的概率:
其中,为网络投影层输出。
2、每个类别的输出概率等于路径上的概率乘积:
假设已计算出了每个分支的概率,求各个分类的预测概率:
- A的预测概率为:0.7*0.6*0.8=0.336
- B的预测概率为:0.7*0.4=0.28
- C的预测概率为:0.7*0.6*0.2=0.084
- D的预测概率为:0.3
- 所有的概率之和为1
4.2.3 类别概率数学公式表示及权重更新
假定一棵哈夫曼树如上图所示。从根节点到叶子节点的路径距离为
。
表示是从根节点到叶子节点
路径上的第j个节点。目标单词为w的概率为:
(37)
表示为从根节点到叶子节点w路径上的第j个节点的逻辑回归分类器的参数
;h为投影层输出向量,可用公式(18)或(24)求出。
是一个特殊的函数,定义为:
(38)
还是以上图为例,让我们举个例子,对公式(37)进行解释说明。从根节点到叶子节点路径上的第n个节点,该节点左子树的概率为:
(39)
该节点右子树的概率为: (40)
对于上图中的,我们可以计算其作为目标单词的概率为:
(41)
将公式(39)和(40)带入可得:
(42)
并且可以很容易验证,所有叶子节点的概率之和为1: (43)
接下来让我们求得权重更新公式。为了简单起见,还是先用上下文单词数为1的情况进行举例说明。为了简化符号表示,做如下定义:
(44)
(45)
对于一个训练实例,损失函数可定义为: (46)
先求E对的偏导数:
(47)
(48)
(49)
当时,
,否则
。
接下来E对进行求导:
(50)
因此,分层softmax中每个非叶子节点的逻辑回归权重系统更新公式为:
(51) 接着更新输入层到隐藏层(投影层)之间的权重。先将E对h求导:
(52)
(53)
(54)
将公式(54)代入公式(23)(针对CBOW算法)或公式(35)(针对Skip-Gram算法)中,就可以得到对应的权重更新公式。
通过公式(51)可知,采用分层softmax后,计算输出层的时间复杂度从O(V)变为了O(L(w)),即O(log(V))。此外,参数数量也没有增加,之前隐藏层到输出层的参数数量为NxV,现在变为了Nx(V-1)。原因是有V-1个非叶子节点,每个非叶子节点的参数个数为N(N为h的维度)。
五、负采样
负采样的思想是:每次在计算softmax时,分母都需要对V个词汇进行指数计算,计算开销极大。为此,负采样将该问题转化为一个二分类问题:给定两个单词,去预测这两个单词是否是一对上下文-目标词对(context-target)。此外,再随机选择一些“负样本”来代替计算所有可能的上下文词作为负样本。这样就大幅降低了计算复杂度。
- 网络架构:采用负采样后的CBOW/Skip-Gram的网络结构变为了:输入层、投影层(隐藏层)和输出层(多个二分类sigmoid函数组成,每个二分类器学习一个正样本和多个负样本)。
- 正样本:每次训练时,对于给定的上下文词
和目标词
,目标将条件
最大化,这部分就是正样本,并且用sigmoid函数去代替softmax函数。因此,根据公式(2)及sigmoid函数,在给定输入单词
的情况下,目标单词为
的概率为
- 负样本:从词汇表中随机选择与上下文不相关的词作为负样本
。选择的概率可遵循
,其中
是词
在语料库出现的频率。用负样本训练时,对于给定的上下文单词
和负样本
,我们需要使得
最小化,即
最大化。
- 损失函数:假设每个正样本对应选择K个负样本。即,有一个正样本,要随机选K个负样本。(对于一个上下文单词,有一个词为正样本,K个词为负样本)。那么损失函数就变为了:
,进行变换可得:
(55)
我们首先将E对进行求导:
(56)
(57)
当为正样本时,
,否则
。
接下来将E对进行求导:
(58)
输出向量的更新公式为(更新隐藏层到输出层之间的权重系数):
(59)
将E对h进行求导: (60)
(61)
求出E对h的偏导后,代入公式(23)和公式(35)后,就可得输入层到隐藏层的权重更新公式。