查看全课大纲(第 19 / 69 节)
  1. 1.NLP 的研究领域、应用与学习路径
  2. 2.自然语言的基本术语
  3. 3.信息论基础:信息熵与交叉熵
  4. 4.语言的进化与语义变迁
  5. 5.主观概率、客观概率与条件概率
  6. 6.贝叶斯原理与推理
  7. 7.随机变量:二项式、期望方差与联合概率
  8. 8.常见概率分布
  9. 9.辛普森悖论与贝叶斯解题实例
  10. 10.语言模型:语言概率与词袋模型
  11. 11.n-gram 语言模型(二元 / 三元 / N-Gram)
  12. 12.语言模型评价:交叉熵、困惑度与插值
  13. 13.朴素贝叶斯文本分类:垃圾邮件
  14. 14.拼写检查
  15. 15.中文分词:构词法、最大匹配、最优路径与 Jieba
  16. 16.词表示问题与语义相似度
  17. 17.TF-IDF 权重处理
  18. 18.One-Hot 表达与词表示的局限
  19. 19.Word2Vec 核心思想
  20. 20.Word2Vec 训练过程
  21. 21.Skip-gram 模型详解
  22. 22.词性标注任务与标注方法(规则 + N-Gram)
  23. 23.EM 算法与混合模型
  24. 24.高斯混合模型 GMM
  25. 25.从混合模型到隐马尔可夫模型
  26. 26.隐马尔可夫模型(HMM)推导与维特比解码
  27. 27.线性链条件随机场 CRF
  28. 28.贝叶斯网络与图模型
  29. 29.隐马尔可夫链与 HMM 推导
  30. 30.PLSA 主题模型
  31. 31.LSI 与 SVD 向量表达
  32. 32.LDA 与狄利克雷分布
  33. 33.主题模型实验复现(困惑度 / 分类 / 相似度 / 延展)
  34. 34.上下文无关文法(CFG)与句法分析
  35. 35.概率上下文无关文法 PCFG
  36. 36.统计机器翻译:词对齐与翻译模型
  37. 37.统计机器翻译中的对齐模型与参数估计
  38. 38.从统计机器翻译到神经机器翻译
  39. 39.神经元与反向传播速览(指向深度学习课)
  40. 40.CNN 原理及其在 NLP 中的应用
  41. 41.循环神经网络的基本原理与 Elman / Jordan 网络
  42. 42.LSTM:长短期记忆网络的核心思想与分步实现
  43. 43.Encoder-Decoder 框架
  44. 44.Seq2Seq 与早期注意力机制
  45. 45.注意力机制的背景与动机
  46. 46.注意力模型实现原理与匹配函数
  47. 47.记忆网络:组成与计算
  48. 48.注意力机制的应用与历史延展
  49. 49.Transformer 结构:Encoder-Decoder 栈与 Self-Attention
  50. 50.Multi-Head Attention、FFNN 与位置编码
  51. 51.层归一化、损失函数与 Universal Transformer 延展
  52. 52.预训练范式:从 ELMo 到 BERT
  53. 53.BERT 与掩码语言模型
  54. 54.BERT 下游任务微调与 GLUE 口径
  55. 55.GPT 与自回归语言建模
  56. 56.GPT-1 到 GPT-4 的演进
  57. 57.指令微调与 RLHF
  58. 58.分词器:BPE、WordPiece 与中文词表
  59. 59.上下文窗口与长文本处理
  60. 60.能力边界、成本与适用场景
  61. 61.文本分类实战:从朴素贝叶斯到逻辑回归
  62. 62.命名实体识别实战
  63. 63.文本生成与摘要实战
  64. 64.语义检索与向量库实战
  65. 65.RAG 知识库问答
  66. 66.NLP 评估指标:BLEU / ROUGE / BERTScore 与人工评估
  67. 67.幻觉与事实性问题
  68. 68.文本与知识结合(知识图谱压缩)
  69. 69.跨媒体信息检索与未来展望

Word2Vec 核心思想

小象实战讲义 · 自然语言处理

在上一节,我们探讨了基于统计的共现矩阵方法(如 TF-IDF、PMI)来获取词向量。这些方法直观,但面临稀疏性和计算效率的挑战。本节我们将进入词向量学习的经典里程碑——Word2Vec。它通过一个精巧的神经网络模型,从大规模文本中高效学习出高质量的稠密词向量,其核心思想“通过上下文预测中心词”或“通过中心词预测上下文”深刻影响了后续的表示学习。理解 Word2Vec 不仅是掌握词嵌入的关键,也是通往现代预训练模型的重要基石。

