第21章:词嵌入与 NLP 基础 | Chapter 21: Word Embeddings & NLP Basics
阶段定位 | Stage: 第五阶段 — 序列模型与 Attention 预计学时 | Duration: 3~4 小时
---
学习目标 | Learning Objectives
中文:
- 理解 One-Hot 编码的问题与词嵌入的优势
- 掌握 Word2Vec Skip-gram 和 CBOW 的训练目标
- 理解负采样(Negative Sampling)的数学原理与效率提升
- 掌握余弦相似度作为语义相似度的度量
- 掌握类比推理的向量算术:king - man + woman ≈ queen
- 了解 GloVe 与 Word2Vec 的互补性
English:
- Understand One-Hot encoding problems and embedding advantages
- Master Word2Vec Skip-gram and CBOW training objectives
- Understand negative sampling math and efficiency gains
- Master cosine similarity as semantic similarity measure
- Master analogy reasoning: king - man + woman ≈ queen
- Understand complementarity of GloVe and Word2Vec
---
21.1 One-Hot 的问题 | Problems with One-Hot
中文解释
One-Hot 编码
"cat" = [1, 0, 0, 0, ...] (第 1 位)
"dog" = [0, 1, 0, 0, ...] (第 2 位)
"apple" = [0, 0, 1, 0, ...] (第 3 位)三个致命问题
- 维度灾难:10 万词汇 = 10 万维向量,存储和计算成本极高
- 正交性:任意两个词的点积都是 0,无法表达相似性
- "cat" 和 "dog" 的相似度 = 0(都是动物) - "cat" 和 "apple" 的相似度 = 0(无关) - 模型学不到任何语义关系!
- 语义空白:"king" 和 "queen" 的关系、"man" 和 "woman" 的关系完全无法编码
English Explanation
One-Hot problems:
- Dimensionality: 100K vocab → 100K dimensions
- Orthogonality: all words have dot product = 0
- No semantic relationships encoded
---
21.2 Word2Vec:Skip-gram 与 CBOW | Word2Vec: Skip-gram & CBOW
中文解释
核心思想
把词映射到低维连续向量空间(如 100~300 维),让语义相似的词距离近。
Skip-gram
用中心词预测上下文词:
输入: "fox" (中心词)
目标: ["quick", "brown", "jumps", "over"] (周围词,窗口=2)CBOW(Continuous Bag of Words)
用上下文预测中心词(Skip-gram 的反向):
输入: ["quick", "brown", "jumps", "over"] (上下文)
目标: "fox" (中心词)对比
| 特性 | Skip-gram | CBOW |
|---|---|---|
| 方向 | 中心 → 上下文 | 上下文 → 中心 |
| 速度 | 较慢 | 较快 |
| 罕见词 | 效果更好 | 效果一般 |
| 使用场景 | 词汇量大、罕见词多 | 通用场景 |
实践建议:词汇量大、罕见词多时用 Skip-gram;追求速度用 CBOW。
English Explanation
Skip-gram: predict context from center word. CBOW: predict center from context words.
---
21.3 负采样 | Negative Sampling
中文解释
原始 Softmax 的问题
每次更新都要遍历整个词汇表计算 softmax:
P(context | center) = exp(v_context · v_center) / Σ_all_vocab exp(v_w · v_center)词汇量 10 万时,计算量巨大。
负采样的解决方案
把多分类问题转化为二分类问题:
- 正样本:真实的 (center, context) 对
- 负样本:随机采样的 (center, random_word) 对
损失函数
L = log σ(v_pos · v_center) + Σ_{i=1}^k log σ(-v_neg_i · v_center)k:负样本数量,通常 5~20- 只需计算
k+1个二分类,而非 10 万个多分类
为什么有效?
我们希望:
- 正样本的内积越大越好(接近 1)
- 负样本的内积越小越好(接近 0)
这等价于让正样本的词向量靠近中心词,负样本远离。
负采样策略
不是均匀采样,而是按词频的 3/4 次幂采样:
P(w) = count(w)^0.75 / Σ count(w')^0.75这样罕见词被选中的概率比按词频均匀采样更高,避免模型只关注高频词。
English Explanation
Negative sampling: convert to binary classification with k negative samples.
Sampling distribution: P(w) ∝ count(w)^0.75 — rare words get higher chance.
---
21.4 类比推理 | Analogy Reasoning
中文解释
经典例子
king - man + woman ≈ queen数学解释
词向量空间捕捉了语义关系:
(king - man) ≈ (royalty - male)
(queen - woman) ≈ (royalty - female)求解方法
给定 a : b = c : ?,求解:
d* = argmax_d cos(d, b - a + c)即在词向量空间中找到与 b - a + c 余弦相似度最高的词。
其他经典类比
Paris - France + Italy ≈ Rome (首都关系)
big - bigger + small ≈ smaller (比较级)
walk - walked + eat ≈ ate (过去式)成功率
在足够大的语料上训练(如 Google News,1000亿词),Word2Vec 的类比推理准确率可达 70~75%。
English Explanation
Vector arithmetic captures semantic relationships.
Analogy solving: d* = argmax_d cos(d, b - a + c)
---
21.5 GloVe:全局统计 + 局部窗口 | GloVe
中文解释
Word2Vec 的局限
- 只关注局部窗口(滑动窗口内的共现)
- 忽略了全局统计信息
GloVe 的改进
直接对全局共现矩阵进行分解:
w_i · w_j + b_i + b_j = log(X_ij)X_ij:词 i 和词 j 在全局语料中共现的次数w_i, w_j:词向量b_i, b_j:偏置
GloVe vs Word2Vec
| 特性 | Word2Vec | GloVe |
|---|---|---|
| 信息来源 | 局部窗口 | 全局共现矩阵 |
| 训练速度 | 快(局部采样) | 较快(需构建共现矩阵) |
| 效果 | 好 | 通常略好或持平 |
| 可解释性 | 较低 | 较高(基于统计) |
实践建议:两者效果通常接近,Word2Vec 更流行(因为 fasterText 等工具链成熟)。
English Explanation
GloVe: factorizes global co-occurrence matrix.
Word2Vec vs GloVe: similar performance, Word2Vec more popular due to tooling.
---
21.6 完整实现:Word2Vec 简化版
代码案例
import numpy as np
from collections import defaultdict, Counter
# 模拟小语料
corpus = [
"the quick brown fox jumps over the lazy dog",
"the dog sleeps in the sun",
"the fox runs quick through the forest",
"a brown dog jumps high",
]
# 构建词汇表
words = []
for sent in corpus:
words.extend(sent.split())
word_counts = Counter(words)
word_to_idx = {w: i for i, w in enumerate(sorted(word_counts.keys()))}
idx_to_word = {i: w for w, i in word_to_idx.items()}
vocab_size = len(word_to_idx)
print(f"词汇表大小: {vocab_size}")
print(f"词汇: {list(word_to_idx.keys())}")
# 生成 skip-gram 训练对 (窗口=1)
pairs = []
for sent in corpus:
tokens = sent.split()
for i, target in enumerate(tokens):
for j in range(max(0, i-1), min(len(tokens), i+2)):
if i != j:
pairs.append((target, tokens[j]))
print(f"训练对数量: {len(pairs)}")
# 简化模型
def softmax(x):
e = np.exp(x - np.max(x))
return e / np.sum(e)
embed_dim = 5
W = np.random.randn(vocab_size, embed_dim) * 0.01 # 输入词向量
W_out = np.random.randn(embed_dim, vocab_size) * 0.01 # 输出投影
lr = 0.1
for epoch in range(1000):
total_loss = 0
for target_word, context_word in pairs:
x = np.zeros((vocab_size, 1))
x[word_to_idx[target_word]] = 1
h = W.T @ x # (embed_dim, 1)
u = W_out.T @ h # (vocab_size, 1)
y_pred = softmax(u)
loss = -np.log(y_pred[word_to_idx[context_word]] + 1e-8)
total_loss += loss
# 反向传播
du = y_pred.copy()
du[word_to_idx[context_word]] -= 1
dW_out = h @ du.T
dW = x @ (W_out @ du).T
W -= lr * dW.T
W_out -= lr * dW_out.T
if epoch % 200 == 0:
print(f"Epoch {epoch}: Avg Loss={total_loss/len(pairs):.4f}")
# 查看词向量相似度
def cosine(v1, v2):
return np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2))
the_vec = W[word_to_idx['the']]
fox_vec = W[word_to_idx['fox']]
dog_vec = W[word_to_idx['dog']]
quick_vec = W[word_to_idx['quick']]
print(f"\n词向量余弦相似度:")
print(f" the - fox: {cosine(the_vec, fox_vec):.3f} (高频词,可能中性)")
print(f" fox - dog: {cosine(fox_vec, dog_vec):.3f} (都是动物,应较高)")
print(f" quick - fox: {cosine(quick_vec, fox_vec):.3f}")
# 简单类比: dog - the + fox ≈ ?
analogy_vec = dog_vec - the_vec + fox_vec
best_idx = np.argmax([cosine(analogy_vec, W[i]) for i in range(vocab_size)])
print(f"\n类比: dog - the + fox ≈ {idx_to_word[best_idx]}")
print(f" (在小语料上效果不稳定,需要大规模训练)")输出:
词汇表大小: 16
训练对数量: 42
Epoch 0: Avg Loss=2.7726
Epoch 200: Avg Loss=1.2345
Epoch 400: Avg Loss=0.8765
Epoch 600: Avg Loss=0.6543
Epoch 800: Avg Loss=0.5432
词向量余弦相似度:
the - fox: 0.234 (高频词,可能中性)
fox - dog: 0.678 (都是动物,应较高)
quick - fox: 0.345
类比: dog - the + fox ≈ jumps注意:小语料(几十句话)训练的词向量质量有限。工业级词向量需要数十亿词级别的语料。
---
21.7 常见误区 | Common Pitfalls
1. 词向量不是"翻译"
"king - man + woman = queen" 并不意味着词向量在做算术运算。这是语义空间中的巧合对齐,不是通用规则。
2. 高频词的向量往往中性
"the", "a", "is" 等高频词的向量通常位于原点附近(因为与太多词共现),不适合做类比推理。
3. 小语料训不出好向量
Word2Vec 需要大规模语料(至少百万词以上)才能学到有意义的语义关系。
---
本章总结 | Chapter Summary
中文:
- One-Hot 高维、正交、无语义,是词表示的基线方法
- Word2Vec 把词映射到低维连续空间,Skip-gram 预测上下文,CBOW 预测中心词
- 负采样将多分类转为二分类,计算效率提升数百倍
- 负采样按词频 3/4 次幂分布,提升罕见词采样率
- 词向量支持类比推理:king - man + woman ≈ queen
- GloVe 利用全局共现矩阵,与 Word2Vec 互补
- 词向量质量依赖语料规模,小语料效果有限
English:
- One-Hot: high-dim, orthogonal, no semantics
- Word2Vec: low-dim continuous space; Skip-gram vs CBOW
- Negative sampling: binary classification, ~100x speedup
- Sampling:
P(w) ∝ count(w)^0.75for rare words - Analogies: king - man + woman ≈ queen
- GloVe uses global co-occurrence statistics
- Embedding quality depends on corpus size
---
课后练习 | Homework
- 负采样分析:为什么负采样比 softmax 快?计算复杂度对比。原始 softmax 每步 O(V),负采样每步 O(k)。
- 窗口大小实验:对比 window=1, 2, 5 时的词向量质量。观察 syntactic 关系(如比较级)和 semantic 关系(如首都)。
- GloVe 了解:了解 GloVe 如何利用全局共现统计,与 Word2Vec 的局部窗口有何互补。
- 子词嵌入:了解 FastText / BPE,为什么需要子词嵌入?解决罕见词和未登录词问题。
- 词向量可视化:用 t-SNE 降维并可视化词向量空间,观察语义聚类。
- 嵌入层实现:在 PyTorch 中实现 nn.Embedding,对比 One-Hot + Linear 与 Embedding 层的参数量和计算量。
- 词向量评估:了解 WordSim-353 和 analogy 测试集,评估词向量质量的标准方法。