BPE Tokenizer 完整入门:从汉字编码到 GPT-2 风格 Byte-Level BPE

BPE Tokenizer 完整入门:从汉字编码到 GPT-2 风格 Byte-Level BPE

主题:汉字如何进入 GPT-2 风格 tokenizer,BPE 的统计算法是什么,完整算例是什么,还有 BPE、WordPiece、Unigram、SentencePiece 等算法的区别,以及主流大模型是否还在使用 BPE。


0. 一句话总览

大模型不能直接吃人类文字,它只能处理整数 token id。

所以文本进入大模型前,要经过:

text 复制代码
原始文本
  ↓
字符编码,例如 Unicode / UTF-8
  ↓
tokenizer 切分
  ↓
token id 序列
  ↓
embedding 向量
  ↓
Transformer

BPE tokenizer 的本质是:

用统计方法找出训练语料中最常一起出现的相邻片段,把它们合并成更大的 token,从而压缩文本长度。

GPT-2 风格 BPE 的特殊点是:

它不是直接从 Unicode 字符开始,而是先把文本转成 UTF-8 字节,然后对字节序列做 BPE 合并。


1. 汉字在计算机里先怎么表示?

1.1 Unicode:给每个字符一个编号

例如:

text 复制代码
中 → Unicode 码点 U+4E2D
国 → Unicode 码点 U+56FD
人 → Unicode 码点 U+4EBA

Unicode 负责回答:

这个字符在全世界字符表里的编号是多少?

但 Unicode 码点还不是计算机真正存储的字节。


1.2 UTF-8:把 Unicode 码点变成字节

计算机最终存的是字节,即 8-bit 数据。

例如:

text 复制代码
中 → U+4E2D → UTF-8: E4 B8 AD
国 → U+56FD → UTF-8: E5 9B BD

所以:

text 复制代码
中国 → E4 B8 AD E5 9B BD

大部分常用汉字在 UTF-8 里是 3 个字节。

字符 Unicode UTF-8 字节 字节数
A U+0041 41 1
U+4E2D E4 B8 AD 3
U+56FD E5 9B BD 3
😂 U+1F602 F0 9F 98 82 4

2. GPT-2 风格 BPE 如何处理汉字?

GPT-2 风格 tokenizer 的链路是:

text 复制代码
汉字文本
  ↓
UTF-8 bytes
  ↓
byte-to-unicode 映射
  ↓
BPE merge 合并
  ↓
token 字符串
  ↓
vocab 查询
  ↓
token id

重点:

GPT-2 风格 BPE 看到的不是"中"这个汉字本身,而是"中"的 UTF-8 字节序列。


2.1 以"中"为例

text 复制代码
中
  ↓ Unicode
U+4E2D
  ↓ UTF-8
E4 B8 AD

十进制就是:

text 复制代码
E4 B8 AD = 228 184 173

GPT-2 tokenizer 会把每个 byte 映射成一个可打印的 Unicode 字符。

大致可以理解为:

text 复制代码
0xE4 → ä
0xB8 → ¸
0xAD → ľ

于是:

text 复制代码
中 → E4 B8 AD → ä ¸ ľ → 举

注意:

举 不是乱码,而是 GPT-2 byte-level tokenizer 的内部 byte 表示。


2.2 以"中国"为例

text 复制代码
中 → E4 B8 AD
国 → E5 9B BD

所以:

text 复制代码
中国 → E4 B8 AD E5 9B BD

经过 GPT-2 的 byte-to-unicode 映射,大致变成:

text 复制代码
中国 → ä¸ľåĽ½

然后 BPE 会根据 merge 表决定是否合并:

text 复制代码
ä + ¸       → ä¸
ä¸ + ľ      → 举        # 可以表示"中"
å + Ľ       → åĽ
åĽ + ½      → åĽ½        # 可以表示"国"
举 + åĽ½  → ä¸ľåĽ½    # 可以表示"中国"

如果训练语料里"中国"非常常见,最终可能合并成一个 token。

如果没有学到整个"中国",可能拆成:

text 复制代码
中国 → 中 / 国

如果中文语料很少,甚至可能拆得更碎:

text 复制代码
中国 → E4 / B8 / AD / E5 / 9B / BD

