Tokenizer 设计哲学:BPE、WordPiece 与 Unigram 的权衡
深入剖析 LLM Tokenizer 的核心算法、设计决策和实际影响,覆盖 BPE/WordPiece/Unigram/SentencePiece 的原理对比和中文场景的特殊考量。
Tokenizer 是 LLM 中最被低估的组件之一。它决定了模型 “看到” 什么、如何表示文本,直接影响模型的效率、能力和成本。一个好的 Tokenizer 设计可以让模型事半功倍,而一个差的设计则可能成为瓶颈。
一、为什么 Tokenizer 如此重要
1.1 Tokenizer 的角色
Tokenizer 是文本和模型之间的桥梁——它将连续的文本序列切分为离散的 token 序列,每个 token 对应词表(vocabulary)中的一个 ID。
输入文本: "大模型改变了世界"
↓ Tokenizer
Token 序列: ["大", "模型", "改变", "了", "世界"]
↓ Embedding
向量序列: [v₁, v₂, v₃, v₄, v₅]
↓ Transformer
...
1.2 Tokenizer 影响全局
Tokenizer 的设计决策会波及整个系统:
| 影响维度 | 具体表现 |
|---|---|
| 模型能力 | token 粒度决定了模型的最小理解/生成单位 |
| 训练效率 | 相同文本,不同 Tokenizer 产生的 token 数差异可达 2-5 倍 |
| 推理成本 | token 数量直接决定计算量和延迟 |
| 上下文长度 | 同样的 4K context,不同 Tokenizer 能装下的文本量不同 |
| API 定价 | 按 token 计费,Tokenizer 效率直接影响成本 |
| 多语言公平性 | 低效的 Tokenizer 会 “惩罚” 某些语言的用户 |
1.3 Tokenizer Tax
一个生动的概念是 “Tokenizer Tax”——同样的含义,不同语言或不同 Tokenizer 下需要的 token 数不同:
"Hello, how are you?"
├── GPT-4 (cl100k): 6 tokens
├── LLaMA: 6 tokens
└── GPT-2: 6 tokens
"你好,最近怎么样?"
├── GPT-4 (cl100k): 7 tokens (1.17x)
├── LLaMA: 11 tokens (1.83x) ← 中文效率很低
└── Qwen: 5 tokens (0.83x) ← 中文优化
LLaMA 的 Tokenizer 对中文非常不友好——同样含义的中文文本需要将近 2 倍的 token,这意味着中文用户的推理成本翻倍、有效上下文长度减半。
二、核心算法详解
2.1 Byte-Pair Encoding (BPE)
原理:BPE 最初是一种数据压缩算法,后来被引入 NLP。
训练过程:
- 初始化:将每个字符(或字节)作为基础 token
- 统计所有相邻 token 对的出现频率
- 将出现频率最高的 token 对合并为新 token
- 重复步骤 2-3,直到达到目标词表大小
示例:
初始: l o w </w> (出现 5 次)
l o w e r </w> (出现 2 次)
n e w e s t </w> (出现 6 次)
合并 1: (e, s) → es (频率: 6+...)
合并 2: (es, t) → est (频率: 6)
合并 3: (l, o) → lo (频率: 7)
...
变体:Byte-Level BPE
GPT-2/GPT-4 使用的是 Byte-Level BPE——基础单位不是字符而是字节(256 个),这样可以表示任何 Unicode 文本而不需要 UNK token。
优点:
- 简单直观,实现容易
- 压缩效率好
- 是目前最主流的方法
缺点:
- 贪心算法,不一定全局最优
- 合并顺序是确定性的(同一文本只有一种切分方式)
2.2 WordPiece
原理:由 Google 提出,BERT 使用。与 BPE 类似,但合并策略不同。
关键区别:
- BPE 合并频率最高的对
- WordPiece 合并使得语言模型似然最大的对
这意味着 WordPiece 偏好合并那些 “共现概率高于独立出现概率” 的 token 对——即信息论意义上的高互信息对。
特点:
- 子词以
##前缀标记(如 “playing” → [“play”, “##ing”]) - 主要在 BERT 系列中使用
- 理论上比 BPE 更优,但实际差异通常很小
2.3 Unigram Language Model
原理:由 Kudo(SentencePiece 作者)提出,是一种完全不同的思路。
训练过程:
- 从一个非常大的候选词表开始
- 训练一个 Unigram 语言模型:
- 计算每个候选 token 的 “价值”(移除它会增加多少 Loss)
- 移除价值最低的 token
- 重复步骤 2-4,直到达到目标词表大小
关键优势:概率化切分
Unigram 可以为同一文本输出多种切分方式,每种有不同的概率:
"unaffable"
├── ["un", "aff", "able"] P = 0.45
├── ["una", "ff", "able"] P = 0.25
├── ["un", "a", "ff", "able"] P = 0.15
└── ...
这在训练时可以做 子词正则化(Subword Regularization)——每次训练随机采样一种切分,增加训练数据多样性,类似数据增强。
2.4 SentencePiece
SentencePiece 不是一种新的分词算法,而是一个语言无关的分词框架:
- 支持 BPE 和 Unigram 两种算法
- 直接处理原始文本(不需要预分词)
- 将空格作为特殊字符
▁处理 - 语言无关——对中文、日文等无空格语言同样适用
LLaMA、T5、PaLM 等都使用 SentencePiece。
三、词表设计决策
3.1 词表大小
词表大小是最重要的设计参数之一:
| 模型 | 词表大小 | 特点 |
|---|---|---|
| GPT-2 | 50,257 | 早期标准 |
| LLaMA-1 | 32,000 | 精简词表 |
| LLaMA-2 | 32,000 | 同上 |
| LLaMA-3 | 128,256 | 大幅扩展 |
| GPT-4 (cl100k) | 100,256 | 大词表 |
| Qwen-2 | 151,936 | 超大词表 |
| DeepSeek-V2 | 102,400 | 大词表 |
词表大小的权衡:
小词表 (32K) 大词表 (128K+)
├── Embedding 矩阵小 ├── Embedding 矩阵大
├── 需要更多 token 表示文本 ├── 更少的 token
├── 训练需要更多步 ├── 训练步数更少
├── 对小模型友好 ├── 对大模型友好
└── 多语言表示效率低 └── 多语言表示效率高
关键计算:
Embedding 参数量 = 词表大小 × 隐藏维度
| 词表 | d_model | Embedding 参数 | 占总参数比例 (7B) |
|---|---|---|---|
| 32K | 4096 | 131M | 1.9% |
| 100K | 4096 | 410M | 5.9% |
| 128K | 4096 | 524M | 7.5% |
| 152K | 4096 | 622M | 8.9% |
对于大模型(>7B),Embedding 参数占比很小,因此大词表的代价相对不高。但对于小模型(<1B),大词表会显著增加参数量。
3.2 特殊 Token 设计
| Token | 用途 | 示例 |
|---|---|---|
<bos> | 序列开始 | 标记序列起点 |
<eos> | 序列结束 | 标记序列终点(也用于停止生成) |
<pad> | 填充 | 批处理时对齐长度 |
<unk> | 未知 | Byte-level BPE 通常不需要 |
| `< | im_start | >` |
| `< | im_end | >` |
[INST] [/INST] | 指令标记 | LLaMA 格式 |
<tool_call> | 工具调用 | Function Calling |
特殊 Token 的设计直接影响模型的交互格式和功能边界。
3.3 预分词(Pre-tokenization)
在 BPE/WordPiece 之前,通常需要一步预分词来确定基本边界:
GPT-2/4 的正则表达式:
pat = r"""'s|'t|'re|'ve|'m|'ll|'d| ?\p{L}+| ?\p{N}+| ?[^\s\p{L}\p{N}]+|\s+(?!\S)|\s+"""
这个正则表达式的作用:
- 常见缩写保持完整(‘s, ‘t, ‘re 等)
- 连续字母作为一个单元
- 连续数字作为一个单元
- 空格作为下一个词的一部分
SentencePiece 的做法:
- 不做预分词,直接处理原始字节流
- 将空格编码为特殊字符
▁ - 语言无关,不依赖任何语言特定的规则
四、中文 Tokenizer 的特殊挑战
4.1 中文的独特性
中文在分词上面临几个独特挑战:
- 无空格:中文词之间没有空格分隔
- 字词粒度:一个汉字可以是独立的词,也可以是词的一部分
- 字符集庞大:常用汉字约 4,000-6,000 个,总量超过 80,000
- 编码效率:UTF-8 中每个汉字占 3 个字节
4.2 不同粒度的比较
文本: "自然语言处理是人工智能的核心技术"
字级切分: 自/然/语/言/处/理/是/人/工/智/能/的/核/心/技/术
词级切分: 自然语言处理/是/人工智能/的/核心技术
BPE 切分: 自然/语言/处理/是/人工/智能/的/核心/技术 (典型)
4.3 中文优化策略
为中文优化 Tokenizer 的常见策略:
1. 增加中文 Token:
- 在词表中显式添加高频中文词和字
- Qwen 的词表中有大量中文 token,效率极高
- 典型做法:在基础词表外额外训练一个中文 BPE
2. 词表扩展(Vocabulary Expansion):
- Chinese LLaMA 的做法:在 LLaMA 词表基础上新增 20,000 中文 token
- 扩展后初始化新 token 的 Embedding(用相关 token 的平均值)
- 然后做中训练让新 token 的 Embedding 收敛
3. 混合粒度:
- 高频词保持完整(“人工智能”、“机器学习”)
- 低频词切分为字或子词
- 通过 BPE 自然实现
4.4 压缩率对比
不同 Tokenizer 对中文的压缩效率(bytes per token):
| Tokenizer | 中文 Bytes/Token | 英文 Bytes/Token | 中文效率 |
|---|---|---|---|
| GPT-2 (50K) | 1.5 | 4.2 | 差 |
| LLaMA (32K) | 1.8 | 4.5 | 很差 |
| GPT-4 cl100k (100K) | 3.4 | 4.2 | 中等 |
| Qwen-2 (152K) | 4.1 | 4.3 | 好 |
| DeepSeek (100K) | 3.8 | 4.2 | 较好 |
| Yi (64K) | 3.5 | 4.2 | 中等偏上 |
越高越好——意味着每个 token 编码了更多的原始信息。
LLaMA 的 1.8 Bytes/Token 意味着平均一个中文字符(3 bytes)需要 1.67 个 token——极其低效。而 Qwen 的 4.1 Bytes/Token 意味着平均 1.37 个中文字符才用一个 token——效率极高。
五、Tokenizer 训练实践
5.1 训练数据的选择
Tokenizer 的训练数据直接决定了词表的构成:
关键原则:
- 代表性:训练数据应该代表模型将要处理的文本分布
- 多样性:覆盖所有目标语言和领域
- 质量:避免噪声数据影响词表
- 规模:通常 10-100GB 文本足够
常见错误:
- 只用英文数据训练 → 中文效率极低
- 只用正式文本训练 → 对口语/网络用语效率低
- 训练数据太小 → 低频词的合并模式不稳定
5.2 词表大小的选择
经验法则:
| 模型规模 | 推荐词表大小 | 理由 |
|---|---|---|
| < 1B | 32K - 64K | Embedding 占比大,不宜过大 |
| 1B - 10B | 64K - 128K | 平衡点 |
| > 10B | 100K - 200K | Embedding 占比小,大词表提升效率 |
| 多语言 (>10种) | 128K - 256K | 每种语言都需要足够的 token |
5.3 评估 Tokenizer 质量
定量指标:
- 压缩率(Compression Ratio):Bytes per Token,越高越好
- 续写困惑度(Fertility):平均一个词被切成多少个 token,越低越好
- 覆盖率:多少比例的常见词可以用单个 token 表示
- UNK 率:出现 UNK token 的比例(Byte-level 应为 0)
定性检查:
- 常见词是否被合理切分
- 专业术语是否被保留
- 数字和标点是否合理处理
- 代码是否合理切分(缩进、操作符等)
六、前沿研究方向
6.1 无 Tokenizer 模型
一个激进的方向是完全抛弃 Tokenizer,直接在字节级别建模:
- MegaByte(Meta, 2023):多尺度 Transformer 处理字节序列
- ByT5(Google, 2022):字节级别的 T5
优势:彻底消除 Tokenizer 偏见,对所有语言公平 挑战:序列长度大幅增加(4-5倍),计算成本显著上升
6.2 动态词表
固定词表的一个问题是不能适应新出现的词汇。动态词表方向探索了:
- 在推理时根据输入自适应调整切分粒度
- 定期用新数据更新词表
6.3 多模态 Tokenizer
将文本、图像、音频统一到一个 Token 空间:
- 图像通过 VQ-VAE 或 CLIP 离散化
- 音频通过 Encodec 等编码器离散化
- 统一的词表实现多模态生成
七、总结
| 算法 | 原理 | 主要使用者 | 特点 |
|---|---|---|---|
| BPE | 频率贪心合并 | GPT 系列, LLaMA | 最主流,简单高效 |
| WordPiece | 似然最大合并 | BERT | 理论更优,实际差异小 |
| Unigram | 概率化切分 | T5, PaLM (via SP) | 支持子词正则化 |
| SentencePiece | 语言无关框架 | LLaMA, T5, mT5 | 支持 BPE + Unigram |
核心建议:
- 新项目首选 SentencePiece + BPE/Unigram
- 词表大小至少 64K,多语言场景 128K+
- 训练数据必须覆盖所有目标语言
- 认真评估中文等非拉丁语系的效率
- 词表设计是一次性决策——后续几乎不可能更改(除非重新预训练)
Tokenizer 是 LLM 的 “视网膜”——它决定了模型能 “看到” 什么。选好了,事半功倍。