约 30 分钟 · 需要向量内积、指数与对数

读完你能: 区分 one-hot、词嵌入和上下文;写出 CBOW、Skip-gram、softmax 和负采样的目标;解释为什么要有两套向量;理解 GloVe 怎样拟合共现统计,以及静态词向量的局限。

1. 从编号到可学习的位置

one-hot 给每个词单独一个坐标轴,任意两个不同词的内积都是 0,彼此一样“远”,没法表达谁和谁更像。词嵌入换一种做法:用一张表 E∈RV×dE\in\mathbb R^{V\times d} 给每个词学一个 dd 维向量,dd 通常远小于词表大小 VV。

拿词的编号去表里取出对应的那一行,和“one-hot 向量乘以矩阵 EE”在数学上是同一个运算;实现时只需按编号查表,不必真的构造那个巨大的 one-hot 向量。

词向量背后的直觉是:经常出现在相似上下文里的词,用法往往相近。 这只是经验规律,不是定理。比如“好”和“坏”常常出现在几乎一样的位置,所以向量相近并不等于意思相同。

2. CBOW 与 Skip-gram

设窗口为中心词左右各一个词,句子是 cats eat fresh fish,以 eat 为中心:

方法 输入 要预测的输出
CBOW cats 与 fresh 的向量(求和或平均) 中心词 eat
Skip-gram 中心词 eat 上下文词 cats、fresh

CBOW 用上下文猜中心词。它把上下文向量求和或平均,所以窗口内部的词序基本被丢掉了。Skip-gram 反过来用中心词猜上下文,把一个窗口拆成若干个“中心词—上下文词”对,每一对是一条训练样本。两者的训练目标确实不同,并不是同一张网络图换了个名字。

常调的参数有窗口大小、向量维度、最低词频和负样本个数。窗口小,学到的偏向局部搭配;窗口大,学到的偏向更宽泛的话题关联。这些参数同时也影响训练成本。

3. 为什么有两套向量

在 Skip-gram 里,每个词都有两个向量:作为中心词时用输入向量 vwv_w,作为上下文词时用输出向量 ucu_c。用完整 softmax 时,

P(c∣w)=eucTvw∑j=1VeujTvw.P(c\mid w)=\frac{e^{u_c^{T}v_w}}{\sum_{j=1}^{V}e^{u_j^{T}v_w}}.

输入、输出各有一张 V×dV\times d 的表,不算偏置一共约 2Vd2Vd 个参数。训练完后,可以只用输入表、只用输出表,或者把两者合起来(例如相加),但要说清楚用的是哪一种。

例1: 设 vw=(1,0)v_w=(1,0),词表里三个词的输出向量分别为 (0,1)(0,1)、(1,1)(1,1)、(−1,0)(-1,0)。内积依次是 0、1、−1,于是

P=(e0,e1,e−1)1+e+e−1≈(0.2447,0.6652,0.0900).P=\frac{(e^0,e^1,e^{-1})}{1+e+e^{-1}}\approx(0.2447,0.6652,0.0900).

如果真实的上下文是第二个词,这一对的交叉熵损失为 −ln⁡0.6652≈0.4076-\ln0.6652\approx0.4076。优化时,模型一边提高真实上下文的分数,一边因为分母的存在压低其他词的分数——所有词在分母里互相竞争。

softmax 的麻烦在于分母要把整个词表都算一遍,词表一大就很慢。另外,实际计算时应先把所有分数减去其中的最大值再取指数,防止溢出;分子分母同乘一个常数,结果不变。

4. 负采样到底在优化什么

负采样不再计算整个词表。对一个真实词对 (w,c)(w,c),再随机抽 KK 个“噪声词” n1,…,nKn_1,\dots,n_K,最大化

ln⁡σ(ucTvw)+∑j=1Kln⁡σ(−unjTvw),σ(x)=11+e−x,\ln\sigma(u_c^{T}v_w)+\sum_{j=1}^{K}\ln\sigma(-u_{n_j}^{T}v_w),\qquad \sigma(x)=\frac1{1+e^{-x}},

等价地,最小化它的相反数。意思很直接:真实词对的内积要大,噪声词对的内积要小。噪声词通常按“词频的 3/43/4 次方”归一化后的分布来抽,这样高频词仍然更常被抽到,但不至于把负样本几乎全占了。

例2: 沿用例1的向量:真实上下文 uc=(1,1)u_c=(1,1),内积为 1;一个负样本 un=(−1,0)u_n=(-1,0),内积为 −1。损失为

ℓ=−ln⁡σ(1)−ln⁡σ(−(−1))=−2ln⁡σ(1)≈0.6265.\ell=-\ln\sigma(1)-\ln\sigma(-(-1))=-2\ln\sigma(1)\approx0.6265.