3. tokenizer 的"学习"是不是统计?

是的。

BPE tokenizer 的学习主要是统计,不是语义理解。

它学的不是:

text 复制代码
"中国"是什么意思?
"苹果"是水果还是公司?
"Transformer"是什么神经网络?

它学的是:

text 复制代码
哪些相邻符号经常一起出现?
哪些片段值得合并成一个 token?
怎样用有限词表压缩训练语料?

所以 BPE tokenizer 更像一个统计压缩器。


4. BPE 算法的核心原理

BPE 全称 Byte Pair Encoding,字节对编码。

它最早是数据压缩算法,后来被用作 NLP 的子词切分算法。

核心规则非常简单:

text 复制代码
1. 把文本拆成最小符号
2. 统计所有相邻符号 pair 的出现次数
3. 找到出现次数最高的 pair
4. 把这个 pair 合并成一个新符号
5. 更新语料
6. 重复,直到词表大小达到目标

一句话:

哪两个相邻片段最常一起出现,就先把它们合并。


5. BPE 的完整小白算例

为了让小白容易理解,先用英文字符演示。

假设训练语料是:

text 复制代码
low
lower
lowest
newer
wider

我们先把每个词拆成字符:

text 复制代码
low    → l o w </w>
lower  → l o w e r </w>
lowest → l o w e s t </w>
newer  → n e w e r </w>
wider  → w i d e r </w>

其中 </w> 表示词尾。

为什么要有词尾?

因为要区分:

text 复制代码
low

和:

text 复制代码
lower 里面的 low

词尾可以帮助 tokenizer 学到"某个片段在词尾出现"。


5.1 第 1 轮:统计相邻 pair

对每个词统计相邻符号。

例如:

text 复制代码
low → l o w </w>

里面有:

text 复制代码
(l, o)
(o, w)
(w, </w>)
text 复制代码
lower → l o w e r </w>

里面有:

text 复制代码
(l, o)
(o, w)
(w, e)
(e, r)
(r, </w>)

统计整个语料,假设得到:

pair 次数
l o 3
o w 3
e r 3
r </w> 3
w e 2
其他 1

假设我们选择第一个最高频 pair:

text 复制代码
l + o → lo

5.2 第 1 轮合并后的语料

text 复制代码
low    → lo w </w>
lower  → lo w e r </w>
lowest → lo w e s t </w>
newer  → n e w e r </w>
wider  → w i d e r </w>

词表新增:

text 复制代码
lo

5.3 第 2 轮:重新统计 pair

现在重新统计,可能最高频是:

text 复制代码
lo + w → low

合并后:

text 复制代码
low    → low </w>
lower  → low e r </w>
lowest → low e s t </w>
newer  → n e w e r </w>
wider  → w i d e r </w>

词表新增:

text 复制代码
low

5.4 第 3 轮:继续统计

可能最高频是:

text 复制代码
e + r → er

合并后:

text 复制代码
low    → low </w>
lower  → low er </w>
lowest → low e s t </w>
newer  → n e w er </w>
wider  → w i d er </w>

词表新增:

text 复制代码
er

5.5 继续重复

BPE 会一直重复:

text 复制代码
统计 pair → 找最高频 → 合并 → 更新语料

直到达到目标词表大小。

最后词表里可能有:

text 复制代码
l
o
w
e
r
lo
low
er
lower
new
wide
...

6. BPE 的数学表达

设训练语料中每个序列是:

text 复制代码
sᵢ = [x₁, x₂, ..., xₘ]

每一轮统计所有相邻 pair:

text 复制代码
count(a, b) = Σᵢ Σⱼ 1[(xⱼ, xⱼ₊₁) = (a, b)]

选择出现次数最多的 pair:

text 复制代码
(a*, b*) = argmax count(a, b)

然后定义新符号:

text 复制代码
c = a* b*

把所有:

text 复制代码
a* b*

替换成:

text 复制代码
c

这就是 BPE 的核心。


7. BPE 训练伪代码

