Word2vector

word2vec是google在2013年推出的一个NLP工具,它的特点是将所有的词向量化,这样词与词之间就可以定量的去度量他们之间的关系,挖掘词之间的联系。Word2vector可以说是nlp的基石,但是其思想不仅仅局限在nlp,比如广告推荐中id的embedding也可以应用,本篇就来梳理一下word2vector,主要总结如何用恰当的词向量表示词,以及如何建模和训练,其中主要内容包括word2vector的基本思想、CBOW与skip-gram模型、霍夫曼树与Hierarchical Softmax、负采样(negative sampling)等


1,Word2vector基础

词向量表示词,有很多种方法。早期的词向量是比较冗余的,比如one-hot编码:一个只有一个是1,其他全为0的向量,向量长度是词汇表大小。这种方法用来表示词向量很简单,但是也有很多问题,如果词汇表特别大,内存消耗特别严重,而且其表达效率不高,因为除了个别位置是1,其他位置均为0。

Distributed representation可以解决One hot representation的问题。它的思路是通过训练,将每个词都映射到一个较短的词向量上来。所有的这些词向量就构成了向量空间,进而可以用普通的统计学的方法来研究词与词之间的关系。这个较短的词向量维度是多大呢?这个一般需要我们在训练时自己来指定。

可以理解为通过训练的方式,降维压缩成一个低维的稠密矩阵,类似自编码思想,所以,很容易我们就联想到了神经网络的思想。神经网络是可以进行词向量的训练的,比如一个三层的神经网络,定义好输入输出数据,取隐藏层作为我们的词向量。

那么输入输出如何定义?一般有CBOW(Continuous Bag-of-Words )与Skip-Gram两种模型

2,CBOW与skip-Gram方法

CBOW模型的训练输入是某一个特征词的上下文相关的词对应的词向量,而输出就是这特定的一个词的词向量。
在这里插入图片描述
Skip-Gram模型和CBOW的思路是反着来的,即输入是特定的一个词的词向量,而输出是特定词对应的上下文词向量。

在这里插入图片描述
这就是神经网络语言模型中CBOW与Skip-Gram来训练模型的基本过程。但是这和word2vec中用CBOW与Skip-Gram来训练模型与得到词向量的过程有很多的不同。word2vec并没有用线程的DNN模型,因为DNN模型参数多,计算量大,训练非常耗时,其中主要消耗计算的地方在softmax输出层。

那么,有什么方法可以简化计算过程吗?——霍夫曼树

3,霍夫曼树原理

softmax计算量巨大,霍夫曼树可以简化计算,用霍夫曼树来代替隐藏层和输出层的神经元,霍夫曼树的叶子节点起到输出层神经元的作用,叶子节点的个数即为词汇表的小大。而内部节点则起到隐藏层神经元的作用。我们首先看下霍夫曼树的基本原理。

霍夫曼树的建立过程如下:
输入:权值为(w1,w2,…wn)的n个节点
输出:对应的霍夫曼树
1)将(w1,w2,…wn)看做是有n棵树的森林,每个树仅有一个节点。
2)在森林中选择根节点权值最小的两棵树进行合并,得到一个新的树,这两颗树分布作为新树的左右子树。新树的根节点权重为左右子树的根节点权重之和。
3) 将之前的根节点权值最小的两棵树从森林删除,并把新树加入森林。
4)重复步骤2)和3)直到森林里只有一棵树为止。

举个例子
我们有(a,b,c,d,e,f)共6个节点,节点的权值分布是(20,4,8,6,16,3)。首先是最小的b和f合并,得到的新树根节点权重是7.此时森林里5棵树,根节点权重分别是20,8,6,16,7。此时根节点权重最小的6,7合并,得到新子树,依次类推,最终得到下面的霍夫曼树。
在这里插入图片描述
那么霍夫曼树有什么好处呢?
一般得到霍夫曼树后我们会对叶子节点进行霍夫曼编码,由于权重高的叶子节点越靠近根节点,而权重低的叶子节点会远离根节点,这样我们的高权重节点编码值较短,而低权重值编码值较长。这保证的树的带权路径最短,也符合我们的信息论,即我们希望越常用的词拥有更短的编码。

