Skip to content

Byte Pair Encoding,字节对编码 —— LLM 最常用的分词算法,将文本拆分为模型词表中的 token。

为什么需要分词

模型只能处理数字。文本必须先变成 token ID 序列,才能做 Embedding 查表和后续计算。分词器决定"怎么切"直接影响模型能力:

  • 切得太细(按字符)→ 序列太长,注意力开销大
  • 切得太粗(按整词)→ 词表巨大,出现新词就废了
  • BPE 在两者之间自动平衡

核心原理

训练阶段: 从字符级开始,迭代合并最高频的相邻 token 对
  "h e l l o" → 合并 "ll" → "h e ll o" → 合并 "hel" → "hel lo"

推理阶段: 按学到的合并规则,从长到短匹配切分
  "hello world" → [hello, ▁world] → [token_id_42, token_id_1089]

ds4.c 实现了 GPT-2 字节级 BPE:所有 256 个字节值通过 gpt2_byte_to_codepoint 映射为可见 Unicode 码点(不可打印字节如 0x00 映射到 256+ 码点),这样任何二进制输入都能分词。

预分词规则:

  • 数字按三位分组(12345123,45,从左往右贪婪匹配)
  • CJK 字符单独切分
  • 空格与后续字符合并(▁hello

在 ds4.c 中的实现

c
// ds4.c — 分词主函数
ds4_tokenize_rendered_chat()    // 入口:渲染后的文本 → token ID 数组

// 关键步骤
bpe_emit_piece()                // 迭代查找最小 rank 的相邻对并合并
gpt2_byte_to_codepoint()        // 字节 → Unicode 码点映射

词表大小 129,280 个 token,对中英文都有良好覆盖。更大的词表意味着中文编码效率高,同样的上下文窗口能装更多内容。

相关概念

  • gguf — 词表存储在 GGUF 文件的元数据中
  • softmax — 分词后 token ID 经 Embedding 查表,最终通过 softmax 采样选出下一个 token

详见 Part 2 — BPE 分词器