python 复制代码
def train_bpe(corpus, vocab_size):
    # 1. 初始切分:字符级或 byte 级
    corpus_symbols = split_to_initial_symbols(corpus)

    # 2. 初始词表
    vocab = set(all_symbols(corpus_symbols))

    # 3. 合并规则
    merges = []

    while len(vocab) < vocab_size:
        pair_counts = {}

        # 4. 统计所有相邻 pair
        for seq in corpus_symbols:
            for a, b in zip(seq, seq[1:]):
                pair_counts[(a, b)] = pair_counts.get((a, b), 0) + 1

        # 5. 找最高频 pair
        best_pair = max(pair_counts, key=pair_counts.get)

        # 6. 合并
        new_symbol = best_pair[0] + best_pair[1]
        merges.append(best_pair)
        vocab.add(new_symbol)

        # 7. 更新语料
        corpus_symbols = merge_pair(corpus_symbols, best_pair, new_symbol)

    return vocab, merges

核心就三句话:

text 复制代码
统计 pair
选最高频 pair
合并 pair

8. GPT-2 风格 Byte-Level BPE 的特殊流程

传统 BPE 可以从字符开始。

GPT-2 风格 BPE 从 byte 开始。

完整流程是:

text 复制代码
原始文本
  ↓
正则预切分
  ↓
UTF-8 bytes
  ↓
byte-to-unicode 映射
  ↓
BPE pair 统计与合并
  ↓
vocab.json + merges.txt

8.1 为什么要从 byte 开始?

因为任何文本都能变成 UTF-8 bytes。

所以 byte-level BPE 有一个巨大优点:

不会真正遇到 OOV,也就是不会出现"这个字符完全无法编码"。

中文、日文、韩文、emoji、生僻字、特殊符号、乱码,都能编码。


8.2 GPT-2 风格 BPE 的两个文件

训练完成后,通常得到两个核心文件:

text 复制代码
vocab.json
merges.txt

其中:

text 复制代码
vocab.json:token 字符串 → token id
merges.txt:BPE 合并规则和优先级

推理时不再统计,而是直接用 merges.txt 里的合并顺序。


9. GPT-2 风格 BPE 推理时如何编码?

训练阶段:

text 复制代码
统计语料 → 学 vocab 和 merges

推理阶段:

text 复制代码
输入文本 → 按已有 merges 合并 → 查 vocab → token id

假设 merge rank 是:

text 复制代码
(ä, ¸)        rank 100
(ä¸, ľ)       rank 101
(å, Ľ)        rank 200
(åĽ, ½)       rank 201
(举, åĽ½)   rank 5000

输入:

text 复制代码
中国

先变成:

text 复制代码
ä ¸ ľ å Ľ ½

按 merge rank 合并:

text 复制代码
ä ¸ ľ å Ľ ½
→ ä¸ ľ å Ľ ½
→ 举 å Ľ ½
→ 举 åĽ ½
→ 举 åĽ½
→ ä¸ľåĽ½

最后查词表:

text 复制代码
ä¸ľåĽ½ → token_id

如果词表里没有"中国"这个整体 token,就会停在更小的粒度:

text 复制代码
举 / åĽ½

也就是:

text 复制代码
中 / 国

10. 中文在 BPE 中为什么可能被切碎?

原因不是中文本身不能被 BPE 表示,而是训练语料决定合并规则。

如果训练语料主要是英文,那么英文片段会被大量合并:

text 复制代码
transform
attention
function
return

中文片段出现较少,就不一定能合并成较大的 token。

于是中文可能更碎:

text 复制代码
我正在学习Transformer

可能被切成:

text 复制代码
我 / 正 / 在 / 学 / 习 / Transformer

也可能更碎到 byte 级。

因此,一个 tokenizer 对中文是否友好,取决于:

text 复制代码
1. 中文语料占比
2. 词表大小
3. 是否 byte-level 或 byte fallback
4. 是否专门优化中日韩文本
5. 是否优化代码、数学、Markdown 等结构文本

11. BPE 的优点和缺点

11.1 优点

优点 解释
简单 算法就是统计 pair + 贪心合并
训练和推理都容易优化
稳定 编码确定性强
可逆 byte-level BPE 可以 lossless decode
无 OOV byte-level BPE 可以表示任意文本
压缩有效 高频片段会变成短 token 序列

11.2 缺点