如何编码呢?
一般对于一个霍夫曼树的节点(根节点除外),可以约定左子树编码为0,右子树编码为1.如上图,则可以得到c的编码是00。在word2vec中,约定编码方式和上面的例子相反,即约定左子树编码为1,右子树编码为0,同时约定左子树的权重不小于右子树的权重。

以上就是霍夫曼树,他是如何应用在word2vector中的?它的参数是什么?loss是什么?又是如何进行计算和优化的?下面来分析

4. 基于Hierarchical Softmax的模型

我们说,word2vector没有直接用神经网络模型,而是对其做了优化,那具体都有哪些呢?
1)首先,对于从输入层到隐藏层的映射,没有采取神经网络的线性变换加激活函数的方法,而是采用简单的对所有输入词向量求和并取平均的方法。比如输入的是三个4维词向量:(1,2,3,4),(9,6,11,8),(5,10,7,12)那么我们word2vec映射后的词向量就是(5,6,7,8),这里是从多个词向量变成了一个词向量。

2)其次,从隐藏层到输出的softmax层这里的计算量个改进。为了避免要计算所有词的softmax概率,word2vec采样了霍夫曼树来代替从隐藏层到输出softmax层的映射。我们在上一节已经介绍了霍夫曼树的原理。如何映射呢?这里就是理解word2vec的关键所在了。

由于我们把之前所有都要计算的从输出softmax层的概率计算变成了一颗二叉霍夫曼树,那么我们的softmax概率计算只需要沿着树形结构进行就可以了。如下图所示,我们可以沿着霍夫曼树从根节点一直走到我们的叶子节点的词w2。

在这里插入图片描述
与之前的神经网络相比,霍夫曼树的内部节点类似于隐藏层的神经元,根节点的词向量对应我们的投影后的词向量,而所有叶子节点就类似于之前神经网络softmax输出层的神经元,叶子节点的个数就是词汇表的大小,在霍夫曼树中,softmax这个映射不是一下就完成的,而是沿着霍夫曼树一步步完成的,因此这种softmax取名为"Hierarchical Softmax"。我们把每一步看做是一个二元逻辑回归的方法,即规定沿着左子树走,那么就是负类(霍夫曼树编码1),沿着右子树走,那么就是正类(霍夫曼树编码0)。判别正类和负类的方法是使用sigmoid函数:
P ( + ) = σ ( x w T θ ) = 1 1 + e − x w T θ P(+)=\sigma(x_w^T\theta)=\frac{1}{1+e^{-x_w^T\theta}} P(+)=σ(xwTθ)=1+exwTθ1
其中 x w x_w xw是当前内部节点的词向量,而θ则是我们需要从训练样本求出的逻辑回归的模型参数。

特点
1)由于是二叉树,之前计算量为V,现在变成了log2V。
2)由于使用霍夫曼树是高频的词靠近树根,这样高频词需要更少的时间会被找到,这符合我们的贪心优化思想。

对于上图中的 w 2 w_2 w2,如果它是一个训练样本的输出,那么我们期望对于里面的隐藏节点 n ( w 2 , 1 ) n(w_2,1) n(w2,1)的P(−)概率大, n ( w 2 , 2 ) n(w_2,2) n(w2,2)的P(−)概率大, n ( w 2 , 3 ) n(w_2,3) n(w2,3)的P(+)概率大,这样沿着节点一路走过来,才能得到我们想要的结果。我们的目标就是找到合适的所有节点的词向量和所有内部节点θ, 使训练样本达到最大似然。

5. 基于Hierarchical Softmax的模型优化

先回忆下前面的例子,我们用公式表达出 w 2 w_2 w2的最大似然函数:

