1. 为什么需要子词分词
在 BPE 流行之前,文本分词主要面临两个极端:
基于词的分词:构建一个固定大小的词表,每个词都是一个 token。这会导致两个问题:一是词表巨大(数百万级),二是未登录词(OOV)无法处理,只能映射为
[UNK]。基于字符的分词:每个字符作为 token,彻底消除 OOV,但序列变得极长,语义信息过于碎片化,模型难以捕捉词级的含义。
子词分词的动机正是希望在两者之间取得平衡——用有限的词表覆盖大部分语料,同时具备一定的组合能力来表征罕见词或新词。BPE 是最早被大规模验证并成功应用的子词分词方法之一。
2. BPE 的起源:从数据压缩到 NLP
BPE 最早由 Philip Gage 在 1994 年提出,题为《A New Algorithm for Data Compression》。它的核心思想是:寻找数据中最频繁出现的相邻字节对,并用一个未使用的字节替换它们,如此反复,从而实现对数据的无损压缩。2016 年,Sennrich 等人在论文《Neural Machine Translation of Rare Words with Subword Units》中将这一思想移植到 NLP 的词表构建中,将“字节”替换为“字符”,从而提出了一种自动学习子词单元的方法。从此,BPE 成为神经机器翻译以及后续大语言模型(如 GPT 系列)的分词基础。
3. BPE 的核心思想与算法步骤
BPE 算法的目标是从一个字符级的词表出发,通过反复合并高频相邻符号对,逐步构建一个包含子词单元的最终词表。整个过程可以拆分为学习(训练)和编码(推理)两个阶段。
3.1 学习阶段:构建合并规则和词表
输入:一个经过基本预处理的训练语料(通常按空格切分为“词”)。
输出:一个最终词表,以及一组按顺序应用的合并规则。
具体步骤如下:
初始化词表和语料表示
将语料中的每个词拆分为字符序列,并在词尾添加一个特殊的结束符号(通常用
</w>),以标记词边界,避免跨词合并。例如,单词 “low” 表示为
l o w </w>。初始词表包含语料中出现的所有字符以及
</w>。
统计相邻符号对频率
在所有词的字符序列中,计算每个相邻符号对出现的总频次。
例如,在 “low” 中出现
(l, o)、(o, w)、(w, </w>),各计数1次(需乘以该词在语料中的出现次数)。
合并最高频的符号对
选择出现次数最多的相邻符号对
(A, B)。如果有多个频率相同,通常按字母序等确定优先级。将该对合并为一个新符号
AB,并将其加入词表。在语料中,将所有连续出现的
A B替换为AB(不会跨单词,因为</w>的阻隔)。记录下这一合并规则:“
A B→AB”。
重复合并直到满足停止条件
重新统计所有相邻符号对频率,重复步骤 3 的合并过程。
停止条件通常是:执行了预先设定的合并次数,或者词表达到目标大小(例如 32,000 个 token)。
最终的词表包含初始字符以及所有合并过程中产生的新符号。合并顺序也被保留,形成“合并优先级列表”。
3.2 编码阶段:将文本分词
给定一段新文本,使用学到的合并规则将其转换为子词序列:
将文本按词划分,每个词切分为字符序列,并附加
</w>。按照学习阶段记录下来的合并优先级顺序,依次尝试应用合并规则。
对每个词,从头开始,每次查找序列中是否存在可以合并的相邻符号,如果存在且符合当前最高优先级的规则,就合并它;然后继续用该规则检查直到不能再合并,再换下一个规则。实际实现中,通常直接按照规则列表的顺序,对序列做一遍扫描替换。
最终,词的字符序列被转换为若干个子词 token,同时
</w>被移除或保留为词边界标志(取决于实现)。所有词的子词序列拼接起来,即得到整个文本的 token 序列。
4. 一个具体的 BPE 学习例子
假设我们的微型语料及词频如下:
low : 5 lower : 2 newest : 6 widest : 3
步骤 1:初始化
将每个词拆成字符并加</w>,得到:
l o w </w> → 频次 5 l o w e r </w> → 频次 2 n e w e s t </w> → 频次 6 w i d e s t </w> → 频次 3
初始词表:{l, o, w, e, r, n, s, t, i, d, </w>}(共 11 个)。
步骤 2:第一次统计相邻对
计算所有相邻对的总频次(高频对示例):
(e, s): newest 中出现 1 次,widest 中出现 1 次 → 6 + 3 = 9 次(s, t): newest 6 次,widest 3 次 → 9 次(e, w): newest 中w e是 6 次;lower 中e r是 2 次(l, o): low 5 次,lower 2 次 → 7 次……
最高频对为(e, s)和(s, t),均为 9 次。假设字典序优先合并(e, s)→es。
规则 1:e s→es。将词表加入es,语料更新为:
l o w </w> l o w e r </w> n e w es t </w> w i d es t </w>
步骤 3:继续合并
重新统计,此时(es, t)频率最高:newest 6 次 + widest 3 次 = 9 次。
规则 2:es t→est。词表加入est,语料更新:
l o w </w> l o w e r </w> n e w est </w> w i d est </w>
之后,高频对依次可能是:
(l, o)→lo(7 次)(lo, w)→low(7 次)(e, r)→er(2 次) 或(w, </w>)(5 次) 等,直至达到目标词表大小。
最终,词表会包含诸如low、est、er、new等有意义的子词单元。像 “lowest” 这种未登录词,在测试时会被编码为low+est,从而完美表征。
5. 关键参数与实现细节
词表大小:通常是超参数,常见取值为 8k、16k、32k、50k 等。词表越大,合并次数越多,tokens 平均长度越长,可覆盖更多完整词汇;词表越小,颗粒度越细。
词边界符号:原始 BPE 在每个词尾部加
</w>,确保不会跨词合并,相当于先把文本分成词,再做子词切分。而SentencePiece则将空格本身作为一个普通字符(如▁)处理,不预分词,直接将整段文本当作字符流应用 BPE,从而实现语言无关的分词。数据结构优化:实际的 BPE 训练会使用优先队列(堆)来高效管理相邻对的频率,每次合并后只需更新受影响位置的对计数,不必每次都全局扫描。这种优化使得千万级语料的训练在几分钟内即可完成。
特殊 token:最终词表中还需加入
[PAD]、[UNK]、[BOS]、[EOS]等控制 token。如果使用 BPE 且字符覆盖足够,[UNK]几乎不会出现,因为任何词都能被拆成字符级序列(除非使用了限制字符表的 byte-level BPE)。
6. BPE 的优缺点
优点
自动发现子词单元:无需语言学知识,能捕获常见前缀、后缀及词根(如 “est”、“ing”、“un”),并能共享子词参数。
平衡词表大小与序列长度:高频词保持完整,低频词拆为子词,避免了 OOV,同时未使序列过长。
语言无关:只依赖统计频率,适用于任意语言(包括中文、日语等无空格分隔的语言,配合 SentencePiece)。
压缩效果好:信息密度高,能用较小的词表编码长文本。
缺点
贪婪分割的非最优性:频率最高的合并可能产生不符合词法的分割。例如,语料中 “unrelated” 出现极少,可能被分割成
unrelated,而不是理想的un+related。对训练语料敏感:如果领域迁移,固定的合并规则可能无法很好地泛化,因为新语料的子词频率分布可能不同。
确定性分词:一个词总是被切成相同的子词序列,无法提供多种可能的分割(对于需要语义多样性或鲁棒性的场景可能不足)。
合并过程不可逆:一旦 BPE 规则固定,无法像概率模型那样考虑全局最优分割。
7. 重要变体与演进
7.1 Byte-level BPE (BBPE)
GPT-2 及后续模型使用的分词方式。它不再以 Unicode 字符为初始符号,而是直接以字节(0~255)为基本单位。256 个字节加上一些特殊 token 构成初始词表,然后应用 BPE 合并字节序列,最终得到一个包含 50,257 个 token 的词表。
优势:
绝对无 OOV:因为所有文本都可以编码为字节流。
能正确处理所有 Unicode 字符,包括非常见符号、Emoji 等。
代价:某些单字符可能会被拆成多个字节 token,略微降低效率,但对于大模型这种极强上下文建模能力的结构,影响很小。
7.2 BPE-Dropout
Provilkov 等(2020)提出,在训练阶段使用 BPE 分词时,以一定概率 p 随机“丢弃”某些合并操作。这使得同一个词在不同训练步可能呈现不同的子词分割,相当于一种隐式的数据增强。它能显著提高模型对拼写错误、同义分割的鲁棒性,并在低资源场景下带来 BLEU 提升。
7.3 SentencePiece 与 Unigram 模式
Google 开源的 SentencePiece 库实现了 BPE 和 Unigram LM 两种算法,且都将空格处理为普通字符,避免了语言依赖的预分词。虽然它支持 BPE,但其默认和更被推崇的模式是 Unigram 语言模型方法,因为 Unigram 能给出词的分割概率,并支持多种编码采样。
8. 与其他子词分词方法的对比
| 方法 | 原理 | 分割依据 | 训练方式 | 代表应用 |
|---|---|---|---|---|
| BPE | 迭代合并高频相邻符号对 | 局部统计频次 | 自底向上(从字符开始合并) | GPT-1, RoBERTa(部分) |
| WordPiece | 每次选择使语言模型似然增量最大的符号对合并 | 概率增益 | 自底向上,与 BPE 类似但准则不同 | BERT, DistilBERT |
| Unigram LM | 假设子词独立,维护一个候选词表,通过 EM 算法估计概率并剔除低概率子词 | 全局概率模型 | 自顶向下(从大词表开始剪枝) | T5, XLNet, ALBERT, LLaMA(部分) |
需要注意,许多现代大模型实际采用的都是经过 SentencePiece 库实现的 BPE 或 Unigram 模式。例如,LLaMA和Mistral使用 SentencePiece 的 BPE(搭配 byte fallback 处理未知字节),而BERT使用 WordPiece。BBPE 依然属于 BPE 家族。
9. 总结
BPE 方法通过一种简单直观的迭代合并策略,构建了一套高效、语言无关的子词词表。它不仅解决了传统词级分词的 OOV 难题,同时控制了序列长度,使得深度学习模型能更好地学习词汇的内部结构和共享表示。从最早的神经机器翻译到 GPT、LLaMA 等千亿参数大模型,BPE 及其变体始终占据着核心地位。理解 BPE 的机制,对于深入掌握现代 NLP 系统的数据预处理、词表设计乃至模型行为分析都至关重要。