第07章 · 计算语言学 · 阶段测试题答案¶
配套测试题:
zh/教辅/阶段测试题/第07章.md建议用时: 60 分钟
一 · 单选题 (8 题)¶
1.1 B - Token 是文本切分的最小单位, 可以是词 / 子词 / 字符。
1.2 A - BPE 从字符开始, 迭代合并最高频对。
1.3 B - Self-Attention 中每个位置都"看"所有其他位置, O(n²)。
1.4 B - 32K token 超过 GPT-3 原始 2048 上百倍, 需 RoPE / YaRN。
1.5 C - Layer Norm 是 Transformer 的标准 (vs Batch Norm 用于 CNN)。
1.6 A - ReLU 仍主流; GeLU/SiLU/GELU 在 Transformer 中常见。
1.7 B - QK^T 计算相似度, Softmax 归一化为概率, 加权 V 求和。
1.8 C - Flash Attention 不存 attention matrix, 内存 O(n) 替代 O(n²)。
二 · 多选题 (4 题)¶
2.1 ABCD
全部是常见位置编码。
2.2 ABD
C 错: Greedy 选最大概率 1 个, Beam Search 选 top-K。
2.3 ABC
D 错: 是采样控制, 不是 Top-p。
2.4 ACD
B 错: KV cache 反而减少重复计算。
三 · 简答题 (5 题)¶
3.1 BPE vs WordPiece vs SentencePiece¶
| 算法 | 出品 | 特点 |
|---|---|---|
| BPE | GPT / Llama | 字符级合并, 频率优先 |
| WordPiece | BERT | 类似 BPE, 用互信息 |
| SentencePiece | 语言无关, 直接训 | |
| Unigram | XLNet | 反向: 删除贡献小 token |
BPE 步骤: ① 初始化字符表 ② 找最高频相邻对 ③ 合并 ④ 重复。
3.2 Self-Attention 公式推导¶
输入: Q (n×d_k), K (m×d_k), V (m×d_v) 步骤: 1. 相似度: S = QK^T / √d_k 2. 归一化: A = softmax(S) (每行) 3. 加权求和: Output = A × V
复杂度: O(n² × d), 即 O(n²) √d 缩放: 防止 d 大时内积过大导致 softmax 饱和。
3.3 Multi-Head Attention¶
核心: 多组 Q/K/V 投影, 各自做 attention, 拼接。
MultiHead(Q, K, V) = Concat(head_1, ..., head_h) × W^O
head_i = Attention(Q × W^Q_i, K × W^K_i, V × W^V_i)
好处: - 不同 head 学不同关系 (语法 / 语义 / 上下文) - 等价于 h 个独立 attention 并行 - 头数 dim 拆分, 不增参数
3.4 KV Cache 原理¶
问题: 推理生成每个 token 时, 重算历史 K, V → O(n²) 解决: 缓存历史的 K, V 矩阵 - 每生成 1 个 token, 只算 1 行新 K, V - 总复杂度 O(n)
内存:
KV = 2 × n_layer × n_head × head_dim × seq_len × batch × dtype_size
7B 模型, 2048 context, FP16: ~1 GB
3.5 Flash Attention 3 大技巧¶
- Tiling: Q/K/V 分块, 在 SRAM 算 (Ampere 192KB)
- Recompute: 不存 attention matrix, 反向时重算
- Online Softmax: 分块算 softmax, 数学等价
收益: 内存 O(n²) → O(n), 速度 2-4×, 数学精确等价。
四 · 编程题 (2 题)¶
4.1 Self-Attention 实现¶
import torch
import torch.nn.functional as F
def self_attention(Q, K, V, mask=None):
d_k = Q.size(-1)
# 1. 相似度
scores = Q @ K.transpose(-2, -1) / (d_k ** 0.5)
# 2. Mask (decoder causal)
if mask is not None:
scores = scores.masked_fill(mask == 0, float('-inf'))
# 3. Softmax
attn = F.softmax(scores, dim=-1)
# 4. 加权
return attn @ V
# 测试
seq_len, d_k = 10, 64
Q = torch.randn(1, seq_len, d_k)
K = torch.randn(1, seq_len, d_k)
V = torch.randn(1, seq_len, d_k)
out = self_attention(Q, K, V)
print(out.shape) # (1, 10, 64)
4.2 BPE Tokenizer 简化¶
def bpe_train(corpus, num_merges=10):
# 初始化字符表
vocab = set()
for word in corpus:
for ch in word:
vocab.add(ch)
# 切分词为字符
splits = {tuple(word) + ('</w>',): 1 for word in corpus}
for _ in range(num_merges):
# 找最高频相邻对
pairs = {}
for word, freq in splits.items():
for i in range(len(word) - 1):
pair = (word[i], word[i + 1])
pairs[pair] = pairs.get(pair, 0) + freq
if not pairs:
break
best_pair = max(pairs, key=pairs.get)
# 合并
new_splits = {}
for word, freq in splits.items():
new_word = []
i = 0
while i < len(word):
if i < len(word) - 1 and word[i] == best_pair[0] and word[i + 1] == best_pair[1]:
new_word.append(best_pair[0] + best_pair[1])
i += 2
else:
new_word.append(word[i])
i += 1
new_splits[tuple(new_word)] = freq
splits = new_splits
return splits
# 测试
corpus = ["low", "lower", "newest", "widest"]
print(bpe_train(corpus, num_merges=5))
五 · 评分标准¶
| 题号 | 分值 |
|---|---|
| 单选 ×8 | 32 分 |
| 多选 ×4 | 20 分 |
| 简答 ×5 | 30 分 |
| 编程 ×2 | 18 分 |
总分 ≥ 80: 优秀 总分 ≥ 60: 合格
六 · 易错点¶
- BPE vs WordPiece: BPE 用频率, WordPiece 用互信息
- Attention 缩放: √d_k 必须有, 否则 softmax 饱和
- Causal Mask: Decoder 才需要, Encoder 不需要
- KV Cache 内存: 7B 模型 2048 context 已经 1GB, 长 context 是 OOM 主因
- Flash Attention: 数学精确等价, 不是近似