Skip to content

分词与词表 — 练习

练习 1:使用 llama-cli 测试分词

使用 llama-cli --verbose-prompt 查看一段中文文本的分词结果,分析哪些 token 是完整的汉字,哪些被拆分。

参考答案

运行命令:

bash
./llama-cli -m model.gguf -p "你好世界" --verbose-prompt

输出会显示 token 序列和对应的文本。对于 LLaMA 模型,中文通常被编码为多个 byte-fallback token,因为 SPM 词表中中文字符覆盖有限。

练习 2:追踪 BPE 编码过程

llama-vocab.cpp 中找到 BPE 编码的实现,画出从输入 "hello" 到 token IDs 的完整流程。

参考答案

流程:

  1. llama_tokenize() 调用内部 llama_vocab::tokenize()
  2. 文本 "hello" 经过预分词(GPT-2 风格正则分割)
  3. "hello" 执行 BPE 编码:
    • 初始: [h, e, l, l, o]
    • 合并 ll["h", "e", "ll", "o"]
    • 查找词表得到对应的 token IDs
  4. 返回 [token_id_h, token_id_e, token_id_ll, token_id_o]

练习 3:比较不同模型的词表

下载两个不同架构的 GGUF 模型,用 gguf-py 分别查看它们的词表大小和类型。

参考答案
python
from gguf import GGUFReader

for model_path in ["llama.gguf", "gpt2.gguf"]:
    reader = GGUFReader(model_path)
    vocab_type = reader.fields.get("tokenizer.ggml.model")
    n_tokens = reader.fields.get("tokenizer.ggml.n_tokens")
    print(f"{model_path}: type={vocab_type}, n_tokens={n_tokens}")

典型结果:

  • LLaMA 2: SPM, 32000 tokens
  • GPT-2: BPE, 50257 tokens
  • Qwen2: BPE, 151936 tokens

练习 4:追踪 HybridDNA 分词过程

假设输入为 "基因序列 <dna>ACGTACGT</dna> 结束",追踪 HybridDNA 分词器的处理流程。思考:<dna></dna> 标签是如何被检测和处理的?ACGTACGT 会被分成哪些 k-mer?

参考答案

处理流程:

  1. 检测到 <dna> 标签,切换到 DNA 模式
  2. ACGTACGT 按 6-base k-mer 分词:
    • 前 6 个碱基 ACGTAC → 对应 DNA k-mer token
    • 剩余 2 个碱基 GT 不足 6 个,需要根据具体实现处理(可能补齐或使用短 k-mer)
  3. 检测到 </dna> 标签,切回 BPE 模式
  4. "基因序列 "" 结束" 分别走标准 BPE 编码

如果输入中包含非 ACGT 字符(如 ACGTXACGT),X 会被替换为 <oov> token。

拓展挑战

  • 阅读 Unicode 处理代码 (unicode.cpp),理解 byte-fallback 机制
  • 实现一个简单的 BPE 分词器(Python),与 llama.cpp 的结果对比
  • 分析 chat template 如何影响分词结果