我们来详细介绍一下 Byte-pair Encoding(BPE),这是一种在自然语言处理(NLP)领域非常流行且重要的子词分词算法。
1. 核心思想:解决什么问题的?#
在 NLP 任务中,我们需要将文本转换成模型能够理解的数字,即“分词”。传统方法主要有两种:
- 词级分词:将句子分成独立的单词。
- 问题:
- 词汇表爆炸:词汇表可能会变得非常庞大(例如几十万甚至上百万词),尤其是对于有丰富形态变化的语言(如德语、土耳其语)。
- 无法处理未知词:对于训练时没见过的词(OOV问题),模型会将其标记为
<UNK>,导致信息丢失。
- 问题:
- 字符级分词:将句子分成单个字符。
- 问题:
- 序列过长:一个句子会被分成非常长的序列,大大增加了模型的计算负担。
- 难以捕捉语义:单个字符本身几乎不携带任何语义信息,模型需要从零开始学习组合,难度很大。
- 问题:
BPE 的诞生就是为了在“词”和“字符”之间找到一个平衡点。 它的核心思想是:“频繁共现的字节对(或字符对)应该被合并成一个新的、更大的符号。”
通过这种方式,BPE 可以从最常见的字符组合开始,逐步构建出子词单元,这些单元既可以是完整的单词(如 "the"),也可以是词根(如 "un-")、词缀(如 "-ing"),甚至是更大的片段。
2. BPE 的工作原理(训练阶段)#
BPE 算法分为两个主要阶段:训练 和 编码。训练阶段的目标是从一个语料库中学习一个合并规则列表。
假设我们有以下小型语料库(单词后跟其频率):
low: 5, lower: 2, newest: 6, widest: 3步骤 1:初始化
首先,将每个单词分解成字符,并在末尾添加一个特殊的结束符 </w>(用来区分单词边界,例如区分 "st" 在中间和结尾的区别)。
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>}
步骤 2:迭代合并 重复以下过程,直到达到预定的合并次数或词汇表大小。
第一轮:统计所有相邻的字节对及其频率。
(l, o): 5+2=7 (o, w): 5+2=7 (w, </w>): 5 (w, e): 2 (e, r): 2 (r, </w>): 2 (n, e): 6 (e, w): 6 (e, s): 6+3=9 <-- 最高频率! (s, t): 6+3=9 (t, </w>): 6+3=9 (w, i): 3 (i, d): 3 (d, e): 3频率最高的字节对是
(e, s),出现 9 次。我们将其合并成一个新的符号es。 更新语料:l o w </w> : 5 l o w e r </w> : 2 n e w es t </w> : 6 # (e, s) 被合并为 es w i d es t </w> : 3 # (e, s) 被合并为 es合并规则记录:
合并 (e, s) -> es第二轮:再次统计当前语料中的字节对。
(l, o): 7 (o, w): 7 (w, </w>): 5 (w, e): 2 (e, r): 2 (r, </w>): 2 (n, e): 6 (e, w): 6 (es, t): 6+3=9 <-- 最高频率! (t, </w>): 9 (w, i): 3 (i, d): 3 (d, es): 3频率最高的是
(es, t),合并为est。 更新语料:l o w </w> : 5 l o w e r </w> : 2 n e w est </w> : 6 # (es, t) 被合并为 est w i d est </w> : 3 # (es, t) 被合并为 est合并规则记录:
合并 (es, t) -> est第三轮:继续统计。
(l, o): 7 (o, w): 7 <-- 最高频率! (w, </w>): 5 (w, e): 2 (e, r): 2 (r, </w>): 2 (n, e): 6 (e, w): 6 (est, </w>): 9 (w, i): 3 (i, d): 3 (d, est): 3频率最高的是
(o, w),合并为ow。 更新语料:l ow </w> : 5 l ow e r </w> : 2 n e w est </w> : 6 w i d est </w> : 3合并规则记录:
合并 (o, w) -> ow
最终结果: 经过几轮合并后,我们得到:
- 合并规则列表(按顺序):
e s -> eses t -> esto w -> ow… (可以继续合并)
- 最终的词汇表:基础字符 + 所有合并产生的新符号。
{l, o, w, e, r, n, s, t, i, d, </w>, es, est, ow}
这个合并规则列表和最终的词汇表就是 BPE 模型的训练成果。
3. BPE 的编码(应用阶段)#
现在,我们如何用训练好的 BPE 模型对一个新词进行分词?
假设新词是 "lowest",我们学到的合并规则是上面的列表。
- 初始化:将单词拆分为字符
l o w e s t </w>。 - 应用规则:按照训练时学到的顺序,尝试应用每一条合并规则。
- 查看规则1:
e s -> es。在l o w e s t </w>中,可以找到(e, s)对,所以合并:l o w es t </w>。 - 查看规则2:
es t -> est。在l o w es t </w>中,可以找到(es, t)对,所以合并:l o w est </w>。 - 查看规则3:
o w -> ow。在l o w est </w>中,可以找到(o, w)对,所以合并:l ow est </w>。 - 后续规则不再适用。
- 查看规则1:
- 得到最终分词结果:
["l", "ow", "est"]
这样,即使 "lowest" 没有出现在训练语料中,BPE 也能将其合理地分解为已知的子词单元。
4. 优点与缺点#
优点:
- 有效平衡词汇表大小和序列长度:比词级分词词汇表小,比字符级分词序列短。
- 强大的泛化能力:能够处理未见过的单词,通过将其分解为已知的子词。
- 能捕捉词法结构:自然地学习到词根、词缀等形态学单元(如
un-, -ing, -est)。
缺点:
- 对分割的贪婪性:合并是基于频率的,可能不是语言学上最合理的分割(例如,
"teacher"可能被分成teach和er,而不是teach和er)。 - 可能存在歧义:同一个单词在不同上下文中可能有不同的分词方式(尽管很少见)。
- 依赖训练语料:分词质量高度依赖于训练 BPE 所用的语料库。
5. 在当今 NLP 中的应用#
BPE 及其变体(如 WordPiece,SentencePiece)是当今几乎所有主流大型语言模型的基石。
- OpenAI 的 GPT 系列:使用 BPE。
- BERT:使用其变体 WordPiece。
- T5,RoBERTa:使用 SentencePiece(它是 BPE 的一种实现,可以直接在原始文本上运行,无需预分词)。
总结#
Byte-pair Encoding(BPE)是一种巧妙的数据压缩算法,被成功应用于 NLP 的子词分词。它通过迭代地合并最高频的相邻符号对,从一个基础字符集开始,逐步构建出一个包含常见子词单元的词汇表。这种方法在词汇量、序列长度和模型泛化能力之间取得了出色的平衡,使其成为现代 NLP 模型不可或缺的预处理组件。