💡 核心导读

  • 从统计到预测:Word2Vec 将词向量学习从一个统计计数问题,转变为一个基于神经网络的预测问题,通过优化一个预测任务来间接学习词向量。
  • 两种经典架构:掌握连续词袋模型(CBOW)和跳字模型(Skip-gram)的核心区别:CBOW 用上下文预测中心词,适合高频词;Skip-gram 用中心词预测上下文,对低频词更友好。
  • 嵌入矩阵的妙用:理解 Word2Vec 模型中“输入嵌入矩阵”和“输出嵌入矩阵”的双重角色,以及它们如何将高维的 One-Hot 向量映射到低维的稠密空间。
  • 效率是关键:初步了解 Word2Vec 为了提升训练效率而引入的层次 Softmax 和负采样技术,它们避免了在全词表上进行昂贵的概率计算。

神经语言模型:Word2Vec 的思想源头

在深入 Word2Vec 之前,我们需要回顾其思想源头——神经语言模型(Neural Language Model)。传统的 n-gram 语言模型通过统计历史词序列的出现频率来预测下一个词,例如:

  • 二元(Bigram)模型:P(wi∣wi−1)P(w_i | w_{i-1})
  • 三元(Trigram)模型:P(wi∣wi−1,wi−2)P(w_i | w_{i-1}, w_{i-2})

但这种模型面临“维度灾难”:随着历史长度 nn 增加,可能的词序列组合呈指数级增长,导致数据极其稀疏。Bengio 等人在 2003 年提出了一种创新的思路:用一个神经网络函数 ff 来逼近整个历史序列对当前词的联合影响。

其核心公式可以抽象为: P(wi∣wi−1,wi−2,...,wi−n+1)≈f(vwi−1,vwi−2,...,vwi−n+1)P(w_i | w_{i-1}, w_{i-2}, ..., w_{i-n+1}) \approx f(\mathbf{v}_{w_{i-1}}, \mathbf{v}_{w_{i-2}}, ..., \mathbf{v}_{w_{i-n+1}})

这里,vw\mathbf{v}_{w} 是词 ww 的稠密向量表示(即词向量)。模型的工作流程如下:

  1. 将固定窗口内的 n−1n-1 个历史词的 One-Hot 向量,分别乘以一个共享的嵌入矩阵 E\mathbf{E},得到它们的稠密向量表示。
  2. 将这些稠密向量拼接或平均后,输入到一个多层前馈神经网络中。
  3. 网络输出层是一个 Softmax,产生在整个词表 VV 上的概率分布,目标是使真实下一个词 wiw_i 的概率最大。

通过反向传播算法,同时优化神经网络的权重参数 θ\theta 和嵌入矩阵 E\mathbf{E}。训练完成后,矩阵 E\mathbf{E} 的每一行就对应一个词的词向量。

这个模型的重大意义在于:

  • 分布式表示:词的含义被分布在一个低维连续向量的各个维度上,语义相似的词会有相似的向量。
  • 自动特征学习:神经网络自动从数据中学习出有效的特征表示,而非人工设计。

然而,原始的神经语言模型计算成本很高,因为输出层的 Softmax 需要在整个词表(可能数万甚至数十万)上进行归一化。Word2Vec 的贡献,正是对上述思想进行了大幅简化,提出了更高效、更专注的词向量学习模型。

Word2Vec 模型架构:CBOW 与 Skip-gram

Word2Vec 摒弃了“预测下一个词”的严格语言模型目标,转而采用更直接的任务来学习词向量:学习词与其上下文之间的关系。它提出了两种具体的模型架构:

连续词袋模型(Continuous Bag-of-Words, CBOW)

CBOW 模型的目标是:给定一个中心词周围的上下文词,预测这个中心词本身。

假设我们有一个句子:... the quick brown fox jumps ...,设定窗口大小为 2。当中心词是 brown 时,其上下文词为 [the, quick, fox, jumps]。

