跳转至

第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 Google 语言无关, 直接训
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 大技巧

  1. Tiling: Q/K/V 分块, 在 SRAM 算 (Ampere 192KB)
  2. Recompute: 不存 attention matrix, 反向时重算
  3. 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: 合格


六 · 易错点

  1. BPE vs WordPiece: BPE 用频率, WordPiece 用互信息
  2. Attention 缩放: √d_k 必须有, 否则 softmax 饱和
  3. Causal Mask: Decoder 才需要, Encoder 不需要
  4. KV Cache 内存: 7B 模型 2048 context 已经 1GB, 长 context 是 OOM 主因
  5. Flash Attention: 数学精确等价, 不是近似