虽然word2vec常被当作无监督,但是其训练过程跟有监督基本差不多,原始的word2vec暂时不考虑负采样和huffman tree,其损失函数就是多元交叉熵:
多元交叉熵的公式:
以传统机器学习来说,这里的Zj就是某个类别的预测概率,yj=0或者1,我们假设有3个类别,模型对样本A的预测结果为[0.2,0.5,0.3],A的实际标签为[0,1,0],则仅仅计算中间为1的那一项(其实就是样本对应的真实类别单独计算一下损失,每一个样本计算的过程中对于单输出问题都是计算一次就行)
则
以cbow为例,
简单理解就是求平均(也可以是求和,gensim里的设计是两种方式都进行了实现)之后的结果【0.23,0.03,0.62,0.12......】经过输出层映射为一个v维的一维矩阵(v是词的数量)要和真实的标签【0,0,0,1,0,0,0.。。】尽量接近;这里ui表示的是输出层,vc表示的是平均之后的向量,他们的乘积加上softmax函数就是word2vec的模型的最终预测结果;
因此可以认为是一个超级多分类模型,类别的数量就是词(去重)的数量;
app2vec的加权体现在这个地方,根据不同的不同的app的gap来对不同的样本进行加权,具体可见我写的app2vec的论文分析在自然语言处理的专栏里;
然后是采用了huffman tree对其进行优化(类别太多用原始的多元交叉熵算死)
huffman tree是一种非线性的数据结构,其建树流程如下:
具体的例子如下:
生成了huffman tree,我们就可以进行愉快的huffman 编码了:
下面我们就针对cbow和skip gram的huffman编码模式进行解释:
可以看到,加入了huffman tree之后,原来的输出层由线性结构变成了树形结构,本来输出层是一个V行的输出(V代表词库的词的总数量),现在变成了一个树型结构,这个树的所有叶子节点的数量为V,即一个节点代表了一个词;那么为什么要这么设计呢?
以一个实际的例子来进行说明,假设此时我们的中心词是足球,那么从projection layer出来我们要经过四次分支才能到达上图中足球所对应的叶子节点,如上图,原始的huffman tree是将左枝叶定义为1,右枝定义为0,而word2vec将左枝定义为0,右枝定义为1,因此在w2v中,分到左枝就当作负类,分到右枝就当作正类,这里每一个节点都对应一个sigmoid变换;即,当Xw进入左枝的时候,则其被分为负类,对应的概率值为:
其中
表示sigmoid函数,Xw表示windows中的词的embedding的求和(或求平均)的结果向量,
表示当前节点对应的待训练的参数(没错,每一个节点都有一个w维的待训练参数(w表示的是embedding的维度大小)),反之如果被分为正类,则其对应的概率值为:
那么
这里的context指的是足球对应的windows内的上下文;
最终其目标函数的形式为:
w属于C表示对词表C中的每一个词w进行一次后面的运算;
lw表示词在huffman tree中对应的路径,那么Huffman tree(或者说分层softmax或者hierarchical softmax)是怎么起到优化性能的作用呢?
还是以上面的这个足球的例子为例,假设我们不适用huffman tree而是使用了原始的softmax:
则对应的“足球”作为中心词的单个样本其损失函数的计算过程中,分母部分要进行W次的累加(这里的W表示词库中词的数量),这还仅仅是一个词作为中心词的结果,可想而知,一轮训练下来非常的耗费时间,但是如果使用huffman tree,如上图,我们对于足球的计算只需要:
进行4次的sigmoid的计算,大大降低了计算的复杂度;
这里也可以很简单的实现样本加权的功能,在第一个求和符号后面添加一个权重函数就可以了;
而对于skip gram的分层softmax其结构如图:
对应的目标函数为:
可以看到,还是一个多输出的结构,在目标函数上的体现就是对多个输出对应的目标函数进行累加也就是这一项:
剩下的优化就交给梯度下降法和自动梯度求导的工具上吧~
接下来就介绍一个非常重要的优化手段,也是目前非常常用的一个构造伪正负样本的方法,negtive sampling(简称neg)是nce(noice constractive estimation)的简化版本,关于nce的研究可见:
磊爷:[译] Noise Contrastive Estimationzhuanlan.zhihu.com
这里暂时不那么深入去研究了;
关于负采样:
word2vec原理(三) 基于Negative Sampling的模型www.cnblogs.com
刘大佬的blog写的很通俗易懂;
比如我们有一个训练样本,中心词是w,它周围上下文共有2c个词,记为context(w)。由于这个中心词w,的确和context(w)在实际语料中真实存在,因此它是一个真实的正例。通过Negative Sampling采样,我们得到neg个和w不同的中心词wi,i=1,2,..neg,这样context(w)和wi们 就组成了neg个并不真实存在的负例。利用这一个正例和neg个负例,我们进行二元逻辑回归,得到负采样对应每个词wi对应的模型参数θi和每个词的词向量。
从上面的描述可以看出,Negative Sampling由于没有采用霍夫曼树,每次只是通过采样neg个不同的中心词做负例,就可以训练模型,因此整个过程要比Hierarchical Softmax简单。
这个思路其实是非常灵活的,它可以本身无监督的问题转化为类似有监督的问题,这种方法在很多地方都有其应用;
当然,这里的负采样不是简单的随机采样,word2vec采样的方法并不复杂,如果词汇表的大小为V,那么我们就将一段长度为1的线段分成V份,每份对应词汇表中的一个词。当然每个词对应的线段长度是不一样的,高频词对应的线段长,低频词对应的线段短。每个词w的线段长度由下式决定:
在word2vec中,分子和分母都取了3/4次幂如下:
(作者实验测试的效果)
在采样前,我们将这段长度为1的线段划分成MM等份,这里M>>V,这样可以保证每个词对应的线段都会划分成对应的小块。而M份中的每一份都会落在某一个词对应的线段上。在采样的时候,我们只需要从M个位置中采样出neg个位置就行,此时采样到的每一个位置对应到的线段所属的词就是我们的负例词。在word2vec中,M取值默认为10^8;