CBOW 模型的处理步骤如下:

  1. 输入层:将上下文窗口中所有 2m2m 个词的 One-Hot 向量作为输入(mm 为单边窗口大小)。
  2. 投影层:每个输入词的 One-Hot 向量与输入嵌入矩阵 V∈R∣V∣×d\mathbf{V} \in \mathbb{R}^{|V| \times d} 相乘,得到其对应的输入词向量 vw\mathbf{v}_w。然后,将所有上下文词的输入向量进行平均,得到一个 dd 维的上下文综合向量。
  3. 输出层:将平均后的上下文向量与另一个输出嵌入矩阵 U∈Rd×∣V∣\mathbf{U} \in \mathbb{R}^{d \times |V|} 相乘,得到一个 ∣V∣|V| 维的分数向量。
  4. Softmax:对分数向量应用 Softmax 函数,得到在词表 VV 上每个词作为中心词的概率分布。
  5. 目标:最大化真实中心词 brown 的概率。

其条件概率公式为: P(wc∣wc−m,...,wc−1,wc+1,...,wc+m)=exp⁡(uwcT⋅vˉ)∑j=1∣V∣exp⁡(ujT⋅vˉ)P(w_c | w_{c-m}, ..., w_{c-1}, w_{c+1}, ..., w_{c+m}) = \frac{\exp(\mathbf{u}_{w_c}^T \cdot \bar{\mathbf{v}})}{\sum_{j=1}^{|V|} \exp(\mathbf{u}_j^T \cdot \bar{\mathbf{v}})} 其中,vˉ=12m∑i≠0vwc+i\bar{\mathbf{v}} = \frac{1}{2m} \sum_{i \neq 0} \mathbf{v}_{w_{c+i}} 是上下文词向量的平均,uwc\mathbf{u}_{w_c} 是输出矩阵 U\mathbf{U} 中对应中心词 wcw_c 的列向量。

跳字模型(Skip-gram)

Skip-gram 模型的目标与 CBOW 相反:给定一个中心词,预测其周围窗口内的每一个上下文词。

同样以句子 ... the quick brown fox jumps ... 为例,中心词为 brown,窗口大小为 2。模型需要分别预测 the, quick, fox, jumps 出现的概率,并假设这些预测是相互独立的。

Skip-gram 模型的处理步骤如下:

  1. 输入层:将中心词的 One-Hot 向量作为输入。
  2. 投影层:输入向量与输入嵌入矩阵 V\mathbf{V} 相乘,得到中心词的输入向量 vwc\mathbf{v}_{w_c}。
  3. 输出层:对于窗口内的每一个目标上下文位置,将中心词向量 vwc\mathbf{v}_{w_c} 与输出嵌入矩阵 U\mathbf{U} 相乘,得到一个 ∣V∣|V| 维的分数向量。
  4. Softmax:对每个分数向量独立应用 Softmax,得到该位置上下文词的概率分布。
  5. 目标:最大化所有上下文词(如 the, quick, fox, jumps)的联合概率(或对数概率之和)。

其条件概率公式为: P(wc+j∣wc)=exp⁡(uwc+jT⋅vwc)∑i=1∣V∣exp⁡(uiT⋅vwc),for j∈[−m,m],j≠0P(w_{c+j} | w_c) = \frac{\exp(\mathbf{u}_{w_{c+j}}^T \cdot \mathbf{v}_{w_c})}{\sum_{i=1}^{|V|} \exp(\mathbf{u}_i^T \cdot \mathbf{v}_{w_c})}, \quad \text{for } j \in [-m, m], j \neq 0 模型目标是最大化平均对数概率: 1T∑t=1T∑−m≤j≤m,j≠0log⁡P(wt+j∣wt)\frac{1}{T} \sum_{t=1}^{T} \sum_{-m \leq j \leq m, j \neq 0} \log P(w_{t+j} | w_t)

CBOW vs. Skip-gram:对比与应用

  • CBOW:使用上下文(多个词)的平滑平均来预测中心词。训练速度通常更快,对高频词的表示学习效果更好。
  • Skip-gram:使用一个中心词来预测多个上下文词。它将每个中心词-上下文词对都视为一个训练样本,因此能产生更多的训练样本,对低频词的表示学习效果更优,在大语料上表现通常更好。

在实际应用中,Skip-gram 更为常用。

从原理到实现:理解嵌入矩阵与计算流程

为了更具体地理解 Word2Vec 的计算过程,我们用一个极简的例子来演示 CBOW 和 Skip-gram 的前向传播步骤。请注意,以下代码仅为教学演示,不涉及实际的训练和优化。

import numpy as np