∏ i = 1 3 p ( n ( w i ) , i ) = ( 1 − 1 1 + e − x w T θ 1 ) ( 1 − 1 1 + e − x w T θ 2 ) 1 1 + e − x w T θ 3 \prod_{i=1}^{3}p(n(w_i),i)=(1-\frac{1}{1+e^{-x_w^T\theta_1}})(1-\frac{1}{1+e^{-x_w^T\theta_2}})\frac{1}{1+e^{-x_w^T\theta_3}} i=13p(n(wi),i)=(11+exwTθ11)(11+exwTθ21)1+exwTθ31

如果我们能得到所有样本的最大似然函数,对其求最大似然估计即可。首先我们得定义一些参数:我们定义输入的词为w,其从输入层词向量求和平均后的霍夫曼树根节点词向量为 x w x_w xw, 从根节点到w所在的叶子节点,包含的节点总数为 l w l_w lw, w在霍夫曼树中从根节点开始,经过的第i个节点表示为 p w i p_{w_i} pwi,对应的霍夫曼编码为 d w i ∈ 0 , 1 d_{w_i}∈{0,1} dwi0,1,其中i=2,3,…lw。而该节点对应的模型参数表示为 θ w i θ_{w_i} θwi, 其中i=1,2,…lw−1,没有i= l w l_w lw是因为模型参数仅仅针对于霍夫曼树的内部节点。

每个霍夫曼树节点j的逻辑回归概率表达为:

