文章摘要
分词器(Tokenizer)是LLM处理文本的第一道工序,决定了模型如何「看见」语言。本文从最基础的字符级分词出发,系统讲解BPE、WordPiece、Unigram、SentencePiece四大算法的原理与差异,对比tiktoken与HuggingFace Tokenizers两大工程实现,并给出2026年主流LLM的分词器选型全景图。
一、为什么分词器是LLM的基石
分词器定义了模型如何「看见」语言
大语言模型不直接处理文字——它处理的是整数序列。分词器(Tokenizer)就是完成「文字→整数」转换的第一道工序。这个看似简单的步骤,实际上决定了模型对语言的几乎所有基本认知:
- 词汇边界:「hugging」是一个词还是「hug」+「ging」两个子词?不同的分词方式直接影响模型对词义的理解
- 上下文窗口利用率:同样的文本,用不同分词器可能产生差异2-3倍的token数量。这意味着同样的128K上下文窗口,能容纳的实际内容量完全不同
- 多语言能力:分词器对中文、日文、阿拉伯文等非拉丁文字的处理效率差异巨大。一个为英文优化的分词器,处理中文时可能需要3-5倍的token数量
- 推理成本:API按token计费。分词效率低意味着同样的内容要付更多钱
分词器的三个层次
分词技术经历了三个发展阶段:
词级(Word-level):最直觉的方式——按空格和标点切分。问题是词汇表爆炸:英语有超过100万个词,加上变形和专有名词,词表可能达到百万级。每个词对应一个embedding向量,百万级词表的embedding层就需要数GB内存。
字符级(Character-level):走向另一个极端——每个字符一个token。词表极小(几十个字符),但序列长度爆炸:「hello」变成5个token,「unbelievable」变成12个。更严重的是,字符级分词丢失了词义信息,模型需要更深的网络才能学到等价表示。
子词级(Subword-level):2026年LLM的标准选择。在词级和字符级之间找到平衡——常见词保持完整,罕见词拆分为子词。例如「unbelievable」可能拆分为「un」+「believ」+「able」三个子词token,既控制了词表大小,又保留了有意义的语义单元。
分词器的经济学影响
一个具体的例子:同样一句「今天天气很好」,在不同分词器下的token数量差异:
- GPT-4的o200k分词器:约4-5个token(中文优化后)
- GPT-4的cl100k分词器:约7-8个token
- Llama 2的SentencePiece:约10-12个token
- 纯字符级:5个token(每个汉字一个token)
看似差异不大,但当处理百万级文档时,这些差异会累积成显著的成本和延迟差距。
💡 一句话理解
分词器不是简单的「预处理」——它是模型架构的一部分。更换分词器意味着模型的embedding层和输出层都需要重新训练,因为词表变了。
二、BPE算法:从数据压缩到NLP基石
BPE的历史:从压缩算法到NLP
字节对编码(Byte Pair Encoding, BPE)最初是一种数据压缩算法,由Philip Gage在1994年提出。其核心思想极其简单:
- 从字符级开始,统计所有相邻字符对的出现频率
- 找到出现频率最高的字符对,将其合并为一个新符号
- 重复步骤1-2,直到达到目标词表大小
例如,在一个英文语料中:
- 初始:h, e, l, l, o(每个字符独立)
- 第1轮合并:「t」+「h」→「th」(因为「th」出现最频繁)
- 第2轮合并:「th」+「e」→「the」
- 第N轮合并:逐步构建出常见的子词单元
BPE在NLP中的应用
2015年,Sennrich等人将BPE引入神经机器翻译,发表了里程碑论文「Neural Machine Translation of Rare Words with Subword Units」。他们发现BPE能优雅地处理未登录词(OOV):
- 训练时见过的词:作为整体token
- 训练时没见过的词:拆分为已知的子词组合
- 极端情况:退化为字符级,但不会完全无法处理
BPE的训练过程详解
BPE训练的核心是一个贪心合并过程:
- 初始化:将训练语料切分为字符序列。每个字符是一个基础token
- 统计频率:遍历整个语料,统计所有相邻token对的出现次数
- 选择最优合并:找到频率最高的token对,创建新token
- 应用合并:在语料中将该token对替换为新token
- 重复:回到步骤2,直到词表达到预设大小(通常30K-200K)
时间复杂度:每轮需要遍历整个语料统计频率,合并次数为词表大小减去初始字符集大小。总体复杂度约为$O(N \times V)$,其中$N$是语料总长度,$V$是目标词表大小。
BPE的变体
原始BPE有多个工程变体:
三、WordPiece与Unigram:两种不同的子词学习策略
WordPiece:基于似然的贪心合并
WordPiece由Google在2016年的论文中提出,用于BERT等模型的预训练。它与BPE的核心区别在于合并标准:
具体来说,WordPiece计算每对token合并后对整体语言模型似然的贡献:
$$\text{score}(a, b) = \frac{\text{count}(ab)}{\text{count}(a) \times \text{count}(b)}$$
这个公式的含义是:如果「ab」作为一个整体的出现频率远高于「a」和「b」独立出现频率的乘积,说明它们有很强的结合倾向,应该合并。
WordPiece的编码方式
WordPiece使用贪心最长匹配(Greedy Longest Match)进行编码:
例如,对于「unhappiness」:
- 尝试匹配「unhappiness」→ 不在词表中
- 尝试匹配「unhappines」→ 不在词表中
- ...
- 匹配「un」→ 在词表中,输出
- 从「happiness」继续,匹配「happi」→ 在词表中
- 继续「ness」→ 在词表中
- 最终:「un」+「happi」+「ness」
Unigram语言模型:从大到小的剪枝策略
Unigram模型由Taku Kudo在2018年提出,采用了与BPE/WordPiece完全相反的策略:
- BPE/WordPiece:从最小开始,逐步合并(自底向上)
- Unigram:从最大开始,逐步剪枝(自顶向下)
Unigram的训练过程:
- 初始化大词表:从训练语料中提取所有高频字符n-gram,构建一个初始词表(通常为目标大小的10-100倍)
- 计算最优分词:使用Viterbi算法,在当前词表上找到使训练数据似然最大的分词方案
- 计算剪枝损失:对每个token,计算如果从词表中移除它,训练数据似然会下降多少
- 剪枝:移除损失最小的token(通常是低频或冗余的token)
- 重复:回到步骤2,直到词表缩小到目标大小
Unigram的关键优势:
三种算法的对比
💡 一句话理解
如果你只需要一个确定性分词器,BPE足够好。如果你需要训练时的数据增强(子词正则化),Unigram是唯一原生支持的方案。
⚠️ 常见踩坑
WordPiece的贪心最长匹配可能导致非直觉的分词结果。例如「hugging」可能被分为「hug」+「ging」而不是「hugg」+「ing」,因为贪心匹配优先选择最长前缀。
四、SentencePiece:语言无关的分词框架
为什么需要SentencePiece?
BPE和WordPiece都有一个共同的工程问题:需要预分词(Pre-tokenization)。
传统BPE在训练前需要先将文本按空格和标点切分为单词,然后在单词内部运行BPE合并。这带来两个问题:
- 空格依赖:中文、日文、泰文等语言没有空格分隔单词,预分词规则需要单独设计
- 预处理不一致:不同语言的预分词规则不同,导致同一套pipeline难以处理多语言
SentencePiece由Google的Taku Kudo和John Richardson在2018年提出,核心创新是:直接在原始Unicode文本上操作,不需要任何预分词。
SentencePiece的工作方式
SentencePiece将空白字符显式表示为特殊符号「▁」(U+2581,Lower One Eighth Block):
- 「Hello world」→「▁Hello」+「▁world」
- 「你好世界」→「▁你」+「▁好」+「▁世」+「▁界」
这样做的好处是:空白字符被当作普通字符处理,模型可以学习到「词首」「词中」的位置信息。
SentencePiece的两种训练模式
SentencePiece本身是一个框架,支持两种底层算法:
选择哪种模式取决于需求:
- 需要确定性分词 → BPE模式
- 需要子词正则化 → Unigram模式
SentencePiece vs tiktoken:两大工程实现
2026年的LLM生态中,两大分词器实现占据了主导地位:
SentencePiece(Llama 2, Gemma, T5等使用):
- 直接在Unicode code point层面操作
- 支持BPE和Unigram两种算法
- 对罕见字符有byte fallback机制
- 词表通常32K-256K
- 多语言覆盖好,但拉丁文字效率略低
tiktoken(GPT系列, Llama 3+使用):
- 在UTF-8字节层面操作
- 纯BPE算法,叠加正则预分词规则
- 永远不会出现UNK(字节级覆盖)
- 词表50K-200K
- Rust实现,速度极快
- 不支持训练自定义分词器
关键差异:中文处理
以中文「机器学习很有趣」为例:
- tiktoken(字节级BPE):先将中文转为UTF-8字节(每个汉字3字节),然后在字节层面做BPE合并。常用汉字会被合并为单token,但罕见汉字可能拆为2-3个字节token
- SentencePiece(code point级BPE):直接在汉字层面操作。常用汉字为单token,罕见汉字通过byte fallback拆为字节
实际效果:对于中文文本,SentencePiece的token效率通常比tiktoken略高(约10-20%),因为code point级别的操作避免了UTF-8编码的中间步骤。但tiktoken在GPT-4o的o200k词表中做了大量中文优化,差距已经很小。
2026年主流LLM的分词器选型
| 模型系列 | 分词器 | 词表大小 | 算法 |
|---|---|---|---|
| GPT-4o/GPT-5 | tiktoken o200k | ~200K | Byte-level BPE |
| GPT-3.5/GPT-4 | tiktoken cl100k | ~100K | Byte-level BPE |
| LLaMA 2 | SentencePiece | 32K | BPE模式 |
| LLaMA 3/3.1/4 | tiktoken风格 | 128K | Byte-level BPE |
| Gemma/Gemma 2 | SentencePiece | 256K | Unigram模式 |
| Claude 3/3.5 | 专有BPE | 未公开 | BPE风格 |
| Qwen 2/2.5 | tiktoken风格 | 152K | Byte-level BPE |
| Mistral | SentencePiece | 32K | BPE模式 |
| T5/mT5 | SentencePiece | 32K/250K | Unigram模式 |
💡 一句话理解
如果你要训练新的LLM且需要多语言支持,SentencePiece的Unigram模式是最安全的选择。如果你只做英文且追求速度,tiktoken是最快的。
⚠️ 常见踩坑
tiktoken不支持训练自定义分词器。如果你需要为新语言或领域定制分词器,必须使用SentencePiece或HuggingFace Tokenizers。
五、分词器的性能指标与评估方法
Fertility(繁殖率)
分词器性能最核心的指标是Fertility——即token数与词数的比值。Fertility越低,分词效率越高:
$$\text{Fertility} = \frac{\text{Token数量}}{\text{Word数量}}$$
理想情况下,每个词对应1个token(Fertility=1)。实际中:
- 英文:好的分词器Fertility约1.2-1.4
- 中文:好的分词器Fertility约1.0-1.5(每字1-1.5 token)
- 低资源语言:Fertility可能达到2.0-5.0
Bits per Character(BPC)
BPC衡量分词器的信息编码效率:
$$\text{BPC} = \frac{-\log_2 P(\text{text})}{\text{字符数}}$$
BPC越低,说明分词器对文本的压缩效率越高。理想的分词器接近英语的熵值(约1.0 bit/character)。
词表覆盖率
给定词表大小,能覆盖训练语料中多少比例的token出现次数:
- 30K词表:覆盖约97-98%的英文语料
- 50K词表:覆盖约98-99%
- 100K词表:覆盖约99-99.5%
- 200K词表:覆盖约99.5%+
边际收益递减:从30K到100K提升约2%,从100K到200K只提升约0.5%。但每个新token都需要对应的embedding向量,词表越大,embedding层的内存和计算开销越高。
多语言Fertility对比
以同一段联合国人权宣言的多语言版本为例:
| 语言 | 原文字符数 | tiktoken cl100k tokens | SentencePiece 32K tokens | Gemma SP 256K tokens |
|---|---|---|---|---|
| 英文 | ~4500 | ~5800 | ~6200 | ~5500 |
| 中文 | ~1500 | ~2200 | ~1800 | ~1600 |
| 日文 | ~2000 | ~3500 | ~2800 | ~2400 |
| 阿拉伯文 | ~3000 | ~5000 | ~4500 | ~3800 |
| 印地文 | ~3500 | ~6000 | ~5500 | ~4200 |
数据说明:cl100k对中文的处理效率不如SentencePiece(因为cl100k的词表以英文为主),但GPT-4o的o200k已经大幅改善了这一问题。Gemma的256K大词表在所有语言上都表现优异,但代价是更大的embedding层。
分词器对模型性能的影响
分词器不仅影响效率,还影响模型质量:
- 语义完整性:如果一个常用词被拆分为太多子词,模型需要更多层才能学到它的完整语义
- 跨语言迁移:多语言分词器如果某种语言的Fertility过高,该语言的性能通常较差
- 代码理解:代码中的特殊符号(如「->」「!=」「{」)如果被拆分为多个token,模型对代码结构的理解能力下降
2025年的一项研究(SuperBPE)表明,在保持词表大小不变的情况下,优化分词器的Fertility可以带来1-3%的下游任务提升,且对低资源语言的提升更为显著。
💡 一句话理解
评估分词器质量的第一指标是Fertility。在你的目标语言和目标领域上测量Fertility,比看任何benchmark都直接。
六、工程实践:HuggingFace Tokenizers与BlockBPE
HuggingFace Tokenizers
HuggingFace的Tokenizers库是2026年使用最广泛的分词器实现,几乎与Transformers库深度绑定。其核心特点:
- Rust实现:核心分词逻辑用Rust编写,单线程速度比旧版Python实现快10-100倍
- 多算法支持:BPE、WordPiece、Unigram均有实现
- 预训练分词器托管:HuggingFace Hub上托管了超过50万个预训练分词器,可直接加载
- 自定义训练:支持在自定义语料上训练新的分词器
训练自定义分词器的典型流程
使用HuggingFace Tokenizers训练一个BPE分词器的关键步骤:
- 准备训练语料:通常1-10GB的目标领域文本
- 配置分词器:选择算法(BPE/WordPiece/Unigram)、词表大小、特殊token
- 训练:调用tokenizer.train()方法,通常几分钟到几十分钟
- 评估:在测试集上计算Fertility和覆盖率
- 部署:保存为JSON文件,加载到推理pipeline
BlockBPE:并行化的新前沿
2025年发表的BlockBPE代表了分词器性能的新突破。它的核心创新是将BPE的串行合并过程并行化:
传统BPE的合并是严格串行的——每次合并后需要重新统计频率。BlockBPE发现,在一次合并中,多个不重叠的token对可以同时合并而不冲突。利用这一特性,BlockBPE在GPU上实现了:
- 比tiktoken快2倍的吞吐量
- 比HuggingFace Tokenizers快2.5倍的吞吐量
- 在高batch推理场景下优势更明显
分词器的部署注意事项
在生产环境中,分词器的工程考量包括:
- 延迟:分词本身需要时间。对于短文本(<100字符),分词延迟可能占总prefill延迟的10-20%
- 一致性:训练和推理必须使用完全相同的分词器版本。版本不一致会导致token ID偏移,模型输出完全错误
- 特殊token:不同模型使用不同的特殊token(如<|endoftext|>、[CLS]、[SEP]),必须严格匹配
- 内存:分词器本身占用内存不大(通常<100MB),但词表到embedding的映射需要GPU内存
分词器版本管理
一个容易被忽视的工程问题:分词器版本必须与模型版本严格对应。
- LLaMA 3.0和LLaMA 3.1的分词器词表相同但合并规则可能不同
- GPT-4从cl100k升级到o200k时,同样的文本产生的token ID完全不同
- 如果你fine-tune了模型但使用了基础模型的分词器,可能导致性能下降
最佳实践:将分词器文件与模型权重一起版本管理,不要依赖「最新版本的默认分词器」。
💡 一句话理解
生产环境中最常见的分词器bug是版本不一致。建议在模型部署脚本中显式指定分词器文件路径,不要依赖自动解析。
⚠️ 常见踩坑
HuggingFace的AutoTokenizer方便但有风险——它可能在你不知情的情况下更新分词器版本。生产环境建议锁定具体版本。
七、前沿趋势:分词器的未来方向
趋势1:更大词表成为主流
2023年,主流LLM的词表大小为32K-50K。到2026年,趋势已经转向100K-256K:
- GPT-4o: 200K(o200k)
- LLaMA 3/4: 128K
- Gemma 2: 256K
- Qwen 2.5: 152K
大词表的好处是直接且明显的:Fertility降低、上下文利用率提高、多语言性能提升。代价是embedding层更大(256K×4096维的embedding需要约2GB内存),但这在2026年的GPU容量下已不是问题。
趋势2:领域自适应分词器
通用分词器在特定领域(如医学、法律、代码)的Fertility通常较高。2025-2026年的趋势是针对特定领域训练专用分词器:
- 代码分词器:将常见的代码模式(如「def init(self)」)作为单token
- 医学分词器:将医学术语(如「myocardial infarction」)保持完整
- 法律分词器:将法律术语和条款编号作为单token
IndicSuperTokenizer(2025)的研究表明,领域自适应分词器可以在不增加词表大小的情况下,将特定领域的Fertility降低15-30%。
趋势3:分词器与模型联合训练
传统做法是先固定分词器,再训练模型。但分词器的选择实际上影响模型的表示学习。2025年开始出现分词器与模型联合优化的研究:
- Soft Tokenization:将分词过程软化为可微操作,允许梯度回传到分词决策
- Adaptive Vocabulary:训练过程中动态调整词表——合并低频token、拆分高频token
- Tokenizer-aware Loss:在损失函数中考虑分词的不确定性
趋势4:超越BPE的新算法
BPE统治了十年,但研究者正在探索替代方案:
- SuperBPE(2025):在BPE基础上引入语义信息指导合并,不仅看频率还看语义一致性
- Scaffold-BPE(2024):迭代剪枝低频token,减少词表中的不平衡
- PickyBPE(2024):丢弃「无信息量」的合并,提高词表利用率
- RWKV World Tokenizer:使用完全不同的算法,在Rust中实现,速度比tiktoken快10倍(单线程)
趋势5:多模态分词器
随着多模态模型的普及,分词器不再只处理文本:
- 视觉token:将图像切分为patch token(如ViT的16×16 patch)
- 音频token:将音频波形编码为离散token(如AudioLM、Whisper)
- 统一分词器:将文本、图像、音频映射到同一个token空间
这对分词器的设计提出了全新挑战:不同模态的token需要在语义空间中对齐,同时保持各自的编码效率。
⚠️ 常见踩坑
分词器联合训练仍处于研究阶段,不建议在生产中使用。当前最稳妥的做法仍然是:先用标准算法训练分词器,再用固定分词器训练模型。
🎯 相关面试题
巩固本篇知识点,备战 AI 岗位面试。
- 中级概念查看详解 →
子词分词:BPE、WordPiece、Unigram 有什么区别?
BPE 按频率自底向上合并、WordPiece 按似然增益合并(BERT)、Unigram 概率化自顶向下裁剪(SentencePiece)。
- 中级概念查看详解 →
BERT 如何处理不常见或罕见词(OOV)?
BERT 用 WordPiece 子词分词,把罕见词拆成已知子词(如 playing→play+##ing),未登录词可一路拆到字符,因此几乎没有传统意义的 OOV;子词共享表示让模型也能组合理解未见过的词。
- 中级场景查看详解 →
如何有效优化和微调 BERT 以应对特定 NLP 任务?
微调 BERT 要按任务接对应任务头,用小学习率(2e-5~5e-5)、少 epoch、warmup 加线性衰减,并通过 dropout、早停、分层学习率、数据增强或继续预训练等手段防过拟合、处理数据不足与类别不平衡。
- 中级场景查看详解 →
BERT 输入长度的 512 限制如何解决?
BERT 因位置编码与 O(L²) 注意力被限制在 512 token;长文本可用截断、滑动窗口分段聚合、层次编码、长上下文模型(Longformer/BigBird)或关键句抽取,按任务取舍。