# ===== 第一部分:定义极简词汇表和参数 =====
# 假设我们的微型词汇表只有4个词
vocab = ["the", "quick", "brown", "fox"]
V = len(vocab)  # 词表大小 = 4
d = 3           # 词向量维度 = 3 (为了演示方便,实际中常为100-300)

# 创建词到索引的映射
word_to_idx = {word: i for i, word in enumerate(vocab)}

# 随机初始化输入嵌入矩阵 V_in (|V| x d) 和输出嵌入矩阵 U_out (d x |V|)
# 注意:在实际Word2Vec中,这两个矩阵都是需要学习的参数。
np.random.seed(42)  # 固定随机种子,确保结果可复现
V_in = np.random.randn(V, d).round(4)  # 输入矩阵
U_out = np.random.randn(d, V).round(4) # 输出矩阵

print("词汇表索引映射:", word_to_idx)
print("\n随机初始化的输入嵌入矩阵 V_in (|V| x d):")
print(V_in)
print("\n随机初始化的输出嵌入矩阵 U_out (d x |V|):")
print(U_out)
词汇表索引映射: {'the': 0, 'quick': 1, 'brown': 2, 'fox': 3}

随机初始化的输入嵌入矩阵 V_in (|V| x d):
[[ 0.4967 -0.1383  0.6477]
 [ 1.523  -0.2342 -0.2341]
 [ 1.5792  0.7674 -0.4695]
 [ 0.5426 -0.4634 -0.4657]]

随机初始化的输出嵌入矩阵 U_out (d x |V|):
[[ 0.242  -1.9133 -1.7249 -0.5623]
 [-1.0128  0.3142 -0.908  -1.4123]
 [ 1.4656 -0.2258  0.0675 -1.4247]]

现在,我们分别模拟 CBOW 和 Skip-gram 的前向传播。


# —— 重新构建上文用到的微型数据(本节各代码块相互独立,可单独运行)
import numpy as np
np.random.seed(42)  # 固定随机种子,确保输出可复现
vocab = ["the", "quick", "brown", "fox"]
V = len(vocab)  # 词表大小 = 4
d = 3           # 词向量维度 = 3 (为了演示方便,实际中常为100-300)
word_to_idx = {word: i for i, word in enumerate(vocab)}
V_in = np.random.randn(V, d).round(4)  # 输入矩阵
U_out = np.random.randn(d, V).round(4) # 输出矩阵

# ===== 第二部分:模拟 CBOW 前向传播 =====
# 假设句子片段 "... quick brown fox ...",窗口大小 m=1
# 中心词是 "brown" (索引2),上下文词是 ["quick", "fox"] (索引1和3)
context_words = ["quick", "fox"]
center_word = "brown"

# 步骤1&2: 获取上下文词的输入向量并平均
context_vec_sum = np.zeros(d)
for word in context_words:
    one_hot = np.zeros(V)
    one_hot[word_to_idx[word]] = 1
    # 通过矩阵乘法获取输入向量: v_w = one_hot^T * V_in
    # 等价于直接取 V_in 的对应行
    word_vec = np.dot(one_hot, V_in)
    context_vec_sum += word_vec

context_avg = context_vec_sum / len(context_words)
print(f"上下文词 '{context_words}' 的平均向量 context_avg:")
print(context_avg.round(4))

# 步骤3: 计算输出分数 (logits)
logits = np.dot(context_avg, U_out)
print(f"\n输出分数向量 logits:")
print(logits.round(4))

# 步骤4: 应用Softmax得到概率分布 (仅为演示,未考虑数值稳定性)
exp_logits = np.exp(logits)
probs = exp_logits / np.sum(exp_logits)
print(f"\n预测的概率分布 (Softmax输出):")
for i, word in enumerate(vocab):
    print(f"  P({word} | context) = {probs[i]:.4f}")

# 步骤5: 计算损失 (交叉熵)
true_center_idx = word_to_idx[center_word]
loss = -np.log(probs[true_center_idx])
print(f"\n对于中心词 '{center_word}' 的交叉熵损失: {loss:.4f}")
上下文词 '['quick', 'fox']' 的平均向量 context_avg:
[ 1.0328 -0.3488 -0.3499]

输出分数向量 logits:
[ 0.0904 -2.0066 -1.4884  0.4104]

预测的概率分布 (Softmax输出):
  P(the | context) = 0.3695
  P(quick | context) = 0.0454
  P(brown | context) = 0.0762
  P(fox | context) = 0.5089

