Word2Vec原理详解

1. 词嵌入(word2vec)

自然语言是一套用来表达含义的复杂系统。在这套系统中,词是表义的基本单元。顾名思义,词向量是用来表示词的向量,也可被认为是词的特征向量或表征。把词映射为实数域向量的技术也叫词嵌入(word embedding)。近年来,词嵌入已逐渐成为自然语言处理的基础知识。

2. 为何不采用one-hot向量

  • 如何使用one-hot
    • 假设词典中不同词的数量(词典大小)为,每个词可以和从到的连续整数值索引一一对应。假设一个字符的索引是整数,为了得到该词的one-hot向量表示,我们创建一个全的长为的向量,并将其第位设成。这样一来,每个词就表示成了一个长度为的向量,可以直接被神经网络使用。
  • 存在的问题
    • 由于任何两个不同词的one-hot向量的余弦相似度都为,故其无法准确表达不同词之间的相似度
  • 解决策略
    • 词嵌入:将每个词表示成一个定长的向量,并使得这些向量能较好地表达不同词之间的相似和类比关系。
      • 跳字模型(skip-gram):通过中心词来推断上下文一定窗口内的单词
      • 连续词袋模型(continuous bag of words, CBOW):通过上下文来推断中心词

3. 跳字模型 skip-gram

跳字模型假设基于某个词来生成它在文本序列周围的词。举个例子,假设文本序列是“the” “man” “loves” “his” “son”。以“loves”作为中心词,设背景窗口大小为2。如图1所示,跳字模型所关心的是,给定中心词“loves”,生成与它距离不超过2个词的背景词“the” “man” “his” “son”的条件概率,即

假设给定中心词的情况下,背景词的生成是相互独立的,那么上式可以改写成

图1:跳字模型关心给定中心词生成背景词的条件概率

3.1 模型输入 one-hot

虽然开篇说了one-hot不行,但是我们不要忽略一个事实,计算机没办法识别“字符”,所有的数据必须转化成二进制的编码形式。

3.2 数学原理


大家已经注意到,我们已经到了Hidden Layer到Output Layer这一层了,简单来看就是隐藏层和输出层进行全连接,然后是一个softmax,输出概率。过程比较简单,一个Forward Propagation,一个Backward Propagation。

在跳字模型中,每个词被表示成两个维向量,用来计算条件概率。假设这个词在词典中索引为,当它为中心词时向量表示为,而为背景词时向量表示为。设中心词在词典中索引为,背景词,在词典中索引为,给定中心词生成背景词的条件概率可以通过对向量内积做softmax运算而得到:

其中词典索引集。假设给定一个长度为的文本序列,设时间步的词为。假设给定中心词的情况下背景词的生成相互独立,当背景窗口大小为时,跳字模型的似然函数即给定任一中心词生成所有背景词的概率

这里小于1和大于的时间步可以忽略。
这样就可以计算出每个中心词推断背景词的概率,而我们在输入的时候给出了背景词的向量,此时只需要最大化背景词的输出概率即可。 基于这样的想法,我们会想到极大化似然估计的方式。但是一个函数的最大值往往不容易计算,因此,我们可以通过对函数进行变换,从而改变函数的增减性,以便优化。这等价于最小化以下损失函数:

最小化损失函数,我们最容易想到的就是梯度下降法。在使用梯度下降法之前,我们要把我们的损失函数定义出来,毕竟上面的式子是一个概率,下面把softmax的计算结果带入得到:

损失函数已经得到了,我们的目标就是最小化它,优化它之前我们要搞清楚我们的参数是谁?每错,我们的参数是中心词和背景词,那对于这样的一个函数显然是非凸函数,因此,我们要做一个假设,假设在对中心词权重更新时,背景词的权重是固定的,然后在以同样的方式来更新背景词的权重。
\begin{align} \frac{\partial {\rm log} P(w_o|w_c)}{\partial \boldsymbol v_c} &= \boldsymbol u_o - \frac{\sum_{j \in \mathcal{V}} {\rm exp}(\boldsymbol u_j^{\top} \boldsymbol v_c) u_j}{\sum_{i \in \mathcal{V}} {\rm exp}(\boldsymbol u_i^{\top} \boldsymbol v_c)} \\ &= \boldsymbol u_o - \sum_{j \in \mathcal{V}} \Bigg( \frac{ {\rm exp}(\boldsymbol u_j^{\top} \boldsymbol v_c)}{\sum_{i \in \mathcal{V}} {\rm exp}(\boldsymbol u_i^{\top} \boldsymbol v_c)} \Bigg) \boldsymbol u_j \\ &= \boldsymbol u_o - \sum_{j \in \mathcal{V}} P(w_j|w_c) \boldsymbol u_j \end{align}
这里就计算出来了中心词的梯度,可以根据这个梯度进行迭代更新。对于背景词的更新是同样的方法,
\begin{align} \frac{\partial {\rm log} P(w_o|w_c)}{\partial \boldsymbol u_o} &= \boldsymbol v_c - \frac{{\rm exp}(\boldsymbol u_o^{\top} \boldsymbol v_c)}{\sum_{i \in \mathcal{V}} {\rm exp}(\boldsymbol u_i^{\top} \boldsymbol v_c)} \boldsymbol v_c \\ &= \boldsymbol v_c - P(w_o|w_c) \boldsymbol v_c \\ &=(1 - P(w_o|w_c)) \boldsymbol v_c \end{align}
当时,即通过中心词我们可以正确预测上下文词时,不需要调整,反之,则相应调整。
但是要注意背景词的个数不是唯一的,所以更新的时候要逐个更新,幅图辅助理解。


