用预测任务学习词向量#
共现矩阵与 SVD 直接对全局统计做分解。Word2Vec 换了一个思路:用一个词预测它的上下文(或反过来),把预测任务训练好之后,词向量作为副产品被得到。真正要优化的是预测,最终使用的是学到的嵌入矩阵。
分布式假设仍然成立:经常出现在相似上下文中的词,语义相近。但 Word2Vec 不再显式构造 V×V 的共现矩阵,而是从语料中逐窗口采样训练样本,因而更容易扩展到大规模语料。
设词表为 V,大小为 V,词向量维度为 d。模型维护两套参数:
- 输入嵌入矩阵 Win∈Rd×V,第 w 列是词 w 作为中心词时的向量 vw;
- 输出嵌入矩阵 Wout∈RV×d,第 w 行是词 w 作为上下文词时的向量 uw。
总参数量为 2Vd。词 w 的 one-hot 向量记为 xw∈RV,则
h=Winxw=vw这个矩阵乘法等价于按列号查表,所以称为 embedding lookup。Word2Vec 的网络没有偏置、没有激活函数、只有一个隐藏层,本质上是线性投影;非线性只出现在输出端的 softmax 或 sigmoid 中。
Skip-gram:中心词预测上下文#
给定长度为 T 的词序列和窗口大小 m,Skip-gram 对每个位置 t,用中心词 wt 预测窗口内所有上下文词 wt+j,j∈{−m,…,−1,1,…,m}):
−m≤j≤mj=0∏P(wt+j∣wt)t=1∏T−m≤j≤mj=0∏P(wt+j∣wt)θmaxt=1∑T−m≤j≤mj=0∑logP(wt+j∣wt)L(θ)=−t=1∑T−m≤j≤mj=0∑logP(wt+j∣wt)建模对象(对于一对上下文,中心词)建模对象(对于整个语料)目标函数(对数似然)损失函数(对于整个语料)Skip-gram 一对正样本的 softmax#
对于一对正样本 (wt,wt+j) ,条件概率由中心词向量 vwt 与候选上下文词向量 uwt+j 的点积经 softmax 得到:
P(wt+j∣wt)=∑w∈Vexp(uwTvwt)exp(uwt+jTvwt)对正样本 (wt,wt+j),损失为
L=−logP(wt+j∣wt)=−uwt+jTvwt+logw∈V∑exp(uwTvwt)计算开销分析
带入整体的损失函数 L(θ),对每个正样本 (wt,wt+j) 都要计算一次 softmax 的分母(主要是中心词变了)。
L(θ)=t=1∑T−m≤j≤mj=0∑[−uwt+jTvwt+logw∈V∑exp(uwTvwt)]如果词表大小=V=106,窗口大小 m=5,语料长度 T=108,则总共要计算 109 次 softmax,每次都要对 106 个词求和,计算量巨大。
对 vwt 求梯度:
∂vwt∂L=−uwo+w∈V∑P(w∣wt)uw第一项把中心词向量拉向真实上下文词的向量;第二项按模型当前的预测分布把所有输出向量加权平均,相当于一个“推开”项,防止模型只靠高频词蒙混过关。对 uw 的梯度为
∂uw∂L=(P(w∣wt)−δw,wo)vwt真实上下文词被拉近,其余词被推远。推导本身不难,关键结论是:每次更新都要对全词表 V 求和并更新所有 uw,这就是 softmax 的瓶颈。
CBOW:上下文预测中心词#
CBOW(Continuous Bag of Words)是 Skip-gram 的镜像:给定窗口内的上下文词 wt+j,j∈{−m,…,−1,1,…,m} ,预测中心词 wt。
θmaxt=1∑TlogP(wt∣wt−m,…,wt−1,wt+1,…,wt+m)目标函数L(θ)=−t=1∑TlogP(wt∣wt−m,…,wt−1,wt+1,…,wt+m)损失函数CBOW一对正样本的 softmax#
对于每个样本,先把上下文词向量取平均:
h=∣Ct∣1w∈Ct∑vw,Ct={wt−m,…,wt−1,wt+1,…,wt+m}再计算每个候选中心词 wt 的 softmax 概率:
P(wt∣Ct)=∑w∈Vexp(uwTh)exp(uwtTh)带入整体的损失函数 L(θ),这里的计算量就小很多,
L(θ)=−t=1∑TlogP(wt∣Ct)=−t=1∑T[uwtTh+logw∈V∑exp(uwTh)]CBOW 把多个上下文词平均成一个向量,一次只预测一个中心词,训练速度比 Skip-gram 快;代价是上下文信息被平均稀释,稀有词作为中心词被训练的机会也更少。
两者对比如下:、
| 比较维度 | CBOW | Skip-gram |
|---|
| 输入 | 多个上下文词 | 一个中心词 |
| 预测目标 | 一个中心词 | 多个上下文词 |
| 建模对象 | P(wt∣Ct) | P(wt+j∣wt) |
| 优化目标 | 最大化中心词的对数似然 | 最大化上下文词的对数似然 |
| 标准损失 | −∑tlogP(wt∣Ct) | −∑t∑j∈JtlogP(wt+j∣wt) |
| 上下文处理 | 聚合上下文词向量 | 分别预测各上下文词 |
| 经典结构的顺序信息 | 不显式保留 | 不显式建模窗口内词序 |
CBOW 的参数结构同样是 Win 和 Wout,但一次更新中,输入矩阵只更新窗口内的 2m 个词,输出矩阵只更新中心词对应的行;Skip-gram 则相反,输入只更新一个词,输出要对窗口内每个上下文词分别求梯度。这解释了训练速度与稀有词效果的差异。
负采样#
softmax 的分母需要对 V 个词求和。负采样(Negative Sampling)把“从全词表中选出正确上下文词”的 V 分类问题,改成“判断某个词对是否真实共现”的二分类问题。
对每个正样本 (wt,wo),从噪声分布 P(w) 中采样 k 个未出现在该窗口中的词作为负例。
用 D=1 表示中心词 wt 与候选上下文词 wo 被判定为真实词对,D=0 表示噪声词对
对于一个正样本 (wt,wo) 和 k 个负样本 (wt,wt,o,i−),i=1,…,k
P(D=1∣wt,wo)=σ(uwoTvwt)(wt,wo)被判定成正样本的概率P(D=0∣wt,wt,o,i−)=σ(−uwt,o,i−Tvwt)(wt,wt,o,i−)被判定成负样本的概率i=1∏kP(D=0∣wt,wt,o,i−)=i=1∏kσ(−uwt,o,i−Tvwt)k个负样本都被判定成负样本的概率
- σ(x)=1/(1+e−x),σ(−x)=1/(1+ex)=1−σ(x)。
对于Skip-gram,建模对象变为最大化正确区分正样本与负样本的分类似然,对单个正样本 (wt,wt+j) 和它对应的 k 个负样本 (wt,wt,j,i−),i=1,…,k 而言就是乘一块:
P(D=1∣wt,wt+j)i=1∏kP(D=0∣wt,wt,j,i−)=σ(uwt+jTvwt)i=1∏k(1−σ(uwt,j,i−Tvwt))单个正样本的损失函数为他的对数似然:
L=−logσ(uwt+jTvwt)−i=1∑klogσ(−uwt,j,i−Tvwt)对于整个语料,负采样方法的损失函数在外面套了两个求和:
LN(θ)=−t=1∑T−m≤j≤mj=0∑[logσ(uwt+jTvwt)+i=1∑klogσ(−uwiTvwt)]对比一下不用负采样的损失函数:
L(θ)=−t=1∑T−m≤j≤mj=0∑[uwt+jTvwt−logw∈V∑exp(uwTvwt)]每次更新只需计算 k+1 个 sigmoid,复杂度从 O(V) 降到 O(k)。
负例按
P(w)∝count(w)3/4采样。3/4 次幂压低了高频词的采样概率、提升了低频词的采样概率,避免负例几乎全是“the”“a”这类词。实践中 k 通常取 5–20(小语料)或 2–5(大语料)。
负采样可以看作对 softmax 的近似:它不直接归一化全词表,而是用少量负例估计“这个上下文词相对于随机词是否足够突出”。训练完成后,Win 的列、或 Win 与 WoutT 的平均,都可以作为最终词向量。
层次 Softmax#
层次 Softmax(Hierarchical Softmax)是另一种降低复杂度的方法:用一棵 Huffman 树把词表组织成二叉树,每个词对应一条从根到叶的路径。预测词 wo 的概率是从根出发、沿路径做若干次二分类的概率乘积:
P(wo∣wt)=l=1∏L(wo)−1σ(sl⋅un(wo,l)Tvwt)其中:
- L(wo):路径长度;
- n(wo,l):路径上的节点;
- sl∈{+1,−1}:该步走向左子树还是右子树。
Huffman 树让高频词路径短、低频词路径长,平均只需 O(logV) 次二分类。
层次 Softmax 在早期实现中很常见,但树结构依赖词频,且难以并行;现代实现更常用负采样。
训练细节#
- 动态窗口:每个样本的窗口大小在 [1,m] 内随机取,近距离词对更容易被采到,相当于一种数据增强;
- 高频词下采样:以与词频相关的概率丢弃高频词(如“的”“the”),减少无信息样本;
- 学习率衰减:训练后期降低学习率,让向量稳定下来;
- 语料与窗口:窗口越大,学到的语义越偏向主题相关;窗口越小,越偏向句法和搭配。
性质与局限#
Word2Vec 得到的是静态词向量:每个词只有一个向量,与上下文无关。因此:
- 多义词无法区分,“bank”在“河岸”和“银行”语境下是同一个向量;
- 词表之外的词(OOV)没有向量,需要借助子词方法处理;
- 向量只编码了窗口内的共现信息,无法直接表示长距离句法结构。
这些局限分别由 子词分词、ELMo 和 BERT 等上下文相关表示逐步解决。Word2Vec 的结构也可以看作对早期 神经网络语言模型 的简化:去掉隐藏层和非线性,只保留嵌入查表和输出预测。