BPE(字节对编码)
一种子词分词算法:从单字符出发,反复合并语料中出现频率最高的相邻字符对,直到达到目标词表大小。GPT 系列 Tokenizer 均基于 BPE 及其变体。
BPE(字节对编码)
一句话理解
BPE 是一种"从字符开始、逐步合并"的分词算法——把最常一起出现的字符对反复粘在一起,直到词表够大为止。
算法原理
BPE 分为训练阶段和编码阶段:
训练阶段(学习合并规则)
- 将训练语料中的每个词拆成单字符序列
- 统计所有相邻字符对的出现频率
- 将频率最高的字符对合并为一个新符号,加入词表
- 重复步骤 2-3,直到词表达到目标大小
python
# 简化示例:训练语料 ["low", "lower", "newest", "widest"]
# 初始:每个词拆成字符
{'l o w </w>': 5, 'l o w e r </w>': 2, 'n e w e s t </w>': 6, 'w i d e s t </w>': 3}
# 第1轮:最频繁的相邻对是 (e, s) → 合并为 "es"
# 第2轮:最频繁的相邻对是 (es, t) → 合并为 "est"
# 第3轮:最频繁的相邻对是 (est, </w>) → 合并为 "est</w>"
# ... 继续直到达到目标词表大小
编码阶段(应用合并规则)
对新文本,先拆成字符,然后按训练时的合并顺序依次应用合并规则:
python
# 已学到的合并规则(按顺序):(e,s)→es, (es,t)→est, (est,</w>)→est</w>, (l,o)→lo, ...
"lowest" → ['l','o','w','e','s','t'] → ['lo','w','est'] → [token_id_1, token_id_2, token_id_3]
为什么选择 BPE
| 优势 | 说明 |
|---|---|
| 无 OOV 问题 | 最坏情况下退化为字符级编码,永远不会遇到"未知词" |
| 自适应粒度 | 高频词保留完整,低频词自动拆分为子词片段 |
| 语言无关 | 不依赖任何语言学规则,中英文、代码通吃 |
| 可控词表大小 | 通过合并轮数精确控制词表大小(通常 30k-100k) |
Byte-level BPE
GPT-2 起,OpenAI 采用了 Byte-level BPE:不从 Unicode 字符开始,而是从字节(0-255)开始。这样基础词表只有 256 个字节,可以编码任意语言和二进制数据,彻底消除 OOV 问题。
BPE 与其他子词算法
- WordPiece(BERT):合并策略不同——BPE 选频率最高的对,WordPiece 选使语言模型似然度提升最大的对
- SentencePiece(LLaMA、T5):将空格也视为普通字符,直接在原始文本上训练,无需预分词
- Unigram(SentencePiece 的一种模式):从大词表开始逐步删减,方向与 BPE 相反