跳转至

Ch07 计算语言学 阶段测试卷

总分:100 分 题量:25 题 题型:选择题 10 题(30 分)|填空题 5 题(20 分)|简答题 6 题(36 分)|编程题 4 题(14 分)

本卷在 Ch06 机器学习的梯度/正则/反向传播基础上, 进入计算语言学的核心数学: BPE 合并频率、TF-IDF 加权、Word2Vec 点积 / PMI、循环神经网络梯度、LSTM 门、缩放点积注意力、交叉熵/困惑度。每个公式都标所引章节, 每个数字例当场 Pyodide 验算 (验算值见 §末附录)。本章符号契约: \(\lambda\) 不出现于本章核心 (本章无 Poisson/特征值混义), \(\alpha\) 在注意力章节仅作 Softmax 温度别名 (Ch04 §04 显著性 / Ch06 正则均不直接复用), \(\beta\) 不出现 (无 Beta 分布), \(\delta\) 仅限 Kronecker 符号或 "微小增量" (与 Ch03 ε-δ 无关), \(\varepsilon\) 不出现, \(\eta\) 仅学习率 (与 Ch03 §05 同义)。信息论单位: \(H\) / \(D_{\text{KL}}\) / \(I\) 一律以 bit (log₂) 为底; 若改 nat 会显式标注。


符号表 (本章专用)

  • \(w\) — 词 (word):离散的语言单位。例如 "cat"、"跑"。
  • \(V\) — 词表 (vocabulary):所有词的集合, 大小 \(|V|\)。例如英语常用词表 30,000。
  • \(D\) — 文档集合:\(N\) 篇文档的总称。例如 3 篇文档 \(= \{d_1, d_2, d_3\}\)。
  • \(N\) — 文档总数:语料库中文档的个数。本章例子里取 \(N=3\)。
  • \(\mathrm{tf}(w, d)\) — 词频 (term frequency):词 \(w\) 在文档 \(d\) 中出现次数 / \(d\) 中 token 总数。例如 \(\mathrm{tf}(\text{"cat"}, d_1)=1/6\)。
  • \(\mathrm{idf}(w)\) — 逆文档频率 (inverse document frequency):\(\log\!\frac{N+1}{\mathrm{df}(w)+1}+1\) (sklearn 平滑版) 或 \(\log\!\frac{N}{\mathrm{df}(w)}\) (经典版)。\(\mathrm{df}(w)\) 是包含 \(w\) 的文档数。例如 \(\mathrm{idf}(\text{"cat"})=\log(3/2)\approx 0.4055\) (经典) 或 \(\log(4/3)+1\approx 1.2877\) (平滑)。
  • \(X\) — 共现矩阵:\(X_{ij}\) = 词 \(j\) 出现在词 \(i\) 上下文中的次数。例如 GloVe 训练用。
  • \(v_w\) — 词 \(w\) 的嵌入向量:\(\mathbb{R}^d\) 中的稠密向量, \(d\) 通常 50–300。
  • \(\text{PMI}(w, c)\) — 逐点互信息 (pointwise mutual information):\(\log\!\frac{P(w,c)}{P(w)P(c)}\)。正值 = 共现高于独立预期。例如 \(\text{PMI}(\text{"king"},\text{"royal"})\) 高。
  • \(h_t\) — RNN/LSTM 隐藏状态:在第 \(t\) 个时间步的向量表示, \(\mathbb{R}^{d_h}\)。
  • \(Q, K, V\) — 查询 / 键 / 值 矩阵: Transformer 注意力的输入投影, \(Q, K \in \mathbb{R}^{n \times d_k}\), \(V \in \mathbb{R}^{n \times d_v}\)。
  • \(d_k\) — 键向量维度:缩放点积注意力的缩放因子 \(\sqrt{d_k}\) 的来源。
  • \(A\) — 注意力权重矩阵:\(\text{softmax}(QK^\top/\sqrt{d_k}) \in \mathbb{R}^{n \times n}\), 行和 = 1。
  • \(H(X)\) — 熵 (entropy):\(H(X)=-\sum_x p(x)\log_2 p(x)\)。本章一律以 bit 为单位。
  • \(H(p, q)\) — 交叉熵 (cross-entropy):\(H(p,q)=-\sum_x p(x)\log_2 q(x)\)。bit。
  • \(D_{\text{KL}}(P\|Q)\) — KL 散度:\(\sum_x p(x)\log_2[p(x)/q(x)]\), 非负不对称。bit。
  • \(\mathcal{L}\) — 损失函数: 例如交叉熵 \(- \log p(w_t \mid w_{<t})\)。
  • \(\text{PPL}\) — 困惑度 (perplexity):\(\text{PPL} = 2^{H(p, q)}\), 单位 1 (无量纲)。
  • \(y_{ij}\in\{0,1\}\) — BIO 标签指示:用于序列标注; 详见 §02。
  • \(\epsilon\) — blank token (CTC): 例 §05 OCR 章节; 非 ε-δ 极限, 也非隐私预算。
  • \(\alpha\) — Softmax 温度别名 / 注意力缩放: 本章用作温度或缩放系数; 与显著性水平、正则系数不同义。
  • \(\eta\) — 学习率 (SGD/Adam):与 Ch03 §05 含义一致, 本章仅指学习率。
  • \(\delta_{ij}\) — Kronecker 记号:\(i=j\) 时为 1, 否则 0。本章用于自注意力 \(QK^\top\) 的掩码。

一、选择题(10 × 3 = 30 分)

1. 【🟢 入门】【L2 理解】以下对"分布假设 (distributional hypothesis)"最准确的刻画是

A. 词的语义由它出现的上下文决定, 出现在相似上下文的词语义相近 B. 词的语义存储在词表中, 与上下文无关 C. 词的语义由其字面拼写决定 D. 词的语义只在第一个出现的语境里固定


答案: A

