4. 词嵌入基础:Word2Vec原理

说到词嵌入,我最早接触这个概念是在2014年。那时候做文本分类,用的还是one-hot编码。说白了,就是把每个词当成一个独立的符号,词与词之间没有任何关系。这显然不合理——「苹果」和「香蕉」应该是相似的,但one-hot编码下它们的余弦相似度永远是0。

Word2Vec的出现,算是彻底改变了这个局面。它由Google的Mikolov团队在2013年提出,核心思想很简单:一个词的含义,可以由它周围的词来定义。你想想看,这其实跟人类学习语言的方式很像——我们理解一个生词,往往也是通过它出现的上下文来推测的。

4.1 CBOW与Skip-gram:两种核心架构

Word2Vec提供了两种训练模式,我分别说说我的理解。

4.1.1 CBOW(连续词袋模型)

CBOW的思路是:用上下文词来预测中心词。举个例子:

句子:"我 喜欢 吃 苹果"
窗口大小=2,对于中心词"吃":
上下文:["我", "喜欢", "苹果", "。"]
目标:预测"吃"

具体怎么做呢?我习惯这么理解:

  1. 每个上下文词都有一个向量表示(初始随机)
  2. 把这些向量加起来(或取平均)
  3. 通过一个softmax层,输出词表中每个词的概率
  4. 让「吃」的概率最大化

我在项目中遇到过一个问题:CBOW对小数据集比较友好。因为它把多个上下文词的信息聚合在一起,相当于做了平滑。但缺点也很明显——它对高频词过于敏感,容易忽略罕见词。

4.1.2 Skip-gram

Skip-gram正好反过来:用中心词来预测上下文词

还是那个句子,中心词"吃":
预测:["我", "喜欢", "苹果", "。"]

每个训练样本变成:
(吃, 我), (吃, 喜欢), (吃, 苹果), (吃, 。)

Skip-gram的训练量更大——每个中心词会产生多个训练对。但好处是,它对罕见词更友好。我个人的经验是:如果语料足够大,Skip-gram的效果通常更好。尤其是当你的任务需要捕捉词与词之间的细微语义关系时,Skip-gram的优势很明显。

核心区别总结

  • CBOW:快,适合大语料,对高频词友好
  • Skip-gram:慢但精准,适合小语料或罕见词较多的场景

4.2 负采样:让训练变得可行

嗯,这里要注意。原始的Word2Vec有一个巨大的问题——每次计算softmax时,都要对整个词表(几十万甚至上百万个词)做归一化。这计算量,你想想看,根本跑不动。

负采样的思路很巧妙:我不需要计算所有词的概率,只需要让正样本的概率变大,同时随机选几个负样本让它们的概率变小

具体来说:

对于训练样本 (吃, 苹果):
- 正样本:("吃", "苹果") → 让它们的点积尽可能大
- 负样本:从词表中随机选k个词,比如 ("吃", "飞机"), ("吃", "桌子")...
  → 让这些点积尽可能小

k的取值,我一般这样设:

  • 小数据集:k=5~10
  • 大数据集:k=2~5

我曾经踩过一个坑:负采样时如果随机选词,很容易选到「的」「了」这种高频无意义词。后来我改用基于词频的采样分布——高频词被选为负样本的概率更高。这样模型能更快学到有意义的区分。

我的小技巧:负采样时,可以给词频加一个0.75的指数。这是Mikolov论文里提到的,实际效果确实比纯词频采样好。

4.3 Hierarchical Softmax:另一种加速方案

除了负采样,还有另一种加速方法——Hierarchical Softmax。说白了,就是用霍夫曼树来代替原来的softmax层。

原来的softmax:

输出层有V个节点(V=词表大小)
每次计算都要算V次

Hierarchical Softmax:

把词表组织成二叉树
每个叶子节点对应一个词
从根到叶子的路径上,每个节点做一个二分类
计算量从O(V)降到O(logV)

我刚开始学的时候觉得这很复杂,其实理解起来不难:

  1. 构建一棵霍夫曼树,高频词路径短,低频词路径长
  2. 每个内部节点都有一个向量
  3. 训练时,沿着目标词的路径,让每个节点的二分类结果正确

举个例子:假设「苹果」的路径是「左→右→左」,那训练时就要让:

  • 根节点:预测向左(正确)
  • 第二层节点:预测向右(正确)
  • 第三层节点:预测向左(正确)

我个人习惯是:词表小于10万时用负采样,大于10万时考虑Hierarchical Softmax。不过现在硬件越来越强,负采样已经成为主流了。

注意:Hierarchical Softmax有一个限制——它假设词与词之间是互斥的(一个样本只能对应一个词)。这在某些多标签场景下不适用。

4.4 实践中的选择建议

说了这么多,到底该怎么选?我整理了一个表格:

场景 推荐方案 理由
语料量 < 1亿词 Skip-gram + 负采样 对罕见词更友好,训练可控
语料量 > 1亿词 CBOW + 负采样 训练速度快,效果差异不大
词表极大(>50万) Skip-gram + Hierarchical Softmax 避免负采样时的采样偏差
实时性要求高 CBOW + 负采样(k=2) 计算量最小

最后说一句:Word2Vec虽然经典,但它有一个固有缺陷——无法处理一词多义。比如「苹果」既可以是水果,也可以是公司。这个问题直到ELMo和BERT出现才得到解决。不过那是后话了,咱们下一章再聊。

本章要点回顾

  • CBOW:上下文→中心词,适合大语料
  • Skip-gram:中心词→上下文,适合小语料
  • 负采样:用少量负样本近似softmax,最常用
  • Hierarchical Softmax:用树结构加速,适合超大词表