Appearance
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+ 码点),这样任何二进制输入都能分词。
预分词规则:
- 数字按三位分组(
12345→123,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,对中英文都有良好覆盖。更大的词表意味着中文编码效率高,同样的上下文窗口能装更多内容。
相关概念
详见 Part 2 — BPE 分词器。