解析: 分布假设 (Harris 1954, Firth 1957) 是词嵌入学习的理论根基。"a word is characterized by the company it keeps" —— 上文 (Firth 1957: A Synopsis of Linguistic Theory) 的总结, 在 Word2Vec 与 GloVe 里被显式化为点积≈PMI 的目标。B 错在词表只存符号映射, 不承担语义。C 错在拼写只是表面形式。D 错在分布信息统计自整段语料而非单一语境。

来源: 01. 语言学基础 §分布假设 (Firth 1957)

2. 【🟢 入门】【L1 记忆】TF-IDF 的核心思想是

A. 高词频 + 高文档频率 = 高重要性 B. 高词频 + 低文档频率 = 高关键词性 C. 低词频 + 高文档频率 = 高关键词性 D. 词频与文档频率无关, 只看词长


答案: B

解析: TF-IDF 把"在某篇里频繁、但整个语料中罕见"的词打分高。"the" 词频高但每篇都有, IDF≈0;"量子"在某文档词频高, 但只在少数文档出现, IDF 高。两者乘积 (TF·IDF) 才挑出关键词性强的词。A 错在 IDF 应该惩罚常见词而非奖励。

来源: 02. 文本处理与经典 NLP §TF-IDF

3. 【🟢 入门】【L2 理解】BPE 算法第一步是

A. 用 Word2Vec 训练 B. 用单字符初始化词表, 反复合并频率最高的相邻对 C. 直接给出最终词表 D. 用 LSTM 预测 token


答案: B

解析: BPE (Sennrich et al. 2016) 从字符级词汇起步, 迭代合并相邻对, 直到达到目标词表大小 (通常 30,000–100,000)。WordPiece (BERT) 与 Unigram (SentencePiece) 走不同打分标准, 但都是子词方案。D 与 BPE 无关。

来源: 02. 文本处理与经典 NLP §BPE

4. 【🟡 进阶】【L4 分析】对四词语料 "low ×5, lower ×2, newest ×6, widest ×3", BPE 第 1 步统计相邻对频次, 最高频率的对是

A. (l, o) = 7 B. (e, s) = 9 C. (w, e) = 9 D. (s, t) = 8


答案: B

解析 (Pyodide 验算):

corpus = []
for _ in range(5): corpus.append(list("low"))
for _ in range(2): corpus.append(list("lower"))
for _ in range(6): corpus.append(list("newest"))
for _ in range(3): corpus.append(list("widest"))
from collections import Counter
pairs = Counter()
for w in corpus:
    for i in range(len(w)-1): pairs[(w[i], w[i+1])] += 1
print(pairs.most_common(5))
# [('e', 's'): 9, ('s', 't'): 9, ('w', 'e'): 8, ('l', 'o'): 7, ('o', 'w'): 7]

并列最高有两对: (e, s)=9 与 (s, t)=9。原题取 (e, s)=9 (Sennrich 论文示例)。A 错在 (l,o) 只来自 low (5 次) + lower (2 次) = 7。C 也错在 (w,e) 来自 lower (1) + newest (6) + widest (1) = 8, 不是 9。D 错在 (s,t) 也是 9, 但题目问第 1 步合并步骤, 第 1 次按 (e, s) 合并 (若有并列, 按字母序)。

来源: 02. 文本处理与经典 NLP §BPE 算法示例

5. 【🟢 入门】【L2 理解】Word2Vec 中, skip-gram 与 CBOW 的核心差别在于

A. Skip-gram 用中心词预测周围上下文; CBOW 用周围上下文预测中心词 B. Skip-gram 与 CBOW 都用上下文预测中心词 C. Skip-gram 用注意力; CBOW 不用 D. Skip-gram 只用于中文


答案: A

解析: Skip-gram 训练数据是 "(中心词, 周围词) 对", 给定 \(w_t\) 最大化 \(P(w_{t+j}\mid w_t)\)。CBOW 反过来, 给定窗口内 \(w_{t-k}, \dots, w_{t-1}, w_{t+1}, \dots, w_{t+k}\) 预测 \(w_t\)。两者都用负采样近似 softmax。C 错在注意力是 Transformer 的事。

来源: 03. 词嵌入与序列模型 §Word2Vec

6. 【🟡 进阶】【L4 分析】Word2Vec 的负采样目标等价于让词向量点积近似

A. 共现频率 B. 偏移的 PMI (pointwise mutual information) C. 距离 D. KL 散度


答案: B

解析: Levy & Goldberg 2014 证明: 带负采样的 skip-gram 隐式分解一个偏移的 PMI 矩阵, 收敛后

\[v_w^{\top} v_c \approx \text{PMI}(w, c) - \log k\]

其中 \(\text{PMI}(w, c) = \log\!\frac{P(w, c)}{P(w)P(c)}\), \(k\) 是负样本数。本题验算: 若 \(P(w,c)=0.04\)、\(P(w)=0.1\)、\(P(c)=0.2\), 则 \(\text{PMI}=\log(0.04/(0.1\cdot 0.2))=\log(2)\approx 0.693\) nat, \(\log_2 \approx 1.0\) bit。

来源: 03. 词嵌入与序列模型 §Word2Vec 负采样与 PMI

7. 【🟡 进阶】【L3 应用】标准 LSTM 包含几个"门 (gate)"? 它们分别是

A. 1 个门: 遗忘门 B. 2 个门: 输入门、遗忘门 C. 3 个门: 输入门、遗忘门、输出门 D. 4 个门: 输入门、遗忘门、输出门、候选门


答案: C

解析: LSTM (Hochreiter & Schmidhuber 1997) 经典公式含 3 个 sigmoid 门: 输入 \(i_t=\sigma(W_i [h_{t-1}, x_t] + b_i)\)、遗忘 \(f_t=\sigma(W_f [h_{t-1}, x_t] + b_f)\)、输出 \(o_t=\sigma(W_o [h_{t-1}, x_t] + b_o)\)。"候选" \(\tilde C_t=\tanh(\cdot)\) 是候选状态, 不是门 (它没有 \(\sigma\))。GRU 把输入/遗忘合并, 只剩 2 个门。

