Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

5.5 Word2vec

前几节将词表示为维度对应词表单词的稀疏长向量。现在介绍更强大的表示:短而稠密的嵌入。嵌入通常有 d=50d=50 到 1000 个维度,而不是词表大小 VV 那么多;这些维度没有清晰的人工解释。向量也是稠密的:元素不再是大多为零的计数或计数函数,而是可以为负的实数。

稠密向量在各种 NLP 任务中通常都优于稀疏向量。原因尚未完全明了,但有一些直觉:用 300 维稠密向量表示词,比用 50,000 维向量所需学习的分类器权重少得多,较小的参数空间可能有助于泛化并避免过拟合;稠密向量也更能捕捉同义关系。例如,稀疏表示中 car 和 automobile 是彼此独立、毫无关联的两个维度,因而可能无法捕捉“以 car 为邻词”和“以 automobile 为邻词”的两个词之间的相似性。

本节介绍一种计算嵌入的方法:带负采样的 skip-gram(skip-gram with negative sampling, SGNS)。skip-gram 是 word2vec 软件包中的两种算法之一,因此也常被宽泛地称为 word2vec(Mikolov et al., 2013a, 2013b)。word2vec 方法速度快、训练高效,代码和预训练嵌入也很容易获得。它学到的是静态嵌入:词表中每个词只有一个固定向量。第 9 章将介绍 BERT 表示等动态上下文嵌入,其中同一个词在不同语境中有不同向量。

word2vec 的直觉是:不再统计每个语境词 cc 在 apricot 附近出现多少次,而是训练一个二元分类器,回答“词 cc 是否可能出现在 apricot 附近?”我们并不真正关心这个预测任务本身,而是把分类器学到的权重当作词嵌入。

关键思想是直接把连续文本用作隐式监督训练数据:出现在目标词 apricot 附近的词 cc,就是“cc 是否可能出现在 apricot 附近?”这一问题的金标准正确答案。这个通常称为自监督(self-supervision)的方法不需要任何人工标注信号。Bengio et al.(2003)和 Collobert et al.(2011)最早在神经语言建模中提出这一思想:预测前文之后的下一个词,并直接用连续文本中的实际下一个词作监督信号,同时学习每个词的嵌入表示。

下一章将介绍神经网络,而 word2vec 比神经网络语言模型简单得多:第一,它把任务从词预测简化为二元分类;第二,它把架构从带隐藏层、需要复杂训练算法的多层神经网络简化为逻辑回归分类器。skip-gram 的思路是:

  1. 把目标词与相邻语境词组成正例;

  2. 从词表随机抽取其他词作为负例;

  3. 用逻辑回归训练分类器区分两种情形;

  4. 将学到的权重用作嵌入。

5.5.1 分类器

先考虑分类任务,再讨论训练。假设句子中目标词为 apricot,语境窗口左右各包含两个词:

... lemon, a [tablespoon of apricot jam, a] pinch ...
         c1c_1 c2c_2 ww c3c_3 c4c_4

目标是训练分类器:给定目标词 ww 与候选语境词 cc 组成的二元组 (w,c)(w,c),例如 (apricot, jam) 或 (apricot, aardvark),返回 cc 是真实语境词的概率——对 jam 为真,对 aardvark 为假:

P(+w,c)(5.11)P(+\mid w,c)\tag{5.11}

cc 不是 ww 的真实语境词的概率为:

P(w,c)=1P(+w,c)(5.12)P(-\mid w,c)=1-P(+\mid w,c)\tag{5.12}

分类器如何计算概率?skip-gram 假设概率以嵌入相似度为基础:若某词的嵌入与目标词嵌入相似,它就更可能出现在目标词附近。两个向量点积较高时可视为相似,因此:

Similarity(w,c)cw(5.13)\operatorname{Similarity}(w,c)\approx\mathbf c\cdot\mathbf w\tag{5.13}

点积只是可从负无穷到正无穷的数,并非概率。用逻辑回归核心的 sigmoid 函数将它转换到 0 与 1 之间:

σ(x)=11+exp(x)(5.14)\sigma(x)=\frac1{1+\exp(-x)}\tag{5.14}

于是,ccww 真实语境词的概率为:

P(+w,c)=σ(cw)=11+exp(cw)(5.15)P(+\mid w,c)=\sigma(\mathbf c\cdot\mathbf w)=\frac1{1+\exp(-\mathbf c\cdot\mathbf w)}\tag{5.15}

为使两个事件(cc 是或不是语境词)的总概率为 1,另一个概率为:

P(w,c)=1P(+w,c)=σ(cw)=11+exp(cw)(5.16)\begin{array}{rcl}P(-\mid w,c)&=&1-P(+\mid w,c)\\&=&\sigma(-\mathbf c\cdot\mathbf w)=\frac1{1+\exp(\mathbf c\cdot\mathbf w)}\end{array}\tag{5.16}

