自然语言是一套用来表达含义的复杂系统。在这套系统中,词是表义的基本单元。在机器学习中,如何使用向量表示词?
顾名思义,词向量是用来表示词的向量,通常也被认为是词的特征向量。近年来,词向量已逐渐成为自然语言处理的基础知识。
为何不采用one-hot向量
我们在循环神经网络中介绍过one-hot向量来表示词。假设词典中不同词的数量为NN,每个词可以和从0到N−1N−1的连续整数一一对应。假设一个词的相应整数表示为ii,为了得到该词的one-hot向量表示,我们创建一个全0的长为NN的向量,并将其第ii位设成1。
然而,使用one-hot词向量并不是一个好选择。一个主要的原因是,one-hot词向量无法表达不同词之间的相似度。例如,任何一对词的one-hot向量的余弦相似度都为0。
word2vec
2013年,Google团队发表了word2vec工具。word2vec工具主要包含两个模型:跳字模型(skip-gram)和连续词袋模型(continuous bag of words,简称CBOW),以及两种高效训练的方法:负采样(negative sampling)和层序softmax(hierarchical softmax)。值得一提的是,word2vec词向量可以较好地表达不同词之间的相似和类比关系。
word2vec自提出后被广泛应用在自然语言处理任务中。它的模型和训练方法也启发了很多后续的词向量模型。本节将重点介绍word2vec的模型和训练方法。
模型
跳字模型
在跳字模型中,我们用一个词来预测它在文本序列周围的词。例如,给定文本序列"the", "man", "hit", "his", 和"son",跳字模型所关心的是,给定"hit",生成它邻近词“the”, "man", "his", 和"son"的概率。在这个例子中,"hit"叫中心词,“the”, "man", "his", 和"son"叫背景词。由于"hit"只生成与它距离不超过2的背景词,该时间窗口的大小为2。
我们来描述一下跳字模型。
假设词典大小为|||V|,我们将词典中的每个词与从0到||−1|V|−1的整数一一对应:词典索引集={0,1,…,||−1}V={0,1,…,|V|−1}。一个词在该词典中所对应的整数称为词的索引。给定一个长度为TT的文本序列中,tt时刻的词为w(t)w(t)。当时间窗口大小为mm时,跳字模型需要最大化给定任一中心词生成背景词的概率:
∏t=1T∏−m≤j≤m,j≠0ℙ(w(t+j)∣w(t))∏t=1T∏−m≤j≤m,j≠0P(w(t+j)∣w(t))
上式的最大似然估计与最小化以下损失函数等价
−1T∑t=1T∑−m≤j≤m,j≠0logℙ(w(t+j)∣w(t))−1T∑t=1T∑−m≤j≤m,j≠0logP(w(t+j)∣w(t))
我们可以用vv和uu分别代表中心词和背景词的向量。换言之,对于词典中一个索引为ii的词,它在作为中心词和背景词时的向量表示分别是vivi和uiui。而词典中所有词的这两种向量正是跳字模型所要学习的模型参数。为了将模型参数植入损失函数,我们需要使用模型参数表达损失函数中的中心词生成背景词的概率。假设中心词生成各个背景词的概率是相互独立的。给定中心词wcwc在词典中索引为cc,背景词wowo在词典中索引为oo,损失函数中的中心词生成背景词的概率可以使用softmax函数定义为
ℙ(wo∣wc)=exp(u⊤ovc)∑i∈exp(u⊤ivc)P(wo∣wc)=exp(uo⊤vc)∑i∈Vexp(ui⊤vc)
当序列长度TT较大时,我们通常随机采样一个较小的子序列来计算损失函数并使用随机梯度下降优化该损失函数。通过微分,我们可以计算出上式生成概率的对数关于中心词向量vcvc的梯度为:
∂logℙ(wo∣wc)∂vc=uo−∑j∈exp(u⊤jvc)∑i∈exp(u⊤ivc)uj∂logP(wo∣wc)∂vc=uo−∑j∈Vexp(uj⊤vc)∑i∈Vexp(ui⊤vc)uj
而上式与下式等价:
∂logℙ(wo∣wc)∂vc=uo−∑j∈ℙ(wj∣wc)uj∂logP(wo∣wc)∂vc=uo−∑j∈VP(wj∣wc)uj
通过上面计算得到梯度后,我们可以使用随机梯度下降来不断迭代模型参数vcvc。其他模型参数uouo的迭代方式同理可得。最终,对于词典中的任一索引为ii的词,我们均得到该词作为中心词和背景词的两组词向量vivi和uiui。
连续词袋模型
连续词袋模型与跳字模型类似。与跳字模型最大的不同是,连续词袋模型中用一个中心词在文本序列周围的词来预测该中心词。例如,给定文本序列"the", "man", "hit", "his", 和"son",连续词袋模型所关心的是,邻近词“the”, "man", "his", 和"son"一起生成中心词"hit"的概率。
假设词典大小为|||V|,我们将词典中的每个词与从0到||−1|V|−1的整数一一对应:词典索引集={0,1,…,||−1}V={0,1,…,|V|−1}。一个词在该词典中所对应的整数称为词的索引。给定一个长度为TT的文本序列中,tt时刻的词为w(t)w(t)。当时间窗口大小为mm时,连续词袋模型需要最大化由背景词生成任一中心词的概率:
∏t=1Tℙ(w(t)∣w(t−m),…,w(t−1),w(t+1),…,w(t+m))∏t=1TP(w(t)∣w(t−m),…,w(t−1),w(t+1),…,w(t+m))
上式的最大似然估计与最小化以下损失函数等价
−∑t=1Tlogℙ(w(t)∣w(t−m),…,w(t−1),w(t+1),…,w(t+m))−∑t=1TlogP(w(t)∣w(t−m),…,w(t−1),w(t+1),…,w(t+m))
我们可以用vv和uu分别代表背景词和中心词的向量(注意符号和跳字模型中的不同)。换言之,对于词典中一个索引为ii的词,它在作为背景词和中心词时的向量表示分别是vivi和uiui。而词典中所有词的这两种向量正是连续词袋模型所要学习的模型参数。为了将模型参数植入损失函数,我们需要使用模型参数表达损失函数中的中心词生成背景词的概率。给定中心词wcwc在词典中索引为cc,背景词wo1,…,wo2mwo1,…,wo2m在词典中索引为o1,…,o2mo1,…,o2m,损失函数中的背景词生成中心词的概率可以使用softmax函数定义为
ℙ(wc∣wo1,…,wo2m)=exp[u⊤c(vo1+…+vo2m)/(2m)]∑i∈exp[u⊤i(vo1+…+vo2m)/(2m)]P(wc∣wo1,…,wo2m)=exp[uc⊤(vo1+…+vo2m)/(2m)]∑i∈Vexp[ui⊤(vo1+…+vo2m)/(2m)]
当序列长度TT较大时,我们通常随机采样一个较小的子序列来计算损失函数并使用随机梯度下降优化该损失函数。通过微分,我们可以计算出上式生成概率的对数关于任一背景词向量voivoi(i=1,…,2mi=1,…,2m)的梯度为:
∂logℙ(wc∣wo1,…,wo2m)∂voi=12m(uc−∑j∈exp(u⊤jvc)∑i∈exp(u⊤ivc)uj)∂logP(wc∣wo1,…,wo2m)∂voi=12m(uc−∑j∈Vexp(uj⊤vc)∑i∈Vexp(ui⊤vc)uj)
而上式与下式等价:
∂logℙ(wc∣wo1,…,wo2m)∂voi=12m(uc−∑j∈ℙ(wj∣wc)uj)∂logP(wc∣wo1,…,wo2m)∂voi=12m(uc−∑j∈VP(wj∣wc)uj)
通过上面计算得到梯度后,我们可以使用随机梯度下降来不断迭代各个模型参数voivoi(i=1,…,2mi=1,…,2m)。其他模型参数ucuc的迭代方式同理可得。最终,对于词典中的任一索引为ii的词,我们均得到该词作为背景词和中心词的两组词向量vivi和uiui。
近似训练法
我们可以看到,无论是跳字模型还是连续词袋模型,每一步梯度计算的开销与词典V的大小相关。显然,当词典较大时,例如几十万到上百万,这种训练方法的计算开销会较大。所以,使用上述训练方法在实践中是有难度的。
我们将使用近似的方法来计算这些梯度,从而减小计算开销。常用的近似训练法包括负采样和层序softmax。
负采样
我们以跳字模型为例讨论负采样。
词典V大小之所以会在目标函数中出现,是因为中心词wcwc生成背景词wowo的概率ℙ(wo∣wc)P(wo∣wc)使用了softmax,而softmax正是考虑了背景词可能是词典中的任一词,并体现在softmax的分母上。
我们不妨换个角度,假设中心词wcwc生成背景词wowo由以下相互独立事件联合组成来近似
- 中心词wcwc和背景词wowo同时出现在该训练数据窗口
- 中心词wcwc和第1个噪声词w1w1不同时出现在该训练数据窗口(噪声词w1w1按噪声词分布ℙ(w)P(w)随机生成,假设一定和wcwc不同时出现在该训练数据窗口)
- ...
- 中心词wcwc和第KK个噪声词wKwK不同时出现在该训练数据窗口(噪声词wKwK按噪声词分布ℙ(w)P(w)随机生成,假设一定和wcwc不同时出现在该训练数据窗口)
我们可以使用σ(x)=1/(1+exp(−x))σ(x)=1/(1+exp(−x))函数来表达中心词wcwc和背景词wowo同时出现在该训练数据窗口的概率:
ℙ(D=1∣wo,wc)=σ(u⊤ovc)P(D=1∣wo,wc)=σ(uo⊤vc)
那么,中心词wcwc生成背景词wowo的对数概率可以近似为
logℙ(wo∣wc)=log[ℙ(D=1∣wo,wc)∏k=1,wk∼ℙ(w)Kℙ(D=0∣wk,wc)]logP(wo∣wc)=log[P(D=1∣wo,wc)∏k=1,wk∼P(w)KP(D=0∣wk,wc)]
假设噪声词wkwk在词典中的索引为ikik,上式可改写为
logℙ(wo∣wc)=log11+exp(−u⊤ovc)+∑k=1,wk∼ℙ(w)Klog[1−11+exp(−u⊤ikvc)]logP(wo∣wc)=log11+exp(−uo⊤vc)+∑k=1,wk∼P(w)Klog[1−11+exp(−uik⊤vc)]
因此,有关中心词wcwc生成背景词wowo的损失函数是
−logℙ(wo∣wc)=−log11+exp(−u⊤ovc)−∑k=1,wk∼ℙ(w)Klog11+exp(u⊤ikvc)−logP(wo∣wc)=−log11+exp(−uo⊤vc)−∑k=1,wk∼P(w)Klog11+exp(uik⊤vc)
当我们把KK取较小值时,每次随机梯度下降的梯度计算开销将由(||)O(|V|)降为(K)O(K)。
我们也可以对连续词袋模型进行负采样。有关背景词w(t−m),…,w(t−1),w(t+1),…,w(t+m)w(t−m),…,w(t−1),w(t+1),…,w(t+m)生成中心词wcwc的损失函数
−logℙ(w(t)∣w(t−m),…,w(t−1),w(t+1),…,w(t+m))−logP(w(t)∣w(t−m),…,w(t−1),w(t+1),…,w(t+m))
在负采样中可以近似为
−log11+exp[−u⊤c(vo1+…+vo2m)/(2m)]−∑k=1,wk∼ℙ(w)Klog11+exp[(u⊤ik(vo1+…+vo2m)/(2m)]−log11+exp[−uc⊤(vo1+…+vo2m)/(2m)]−∑k=1,wk∼P(w)Klog11+exp[(uik⊤(vo1+…+vo2m)/(2m)]
同样地,当我们把KK取较小值时,每次随机梯度下降的梯度计算开销将由(||)O(|V|)降为(K)O(K)。
层序softmax
层序softmax利用了二叉树。树的每个叶子节点代表着词典V中的每个词。每个词wiwi相应的词向量为vivi。我们以下图为例,来描述层序softmax的工作机制。
假设L(w)L(w)为从二叉树的根到代表词ww的叶子节点的路径上的节点数,并设n(w,i)n(w,i)为该路径上第ii个节点,该节点的向量为un(w,i)un(w,i)。以上图为例,L(w3)=4L(w3)=4。那么,跳字模型和连续词袋模型所需要计算的任意词wiwi生成词ww的概率为:
ℙ(w∣wi)=∏j=1L(w)−1σ([n(w,j+1)=leftChild(n(w,j))]⋅u⊤n(w,j)vi)P(w∣wi)=∏j=1L(w)−1σ([n(w,j+1)=leftChild(n(w,j))]⋅un(w,j)⊤vi)
其中σ(x)=1/(1+exp(−x))σ(x)=1/(1+exp(−x)),如果xx为真,[x]=1[x]=1;反之[x]=−1[x]=−1。
由于σ(x)+σ(−x)=1σ(x)+σ(−x)=1,wiwi生成词典中任何词的概率之和为1:
∑w=1ℙ(w∣wi)=1∑w=1VP(w∣wi)=1
让我们计算wiwi生成w3w3的概率,由于在二叉树中由根到w3w3的路径上需要向左、向右、再向左地遍历,我们得到
ℙ(w3∣wi)=σ(u⊤n(w3,1)vi))⋅σ(−u⊤n(w3,2)vi))⋅σ(u⊤n(w3,3)vi))P(w3∣wi)=σ(un(w3,1)⊤vi))⋅σ(−un(w3,2)⊤vi))⋅σ(un(w3,3)⊤vi))
我们可以使用随机梯度下降在跳字模型和连续词袋模型中不断迭代计算字典中所有词向量vv和非叶子节点的向量uu。每次迭代的计算开销由(||)O(|V|)降为二叉树的高度(log||)O(log|V|)。
结论
word2vec工具中的跳字模型和连续词袋模型可以使用两种负采样和层序softmax减小训练开销。
参考文献:
http://zh.d2l.ai/chapter_natural-language-processing/word2vec.html