缺点 解释
贪心 每一步只看局部最高频 pair,不保证全局最优
不懂语义 合并依据是频率,不是语义
对语料敏感 训练语料偏英文,中文就可能碎
词表浪费 高频但无语义价值的片段也可能进词表
多语言公平性问题 不同语言 token 压缩率可能差别很大

12. 有没有比 BPE 更好的算法?

有。

主流替代方案包括:

text 复制代码
WordPiece
Unigram Language Model
SentencePiece
byte fallback / hybrid tokenizer
直接 byte-level language model

13. WordPiece:比 BPE 更关注"组合价值"

WordPiece 是 BERT 系列常用的 tokenizer。

BPE 主要看:

text 复制代码
哪个 pair 出现次数最多?

WordPiece 更关心:

text 复制代码
合并这个 pair 后,是否能更好解释语料?

一种直观分数可以写成:

text 复制代码
score(a, b) = freq(a, b) / (freq(a) × freq(b))

这个分数表达的是:

a 和 b 是不是强绑定?还是只是因为 a、b 各自都太常见,所以碰巧一起出现很多?

例如:

text 复制代码
New York

如果 NewYork 经常强绑定,那么 WordPiece 倾向于把它们看作更有价值的组合。

BPE 更像:

text 复制代码
出现次数多就合并

WordPiece 更像:

text 复制代码
绑定关系强、对建模有收益才合并

14. Unigram LM:更像真正的概率模型

Unigram Language Model 是 SentencePiece 中常用的一类算法。

它和 BPE 的方向相反。

BPE 是:

text 复制代码
从小词表开始,不断合并,词表变大

Unigram LM 是:

text 复制代码
先准备一个很大的候选词表,然后删除贡献小的 token,词表变小

14.1 Unigram LM 如何理解?

比如:

text 复制代码
人工智能

可以有很多切法:

text 复制代码
人工 / 智能
人 / 工 / 智 / 能
人工智能
人工 / 智 / 能

Unigram LM 给每个 token 一个概率:

text 复制代码
P(人工)
P(智能)
P(人工智能)
P(人)
P(工)
...

一句话的概率是所有切分路径概率的总和或最优路径概率近似。

训练目标是:

text 复制代码
让整个训练语料的概率最大

然后删除那些对语料概率贡献小的 token。


14.2 Unigram LM 的优点

优点 解释
概率化 比 BPE 的贪心频率更接近统计建模
多切分路径 可以考虑一句话的多种切法
适合多语言 尤其适合中文、日文这种无空格语言
可用于采样 可以做 subword regularization,增强模型鲁棒性

缺点是:

text 复制代码
训练更复杂
推理实现更复杂
工程速度可能不如 BPE 简单直接

15. SentencePiece:不是单一算法,而是 tokenizer 框架

SentencePiece 是一个语言无关的 tokenizer / detokenizer 框架。

它支持:

text 复制代码
BPE
Unigram LM
char
word

它的重要特点是:

可以直接从原始文本训练,不要求先按空格分词。

这对中文、日文、韩文很重要,因为这些语言不像英文那样天然用空格分词。

SentencePiece 通常用 表示空格。

例如:

text 复制代码
Hello world

可以内部表示成:

text 复制代码
▁Hello ▁world

这样空格也成为 tokenizer 学习的一部分。


16. BPE、WordPiece、Unigram、SentencePiece 对比

方法 核心思想 训练方向 优点 缺点 典型模型
BPE 高频相邻 pair 合并 小词表 → 大词表 简单、快、稳定 贪心、不懂语义 GPT-2、RoBERTa、很多 GPT 类模型
Byte-Level BPE 从 UTF-8 byte 开始做 BPE byte → subword 无 OOV、可逆、工程强 某些语言可能碎 GPT-2、OpenAI tiktoken、Qwen、DeepSeek LLM
WordPiece 更关注合并带来的建模收益 小词表 → 大词表 比 BPE 更概率化 实现复杂 BERT、DistilBERT、MobileBERT
Unigram LM 概率模型选择 token 大词表 → 小词表 理论优雅、多切分路径 训练复杂 T5/ALBERT 等 SentencePiece 系模型
SentencePiece tokenizer 框架 支持 BPE/Unigram 语言无关,适合中日韩 本身不是单一算法 LLaMA 1/2、T5、Gemma 等许多模型