式 5.15 只处理一个词,但窗口中有多个语境词。skip-gram 作出简化假设,认为所有语境词彼此独立,因此可直接将概率相乘:

P(+w,c1:L)=i=1Lσ(ciw)(5.17)P(+\mid w,c_{1:L})=\prod_{i=1}^L\sigma(\mathbf c_i\cdot\mathbf w)\tag{5.17}
logP(+w,c1:L)=i=1Llogσ(ciw)(5.18)\log P(+\mid w,c_{1:L})=\sum_{i=1}^L\log\sigma(\mathbf c_i\cdot\mathbf w)\tag{5.18}

总之,给定测试目标词 ww 及其由 LL 个词构成的语境窗口 c1:Lc_{1:L},skip-gram 训练的概率分类器依据窗口与目标词的相似程度赋予概率;具体做法是将目标词嵌入与每个语境词嵌入的点积输入 sigmoid。为计算这个概率,只需要词表中每个目标词和语境词的嵌入。

图 5.6 skip-gram 模型学到的嵌入。算法为每个词存储两个嵌入:目标嵌入(也称输入嵌入)和语境嵌入(也称输出嵌入)。因此,算法学习的参数 θ\theta2V2Vdd 维向量组成的矩阵,由目标嵌入矩阵 W\mathbf W 和语境加噪声嵌入矩阵 C\mathbf C 拼接而成。

skip-gram 实际为每个词保存两个嵌入:一个用于该词充当目标时,另一个用于它充当语境时。因此需要学习两个矩阵 W\mathbf WC\mathbf C,二者都为词表 VV 中的每个词包含一个嵌入。

5.5.2 学习 skip-gram 嵌入

skip-gram 的学习算法输入文本语料和选定的词表大小 NN。它先为 NN 个词各随机分配一个嵌入向量,然后反复调整:使词 ww 的嵌入更接近文本中邻近词的嵌入,更远离不在附近的词。仍考虑:

... lemon, a [tablespoon of apricot jam, a] pinch ...

目标词 ww 是 apricot,L=±2L=\pm2 的窗口中有 4 个语境词,因而得到 4 个正训练实例。训练二元分类器还需要负例;SGNS 通常使用比正例更多的负例,比例由参数 kk 决定。对每个正例 (w,cpos)(w,c_{pos}),创建 kk 个负样本,每个由目标 ww 和一个噪声词(noise word)cnegc_{neg} 组成。噪声词从词表随机抽取,但不能是目标词。下表以 k=2k=2 为例:

正例 +

负例 −

ww

cposc_{pos}

ww

cnegc_{neg}

ww

cnegc_{neg}

apricot

tablespoon

apricot

aardvark

apricot

seven

apricot

of

apricot

my

apricot

forever

apricot

jam

apricot

where

apricot

dear

apricot

a

apricot

coaxial

apricot

if

噪声词根据加权一元概率 Pα(w)P_\alpha(w) 选择,其中 α\alpha 是权重。若直接按未加权概率 P(w)P(w) 抽样,the 被选中的概率就是其一元概率,aardvark 亦然。实践中常设 α=.75\alpha=.75

Pα(w)=count(w)αwcount(w)α(5.19)P_\alpha(w)=\frac{\operatorname{count}(w)^\alpha}{\sum_{w'}\operatorname{count}(w')^\alpha}\tag{5.19}

α=.75\alpha=.75 会略微提高低频噪声词的概率,因而效果更好。设 P(a)=.99P(a)=.99P(b)=.01P(b)=.01

Pα(a)=.99.75.99.75+.01.75=.97Pα(b)=.01.75.99.75+.01.75=.03(5.20)\begin{array}{l}P_\alpha(a)=\frac{.99^{.75}}{.99^{.75}+.01^{.75}}=.97\\P_\alpha(b)=\frac{.01^{.75}}{.99^{.75}+.01^{.75}}=.03\end{array}\tag{5.20}

可见,罕见事件 bb 的概率从 .01 增至 .03。

给定正、负训练实例和初始嵌入,学习算法要调整嵌入,使正例中目标词—语境词对 (w,cpos)(w,c_{pos}) 的相似度最大,使负例中 (w,cneg)(w,c_{neg}) 的相似度最小。对一个正例及其 kk 个噪声词,可把两个目标写成需要最小化的损失:第一项让真实语境词有较高的“是邻词”概率,第二项让每个噪声词有较高的“不是邻词”概率;在独立性假设下将它们相乘:

L(w,cpos,cneg)=log[P(+w,cpos)i=1kP(w,cnegi)]=[logP(+w,cpos)+i=1klogP(w,cnegi)]=[logσ(cposw)+i=1klogσ(cnegiw)](5.21)\begin{array}{l}L(w,c_{pos},c_{neg^*})=-\log\left[P(+\mid w,c_{pos})\prod_{i=1}^kP(-\mid w,c_{neg_i})\right]\\=-\left[\log P(+\mid w,c_{pos})+\sum_{i=1}^k\log P(-\mid w,c_{neg_i})\right]\\=-\left[\log\sigma(\mathbf c_{pos}\cdot\mathbf w)+\sum_{i=1}^k\log\sigma(-\mathbf c_{neg_i}\cdot\mathbf w)\right]\end{array}\tag{5.21}