P ( d j w ∣ x w , θ j − 1 w ) = { σ ( x w T θ j − 1 w ) d j w = 0 1 − σ ( x w T θ j − 1 w ) d j w = 1 P(d_j^w|x_w,\theta_{j-1}^w)=\left\{ \begin{aligned} & \sigma(x_w^T\theta_{j-1}^w) & d_j^w=0\\ & 1- \sigma(x_w^T\theta_{j-1}^w) & d_j^w=1\\ \end{aligned}\right. P(djwxw,θj1w)={σ(xwTθj1w)1σ(xwTθj1w)djw=0djw=1

那么对于某一个目标输出词w,其最大似然为:

∏ j = 2 l w P ( d j w ∣ ( x w , θ j − 1 w ) = ∏ j = 2 l w [ σ ( x w T θ j − 1 w ) ] 1 − d j w [ 1 − σ ( x w T θ j − 1 w ) ] d j w \prod_{j=2}^{l_w}P(d_j^w|(x_w,\theta_{j-1}^{w})=\prod_{j=2}^{l_w}[\sigma(x_w^T\theta_{j-1}^w) ]^{1-d_j^{w}}[1-\sigma(x_w^T\theta_{j-1}^w) ]^{d_j^w} j=2lwP(djw(xw,θj1w)=j=2lw[σ(xwTθj1w)]1djw[1σ(xwTθj1w)]djw

解释两点
1)为什么j从2开始。从根节点到子节点看做1到lw,第一层节点作为输出,没有输入。
2)为什么公式是针对某一个目标输出词w,而不是全部词。每个词的路径不同,能优化的只是这条路径上的参数,这样可以减少梯度计算量。

下面就是梯度求解的常规做法,取log,求导数:

L = l o g ∏ j = 2 l w P ( d j w ∣ ( x w , θ j − 1 w ) = ∑ j = 2 l w ( ( 1 − d j w ) l o g [ σ ( x w T θ j − 1 w ) ] ( d j w ) l o g [ 1 − σ ( x w T θ j − 1 w ) ] ) L = log\prod_{j=2}^{l_w}P(d_j^w|(x_w,\theta_{j-1}^{w}) =\sum_{j=2}^{l_w}((1-d_j^{w})log[\sigma(x_w^T\theta_{j-1}^w) ] ({d_j^w})log[1-\sigma(x_w^T\theta_{j-1}^w) ]) L=logj=2lwP(djw(xw,θj1w)=j=2lw((1djw)log[σ(xwTθj1w)](djw)log[1σ(xwTθj1w)])

∂ L ∂ θ j − 1 w = ( 1 − d j w − σ ( x w T θ j − 1 w ) ) x w \frac{\partial L}{\partial{\theta_{j-1}^{w}}}=(1-d_j^w-\sigma(x_w^T\theta_{j-1}^w))x_w θj1wL=(1djwσ(xwTθj1w))xw

∂ L ∂ x w = ∑ j = 2 l w ( 1 − d j w − σ ( x w T θ j − 1 w ) ) θ j − 1 w \frac{\partial L}{\partial x_w}=\sum_{j=2}^{l_w}(1-d_j^w-\sigma(x_w^T\theta_{j-1}^w))\theta_{j-1}^w xwL=j=2lw(1djwσ(xwTθj1w))θj1w

我们说word2vector有两种模型CBOW和skip-gram这两种模型。他们分别是怎么实现优化的呢?

5.1 基于Hierarchical Softmax的CBOW模型优化

首先我们要定义词向量的维度大小M,以及CBOW的上下文大小2c,这样我们对于训练样本中的每一个词,其前面的c个词和后面的c个词作为了CBOW模型的输入,该词本身作为样本的输出,期望softmax概率最大。

在做CBOW模型前,我们需要先将词汇表建立成一颗霍夫曼树(可以将频率作为权重)。对于从输入层到隐藏层(投影层),这一步比较简单,就是对w周围的2c个词向量求和取平均即可,即

x w = 1 2 c ∑ i = 1 2 c x i x_w=\frac{1}{2c}\sum_{i=1}^{2c}x_i xw=2c1i=12cxi

第二步,通过梯度上升法来更新我们的θwj−1和xw,注意这里的xw是由2c个词向量相加而成,我们做梯度更新完毕后会用梯度项直接更新原始的各个xi(i=1,2…2c),即:

θ j − 1 w = θ j − 1 w + η ( 1 − d j w − σ ( x w T θ j − 1 w ) ) x w \theta_{j-1}^w =\theta_{j-1}^w + \eta (1-d_j^w-\sigma(x_w^T\theta_{j-1}^w))x_w θj1w=θj1w+η(1djwσ(xwTθj1w))xw

x i = x i + η ∑ j = 2 l w ( 1 − d j w − σ ( x w T θ j − 1 w ) ) θ j − 1 w x_i = x_i+\eta\sum_{j=2}^{l_w}(1-d_j^w-\sigma(x_w^T\theta_{j-1}^w))\theta_{j-1}^w xi=xi+ηj=2lw(1djwσ(xwTθj1w))θj1w

5.2,基于Hierarchical Softmax的skip-gram模型优化

在做CBOW模型前,我们需要先将词汇表建立成一颗霍夫曼树。skip-gram模型从输入层到隐藏层(投影层),这一步比CBOW简单,由于只有一个词,所以,即xw就是词w对应的词向量。

第二步,通过梯度上升法来更新我们的 θ j − 1 θ_j−1 θj1 x w x_w xw,注意这里的 x w x_w xw周围有2c个词向量,此时如果我们期望 P ( x i ∣ x w ) , i = 1 , 2...2 c P(x_i|x_w),i=1,2...2c P(xixw),i=1,2...2c最大。此时我们注意到由于上下文是相互的,在期望 P ( x i ∣ x w ) , i = 1 , 2...2 c P(x_i|x_w),i=1,2...2c P(xixw),i=1,2...2c最大化的同时,反过来我们也期望 P ( x w ∣ x i ) , i = 1 , 2...2 c P(x_w|x_i),i=1,2...2c P(xwxi),i=1,2...2c最大。那么是使用 P ( x i ∣ x w ) P(x_i|x_w) P(xixw)好还是 P ( x w ∣ x i ) P(x_w|x_i) P(xwxi)好呢,word2vec使用了后者,这样做的好处就是在一个迭代窗口内,我们不是只更新 x w x_w xw一个词,而是 x i , i = 1 , 2...2 c x_i,i=1,2...2c xi,i=1,2...2c共2c个词。这样整体的迭代会更加的均衡。因为这个原因,Skip-Gram模型并没有和CBOW模型一样对输入进行迭代更新,而是对2c个输出进行迭代更新。

6,基于负采样(negative sampling)的模型

使用霍夫曼树来代替传统的神经网络,可以提高模型训练的效率,但是如果我们的训练样本里的中心词w是一个很生僻的词,那么就得在霍夫曼树中辛苦的向下走很久了。能不能不用搞这么复杂的一颗霍夫曼树,将模型变的更加简单呢?

Negative Sampling就是这么一种求解word2vec模型的方法,它摒弃了霍夫曼树,采用了Negative Sampling(负采样)的方法来求解,下面我们就来看看Negative Sampling的求解思路。

比如我们有一个训练样本,中心词是w,它周围上下文共有2c个词,记为context(w)。由于这个中心词w,的确和context(w)相关存在,因此它是一个真实的正例。通过Negative Sampling采样,我们得到neg个和w不同的中心词 w i , i = 1 , 2 , . . n e g w_i,i=1,2,..neg wi,i=1,2,..neg,这样context(w)和 w i w_i wi就组成了neg个并不真实存在的负例。利用这一个正例和neg个负例,我们进行二元逻辑回归,得到负采样对应每个词 w i w_i wi对应的模型参数 θ i θ_i θi,和每个词的词向量。

是不是简单多了,没有霍夫曼树,每次得到数据以后,采样neg个不同的中心词作为负样本就可以进行二元逻辑回归训练。摆在我们面前的有两个问题:1)如何负采样?2)如何进行一个正样本与neg个负样本的二元逻辑回归?

6.1 负采样

每个词都是有权重的,采样也肯定跟权重相关,单词的权重用一下公式表示:
l e n ( w ) = c o u n t ( w ) 3 / 4 ∑ c o u n t ( u ) 3 / 4 len(w)=\frac{count(w)^{3/4}}{\sum count(u)^{3/4}} len(w)=count(u)3/4count(w)3/4
很明显这跟词频相关,为什么取3/4?很多时候这种参数都是经验值

word2vec采样的方法并不复杂,如果词汇表的大小为V,那么我们就将一段长度为1的线段分成V份,每份对应词汇表中的一个词。当然每个词对应的线段长度是不一样的,高频词对应的线段长,低频词对应的线段短。每个词w的线段长度按照权重分配。
在这里插入图片描述
在采样前,我们将这段长度为1的线段划分成M(默认10^8)等份,这里M>>V,这样可以保证每个词对应的线段都会划分成对应的小块。而M份中的每一份都会落在某一个词对应的线段上。在采样的时候,我们只需要从M个位置中采样出neg个位置就行,此时采样到的每一个位置对应到的线段所属的词就是我们的负例词。

6.2 优化

通过负采样,我们得到了neg个负例 ( c o n t e x t ( w ) , w i ) i = 1 , 2 , . . n e g (context(w),w_i)i=1,2,..neg (context(w),wi)i=1,2,..neg。为了统一描述,我们将正例定义为w_0。

在逻辑回归中,正样本期望满足:
p ( c o n t e x t ( w 0 ) , w i ) = σ ( x w 0 T θ w i ) , y i = 1 , i = 0 p(context(w_0),w_i)=\sigma(x_{w_0}^T\theta^{w_i}),y_i=1,i=0 p(context(w0),wi)=σ(xw0Tθwi),yi=1,i=0
对于负样本期望满足:
p ( c o n t e x t ( w 0 ) , w i ) = 1 − σ ( x w 0 T θ w i ) , y i = 0 , i = 1 , 2.... n e g p(context(w_0),w_i)=1-\sigma(x_{w_0}^T\theta^{w_i}),y_i=0,i=1,2....neg p(context(w0),wi)=1σ(xw0Tθwi),yi=0,i=1,2....neg
那么我们期望可以最大化一下公式:
∏ i = 0 n e g P ( c o n t e x t ( w 0 ) , w i ) = σ ( x w 0 T θ w 0 ) ∏ i = 0 n e g ( 1 − σ ( x w 0 T θ w i ) ) \prod_{i=0}^{neg}P(context(w_0),w_i)=\sigma(x_{w_0}^T\theta^{w_0})\prod_{i=0}^{neg}(1-\sigma(x_{w_0}^T\theta^{w_i})) i=0negP(context(w0),wi)=σ(xw0Tθw0)i=0neg(1σ(xw0Tθwi))
继续表达成似然函数,以及最大似然函数:
∏ i = 0 n e g σ ( x w 0 T θ w i ) y i ( 1 − σ ( x w 0 T θ w i ) ) 1 − y i \prod_{i=0}^{neg}\sigma(x_{w_0}^T\theta^{w_i})^{y_i}(1-\sigma(x_{w_0}^T\theta^{w_i}))^{1-y_i} i=0negσ(xw0Tθwi)yi(1σ(xw0Tθwi))1yi

取log然后求偏导
∂ L ∂ θ w i = ( y i − σ ( x w 0 T θ w i ) ) x w 0 \frac{\partial L}{\partial \theta^{w_i}}=(y_i-\sigma(x_{w_0}^T \theta ^{w_i}))x_{w_0} θwiL=(yiσ(xw0Tθwi))xw0
∂ L ∂ x w 0 = ∑ i = 0 n e g ( y i − σ ( x w 0 T θ w i ) ) θ w i \frac{\partial L}{\partial x^{w_0}}=\sum_{i=0}^{neg}(y_i-\sigma(x_{w_0}^T \theta ^{w_i}))\theta^{w_i} xw0L=i=0neg(yiσ(xw0Tθwi))θwi
通过梯度下降算法就可以迭代求解了。

7,总结

1)w2v就是单词的向量表示
2)CBOW与skip-gram是两种w2v思路,主要区别在于上下文与单词本身输入输出关系。
3)w2v处理的语料库比较大,参数众多,一般通过霍夫曼树或者负采样简化计算,这两种方法,都是在输出端进行的。
4)Python可以用gensim库实现w2v

参考文献:
http://mccormickml.com/2016/04/19/word2vec-tutorial-the-skip-gram-model/
https://www.jianshu.com/p/1405932293ea
https://www.jianshu.com/p/d8bfaae28fa9
https://blog.csdn.net/github_36235341/article/details/78607323
https://www.cnblogs.com/pinard/p/7243513.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Word2Vec是一种用于将文本转换为向量表示的工具,它是通过训练一个神经网络模型来实现的。在Word2Vec的源码中,有几个主要的部分和过程。 首先,源码中包含了数据预处理的步骤。这个步骤包括将原始文本分割成单词,建立词汇表并为每个单词分配一个唯一的标识符。源码还负责将原始文本转换为训练样本,其中每个样本由一个输入单词和一个输出单词组成。 接下来,源码中定义了训练模型的结构和参数。该模型通常是一个两层的神经网络,其中包含一个隐藏层和一个输出层。隐藏层的节点数可以根据需求进行设置。训练模型中的参数包括学习率、迭代次数和训练样本的窗口大小等。 然后,源码中实现了模型的训练过程。训练过程基于输入和输出单词的样本对,通过对模型进行多次迭代来优化模型的参数。在每一次迭代的过程中,模型会根据当前输入单词预测输出单词,并计算预测结果与实际输出之间的误差。然后,模型会使用误差来更新参数,以提高模型的准确性。 最后,源码中还提供了用于将训练好的模型应用于新的文本数据的方法。通过载入训练好的模型参数,并使用这些参数来将新的文本转换为向量表示。 总的来说,Word2Vec的源码实现了一个能够将文本转为向量表示的工具,并通过训练神经网络模型来优化向量表示的准确性。通过了解源码,我们可以更好地理解Word2Vec的原理和实现过程,并且可以根据需要进行修改和扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值