17. 主流大模型是不是还在用 BPE?

结论:

是的,BPE 或 BPE 变体仍然是主流大模型 tokenizer 的核心路线之一,但不是唯一路线。

常见情况如下。

17.1 GPT-2 / RoBERTa / BART / DeBERTa

这些模型使用 BPE 或 byte-level BPE 类 tokenizer。

GPT-2 使用 byte-level BPE,词表大小约 50,257:

text 复制代码
256 个 byte 基础 token
+ 约 50,000 个 BPE merge token
+ 特殊 token

17.2 OpenAI tiktoken 系列

OpenAI 的 tiktoken 是快速 BPE tokenizer,用于 OpenAI 模型。

它的核心仍是 BPE:

text 复制代码
文本 → bytes → BPE token ids

它强调:

text 复制代码
可逆
无损
可以处理任意文本
压缩文本长度

17.3 LLaMA 系列

LLaMA 1 / LLaMA 2 主要使用 SentencePiece tokenizer。

LLaMA 3 之后切换到更大的 tokenizer,词表约 128K,并更重视多语言和压缩效率。

LLaMA 3 的 tokenizer 通常被描述为 tiktoken/BPE 风格,Meta 官方也强调 LLaMA 3 使用 128K 词表来更高效编码语言。


17.4 Qwen 系列

Qwen 系列使用 BPE / tiktoken 风格 tokenizer。

Qwen-7B 的 tokenizer 说明中明确提到:

text 复制代码
BPE tokenization on UTF-8 bytes using tiktoken

也就是说,Qwen 是典型的 byte-level BPE 路线。


17.5 DeepSeek 系列

DeepSeek LLM 官方说明中提到使用 Hugging Face Tokenizer 实现 Byte-level BPE,并使用专门设计的 pre-tokenizer。

所以 DeepSeek LLM / DeepSeek-R1 一类模型也属于 byte-level BPE 路线或其变体。


17.6 BERT 系列

BERT 使用 WordPiece。

它不是 BPE,但和 BPE 一样属于子词 tokenizer。

BERT 的 WordPiece 推理阶段常用贪心最长匹配:

text 复制代码
unaffable → un / ##aff / ##able

17.7 T5 / ALBERT / 一些多语言模型

这些模型常用 SentencePiece / Unigram LM。

SentencePiece 对中日韩、多语言、无空格文本比较友好。


18. 对中文大模型来说,tokenizer 设计为什么重要?

因为 token 数直接影响:

text 复制代码
训练成本
推理成本
上下文长度利用率
显存占用
attention 计算量

Transformer 注意力复杂度近似是:

text 复制代码
O(n²)

其中 n 是 token 数。

如果中文一句话被切得很碎,token 数变多,那么:

text 复制代码
上下文窗口被浪费
推理变慢
训练成本变高
长文本能力下降

所以中文友好的 tokenizer 会尽量让常见中文词、短语、标点组合、换行结构、代码符号成为更高效的 token。


19. 从工程角度如何判断一个 tokenizer 好不好?

一个好的 tokenizer 应该满足:

指标 解释
压缩率高 同样文本 token 数少
无 OOV 任意字符都能编码
可逆 decode(encode(text)) = text
多语言公平 中文、英文、代码都不要太浪费
代码友好 对缩进、换行、括号、关键字优化
数学/Markdown 友好 对公式、符号、表格结构友好
编码速度快 推理服务中 tokenizer 不能成为瓶颈
词表大小合适 太小会碎,太大会增加 embedding 参数

20. BPE 为什么还没被淘汰?

因为 BPE 虽然不是理论最优,但工程优势非常强:

text 复制代码
简单
确定
快
容易实现
容易并行
容易部署
可逆性好
byte-level 后没有 OOV

所以今天很多大模型仍然使用 BPE 或 BPE 变体。

它就像工程中的"足够好且足够稳定"的方案。


21. 最终总结

21.1 汉字进入 GPT-2 风格 BPE 的过程

text 复制代码
中
  ↓ Unicode
U+4E2D
  ↓ UTF-8
E4 B8 AD
  ↓ byte-to-unicode
ä ¸ ľ
  ↓ BPE merge
举
  ↓ vocab
某个 token id

21.2 BPE 的核心算法