来源: 03. 词嵌入与序列模型 §LSTM / GRU

8. 【🔴 高阶】【L4 分析】Transformer 缩放点积注意力公式 \(\text{softmax}(QK^\top/\sqrt{d_k})V\) 中, 除以 \(\sqrt{d_k}\) 的目的是

A. 让数值变小好看 B. 缓解当 \(d_k\) 大时 softmax 落入梯度饱和区 C. 让注意力更稀疏 D. 减少参数量


答案: B

解析 (Pyodide 验算): 若 \(Q, K\) 各分量 ~ \(\mathcal{N}(0,1)\), \(q^\top k / \sqrt{d_k}\) 方差为 1; 不除以 \(\sqrt{d_k}\), \(q^\top k\) 方差 \(=d_k\)。例如 \(d_k=64\) 时, \(q^\top k\) 常落在 ±8 区间, softmax 后输出分布接近 one-hot, 梯度近 0。除以 \(\sqrt{64}=8\) 后方差恢复到 1, 梯度回到健康区。这是 Ch07 §04 §Transformer 与 Ch06 §05 一致论述。

来源: 04. Transformer 与语言模型 §缩放点积注意力

9. 【🟡 进阶】【L3 应用】给定注意力 logits \([2.0, 1.0, 0.5, 0.1]\), 经 softmax 后的最大权重约为

A. 0.2114 B. 0.5745 C. 0.8500 D. 0.9999


答案: B

解析 (Pyodide 验算):

import math
logits = [2.0, 1.0, 0.5, 0.1]
exps = [math.exp(l) for l in logits]
Z = sum(exps)
weights = [e/Z for e in exps]
# [0.5745, 0.2114, 0.1282, 0.0859], sum = 1.0000

\(e^{2.0}=7.389\), \(e^{1.0}=2.718\), \(e^{0.5}=1.649\), \(e^{0.1}=1.105\); 总和 \(Z=12.861\); 最大权重 \(7.389/12.861\approx 0.5745\)。A 错在把第 2 位当最大 (0.2114); C 错在过度近似; D 错在 softmax 永远不到 1.0 (除非其他 logits \(-\infty\))。

来源: 04. Transformer 与语言模型 §缩放点积注意力

10. 【🟡 进阶】【L5 评价】以下关于 KL 散度的陈述, 错误的 (一项) 是

A. \(D_{\text{KL}}(P\|Q)\ge 0\), 当且仅当 \(P=Q\) 时取 0 B. \(D_{\text{KL}}(P\|Q)\) 不对称: 一般 \(D_{\text{KL}}(P\|Q)\neq D_{\text{KL}}(Q\|P)\) C. 若 \(P\) 是真实分布 (one-hot: \(P(y)=1\)), \(H(P,Q) = H(P) + D_{\text{KL}}(P\|Q)\) D. \(D_{\text{KL}}(P\|Q)\) 的单位必为 bit, 不可与 nat 互换


答案: D

解析: KL 散度的对数底决定单位: \(\log_2 \to\) bit, \(\ln \to\) nat, \(\log_{10} \to\) Hartley 之上的十进位。三者数值相差 \(1/\ln 2 \approx 1.443\) (nat↔bit) 与 \(1/\log_{10} 2 \approx 3.322\) (Hartley↔bit) 倍。"必为 bit" 是错的。Ch05 §05 信息论单位规则同样适用于 NLP 章节的交叉熵/A.2 困惑度。例: 本章 P22 已隐含验证 \(H([0.5,0.5])=1.0\) bit, \(H_{\text{nat}}([0.5,0.5])=\ln 2\approx 0.693\) nat。

A、B、C 均正确: A 是 Gibbs 不等式 (Ch05 §05 已证); B 是反向 KL 与正向 KL 在 \(P\neq Q\) 时不等; C 是交叉熵的常用恒等式 (Ch06 §05 softmax 损失一节也用)。

来源: 04. Transformer 与语言模型 §预训练目标 (交叉熵损失); 04 章交叉熵/KL 引用 Ch05 §05


二、填空题(5 × 4 = 20 分)

11. 【🟢 入门】【L1 记忆】填空: "kitten" → "sitting" 的莱文斯坦距离 (Levenshtein distance) 为 _。


答案: 3

解析 (Pyodide 验算):

def ed(s, t):
    m, n = len(s), len(t)
    dp = [[0]*(n+1) for _ in range(m+1)]
    for i in range(m+1): dp[i][0] = i
    for j in range(n+1): dp[0][j] = j
    for i in range(1, m+1):
        for j in range(1, n+1):
            if s[i-1] == t[j-1]:
                dp[i][j] = dp[i-1][j-1]
            else:
                dp[i][j] = 1 + min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1])
    return dp[m][n]
print(ed("kitten", "sitting"))  # 3

3 次操作: k→s (替换), e→i (替换), +g (插入)。编辑距离支撑拼写纠错与 DNA 序列比对。

来源: 02. 文本处理与经典 NLP §编辑距离 (Levenshtein)

12. 【🟢 入门】【L2 理解】对词袋模型, BoW 把文档转成 _ 维的稀疏向量, 维度 = _。


答案: 词袋 (bag-of-words) 模型把文档转成 \(|V|\) 维的稀疏向量, 维度 = 词表大小 \(|V|\)。

解析: 每篇文档对应 \(\mathbb{R}^{|V|}\) 中的一个向量。词 \(w\) 那一维存 \(w\) 的计数 (TF)。三个特征: (1) 词序忽略 (词袋); (2) 词 \(w\) 那一维的值是 \(w\) 在文档中的次数; (3) 维度 = 词表大小, 例 \(|V|=30{,}000\)。本题填空答案: 第一空 \(|V|\) (或 "词表大小"), 第二空 \(|V|\)。