对输入向量求梯度(利用 ddxln⁡σ(x)=1−σ(x)\frac{d}{dx}\ln\sigma(x)=1-\sigma(x)):

∂ℓ∂vw=(σ(ucTvw)−1)uc+∑jσ(unjTvw)unj.\frac{\partial\ell}{\partial v_w}=(\sigma(u_c^{T}v_w)-1)u_c+ \sum_j\sigma(u_{n_j}^{T}v_w)u_{n_j}.

代入 σ(1)≈0.7311\sigma(1)\approx0.7311、σ(−1)≈0.2689\sigma(-1)\approx0.2689:

∂ℓ∂vw≈−0.2689 (1,1)+0.2689 (−1,0)=(−0.5379,−0.2689).\frac{\partial\ell}{\partial v_w}\approx-0.2689\,(1,1)+0.2689\,(-1,0)=(-0.5379,-0.2689).

如果只更新输入向量、学习率取 0.1:

vwnew=(1,0)−0.1×(−0.5379,−0.2689)≈(1.0538,0.0269).v_w^{new}=(1,0)-0.1\times(-0.5379,-0.2689)\approx(1.0538,0.0269).

vwv_w 向 uc=(1,1)u_c=(1,1) 的方向靠近了一点,同时远离 un=(−1,0)u_n=(-1,0)。

负采样给不出完整的词表概率

负采样训练的是一个局部的二分类器:分辨“真实词对”和“噪声词对”。它不会把完整 softmax 逐项算出来,σ(ucTvw)\sigma(u_c^Tv_w) 也不是对所有词加起来等于 1 的概率分布,不能直接当语言模型用。

5. GloVe:拟合全局共现次数的对数

先在整个语料上统计词 ii 周围出现词 jj 的次数,得到共现矩阵 XX。GloVe 最小化

J=∑i,j:Xij>0f(Xij)(wiTw~j+bi+b~j−ln⁡Xij)2,J=\sum_{i,j:X_{ij}>0}f(X_{ij}) \left(w_i^{T}\widetilde w_j+b_i+\widetilde b_j-\ln X_{ij}\right)^2,

常用的权重函数是

f(x)={(x/xmax)α,0<x<xmax1,x≥xmax.f(x)=\begin{cases}(x/x_{max})^\alpha,&0<x<x_{max}\\1,&x\ge x_{max}.\end{cases}

也就是说,让“两个词向量的内积加上偏置”去逼近它们共现次数的对数。权重 ff 的作用是:很少共现的词对噪声大,权重小一些;特别常见的词对权重封顶为 1,不让它们主导损失。Xij=0X_{ij}=0 的词对没法取 ln⁡0\ln 0,求和时直接跳过。

例3: 设 Xij=4X_{ij}=4,当前“内积加偏置”为 1,xmax=10x_{max}=10,α=0.75\alpha=0.75。这一项的损失为

(4/10)0.75(1−ln⁡4)2≈0.503×0.149≈0.0751.(4/10)^{0.75}(1-\ln4)^2\approx0.503\times0.149\approx0.0751.

Word2Vec 一次看一个窗口里的词对,GloVe 先把整个语料的共现次数汇总成矩阵再拟合。两者用的都是分布信息,谈不上谁永远更好。

6. 相似度、类比与局限

有了词向量,可以用余弦相似度查找向量近邻,也可以把一段文本的词向量平均一下当作文档向量,作为简单的基线。但平均会丢掉词序、否定和词与词之间的结构。另外,词向量的单个维度通常没有可以命名的固定含义。

静态词向量给每个词只分配一个固定向量,所以“银行”义和“河岸”义的 bank 会被揉在一起。上下文相关的表示会根据整段输入为同一个词在不同位置生成不同的向量,能缓解这个问题,但并不意味着歧义从此消失。

使用词向量时还要检查:词表覆盖够不够,换到新领域后效果如何,以及训练数据中的偏差。近邻关系可能复现语料里的偏见;“国王 − 男人 + 女人 ≈ 女王”这类向量类比只是有趣的现象,不能当作现实决策的规则。

自测

1. V=10000、d=100,两套不带偏置的嵌入表一共有多少参数?

2Vd=2×10000×100=2 000 0002Vd=2\times10000\times100=2\,000\,000,即 200 万。输入表和输出表都要训练。

2. 正对的内积从 1 增大到 2,负采样损失里正对那一项变大还是变小?

σ(2)>σ(1)\sigma(2)>\sigma(1),所以 −ln⁡σ(2)-\ln\sigma(2) 更小,正对那一项变小。但还得看负对那一项:如果负对的内积也增大,它的损失会随之上升。整体放大向量并不总让每个内积增大——原本为负的内积会变得更负,因此应分别检查正对与负对。