text 复制代码
1. 拆成最小符号
2. 统计所有相邻 pair
3. 找出现次数最多的 pair
4. 合并成新 token
5. 更新语料
6. 重复直到词表达到目标大小

公式:

text 复制代码
(a*, b*) = argmax count(a, b)

然后:

text 复制代码
a* b* → a*b*

21.3 BPE 的本质

text 复制代码
统计压缩,不是语义理解

它学到的是:

text 复制代码
哪些片段经常一起出现,值得用一个 token 表示

不是:

text 复制代码
这些片段到底是什么意思

21.4 更高级的 tokenizer 算法

text 复制代码
BPE:最高频 pair 合并,简单稳定
WordPiece:更关注合并对建模概率的收益
Unigram LM:概率模型,从大候选词表中删除低贡献 token
SentencePiece:语言无关 tokenizer 框架,支持 BPE 和 Unigram
Byte-level BPE:从 UTF-8 byte 开始,无 OOV,可逆

21.5 主流大模型是否使用 BPE

答案是:

text 复制代码
大量主流大模型仍然使用 BPE 或 BPE 变体。

包括:

text 复制代码
GPT-2:byte-level BPE
OpenAI tiktoken 系:BPE
Qwen:UTF-8 byte-level BPE / tiktoken 风格
DeepSeek LLM:Byte-level BPE
RoBERTa/BART/DeBERTa:BPE 类
LLaMA 3:大词表 tiktoken/BPE 风格

但也有很多模型使用其他路线:

text 复制代码
BERT:WordPiece
T5/ALBERT/部分多语言模型:SentencePiece / Unigram
LLaMA 1/2:SentencePiece

22. 参考资料

  1. Hugging Face Transformers tokenizer summary: https://huggingface.co/docs/transformers/en/tokenizer_summary
  2. Hugging Face LLM Course: Byte-Pair Encoding tokenization: https://huggingface.co/learn/llm-course/en/chapter6/5
  3. Hugging Face LLM Course: WordPiece tokenization: https://huggingface.co/learn/llm-course/en/chapter6/6
  4. Google Research Blog: A Fast WordPiece Tokenization System: https://research.google/blog/a-fast-wordpiece-tokenization-system/
  5. SentencePiece paper: https://arxiv.org/abs/1808.06226
  6. SentencePiece GitHub: https://github.com/google/sentencepiece
  7. OpenAI tiktoken GitHub: https://github.com/openai/tiktoken
  8. Meta Llama 3 introduction: https://ai.meta.com/blog/meta-llama-3/
  9. DeepSeek LLM GitHub FAQ: https://github.com/deepseek-ai/DeepSeek-LLM
  10. Qwen tokenizer note: https://huggingface.co/Qwen/Qwen-7B/blob/main/tokenization_qwen.py
相关推荐
沉浸式学习ing4 小时前
播客和视频怎么变成知识库里的笔记?音视频转结构化笔记完整方案
人工智能·笔记·gpt·学习·ai·音视频·notion
YoungHong19924 小时前
Pi Coding Agent : AI时代的“VSCode“
ide·人工智能·gpt·claude·claudecode
weelinking5 小时前
2026年三大主流大模型深度对比:GPT-5.5、Claude 4.6与DeepSeek V4谁更值得选择?
java·大数据·人工智能·git·python·gpt·github
梦梦代码精5 小时前
开源智能体平台 BuildingAI 深度解析:Monorepo 架构、MCP 集成及 GPT-Image-2 接入实测
前端·人工智能·后端·gpt·开源·github
GuokLiu6 小时前
260515-ChatGPT-image2生成Github单页海报的提示词示例
gpt·prompt·image
应用市场14 小时前
AI 编程助手三强争霸(2026 版):Claude、Gemini、GPT 各自擅长什么?
人工智能·gpt
应用市场14 小时前
Claude + GPT API 实战手册(2026 版)
gpt
卷Java18 小时前
2026年4月AI军备竞赛全景:DeepSeek V4 vs GPT-5.5 vs Gemini vs Claude
人工智能·gpt·大模型
Ai马猴子1 天前
迭代升级再塑旗舰标杆,gpt-5.2入驻 DMXAPI,综合智能表现越级强悍
gpt