目录
3 基于Hierarchical Softmax的CBOW模型
4 基于Hierarchical Softmax的Skip-gram模型
上一篇Skip-gram推导的文章中最后提到求概率时需要计算softmax,如果词典的大小V十分庞大的时候,整个分母需要计算中心词和词典中所有词的乘积,这显然是个非常庞大的计算量,因此Wordvec中提出了两种解决方案,一种是基于Hierarchical softmax的解决方案,一种是基于Negative sampling的解决方案。本文是讲解的是Hierarchical softmax的解决方案,在后一篇文章中讲解基于Negative sampling的解决方案。
1 基于Hierarchical Softmax的模型
我们先回顾下上篇文章中所讲到的部分。
这里面分为三层,输入层,隐藏层,输出层,我们从前一篇文章中知道,Hidden layer就是word embedding,然后经过一个W‘ 矩阵,得到一个词典大小维度的向量,最后再经过一个softmax,得出最后所有单词的概率分布。这里面存在的就是在于如果词典大小V如果很大的情况下,计算从Hidden layer到Output layer的计算量很大,因为需要计算词典中所有的词。
因为Word2vec对这个模型进行了改进和优化。首先对于输入层到隐藏层的部分,没有再采用神经网络所采用的线性变化+激活函数的方式了,而是仅仅采用对输入的词向量进行求和并取平均值的方法,这无疑省略了很多计算,最后使得输入的向量无论是一个中心词向量还是一堆context向量,最后所得到的结果都是一个向量。举个例子,比如输入的是三个5维的词向量,(1,2,3,4,5),(2,0,3,1,1),(3,4,0,1,0),那么word2vec对它们就是求和取平均值,
最后所得到的向量为(2,2,2,2,2),所以结果是将多个向量变成了一个向量。
第二个改进是从隐藏层到输出层的softmax的改进,为了避免需要计算所有词向量,word2vec采用了hierarchical softmax的方式,简单来说就是采用哈夫曼树(也叫作霍夫曼树)建树的方式来计算softmax,下面会详细介绍如何采用哈夫曼树来进行softmax的计算和建模。
因为我们输出层所要做的是要求出词典的所有词的概率,最后从中选出所需要的词语作为输出。因为我们知道词典的大小为V,所以如下图所示:
我们将叶节点个数设为V,这就对应着我们最后的V个概率值。先前的模型计算概率是在分母部分计算所有词向量的乘积,在哈夫曼树中,我们要计算概率只需要从根节点沿着树往下到叶节点为止即可,这样对于每个叶节点的概率,需要计算的量直接从V 减少到了log2 V,因为这是基于二叉树的性质。
比如对于来说,只需要计算从根节点到节点之间节点的乘积即可,省去了很多计算量。在这里根节点的值就是输入的向量求和取平均值的那个向量,所有叶子节点对应的就是输出层的V个神经元,叶子节点的个数就是词典的大小V。对应于上面的神经网络图来说,Input layer就是求和取平均值的向量,隐藏层的神经元就是哈夫曼树中所有的内部节点,输出层的神经元就是所有叶子节点。因为在哈夫曼树中,隐藏层到输出层的softmax映射不是一下子分母求和完成的,而是沿着哈夫曼树一步步向下延伸所求得的,因此这种softmax叫做“Hierarchical softmax” ,也叫层级softmax。
那么如何沿着哈夫曼树来计算概率呢? 在Word2vec中,所采用的是二元逻辑回归的方式,它们规定沿着左子树走,就定义为负类(哈夫曼树的编码为1),沿着柚子树走,就定义为正类(哈夫曼树的编码为0)。计算正类和负类所采用的计算方式是sigmoid函数,即
那么很容易理解 P(-) = 1 - P(+),因为哈夫曼树是二叉树,要么就往左边走,不然就往右边走。
上面公式中的 就是 哈夫曼树中的内部节点的词向量,这个 是内部所有节点的词向量,也就是说计算P(+)或者P(-)的概率时,对于任意一个内部节点,都是使用 作为词向量, 就是我们需要在训练过程中所要更新的逻辑回归的参数, 是对于任意一个内部节点都不一样的,这点和 是不一样的。
当计算到某一个内部节点时,根据P(+)和P(-)的值的大小来决定是左子树走还是往右子树走,谁大就往哪边走,而控制P(−),P(+)谁的概率值大的因素一个是当前节点的词向量,另一个是当前节点的模型参数。对于上图中的 来说,在训练的过程中,我们当然希望n(,1)的P(-) 更大,n(,2)的P(-) 更大,n(,3)的P(+)更大。所以根据这样的方式,我们就可以对模型进行训练,来得到一些比较好的参数的取值,进而进行模型的预测。
在这里总结一下使用哈夫曼树的优点:
1.由于哈夫曼树是二叉树,所以计算量直接从V 降低到了log2V。
2.由于根据哈夫曼树的性质,靠近树根的节点是更加高频的词汇,离树根较远的节点是出现次数较少的词汇,这样就使得查找高频词汇所需要的花费的路径和时间更少,符合我们贪心优化的思想。
回到模型本身,我们的目标就是希望找到合适的所有节点的词向量和所有内部节点的 ,来使得训练样本达到最大似然,达到最优的结果,那么具体的数学实现是怎么样的呢?接下来进行讲解。
2 基于Hierarchical Softmax的数学推导
因为我们需要使用最大似然法来寻找所有节点的词向量和所有内部节点 。 用上面的 来进行讲解,我们期望最大化下面的似然函数:
对于所有的训练样本,我们期望最大化所有样本的似然函数乘积。
为了便于我们后面一般化的描述,我们定义输入的词为,其从输入层词向量求和平均后的哈夫曼树根节点词向量为, 从根节点到所在的叶子节点,中间包含的节点总数为, 在哈夫曼树中从根节点开始,经过的第个节点表示为,对应的哈夫曼编码为 ∈ {0,1} ,其中 = 2,3,... 。而该节点对应的模型参数表示为, 其中 = 1,2,... −1,没有 = 是因为模型参数仅仅针对于哈夫曼树的内部节点。也就是说 对应的是 。
定义 经过的哈夫曼树某一个节点 j 的逻辑回归概率为 P( | ,),表达式为:
那么对于某一个目标词 ,它的最大似然为:
在word2vec中,由于使用的是随机梯度上升法,所以并没有把所有样本的似然乘起来得到真正的训练集最大似然,仅仅每次只用一个样本更新梯度,这样做的目的是减少梯度计算量。这样我们可以得到 的对数似然函数 如下:
要得到模型中 词向量和内部节点的模型参数 , 我们使用梯度上升法即可。首先我们求模型参数 的梯度:
同样,我们求出 的梯度表达式:
有了梯度表达式,我们就可以用梯度上升法来进行迭代来更新我们模型所需要的所有的参数 和 了。上面的高数求导过程如果有不懂的地方,就请自己补补高数部分了,这属于比较简单的高数求导了。
3 基于Hierarchical Softmax的CBOW模型
因为word2vec中有两种模型,Skip-gram和CBOW,这两种模型在上一篇文章中有所介绍,不懂的可以翻阅上一篇文章,我们这里先看看CBOW模型是如何应用Hierarchical softmax的。
第一步我们需要先定义词向量的维度大小M,以及CBOW模型的上下文大小2c,这样对于训练样本中的每一个词,它前面的c个词和后面的c个词作为模型的输入,然后在输出的概率分布中,它自己的概率值期望要最大。
然后我们需要将词汇表建立生成一颗哈夫曼树。
对于从输入层到隐藏层(投影层),我们就直接采用求和取平均值的方式,对2c个词向量进行求和并取平均值,来得到 。即:
第二步,我们就采用梯度上升的方式来更新 和 ,因为这里的 是由2c个词向量计算所得到的,因此我们直接用梯度项来更新原始的每个 ( = 1,2...,2c),即:
这里的 为梯度上升法的步长,也就是我们常说的学习率(learning rate)。
我们总结一下基于Hierarchical Softmax的CBOW模型的算法流程,梯度迭代部分这里采用了随机梯度上升法:
输入 : 基于CBOW的语料训练样本,词向量的维度大小M,CBOW的上下文大小2c,步长
输出 : 哈夫曼树内部节点模型参数 ,所有的词向量
1 基于训练样本建立哈夫曼树
2 随机初始化所有的参数 和 所有的词向量
3 进行梯度上升迭代过程, 对于训练样本中的每一个样本(context(), )因为输入部分是2c个context,输出是,所以是(context(),),对于每个样本作如下处理:
(1) e = 0, 计算
(2) for j = 2 to ,计算:
(3) 对于context() 中的每一个词向量 (共2c个)进行更新:
=
(4) 如果梯度收敛,则结束迭代,否则返回步骤(3) 继续迭代。
4 基于Hierarchical Softmax的Skip-gram模型
在了解CBOW模型后,现在来了解基于Hierarchical Softmax的Skip-gram模型就会容易很多了,因为两者的方式大同小异。Skip-gram的输入输出和CBOW相反,此时输入的只有一个中心词 ,输出的为 2c个 context()。
对于训练样本中的每一个词,该词自己作为模型的输入,期望该词前面的c个单词和后面的c个单词,总共2c个单词的输出概率比其它词要大。
同样的,我们基于训练数据先建立一颗哈夫曼树。
对于从输入层到隐藏层(投影层),这一步比CBOW简单,由于输入只有一个词,所以,即 就是词 对应的词向量。
第二步,采用梯度上升的方式来更新 和 ,注意因为这里 周围有2c 个词向量,我们期望 P( | ),i=1,2...2c 最大。此时我们注意到由于是上下文相关的,在期望 P( | ),i=1,2...2c 最大时,同时反过来我们也期望 P( | ),i=1,2...2c 也最大。那么是使用哪个方式更好呢? word2vec 选用了后者,因为后者的好处在于它不是仅仅只更新 一个词,而是 , = 1,2...2c 个词。这样整体迭代会更加均衡。也正是因为这个原因,Skip-gram并没有和CBOW模型一样选择对输入进行更新,而是对 2c 个输出进行迭代更新。
这里总结下基于Hierarchical Softmax的Skip-Gram模型算法流程,梯度迭代使用了随机梯度上升法:
输入 : 基于Skip-gram的语料训练样本,词向量的维度大小M,CBOW的上下文大小2c,步长
输出 : 哈夫曼树内部节点模型参数 ,所有的词向量
1 基于训练样本建立哈夫曼树
2 随机初始化所有的参数 和 所有的词向量
3 进行梯度上升迭代过程, 对于训练样本中的每一个样本(,context()),对于每个样本作如下处理:
(1) for i = 1 to 2c :
(a) e = 0
(b) for j = 2 to ,计算:
(c)
=
(2) 如果梯度收敛,则结束迭代,否则返回步骤(1) 继续迭代。