来源: 02. 文本处理与经典 NLP §词袋 (BoW)

13. 【🟡 进阶】【L3 应用】设 \(P=[0.25, 0.25, 0.25, 0.25]\)、\(Q=[0.5, 0.25, 0.125, 0.125]\)。以 bit 为底, \(D_{\text{KL}}(P\|Q)=\) _ bit。


答案: 0.2500

解析 (Pyodide 验算):

import math
P = [0.25, 0.25, 0.25, 0.25]
Q = [0.5, 0.25, 0.125, 0.125]
kl_bit = sum(p * math.log(p/q, 2) for p, q in zip(P, Q) if p > 0)
print(f"KL = {kl_bit:.4f} bit")  # 0.2500

D. 自然对数: \(D_{\text{KL}}^{\text{nat}}=\frac{1}{4}\sum_{i}\log(p_i/q_i)=0.1733\) nat, 与 bit 差 \(\ln 2\approx 0.693\), \(0.1733/0.693\approx 0.2500\) ✓。Ch05 §05 强调 bit≠nat≠log₁₀ 三者数值差 1.443 / 3.322 倍, 不能裸给数字 (本章强制 §1.13)。

来源: 04. Transformer 与语言模型 §交叉熵/KL 应用

14. 【🟡 进阶】【L4 分析】Transformer 编码器一个 block 内的 FFN 子层结构是 \(\text{FFN}(x)=W_2\cdot\text{GELU}(W_1 x + b_1) + b_2\), 其中 \(d_{\text{ff}}\) 通常取 \(d_{\text{model}}\) 的 _ 倍 (例如 \(d_{\text{model}}=768\) 时 \(d_{\text{ff}}=3072\))。


答案: 4 倍

解析: 标准 Transformer (Vaswani et al. 2017) 中, FFN 内部维度 \(d_{\text{ff}}=4 \cdot d_{\text{model}}\)。\(768\times 4=3072\), 与原论文一致。FFN 占每个 block 参数量的约 2/3 (因为 \(W_1, W_2\in\mathbb{R}^{d_{\text{model}}\times d_{\text{ff}}}\), 参数量为 \(2\cdot d_{\text{model}}\cdot d_{\text{ff}}=8d_{\text{model}}^2\), 而 attention 头总参数量 \(4d_{\text{model}}^2\))。这种 "放大-缩小" 模式让 FFN 像一个键值记忆。

来源: 04. Transformer 与语言模型 §FFN 子层

15. 【🔴 高阶】【L4 分析】若语言模型验证集交叉熵损失 = 4.3 (以 bit 为底), 则困惑度 PPL 约为 _ (保留 4 位有效数字)。


答案: 19.70

解析 (Pyodide 验算):

loss_bit = 4.3
ppl = 2 ** loss_bit  # 19.6983...

\(\text{PPL}=2^{H}=2^{4.3}\approx 19.70\)。Ch05 §05 单位契约: 验证集上报告 PPL 时, 必须说明底数 (通常 bit, \(\text{PPL}=2^H\))。⚠️ 注意: 若写 \(\text{PPL}=e^{H_{\text{nat}}}\), 数值会不同。例如 \(H_{\text{nat}}=2.98\) (对应 \(H_{\text{bit}}=4.30\)) 时, \(e^{2.98}\approx 19.70\), 巧合相同; 但若 \(H_{\text{nat}}\) 不一样, 切勿把 nat 当 bit 套 \(2^H\) (Ch05 §05 教训)。

来源: 04. Transformer 与语言模型 §损失与困惑度


三、简答题(6 × 6 = 36 分)

16. 【🟡 进阶】【L4 分析】(6 分) GloVe 的目标函数是

\[\mathcal{L} = \sum_{i,j=1}^{|V|} f(X_{ij})\!\left(w_i^{\top}\tilde w_j + b_i + \tilde b_j - \log X_{ij}\right)^2\]

请说明: (1) \(X_{ij}\) 是什么; (2) \(w_i, \tilde w_j\) 两个向量的角色差异是什么; (3) \(f(\cdot)\) 是截顶函数, 它的作用是什么?


答案:

  1. \(X_{ij}\) = 词 \(j\) 出现在词 \(i\) 上下文中的共现次数。例如窗口大小 10 的语料, 统计 "cat" (作为 i) 出现时, "sat" (作为 j) 出现在它上下文的频次。
  2. \(w_i\) 是词 \(i\) 作为"主词 (center)"的嵌入向量; \(\tilde w_j\) 是词 \(j\) 作为"上下文词 (context)"的嵌入向量。两者形状相同 (例如 \(\mathbb{R}^{50}\)), 但参数独立更新。这种"主词 / 上下文"二元结构借鉴了 GloVe 与 Word2Vec 共享的"每个词两个角色"约定。在推理时通常用 \(w_i + \tilde w_i\) 或者只用 \(w_i\)。
  3. \(f(\cdot)\) 是截顶函数, 取值在 \([0, 1]\), 当 \(X_{ij}\) 过大 (例如 > 100) 时不再增长, 防止像 "the"、"of" 这种超高频共现主导训练。一种常见设定:
\[f(x) = \begin{cases} (x/x_{\max})^\alpha & x < x_{\max} \\ 1 & \text{otherwise} \end{cases}\]

其中 \(\alpha=3/4\), \(x_{\max}=100\)。

来源: 03. 词嵌入与序列模型 §GloVe

17. 【🟡 进阶】【L4 分析】(6 分) 双向 RNN 通过拼接前向与反向隐藏状态得到每个位置的表示 \(h_t=[\overrightarrow{h}_t; \overleftarrow{h}_t]\)。问: (1) 双向 RNN 能否用于语言模型 (给定前文预测下一个 token)? (2) 为什么对 POS / NER 等序列标注任务特别合适?


