目录
引论:为什么"分词"是 LLM 一切奇怪行为的根源
第一部分:分词的语言学与计算基础
1.1 什么是"词"?语言学的尴尬定义
1.2 词、词素、字符、短语:分词粒度的连续谱
1.3 语言模型如何"看见"文本
1.4 词表大小如何影响参数量与序列长度
第二部分:三大经典分词方案
2.1 词级分词:Zipf 定律与 OOV 的诅咒
2.2 字符/字节级分词:"tokenizer-free"的诱惑
2.3 子词分词:词与字符之间的最优中庸
第三部分:字节对编码 BPE 算法深度解析
3.1 为什么所有前沿模型都用 BPE?
3.2 BPE 训练算法的形式化描述
3.3 完整训练 Walkthrough:Peter Piper 示例
3.4 测试时分词:贪心应用合并规则
3.5 Python 实现:从零写一个 BPE
3.6 BPE 的姐妹算法:WordPiece 与 Unigram LM
第四部分:超越 BPE — SentencePiece 与 SuperBPE
4.1 Pre-tokenization 的代价:为什么按空格切并不普适
4.2 SentencePiece:把空格当字符的库
4.3 SuperBPE:跨越空格的"超级词"
第五部分:分词的隐秘代价
5.1 草莓里有几个 r?Spelling 的根本失败
5.2 故障 Token:SolidGoldMagikarp 之谜
5.3 Tokenization 与所有"奇怪行为"的对照表
第六部分:多语言 NLP — 当世界不只是英语
6.1 7000 种语言与 40% 英语的 Common Crawl
6.2 多语言语言模型的架构演化
6.3 跨语言迁移:XLM-R 的奇迹
6.4 词表重叠与跨语言对齐
6.5 多语言的诅咒:容量与覆盖的取舍
第七部分:分词的公平性问题
7.1 Token 通胀:同样意思在缅甸语要多花 15 倍
7.2 子词肥沃度与下游性能的负相关
7.3 API 定价不公的伦理含义
第八部分:字符/字节级模型的复兴
8.1 CANINE:mBERT 的字符级对手
8.2 ByT5 与 MrT5:动态删除的字节序列
8.3 Byte Latent Transformer (BLT):熵驱动的动态 patch
8.4 H-Nets 与层次化自回归 Transformer
8.5 潜在分词:把"切词"也学进去
第九部分:练习题与研究方向
参考文献与延伸阅读
引论:为什么"分词"是 LLM 一切奇怪行为的根源
"We will see that a lot of weird behaviors and problems of LLMs actually trace back to tokenization.
… Why someone out there ideally finds a way to delete this stage entirely."
— Andrej Karpathy
打开任意一篇关于大语言模型(LLM)的论文,你会读到 transformer、attention、scaling laws、RLHF…
唯独很少有人花一整章去讲分词(tokenization) ——这个把人类文字喂进模型之前的"预处理步骤"。
然而正是这个看似平凡的步骤,决定了:
模型为什么数不清 strawberry 里有几个 r;
为什么同样一句话,缅甸语用户要支付英语用户 15 倍的 API 费用;
为什么 GPT-3 听到 SolidGoldMagikarp 这种诡异字符串会"精神错乱";
为什么 LLM 在低资源语言上的性能可以差 30 个百分点;
为什么算术、字符串反转、Python 缩进这些"小事"会成为 LLM 的死穴。
分词不是一个工程细节,而是语言模型的本体论 ——它定义了模型眼中"语言的原子"是什么。
原子选错了,下游一切都会跑偏。这门课要带你看到,tokenization 是 LLM 的隐形基石,也是隐形天花板 。
原始文本(人类可读 / 比特流)
编码
Tokenizer (词表 V + 合并规则)
token IDs
嵌入层(|V| × d_model 参数)
Transformer 主体
⚠ 词表越大,参数越多
⚠ 切法决定序列长度
⚠ 不同语言 token 数差 15×
分词处在原始文本与模型之间的位置。词表大小决定嵌入层参数量;分词粒度决定序列长度;分词方案对语言公平性有决定性影响。
本教材读法建议
本文长度约 30000 字,建议分两次精读:第一次理解 Part 1–3 的核心算法(BPE);第二次在做 multilingual / cross-lingual 项目时再读 Part 6–8。
若你已熟悉 BPE,可直接跳到 Part 5(故障 Token)或 Part 8(字节级前沿)。
第一部分:分词的语言学与计算基础
1.1 什么是"词"?语言学的尴尬定义
看似简单的问题:"下面这句话有几个词?"
We'd sat back on the grass , and time flew by as we looked at the Milky Way .
17 个空格分隔的词 + 2 个标点。但语言学上真的是这样吗?
我们可以"凭空格"数出 17 个词,但这种朴素切分会立刻撞墙:
We'd = we + had——这是 1 个词 还是 2 个词 ?
looked = look + -ed——后缀 -ed 携带过去式信息,难道不算独立单位?
Milky Way 是一个 专有名词实体(银河系),但被空格切成 2 个 token;
sat = sit + -ed,但这是一个不规则变化(屈折),按形式根本切不开。
为了把上述模糊性收紧,语言学家用词素(morpheme) 这个更精细的概念:
定义:词素(morpheme)
词素是
携带意义或语法功能的最小语言单位 。
looked 包含两个词素:实义词素
look + 屈折词素
-ed(过去时)。
词素粒度也并非完美:sat(坐的过去式)显然包含 sit + 过去时的语义,但在拼写上无法机械拆出 -ed;
而 Milky Way 是一个整体专有名词,按词素切反而丢失语义。
这就是语言学家给我们的第一个教训:不存在一个"客观正确"的分词粒度 。
1.2 词、词素、字符、短语:分词粒度的连续谱
不同粒度的分词如同把同一句话用不同分辨率显微镜观察:
细
粗
字符
W
e
l
o
o
k
e
d
a
t
|V| ≈ 100;序列极长;无 OOV
词素
We
look
-ed
at
语言学上有意义,但要语言学家标注
词
We
looked
at
|V| 巨大;OOV 严重;语义直观
短语
We looked at
the Milky Way
语义完整;难以泛化新短语
分词粒度的连续谱。语言模型的核心问题是在覆盖率 (vocabulary 是否能表示任意输入)与语义性 (每个 token 是否对应有意义的单位)之间取得平衡。
当代主流 LLM(GPT、Llama、Gemini、Claude、DeepSeek)都没有选择上面任何一种原始 方案,而是选择了一个数据驱动的折衷——
子词(subword)分词 ,本教材的核心算法 BPE 即属于此。我们稍后会看到,子词的"token"通常并不对应任何语言学单位,
但凭借数据统计的力量,它意外地工作得非常好。
1.3 语言模型如何"看见"文本
要理解为什么 tokenization 如此关键,我们需要先把 LLM 的"视觉"过程完整还原一遍:
flowchart LR
A["原始字符串 'We looked at the Milky Way.'"] --> B[Tokenizer encode]
B --> C["Token 序列 (We)(looked)(at)(the)(Milky)(Way)(.)"]
C --> D["Token IDs [2167, 10802, 540, 290, 10282, 5781, 0]"]
D --> E[Embedding Lookup E[id] ∈ ℝ^d]
E --> F[嵌入向量序列 x_1, x_2, ..., x_n ∈ ℝ^d]
F --> G[Transformer 主体]
G --> H[输出隐状态 h_1, ..., h_n]
H --> I[Un-embed h · E^T 得 logits]
I --> J[Argmax / Sample 下一个 token ID]
J --> K[Tokenizer decode]
K --> L["新生成的字符串"]
注意两个隐藏但关键的事实:
Tokenizer 是一段独立代码 ,不 是 transformer 的一部分。它通常在预训练之前就被独立训练并冻结。
Decode 是 encode 的逆过程 ,但因为分词的多对一映射,decode 时必须使用相同的 tokenizer。
若你用 Llama tokenizer encode、用 GPT tokenizer decode,结果将是乱码。
1.4 词表大小如何影响参数量与序列长度
词表大小 $|V|$ 是 tokenizer 最重要的超参数。它通过两个独立通道影响模型:
(a) 参数量通道
嵌入矩阵 $\mathbf{E} \in \mathbb{R}^{|V| \times d_\text{model}}$ 与输出投影 $\mathbf{W}_\text{out} \in \mathbb{R}^{d_\text{model} \times |V|}$(在很多模型中权重共享)直接随 $|V|$ 线性增长:
$$
\#\text{params}_\text{embed} = |V| \cdot d_\text{model}
$$
例如 Llama 4 的 $|V| = 201{,}000$、$d_\text{model} = 8192$,仅嵌入层就有 16 亿参数 ,对总参数量的占比已经接近 5%。
(b) 序列长度通道
更细的分词 = 同样文本变成更长的 token 序列。Self-attention 的复杂度是序列长度的平方:
$$
\mathcal{O}_\text{attn} = \mathcal{O}\!\left(n^2 \cdot d_\text{model}\right)
$$
若分词把序列长度增加 2×,attention 计算量增加 4×,KV cache 内存增加 2×。
对推理成本和上下文窗口利用率都是直接打击。
所以选择 $|V|$ 总是在权衡:更大的词表 → 更短的序列 + 更稀疏的语义 + 更多嵌入参数;
更小的词表 → 更密集的语义 + 更长的序列 + 更难训练的低频长尾 。
字符级 (|V|≈256)
BPE (|V|≈50k)
词级 (|V|≈200k)
t
h
e
M
i
l
k
y
W
a
y
.
Transformer
n=14, slow
the
Milky
Way
.
Transformer
n=4, fast ✓
the
Milky_Way
.
Transformer
embed 巨大
三种分词把同一句话送入模型时的成本对比
第二部分:三大经典分词方案
2.1 词级分词:Zipf 定律与 OOV 的诅咒
最朴素的方案:按空格切,再加上标点处理。这有两个根本困难。
困难一:词表无上限增长
语料 不同词数 (types)
Shakespeare 全集 31,000
Brown corpus (1M words) 38,000
Switchboard 电话会话 20,000
COCA (Corpus of Contemporary American English) 2,000,000
Google n-grams 13,000,000
更糟糕的是,词频遵循 Zipf 定律 ——一个词排名为 $r$,频率与 $1/r$ 成正比:
词频排名 r (log)
频率 f(r) (log)
"the" → 7%
"and" → 3%
"unicorn" → 0.001%
"COVID-19" → 1 次
Zipf 定律:长尾决定了 OOV 永远无法消除
困难二:Out-Of-Vocabulary (OOV) 必然发生
即使你把训练语料里所有词都收入词表,也无法防止:
新造词 :Merriam-Webster 字典每版增 5000 个新词(rizz , doomscroll , vibe coding );
拼写错误 :importaNt;
专有名词 :地名、人名、产品名层出不穷;
形态变化 :英语屈折少,但希腊语动词有 100+ 形式,土耳其语理论上可以单词长到数十字符(凝集语)。
传统应对方案:
规则归一化
正则化拼写,如 importaNt → important,ESPRESSSOOO → ESPRESSO;但维护成本高且漏洞百出。
UNK 符号
把所有未知词映射为单一的 <UNK>;问题是太多语义信息被压成同一个槽。
UNK 的灾难性示例
原文:
Zipf's law is importaNt in NLP.
朴素词级分词器:
UNK law isUNK in NLP.
模型完全失去了语义内容。这就是为什么 Sutskever et al. (2014) 在早期 seq2seq 论文里专门讨论"如何处理稀有词"——OOV 一度是机器翻译的最大死穴。
2.2 字符/字节级分词:"tokenizer-free"的诱惑
另一个极端:把每个字符(或每个字节)当作 token。词表瞬间收缩到几十到几百个槽。
字符 vs 字节的微妙区别
对 ASCII 文本,字符与字节一一对应。但对 Unicode:
"😀" = 1 个字符,4 个字节 (UTF-8 编码 F0 9F 98 80)
"地" = 1 个字符,3 个字节 (UTF-8 编码 E5 9C B0)
字节级分词更彻底地"无歧义",所有 Unicode 都能表示;字符级与 Unicode codepoint 一一对应,但要处理 100k+ 个 codepoint。
代表工作:
CharBERT 、
CANINE 、
Charformer 、
ByT5 。
维度 字符/字节级
✅ 优势 极小词表(~256)、零 OOV、可直接看到拼写
❌ 缺陷 序列极长(中文 1 字 = 3 字节,attention 计算 9× 增加);高层语义需要更深网络去组合
争议至今未息:字符级模型究竟更"难"还是更"清晰"?Karpathy 在 2024 年的播客里强烈支持"长期来说我们应该删掉 tokenization 这一步" 。Part 8 我们会重新审视这个方向的最新研究。
2.3 子词分词:词与字符之间的最优中庸
工业界 2016 年以来的事实标准:子词(subword)分词。核心思想:
让数据告诉我们词表应该是什么。频繁组合的字符序列升级为单个 token;
罕见词自动被切成更小的字符片段。最频繁的"完整词"(如 the)保持为单个 token;
而 antidisestablishmentarianism 这种罕见词可能被切成多个有意义的子词单元。
子词的设计哲学:
从数据出发 :用语料频率统计决定切分边界;
词表大小可控 :通常 30k–250k,由超参数 $N$ 决定;
零 OOV :因为最基础的字节都在词表里,任何输入都可被表示;
子词重用 :picked 和 picking 可共享 pick 子词,提升泛化。
三大主流子词算法:
本教材聚焦 BPE,因为它已成为 GPT、Llama、Gemini、Claude、DeepSeek、Qwen、Mistral 等所有前沿模型的事实标准。
第三部分:字节对编码 BPE 算法深度解析
3.1 为什么所有前沿模型都用 BPE?
看看 2025–2026 年度主流 LLM 的分词器:
模型家族 类型 词表大小
Gemini 2.x / Gemma 3 BPE 262k
Gemini 1.x / Gemma 2 BPE 256k
Llama 4 BPE 201k
GPT-4o / GPT-5 / o1 / o3 BPE 200k
Kimi K2 BPE 163k
Qwen2.5 / Qwen3 / GLM-4 BPE 151k
Grok 2 BPE 131k
Llama 3 / Hunyuan T1 / TurboS BPE 128k
DeepSeek v3 / R1 BPE 128k
为什么所有人都选 BPE?三大原因:
历史遗产 :GPT-2 (2019) 使用 BPE 并开源后,整个开源生态都跟进了;
简单且确定 :训练算法仅 ~30 行代码;测试时分词是贪心的,无歧义;
压缩效率好 :BPE 实际上是一个数据压缩算法(Gage, 1994),它会自动找出高频 n-gram。
3.2 BPE 训练算法的形式化描述
算法 3.1:BPE Training
输入:
D — 训练语料(字符串集合)
N — 目标词表大小
输出:
V — 词表(token 集合)
M — 有序合并规则列表 [(v_a, v_b) → v_new, ...]
步骤:
1. Pre-tokenize: 按空格切 D,得到"词序列"
2. 初始化 V ← {所有字节} ∪ {空格符 _}
3. 将 D 转换为字节序列(每个字符 → 1+ 字节)
4. M ← []
5. while |V| < N:
a. 统计 D 中所有相邻 token 对 (v_i, v_j) 的频率
b. 取频率最高的对 (v_a, v_b)
c. 创建新 token v_new = v_a + v_b
d. V ← V ∪ {v_new}
e. M.append((v_a, v_b) → v_new)
f. 将 D 中所有 (v_a, v_b) 替换为 v_new
6. return V, M
关键设计选择:
预分词(pre-tokenization) :先按空格切。这样合并不会跨越词边界,保证每个 token 不会同时包含两个不相关的词碎片。
最高频合并 :贪心选择,不回溯;非常类似数据压缩中的 BPE。
有序合并规则 :M 的顺序至关重要,测试时必须按相同顺序应用,否则结果不一致。
3.3 完整训练 Walkthrough:Peter Piper 示例
让我们用 PDF 课件里的小语料完整走一遍:
语料 D = "Peter Piper picked a peck of pickled peppers"
步骤 1:Pre-tokenize
按空格切,并在每个词前加上空格标记 _(表示"词首",这是 GPT-2 BPE 的惯例):
Peter _Piper _picked _a _peck _of _pickled _peppers
步骤 2:初始化词表
$V_0 = \{$_, a, c, d, e, f, i, k, l, o, p, P, r, s, t$\}$ — 共 15 个字节。
步骤 3:把语料转成 token 序列
P e t e r _ P i p e r _ p i c k e d _ a _ p e c k _ o f _ p i c k l e d _ p e p p e r s
步骤 4–N:迭代合并
统计所有相邻对的频率,找出最高的 7 个:
Token Pair Frequency
_ + p4
p + e4
c + k3
e + r3
e + d2
i + c2
p + i2
合并 1:_ + p → _p
P e t e r
_p i p e r
_p i c k e d
_ a
_p e c k
_ o f
_p i c k l e d
_p e p p e r s
合并规则 M
1. _ + p → _p
词表更新
V = V_0 ∪ {_p}
直觉
把"空格 + p"合并成一个 token,等价于学习到"很多 p 开头的词"。
这一步把 4 个 token 对压缩成 4 个新 token。
合并 2:c + k → ck(注意,_p 合并后 p+e 的计数从 4 降到 2,所以下一个最高是 c+k)
P e t e r
_p i p e r
_p i ck e d
_ a
_p e ck
_ o f
_p i ck l e d
_p e p p e r s
合并规则 M
1. _ + p → _p
2. c + k → ck
英语中 'ck' 是常见组合
注意 BPE 自动发现了正字法规律(pick, peck, pickle 都包含 ck),无需任何语言学知识。
合并 3:e + r → er
P e t er
_p i p er
_p i ck e d
_ a
_p e ck
_ o f
_p i ck l e d
_p e p p er s
合并规则 M
1. _ + p → _p
2. c + k → ck
3. e + r → er
名词后缀 'er'
英语高频名词后缀(pepper, Peter, Piper)。BPE 又自动发现了一个形态学单元。
合并 4:_p + e → _pe
P e t er
_p i p er
_p i ck e d
_ a
_pe ck
_ o f
_p i ck l e d
_pe p p er s
合并规则 M
1. _ + p → _p
2. c + k → ck
3. e + r → er
4. _p + e → _pe
注意:合并的是 token 对,不是字符对
现在 _p 已经是一个 token,BPE 接着把 _p + e 合并成 _pe,这是一个三字节序列!合并可以无限嵌套。
合并 5:_p + i → _pi
P e t er
_pi p er
_pi ck e d
_ a
_pe ck
_ o f
_pi ck l e d
_pe p p er s
"_pi" 现在覆盖 Piper, picked, pickled
合并 6:_pi + ck → _pick
P e t er
_pi p er
_pick e d
_ a
_pe ck
_ o f
_pick l e d
_pe p p er s
合并规则 M
6. _pi + ck → _pick
学到了完整词根 "pick"
注意此时 _pick 是 5 个字节 合并成的单个 token。
这让 picked, pickled 共享一个共同的 _pick 前缀,是 BPE 泛化能力的核心。
…依此类推,直到 $|V| = N$。
观察总结
经过 6 步 BPE 合并,我们的微型语料从 41 个字节缩短到约 18 个 token。
原本没有任何语言学输入 ,
算法却"自动"发现了:(1) 英语正字法组合
ck;(2) 名词后缀
-er;(3) 完整词根
pick;
(4) 词首标记
_pe、
_pi。这正是子词分词的魅力——形态学是统计的副产品。
3.4 测试时分词:贪心应用合并规则
训练完成后,得到了词表 $V$ 和有序合并规则 $M$。对新文本 _pier:
输入:
_pier
字节:
_
p
i
e
r
合并1:
_p
i
e
r
← 应用规则 1: _ + p → _p
合并3:
_p
i
er
← 应用规则 3: e + r → er(规则 2 不适用)
合并5:
_pi
er
← 应用规则 5: _p + i → _pi
最终 token:
_pi
er
最终序列:[_pi, er](2 个 token)
测试时 BPE 应用:把输入按字节展开,然后按训练时记录的顺序 贪心应用合并规则;不能合并的规则跳过。
注意 _pier 没有作为完整词出现在训练语料里,但通过合并 _pi + er 实现了优雅切分。
为什么测试时也"贪心"?
理论上,对一个测试串,最优切分可能要做 dynamic programming。但 BPE 选择的
有序贪心应用 有两个优势:
(1) 时间复杂度线性于串长;(2) 与训练时的合并顺序保持一致,让"训练合并出来的高频片段"在测试时也会被合出来。
SentencePiece 在某些场景下确实实现了 DP-based 最优切分(叫 Viterbi-BPE),但开销大且无明显收益。
3.5 Python 实现:从零写一个 BPE
为了让你彻底吃透算法,下面是一份 可运行 的极简 BPE 实现(仅 ~50 行):
from collections import Counter, defaultdict
def get_stats(corpus):
"""统计相邻 token 对的频率。corpus: List[List[str]]"""
pairs = Counter()
for word in corpus:
for i in range(len(word) - 1):
pairs[(word[i], word[i+1])] += 1
return pairs
def merge_pair(corpus, pair):
"""把语料中所有 pair (a,b) 替换为 'a+b'"""
a, b = pair
new_corpus = []
for word in corpus:
i = 0
new_word = []
while i < len(word):
if i < len(word) - 1 and word[i] == a and word[i+1] == b:
new_word.append(a + b)
i += 2
else:
new_word.append(word[i])
i += 1
new_corpus.append(new_word)
return new_corpus
def train_bpe(text, vocab_size):
"""BPE 训练主函数"""
# Step 1: pre-tokenize (按空格切,每个词前加 _ 标记词首)
words = ["_" + w for w in text.split()]
# 转成 List[List[str]],每个内层 list 是字符序列
corpus = [list(w) for w in words]
# 初始化词表
vocab = set(ch for word in corpus for ch in word)
merges = [] # 有序合并规则
while len(vocab) < vocab_size:
pairs = get_stats(corpus)
if not pairs:
break
best_pair = max(pairs, key=pairs.get)
if pairs[best_pair] < 2: # 不再有可合并对
break
corpus = merge_pair(corpus, best_pair)
new_token = best_pair[0] + best_pair[1]
vocab.add(new_token)
merges.append(best_pair)
return vocab, merges
def tokenize(text, merges):
"""测试时分词:按 merges 顺序贪心应用"""
words = ["_" + w for w in text.split()]
result = []
for word in words:
tokens = list(word)
for pair in merges:
tokens = merge_pair([tokens], pair)[0]
result.extend(tokens)
return result
# Demo
text = "Peter Piper picked a peck of pickled peppers"
vocab, merges = train_bpe(text, vocab_size=25)
print("Merges:", merges[:6])
# [('_', 'p'), ('c', 'k'), ('e', 'r'), ('_p', 'e'), ('_p', 'i'), ('_pi', 'ck')]
print(tokenize("pier picked", merges))
# ['p', 'i', 'er', '_pick', 'e', 'd']
生产级实现的差别
真实工业 BPE(如
tiktoken、
tokenizers 库)有大量优化:
用 priority queue + linked list ,把每步合并的统计更新降到 $O(\log n)$;
用 regex pre-tokenization (GPT-2 famous regex),保证标点、数字、空格的特殊处理;
采用 byte-level 而非 character-level,词表能严格保证 $\geq 256$ 且无 OOV;
对 tiktoken 这种 Rust 实现,1 GB 文本秒级训练。
3.6 BPE 的姐妹算法:WordPiece 与 Unigram LM
WordPiece
BERT、DistilBERT、ELECTRA 使用。改动很简单:合并准则不是频率 ,而是合并后对训练数据似然的提升 :
$$
\text{score}(v_a, v_b) = \frac{\#(v_a v_b)}{\#(v_a) \cdot \#(v_b)}
$$
分子是合并后 token 的频率,分母是两个原 token 独立频率的乘积。这等价于挑选互信息(pointwise mutual information)最大的对。
直觉:如果两个 token 总是一起出现(比 chance 高得多),就应该合并。
Unigram Language Model
Kudo (2018) 提出,被 SentencePiece 默认采用,T5、XLM-R、Llama 2 都基于它。哲学完全相反:
初始化 :从一个超大词表开始(数百万个候选子词,包括所有可能的字符 n-gram);
EM 迭代 :
E 步:对每个词,计算用当前词表分词的所有可能切分及其概率;
M 步:根据当前切分的统计量更新每个子词的 unigram 概率;
修剪 :删除对总似然贡献最小的 X% 子词;
重复 2–3 直到词表大小达到目标 $N$。
Unigram LM 的一个独特优势:测试时可以产生多个可能的切分 ,每个切分有概率。这支持 BPE 不支持的子词正则化(subword regularization) ——训练时随机采样不同切分,等价于数据增强。
算法 合并方向 合并准则 测试时 典型用户
BPE 自底向上 频率最高 确定性贪心 GPT, Llama, Claude
WordPiece 自底向上 似然增益最大 (PMI) 确定性贪心 BERT, ELECTRA
Unigram 自顶向下 对似然边际贡献 概率性,可采样 T5, XLM-R, Llama 2
第四部分:超越 BPE — SentencePiece 与 SuperBPE
4.1 Pre-tokenization 的代价:为什么按空格切并不普适
回顾 BPE 算法的第 1 步:按空格切 。这个"无害"假设隐含着两个大问题:
问题 1:很多语言不用空格
中文 :「我喜歡自然語言處理」没有空格;
日文 :「私は自然言語処理が好きです」混合假名汉字;
泰文 :「ผมชอบประมวลผลภาษาธรรมชาติ」整段没有空格。
按空格切,对这些语言相当于不切 ,整个句子是一个"词",BPE 完全失去其设计前提。
问题 2:多词表达(multi-word expressions)
英文里 on the other hand、depend on、kick the bucket 是固定搭配,
但按空格切后变成多个独立 token,模型必须靠 attention 重新把它们"粘"起来。
4.2 SentencePiece:把空格当字符的库
Google 2018 年发布的 SentencePiece 库提出了一个简洁方案:
SentencePiece 的核心想法
不预分词。把
空格视为词表里的一个普通字符 (用特殊符号
▁ 表示)。
BPE 或 Unigram 直接在
未切分的字节流 上跑。
这样:
中文句子可以"自然"形成子词,不需要任何中文分词器;
分词与还原是无歧义可逆 的(reversible),只要 "".join(tokens).replace("▁", " ");
多语言可统一处理。
SentencePiece 不是一个算法 ——它是一个实现库,里面同时支持 BPE 和 Unigram。
T5、Llama 2、XLM-R、Gemma 都用 SentencePiece + Unigram;Llama 3、4 切换到 SentencePiece + BPE。
4.3 SuperBPE:跨越空格的"超级词"
2025 年 Liu et al. 提出 SuperBPE,对预分词的"教条"做了进一步突破:
SuperBPE 的两阶段课程
阶段 1(subword learning) :按 BPE 标准做法,强制不跨空格地学习子词;
阶段 2(superword learning) :移除空格约束,让 BPE 继续合并,可以跨越多个英文单词。
直观看效果:
原始 BPE
By the way , I am a fan of the Milky Way .
SuperBPE
By the way, I am a fan of the Milky Way .
效果:
同等 $|V|$ 下,序列长度减少约 30%;
推理计算成本同步下降;
多词表达自动成为单 token(By the way,、Milky Way)。
词表大小 |V|
Bytes / Token (↑ better)
BPE w/ pretok
BPE w/o pretok
SuperBPE
BPE upper bound (整词均为 1 token)
SuperBPE 在所有词表大小下都实现更高压缩率,因为它能合并多词表达(数据来源:Liu et al. 2025 论文 Figure 1 示意)。
第五部分:分词的隐秘代价
即使 BPE 已是 LLM 的事实标准,它远未"解决所有问题"。本部分聚焦三个广为人知的失败模式。
5.1 草莓里有几个 r?Spelling 的根本失败
2024 年最有名的 LLM "笑话":
用户:How many 'r's are in 'strawberry'?
ChatGPT (GPT-4o):There are two "r"s in the word "strawberry."
用户:Verify with code.
ChatGPT:There are three "r"s in the word "strawberry."
为什么连"数字母"这种小学一年级问题,最强 LLM 都数不对?根源就在分词:
模型 strawberry 被切成
GPT-2 ["str", "aw", "berry"]
GPT-4o ["strawberry"](单个 token)
两者都没法让模型"看到"单个字符 r。模型必须从"strawberry"这个不透明 token 的嵌入向量 里"反推"出它的字符组成——而这从未在训练目标里被监督过 。
更广义地说,子词模型在以下任务上系统性失败:
拼写
把 token 分解成字符;模型从未学过此映射,只能靠"字符在多少个语境里出现"做模糊推理。
反转字符串
对错别字的鲁棒性
单个字符的改动会让 BPE 合并路径完全不同:importaNt 与 important 的 token 序列毫无重叠。
细粒度算术
"723 + 856" 中数字常被切成奇怪的子片段,导致进位算错。
字符级基准 CUTE
Edman et al. 2024 提出的 CUTE benchmark 专门测试 LLM 的字符级能力:拼写、反转、字符替换、字符计数。
GPT-4o 在多项任务上仍然显著低于人类。这印证了一个深刻结论:
模型的"语言原子"是子词,任何需要原子内部信息的任务都被迫做逆向工程 。
5.2 故障 Token:SolidGoldMagikarp 之谜
2023 年 2 月,一组研究者发现 GPT-3 对某些字符串表现出极端诡异行为:
用户:Tell me about SolidGoldMagikarp.
GPT-3:(输出关于宝可梦 Magikarp 的内容,但坚持把"SolidGold"误读为"distribute")
用户:Is there a difference between SolidGoldMagikarp and SolidGoldMagikarp?
GPT-3:(声称两者完全不同,回答语无伦次)
还有比如 petertodd、attRot、NOTHING IS FAIR IN THIS WORLD OF MADNESS 等等。这些被称为 glitch tokens (故障 token)。
根源:训练分布不匹配
BPE tokenizer 是在某个语料 $\mathcal{D}_\text{tok}$ 上训练的;LLM 是在另一个语料 $\mathcal{D}_\text{LM}$ 上训练的。
若 $\mathcal{D}_\text{tok}$ 包含大量 Reddit 抓取数据,
SolidGoldMagikarp(一个高活跃用户名)会因高频被合并成单个 token。
但 OpenAI 后来在训练 GPT-3 时
清洗 了 Reddit 数据,导致这个 token 的嵌入
几乎从未在 LM 训练中被更新 ,保留随机初始化状态。
Tokenizer 训练语料
D_tok (含 Reddit 等)
SolidGoldMagikarp
出现 10000+ 次
→ 被收入词表,分配 token ID 12345
词表 V
"hello" → 5
"the" → 290
"SolidGoldMagikarp" → 12345
LM 训练语料
D_LM (Reddit 被过滤掉)
SolidGoldMagikarp
几乎从不出现
→ 嵌入向量从未被更新
结果:故障 Token (Glitch Token)
嵌入向量随机 → 模型见到时行为不可预测、产生幻觉
有名的研究 "Fishing for Magikarp" (Land & Bartolo, 2024 ) 系统性地在 GPT-2、Llama 2/3、OLMo、Qwen 等模型上自动检测了这类 token,发现每个模型都有数百到数千个 。
故障 token 的危害不仅是"好奇心":
浪费词表槽位 :本应给低资源语言的 token 被废 token 占用;
对抗攻击面 :攻击者用故障 token 触发不可预测行为,绕过 safety filter;
API 不稳定 :用户输入若包含故障 token,可能突然得到乱码或重复输出。
缓解策略
最简单也最有效的对策:
tokenizer 训练数据应与 LM 训练数据严格一致 。
这个看似显然的原则在工业实践里经常被忽略——因为 tokenizer 训练比 LM 训练早数月,数据策略可能已经变化。
5.3 Tokenization 与所有"奇怪行为"的对照表
Karpathy 在 2024 年播客里给出的"症状—病因"表,至今仍准确:
LLM 的奇怪行为 根源
不会拼写单词 子词 token 隐藏字符信息
不能反转字符串 同上
在非英语任务上更差 非英语 token 的训练样本少
简单算术做错 数字常被切成奇怪的子片段
Python 代码经常出错 缩进、空格被切得不一致
看到 <|endoftext|> 时突然停止 这是真实的特殊 token,触发 EOS
对 trailing whitespace 警告 训练时 trailing space 几乎从未出现
遇到 SolidGoldMagikarp 时崩溃 故障 token
偏好 YAML 而非 JSON JSON 的特殊符号在 BPE 下 token 更多
不是真正的 end-to-end 模型 tokenizer 是独立预处理步骤
第六部分:多语言 NLP — 当世界不只是英语
6.1 7000 种语言与 40% 英语的 Common Crawl
全世界有超过 7000 种活语言 。但 NLP 的全部训练数据严重偏向英语:
约 20% 的人口能说英语;只有 5% 是英语母语者 ;
Common Crawl(最大的开放网络爬虫语料)中40–45% 是英语 ;
许多低资源语言(Tagalog 他加禄语、Amharic 阿姆哈拉语、Yoruba 约鲁巴语)不到 0.01% 。
如果 NLP 只服务英语
我们就在
建立一种系统性排斥世界绝大多数人的技术 。这不是浪漫主义口号——商业现实是,亚洲、非洲、拉丁美洲市场恰恰是数字化最快的地区。
语言 第一语言使用者(百万)
普通话 (Mandarin) 939
西班牙语 485
英语 380
印地语 345
孟加拉语 234
葡萄牙语 236
俄语 147
日语 123
越南语 85
韩语 81.7
高资源 vs 低资源语言
高资源语言(high-resource) :拥有大量数字文本与标注数据,如英语、汉语、西班牙语。
低资源语言(low-resource) :可用数据稀少,如 Yoruba、Tibetan、Quechua。
划分不仅是绝对数据量,还包括
对 NLP 工具/标准的支持程度 。
推荐资源:
6.2 多语言语言模型的架构演化
多语言语言模型(multilingual LM)架构上和单语言完全相同 。唯一差别是训练数据和分词器都覆盖多语言。
flowchart LR
A["1. 收集 各语种文本"] --> B["2. 训练 多语言 BPE/Unigram"]
B --> C["3. 训练 LM (MLM 或 CLM)"]
C --> D["多语言 LM"]
2018 年至今主要里程碑:
模型 年份 语言数 架构
mBERT 2018 104 Encoder
XLM-R 2020 100 Encoder
mT5 2021 101 Encoder-Decoder
BLOOM 2022 46 Decoder
GPT-4, Llama, Gemini, Claude 2023+ 隐式 Decoder
早期方案:Translation Language Modeling (TLM)
XLM (Conneau & Lample, 2019) 用了一个有趣的技巧:把两个语言的
平行句对 拼接,然后在拼接后的序列上做 MLM。
模型可以在预测一个掩码词时"窥探"另一种语言的对应内容,强制学习跨语言对齐。
但 XLM-R 证明:
只用大规模多语言单语数据 + MLM 也能学到强跨语言能力 ,TLM 渐被弃用。
6.3 跨语言迁移:XLM-R 的奇迹
多语言 LM 最神奇的能力是 cross-lingual transfer (跨语言迁移):
在英语标注数据上 fine-tune 一个分类头,然后直接在从未见过任何标注数据 的法语、中文、Swahili 上做预测——竟然也能 work。
Stage 1: 预训练
XLM-R
MLM on 2.5TB CC, 100 lang
Stage 2: Fine-tune
+ Classifier Head
仅用英语标注数据训练
Stage 3: 零样本推理
部署到任意语言
无需目标语标注
Stage 2 训练样本(英语 only):
"Great movie, loved it!" → Positive
"Terrible service, awful." → Negative
"Best purchase ever!" → Positive
Stage 3 预测(零样本):
FR: "Film magnifique !" → Positive
DE: "Schrecklicher Service" → Negative
ZH: "非常好的体验" → Positive
共享的多语言表示空间是迁移的关键
XLM-R 的跨语言迁移 pipeline。预训练时模型学到一个跨语言共享的语义空间;fine-tune 仅用英语数据;推理时直接处理任意预训练见过的语言。
为什么这能 work?两个核心机制:
共享子词词表 :相近语言(如英语、法语)会有大量重叠 token,比如 nation、solution;
对齐的语义空间 :MLM 训练迫使模型把"上下文相似"的词放到向量空间的相近位置,这一性质跨语言传递。
6.4 词表重叠与跨语言对齐
研究表明(Limisiewicz et al., 2023 ;Kallini et al., 2025a ):
词表重叠促进跨语言迁移
重叠越多的词表,跨语言迁移性能越好。即使是
"假朋友"(false friends) ——两种语言里同形但意义不同的词——也能帮助学到有用的跨语言嵌入。
但需要避免极端:每种语言仍需
足够多的专属 token 。
happy, apple,
Batman, pie, of
(a) 完全重叠
happy
apple
Batman
pie
feliz
manzana
(b) 高相似度
happy
apple
Batman
pie/pie
feliz
manzana
(c) 低相似度
happy_EN
apple_EN
feliz_ES
manzana_ES
(d) 无重叠
实证结果:跨语言迁移效果 (a) ≈ (b) > (c) ≫ (d)
完全重叠和高相似度重叠都能产生有效的跨语言嵌入
无重叠(如 XLM-V 给每个语言独立子集)会严重损害迁移能力
参考:Kallini et al. 2025a, "Cross-lingual transfer through vocabulary overlap"
反例:XLM-V 把词表扩大到 100 万 token(XLM-R 的 4 倍),给每种语言更多专属 token。
覆盖率确实更好,但推理效率代价巨大 ,且某些跨语言任务上表现反不如 XLM-R。
6.5 多语言的诅咒:容量与覆盖的取舍
"既然跨语言迁移这么神奇,那加上几千种语言不就完美了吗?"——并非如此。
多语言的诅咒(Curse of Multilinguality)
固定模型容量下,
加入更多语言会逐渐损害每种语言的表现 。
XLM-R 在 XNLI 跨语言 NLI 任务上:
训练 7 种语言:准确率 71.8%
训练 100 种语言:准确率 67.7%
4 个百分点的下降意味着
每种语言分到的模型容量都在缩水 。
语言数量
准确率 (%)
7
15
30
60
100
80
70
60
50
40
低资源语言
高资源语言
All
XLM-R 在不同语言数下的 XNLI 准确率。高资源语言(红)显著下降;低资源(蓝)初期受益于迁移,但语言数继续增加后也会下降。模型容量是瓶颈。
应对方案:
扩大模型容量 :mT5-XXL (13B)、BLOOM (176B) 在更多语言下仍保持性能;
语言特定模块 :MAD-X (Pfeiffer et al., 2020 ) 给每种语言加 adapter,避免参数冲突;
专家混合 (MoE) :让不同 expert 处理不同语言族。
第七部分:分词的公平性问题
7.1 Token 通胀:同样意思在缅甸语要多花 15 倍
回到 PDF 课件里那张表——同一句话在不同语言里被切成多少 token:
语言 文本 Token 数 字符数 Token/Char
英语 We'd sat back on the grass, and time flew by as we looked at the Milky Way. 21 75 0.28
法语 Nous étions assis dans l'herbe, et le temps a filé tandis que nous contemplions la Voie lactée. 27 95 0.28
索马里语 Waxaan dib u fadhiisanay cawskii, wakhtiguna wuu duulay markii aanu eegin Jidka caanaha. 30 88 0.34
泰语 พวกเรานั่งพักผ่อนบนพื้นหญ้า และเวลาก็ผ่านไปอย่างรวดเร็ว... 36 79 0.46
更刺眼的对比来自 Petrov et al. 2023 :
Token 长度差距高达 15 倍
同一段意思,OpenAI tokenizer 在英语里切成 N 个 token,在缅甸语、僧伽罗语、藏语里能切到
15N 个 token。
每词平均 token 数(subword fertility) — 越低越好
拉丁字母
1.0
日语
1.2
韩语
1.5
西里尔字母
2.0
阿拉伯
2.5
泰语
3.0
希伯来
3.3
天城文 (印地)
3.8
孟加拉
5.0
泰米尔
6.0
格鲁吉亚
7.5
藏语
11.3
数据来源:Ahia et al. 2023, "Do all languages cost the same?"
7.2 子词肥沃度与下游性能的负相关
Rust et al. (2021) 给出了关键论断:
分词器的选择对下游性能的影响,可以和预训练数据集规模 相当。
也就是说,给一个语言适配的 tokenizer 可能比单纯堆更多数据更重要。
7.3 API 定价不公的伦理含义
商业 LLM API 几乎都按 token 数计费。这意味着:
非英语用户被"系统性多收费"
Ahia et al. 2023 系统分析 OpenAI API 在 22 种语言上的收费:
用户用低资源语言(如肖纳语、约鲁巴语) 提交同等信息量的请求,要支付15 倍 的费用;
这些用户往往恰恰来自消费能力较弱 的国家;
更糟糕:他们得到的回答质量也更差(因为 fertility 高导致序列截断更频繁)。
这是双重不公 :(1) 价格更高;(2) 质量更低。
分词不再只是工程细节,而成为数字鸿沟的算法化 。
思考题 7.1
若你是 LLM 公司的产品经理,发现非英语用户的
每条消息成本 是英语用户的 5 倍。请提出三个可以缓解(但不必彻底解决)这种不公平的方案,并讨论各自的工程/商业代价。
第八部分:字符/字节级模型的复兴
本课最有 inspirational 价值的部分。多语言公平性、Spelling 失败、Glitch token 这一切问题,
都可以被一个根本方案绕过:不要 tokenizer 了 。直接在字节上训练。
8.1 CANINE:mBERT 的字符级对手
Clark et al. (2022) 提出的 CANINE 是字符级 multilingual 模型:
输入是 Unicode codepoint(覆盖所有语言);
用 hash embedding 把巨大的 codepoint 空间压缩到固定维度;
用一个 downsample CNN 把字符级序列降采样到子词级长度,再喂给 Transformer。
模型 输入 参数 MasakhaNER 平均 F1
mBERT 子词 179M 72.4
CANINE-C 字符 127M 65.5 (-6.9)
CANINE-C + n-grams 字符 167M 76.8 (+4.4)
在 MasakhaNER(11 种非洲语言 NER 基准)上的尤其抢眼结果——CANINE-C 在 Amharic 上 F1 = 50.0,mBERT = 0.0 。
原因:mBERT 完全没在 Amharic 上训练;CANINE-C 字符级覆盖让它能"看懂"全 Unicode。
8.2 ByT5 与 MrT5:动态删除的字节序列
ByT5 把 T5 的 SentencePiece 替换成纯字节输入,证明字节级模型可以匹敌子词模型,但代价是更长的序列和更慢的训练。
2025 年 MrT5 (Kallini et al.) 在 ByT5 基础上加入一个可学习的"删除门"(delete gate) ,让模型动态决定哪些字节可以丢弃:
T
h
e
' '
Delete Gate(可学习)
-0.1 ✓
-28.6 ✗
-1.4 ✓
T
e
' '
⟵ 'h' 被删除(gate score 极低)
后续 Transformer 层(处理更短的序列)
学到语言特定压缩:
中文压缩率 ↑
英文压缩率 ↓
MrT5 的精彩之处:学到的删除模式因语言而异 ——中文的 codepoint 被大量保留(信息密度高),英文的字节被大量删除(冗余多)。这本质上是把分词学进了模型架构 ,而非作为预处理步骤。
8.3 Byte Latent Transformer (BLT):熵驱动的动态 patch
Meta 2024 年的 BLT (Pagnoni et al., 2025) 提出更激进的设计:
Local Encoder :用小型 transformer 处理原始字节;
动态 patch 划分 :根据局部熵把字节序列切成可变长度的"patch";
Latent Transformer :在 patch 级别上做主要计算;
Local Decoder :把 patch 表示解码回字节。
BLT 在 8B 参数级别上首次匹敌 Llama 3 8B(subword 模型),同时使用 50% 更少的推理 FLOP 。
8.4 H-Nets 与层次化自回归 Transformer
两条平行的新方向:
8.5 潜在分词:把"切词"也学进去
研究愿景:Latent Tokenization
所有这些前沿工作有一个共同主题:
让"什么是 token"由模型自己学 。
传统 BPE 是预处理;字节级模型让模型在内部学到适合的语义聚合粒度。
字符/字节级模型解决的不只是公平性,还包括:
问题 BPE 的处理 字节级的处理
故障 Token 普遍存在 不存在(每个字节都在训练中)
拼写任务 无法直接做 原生支持
对错别字鲁棒性 极差(合并路径剧变) 强
低资源语言 fertility 高、性能差 无 fertility 概念,性能均衡
训练效率 高 较低(序列长)
推理效率 高 较低(除非动态降采样)
2025–2026 年最重要的开放问题:动态字节级 / latent tokenization 能否在保持质量的同时把推理效率推到与 BPE 相当?
若答案是肯定的,整个 tokenizer 这一层有可能在未来 5 年内消失。
第九部分:练习题与研究方向
课后练习
练习 9.1(BPE 训练)
对语料 "
low lower lowest newer newest wider widest",从字节开始手动执行 BPE,
列出前 5 步合并。每步给出:(a) 当前频率最高的 pair;(b) 合并后的语料;(c) 当前的合并规则列表。
练习 9.2(测试时分词)
基于练习 9.1 训练出的 BPE,给
"newest" 和
"slowest" 分词。
注意
slowest 在训练语料里没出现过——它会被切成什么?说明这反映了 BPE 的哪个性质。
练习 9.3(嵌入参数计算)
对 Llama 4 ($d=8192$, $|V|=201{,}000$) 和 Gemma 3 ($d=2304$, $|V|=262{,}000$):
计算各自嵌入层的参数量;
若两个模型都把 $|V|$ 改为 50{,}000,嵌入层参数分别节省多少?
讨论:为什么大模型倾向用更大词表?
练习 9.4(公平性诊断)
选三种你熟悉但 fertility 较高的语言(如阿拉伯语、印地语、泰语),用
tiktoken 或 HuggingFace tokenizer 测量:
把 UDHR(世界人权宣言)的前 1000 字符在该语言版本与英文版本下分别 token 化,比较 token/字符比;
计算"消息成本比"——若英文用户花 1 美元,该语言用户实际花多少?
若 OpenAI 想做"按信息量定价",你会怎么设计这个机制?
练习 9.5(故障 Token 检测)
设计一个算法,自动从给定 LLM 检测 glitch token:
输入:tokenizer 与 LM;
输出:嵌入向量"诡异"的 token 列表;
提示:嵌入范数、与平均嵌入的余弦距离、邻居一致性都可作信号。
参考
Land & Bartolo (2024) 后比较你的设计。
研究方向
更好的多语言分词器 :能否设计一个分词算法,给所有语言一个"公平"的 fertility 上限?
潜在分词的可解释性 :BLT/H-Nets 学到的 patch 划分对应什么语言学单元?
分词鲁棒性 :能否在 BPE 训练时加入对抗扰动,让 token 序列对错别字更稳定?
分词器与对齐 :tokenizer 训练数据的偏差如何传播到下游 RLHF / DPO 中?
字符级智能体 :字节级 LLM 在工具调用(需要精确字符串处理)上表现是否优于 BPE?
参考文献与延伸阅读
核心算法
Gage, P. (1994). A New Algorithm for Data Compression . C Users Journal. — BPE 的原始论文(数据压缩背景)。
Sennrich, R., Haddow, B., & Birch, A. (2016). Neural Machine Translation of Rare Words with Subword Units . ACL. — 把 BPE 引入 NLP 的奠基论文。
Wu, Y. et al. (2016). Google's Neural Machine Translation System . arXiv. — WordPiece 算法。
Kudo, T. (2018). Subword Regularization: Improving Neural Network Translation Models with Multiple Subword Candidates . ACL. — Unigram LM 算法。
Kudo, T. & Richardson, J. (2018). SentencePiece: A simple and language independent subword tokenizer . EMNLP Demo.
Liu, A. et al. (2025). SuperBPE: Space Travel for Language Models . arXiv.
多语言模型
Devlin, J. et al. (2019). BERT . NAACL. — mBERT 在 104 种语言上预训练。
Conneau, A. et al. (2020). Unsupervised Cross-lingual Representation Learning at Scale (XLM-R) . ACL.
Xue, L. et al. (2021). mT5: A Massively Multilingual Pre-trained Text-to-Text Transformer . NAACL.
BigScience Workshop (2022). BLOOM: A 176B-Parameter Open-Access Multilingual Language Model .
Liang, D. et al. (2023). XLM-V: Overcoming the Vocabulary Bottleneck in Multilingual Masked Language Models . NAACL.
故障 Token & 分词缺陷
Land, S. & Bartolo, M. (2024). Fishing for Magikarp: Automatically Detecting Under-trained Tokens in Large Language Models . EMNLP.
Edman, L. et al. (2024). CUTE: Measuring LLMs' Understanding of Their Tokens . arXiv.
Huang, S. et al. (2023). When Reasoning Meets Information Aggregation: A Case Study with Sports Narratives . arXiv. — 字符级任务中的 BPE 限制。
公平性 & 评测
Petrov, A. et al. (2023). Language Model Tokenizers Introduce Unfairness Between Languages . NeurIPS.
Ahia, O. et al. (2023). Do All Languages Cost the Same? Tokenization in the Era of Commercial Language Models . EMNLP.
Rust, P. et al. (2021). How Good is Your Tokenizer? On the Monolingual Performance of Multilingual Language Models . ACL.
Limisiewicz, T. et al. (2023). Tokenization Impacts Multilingual Language Modeling . ACL.
Kallini, J. et al. (2025a). Cross-lingual transfer through vocabulary overlap . (referenced in CS224N 2026 lecture)
字符 / 字节级模型
Clark, J. H. et al. (2022). CANINE: Pre-training an Efficient Tokenization-Free Encoder for Language Representation . TACL.
Xue, L. et al. (2022). ByT5: Towards a Token-Free Future with Pre-trained Byte-to-Byte Models . TACL.
Kallini, J. et al. (2025b). MrT5: Dynamic Token Merging for Efficient Byte-level Language Models . ICLR.
Pagnoni, A. et al. (2025). Byte Latent Transformer: Patches Scale Better Than Tokens . arXiv.
Hwang, S. et al. (2025). H-Nets: Hierarchical State Space Models . arXiv.
Neitemeier, P. et al. (2025). Hierarchical Autoregressive Transformers: Combining Byte- and Word-Level Processing . arXiv.
Minixhofer, B. et al. (2025). Bolmo: Byte-Level Open Language Models . arXiv.
Zheng, X. et al. (2025). EvaByte: Efficient Byte-Level Modeling . arXiv.
语言学背景
Jurafsky, D. & Martin, J. H. (2024). Speech and Language Processing (3rd ed., draft). Chapter 2 — Regular Expressions, Tokenization, Edit Distance.
Dryer, M. & Haspelmath, M. (eds.) (2013). World Atlas of Language Structures Online .
Eberhard, D. M., Simons, G. F., & Fennig, C. D. (2024). Ethnologue: Languages of the World (27th ed.).
博客与教程
Karpathy, A. (2024). Let's build the GPT Tokenizer . YouTube. — 从零实现 BPE 的 2 小时长讲座,强烈推荐。
Arnett, C. (2024). Tokenizer-free or not? Blog post. — 字节级 vs 子词级的深度对比。
HuggingFace NLP Course. Chapter 6: The Tokenizers Library .
配套阅读(CS224N 课程相关)
CS224N Winter 2026 Lecture 14 原始幻灯片(Julie Kallini)
本地 Lab Wiki:foundations/Tokenizer/、frontiers/Multilingual/
本系列教材 Lecture 7(预训练)、Lecture 8(后训练)、Lecture 11(评估)涉及到的分词器影响
本教材由 Claude (Opus 4.7) 基于 CS224N Winter 2026 Lecture 14 (Julie Kallini) 改编,结合 deep-research 方法论原则,于 2026 春为研究生学习者深度展开。
鸣谢:Julie Kallini 的原始讲座设计;Dan Jurafsky、Alisa Liu、Yejin Choi、Christopher Potts、Catherine Arnett、Tolúlọpẹ́ Ògúnrẹ̀mí 的素材共享。
建议配合手写 BPE 实现、Tiktokenizer 在线工具、HuggingFace tokenizers 库一同学习。