对于中心词 'brown' 的交叉熵损失: 2.5743

# —— 重新构建上文用到的微型数据(本节各代码块相互独立,可单独运行)
import numpy as np
np.random.seed(42)  # 固定随机种子,确保输出可复现
vocab = ["the", "quick", "brown", "fox"]
V = len(vocab)  # 词表大小 = 4
d = 3           # 词向量维度 = 3 (为了演示方便,实际中常为100-300)
word_to_idx = {word: i for i, word in enumerate(vocab)}
V_in = np.random.randn(V, d).round(4)  # 输入矩阵
U_out = np.random.randn(d, V).round(4) # 输出矩阵
context_words = ["quick", "fox"]
center_word = "brown"
context_vec_sum = np.zeros(d)
for word in context_words:
    one_hot = np.zeros(V)
    one_hot[word_to_idx[word]] = 1
    # 通过矩阵乘法获取输入向量: v_w = one_hot^T * V_in
    # 等价于直接取 V_in 的对应行
    word_vec = np.dot(one_hot, V_in)
    context_vec_sum += word_vec
context_avg = context_vec_sum / len(context_words)

# ===== 第三部分:模拟 Skip-gram 前向传播 =====
# 使用相同的词汇表和随机矩阵
# 中心词为 "brown" (索引2),我们希望预测其上下文词,例如 "quick" (索引1) 和 "fox" (索引3)
center_word = "brown"
target_context_words = ["quick", "fox"] # 假设我们只考虑这两个位置

# 步骤1&2: 获取中心词向量
center_one_hot = np.zeros(V)
center_one_hot[word_to_idx[center_word]] = 1
v_c = np.dot(center_one_hot, V_in)  # 中心词向量
print(f"中心词 '{center_word}' 的向量 v_c:")
print(v_c.round(4))

total_log_prob = 0
print("\n对每个目标上下文词进行预测:")
for target_word in target_context_words:
    # 步骤3&4: 计算该目标词的概率
    logits_sg = np.dot(v_c, U_out)
    exp_logits_sg = np.exp(logits_sg)
    probs_sg = exp_logits_sg / np.sum(exp_logits_sg)
    
    target_idx = word_to_idx[target_word]
    target_prob = probs_sg[target_idx]
    target_log_prob = np.log(target_prob)
    total_log_prob += target_log_prob
    
    print(f"  预测 P({target_word} | {center_word}) = {target_prob:.4f}, log prob = {target_log_prob:.4f}")

# 步骤5: 计算平均对数概率 (Skip-gram的目标是最大化这个值)
avg_log_prob = total_log_prob / len(target_context_words)
print(f"\n对上下文词 '{target_context_words}' 的平均对数概率: {avg_log_prob:.4f}")
# 损失通常是负的平均对数概率
loss_sg = -avg_log_prob
print(f"对应的损失 (负的平均对数概率): {loss_sg:.4f}")
中心词 'brown' 的向量 v_c:
[ 1.5792  0.7674 -0.4695]

对每个目标上下文词进行预测:
  预测 P(quick | brown) = 0.0970, log prob = -2.3331
  预测 P(fox | brown) = 0.3823, log prob = -0.9617

对上下文词 '['quick', 'fox']' 的平均对数概率: -1.6474
对应的损失 (负的平均对数概率): 1.6474

通过以上演示,我们可以看到:

  1. 嵌入矩阵是核心:V_in 将 One-Hot 词映射为稠密向量,U_out 用于计算预测分数。训练后,V_in 的行向量通常作为最终的词向量使用(有时也会使用 U_out 的列向量或两者的组合)。
  2. 计算流程清晰:CBOW 先聚合上下文再预测;Skip-gram 直接用中心词进行多次预测。
  3. 效率瓶颈:计算 probs 时需要对整个词表 VV 进行 exp⁡\exp 和求和,当 ∣V∣|V| 很大时(例如 10 万),这一步的计算成本极高。这正是 Word2Vec 提出负采样(Negative Sampling) 和层次 Softmax(Hierarchical Softmax) 等优化技术的根本原因,它们将在下一节详细讨论。

📝 动手练一练

  1. 概念辨析:假设我们有一个训练好的 Word2Vec 模型。现在给定句子“猫在沙发上睡觉”,窗口大小为 2。请分别说明,在 CBOW 和 Skip-gram 模型中,当中心词为“在”时,模型的输入和预测目标分别是什么?