训练结束后,对于词典中的任一索引为iii的词,我们均得到该词作为中心词和背景词的两组词向量和。
这里存在几个问题:

  • 在词向量映射过程中需要计算大量的乘法运算,有没有什么方法减少运算量?
    • 可以通过查表(Lookup Table)方式,因为计算出来的这组向量,和单词在one-hot编码表的位置是有关系的!举个例子,如果单词出现的位置column=3,那么对应的就会选中权重矩阵的Index=3的列。
  • 一个是在词典中所有的词都有机会被当做是“中心词”和“背景词”,那么在更新的时候,都会被更新一遍,这种时候该怎么确定一个词的向量到底该怎么选择呢?
    • 在自然语言处理应用中,一般使用跳字模型的中心词向量作为词的表征向量。
  • 从刚刚最终的梯度公式中,存在着一个参数,我们知道这个参数代表的含义是词典中单词的个数,通常这个个数会非常大,这时候我们在进行迭代的时候对系统消耗也是巨大的,因为每走一步就要对所有的单词进行一次矩阵运算。这种时候该如何进行优化呢?
    • 负采样 Negative Sampling
    • 层级softmax Hierarchical Softmax

4. 连续词袋模型 CBOW

连续词袋模型与跳字模型类似。与跳字模型最大的不同在于,连续词袋模型假设基于某中心词在文本序列前后的背景词来生成中心词。在同样的文本序列“the” “man” “loves” “his” “son”里,以“loves”作为中心词,且背景窗口大小为2时,连续词袋模型关心的是,给定背景词“the” “man” “his” “son”生成中心词“loves”的条件概率(如图2所示),也就是

图2:连续词袋模型关心给定背景词生成中心词的条件概率

因为连续词袋模型的背景词有多个,我们将这些背景词向量取平均,然后使用和跳字模型一样的方法来计算条件概率。设和分别表示词典中索引为的词作为背景词和中心词的向量(注意符号的含义与跳字模型中的相反,假设输入向量为,输出向量为)。设中心词在词典中索引为,背景词在词典中索引为,那么给定背景词生成中心词的条件概率

P(w_c \mid w_{o_1}, \ldots, w_{o_{2m}}) = \frac{\text{exp}\left(\frac{1}{2m}\boldsymbol{u}_c^\top (\boldsymbol{v}_{o_1} + \ldots + \boldsymbol{v}_{o_{2m}}) \right)}{ \sum_{i \in \mathcal{V}} \text{exp}\left(\frac{1}{2m}\boldsymbol{u}_i^\top (\boldsymbol{v}_{o_1} + \ldots + \boldsymbol{v}_{o_{2m}}) \right)}

为了让符号更加简单,我们记,且,那么上式可以简写成

给定一个长度为的文本序列,设时间步t的词为,背景窗口大小为。连续词袋模型的似然函数是由背景词生成任一中心词的概率

训练连续词袋模型同训练跳字模型基本一致。连续词袋模型的最大似然估计等价于最小化损失函数

注意到

通过微分,我们可以计算出上式中条件概率的对数有关任一背景词向量的梯度
\begin{align} \frac{\partial \log\, P(w_c \mid \mathcal{W}_o)}{\partial \boldsymbol{v}_{o_i}} &= \frac{1}{2m} \left(\boldsymbol{u}_c - \sum_{j \in \mathcal{V}} \frac{\exp(\boldsymbol{u}_j^\top \bar{\boldsymbol{v}}_o)\boldsymbol{u}_j}{ \sum_{i \in \mathcal{V}} \text{exp}(\boldsymbol{u}_i^\top \bar{\boldsymbol{v}}_o)} \right) \\ &= \frac{1}{2m}\left(\boldsymbol{u}_c - \sum_{j \in \mathcal{V}} P(w_j \mid \mathcal{W}_o) \boldsymbol{u}_j \right) \end{align}

中心词的梯度同理可得,
\begin{align} \frac{\partial \log\, P(w_c \mid \mathcal{W}_o)}{\partial \boldsymbol{u}_c} &=\bar{\boldsymbol{v}}_o - \frac{\exp (\boldsymbol{u}_c^\top \bar{\boldsymbol{v}}_o)}{\sum_{i \in \mathcal{V}} \exp \left( \boldsymbol{u}_i^\top \bar{\boldsymbol{v}}_o \right)} \bar{\boldsymbol{v}}_o \\ &= \bar{\boldsymbol{v}}_o - P(w_c \mid \mathcal{W}_o) \bar{\boldsymbol{v}}_o \\ &= \left( 1- P(w_c \mid \mathcal{W}_o) \right) \bar{\boldsymbol{v}}_o \end{align}

同跳字模型不一样的一点在于,我们一般使用连续词袋模型的背景词向量作为词的表征向量。

参考

  1. NLP之---word2vec算法skip-gram原理详解
  2. Word2Vec Tutorial - The Skip-Gram Model
  3. 动手学深度学习

你可能感兴趣的:(Word2Vec原理详解)