Word2vec - 最经典的词嵌入学习算法

如果想要开始研究基于深度学习的自然语言处理,你很难逃开 Word2vec 这一最为经典的词嵌入学习算法。然而,想要透彻理解 Word2vec 又并非易事。因此,我写这篇博文,力图叙述清楚 Word2vec 的原理,以对学到的知识做一个梳理。

为什么要使用 Word2vec?

One-Hot Representation

自然语言处理(NLP)相关任务中,要将自然语言交给机器学习中的算法来处理,通常需要首先将语言数学化,因为机器没法理解自然语言。作为语言最细粒度的单位,词语被转换为数值形式的产物通常为词向量,顾名思义就是把一个词表示成一个向量。

最简单的词向量方式是 One-Hot Representation。简单来说,就是每个词向量的长度为词典大小,向量的分量只有一个 1,其他全为 0, 1 的位置对应该词在词典中的位置。这样的做法非常简单,也容易实现,只需要用哈希表给词典中的每个词语分配一个编号即可。NLP 领域的很多主流任务完全可以通过这种简洁的表示方法,配合其他的算法来完成。

但是,One-Hot Representation 有两个不可忽视的缺点:

  1. One-Hot Representation 的词向量是高维稀疏的。当数据的维度越高,要找到最优解甚至达到稍低维度时模型的同等表现,所需要的数据越多,而且呈指数型增长。此问题被称为“维度灾难”。
  2. One-Hot Representation 无法体现词语间的相似度。因为每个单词都背表示为表示为完全独立的个体,不同词向量都是正交的。因此,词向量缺少语法和语义的信息。

Distributed Representation

因此,One-Hot Representation 已经逐渐不能满足需求,人们寻求在词向量表示上的新方法。之后,Hinton 在 1986 年提出了 Distributed Representation,基本思想是将每个词表达成 n 维稠密、连续的实数向量,每个分量通过训练得到。例如:[0.792, −0.177, −0.107, 0.109, −0.542, ...]

这样,两个问题都迎刃而解:由于词向量维度较低,“维度灾难”难以出现;而两个词语义、语法上的相似性也可以通过计算两个词之间的“距离”来表示,因为所有词向量一起可以组成一个词向量空间,只要计算欧式距离或者 cos 距离即可。

语言模型

接下来,我们介绍语言模型。在统计自然语言处理中,语言模型(Language Model)指的是计算一个句子是否是自然语言的概率模型,通常用于在机器翻译、语音识别等任务得到若干候选答案后挑选一个比较正常的结果。例如,我们有 Bigram 模型,通过前一个词语已确定、后一个词语出现的概率来计算整句话遵循自然语言规则的概率:

$$P(w_1, w_2, …, w_n) = \prod^n_{i=2}P(w_i | w_{i-1})$$

大部分的有监督机器学习模型,都可以归结为f(x)->y。将语言模型看作fx为一个句子里的一个词语,那么y就是这个词语的上下文词语。根据语言学中一个非常重要的假设——分布相似性,类似的词有相似的语境,即其上下文词语y应该相似。两个语义相似的词对应的向量也是相似的,具体反映在夹角或距离上。

Word2vec 就是源于以上思想。通过词语及其上下文,我们可以训练出一个模型f。在 Word2vec 中,我们关心神经网络训练完后得到的权重(即模型参数),这些向量化表示的权重就是我们需要的词向量,或者也被称为词嵌入(Word Embeddings)。当然,得到词嵌入的不止 Word2vec 一种算法,但 Word2vec 是提出时间较早并且比较经典的一种,因此值得花时间去透彻理解。

Word2vec 的两种语言模型

Word2vec 是一种基于迭代的词嵌入学习算法,其包含两种语言模型:

  • Skip-gram:根据词预测目标上下文
  • Continuous Bag of Words (CBOW):根据上下文预测目标词

Skip-gram

在 Skip-gram 中,我们用当前词x来预测上下文y。一般的数学模型只接受数值型输入,因此x的原始输入形式就使用前文提到的 One-Hot Representation,每个词语都有自己的唯一表示。y使用的就是词典中每个词是正确上下文的概率。

y只取x的下一个词时,网络结构如下图:

设词典中词语数量为V,隐藏层节点数为N。当模型训练完后,当我们输入一个 One-Hot Representation 的向量作为x时,则在输入层到隐藏层的权重里,只有对应 1 这个位置的权重被激活,这些权重的个数为N,跟隐藏层节点数是一致的。由于每个词语的 One-Hot Representation 里 1 的位置是不同的,因此,对应 1 这个位置的权重组成的向量就可以作为该词的唯一表示。

同理,通过训练完后的隐藏层到输出层的权重同样可以得到另一种词向量。两种词向量分别称为“输入向量”和“输出向量”,一般我们使用“输入向量”。

由于N通常要远远小于V,因此我们通过 Word2vec 完成了对词向量的降维,以避免“维度灾难”的出现。

另外,隐藏层的激活函数其实是线性的,相当于没做任何处理。这是 Word2vec 相对于之前的语言模型的简化之处。在用反向传播算法训练神经网络时,本质上是链式求导

更一般的情形下,上下文y应该有多个词,因此网络结构扩展如下图:

CBOW

在 CBOW 中,我们用上下文预测当前词。其他与 Skip-gram 相似,因此有网络结构如下图:

具体步骤如下:

  1. 生成所有的 One-Hot Representation;
  2. 根据上下文得到相对应的词向量;
  3. 将所有的上下文词向量求和后做一个平均,作为隐藏层的向量;
  4. 在隐藏层向量和输出向量相乘后,通过 Softmax 计算预测概率;
  5. 通过反向传播更新参数。

损失函数为:

$$H(\hat y, y) = -\sum^V_{j=1}y_jlog(\hat y_j)$$

训练技巧

Word2vec 本质上是一个语言模型,它的输出节点数是 V 个,对应了 V 个词语,本质上是一个多分类问题,但实际当中,词语的个数非常非常多,会给计算造成很大困难,所以需要用技巧来加速训练。对于 Word2vec,提出了两种训练技巧:

  • 负采样(Negative Sampling):采样负例。本质是预测总体类别的一个子集。
  • 分级的 Softmax(Hierarchical Softmax):用一种有效的树结构来计算所有词汇的概率。本质是把 N 分类问题变成 log(N) 次二分类。

因其不是 Word2vec 的精髓,在这篇文章中,暂时不对这两种训练技巧做过多的介绍了。有兴趣的同学可以在参考资料中选择阅读,或者等待下一篇文章。

如何使用 Word2Vec?

gensim 是一款开源的第三方 Python 工具包,包含 Word2vec 在内的多种主题模型算法。这里有一个简单的 demo来演示如何使用 gensim 中的 Word2vec。你也可以查阅 gensim 的官方文档来学习更多的用法。

结语

Word2vec 作为最经典的词嵌入学习算法,让词嵌入开始广泛被使用。然而,Word2vec 学习的向量其实和真正的语义还有差距,因为其学到的更多是具备相似上下文的词语,例如表示“good”和“bad”的词嵌入相似度就非常高。因此,后续又有一些新的词嵌入学习算法被提出并大量使用,其中最火的就是 Glove。

到目前为止,这篇博文介绍了为什么要使用 Word2vec 的产物,以及 Word2vec 的算法本质。我的目标是能够覆盖参考资料中的《N问word2vec》中的所有问题,因此后续学习还会更新此文来添加公式推导、训练技巧介绍等内容,或者写下一篇文章。

参考资料

写作参考

补充阅读