文章目录
- [1. 为什么需要 BPE?](#1. 为什么需要 BPE?)
-
- [方法一:一个字母一个 Token](#方法一:一个字母一个 Token)
- [方法二:一个单词一个 Token](#方法二:一个单词一个 Token)
- [2. BPE 就是在两者之间折中](#2. BPE 就是在两者之间折中)
- [3. 用一个超级简单的例子理解 BPE](#3. 用一个超级简单的例子理解 BPE)
- [4. 第一次合并](#4. 第一次合并)
- [5. 再统计一次](#5. 再统计一次)
- [6. 一直重复](#6. 一直重复)
- [7. 所以 BPE 的算法其实就这几行](#7. 所以 BPE 的算法其实就这几行)
- [8. 为什么这样做最后会产生「词根」「后缀」?](#8. 为什么这样做最后会产生「词根」「后缀」?)
- [9. 再看一个现实一点的例子](#9. 再看一个现实一点的例子)
- [10. 遇到从没见过的新词怎么办?](#10. 遇到从没见过的新词怎么办?)
- [11. 那为什么 GPT 经常说「Byte-level BPE」?](#11. 那为什么 GPT 经常说「Byte-level BPE」?)
-
- [UTF-8 是什么关系?](#UTF-8 是什么关系?)
- [12. 中文 BPE 是什么样?](#12. 中文 BPE 是什么样?)
- [13. 这也解释了一个很有意思的现象](#13. 这也解释了一个很有意思的现象)
- [14. 这就是为什么代码 Tokenizer 也很有意思](#14. 这就是为什么代码 Tokenizer 也很有意思)
- [15. BPE 有两个阶段,千万别混](#15. BPE 有两个阶段,千万别混)
-
- [阶段一:训练 Tokenizer](#阶段一:训练 Tokenizer)
- 阶段二:真正给模型分词
- [16. 用一张脑图记住 BPE](#16. 用一张脑图记住 BPE)
- [17. 为什么它叫 Byte **Pair** Encoding?](#17. 为什么它叫 Byte Pair Encoding?)
- [18. 用一句话做学习检验](#18. 用一句话做学习检验)
可以。用费曼学习法讲 BPE,关键不是先背"Byte Pair Encoding",而是先把它理解成一句人话:
BPE 就是在大量文本里,发现哪些相邻的小片段经常一起出现,然后把它们粘成一个更大的 Token。反复粘,直到词表够大。
你可以把它理解成:给常见字符串建立快捷键。
1. 为什么需要 BPE?
假设大模型看到一句:
text
I am playing football
模型不能直接处理字符串,它最终要处理的是一串数字,例如:
text
[40, 716, 5732, 9012]
所以中间需要一个 Tokenizer(分词器):
text
文本
↓
Tokenizer
↓
Token
↓
Token ID
↓
神经网络
问题来了:
到底应该怎么切?
方法一:一个字母一个 Token
比如:
text
playing
切成:
text
p l a y i n g
好处是词表非常小。
26 个字母基本就够用了。
但坏处非常明显:
text
internationalization
可能变成二十多个 Token。
模型处理序列的长度直接爆炸。
方法二:一个单词一个 Token
把:
text
playing
直接作为一个 Token。
这样非常爽:
text
playing → 一个 Token
但是马上又出问题。
英语单词太多:
text
play
plays
played
playing
player
players
playground
...
更别说:
text
OpenAI
DeepSeek
ChatGPT
wg666
awefwef123
你不可能提前把世界上所有字符串都放进词表。
2. BPE 就是在两者之间折中
BPE 的思想是:
非常常见的字符串 → 合并成一个 Token。
不常见的字符串 → 继续拆成更小的 Token。
例如:
text
playing
最终可能切成:
text
play
ing
而不是:
text
p l a y i n g
也不是一定要求:
text
playing
整体成为一个 Token。
这就是 BPE 最核心的思想。
3. 用一个超级简单的例子理解 BPE
假设我们的整个训练语料只有:
text
abab
abab
abac
一开始 BPE 什么都不懂。
所以全部拆成最小单位:
text
a b a b
a b a b
a b a c
现在开始统计:
哪两个相邻字符一起出现次数最多?
第一次统计
看看:
text
a b
b a
a b
abab 出现两次。
然后:
text
a b
b a
a c
abac 出现一次。
所以统计结果大概是:
| 相邻组合 | 次数 |
|---|---|
a + b |
5 |
b + a |
3 |
a + c |
1 |
发现:
text
a + b
出现最多。
于是 BPE 做第一件事:
把
a和b合并成一个新 Token:ab。
4. 第一次合并
原来:
text
a b a b
a b a b
a b a c
现在就变成:
text
ab ab
ab ab
ab a c
词表原来有:
text
a
b
c
现在增加:
text
ab
变成:
text
a
b
c
ab
5. 再统计一次
现在整个语料是:
text
ab ab
ab ab
ab a c
重新统计相邻 Token。
你可能发现:
text
ab + ab
出现得最多。
于是:
text
ab + ab
合并成:
text
abab
现在:
text
abab
abab
ab a c
词表又多了:
text
abab
6. 一直重复
BPE 就不停重复:
text
统计最高频相邻 Token
↓
把它们合并
↓
加入词表
↓
重新统计
↓
继续合并
直到:
text
词表大小达到设定值
比如我们希望得到 50,000 个 Token,那就不断合并,直到词表差不多达到目标规模。
7. 所以 BPE 的算法其实就这几行
伪代码基本就是:
python
初始化:把文本拆成最小单位
while 词表大小 < 目标大小:
统计所有相邻 token pair
找到出现次数最多的 pair
把这个 pair 合并成新 token
记录这条合并规则
例如最终学习到了:
text
a + b → ab
ab + ab → abab
i + n → in
in + g → ing
p + l → pl
pl + ay → play
...
这些东西就是 BPE merge rules。
8. 为什么这样做最后会产生「词根」「后缀」?
这就是 BPE 很聪明的地方。
注意:
BPE 完全不懂英语语法。
它不知道:
text
ing
是进行时后缀。
但是训练语料里有:
text
playing
running
walking
working
talking
looking
reading
ing 出现实在太频繁。
于是经过:
text
i + n → in
in + g → ing
以后:
text
ing
自然就变成一个 Token。
于是:
text
playing
有可能变成:
text
play + ing
text
working
变成:
text
work + ing
text
walking
变成:
text
walk + ing
没有任何语言学家告诉 BPE:"ing 是后缀"。
它纯粹通过:
高频共现
自己"发现"了这个结构。
这点非常重要。
9. 再看一个现实一点的例子
假设语料里面经常出现:
text
happy
happier
happiness
unhappy
训练久了以后可能形成这些 Token:
text
happy
happi
ness
un
er
于是:
text
unhappy
可能:
text
un + happy
而:
text
happiness
可能:
text
happi + ness
但是注意:
BPE 并不保证符合真正的词法学。
它不是:
text
词根分析算法
而是:
text
字符串统计压缩算法
只不过语言天然存在大量重复结构,所以它最后经常看起来像是在学习词根、前缀和后缀。
10. 遇到从没见过的新词怎么办?
这正是 BPE 最大的价值之一。
比如训练的时候从来没有见过:
text
superduperAI2026
如果是传统的"一个单词一个词表项",那就是:
text
<UNK>
即 unknown。
很尴尬。
但 BPE 可以拆:
text
super
duper
AI
202
6
实在不行继续拆:
text
sup
er
du
per
A
I
2
0
2
6
因此理论上:
只要最底层单位覆盖全部输入,就可以表示任意字符串。
11. 那为什么 GPT 经常说「Byte-level BPE」?
这里再进一层。
最原始的 BPE 是 Byte Pair Encoding ,其实最早是个数据压缩算法,后来才被拿来做 NLP 分词。
现代 GPT 类模型常见的是:
Byte-level BPE
最底层甚至不是:
text
中文字符
英文字母
而是:
text
byte(字节)
UTF-8 是什么关系?
比如:
text
A
UTF-8:
text
41
只有一个 byte。
但中文:
text
我
UTF-8 编码通常需要 3 个 byte。
所以 byte-level tokenizer 最底层原则上可以把:
text
任何 UTF-8 文本
都表示出来。
包括:
text
中文
英文
Emoji
代码
奇怪符号
这解决了 OOV(Out Of Vocabulary,词表外字符)问题。
12. 中文 BPE 是什么样?
假设语料里面疯狂出现:
text
人工智能
人工智能
人工智能
人工神经网络
人工智能模型
最开始可能是:
text
人 工 智 能
发现:
text
人 + 工
特别常见。
合成:
text
人工
然后:
text
智 + 能
特别常见:
text
智能
然后:
text
人工 + 智能
又非常常见。
可能进一步得到:
text
人工智能
于是最终:
text
我正在研究人工智能
可能被切成类似:
text
我
正在
研究
人工智能
注意还是那句话:
不是人为规定"人工智能是一个词"。
而是因为这个字符串在训练数据里足够常见。
13. 这也解释了一个很有意思的现象
为什么有些词只占 1 Token:
text
the
function
import
而一些奇怪词可能占很多 Token:
text
xqwejasd123
因为前者在训练数据中出现过无数次。
BPE 会觉得:
"天天见,直接给你办个 VIP,整个字符串一个编号。"
而后者:
"你谁啊?没怎么见过。拆开处理。"
所以可以粗略理解为:
出现得越频繁 → 越倾向形成大 Token。
越罕见 → 越容易被拆碎。
14. 这就是为什么代码 Tokenizer 也很有意思
例如训练数据里面大量存在 Java:
java
public static void main
那么 tokenizer 很可能学会很多类似:
text
public
static
void
main
甚至:
text
public static
是否成为一个 Token,要看具体 tokenizer 和语料统计。
而一个极其罕见的变量名:
java
wgHuangJiaSuperServiceImpl666
很可能被切成:
text
wg
Huang
Jia
Super
Service
Impl
666
甚至切得更碎。
这也是为什么:
Token 数量 ≠ 字符数量 ≠ 单词数量。
15. BPE 有两个阶段,千万别混
这是理解 tokenizer 很关键的一点。
阶段一:训练 Tokenizer
拿大量训练文本:
text
海量语料
↓
统计 pair
↓
不断 merge
↓
得到词表 + merge rules
最后保存:
text
Vocabulary
Merge Rules
例如:
text
i + n → in
in + g → ing
p + l → pl
...
这个阶段通常只做一次。
阶段二:真正给模型分词
以后用户输入:
text
playing
不是重新统计全互联网。
而是拿已经训练好的:
text
merge rules
执行。
例如初始:
text
p l a y i n g
根据已经学好的合并优先级,逐步:
text
p l → pl
pl a → pla
pla y → play
i n → in
in g → ing
最后:
text
play | ing
然后查词表:
text
play → 1382
ing → 287
于是模型真正收到:
text
[1382, 287]
16. 用一张脑图记住 BPE
以后你只需要在脑子里记这个:
text
BPE
│
┌──────────┴─────────┐
│ │
为什么? 怎么做?
│ │
字符太碎 找最高频相邻 pair
单词词表太大 ↓
│ 合并
└────────┬───────────┘
↓
高频字符串
↓
一个 Token
↓
低频字符串继续拆
最终实现:
text
字符级 单词级
│ │
太碎 词表爆炸
│ │
└──────── BPE ────────────┘
↑
折中
17. 为什么它叫 Byte Pair Encoding?
关键就在 Pair:
BPE 每一步只看:
两个相邻单位
例如:
text
i n g
不能第一步直接说:
text
ing
是最高频三元组,然后一次合并。
而是:
text
i + n → in
再:
text
in + g → ing
所以"大 Token"是由小 Token 一层层长出来的。
例如:
text
t + i → ti
ti + on → tion
a + tion → ation
iz + ation → ization
最终甚至能形成很长的 Token。
18. 用一句话做学习检验
现在假设一个完全不懂 NLP 的朋友问你:
什么是 BPE?
如果你能回答:
BPE 就是先把文本拆得很细,然后统计哪些相邻片段最经常一起出现,把最高频的两个合成一个新 Token,再重复这个过程。这样常见字符串会变成一个 Token,罕见字符串仍然可以拆成多个小 Token,既不会让序列太长,也不用维护包含所有单词的巨大词表。
那么 BPE 的核心你已经掌握了。
最后给你一个面试级定义
如果面试官问:
"介绍一下 BPE 分词算法。"
可以回答成:
BPE 是一种基于频率的子词分词算法。它首先将语料拆分成字符或字节等基本单元,然后统计所有相邻 Token Pair 的出现频率,每轮选择最高频 Pair 合并成新的 Token,并将该合并操作加入 merge rules,重复直到达到预设词表大小。推理时按照训练阶段学习到的 merge rules 对输入文本进行合并,从而将文本编码为 Token 序列。它在字符级和词级分词之间取得折中,高频字符串可以使用较少 Token 表示,同时低频词和未登录词仍然可以由更小的子词或字节组合表示。
如果你后面准备学大模型,这里下一步最值得一起搞懂的是 BPE、WordPiece、Unigram/SentencePiece 到底有什么区别。这三个搞明白以后,LLM 的 tokenizer 基本就打通了。