也就是最大化目标词与真实语境词的点积,最小化它与 kk 个负采样非邻词的点积。使用随机梯度下降最小化该损失。

图 5.7 一步梯度下降的直觉。skip-gram 调整嵌入,使目标嵌入(apricot)更接近邻近词的语境嵌入(jam,即点积更高),并远离附近未出现的噪声词语境嵌入(Tolstoy、matrix,即点积更低)。

对式 5.21 中不同嵌入求导,得到(证明留作章末练习):

Lcpos=[σ(cposw)1]w(5.22)\frac{\partial L}{\partial\mathbf c_{pos}}=[\sigma(\mathbf c_{pos}\cdot\mathbf w)-1]\mathbf w\tag{5.22}
Lcnegi=σ(cnegiw)w(5.23)\frac{\partial L}{\partial\mathbf c_{neg_i}}=\sigma(\mathbf c_{neg_i}\cdot\mathbf w)\mathbf w\tag{5.23}
Lw=[σ(cposw)1]cpos+i=1kσ(cnegiw)cnegi(5.24)\frac{\partial L}{\partial\mathbf w}=[\sigma(\mathbf c_{pos}\cdot\mathbf w)-1]\mathbf c_{pos}+\sum_{i=1}^k\sigma(\mathbf c_{neg_i}\cdot\mathbf w)\mathbf c_{neg_i}\tag{5.24}

因此,从时刻 ttt+1t+1 的 SGD 更新为:

cpost+1=cpostη[σ(cpostwt)1]wt(5.25)\mathbf c_{pos}^{t+1}=\mathbf c_{pos}^t-\eta[\sigma(\mathbf c_{pos}^t\cdot\mathbf w^t)-1]\mathbf w^t\tag{5.25}
cnegit+1=cnegitησ(cnegitwt)wt(5.26)\mathbf c_{neg_i}^{t+1}=\mathbf c_{neg_i}^t-\eta\sigma(\mathbf c_{neg_i}^t\cdot\mathbf w^t)\mathbf w^t\tag{5.26}
wt+1=wtη([σ(cpostwt)1]cpost+i=1kσ(cnegitwt)cnegit)(5.27)\mathbf w^{t+1}=\mathbf w^t-\eta\left([\sigma(\mathbf c_{pos}^t\cdot\mathbf w^t)-1]\mathbf c_{pos}^t+\sum_{i=1}^k\sigma(\mathbf c_{neg_i}^t\cdot\mathbf w^t)\mathbf c_{neg_i}^t\right)\tag{5.27}

与逻辑回归一样,算法从随机初始化的 W\mathbf WC\mathbf C 出发,遍历训练语料,用梯度下降按式 5.25—5.27 移动二者,使式 5.21 的损失最小。

skip-gram 为每个词 ii 学习目标嵌入 wi\mathbf w_i 和语境嵌入 ci\mathbf c_i,分别存于矩阵 W\mathbf WC\mathbf C。常见做法是将二者相加,用 wi+ci\mathbf w_i+\mathbf c_i 表示词 ii;也可以丢弃 C\mathbf C,只用 wi\mathbf w_i。与 tf-idf 等计数方法相同,语境窗口大小会影响 skip-gram 嵌入的表现,实验中常在开发集上调节该参数。

5.5.3 其他静态嵌入

静态嵌入还有许多种。word2vec 的扩展 fastText(Bojanowski et al., 2017)解决了未知词问题,即测试语料中出现训练语料从未见过的词。相关问题是词稀疏性:在形态丰富的语言中,每个名词或动词的许多形式可能都很少出现。

fastText 使用子词模型解决这些问题:把每个词表示为词本身及其组成字符 n 元语法的词袋,并在词两端加特殊边界符 <>。例如 n=3n=3 时,where 表示为 <where> 加字符三元语法:

<wh, whe, her, ere, re>

算法为每个组成 n 元语法学习 skip-gram 嵌入,并将它们的嵌入之和作为 where 的表示。未知词也可以仅用其组成 n 元语法之和表示。fastText 的开源库及 157 种语言的预训练嵌入见 https://fasttext.cc

另一种广泛使用的静态嵌入模型是 GloVe(Global Vectors;Pennington et al., 2014)。它着眼于语料的全局统计,基于词—词共现矩阵中的概率比率。

word2vec 等稠密嵌入与基于计数的嵌入之间其实存在优雅的数学关系:word2vec 可以看作隐式优化某个采用特定 PPMI 加权的计数矩阵函数(Levy and Goldberg, 2014c)。