我所理解的word2vec

时间:2021-12-07 01:42:48

建议前往个人博客:http://yobobobo001.github.io/2016/05/26/%E6%88%91%E6%89%80%E7%90%86%E8%A7%A3%E7%9A%84word2vec/
更好阅读显示

最近开始加固NLP的基础技能,首当其冲的是word2vec,对word2vec的印象一直停留在:学出来的向量隐含了词语的信息,向量之间的夹角可以表示词语之间的相关性。现在,一起来探讨下word2vec的原理以及实现细节。这次把paper细读了一遍,实现了其中的Huffman编码,以及把相应的网络结构在框架中实现了一遍。本文主要参照Mikolov的word2vec论文[1]以及公开的源码实现。

文本在计算机中的表示方式

文本不像天气这种形象的特征值有具体的数值,当模型需要用到文本的时候,如何把文本作为特征放入模型中呢?当应用场景只有文本的时候,比如搜索引擎的排序机制,搜索引擎下方的相关推荐等,这个时候应该如何做推荐呢?首先,得把文本表示在计算机里面。

One-hot

最初的时候,是把词表里面的每个单词挨个编号,每个词是一个维度为词表大小的向量,除了改词对应编号上的位置为1之外,其他位置都为0。比如有3个词a,b,c。这三个词对应的编号为0,1,2,则b的向量表示为(1,0,0)。这种表示方法简单粗暴,容易实现,可是这种表达方式除了表示一个词之外没有任何的含义,因为把词的编号换一种编号方式也是等价的。One-hot仅仅是一个词的代号,词与词(向量与向量)之间毫无关联。

Distributed Representation

Distributed Representation的想法是用一组实数向量表示词,而实数向量之间的关系可以代表词语之间的相似度,比如向量的夹角cosine。这种方法相较于One-hot方式另一个区别是维数下降极多,对于一个100W的词表,我们可以用100维的实数向量来表示一个词,而One-hot得要100W维。

如何训练词向量

一般而言,一篇文章都会有个主题,比如海贼王的文章里面可能通篇都出现海贼王相关的词语,如路飞,索隆等,这些词的语义肯定比不同文章的更相近,所以作者提出了以下两种模型,把相近的单词放进模型里面训练。

cbow

我所理解的word2vec

把中间的词单独拎出来,让周围的词去预测这个词的概率。

  1. 每个单词先映射到公用词表中(大矩阵)一列对应的向量
  2. 把向量相加
  3. 把这个向量经过一个softmax得出预测相应单词的概率。

skip-gram

我所理解的word2vec

skip-gram则是输入一个单词,把词周围的其他词作为要预测的单词。

训练的细节

softmax层加速

两种网络结构的最后一层都是一个大的softmax,起到对于每个词的预测概率归一化作用,可是在实际训练过程中每次迭代都要通过softmax计算每个词的概率是相当耗费时间的,能否优化这个呢?这个问题早在03年Bengio提出的语言模型[2]也遇到,后来他们提出了Hierarchical Softmax[3]来加速。

为什么要归一化

在每次迭代中把要预测的词相关权重增加,通过归一化,同时把其他的词相关权重减少。这个不难理解,总的预测概率和是1,把其中某一个词的概率增加就意味着把其他词的预测概率打压。能不能只增加其中某个词的概率呢?可以,但是收敛很慢。

Hierarchical Softmax 是如何提速的?

Hierarchical Softmax 相对于原来的softmax是把一个多分类问题转换成了多个二分类问题。通俗地说,现在仓管人员要去仓库找一个配件,按照softmax策略是把仓库里面的配件一个个的过一遍,最后确定下来是哪个,Hierarchical Softmax则是根据预先记录的表知道了要找的配件在第二个房间的第一个货架第二行第一个直接去取的。在上面提到,归一化的作用是把其他词的概率打压,那么能不能把词分好类别直接打压呢?这样就是每次打压一个类别(多个单词),而不用一个个地打压每个单词的相关权重了。原来的softmax是这样的:

我所理解的word2vec

现在我们构建一颗二叉树把所有单词放在叶子节点上:

我所理解的word2vec

现在我们要更新12号节点,沿着二叉树的路径可以看到判断是这样的:是否在1号节点的左儿子里,是否在2号节点的左儿子里,是否在5号节点的左儿子里,是否在9号儿子的左节点里。这就变成了多个二分类问题,作者采用哈弗曼树编码更是把每个单词在树中路径的长度减少到极致,并且等价于原来的softmax,因为整棵树的叶子节点和是归一化的。所以,最终的更新只需要更新一部分的权重即可。注意:最终的节点已经不是表示单词了,而是二叉树上的非叶子节点。