👉 点击查看参考答案
  • CBOW 模型:

    • 输入:中心词“在”的上下文词,即窗口内的词:["猫", "沙发", "上"](注意:“睡觉”超出了窗口)。
    • 预测目标:中心词“在”本身。模型的任务是根据输入的三个上下文词,预测出最可能出现在中间的那个词是“在”。
  • Skip-gram 模型:

    • 输入:中心词“在”本身。
    • 预测目标:中心词“在”的每一个上下文词,即分别预测 P("猫"|"在"), P("沙发"|"在"), P("上"|"在")。模型的任务是,给定“在”,使其周围出现“猫”、“沙发”、“上”这些词的概率尽可能大。
  1. 手算理解:沿用上面代码示例中的微型词汇表 ["the", "quick", "brown", "fox"]、随机初始化的 V_in 和 U_out 矩阵。请手动计算(或写一小段代码验证),在 Skip-gram 模型中,当中心词为 "the" (索引0) 时,模型预测上下文词 "quick" (索引1) 的未归一化的分数(logit)是多少?即计算 uquickT⋅vthe\mathbf{u}_{quick}^T \cdot \mathbf{v}_{the}。提示:vthe\mathbf{v}_{the} 是 V_in 的第0行,uquick\mathbf{u}_{quick} 是 U_out 的第1列。
👉 点击查看参考答案

根据上文代码输出的矩阵(同一组随机初始化参数):

  • vthe\mathbf{v}_{the} = VinV_{in}[0] = [0.4967, -0.1383, 0.6477]
  • uquick\mathbf{u}_{quick} = UoutU_{out}[:, 1] = [-1.9133, 0.3142, -0.2258](UoutU_{out} 的列对应词)

计算点积: score=0.4967×(−1.9133)+(−0.1383)×0.3142+0.6477×(−0.2258)score = 0.4967 \times (-1.9133) + (-0.1383) \times 0.3142 + 0.6477 \times (-0.2258) =(−0.9503)+(−0.0435)+(−0.1463)= (-0.9503) + (-0.0435) + (-0.1463) =−1.1400= -1.1400

所以,未归一化的分数约为 -1.1400。你可以运行以下代码进行验证:

import numpy as np
# 复用上文同一组 V_in、U_out(seed 42,保留4位小数)
V_in = np.array([[ 0.4967, -0.1383,  0.6477],
                 [ 1.523,  -0.2342, -0.2341],
                 [ 1.5792,  0.7674, -0.4695],
                 [ 0.5426, -0.4634, -0.4657]])
U_out = np.array([[ 0.242,  -1.9133, -1.7249, -0.5623],
                  [-1.0128,  0.3142, -0.908,  -1.4123],
                  [ 1.4656, -0.2258,  0.0675, -1.4247]])
v_the = V_in[0]
u_quick = U_out[:, 1]
score = np.dot(v_the, u_quick)
print(f"分数 logit('quick' | 'the') = {score:.4f}")
分数 logit('quick' | 'the') = -1.1400

输出:分数 logit('quick' | 'the') = -1.1400