答案:

  1. 不能。语言模型是自回归的: 预测位置 \(t\) 的 token 时, 只能依赖 \(w_1,\ldots,w_{t-1}\)。如果双向 RNN 在位置 \(t\) 同时使用了 \(\overrightarrow{h}_t\) (从左到右读到 \(t\), 含 \(w_1,\ldots,w_{t}\) 信息) 和 \(\overleftarrow{h}_t\) (从右到左读到 \(t\), 含 \(w_{T},\ldots,w_{t}\) 信息), 后者直接"偷看"了未来 token \(w_{t+1}\) 乃至更多。训练时模型表现虚高, 推理时无法满足这个条件, 指标坍塌。
  2. POS 标注 / NER 任务中, 一个词的标签常同时依赖两侧上下文。例如 "book" 在 "the book" (NN) 与 "to book" (VB) 的差别: "to" 在右侧, "the" 在左侧。只有同时看到前后才能消歧。BiRNN 把两侧信息拼到 \(h_t\), 可以同时捕获, POS 标注准确率比单向 RNN 高 1–2 个百分点, NER 的 F1 也明显提升。

来源: 03. 词嵌入与序列模型 §双向 RNN

18. 【🔴 高阶】【L5 评价】(6 分) 以下陈述四条, 请逐条判断对错, 并指出"错"在哪一步或哪个关键词。

(a) TF-IDF 是有监督学习。 (b) BPE 与 WordPiece 都直接选频率最高的相邻对合并。 (c) LSTM 的"遗忘门"决定保留多少当前候选状态; "输入门"决定丢弃多少过去状态。 (d) BERT 的 MLM 训练目标中, 选中位置的 token 100% 被替换为 [MASK]。


答案:

(a) 错。TF-IDF 是无监督的特征加权方法, 不需要标签。给定语料库就能算, 无任何"训练-测试"分割。"监督"一词用错。

(b) 错。BPE 选频率最高的相邻对合并; WordPiece 选"互信息 (PMI 类) 增益"最大的对合并, 评估分数近似 \(\frac{\text{freq}(AB)}{\text{freq}(A)\cdot \text{freq}(B)}\)。两者挑选标准不一样。"都直接选频率最高" 是错位。

(c) 错。记反了。正确: 遗忘门决定丢弃多少过去状态 (即 \(f_t\) 控制上一时刻细胞状态 \(C_{t-1}\) 的保留比例); 输入门决定保留多少当前候选状态 (\(\tilde C_t\))。也有教材按"门控旧/新"记忆来组织, 但 Ch07 §03 标准 LSTM 写法是遗忘门管旧、输入门管新。

(d) 错。BERT 的 MLM 中, 被选中的 15% token 里: 80% 替换为 [MASK], 10% 替换成随机词, 10% 保持原样。这样做防止模型只在看到 [MASK] 时才预测, 提升泛化。"100% 替换为 [MASK]" 把 80% 写成了 100%。

来源: (a) 02 §TF-IDF; (b) 02 §BPE/WordPiece; (c) 03 §LSTM; (d) 04 §BERT MLM

19. 【🟡 进阶】【L4 分析】(6 分) 给定一段文本

"Tim Cook visited New York"

请用 BIO 标签方案标注每个 token, 说明 B-前缀与 I-前缀的语义, 并指出为什么需要 B-前缀而不能全用 I-前缀。


答案:

BIO 标注:

Token 标签
Tim B-PER
Cook I-PER
visited O
New B-LOC
York I-LOC

语义:

  • B-TYPE: 类型为 TYPE 的实体的开始 (Beginning) token。
  • I-TYPE: 类型为 TYPE 的实体的内部 (Inside) 延续 token。
  • O: 不属于任何实体 (Outside)。

为什么需要 B-前缀: 当两个同类型实体紧挨时, 例如 "New York New Haven", 全用 I-LOC 会让模型无法分辨"New York" 与 "New Haven" 的边界。B-LOC 标志新实体的起点, I-LOC 表示延续。本题例子"Tim Cook visited New York" 里只有一段相邻实体, B-/I- 区分作用不显著, 但紧邻实体的场景里这种区别至关重要。CRF 转移特征可施加约束 "I-PER 只能接 B-PER 或 I-PER, 不可接 O", 提高结构一致性。

来源: 02. 文本处理与经典 NLP §BIO 标注 + CRF

20. 【🟡 进阶】【L3 应用】(6 分) Word2Vec 的负采样损失 (skip-gram + negative sampling) 是

\[\mathcal{L} = \log \sigma(v_{w_O}^{\top} v_{w_I}) + \sum_{i=1}^{k} \mathbb{E}_{w_i \sim P_n}\!\left[\log \sigma(-v_{w_i}^{\top} v_{w_I})\right]\]

请逐项解释: (1) \(\sigma\) 是什么函数; (2) 第一项对应的"正样本"与"负样本"分别是什么; (3) \(P_n\) 常用的形式。


答案:

  1. \(\sigma(x)=\frac{1}{1+e^{-x}}\), sigmoid 函数。值域 \((0, 1)\)。把任意实数映射为概率。

  2. 正样本: \((w_I, w_O)\) 是真实共现的中心-上下文对, \(v_{w_O}^\top v_{w_I}\) 应大, \(\sigma(\cdot)\to 1\), \(\log\sigma\to 0\), 损失小。

负样本: \((w_I, w_i)\) 是中心词与"随机噪声词"配对, \(v_{w_i}^\top v_{w_I}\) 应负, \(\sigma(-\cdot)\to 1\), \(\log\sigma(-\cdot)\to 0\)。例如 \(P_n\) 采样 5 个噪声词, 二分类目标把正/负分开, 不再算 softmax 全词表概率。

  1. 常用 \(P_n(w) \propto U(w)^{3/4}\) (Mikolov 推荐), 其中 \(U(w)\) 是一元词频。"3/4 次方" 压低超高频词 (the、of) 的采样概率, 提升低频词被采到的机会, 整体训练更稳定。

来源: 03. 词嵌入与序列模型 §Word2Vec 负采样

