大模型的分词算法中,经常遇到BPE, BBPE. 什么是BPE和BBPE? 如何理解这两个概念,一文通俗易懂解释、附案例说明。
BPE(Byte Pair Encoding)是一种基于频率统计的子词分词算法,通过不断合并语料中出现频率最高的相邻符号对来构建词表,从而在词表大小和泛化能力之间取得平衡。
BBPE(Byte-Level BPE)则将最小单位从字符扩展到UTF-8字节,先以256个字节作为基础词表,再执行BPE合并,因此理论上能够编码任意文本,不存在OOV问题。GPT-2、GPT-3、GPT-4等模型均采用了BBPE思想。
以往的博客有一个共同问题:
它们讲的是算法流程,但没有讲清楚“为什么要这么干”。
我换一个更接近人类学习语言的例子,让大家迅速理解这两个算法的思想。
先忘掉BPE
假设你是个刚学英语的小孩。
你见过下面这些单词:
play
playing
played
player
playground
老师问:
你发现什么规律了吗?
你会发现:
play
经常出现。
后面变化的是:
ing
ed
er
ground
于是你的大脑自然形成:
play + ing
play + ed
play + er
play + ground
而不是:
p+l+a+y+i+n+g
事实上:
BPE就是在模拟这种学习过程。
第一步:把所有单词拆成最小单位
训练语料:
play
playing
played
player
初始状态:
p l a y
p l a y i n g
p l a y e d
p l a y e r
此时词表:
p
l
a
y
i
n
g
e
d
r
模型现在什么都不懂。
它只知道:
字符
第二步:统计谁总是挨着出现
观察:
p l
l a
a y
出现次数:
| Pair | 次数 |
|---|---|
| p l | 4 |
| l a | 4 |
| a y | 4 |
| y i | 1 |
| i n | 1 |
| n g | 1 |
| y e | 2 |
BPE规则:
谁出现最多,我先记住谁。
于是:
p+l
被合并。
得到新Token:
pl
词表变成:
pl
a
y
...
语料变成:
pl a y
pl a y i n g
pl a y e d
pl a y e r
第三步:继续找最高频Pair
现在统计:
(pl,a)
(a,y)
次数:
(pl,a)=4
(a,y)=4
假设先选:
(pl,a)
合并:
pla
语料变:
pla y
pla y i n g
pla y e d
pla y e r
第四步
统计:
(pla,y)=4
最高。
合并:
play
语料:
play
play i n g
play e d
play e r
这时候发生了什么?
模型突然发现:
play
是个高频结构。
于是:
play
成为一个独立Token。
这就是BPE最核心思想:
高频结构保留,低频结构拆开。
为什么这样更好?
看一句话:
I am playing football
如果按字符:
I
a
m
p
l
a
y
i
n
g
...
14个以上Token。
如果BPE:
I
am
play
ing
football
可能只剩5个Token。
节省大量计算。
再举一个中文例子
假设训练数据:
人工智能
人工客服
人工审核
人工标注
初始化:
人 工 智 能
人 工 客 服
人 工 审 核
人 工 标 注
统计:
(人,工)
出现:
4次
最高。
合并:
人工
语料:
人工 智能
人工 客服
人工 审核
人工 标注
继续统计:
(人工,智能)
1次
(人工,客服)
1次
...
都不高。
于是最终词表可能有:
人工
但没有:
人工智能
人工客服
这意味着:
模型学会了:
人工
这个概念。
看到新词:
人工翻译
也能理解。
因为:
人工 + 翻译
这就是BPE最大的价值
不是记住单词。
而是记住:
高频子词(Subword)
那BBPE又是什么?
这里很多人第一次学会懵。
因为名字只差一个B。
实际上差别非常大。
BPE:
字符
↓
合并
↓
Token
BBPE:
字节(Byte)
↓
合并
↓
Token
什么叫字节?
电脑不认识:
A
你
😊
电脑只认识:
01010101
这种二进制。
例如:
字符:
A
ASCII:
65
字符:
B
ASCII:
66
所以:
AB
实际上:
65
66
BBPE训练过程
假设语料:
cat
cat
cat
car
转换字节:
c = 99
a = 97
t = 116
r = 114
得到:
99 97 116
99 97 116
99 97 116
99 97 114
统计:
99+97
出现:
4次
最高。
合并:
CA
(新Token)
编号:
256
语料变:
256 116
256 116
256 116
256 114
再统计:
256+116
出现:
3次
继续合并:
CAT
编号:
257
最后:
cat
变成一个Token。
为什么GPT不用普通BPE?
来看这个例子:
hello
训练过。
突然用户输入:
hello😊
普通BPE可能没见过:
😊
直接傻了。
但BBPE不会。
因为:
😊
也是字节组成。
例如:
240
159
152
138
(UTF-8编码)
那么:
hello😊
一定能拆成:
hello
240
159
152
138
一定能编码。
GPT为什么选BBPE
因为互联网有:
英文
中文
日文
韩文
Emoji
代码
乱码
特殊符号
如果普通BPE:
需要:
英文字符集
中文字符集
日文字符集
...
很麻烦。
BBPE只需要:
0~255
这256个字节。
理论上就能表示世界上所有文本。
最后用一句话彻底理解
把 BPE 想象成:
从“拼音识字”慢慢学习常见词根和词组。
例如:
p
→ pl
→ pla
→ play
逐步合并。
把 BBPE 想象成:
连字都不认,直接从电脑最底层的字节开始学习。
例如:
99
97
116
↓
ca
↓
cat
最终得到Token。
所以:
BPE = 字符级学习高频子词
BBPE = 字节级学习高频子词(GPT系列主流方案)
理解这一点后,你再去看 GPT Tokenizer 的 Token 数统计、Qwen Tokenizer、SentencePiece、WordPiece,基本就能一眼看懂它们到底在干什么了。
追问:BPE的名字是不是有误导性?B既然指的是Byte, 那为什么还要说是:BPE = 字符级学习高频子词 字符不应该是叫做Character吗?
这个疑问非常好,而且很多刚接触 Tokenizer 的人都会被这个名字绕晕。
实际上:
BPE 里的 B 根本不是 Byte。
很多人第一次看到:
BPE
BBPE
会自然理解成:
B = Byte
BB = Byte Byte
但这是错的。
BPE全称是什么?
BPE 的全称:
Byte Pair Encoding
这里的 Byte 确实是:
Byte
字节
但是这里有一个历史问题。
BPE最早根本不是分词算法
BPE最早诞生于1994年:
由:
Philip Gage
提出。
用于:
文件压缩
不是 NLP。
原始BPE处理的是:
字节流(Byte Stream)
例如:
65 66 65 66 65 66
即:
A B A B A B
它不断寻找:
AB
这种高频字节对。
然后替换。
例如:
ABABAB
变:
X X X
达到压缩目的。
所以名字里的:
Byte Pair Encoding
是历史遗留名称。
NLP后来借用了这个算法
2015年左右。
论文:
Neural Machine Translation of Rare Words with Subword Units
把BPE引入NLP。
但作者并没有真的处理Byte。
而是处理:
字符(Character)
例如:
l o w
统计:
(l,o)
(o,w)
然后不断合并。
所以实际流程:
Character
↓
Character Pair
↓
Merge
↓
Subword
但是大家仍然沿用:
BPE
这个名字。
没有改名。
因此严格来说:
现代NLP里的经典BPE其实是:
Character Pair Encoding
更准确。
只是没人这么叫。
那BBPE又是什么?
后来GPT-2团队发现:
字符级BPE有问题。
例如:
hello
你好
😊
字符集越来越大。
各种Unicode字符不好处理。
于是GPT-2提出:
我们不要从 Character 开始了。
改成:
UTF-8 Byte
开始。
流程变成:
Byte
↓
BPE
↓
Token
这时候才真正回到了:
Byte Pair Encoding
的原始含义。
所以有趣的现象出现了:
| 名称 | 实际处理对象 |
|---|---|
| BPE(NLP传统) | Character |
| BBPE(GPT-2) | Byte |
| 原始BPE(压缩算法) | Byte |
换句话说:
最开始的BPE是Byte。
后来NLP把它改成Character。
GPT-2又把它改回Byte。
为什么会出现BBPE这个名字?
严格来说:
GPT-2论文里甚至没有正式提出:
BBPE
这个术语。
GPT-2论文更多写的是:
Byte-level BPE
即:
BPE operating on bytes
后来社区为了区分:
Character-level BPE
和
Byte-level BPE
才逐渐出现:
BBPE
这个叫法。
最准确的理解方式
如果从工程角度分类:
BPE
├── Character-level BPE
│ (传统NLP)
│
└── Byte-level BPE
(GPT-2/GPT-3/GPT-4)
所以你看到:
BPE = 字符级学习高频子词
并不是说:
B = Character
而是说:
NLP领域里常说的BPE,虽然名字来自 Byte Pair Encoding,但实际训练时通常以 Character 作为初始符号集合。
这也是为什么很多人第一次学习时会觉得名字和实现完全对不上——因为它本来就是一个从压缩领域“借用过来”的算法名,后来含义发生了演化。

浙公网安备 33010602011771号