# 学习词嵌入

- 原标题：Learning Word Embedding \| Lil'Log
- 类型：博客
- 来源：Lilian Weng 博客
- 发布时间：未知（待核验）
- 首次精选：2026-10-29 23:09
- 分级：值得看
- 学习层级：进阶
- 主题：[neural-model-foundations](<https://oplearnx.com/md/topics/neural-model-foundations.md>)（第 8 位）
- 原文链接：[https://lilianweng.github.io/posts/2017-10-15-word-embedding](<https://lilianweng.github.io/posts/2017-10-15-word-embedding>)
- 本站页面：[https://oplearnx.com/resources/pk\_541970caf81e](<https://oplearnx.com/resources/pk_541970caf81e>)

## 摘要

这篇博客讲如何把自由文本中的词转换为稠密数值向量表示，指出 one-hot 编码在词表规模大时不实用，而词嵌入能在低维稠密空间中近似词间相似度并体现隐含语义关系。内容涵盖基于计数的向量空间模型、基于上下文的 Skip-Gram 与 CBOW、各类损失函数（全 softmax、层次 softmax、交叉熵、噪声对比估计 NCE、负采样 NEG）、其他训练技巧、GloVe 全局向量，以及用《权力的游戏》文本做 word2vec 的示例。

## 中文精读

### 1. 学习词嵌入（总览）

- 人类词汇存在于自由文本中，要让机器学习模型理解并处理自然语言，需要把词语转成数值。最简单的做法是 one-hot 编码：每个不同的词占一个维度，用 0/1 表示该词是否出现。
- one-hot 面对整个词表时维度可达数十万，计算上不可行。词嵌入用维度低得多、因而更稠密的（非二值）数值向量表示词和短语。
- 好的词嵌入应能近似词间相似度（如 cat 与 kitten 相近），或揭示潜在语义关系（cat–kitten 类比于 dog–puppy）。上下文信息对学习词义与词间关系非常有用，因为相似的词常出现在相似上下文中。
- 学习词嵌入有两大类方法，都依赖上下文知识：基于计数的方法（count-based），无监督，对全局词共现矩阵做矩阵分解，原始共现计数效果不佳，需要在其上做聪明处理；基于上下文的方法（context-based），有监督，给定局部上下文设计模型预测目标词，同时学出高效的嵌入表示。

### 2. 基于计数的向量空间模型

- 基于计数的向量空间模型高度依赖词频与共现矩阵，假设出现在相同上下文中的词具有相似或相关的语义。
- 这类模型把相邻词共现等计数统计量映射为小规模、稠密的词向量；PCA、主题模型、神经概率语言模型都是这一类别的例子。
- 与基于计数的方法不同，基于上下文的方法构建直接以“由邻居预测某个词”为目标的预测模型，稠密词向量是模型参数的一部分，训练过程中学出每个词的最佳向量表示。

### 3. 基于上下文：Skip-Gram 模型

- 设一个固定大小的滑动窗口沿句子移动：中间词是“目标词”，窗口内左右两侧的词是上下文词。skip-gram 模型（Mikolov 等，2013）训练来预测在给定目标词时，某个词成为上下文词的概率。
- 文中以 5 词窗口沿“The man who passes the sentence should swing the sword.”滑动为例，逐位置列出目标词与对应上下文，如目标 the 的上下文是 man、who，目标 passes 的上下文是 man、who、the、sentence 等。
- 每个“上下文—目标”对都作为一条新的训练样本；例如目标词 swing 产生四条样本：（swing, sentence）、（swing, should）、（swing, the）、（swing, sword）。
- 给定词表大小 V，学习大小为 N 的嵌入向量；模型每次用一个目标词（输入）预测一个上下文词（输出）。输入词与输出词都被编码为大小 V 的 one-hot 向量。
- 输入的二值向量与大小为 V×N 的词嵌入矩阵 W 相乘，得到输入词的嵌入向量（即 W 的第 i 行），构成 N 维隐藏层；隐藏层再与大小 N×V 的上下文矩阵 W′ 相乘，产生输出的 one-hot 向量。
- W′ 以“作为上下文”的角度编码词义，与嵌入矩阵 W 不同；尽管名字相似，W′ 与 W 相互独立，不是转置或逆之类的关系。

### 4. 基于上下文：连续词袋模型（CBOW）

- 连续词袋模型（CBOW）是另一种学词向量的相似模型，它由多个源上下文词（如 sentence、should、the、sword）预测目标词（如 swing）。
- 由于上下文词有多个，模型把各上下文词经输入向量与矩阵 W 相乘得到的词向量做平均，得到隐藏层中的定长向量，其他符号含义与 skip-gram 图相同。
- 平均这一步会平滑掉大量分布信息，因此有人认为 CBOW 更适合小数据集。

### 5. 损失函数（总述）

- skip-gram 与 CBOW 都需要通过最小化设计良好的损失/目标函数来训练，可以选用多种损失函数。
- 后续讨论以 skip-gram 模型为例说明损失如何计算。

### 6. 全 softmax

- skip-gram 用矩阵 W 定义每个词的嵌入向量，用输出矩阵 W′ 定义上下文向量；给定输入词 w\_I，把 W 中对应的行记为 v\_\{w\_I\}（嵌入向量），把 W′ 中对应的列记为 v′\_\{w\_I\}（上下文向量）。
- 输出层用 softmax 计算给定 w\_I 时预测出输出词 w\_O 的概率：分子为 exp\(v′\_\{w\_O\}ᵀ v\_\{w\_I\}\)，分母对词表中全部词 i=1…V 的同一项求和。
- 原文紧接着有一句“This is accurate as presented in”，该句本身残缺、没有补完（原缺后续内容），随后才转入下面的讨论。
- 当词表 V 极大时，每个样本都要遍历所有词计算分母，计算上不可行；对更高效条件概率估计的需求催生了层次 softmax 等方法。

### 7. 层次 softmax

- Morin 和 Bengio（2005）提出层次 softmax，借助二叉树结构加快求和计算：每个叶子是一个词，每个内部节点表示到达其子节点的相对概率。
- 每个词 w\_i 从根到其叶子有唯一路径，取到该词的概率等于沿树的分支走这条路径的概率；已知内部节点 n 的嵌入向量 v\_n，词的获取概率可由在每个内部节点处左转或右转的概率连乘得到（σ 为 sigmoid），右转概率为 σ\(v′\_nᵀ v\_\{w\_I\}\)，左转为 σ\(−v′\_nᵀ v\_\{w\_I\}\)。
- 给定输入词 w\_I 得到上下文词 w\_O 的概率是沿路径各节点带符号项之积，符号由指示函数决定（下一节点为左子节点取 1，否则取 −1），路径深度为 L\(w\_O\)；内部节点的嵌入在训练中学得。
- 树结构把训练时分母估计的复杂度从 O\(V\) 降到 O\(log V\)，但预测时仍需计算每个词的概率并选出最好的，因为事先不知道会到达哪个叶子。
- 好的树结构对模型性能至关重要，常用原则包括：按词频分组（如 Huffman 树以简单提速）、把相似的词分到同一或邻近分支（如使用预定义词聚类、WordNet）。

### 8. 交叉熵

- 另一种做法完全脱离 softmax 框架，改为衡量预测概率 p 与真实二值标签 y 之间的交叉熵。
- 两个分布 p、q 的交叉熵为 H\(p,q\)=−Σ\_x p\(x\) log q\(x\)；真实标签只有在 w\_i 是输出词时 y\_i 为 1，否则为 0。损失函数 L\_θ 旨在最小化预测与真实标签的交叉熵，交叉熵越低表示两个分布越相似。
- 代入 softmax 表达式后，损失化为 −v′\_\{w\_O\}ᵀ v\_\{w\_I\} \+ log Σ\_i exp\(v′\_\{w\_i\}ᵀ v\_\{w\_I\}\)；为用 SGD 反向传播训练，需要求梯度。
- 记 z\_IO = v′\_\{w\_O\}ᵀ v\_\{w\_I\}，梯度推导结果为 −∇\_θ z\_IO \+ Σ\_i p\(w\_i\|w\_I\) ∇\_θ z\_\{Ii\}，最后写成 −∇\_θ z\_IO 加上在噪声分布 Q\(w̃\) 下的期望 E\_\{w\_i∼Q\(w̃\)\} ∇\_θ z\_\{Ii\}。
- 按该式，正确的输出词经第一项得到正向强化（∇\_θ z\_IO 越大损失越好），其他词则通过第二项起负向作用；关键问题是怎样用一小批噪声词样本而非扫描整个词表来估计这个期望。

### 9. 噪声对比估计（NCE）

- 噪声对比估计（NCE）用逻辑回归分类器把目标词与噪声样本区分开（Gutmann 和 Hyvärinen，2010）。给定输入词 w\_I，真实输出词为 w，同时从噪声分布 Q 采样 N 个词 w̃\_1…w̃\_N，分类器决策 d 取二值。
- 损失为 −\[log p\(d=1\|w, w\_I\) \+ Σ\_\{i, w̃\_i∼Q\} log p\(d=0\|w̃\_i, w\_I\)\]；N 足够大时按大数定律，可把求和写成 N·E\_\{w̃\_i∼Q\} log p\(d=0\|w̃\_i, w\_I\)。
- 在 w、w̃\_1…w̃\_N 中，有 1/\(N\+1\) 的机会取到真实词（依 p\(w\|w\_I\) 采样），有 N/\(N\+1\) 的机会取到噪声词（每个依 q\(w̃\)∼Q 采样），由此得到联合概率并推出 p\(d=1\|w,w\_I\)=p\(w\|w\_I\)/\(p\(w\|w\_I\)\+Nq\(w̃\)\)，p\(d=0\|w,w\_I\)=Nq\(w̃\)/\(p\(w\|w\_I\)\+Nq\(w̃\)\)。
- 把两者代回即得 NCE 二分类器的损失形式。但 p\(w\|w\_I\) 的分母仍需对全词表求和，记该分母为输入词的配分函数 Z\(w\_I\)；常见假设是 Z\(w\)≈1（期望 softmax 输出层已被归一化，Minh 和 Teh，2012），损失由此简化为含 exp\(v′\_wᵀ v\_\{w\_I\}\) 与 Nq\(w̃\) 的形式。
- 噪声分布 Q 是可调参数，设计上希望它贴近真实数据分布、且易于采样。例如 TensorFlow 的 NCE 损失采样实现假设噪声服从对数均匀分布（即 Zipf 定律）：词的对数概率与其按频次降序的排名成反比，高频词排名低；此时 q\(w̃\) = \(1/log V\)\(log\(r\_w̃\+1\) − log r\_w̃\)，其中 r\_w̃∈\[1,V\] 是词的频次排名。

### 10. 负采样（NEG）

- 负采样（NEG）由 Mikolov 等（2013）提出，是 NCE 损失的简化变体，因训练 Google 的 word2vec 项目而尤为著名。
- 与试图近似最大化 softmax 输出对数概率的 NCE 不同，负采样做了进一步简化，因为它关注的是学出高质量词嵌入，而不是对自然语言的词分布建模。
- NEG 用 sigmoid 函数近似二分类器输出：p\(d=1\|w, w\_I\)=σ\(v′\_wᵀ v\_\{w\_I\}\)，p\(d=0\|w, w\_I\)=1−σ\(v′\_wᵀ v\_\{w\_I\}\)=σ\(−v′\_wᵀ v\_\{w\_I\}\)；最终损失为 −\[log σ\(v′\_wᵀ v\_\{w\_I\}\) \+ Σ\_\{i, w̃\_i∼Q\} log σ\(−v′\_\{w̃\_i\}ᵀ v\_\{w\_I\}\)\]。

### 11. 学习词嵌入的其他技巧

- Mikolov 等（2013）给出若干有助于取得良好词嵌入学习效果的做法。
- 软滑动窗口：为窗口内的词配对时，给距离更远的词更小权重。一种启发式是设定最大窗口 s\_max，每个训练样本的实际窗口大小在 1 到 s\_max 间随机采样，于是每个上下文词被观测到的概率为 1/（它与目标词的距离），而相邻词总会被观测到。
- 频繁词子采样：过于频繁的词可能过于泛化而难以区分上下文（如停用词），罕见词则更可能携带独特信息；为平衡二者，Mikolov 等提出在采样时以 1−√\(t/f\(w\)\) 的概率丢弃词 w，f\(w\) 为词频，t 为可调阈值。
- 先学习短语：短语常是一个概念单元而非单词的简单组合（即使知道 new 和 york 的含义，也难判断 New York 是城市名），先学出这类短语并把它们当作词单元再训练词嵌入模型能提升质量。
- 一种简单的数据驱动做法基于一元和二元计数：s\_phrase = \(C\(w\_i w\_j\) − δ\)/\(C\(w\_i\)C\(w\_j\)\)，C\(.\) 是一元词或二元组的简单计数，δ 是防止超低频词与短语的折扣阈值；分数越高越可能是短语。要形成长于两词的短语，可用递减的分数门槛多次扫描词表。

### 12. GloVe：全局向量

- Pennington 等人（2014）提出的 GloVe 模型把基于计数的矩阵分解和基于上下文的 skip-gram 模型结合起来。
- 文中把共现概率定义为 p\_co\(w\_k\|w\_i\) = C\(w\_i, w\_k\) / C\(w\_i\)，即两词共现计数除以 w\_i 的计数。
- 以 ice、steam 为例：与 ice 相关而与 steam 无关的 solid，其两个共现概率之比会很大；与两者都相关（water）或都不相关（fashion）的词，比值接近 1。
- 核心直觉是词义由共现概率的比值而非概率本身刻画，因此把关系建模为 F\(w\_i, w\_j, w̃\_k\) 等于上述比值，并让 F 作用于两词的线性差 \(w\_i − w\_j\)ᵀw̃\_k。
- 考虑目标词与上下文词之间的对称性，最终把 F 取为指数函数，得到 w\_iᵀw̃\_k = log C\(w\_i, w̃\_k\) − log C\(w\_i\)。
- 由于 −log C\(w\_i\) 与 k 无关，可为 w\_i 加偏置 b\_i，并对称地为上下文词加偏置 b̃\_k，得到 log C\(w\_i, w̃\_k\) = w\_iᵀw̃\_k \+ b\_i \+ b̃\_k。

### 13. 示例：在《权力的游戏》语料上运行 word2vec

- 回顾完上面的理论后，文中用《权力的游戏》语料做了一个词向量小实验，整个过程借助 gensim 完成，非常直接。
- 第一步抽取词：用 NLTK 的英文停用词表和分句工具，逐行读取五个 .txt 文件（001ssb.txt 至 005ssb.txt），转小写、用 unicode\_escape 解码后按 ascii 编码并忽略错误，再用正则 \\b\(\\w\+\)\\b 提取词并过滤停用词；只保留长度大于 1 的词列表，若该文件得到的句子列表数大于 1 则并入总结果，最终得到按句子组织的词列表（每个子列表是一个句子）。
- 第二步把句子词列表喂给 gensim 的 Word2Vec：向量维度 size=128、窗口 window=3、min\_count=5、workers=4，随后用 model.wv.save\_word2vec\_format 以非二进制方式保存为 got\_word2vec.txt。
- 第三步用 model.most\_similar 检查结果：在 GoT 词向量空间中。
- 与 king 最相似的十个词依次为 kings（0.897245）、baratheon（0.809675）、son（0.763614）、robert（0.708522）、lords（0.698684）、joffrey（0.696455）、prince（0.695699）、brother（0.685239）、aerys（0.684527）、stannis（0.682932）。
- 与 queen 最相似的十个词依次为 cersei（0.942618）、joffrey（0.933756）、margaery（0.931099）、sister（0.928902）、prince（0.927364）、uncle（0.922507）、varys（0.918421）、ned（0.917492）、melisandre（0.915403）、robb（0.915272）。

```python
from gensim.models import Word2Vec

# size: the dimensionality of the embedding vectors.
# window: the maximum distance between the current and predicted word within a sentence.
model = Word2Vec(GOT_SENTENCE_WORDS, size=128, window=3, min_count=5, workers=4)
model.wv.save_word2vec_format("got_word2vec.txt", binary=False)
```

### 14. 示例：在《权力的游戏》语料上运行 word2vec

- 在回顾理论之后，文中用《权力的游戏》语料做了一次词向量实验，流程通过 gensim 完成，非常直接。
- 第一步是抽取词：用 NLTK 的英文停用词表和分词工具，按行读取五个 .txt 文件，转小写、解码后再用正则 \\b\(\\w\+\)\\b 提取单词并过滤停用词，只保留长度大于 1 的句子，得到按句子组织的词列表（每个子列表是一个句子）。
- 第二步把句子词列表喂给 gensim 的 Word2Vec：向量维度 size=128、窗口 window=3、min\_count=5、workers=4，随后用 save\_word2vec\_format 保存为文本格式。
- 第三步检查结果：在得到的 GoT 词向量空间中，与 king 最相似的词包括 kings（0.897245）、baratheon（0.809675）、son（0.763614）、robert（0.708522）、lords（0.698684）等。
- 与 queen 最相似的词包括 cersei（0.942618）、joffrey（0.933756）、margaery（0.931099）、sister（0.928902）、prince（0.927364）等。

```python
from gensim.models import Word2Vec

# size: the dimensionality of the embedding vectors.
# window: the maximum distance between the current and predicted word within a sentence.
model = Word2Vec(GOT_SENTENCE_WORDS, size=128, window=3, min_count=5, workers=4)
model.wv.save_word2vec_format("got_word2vec.txt", binary=False)
```

### 15. 参考文献

- 列出的参考资料包括 TensorFlow 的“Vector Representations of Words”教程，以及 Chris McCormick 的 skip-gram 教程和 Sebastian Ruder 关于 softmax 近似的词向量系列文章。
- 还包括 Xin Rong 的《word2vec Parameter Learning Explained》，以及 Mikolov 等人关于向量空间中词表示高效估计、词与短语分布式表示的论文。
- 方法论类文献包括 Morin 与 Bengio 的层次化概率神经网络语言模型、Gutmann 与 Hyvärinen 的噪声对比估计（noise-contrastive estimation）。
- 另有 Baroni 等人对上下文计数与上下文预测两类语义向量的系统比较，以及 Pennington 等人的 GloVe 原始论文。

---
来源：LearnMap · 学径（https://oplearnx.com）