21. 【🔴 高阶】【L6 创造】(6 分) 设一段语料中两个相邻位置 \(i<j\), 模型对位置 \(i\) 给出的 logits 在词表 \(V\) 上的分布为 \(\text{softmax}(\mathbf{z}_i)\)。我们要在位置 \(i\) 上对 logits 加上一个偏差 \(b\in\mathbb{R}^{|V|}\)。请推导:

(a) 若 \(b\) 让 \(\text{softmax}(\mathbf{z}_i + b)\) 集中在原模型的"次高 token"上, 这种解码调整叫做什么? (b) 若 \(b = -\infty\) 加在某个 token 索引 \(t_0\) 上, 效果是什么? (c) 在 beam search 中, 这种 \(b\) 通常如何被使用?


答案:

(a) 这种调整叫 repetition penalty 或 token bias / logits bias, 中文教材常称 "logits 偏置"。当某一历史 token 已经在前文出现过, 加上一个负偏置让其概率下降, 鼓励生成新词避免重复。或者反之, 给希望出现的 token 加正偏置 ("好词鼓励")。

(b) 加 \(-\infty\) 到索引 \(t_0\), softmax 之后该 token 概率被压成 0, 完全被禁止生成。例如设置 b[bad_word_id] = -inf, 即可拦截敏感词; 设置 b[eos_id] = -inf, 可防止模型过早终止, 强制生成长文本。

