【NLP-03】Word2Vec
目录
- word2vec 简介
- CBOW与Skip-Gram模型
- 优化方法
- 优点
- word2vec API讲解
- 三个最常见的应用
一句话简述:2013年Google发明,使用跳字节模型(skip-gram)或连续词袋模型(continuous bag of words ,CBOW)训练词向量(初始位one-hot),得到嵌入词向量。对比one-hot,大大压缩了词向量表示的维度,同时增加了语义表达。并采用负采样(negative sampling)和层次softmax(hierarchical softmax)优化计算速度。
在word2vec出现之前,自然语言处理经常把字词转为one-hot编码类型的词向量,这种方式虽然非常简单易懂,但是数据稀疏性非常高,维度很多,很容易造成维度灾难,尤其是在深度学习中;其次这种词向量中任意两个词之间都是孤立的,存在语义鸿沟(因为任何one-hot编码乘积为0,这样就不能体现词与词之间的关系,如下图所示)而有Hinton大神提出的Distributional Representation 很好的解决了one-hot编码的主要缺点。解决了语义之间的鸿沟,可以通过计算向量之间的距离来体现词与词之间的关系。Distributional Representation 词向量是密集的。word2vec是一个用来训练Distributional Representation 类型的词向量的一种工具。
说明:Distributed representation可以解决One hot representation的问题,它的思路是通过训练,将每个词都映射到一个较短的词向量上来。所有的这些词向量就构成了向量空间,进而可以用普通的统计学的方法来研究词与词之间的关系。这个较短的词向量维度是多大呢?这个一般需要我们在训练时自己来指定。
一、简介
1.1 word vector
很明显,用上下文来表示中间向量,这种分布式表达方式比one-hot形式能更好反映出不同词但意思相近词的关系。可视化形式更加明显,如下图所示:
1.2 Word2Vec概述
主要来源于Mikolov et al. 2013的一篇论文,例如,用中心词去表示周边词语:
想法:使用概率来表示中心词出现时周边词出现的可能性,再用最大似然函数求出最大的可能性
实际就是求参数θ的过程,那怎么去计算这个表达式呢:
我们使用了向量相乘的方式来进行处理:
O(output)表示周边词,c(center)表示中心词,T表示所在位置,U和V都表示词向量。这种形式就是softmax的模型
(两个好处:1.所有的概率值都是正数了 ;2.概率之和为1)。
接下来我们用梯度下降的方式求解参数,注意每个单词有两个向量,一个输入一个输出:
通过上述步骤,求出θ,再用θ表示出词向量,即得到所求。
二、CBOW与Skip-Gram模型
word2vec模型其实就是简单化的神经网络,主要包含两种词训练模型:CBOW(Continuous Bag-of-Words)模型和Skip-gram模型。模型的结构图如下(注意:这里只是模型结构,并不是神经网络的结构)
CBOW模型根据中心词W(t) 周围的词来预测中心词;Skip-gram模型则根据中心词W(t) 来预测周围的词。
1)输入层是上下文的词语的词向量,在训练CBOW模型,词向量只是个副产品,确切来说,是CBOW模型的一个参数。训练开始的时候,词向量是个随机值,随着训练的进行不断被更新) 。
投影层对其求和,所谓求和,就是简单的向量加法。
输出层输出最可能的w。由于语料库中词汇量是固定的|C|个,所以上述过程其实可以看做一个多分类问题。给定特
征,从|C|个分类中挑一个.输出值的维度和输入值的维度是一致的。
2)Skip-gram模型的第一层是输入层,输入值是中心词的one-hot编码形式,隐藏层只是做线性转换,输出的是输出值的softmax转换后的概率。
神经网络结构如下
神经网络的训练是有监督的学习,因此要给定输入值和输出值来训练神经网络,而我们最终要获得的是隐藏层的权重矩阵。
2.1 CBOW
- 输入层:上下文单词的onehot. {假设单词向量空间dim为V,上下文单词个数为C}
- 所有onehot分别乘以共享的输入权重矩阵W. {VN矩阵,N为自己设定的数,初始化权重矩阵W}
- 所得的向量 {因为是onehot所以为向量} 相加求平均作为隐层向量, size为1N.
- 乘以输出权重矩阵W' {NV}
- 得到向量 {1V} 激活函数处理得到V-dim概率分布 {PS: 因为是onehot嘛,其中的每一维斗代表着一个单词}
- 概率最大的index所指示的单词为预测出的中间词(target word)与true label的onehot做比较,误差越小越好(根据误差更新权重矩阵)
所以,需要定义loss function(一般为交叉熵代价函数),采用梯度下降算法更新W和W'。训练完毕后,输入层的每个单词与矩阵W相乘得到的向量的就是我们想要的词向量(word embedding),这个矩阵(所有单词的word embedding)也叫做look up table(其实这个look up table就是矩阵W自身),也就是说,任何一个单词的onehot乘以这个矩阵都将得到自己的词向量。有了look up table就可以免去训练过程直接查表得到单词的词向量了,而且得到的还是一个稠密的词向量。
更细节地(涉及重要数学公式):
参数说明:U 和 V 最初为随机向量矩阵。
最小化目标函数:
2.2 skip-gram
具体流程如下:
损失函数如下:
三、优化方法
跳字模型的核心在于使用softmax运算得到给定中心词 wc 来生成背景词 wo 的条件概率
该条件概率相应的对数损失
考虑到sofmax归一化需要遍历整个词汇表(上面式子也能看出,要遍历V),不论是跳字模型还是连续词袋模型,由于条件概率使用了softmax运算,每一步的梯度计算都包含词典大小数目的项的累加。对于含几十万或上百万词的较大词典,每次的梯度计算开销可能过大。为了降低该计算复杂度,本节将介绍两种近似训练方法,即负采样(negative sampling)或层序softmax(hierarchical softmax)。由于跳字模型和连续词袋模型类似,本节仅以跳字模型为例介绍这两种方法。
3.1 层次Softmax(Hierarchical Softmax)
哈夫曼树说明:一般得到哈夫曼树后我们会对叶子节点进行哈夫曼编码,由于权重高的叶子节点越靠近根节点,而权重低的叶子节点会远离根节点,这样我们的高权重节点编码值较短,而低权重值编码值较长。这保证的树的带权路径最短,也符合我们的信息论,即我们希望越常用的词拥有更短的编码。如何编码呢?一般对于一个霍夫曼树的节点(根节点除外),可以约定左子树编码为0,右子树编码为1.如上图,则可以得到c的编码是00。
在源代码中,基于Hierarchical Softmax的CBOW模型算法在435-463行,基于Hierarchical Softmax的Skip-Gram的模型算法在495-519行。大家可以对着源代码再深入研究下算法。具体讲解如下:
假设L(w)为从二叉树的根结点到词w的叶结点的路径(包括根结点和叶结点)上的结点数。设n(w,j)为该路径上第j个结点,并设该结点的背景词向量为un(w,j)。以图为例,L(w3)=4。层序softmax将跳字模型中的条件概率近似表示为
leftChild(n) 是结点 n 的左子结点:如果判断 x 为真, [[x]]=1 ;反之 [[x]]=−1 。 让我们计算图10.3中给定词 wc 生成词 w3 的条件概率。我们需要将 wc 的词向量 vc 和根结点到 w3 路径上的非叶结点向量一一求内积。由于在二叉树中由根结点到叶结点 w3 的路径上需要向左、向右再向左地遍历(图中加粗的路径),我们得到
可以看出对应的开销为L(W),是V的对数级别。
3.2 负例采样(Negative Sampling)
在讲基于Negative Sampling的word2vec模型前,我们先看看Hierarchical Softmax的的缺点。的确,使用霍夫曼树来代替传统的神经网络,可以提高模型训练的效率。但其缺陷也很明显:
- 如果我们的训练样本里的中心词w是一个很生僻的词,那么就得在霍夫曼树中辛苦的向下走很久了
- 者语料非常大的时候,构造树依然浪费很多时间。
能不能不用搞这么复杂的一颗霍夫曼树,将模型变的更加简单呢?Negative Sampling就是这么一种求解word2vec模型的方法,Negative Sampling的求解思路(摒弃了霍夫曼树)。
负采样修改了原来的目标函数。给定中心词 wc 的一个背景窗口,我们把背景词 wo 出现在该背景窗口看作一个事件,并将该事件的概率计算为
D=1表示同时出现,D=0表示不是同时出现。σ为sigmoid函数,我们先考虑最大化文本序列中所有该事件的联合概率来训练词向量。具体来说,给定一个长度为 T 的文本序列,设时间步 t 的词为 w(t) 且背景窗口大小为 m ,考虑最大化联合概率
然而,以上模型中包含的事件仅考虑了正类样本。这导致当所有词向量相等且值为无穷大时,以上的联合概率才被最大化为1。很明显,这样的词向量毫无意义。负采样通过采样并添加负类样本使目标函数更有意义。设背景词 w_o 出现在中心词 wc 的一个背景窗口为事件 P ,我们根据分布 P(w) 采样 K 个未出现在该背景窗口中的词,即噪声词。设噪声词 w_k ( k=1,…,K )不出现在中心词 w_c 的该背景窗口为事件 N_k 。假设同时含有正类样本和负类样本的事件 P,N1,…,NK 相互独立,负采样将以上需要最大化的仅考虑正类样本的联合概率改写为:
其中条件概率被近似表示为
设文本序列中时间步 t 的词 w^(t) 在词典中的索引为 i_t ,噪声词 w_k 在词典中的索引为 h_k 。有关以上条件概率的对数损失为:
现在,训练中每一步的梯度计算开销不再与词典大小相关,而与 K 线性相关。当 K 取较小的常数时,负采样在每一步的梯度计算开销较小。
在源代码中,基于Negative Sampling的CBOW模型算法在464-494行,基于Negative Sampling的Skip-Gram的模型算法在520-542行。有空再对着源代码再深入研究下算法。
gensim的python版word2vec来使用word2vec解决实际问题。
小结:
- 层序softmax使用了二叉树,并根据根结点到叶结点的路径来构造损失函数。其训练中每一步的梯度计算开销与词典大小的对数相关。
- 负采样通过考虑同时含有正类样本和负类样本的相互独立事件来构造损失函数。其训练中每一步的梯度计算开销与采样的噪声词的个数线性相关。
四、优点
1)降低输入的维度。词向量的维度一般取100-200,对于大样本时的one-hot向量甚至可能达到10000以上。
2)增加语义信息。两个语义相近的单词的词向量也是很相似的。
五、word2vec API讲解
gensim是一个很好用的Python NLP的包,不光可以用于使用word2vec,还有很多其他的API可以用。它封装了google的C语言版的word2vec。当然我们可以可以直接使用C语言版的word2vec来学习,但是个人认为没有gensim的python版来的方便。
安装gensim是很容易的,使用"pip install gensim"即可。但是需要注意的是gensim对numpy的版本有要求,所以安装过程中可能会偷偷的升级你的numpy版本。而windows版的numpy直接装或者升级是有问题的。此时我们需要卸载numpy,并重新下载带mkl的符合gensim版本要求的numpy。
在gensim中,word2vec 相关的API都在包gensim.models.word2vec中。和算法有关的参数都在类gensim.models.word2vec.Word2Vec中。算法需要注意的参数有:
官方API介绍如下:
class gensim.models.word2vec.Word2Vec(sentences=None, corpus_file=None, size=100, alpha=0.025, window=5, min_count=5, max_vocab_size=None, sample=0.001, seed=1, workers=3, min_alpha=0.0001, sg=0, hs=0, negative=5, ns_exponent=0.75, cbow_mean=1, hashfxn=<built-in function hash>, iter=5, null_word=0, trim_rule=None, sorted_vocab=1, batch_words=10000, compute_loss=False, callbacks=(), max_final_vocab=None)
六、三个最常见的应用
当训练完模型之后,我们就可以用模型来处理一些常见的问题了,主要包括以下三个方面:
1)找出某一个词向量最相近的集合
model.wv.similar_by_word()
从这里可以衍生出去寻找相似的句子,比如"北京下雨了",可以先进行分词为{"北京","下雨了"},然后找出每个词的前5或者前10个相似的词,比如"北京"的前五个相似词是
{"上海", "天津","重庆","深圳","广州"}
"下雨了"的前五个相似词是
{"下雪了","刮风了","天晴了","阴天了","来台风了"}
然后将这两个集合随意组合,可以得到25组不同的组合,然后找到这25组中发生概率最大的句子输出。
2)查看两个词向量的相近程度
model.wv.similarity()
比如查看"北京"和"上海"之间的相似度
3)找出一组集合中不同的类别
model.wv.doesnt_match()
比如找出集合{"上海", "天津","重庆","深圳","北京"}中不同的类别,可能会输出"深圳",当然也可能输出其他的
参考文献
【1】论文:
https://arxiv.org/pdf/1310.4546.pdf :
Tomas Mikolov, Ilya Sutskever, Kai Chen, Greg S Corrado, and Jeff Dean. 2013. Distributed representations
of words and phrases and their compositionality.In NeurIPS, pages 3111–3119.
https://arxiv.org/pdf/1301.3781.pdf:
Mikolov T , Chen K , Corrado G , et al. Efficient Estimation of Word Representations in Vector Space[J]. Computer ence, 2013.
【2】详细的推导:
word2vec 中的数学原理详解 https://www.cnblogs.com/peghoty/p/3857839.html
word2vec原理(三) 基于Negative Sampling的模型 https://www.cnblogs.com/pinard/p/7249903.html
【3】CS224n课程
【4】动手学习深度学习 http://zh.d2l.ai/chapter_natural-language-processing/word2vec.html