📝 动手练一练

  1. 概念辨析:假设我们有一个训练好的 Word2Vec 模型。对于同一个词,其“输入嵌入矩阵”中的向量和“输出嵌入矩阵”中的向量,含义和用途有何不同?在 CBOW 和 Skip-gram 模型中,哪个矩阵在预测时被用作最终的词向量更常见?

    👉 点击查看参考答案

    在 Word2Vec 模型中:

    • 输入嵌入矩阵:负责将输入的 One-Hot 向量映射为稠密向量。在 CBOW 中,它映射上下文词;在 Skip-gram 中,它映射中心词。
    • 输出嵌入矩阵:负责将隐藏层向量映射到输出层,用于计算与词表中每个词的“得分”,进而通过 Softmax 或负采样得到概率。

    两者的含义不同:输入向量更侧重于词在作为“输入特征”时的表示,而输出向量更侧重于词在作为“预测目标”时的表示。在实际应用中,通常将输入嵌入矩阵中的向量作为该词的最终词向量(即 word2vec.wv.vectors),因为它在上下文中更稳定。也有做法是将两个矩阵的向量平均或拼接,但单独使用输入向量是最常见的做法。

  2. 手算理解:假设我们有一个极简的词表 [‘自然’, ‘语言’, ‘处理’],其 One-Hot 编码顺序对应为 [1,0,0], [0,1,0], [0,0,1]。假设 CBOW 模型的输入嵌入矩阵 E\mathbf{E}(维度 3x2)和输出嵌入矩阵 E′\mathbf{E}'(维度 2x3)的初始值如下(仅为演示,非实际训练结果): E=[0.10.20.30.40.50.6],E′=[0.70.80.91.01.11.2]\mathbf{E} = \begin{bmatrix} 0.1 & 0.2 \\ 0.3 & 0.4 \\ 0.5 & 0.6 \end{bmatrix}, \quad \mathbf{E}' = \begin{bmatrix} 0.7 & 0.8 & 0.9 \\ 1.0 & 1.1 & 1.2 \end{bmatrix} 对于一个上下文窗口为 2(即前后各 1 个词)的 CBOW 模型,给定上下文词为 [‘自然’, ‘处理’],请手动计算: a) 上下文词的平均隐藏层向量 h\mathbf{h}。 b) 在未使用 Softmax 的情况下,模型对中心词的原始得分(logits)向量 s\mathbf{s}(即 s=hTE′\mathbf{s} = \mathbf{h}^T \mathbf{E}')。 c) 根据得分向量 s\mathbf{s},模型预测的中心词最可能是词表中的哪一个?

    👉 点击查看参考答案
    import numpy as np
    
    # 定义词表及One-Hot
    vocab = ['自然', '语言', '处理']
    # 定义嵌入矩阵
    E_input = np.array([[0.1, 0.2],  # ‘自然’
                        [0.3, 0.4],  # ‘语言’
                        [0.5, 0.6]]) # ‘处理’
    E_output = np.array([[0.7, 0.8, 0.9],
                         [1.0, 1.1, 1.2]])
    
    # a) 计算上下文词‘自然’(索引0)和‘处理’(索引2)的平均隐藏向量 h
    v_context1 = E_input[0]  # [0.1, 0.2]
    v_context2 = E_input[2]  # [0.5, 0.6]
    h = (v_context1 + v_context2) / 2
    print(f"平均隐藏层向量 h: {h}")
    
    # b) 计算得分向量 s = h^T * E_output
    s = np.dot(h, E_output)  # h 是 (2,), E_output 是 (2,3), 结果 s 是 (3,)
    print(f"原始得分向量 s: {s}")
    
    # c) 找出得分最高的索引,即为预测的中心词索引
    predicted_idx = np.argmax(s)
    predicted_word = vocab[predicted_idx]
    print(f"预测的中心词索引: {predicted_idx}, 对应词: '{predicted_word}'")

平均隐藏层向量 h: [0.3 0.4] 原始得分向量 s: [0.61 0.68 0.75] 预测的中心词索引: 2, 对应词: ‘处理’ ```

运行上述代码,可以得到结果:
- 平均隐藏层向量 h=[0.3,0.4]\mathbf{h} = [0.3, 0.4]
- 原始得分向量 s=[0.61,0.68,0.75]\mathbf{s} = [0.61, 0.68, 0.75]
- 得分最高的索引是 2,对应词 `‘处理’`。

因此,在此特定参数和上下文下,模型预测的中心词最可能是 **`‘处理’`**。请注意,这只是初始随机参数下的一个前向传播示例,并非有意义的训练结果。

</details>

本章小结

本节我们深入探讨了 Word2Vec 的核心思想与模型架构。我们从神经语言模型的背景出发,理解了 Word2Vec 如何将复杂的语言概率预测问题,简化为更高效的“词-上下文”关系建模任务。重点掌握了 CBOW 和 Skip-gram 两种经典模型的目标、架构与计算流程,并通过代码演示了其前向传播步骤。关键点在于理解双嵌入矩阵(输入矩阵 V\mathbf{V} 和输出矩阵 U\mathbf{U})的作用,以及它们如何通过一个预测任务被共同优化,从而产生高质量的稠密词向量。

📋 行动清单

  • 理清模型目标:能够清晰说出 CBOW 和 Skip-gram 在输入、输出和目标上的本质区别。
  • 理解计算图:对照讲义中的公式和代码,在心中勾勒出 CBOW/Skip-gram 从前向传播到计算损失的数据流动图。
  • 预见效率问题:思考当词表规模 ∣V∣|V| 达到 10 万量级时,输出层 Softmax 的计算会成为怎样的瓶颈?这为学习下一节的优化技术(负采样、层次 Softmax)做好了准备。

—— 小象教研组