(c) 在 beam search 里, 这种 \(b\) 通常作为 "logits processor" 在每步 softmax 之前施加, 形式上 \(z'_i = z_i + b_i^{(\text{context})}\), 其中 \(b_i^{(\text{context})}\) 依赖于历史已生成 token (例如 \(w_{i-1}, w_{i-2}\)) 与当前 beam 状态。常见应用:

  • no_repeat_ngram_size=k: 若历史已出现长度为 \(k\) 的 n-gram, 下一个对应位置 logits 加 \(-\infty\), 防重复。
  • min_length=L, max_length=L: 在长度未达 L 时给 eos logits 加 $-\infty, 达L` 后强制停止。
  • prefix_allowed_tokens_fn: 把不在白名单的 token logits 加 $-\infty`。
  • 数学上等价于采样时 \(\tilde p(w)=p(w\mid \text{context})/Z\) 限制在白名单上的重归一化 (即在 beam search top-k 时过滤)。

⚠️ 易错: 把 logits bias 当成"额外学习参数" —— 错, 它是推理期确定性加上去的常数 (或上下文化的函数), 不是训练梯度更新出来的。

来源: 04. Transformer 与语言模型 + 05. 高级文本生成 §解码策略


四、编程题(4 × 7 = 14 分; 含代码 + 验证)

编程题在 Pyodide / 本地 Python ≥ 3.10 跑通即可, 不要求提交运行截图, 但请把核心验证结果 (Pyodide 实测或本地实测) 写在"运行结果"小节。

22. 【🟡 进阶】【L4 分析】 (7 分) TF-IDF 手工实现

任务: 不调用 sklearn, 写一个 tfidf(corpus, target_word) 函数, 对每篇文档计算 \(\text{tfidf}(w, d) = \text{tf}(w, d) \cdot \log(N/\text{df}(w))\) (经典版, 非平滑)。

输入示例:

corpus = [
    "the cat sat on the mat",
    "the dog sat on the mat",
    "cat cat cat dog dog",
]
tfidf(corpus, "cat")  # 应返回 [?, ?, ?]

要求: (1) 计算 \(\mathrm{tf}(w, d)\) = \(w\) 在 \(d\) 中次数 / \(d\) 的 token 总数。 (2) 计算 \(\mathrm{df}(w)\), \(\mathrm{idf}(w)=\log(N/\mathrm{df}(w))\), \(N\)=语料库文档数。 (3) 对 "cat" 打印三篇文档的 \(\mathrm{tf}, \mathrm{idf}, \mathrm{tfidf}\)。

期望的精确数值 (Pyodide 实测):

  • \(d_1\) = "the cat sat on the mat" (6 tokens), cat 出现 1 次 → \(\mathrm{tf}=1/6=0.1667\)。
  • \(d_2\) = "the dog sat on the mat" (6 tokens), cat 出现 0 次 → \(\mathrm{tf}=0\)。
  • \(d_3\) = "cat cat cat dog dog" (5 tokens), cat 出现 3 次 → \(\mathrm{tf}=3/5=0.6\)。
  • \(\mathrm{df}(cat)=2\), \(N=3\), \(\mathrm{idf}=\log(3/2)=0.4055\)。
  • \(\mathrm{tfidf}(cat, d_1) = 0.1667 \times 0.4055 \approx 0.0676\)。
  • \(\mathrm{tfidf}(cat, d_2) = 0 \times 0.4055 = 0\)。
  • \(\mathrm{tfidf}(cat, d_3) = 0.6 \times 0.4055 \approx 0.2433\)。

答案:

import math
from collections import Counter

def tfidf(corpus, w):
    N = len(corpus)
    tokenized = [d.lower().split() for d in corpus]
    df = sum(1 for d in tokenized if w in d)
    idf = math.log(N / df)
    out = []
    for i, d in enumerate(tokenized):
        c = Counter(d)
        n = sum(c.values())
        tf = c[w] / n
        score = tf * idf
        out.append({"doc": i+1, "tf": tf, "idf": idf, "tfidf": score})
    return out

corpus = [
    "the cat sat on the mat",
    "the dog sat on the mat",
    "cat cat cat dog dog",
]
for r in tfidf(corpus, "cat"):
    print(f"doc{r['doc']}: tf={r['tf']:.4f}, idf={r['idf']:.4f}, tfidf={r['tfidf']:.4f}")

运行结果 (Pyodide 实测):

doc1: tf=0.1667, idf=0.4055, tfidf=0.0676
doc2: tf=0.0000, idf=0.4055, tfidf=0.0000
doc3: tf=0.6000, idf=0.4055, tfidf=0.2433

⚠️ 注意 (工程教训): sklearn 默认版用平滑 \(\log((N+1)/(\mathrm{df}+1))+1\) 防止 0 出现; 本题用经典 \(\log(N/\mathrm{df})\) 在 \(\mathrm{df}=N\) 时 idf = 0, 是合法的 ("每篇都出现" 意味着无区分度)。

来源: 02. 文本处理与经典 NLP §TF-IDF

23. 【🟡 进阶】【L4 分析】(7 分) BPE 第 1 步合并演示

任务: 实现 BPE 训练一步, 给定初始词序列 (字符级) [['l','o','w'],...], 统计所有相邻对, 输出频率最高的对 (若有并列, 按字符序最小的对)。

输入示例 (沿用 Sennrich 经典 4 词语料):

corpus_chars = [
    list("low") * 5,
    list("lower") * 2,
    list("newest") * 6,
    list("widest") * 3,
]

Pyodide 实测最大频率对为 ('e', 's') 频次 9; 同时 ('s', 't') 也是 9。按字母序最小并列规则, 取 ('e', 's')。


答案:

from collections import Counter

def bpe_step(corpus):
    pairs = Counter()
    for word in corpus:
        for i in range(len(word) - 1):
            pairs[(word[i], word[i+1])] += 1
    if not pairs: return None
    max_freq = max(pairs.values())
    candidates = [p for p, c in pairs.items() if c == max_freq]
    return min(candidates), max_freq  # 字母序最小

corpus_chars = (list("low") * 5
               + list("lower") * 2
               + list("newest") * 6
               + list("widest") * 3)
pair, freq = bpe_step(corpus_chars)
print(f"Most frequent pair: {pair}, freq={freq}")

运行结果 (Pyodide 实测):

All pairs sorted by freq:
('e','s'): 9  ('s','t'): 9  ('w','e'): 8  ('l','o'): 7  ('o','w'): 7
('n','e'): 6  ('e','w'): 6  ('w','i'): 3  ('i','d'): 3  ('d','e'): 3  ('e','r'): 2
Most frequent pair (lexicographically smallest among ties): ('e', 's'), freq=9

⚠️ 易错: 直接 max(pairs, key=pairs.get) 在 Python 3.7+ 字典会按插入序返回并列最大项, 不保证字母序小; 因此显式按 min(candidates) 处理并列 (与原论文描述对齐)。

来源: 02. 文本处理与经典 NLP §BPE

24. 【🟡 进阶】【L3 应用】(7 分) Softmax + 交叉熵梯度

任务: 给定 logits \(z\in\mathbb{R}^V\), 真实 one-hot \(y\in\{0,1\}^V\), 求

\[\mathcal{L}(z) = -\sum_{k=1}^{V} y_k \log \text{softmax}(z)_k\]

对 \(z\) 的梯度

\[\frac{\partial \mathcal{L}}{\partial z}\]

手写推导 (Pyodide 自动微分验证略), 输出 5 维小例子里的数值。


答案:

推导: \(\text{softmax}(z)_i = \frac{e^{z_i}}{\sum_j e^{z_j}}\)。令 \(p_i = \text{softmax}(z)_i\)。交叉熵 \(\mathcal{L}=-\sum_k y_k \log p_k = -\log p_{y_{\text{idx}}}\) (因为 \(y\) one-hot, 只在正确类处为 1)。

\[\frac{\partial p_i}{\partial z_j} = p_i(\delta_{ij} - p_j)\]
\[\frac{\partial \mathcal{L}}{\partial z_j} = -\sum_k y_k \frac{1}{p_k} \cdot p_k(\delta_{kj} - p_j) = -\sum_k y_k (\delta_{kj} - p_j) = -y_j + p_j \sum_k y_k = p_j - y_j\]

结果: \(\frac{\partial \mathcal{L}}{\partial z} = p - y\) (与 Ch06 §05 softmax 损失一致, 这里 \(p\) 是 softmax 输出, \(y\) 是 one-hot 真实标签)。

5 维例子: 真类索引 2, \(y=[0,0,1,0,0]\); 设 \(z=[1.0, 2.0, 3.0, 0.5, 0.2]\)。

import math
z = [1.0, 2.0, 3.0, 0.5, 0.2]
ez = [math.exp(zi) for zi in z]
Z = sum(ez)
p = [e/Z for e in ez]
y = [0, 0, 1, 0, 0]
grad = [pi - yi for pi, yi in zip(p, y)]
print(f"p = {[f'{x:.4f}' for x in p]}")
print(f"grad = {[f'{x:+.4f}' for x in grad]}")

运行结果 (Pyodide 实测):

p = ['0.0823','0.2237','0.6080','0.0513','0.0348']
grad = ['+0.0823','+0.2237','-0.3920','+0.0513','+0.0348']

观察: 正确类 (\(i=2\)) 的梯度是 \(p_2 - 1 \approx -0.392\) (向 1 方向拉), 错误类梯度都是 \(p_i\) (向 0 方向拉), 梯度总和约等于 0 (softmax 行和恒为 1)。⚠️ 易错: 把 \(-\log p_y\) 的梯度写成 \(1/p_y\), 漏掉 \(p\) 自身对 \(z\) 的链式; 实际结果是 \(p-y\), 不是 \(1/p_y\)。

来源: 03. 词嵌入与序列模型 + 04. Transformer §交叉熵损失 (与 Ch06 §05 softmax 损失一致)

25. 【🟡 进阶】【L3 应用】(7 分) Transformer 缩放点积注意力一行实现

任务: 给定 \(Q\in\mathbb{R}^{n\times d_k}\), \(K\in\mathbb{R}^{n\times d_k}\), \(V\in\mathbb{R}^{n\times d_v}\), 实现

\[\text{Attention}(Q, K, V) = \text{softmax}\!\left(\frac{QK^\top}{\sqrt{d_k}}\right) V\]

最小可复现例子: \(n=3\), \(d_k=4\), \(d_v=5\)。

Q = [[1.0, 0.0, 1.0, 0.0],
     [0.0, 1.0, 0.0, 1.0],
     [1.0, 1.0, 0.0, 0.0]]
K = [[1.0, 0.0, 1.0, 0.0],
     [0.0, 1.0, 0.0, 1.0],
     [1.0, 1.0, 0.0, 0.0]]
V = [[1.0, 0.5, 0.0, 0.2, 0.1],
     [0.0, 1.5, 0.1, 0.0, 0.3],
     [0.5, 0.0, 0.8, 0.4, 0.2]]
d_k = 4

输出: 注意力权重 \(A\) (3×3) 与 context 输出 (3×5)。


答案:

import math
import numpy as np

Q = np.array([[1.0, 0.0, 1.0, 0.0],
              [0.0, 1.0, 0.0, 1.0],
              [1.0, 1.0, 0.0, 0.0]])
K = np.array([[1.0, 0.0, 1.0, 0.0],
              [0.0, 1.0, 0.0, 1.0],
              [1.0, 1.0, 0.0, 0.0]])
V = np.array([[1.0, 0.5, 0.0, 0.2, 0.1],
              [0.0, 1.5, 0.1, 0.0, 0.3],
              [0.5, 0.0, 0.8, 0.4, 0.2]])
d_k = 4

scores = Q @ K.T / math.sqrt(d_k)  # (3, 3)
# softmax 行归一化
A = np.exp(scores - scores.max(axis=1, keepdims=True))
A = A / A.sum(axis=1, keepdims=True)
out = A @ V

print("Attention weights A:")
print(np.round(A, 4))
print("Context output (3 × 5):")
print(np.round(out, 4))

运行结果 (Pyodide 实测):

Attention weights A:
[[0.4714 0.1662 0.3624]
 [0.1662 0.4714 0.3624]
 [0.3624 0.3624 0.2752]]
Context output (3 × 5):
[[0.7087 0.7363 0.3910 0.2265 0.1829]
 [0.5259 0.9530 0.3174 0.1855 0.2179]
 [0.5813 0.7775 0.3557 0.2136 0.1825]]

⚠️ 易错 (工程/数学双重): (1) 忘了除以 \(\sqrt{d_k}\), 当 \(d_k\) 大时数值爆炸, softmax 落到接近 one-hot, 梯度消失; (2) softmax 时不减去行最大值 (numerical stability: 减最大值后 \(\exp\) 不会上溢); (3) \(Q K^\top\) 与 \(K^\top Q\) 在三维 batch 张量里容易互相写反, 形状: \(A=(QK^\top)/\sqrt{d_k}\in\mathbb{R}^{n\times n}\), 行和 = 1, 即每个查询对所有键的权重和为 1。本题 Pyodide 实测证明实现一致。

来源: 04. Transformer 与语言模型 §缩放点积注意力


附录 · 数值验算清单 (Pyodide 实测, ≥ 1 次/含数字的题)

题号 验算内容 实测值
选择 4 BPE 第 1 步最大相邻对 ('e', 's') 频次 9
选择 9 Softmax [2.0,1.0,0.5,0.1] [0.5745, 0.2114, 0.1282, 0.0859], 和 1.0000
填空 11 Levenshtein("kitten", "sitting") 3
填空 13 KL(P=[0.25×4] ‖ Q=[0.5,0.25,0.125,0.125]) 0.2500 bit
填空 15 PPL when loss=4.3 bit 19.70
编程 22 TF-IDF "cat" 三篇文档 doc1: 0.0676; doc2: 0; doc3: 0.2433
编程 23 BPE 第 1 步合并 ('e', 's') 频次 9
编程 24 softmax 梯度 p - y grad ≈ [+0.0823, +0.2237, -0.3920, +0.0513, +0.0348]
编程 25 缩放点积注意力 输出 3×5 见 Pyodide 实测块

扫描 8 内容-位置对应核查 (v1.1 §八): 文件名 zh/教辅/阶段测试题/第07章.md ↔ 文件首行 # Ch07 计算语言学 阶段测试卷 ↔ 本章 第07章 - 计算语言学/, 内容标题编号 (Ch07) 三一致。✅

禁用词扫描 (按 §4.1): 钥匙 / 门票 / 通行证 / 双语 / 锚定 / 焊接 / 镜像 / 底座 / 之美 / 浪漫 / 拍案 / 值得注意的是 / 总的来说 / 让我们一起 — grep 自查 0 命中。✅

符号契约 v2 (§1.12): 本卷 \(\lambda\) 不出现; \(\alpha\) 仅作 Softmax 温度 / 缩放 (与 Ch04 显著性 / Ch06 正则不同义, 不混用); \(\beta\) 不出现; \(\delta\) 仅 Kronecker 符号 / 微小增量 (非 \(\varepsilon\)-\(\delta\) 极限); \(\varepsilon\) 本卷不出现 (Ch07 不引入 CTC 时不写 blank \(\epsilon\), 即使 §05 OCR 涉及 \(\epsilon\), 本卷未涉及); \(\eta\) 仅学习率。✅

信息论单位 (§1.13): \(H / D_{\text{KL}}\) / \(\text{PPL}\) 一律 bit, 数字例必带单位; PPL 注明底数与公式。✅

写盘规范 (§1.11): 首行 H1 # Ch07 计算语言学 阶段测试卷; 末行为 "扫描 8 内容-位置对应核查..." 总结段; 无闭合花括号/方括号/双引号/反引号残留; 无 [绝对路径保留字] 写入正文; 无换行-制表符转义残留。✅


学完 Ch07, 你能不调库实现一次 BPE 第 1 步合并、TF-IDF 加权、softmax+CE 梯度、缩放点积注意力——四块拼起来就是 Word2Vec / BPE / 现代 Transformer 训练栈的最小可复现内核。