我所理解的word2vec

这样,每个样本迭代在最后的softmax层由原来的O(N)次运算下降到了O(logN)级别,搞过ACM的同学可以意识到这个做法类似线段树的段更新。

negative sampling

不做归一化可是又想降低其他单词的预测概率,该怎么做呢?这就是negative sampling的由来。作者对其他的单词进行负采样以降低其他单词的相关权重,作者认为负采样中单词作为负样本的概率应该和其词频正相关,所以词频越高的越大概率被抽到。这种方案我认为只是一种近似方案,和Hierarchical Softmax 这种等价于原来的softmax是有明显区别的。不过这种方案在低频词上的学习会好一些,主要原因在于负采样更容易抽到其中的高频词。

训练数据的窗口选取策略

从cbow的网络结构可以看出,模型输入的单词数量是不定长的,那在构造训练样本的时候应该如何选取预测单词附近的多少个单词作为输入呢?Mikolov认为离预测单词近的词语比那些远的单词更相关,所以采用了随机窗口大小的方式来选取,每次在区间[1, window]随机一个数值K,然后在预测单词的前后各选取k个单词作为输入。

window是可选参数大小,window增大可以使向量学习更充分,但同时也增加了训练的复杂度。

exp运算打表

计算softmax的时候需要求e的x次方,一轮迭代中指数运算至少需要上亿级别的指数运算,由于sigmod函数是个长“S”型的函数,可以通过对中间部分的x查表来取代多次指数运算。

我所理解的word2vec

降采样

对于语料中的高频词,Mikolov选择对它们进行降采样(sub-samplig),我认为高频词在语料中的出现次数比较多,而且高频词一般而言都不是决定附近词语的词,比如“的”这种停用词。所以对高频词进行降采样既不影响模型效果,又能提升收敛速度,何乐而不为呢?

我所理解的word2vec

低频词的处理

对于训练预料中的低频词,源码中是对这部分进行过滤处理,我认为主要是这部分低频词的数据不充足,模型对于低频词向量训练不充分,学习的向量置信度不高,也会影响其他向量的效果。所以,过滤低频词是一个比较好的选择。

学习率调整策略

学习率过大导致模型不收敛,学习率过小则会陷入局部最优,Mikolov在实现过程中采取了学习率随着实际训练的语料增加而减少。

我所理解的word2vec

学习率的动态调整极为重要,在搭建网络训练过程中,跑了15轮的迭代相应的观察指标都没有降下来,我反反复复检查了数据生成以及网络实现都没有发现问题,断断续续debug了两天之后才意识到根本不是实现上的问题,而是学习率没有控制好,模型没有收敛。

caffe等框架中的实现方法

这段主要是在框架中实现源码的细节,如对框架代码不熟悉者可略过

网络结构:

我所理解的word2vec

在Hierarchical Softmax添加了全连接矩阵,每次需要做二分类(logistics regression)的时候就把相应列中的参数抠出来组成一个小矩阵乘以输入的x向量即可,相应的bias偏置项也一样,梯度回传的时候则根据每个二分类的loss分别回传,记得对应之前抠出来的列向量。

我所理解的word2vec

相关指标以及效果

训练指标

如何评估模型是否符合预期地正在训练呢?最大似然,如果模型朝着正确的方向收敛,相应的单词出现时其预测概率会增大。所以,通过累加每个单词的最大似然预测求均值可以看出模型是否如预期一样收敛。贴一个自己训练过程中的最大似然(取反)

我所理解的word2vec

评估指标

原文中作者主要是模型学到的向量所包含的线性代数关系作为评估指标的,即判断类似

我所理解的word2vec

这种关系的准确率,我查了不少资料,发现很少单独针对词向量的模型,更多的是把训练出来的词向量放到实际应用场景中看是否有所提升,如语音识别,机器翻译等。

实际效果

用了wiki的数据进行训练:

我所理解的word2vec

引用

[1]:Tomas Mikolov. Ilya Sutskever(2013) Distributed Representations of Words and Phrasesand their Compositionality

[2]:Y Bengio. Réjean Ducharme. Pascal Vincent. (2003) A Neural Probabilistic Language Model

[3]:Frederic Morin. Yoshua Bengio(2003)Hierarchical Probabilistic Neural Network Language Model

[4]:peghoty(2014) word2vec中的数学