词向量Word2Vec(深度细致分析)
本⽂以博客园对于word2vec的解释为基础,同时参考了其他相关博客的分析并加⼊了⾃⼰的理解,希望站在巨⼈的肩膀上进⾏⼀定的学习输出。⾄于本⽚⽂章的属性,个⼈认为是伪原创吧,有需要的同学可以⾃⾏转到相应的链接。
word2vec是google在2013年推出的⼀个NLP⼯具,它的特点是将所有的词向量化,这样词与词之间就可以定量的去度量他们之间的关系,挖掘词之间的联系。有兴趣可以看看
⼀,⾃然语⾔的基础——词向量
⾃然语⾔是⼀套⽤来表达含义的复杂系统。在这套系统中,词语(这⾥常见的是把词语理解为英⽂中的单词或者汉语中的字)是表义的基本单元。⽽词语是⼈类的抽象总结,是符号形式的。⽽计算机的基础是数学,是不能直接处理抽象符号的,所以⼀个很⾃然的想法是能不能把⼈类的抽象符号词语转换为数学语⾔以供计算机使⽤呢?答案是可以的,也就是把抽象的词语转换成数值形式,或者说嵌⼊到⼀个数学空间⾥,这种嵌⼊⽅式,就叫词嵌⼊(word embedding),⽽ word2vec,就可以认为是词嵌⼊( word embedding) 的⼀种(准确的说
word2vec整个流程是处理语义联系的,只不过在这个处理流程的产物之⼀便是词向量)。简单点来说就是把⼀个词语转换成对应向量的表达形式,来让计算机读取数据。
⽤词向量来表⽰词并不是word2vec的⾸创,在很久之前就出现了。最早的词向量是使⽤哑编码(one-hot)产⽣的,它所产⽣的词向量维度⼤⼩为整个词汇表的⼤⼩,对于每个具体的词汇表中的词,将对应的位置置为1。⽐如我们有下⾯的5个词组成的词汇表,词"Queen"的序号为2, 那么它的词向量就是(0,1,0,0,0)。同样的道理,词"Woman"的词向量就是(0,0,0,1,0)。这种词向量的编码⽅式我们⼀般叫做1-
茶底世界吉他谱of-N reprentation或者one hot reprentation.
哑编码表⽰(One hot reprentation)⽤来表⽰词向量⾮常简单,但是却有很多问题。最⼤的问题是我们的词汇表⼀般都⾮常⼤,⽐如英语单词总量达到百万级别(百度百科显⽰英语单词总数为99万),这样每个词都⽤百万维的向量来表⽰简直是内存的灾难,⽽且也带来了巨量的计算。并且这样的向量其
百家讲坛纪连海
实除了⼀个位置是1,其余的位置全部都是0,表达的效率不⾼,能不能把词向量的维度变⼩呢?高考作文人物素材
词的分布式表⽰(Distributed reprentation)可以解决One hot reprentation的问题,它的思路是通过训练,将每个词都映射到⼀个较短的词向量上来。所有的这些词向量就构成了向量空间,进⽽可以⽤普通的统计学的⽅法来研究词与词之间的关系。这个较短的词向量维度是多⼤呢?这个⼀般需要我们在训练时⾃⼰来指定。
⽐如下图我们将词汇表⾥的词⽤"Royalty",“Masculinity”, "Femininity"和"Age"4个维度来表⽰(这四个单词的意思分别是王权,男性,⼥性,年龄),King这个词对应的词向量可能是(0.99,0.99,0.05,0.7)。⼤致可以理解为国王为具有王权的男性,这样就从原来⾮常稀疏的one hot产⽣的词向量转变成了现在的稠密向量,⼤⼤节约了内存和减少了计算量。当然在实际情况中,我们并不能对词向量的每个维度做⼀个很好的解释。
有了⽤Distributed Reprentation表⽰的较短的词向量,我们就可以较容易的分析词之间的关系了,⽐如我们将词的维度降维到2维,有⼀个有趣的研究表明,⽤下图的词向量表⽰我们的词时,我们可以发现:
可见我们只要得到了词汇表⾥所有词对应的词向量,就可以⽤数学的⽅式来计算词语之间的关系了,
进⽽也就可以进⼀步的对⾃然语⾔进⾏处理了。那么关键是如何训练得到合适的词向量呢?⼀个很常见的⽅法是使⽤神经⽹络语⾔模型。
⼆,神经⽹络语⾔模型
神经⽹络语⾔模型采⽤的⽅法⼀般是三层的神经⽹络结构(当然也可以多层),分为输⼊层,隐藏层和输出层(softmax层)。从数据输⼊输出的⾓度看,该模型分为连续词袋模型(Continuous Bag-of-Words,简称CBOW) 与和跳字模型(Skip-Gram)两种模型。
CBOW的训练模型如图所⽰
图中的V表⽰⽂档词汇表的⼤⼩,也即单词的维度(单词维度与词汇表⼤⼩⼀致),k表⽰第⼏个中⼼词(k<V),C表⽰中⼼词的上下⽂单词数量,也就是窗⼝的2倍,N表⽰我们希望⽣成的稠密词向量的维度。
CBOW模型的训练输⼊是某⼀个中⼼词的上下⽂相关的词对应的词向量,⽽输出就是这中⼼词的词向量。⽐如下⾯这段话,结合上图的CBOW训练图,
1,输⼊层:假设该句⼦所在的⽂档的词汇表是V = 1万,我们的上下⽂⼤⼩取值为4(也即窗⼝为4),中⼼词是"Learning",也就是我们需要的输出词向量,上下⽂对应的词有8个,前后各4个,每个词由于均采⽤one-hot编码,每个单词向量均有1万维,形状为1*V,这8个one-hot词向量是我们模型的输⼊。
2,然后每个词向量乘以⼀个共享的输⼊权重矩阵W,该矩阵的形状为V*N(N<<V,是我们⼈为设置的数,由此可对稀疏的one-hot原始词向量进⾏显著的降维,这⾥假设V=200)。相乘之后每个单词的词向量形状为1*N。
3,隐藏层:将这8个单词的词向量在列的⽅向上拼接,形成⼀个向量,形状为1*8N
4,将这个向量再乘以输出权重矩阵W`,形状为8N*V(注意此时图中矩阵的形状有误),得到⼀个形状为1*V的向量。
5,上述得到的向量经过softmax处理,得到预测中⼼词属于词汇表每个词概率值。
6,概率最⼤的index所指⽰的单词为预测出的中⼼词,该预测中⼼词与真实中⼼词(true label)作⽐较得出误差值,通过反向传播不断减⼩该误差值。
所以,需要定义loss function(⼀般为交叉熵损失函数),采⽤梯度下降法(或者梯度上升法)更新W和W’。训练完毕后,输⼊层的每个单词的one-hot向量与输⼊权重矩阵W相乘得到的向量的就是我们想要的词向量,这个矩阵W(所有单词的词向量)也叫做look up table,也就是说,任何⼀个单词的one-hot乘以这个矩阵都将得到⾃⼰的词向量。换句话说,输⼊权重矩阵其实就是词汇表在数学空间的表⽰。⽽输出权重矩阵相当于上下⽂单词到中⼼词的⼀种映射。
这⾥我们可以看到,原来我们使⽤one-hot编码产⽣的词向量,词汇表中的每个单词都是1*V的向量,现在我们训练出look up table矩阵后,词汇表便可以使⽤⼀个矩阵完全表⽰了。周一伟>快速长头发
通过不断喂样本给上述CBOW模型,我们训练出⽐较合适的输⼊和输出权重矩阵。这样当我们有新的
葱油饼的制作方法
需求,要求出某8个词对应的最可能的输出中⼼词时,我们可以通过⼀次神经⽹络前向传播算法并通过softmax处理找到概率最⼤的词即可。
搞懂了CBOW模型,skip-gram模型便⽐较容易理解了。
Skip-Gram模型和CBOW的思路是反着来的,即输⼊是中⼼词的one-hot向量,⽽输出是中⼼词对应的上下⽂词向量。还是上⾯的例⼦,我们的上下⽂⼤⼩取值为4, 特定的这个词"Learning"是我们的输⼊,⽽这8个上下⽂词是我们的输出。
彩墨游戏这样我们这个Skip-Gram的例⼦⾥,我们的输⼊是中⼼词, 输出是softmax概率排前8的8个词,对应的Skip-Gram神经⽹络模型输⼊层有1个神经元,输出层有词汇表⼤⼩个神经元。隐藏层的神经元个数我们可以⾃⼰指定。通过神经⽹络的反向传播算法,我们可以求出神经⽹络模型的参数,同时得到所有的词对应的词向量。这样当我们有新的需求,要求出某1个词对应的最可能的8个上下⽂词时,我们可以通过⼀次神经⽹络前向传播算法得到概率⼤⼩排前8的softmax概率对应的词即可。
以上就是神经⽹络语⾔模型中如何⽤CBOW与Skip-Gram来训练模型与得到词向量的⼤概过程。但是这和word2vec中⽤CBOW与Skip-Gram来训练模型与得到词向量的过程有很多的不同。
word2vec为什么 不⽤现成的神经⽹络模型,要继续优化出新⽅法呢?最主要的问题是神经⽹络模型
的这个处理过程⾮常耗时。我们的词汇表⼀般是百万级别,这意味着我们神经⽹络的输出层需要进⾏softmax计算各个词的输出概率的的计算量很⼤。有没有简化⼀点点的⽅法呢?
三,word2vec相对于传统的神经⽹络的改进
word2vec可以认为是在神经⽹络的基础上做了⼀系列的改进以克服传统神经⽹络计算量过⼤的缺点。word2vec同样也分为CBOW和skip-gram两种模型,我们以前⽂的CBOW模型为例,看看word2vec相对于传统的神经⽹络有哪些改进:
1,输⼊层:传统的神经⽹络输⼊的是单词的one-hot向量,然后乘以输⼊权重矩阵W才能到达隐藏层。单词one-hot向量是⾼度稀疏的,⾼度稀疏的⾼维单词one-hot向量与V N维的W矩阵相乘的计算量为V N,再加上需要8个单词的one-hot向量需要这样计算,所以这⼀步的计算量为8V N = 16000000。上⽂也提到每个单词的one-hot向量乘以矩阵W得到该单词的词向量,那么有没有什么⽅法可以避免使⽤乘法运算呢?答案是有的,那就是对词汇表的每个单词指定⼀个索引,再把这个索引作为输⼊权重矩阵W的⾏索引就可以直接得到这个单词的词向量了,前⽂我们也说过,矩阵W实际上对应着词汇表,所以词汇表中的单词当然可以像查字典⼀样在矩阵W中通过索引查得啦。这样通过查索引⽽不是矩阵相乘的⽅法⼤⼤减少了这⼀步的计算量。
2,投影层(隐藏层):这⼀层也叫做隐藏层,在上⽂传统的神经⽹络⾥,词向量在这⼀层是通过列向量
拼接的⽅式形成⼀个中间向量的,中间向量的形状为18N。由于N不是很⼩,这个向量的维度也不会太⼩,⽽向量维度越⾼就意味着下⼀步的计算量越⼤,所以能不能在这⼀步将新向量的维度减⼩呢?word2vec的做法是在词向量合并的时候不通过列的拼接,⽽是在相同的列上直接求和(或者求和后再求平均)的⽅式将投影层得到的中间向量的维度降低为1N,也就是维度没有增加。
3,输出层:传统的神经⽹络是将隐藏层得到的中间向量再乘以输出权重矩阵W`,再经过softmax得到预测单词的。如上例所述,预测⼀个中⼼词(相当于⼀个样本)的计算量为8N V=16000000,⼜由于输出权重矩阵不是共享的,每个中⼼词均有⼀个特定的输出权重矩阵,这对于内存的占⽤是⼗分巨⼤的。但是在word2vec中,投影层得到的中间向量是通过层级softmax(Hierarchical Softmax)或者是负采样(negative sampling)的⽅式得到预测词极其概率的。这⼤⼤减少了这⼀步骤的计算量和所需内存。
由于层级softmax和负采样⽐较复杂,所以需要单独来讲。
⾸先来看看层级softmax,传统的神经⽹络模型在输出层使⽤的可以认为是单层的softmax,单层softmax形象直观,便于理解,在向量进⾏softmax转换后,只需要选择概率值最⼤的单词作为中⼼词的预测词即可,但是上⽂也提到这将会带来巨量的计算。所以我们将单层softmax进⾏改进得到层级softmax。⽽说到层级softmax,就不得不提到哈夫曼树(Huffman tree,也称霍夫曼树),哈夫曼树是带权路径长度最短的⼆叉树,特点是权值较⼤的结点离根较近。有些⽂章认为哈夫曼树就是层级softmax,
个⼈不是很赞同。我个⼈的理解是层级softmax这种⽅法是需要哈夫曼树这种⽅式来实现的,也就是说层级softmax是⽬的,⽽哈夫曼树只是实现⽬的的途径⽽已。
好了,下⾯我们来看看哈夫曼树的构建。哈夫曼树的构建过程如下:
输⼊:权值为(w1,w2,…wn)的n个节点
输出:对应的哈夫曼树
1)将(w1,w2,…wn)看做是有n棵树的森林,每个树仅有⼀个节点。
2)在森林中选择根节点权值最⼩的两棵树进⾏合并,得到⼀个新的树,这两颗树分布作为新树的左右⼦树。新树的根节点权重为左右⼦树的根节点权重之和。
制作u盘启动盘
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合并,得到新⼦树,依次类推,最终得到下⾯的哈夫曼树。