0 · 引言:本讲在 CS224N 中的位置
词向量(word vectors,也叫 word embeddings、neural word representations)几乎是整门 CS224N 第一个真正"动手"的内容。本讲之后的所有模型 — RNN、Transformer、BERT、LLaMA —— 在输入端都依赖某种形式的 embedding 表,因此你对本讲的理解将直接迁移到 Lecture 5(Transformer)的 token embedding、Lecture 7(pretraining)的 input layer、甚至 Lecture 14(tokenization)对子词单位的设计。
原 PPT 的 6 节安排是:
- 课程组织(行政性内容,本教材略去)
- Word2vec introduction(15 min)
- Word2vec objective function gradients(25 min, 本讲最硬核的一段)
- Optimization basics(5 min)
- Can we capture word meaning more effectively by counting?(10 min, 引入 GloVe)
- Evaluating word vectors(10 min)
本教材在保留 PPT 全部要点的前提下,做了三件 PPT 没做、但研究生需要的事:
- 把 PPT 上一句话带过的"为什么"展开成完整的论证(标记为 🤔 为什么 模块);
- 把 word2vec / GloVe 联通到 2024–2026 仍在使用的范式(contrastive learning、矩阵分解视角、Transformer 词嵌入层),标记为 🎓 研究生延伸;
- 每节配可推导/可编程的练习,并在 §8 给出 ≤ 40 行的 SGNS 最小复现代码。
1 · 词义如何表征?
1.1 denotational semantics:符号 ⇔ 所指
语言学中最朴素的词义观叫 denotational semantics(指称语义):词作为 signifier(能指 / 符号),指向 signified(所指 / 事物或观念)。形式上:
$$ \text{tree} \;\Longleftrightarrow\; \{\,🌳, \,🌲, \,🌴, \,\dots\,\} \tag{1.1} $$这种"符号→对象集合"的映射在词典编纂里非常实用,但计算机无法直接消费一张图片集合或语义网络。我们需要 把"指称"变成"可计算的对象"。这就是本讲要解决的核心问题。
1.2 早期方案:WordNet(语义网络)
2013 年以前最主流的工程方案是 WordNet(Princeton, 1985–):一张人工标注的 synset(同义词集合)+ hypernym(is-a 关系)网络。NLTK 里只需几行 Python 即可访问:
from nltk.corpus import wordnet as wn
panda = wn.synset("panda.n.01")
hyper = lambda s: s.hypernyms()
list(panda.closure(hyper))
# -> [Synset('procyonid.n.01'), Synset('carnivore.n.01'), Synset('mammal.n.01'), ...]
WordNet 的问题在 PPT 中列出了 6 条,但本质上可以归纳为两类失败:
| 失败类型 | 具体表现 |
|---|---|
| ① 缺乏连续度量 | "proficient" 与 "good" 在不同语境下相似度不同;WordNet 只给二元的"是否同义"。 |
| ② 维护成本爆炸 | 新词("wicked, badass, bombest")、新义、跨领域、跨语种都需人工增补;信息工业的速度根本跟不上。 |
1.3 上一代基线:one-hot 表征
把词表 $V$ 中第 $i$ 个词表示为长度 $|V|$ 的指示向量:
$$ \text{hotel} = [\,0,0,0,0,0,0,0,\underbrace{1}_{i\text{-th}},0,0,0,0,0,0\,]^\top, \quad |V|\approx 5\times10^5 \tag{1.2} $$这种表示叫 localist representation。它有三大致命缺陷:
- 正交性:任意两个不同词的内积恒为 0,
motel·hotel与motel·banana都是 0,模型无法学到"汽车旅馆 ≈ 酒店"。 - 维度爆炸:$|V|$ 通常 $10^5$–$10^7$,下游矩阵参数线性增长。
- 泛化失败:训练集见过
"Seattle hotel",测试集出现"Seattle motel"时无法泛化。
one-hot 与 LLM 的关联
现代 Transformer 的 input embedding layer,从数学上看 就是 一个 $|V|\times d$ 的查表矩阵 $E$,输入 one-hot 后取出对应行,即 $E^\top \mathbf{x}_{\text{one-hot}}$。所以 one-hot 没有消失,它只是被"压缩"到了稠密向量空间——而 word2vec 正是教这个查表矩阵 $E$ 该长什么样的第一种成功方法。1.4 关键思想:分布式语义(distributional semantics)
本讲(也是现代 NLP)的奠基性 insight 来自语言学家 J.R. Firth (1957):
"You shall know a word by the company it keeps."
形式化地:词 $w$ 的 分布式语义 由它的 上下文分布 $P(\text{context} \mid w)$ 决定。看下面三个真实语料里的"banking":
| … government debt problems turning into banking crises as happened in 2009 … |
| … saying that Europe needs unified banking regulation to replace the hodgepodge … |
| … India has just given its banking system a shot in the arm … |
这些上下文词(debt, crises, regulation, system, …)共同 定义了 banking 的含义。我们的目标就是把这种"上下文分布"压缩成一个稠密向量:
$$ \textbf{banking} = \begin{bmatrix}0.286\\0.792\\-0.177\\-0.107\\0.109\\-0.542\\0.349\\0.271\end{bmatrix}\in\RR^{d},\quad d\approx 50\text{–}300 \tag{1.3} $$这种向量有几个并列的名字,三者指的是同一个东西:
- word vectors(本讲用语)
- word embeddings(强调"嵌入"到欧氏空间)
- (neural) word representations(强调神经网络学到)
另一个重要术语:上面的向量是 distributed representation(分布式表示,注意与 distributional semantics 名字像但概念不同)—— "分布式"指的是词义被分摊到所有维度上,没有任何一维独占某个特征;与之相对的 one-hot 是 localist。两个 d 不同:
- distributional semantics:词义如何定义(由上下文)
- distributed representation:词义如何编码(分散在多维)
分布式假设的现代回响
2018 年以来的 BERT/GPT 把分布式假设推到了极致:词义不再是一个 静态向量,而是上下文相关的(contextualized)。但请注意:Transformer 的 word embedding layer(输入端的 token embedding)仍然是 word2vec 风格的 静态 向量,self-attention 才是把它"按上下文重新计算"的机制。因此 word2vec 不是被淘汰,而是下沉为基础设施。练习 1.1
(A)证明:两个不同 one-hot 向量的余弦相似度恒为 0。(B)给出一个例子,说明 WordNet 给出"同义"但语境里其实不应该互换的词对。2 · Word2Vec 框架概览
2.1 skip-gram 的直觉:用中心词"猜"周边词
Word2Vec(Mikolov et al., 2013a, NeurIPS)是第一个 把分布式语义大规模工程化的成功模型。它的 idea 极其简洁——只有 4 句话:
- 有一个大语料 corpus,相当于一长串 token。
- 词表 $V$ 中每个词 $w$ 分配一个向量 $\mathbf{v}_w\in\RR^d$。
- 遍历语料每个位置 $t$(中心词 $c$),考虑窗口内的上下文词 $o$("outside words")。
- 用 $c$ 和 $o$ 的向量计算 $P(o\mid c)$,然后不断调整向量 让真正出现过的 $(c,o)$ 概率变高。
注意三个细节:
- 窗口是 对称 的,包含左右各 $m$ 个词;本图 $m=2$,实际生产中 $m\in[5,10]$。
- 预测不考虑相对位置("position-independent"):$P(\text{banking}|\text{into})$ 不区分 banking 是 $t+1$ 还是 $t+2$。这是 word2vec 的简化假设,也是它叫"bag of words 风格"的原因。
- 所谓"调整向量",本质就是 梯度下降。下一节我们会把目标函数写出来并求导。
2.2 两套向量 u / v:一个工程美学决策
本讲最容易被初学者忽略、但研究生必须掌握的设计:每个词维护两个向量:
- $\mathbf{v}_w$ — 当 $w$ 充当 中心词(center)时使用
- $\mathbf{u}_w$ — 当 $w$ 充当 上下文词(outside)时使用
训练完毕通常把两个向量平均,或者直接丢弃 $\mathbf{u}$ 只保留 $\mathbf{v}$。整套参数集合:
$$ \theta = \begin{bmatrix}\mathbf{v}_{\text{aardvark}}\\\vdots\\\mathbf{v}_{\text{zebra}}\\\mathbf{u}_{\text{aardvark}}\\\vdots\\\mathbf{u}_{\text{zebra}}\end{bmatrix}\;\in\RR^{2dV} \tag{2.1} $$为什么要用两套向量?
若只有一套 $\mathbf{v}$,那 $P(w \mid w)$(中心词预测自己)就会变成 $\exp(\mathbf{v}_w^\top \mathbf{v}_w) / Z$,这个内积恒为正的最大值。这会逼模型把每个词的概率"自指",破坏训练动力学。两套向量解耦了"作为中心"和"作为上下文"两种角色,让梯度计算和优化都更平滑(Goldberg & Levy 2014 的 note 给出了详细论证)。工程实践中:一套向量也能 work,但稍逊色一些。3 · 目标函数与完整梯度推导
3.1 似然函数 L(θ)
对长度为 $T$ 的语料,每个位置 $t$ 都贡献 $2m$ 个 (中心,上下文) 对。假设这些条件概率条件独立,整体数据似然:
$$ L(\theta) \;=\; \prod_{t=1}^{T}\prod_{\substack{-m\le j\le m\\ j\ne 0}} P\!\left(w_{t+j}\,\big|\,w_t;\theta\right) \tag{3.1} $$实践中我们最大化对数似然、即最小化 平均负对数似然:
$$ J(\theta) \;=\; -\frac{1}{T}\log L(\theta) \;=\; -\frac{1}{T}\sum_{t=1}^{T}\sum_{\substack{-m\le j\le m\\ j\ne 0}} \log P\!\left(w_{t+j}\,\big|\,w_t;\theta\right) \tag{3.2} $$这就是我们要最小化的 目标函数 / 代价函数 / 损失函数(在不同子领域里这三个词被混用)。一个等价的口号:
Minimizing J(θ) ⟺ Maximizing predictive accuracy.
3.2 用 softmax 实现 P(o|c)
现在的关键:$P(w_{t+j} \mid w_t;\theta)$ 该怎么算? word2vec 给出一个非常优雅的答案:
$$ \boxed{\;P(o \mid c) \;=\; \frac{\exp(\mathbf{u}_o^\top \mathbf{v}_c)}{\sum_{w\in V}\exp(\mathbf{u}_w^\top \mathbf{v}_c)}\;} \tag{3.3} $$把公式拆成三步看:
- ① 点积衡量相似性:$\mathbf{u}_o^\top \mathbf{v}_c = \sum_{i=1}^{d} u_{o,i} v_{c,i}$。两个向量越对齐(同方向、大模长),点积越大。
- ② 指数化保证非负:$\exp(\cdot)>0$,避免负概率。
- ③ 归一化得到概率分布:除以分母(对全词表的 sum),保证 $\sum_o P(o\mid c)=1$。
这正是 softmax 函数 在多分类中的标准用法:
$$ \text{softmax}(x_i) = \frac{\exp(x_i)}{\sum_{j=1}^{n}\exp(x_j)} \in (0,1),\quad \sum_i \text{softmax}(x_i)=1 \tag{3.4} $$3.3 关键推导:∂/∂v_c log P(o|c)
这是本讲最重要的一段数学,建议自己用纸笔重做一遍。目标:对中心词向量 $\mathbf{v}_c$ 求 $\log P(o\mid c)$ 的梯度。
Step 1:把 log 展开为差。
$$ \log P(o\mid c) \;=\; \mathbf{u}_o^\top \mathbf{v}_c \;-\; \log\sum_{w\in V} \exp(\mathbf{u}_w^\top \mathbf{v}_c) \tag{3.5} $$Step 2:分别对两项求 $\partial/\partial \mathbf{v}_c$。第一项是线性的:
$$ \frac{\partial}{\partial \mathbf{v}_c} \big(\mathbf{u}_o^\top \mathbf{v}_c\big) \;=\; \mathbf{u}_o \tag{3.6} $$Step 3:第二项用链式法则。令 $S = \sum_{w} \exp(\mathbf{u}_w^\top \mathbf{v}_c)$,则 $\frac{\partial \log S}{\partial \mathbf{v}_c} = \frac{1}{S}\frac{\partial S}{\partial \mathbf{v}_c}$,而
$$ \frac{\partial S}{\partial \mathbf{v}_c} \;=\; \sum_{x\in V}\exp(\mathbf{u}_x^\top \mathbf{v}_c)\,\mathbf{u}_x \tag{3.7} $$把 $\exp(\mathbf{u}_x^\top \mathbf{v}_c)/S$ 这个比值认出来:这正是 $P(x \mid c)$!于是:
$$ \frac{\partial}{\partial \mathbf{v}_c}\log \sum_w \exp(\mathbf{u}_w^\top \mathbf{v}_c) \;=\; \sum_{x\in V} P(x\mid c)\,\mathbf{u}_x \tag{3.8} $$Step 4:合并得到最终梯度:
$$ \boxed{\;\frac{\partial}{\partial \mathbf{v}_c}\log P(o\mid c) \;=\; \mathbf{u}_o - \sum_{x\in V} P(x\mid c)\,\mathbf{u}_x\;} \tag{3.9} $$这个梯度的几何解释
$\mathbf{u}_o$ 是"真实"的 outside 向量;$\sum_x P(x\mid c)\mathbf{u}_x$ 是"模型当前预测的 outside 向量的期望"。所以 $\nabla_{\vc}\log P = (\text{observed}) - (\text{expected})$。这是所有指数族 / softmax 模型的通用形式——你会在最大熵、CRF、能量模型里反复见到。如果模型预测完美,$\mathbf{u}_o = \mathbb{E}_{P(x|c)}[\mathbf{u}_x]$,梯度为零,停止更新。3.4 对 ∂/∂u_o 的推导(自己来)
类似地,对 outside 向量 $\mathbf{u}_o$(注意只对 正确 的那个 outside 词 o,不是对所有 $w$)求导。展开 (3.5) 再求导:
$$ \frac{\partial}{\partial \mathbf{u}_o}\log P(o\mid c) \;=\; \mathbf{v}_c \;-\; \frac{\exp(\mathbf{u}_o^\top \mathbf{v}_c)}{\sum_w \exp(\mathbf{u}_w^\top \mathbf{v}_c)}\,\mathbf{v}_c \;=\; \big(1 - P(o\mid c)\big)\,\mathbf{v}_c \tag{3.10} $$而对错误的 outside 词 $w'\ne o$:
$$ \frac{\partial}{\partial \mathbf{u}_{w'}}\log P(o\mid c) \;=\; -P(w' \mid c)\,\mathbf{v}_c \tag{3.11} $$合起来:真实词的 outside 向量被往 $\mathbf{v}_c$ 方向推,其他词的 outside 向量被往 $\mathbf{v}_c$ 反方向拉。这就是 word2vec 学习的几何机制。
3.5 参数张量 θ:维度核算
有 $|V|$ 个词,每个词维护 2 个 $d$ 维向量,所以 $\theta\in\RR^{2d|V|}$。常见量级:
| 设定 | |V| | d | |θ|(参数量) |
|---|---|---|---|
| Mikolov 2013 (Google News) | 3M | 300 | 1.8 × 10⁹ |
| 本课程作业 (a1, 截取语料) | ~20K | 50–100 | ~ 2–4 M |
| GloVe-840B (Common Crawl) | 2.2M | 300 | 1.32 × 10⁹ |
10 亿级参数听起来吓人,但全是embedding 查表,没有 dense MLP/attention,磁盘存储约 4 GB(float32)即可。
练习 3.1 — 推导题
(A)从 (3.5) 出发独立推出 (3.9)。(B)证明 $\sum_{x\in V} P(x\mid c)=1$(提示:softmax 性质)。(C)若把 softmax 改为 max 函数(即 argmax 输出 one-hot),(3.9) 的梯度变成什么形式?说明这种"hard"版本为何无法用 SGD 训练。练习 3.2 — 数值题
设 $|V|=10000$, $d=100$, 中心词 c = "into",已知 $\mathbf{v}_c = (0.1, 0.2, \ldots)$(虚构数)。若一次梯度更新需要对 (3.9) 的求和遍历全词表,估计单次 SGD 步骤的浮点数运算量(FLOPs),并解释为何这促使了下一节负采样的提出。4 · 优化:从 GD 到 SGD
4.1 批量梯度下降 (Batch GD)
梯度下降的核心思想:把"目标函数 $J(\theta)$"想成一座山,每一步沿 负梯度(最陡下坡)方向走一小段:
$$ \theta^{\text{new}} = \theta^{\text{old}} - \alpha\, \nabla_\theta J(\theta) \tag{4.1} $$ $$ \theta_j^{\text{new}} = \theta_j^{\text{old}} - \alpha\, \frac{\partial}{\partial \theta_j^{\text{old}}} J(\theta) \tag{4.2} $$其中 $\alpha$ 称为 step size 或 学习率(learning rate)。伪代码:
while True:
theta_grad = evaluate_gradient(J, corpus, theta) # 用全语料计算
theta = theta - alpha * theta_grad
4.2 随机梯度下降 (SGD)
问题:$J(\theta)$ 是整个语料所有窗口 的和($T$ 通常 $10^9$ 级)。一次 batch GD 要算整个 corpus 才能更新一次——谁等得起?解决方案是 SGD:每次只用一个窗口估计梯度:
while True:
window = sample_window(corpus)
theta_grad = evaluate_gradient(J, window, theta)
theta = theta - alpha * theta_grad
更工程化的版本是 mini-batch SGD:每次抽 $B$ 个窗口(典型 $B\in\{32, 64, 128, 256\}$),平均它们的梯度后更新。好处:
- GPU 并行,吞吐量提升;
- 梯度方差降低($\propto 1/B$),训练更稳;
- 仍保持随机性,能逃局部极小/鞍点。
4.3 稀疏梯度更新
关键工程观察:在 (3.9) 的梯度公式里,大部分词的 $\mathbf{u}_w$ 没被这次窗口"看见",它们的梯度为 0;只有窗口内的 $2m+1$ 个词 + 负采样的 $2km$ 个噪声词需要更新。整个梯度向量 $\nabla_\theta J_t(\theta)\in\RR^{2dV}$ 是极度稀疏的:
$$ \nabla_\theta J_t(\theta) \;=\; \big[\,0,\ldots,0,\ \nabla_{\mathbf{v}_{\text{like}}},\ 0,\ldots,0,\ \nabla_{\mathbf{u}_{I}},\ \ldots,\ \nabla_{\mathbf{u}_{\text{learning}}},\ldots,0,\ldots,0\,\big]^\top \tag{4.3} $$nn.Embedding(..., sparse=True) + SparseAdam)只更新出现的行;(b) 用稠密更新但仅在用到的行处梯度非零(实现简单,多算几次 0 即可)。在分布式训练中(a)是必须的——否则每次都要广播 $2d|V|$ 大小的全量梯度。
SGD 在现代 LLM 中的演化
2026 年训练 LLM 时几乎没人直接用 vanilla SGD:人们用 AdamW、Lion、Sophia 等带自适应学习率和动量的优化器。但所有这些方法的骨架都是 (4.1):你算出当前梯度,然后按某种方式更新参数。理解 SGD 是理解 Adam 的前提。建议自己实现一遍 SGD(10 行)→ Momentum SGD → AdaGrad → Adam,体会从 5 行到 20 行的复杂度跃迁。练习 4.1
若学习率 $\alpha$ 过大,梯度下降会出现什么现象?过小呢?画出 1-D 抛物线 $J(\theta)=\theta^2$ 上分别 $\alpha=0.1, 0.5, 1.0, 1.1$ 时连续 5 步迭代的轨迹。5 · 算法家族:CBOW / SG / 负采样
5.1 两种模型变体
| 变体 | 预测方向 | 用途偏好 |
|---|---|---|
| Skip-gram (SG) | 中心词 c → 多个上下文词 o (本讲推导的就是这个) | 低频词效果更好;小语料;分析任务 |
| CBOW (Continuous Bag-of-Words) | 多个上下文词的平均 → 中心词 | 高频词更准;训练更快;当年 Google News 默认 |
原 PPT 推导的是 SG。CBOW 的 loss 留作练习。
5.2 负采样:把 softmax 分母搞掉
(3.3) 的分母 $\sum_{w\in V}\exp(\mathbf{u}_w^\top \mathbf{v}_c)$ 每步都要遍历全词表,$|V|=10^6$ 时这是计算瓶颈。负采样 (Negative Sampling, Mikolov 2013b) 把"多分类"问题转成"$K+1$ 个二分类"问题:
$$ J_{\text{neg-sample}}(\mathbf{u}_o,\mathbf{v}_c,U) = -\log \sigma(\mathbf{u}_o^\top \mathbf{v}_c) - \sum_{k\in \{K \text{ sampled}\}} \log \sigma(-\mathbf{u}_k^\top \mathbf{v}_c) \tag{5.1} $$其中 $\sigma(x)=1/(1+e^{-x})$ 是 sigmoid。直观理解:
- 第一项:让真实的 (c, o) 对的 sigmoid 接近 1;
- 第二项:让 $K$ 个随机抽样的(噪声)词 $w_k$ 与 $c$ 的 sigmoid 接近 0(即 $-\mathbf{u}_k^\top\mathbf{v}_c$ 大)。
所以现在每步只需要 $K+1$ 次内积,独立于 |V|。典型 $K\in\{5,10,20\}$(小语料用大 K)。
5.3 抽样分布:那个神秘的 3/4 power
负样本不是均匀抽,而是按修正的 unigram 分布:
$$ P(w) = \frac{U(w)^{3/4}}{Z},\quad Z=\sum_{w'\in V}U(w')^{3/4} \tag{5.2} $$其中 $U(w)$ 是 $w$ 在语料中的频率。
为何 3/4 次幂?
若直接按 $U(w)$ 抽,最高频词(the, of, a)几乎垄断了所有负样本,模型只学会"和 the 不一样"而无法区分中频词。若按均匀分布抽,又会出现大量极罕见词当负样本——它们本来概率就极低,没什么信号。3/4 是 Mikolov 用 grid search 找到的折中:把 0.9 → 0.92、0.01 → 0.032,压扁高频、抬升低频。这是个纯工程经验值,没有理论保证,但事实证明跨语料都很 robust。负采样 ≈ 矩阵分解:Levy & Goldberg 2014 的重大发现
2014 年 Levy & Goldberg 在 NeurIPS 上证明了:SGNS(skip-gram with negative sampling)实质上在隐式地分解 shifted PMI 矩阵: $$M_{ij}=\text{PMI}(w_i,c_j)-\log K,\quad \text{PMI}(w,c)=\log\frac{P(w,c)}{P(w)P(c)}$$ 这把"神经"方法和"计数"方法(GloVe / LSA)统一在一个矩阵分解框架下,是 word embedding 理论上最重要的论文之一。研究生应当读原文。5.4 "Bag of Words" 警告
由于 word2vec 对位置不敏感(窗口内任何相对位置都给同一个 P 估计),它本质上是 词袋模型。在一个句子里,"dog bites man" 与 "man bites dog" 学到的中心-上下文统计是一样的。这是 word2vec 的根本局限——也是 Transformer 用 positional encoding + self-attention 试图修复的事。
练习 5.1
推导 CBOW 的目标函数。设上下文词向量为 $\bar{\mathbf{v}} = \tfrac{1}{2m}\sum_{j\ne 0}\mathbf{v}_{w_{t+j}}$,写出 $P(w_t \mid \bar{\mathbf{v}})$ 和负采样版本的损失。练习 5.2
(理论题)证明 (5.1) 中的 sigmoid 损失等价于:把"是否为真实 (c,o) 对"看作 Bernoulli 变量、做最大似然估计。6 · 计数法路线:从共现矩阵到 GloVe
6.1 一个困惑:我们为什么要"遍历语料"?
PPT 上 Manning 半开玩笑地说:"There's something weird about iterating through the whole corpus (perhaps many times); why don't we just accumulate all the statistics of what words appear near each other?!?" —— 这其实是 NLP 早 20 年的主流思路:直接统计共现。让我们看看它能走多远。
6.2 共现矩阵 X
给定语料和窗口大小,构造矩阵 $X\in\RR^{|V|\times |V|}$:$X_{ij}$ = 词 $i$ 与词 $j$ 在窗口内共同出现的次数。两种主流变体:
- 窗口共现:类似 word2vec,捕捉句法+语义(产出"word space");
- 词-文档:$X_{ij}$ = 词 $i$ 在文档 $j$ 中的频次,捕捉主题(产出"document space",即 LSA, Latent Semantic Analysis)。
例子(PPT 第 38 页, window=1, symmetric):
三个句子:
- I like deep learning .
- I like NLP .
- I enjoy flying .
把 $X$ 的第 $i$ 行直接当作词 $i$ 的向量?三个问题:
- 维度爆炸:向量长度随 $|V|$ 增长 → 存储 $O(|V|^2)$;
- 稀疏:大部分元素为 0,下游模型不 robust;
- 不平衡:高频词(the, of)共现数极大,主导相似度。
6.3 SVD 降维 → LSA
经典做法是奇异值分解(Singular Value Decomposition):
$$ X = U\,\Sigma\,V^\top,\quad U\in\RR^{|V|\times r},\ \Sigma\in\RR^{r\times r}_{\ge 0},\ V\in\RR^{|V|\times r} \tag{6.1} $$截断到 top-$k$ 个奇异值得到秩-$k$ 最佳近似 $\hat{X}_k$(Eckart-Young 定理,最小化 Frobenius 范数)。词向量 = $U_k$ 的前 $k$ 列。
为何对原始 X 直接 SVD 不 work?
原始 $X$ 的元素跨度太大:function words ("the", "he", "has") 在每个窗口都出现,共现数动辄上万;内容词只有几次。SVD 倾向于优先解释那些数值最大的元素,结果第一主成分常常是"the-likeness"——这显然不是我们要的语义。解决方案:- 对 cell 取对数:$X' = \log(1 + X)$
- 截顶:$X' = \min(X, 100)$
- 直接丢弃 stop words
- 用 ramped window(离中心越远权重越低)
- 用 PPMI(positive pointwise mutual information)替代原始 count
6.4 GloVe (Pennington, Socher, Manning, EMNLP 2014)
GloVe(Global Vectors)的设计哲学:结合 word2vec 的"局部窗口梯度学习"和 LSA 的"全局共现统计"。它的灵感来自一个关键观察。
观察:两个词的差异不应反映在绝对共现概率上,而应反映在共现概率的比值上。例如:
| x = | solid | gas | water | random |
|---|---|---|---|---|
| P(x|ice) | 1.9×10⁻⁴ | 6.6×10⁻⁵ | 3.0×10⁻³ | 1.7×10⁻⁵ |
| P(x|steam) | 2.2×10⁻⁵ | 7.8×10⁻⁴ | 2.2×10⁻³ | 1.8×10⁻⁵ |
| P(x|ice)/P(x|steam) | 8.9 (大) | 0.085 (小) | 1.36 | 0.96 |
"ice 比 steam 更 solid"、"ice 不如 steam 那么 gas"——这种结构性 信息在比值里。GloVe 的设计目标:让词向量的算术运算线性地编码 log 共现比值。
形式上他们假设:
$$ \mathbf{w}_i \cdot \mathbf{w}_j = \log P(i \mid j), \quad\text{从而}\quad \mathbf{w}_x \cdot (\mathbf{w}_a - \mathbf{w}_b) = \log\frac{P(x\mid a)}{P(x \mid b)} \tag{6.2} $$把 $P(i\mid j)=X_{ij}/X_j$ 代入,整理后得到一个对称化的加权最小二乘损失:
$$ J = \sum_{i,j=1}^{V} f(X_{ij}) \Big(\mathbf{w}_i^\top \tilde{\mathbf{w}}_j + b_i + \tilde{b}_j - \log X_{ij}\Big)^2 \tag{6.3} $$其中 $f$ 是权重函数(避免高频共现 dominate、避免零共现 NaN):
$$ f(x) = \begin{cases} (x/x_{\max})^{\alpha} & x < x_{\max}\\ 1 & x\ge x_{\max}\end{cases},\quad x_{\max}=100, \alpha = 3/4 \tag{6.4} $$GloVe 的优势:
- 训练快:直接对 $X$ 做加权回归,无需扫语料;
- 规模化:原作者训练到 840B tokens;
- 线性结构强:在类比任务上 SOTA(见 §7)。
6.5 统一视角:所有 word embedding 都在做矩阵分解
SGNS, GloVe, LSA 的统一解释
| 方法 | 分解的矩阵 | 近似目标 |
|---|---|---|
| LSA / SVD | X 或 log X | min ||X − UΣV^⊤||_F |
| SGNS | PMI(w,c) − log K | 隐式(Levy & Goldberg 2014) |
| GloVe | log X_ij | weighted least squares (6.3) |
练习 6.1
(推导题)从假设 $\mathbf{w}_i^\top \mathbf{w}_j = \log P(i\mid j)$ 出发,证明它同时 满足 $\mathbf{w}_j^\top \mathbf{w}_i = \log P(j\mid i)$ 当且仅当 $P(i\mid j)P(j) = P(j\mid i)P(i)$(即贝叶斯定理)。这解释了为何 GloVe 需要 (6.3) 中两个偏置 $b_i, \tilde{b}_j$ 来吸收边际概率。7 · 评测词向量
7.1 内在 vs 外在评测
| Intrinsic 内在 | Extrinsic 外在 | |
|---|---|---|
| 对象 | 词向量自身的几何性质 | 下游任务表现 |
| 例子 | 类比、相似度、聚类 | NER, QA, sentiment, MT |
| 速度 | 分钟级 | 小时~天 |
| 风险 | 与真实任务相关性未知 | 难判断瓶颈在 embedding 还是模型 |
7.2 内在评测 ① — 词向量类比
经典任务:man : woman :: king : ?,期望答案 queen。具体做法:
$$ d = \arg\max_{i\in V \setminus \{a,b,c\}} \frac{(\mathbf{x}_b - \mathbf{x}_a + \mathbf{x}_c)^\top \mathbf{x}_i}{\lVert \mathbf{x}_b - \mathbf{x}_a + \mathbf{x}_c\rVert \cdot \lVert\mathbf{x}_i\rVert} \tag{7.1} $$注意三点:
- 评价指标是 余弦相似度(除范数),不是纯内积;
- 必须把输入词 $a,b,c$ 从候选里剔除(否则答案常常是输入词本身);
- 这个 trick 叫 3CosAdd;改进版 3CosMul(Levy & Goldberg 2014)效果更好。
GloVe 在 Wikipedia + Gigaword 上学到的词向量在二维 PCA 投影下能清晰展示:
- 性别:man↔woman, king↔queen, uncle↔aunt, nephew↔niece —— 这些对的差向量近似平行;
- 头衔/地位:sir↔madam, earl↔duchess, king↔queen, emperor↔empress;
- 家族关系:sister/brother, niece/nephew, heir/heiress;
- 动词→名词:swim→swimmer, drive→driver, teach→teacher(COALS 图)。
线性结构来自哪里?
若词向量满足 $\mathbf{w}_i\cdot \mathbf{w}_j = \log P(i\mid j)$(GloVe 假设),那么 $\mathbf{w}_x\cdot(\mathbf{w}_a-\mathbf{w}_b) = \log\frac{P(x|a)}{P(x|b)}$,是log 比值,自然满足"对称差"性质:$\log\frac{P(x|a)}{P(x|b)} = \log\frac{P(x|c)}{P(x|d)}$ ⟺ 上下文相似度比相同。
所以类比可解 不是巧合,而是 GloVe 损失函数直接逼出来的代数性质。SGNS 也大致继承了这个性质(因为它隐式分解 PMI,PMI 也有 log 形式)。
7.3 内在评测 ② — 相似度任务
给定一组人类标注的词对相似度(例如 WordSim-353:tiger-cat=7.35, stock-jaguar=0.92),计算词向量余弦相似度,与人类打分做 Spearman 相关。常用 benchmark:
| 数据集 | 词对数 | 说明 |
|---|---|---|
| WordSim-353 (WS353) | 353 | 最经典;混合 similarity 与 relatedness |
| MC (Miller-Charles) | 30 | 极小但极干净 |
| RG (Rubenstein-Goodenough) | 65 | 名词对,1965 年的标注 |
| SCWS (Huang) | 2003 | 带上下文,可评 polysemy |
| RW (Rare Word) | 2034 | 低频词,挑战 OOV/morphology |
原 PPT 给出的一组对照(Spearman ρ × 100):
| Model | Size | WS353 | MC | RG | SCWS | RW |
|---|---|---|---|---|---|---|
| SVD | 6B | 35.3 | 35.1 | 42.5 | 38.3 | 25.6 |
| SVD-S | 6B | 56.5 | 71.5 | 71.0 | 53.6 | 34.7 |
| SVD-L | 6B | 65.7 | 72.7 | 75.1 | 56.5 | 37.0 |
| CBOW | 6B | 57.2 | 65.6 | 68.2 | 57.0 | 32.5 |
| SG | 6B | 62.8 | 65.2 | 69.7 | 58.1 | 37.2 |
| GloVe | 6B | 65.8 | 72.7 | 77.8 | 53.9 | 38.1 |
| GloVe | 42B | 75.9 | 83.6 | 82.9 | 59.6 | 47.8 |
三个关键 takeaways:
- SVD 的简单版(hack 后的 SVD-L)已经接近神经方法——"counting 不死"。
- 语料越大越好:GloVe 从 6B → 42B token,几乎所有指标都跳 8-10 点。
- 低频词(RW)是公认难点:所有方法都掉到 30-50 区间,是 fastText 后来引入字符 n-gram 的原因。
7.4 外在评测 — NER 案例
命名实体识别 (Named Entity Recognition):识别句子中的人名、地名、机构名。例 "Chris Manning lives in Palo Alto." → (Chris Manning, PER), (Palo Alto, LOC)。把 word embedding 当 feature 喂给 NER 分类器(CRF 或 BiLSTM),比较 F1。
| Embedding | Dev | Test | ACE | MUC7 |
|---|---|---|---|---|
| Discrete (one-hot/手工特征) | 91.0 | 85.4 | 77.4 | 73.4 |
| SVD | 90.8 | 85.7 | 77.3 | 73.7 |
| HPCA | 92.6 | 88.7 | 81.7 | 80.7 |
| CBOW | 93.1 | 88.2 | 82.2 | 81.1 |
| GloVe | 93.2 | 88.3 | 82.9 | 82.2 |
结论:在外在任务上 GloVe 略胜 SG/CBOW,是 2015 年前后 NLP pipeline 的默认选择。
练习 7.1
WordSim-353 的问题:tiger-cat 和 plane-car 都是 ~7 分。但前者是 "is-a" 关系,后者是 "co-hyponym"。若你设计一个 NER 系统,哪种关系对你更有用?为什么这暴露了"intrinsic"评测的根本局限?练习 7.2 — 编程题
下载 GloVe.6B.50d,写一个 Python 函数analogy(a,b,c,topk=5),实现 (7.1)。在 5 组类比上测试:(king,man,woman)、(Paris,France,Japan)、(big,bigger,small)、(running,run,walk)、(cat,cats,dog)。
8 · 最小化 PyTorch 实现:40 行 SGNS
下面是一个能跑、能验证的 skip-gram + negative sampling 极简实现。删除注释后正好 38 行。建议你 fork 并在 Penn Treebank 子集上跑一次。
import torch, torch.nn as nn, torch.nn.functional as F
from torch.utils.data import DataLoader, Dataset
import random, collections
class SGNS(nn.Module):
def __init__(self, V, d):
super().__init__()
self.v = nn.Embedding(V, d) # center vectors v_w
self.u = nn.Embedding(V, d) # outside vectors u_w
nn.init.uniform_(self.v.weight, -0.5/d, 0.5/d)
nn.init.zeros_(self.u.weight)
def forward(self, c, o_pos, o_neg):
# c: (B,) o_pos: (B,) o_neg: (B, K)
vc = self.v(c) # (B, d)
uo = self.u(o_pos) # (B, d)
Uk = self.u(o_neg) # (B, K, d)
pos = F.logsigmoid((vc * uo).sum(-1)) # (B,)
neg = F.logsigmoid(-(Uk * vc.unsqueeze(1)).sum(-1)) # (B, K)
return -(pos + neg.sum(-1)).mean() # scalar
class SGNSData(Dataset):
def __init__(self, tokens, w2i, window=5, K=5):
self.tok = [w2i[w] for w in tokens]; self.w = window; self.K = K
freq = collections.Counter(self.tok)
p = torch.tensor([freq[i]**0.75 for i in range(len(w2i))])
self.p = p / p.sum() # 3/4-power dist
def __len__(self): return len(self.tok)
def __getitem__(self, i):
c = self.tok[i]
j = random.choice([k for k in range(-self.w, self.w+1)
if k != 0 and 0 <= i+k < len(self.tok)])
o = self.tok[i+j]
neg = torch.multinomial(self.p, self.K, replacement=True)
return c, o, neg
def train(tokens, w2i, d=100, lr=1e-3, epochs=3, batch=512):
model = SGNS(len(w2i), d)
opt = torch.optim.Adam(model.parameters(), lr=lr)
loader = DataLoader(SGNSData(tokens, w2i), batch_size=batch, shuffle=True)
for ep in range(epochs):
for c, o, neg in loader:
opt.zero_grad(); loss = model(c, o, neg); loss.backward(); opt.step()
print(f"epoch {ep} loss {loss.item():.4f}")
return (model.v.weight + model.u.weight).detach() / 2 # 平均两套向量
几个工程细节值得讲:
nn.init.uniform_(self.v.weight, -0.5/d, 0.5/d)+zeros_(self.u.weight):原作者的初始化策略,避免初期 $\mathbf{u}^\top\mathbf{v}$ 爆炸;F.logsigmoid而不是torch.log(torch.sigmoid(...)):数值稳定,避免 log(0);torch.multinomial(self.p, K, replacement=True):经验上 K=5 对小语料、K=2 对大语料;- 最后平均 两套向量 $\tfrac{1}{2}(V+U)$ 作为最终 embedding,是经验上的小提升技巧;
- 真正的 word2vec C 代码还做了 subsampling:以概率 $1-\sqrt{t/f(w)}$ 跳过高频词($t\approx 10^{-5}$)。这能进一步加速并提升低频词质量。
9 · 通向现代 LLM:word2vec 在 2026 年还有意义吗?
简短答案:有,但角色变了。
| 2013–2017 (静态时代) | 2018 后 (上下文化时代) |
|---|---|
| word2vec / GloVe 是 NLP pipeline 的第一道工序 | 是 Transformer 输入层的初始化或对照 |
| 下游任务 = embedding + LSTM/CNN + softmax | 下游任务 = pretrained Transformer + 小幅 fine-tune |
| 每个词一个向量 | 每个词每个上下文一个向量(contextualized) |
| 无法处理 OOV | BPE/SentencePiece 子词切分 → 几乎不 OOV |
9.1 word2vec → Transformer token embedding
Transformer 的第一层是 nn.Embedding(V_subword, d_model)——本质和 word2vec 的 $U$ 矩阵完全一样。区别在于:
- 这个矩阵在 LLM 中和后面 12-96 层 self-attention 端到端训练,而不是单独学;
- 词表是 BPE/sentencepiece 子词单位(GPT-2: 50257, LLaMA-3: 128256),不是 word;
- 初始化用 Gaussian 而不是 word2vec 的输出(虽然有研究说预训练 word2vec 初始化能加速收敛)。
9.2 word2vec ↔ contrastive learning
仔细看 SGNS 损失 (5.1):
- "真正"对 (c, o) → 拉近向量(正样本)
- "随机"对 (c, w_k) → 推远向量(负样本)
这正是 contrastive learning 的范式!2020 年后 SimCLR / InfoNCE / CLIP 在视觉和多模态领域大火,它们的损失函数(InfoNCE)几乎是 SGNS 的连续推广:
$$ \mathcal{L}_{\text{InfoNCE}} = -\log \frac{\exp(\mathbf{q}^\top \mathbf{k}_+/\tau)}{\sum_{i=0}^{K}\exp(\mathbf{q}^\top \mathbf{k}_i/\tau)} \tag{9.1} $$把 $\mathbf{q}=\mathbf{v}_c$, $\mathbf{k}_+=\mathbf{u}_o$, $\mathbf{k}_i=\mathbf{u}_k$ 代入、温度 $\tau=1$,你就得到了 softmax 风格的 SGNS。所以——word2vec 是 contrastive learning 在文本上最早的 successful instance。
9.3 静态 vs 上下文:词义偏置 (bias) 的发现
word2vec 的线性结构带来一个意外副作用:偏置也是线性的。Bolukbasi et al. 2016 著名地证明 "man:computer_programmer :: woman:?" → "homemaker"。这开启了 NLP fairness 的研究方向。静态 embedding 的偏置是数据集偏置的最忠实化石——这对 2026 年的 LLM alignment 工作仍有借鉴意义。
三个建议性扩展阅读
- fastText (Bojanowski et al. 2017):用字符 n-gram embedding 之和表示词,OOV-free,多语言效果提升显著。
- ELMo (Peters et al. 2018, NAACL best paper):把双向 LSTM 的所有层向量做加权和——第一个真正成功的 contextualized embedding。
- BERT (Devlin et al. 2019):用 Transformer + masked LM 取代 LSTM,把 NLP pipeline 推向 fine-tune 范式。
📚 参考文献
- Mikolov 2013a — Mikolov, T., Chen, K., Corrado, G., & Dean, J. (2013). Efficient Estimation of Word Representations in Vector Space. ICLR Workshop.
arXiv:1301.3781 - Mikolov 2013b — Mikolov, T., Sutskever, I., Chen, K., Corrado, G. S., & Dean, J. (2013). Distributed Representations of Words and Phrases and their Compositionality. NeurIPS.
arXiv:1310.4546(此篇含负采样、subsampling、phrase 检测) - Pennington 2014 — Pennington, J., Socher, R., & Manning, C. D. (2014). GloVe: Global Vectors for Word Representation. EMNLP.
- Levy & Goldberg 2014 — Levy, O., & Goldberg, Y. (2014). Neural Word Embedding as Implicit Matrix Factorization. NeurIPS. (证明 SGNS ≈ shifted PMI 分解)
- Levy, Goldberg & Dagan 2015 — Improving Distributional Similarity with Lessons Learned from Word Embeddings. TACL. (强烈推荐的统一视角综述)
- Bojanowski 2017 — Bojanowski, P., Grave, E., Joulin, A., & Mikolov, T. (2017). Enriching Word Vectors with Subword Information. TACL. (fastText)
- Bolukbasi 2016 — Bolukbasi, T., Chang, K.-W., Zou, J., Saligrama, V., & Kalai, A. (2016). Man is to Computer Programmer as Woman is to Homemaker? Debiasing Word Embeddings. NeurIPS.
- Rohde 2005 — Rohde, D., Gonnerman, L., & Plaut, D. (2005). An Improved Model of Semantic Similarity Based on Lexical Co-Occurrence. ms. (COALS)
- Firth 1957 — Firth, J. R. (1957). A synopsis of linguistic theory, 1930–1955. Studies in Linguistic Analysis, 1–32.
- Goldberg & Levy 2014 — word2vec Explained: Deriving Mikolov et al.'s Negative-Sampling Word-Embedding Method.
arXiv:1402.3722(本讲推导的"教师版",强烈推荐细读)
🔖 术语速查
| 中文 / 英文 | 定义 | 本讲位置 |
|---|---|---|
| 分布式语义 / distributional semantics | 词义由其上下文决定 | §1.4 |
| 分布式表示 / distributed representation | 词义分摊到所有维度(≠ localist one-hot) | §1.4 |
| 中心词 v_c / 上下文词 u_o | word2vec 的两套向量;分别对应词作为"被预测端"和"预测者"的角色 | §2.2 |
| softmax | 把实向量映射为概率分布;多分类标配 | §3.2 |
| 负采样 / Negative Sampling | 用 K 个二分类代替 |V| 分类,绕开 softmax 分母 | §5.2 |
| 3/4 power 采样 | P(w) ∝ U(w)^{3/4},压扁高频、抬升低频 | §5.3 |
| 共现矩阵 X | X_ij = i 与 j 在窗口内共同出现的次数 | §6.2 |
| SVD / LSA | X = UΣV^⊤;截断 → 低秩词向量 | §6.3 |
| GloVe | 对 log X_ij 做加权最小二乘回归,得到与窗口梯度等价的全局解 | §6.4 |
| 类比 / analogy | man:woman :: king:? → 用向量加减求 cos 最近邻 | §7.2 |
| WordSim-353 | 353 词对人工相似度评分,最常用的 intrinsic 评测集 | §7.3 |
| NER | 命名实体识别;word vector 的标准 extrinsic 评测任务 | §7.4 |
| SGNS | Skip-Gram with Negative Sampling,word2vec 工程默认实现 | §5.2 §8 |
教材编纂:由 Claude (Opus 4.7) 基于 CS224N Winter 2026 Lecture 2 by Diyi Yang + 经典文献综合编写 · 整理日期 2026-05-17 · 单文件本地 HTML