BPE 子词分词算法

This article is extracted from the chat log with AI. Please identify it with caution.

我们来详细介绍一下 Byte-pair Encoding(BPE),这是一种在自然语言处理(NLP)领域非常流行且重要的子词分词算法。

1. 核心思想:解决什么问题的?#

在 NLP 任务中,我们需要将文本转换成模型能够理解的数字,即“分词”。传统方法主要有两种:

  1. 词级分词:将句子分成独立的单词。
    • 问题
      • 词汇表爆炸:词汇表可能会变得非常庞大(例如几十万甚至上百万词),尤其是对于有丰富形态变化的语言(如德语、土耳其语)。
      • 无法处理未知词:对于训练时没见过的词(OOV问题),模型会将其标记为 <UNK>,导致信息丢失。
  2. 字符级分词:将句子分成单个字符。
    • 问题
      • 序列过长:一个句子会被分成非常长的序列,大大增加了模型的计算负担。
      • 难以捕捉语义:单个字符本身几乎不携带任何语义信息,模型需要从零开始学习组合,难度很大。

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

最终结果: 经过几轮合并后,我们得到:

  • 合并规则列表(按顺序)
    1. e s -> es
    2. es t -> est
    3. o w -> ow … (可以继续合并)
  • 最终的词汇表:基础字符 + 所有合并产生的新符号。 {l, o, w, e, r, n, s, t, i, d, </w>, es, est, ow}

这个合并规则列表最终的词汇表就是 BPE 模型的训练成果。


3. BPE 的编码(应用阶段)#

现在,我们如何用训练好的 BPE 模型对一个新词进行分词?

假设新词是 "lowest",我们学到的合并规则是上面的列表。

  1. 初始化:将单词拆分为字符 l o w e s t </w>
  2. 应用规则:按照训练时学到的顺序,尝试应用每一条合并规则。
    • 查看规则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>
    • 后续规则不再适用。
  3. 得到最终分词结果["l", "ow", "est"]

这样,即使 "lowest" 没有出现在训练语料中,BPE 也能将其合理地分解为已知的子词单元。


4. 优点与缺点#

优点:

  • 有效平衡词汇表大小和序列长度:比词级分词词汇表小,比字符级分词序列短。
  • 强大的泛化能力:能够处理未见过的单词,通过将其分解为已知的子词。
  • 能捕捉词法结构:自然地学习到词根、词缀等形态学单元(如 un-, -ing, -est)。

缺点:

  • 对分割的贪婪性:合并是基于频率的,可能不是语言学上最合理的分割(例如,"teacher" 可能被分成 teacher,而不是 teacher)。
  • 可能存在歧义:同一个单词在不同上下文中可能有不同的分词方式(尽管很少见)。
  • 依赖训练语料:分词质量高度依赖于训练 BPE 所用的语料库。

5. 在当今 NLP 中的应用#

BPE 及其变体(如 WordPiece,SentencePiece)是当今几乎所有主流大型语言模型的基石。

  • OpenAI 的 GPT 系列:使用 BPE。
  • BERT:使用其变体 WordPiece。
  • T5,RoBERTa:使用 SentencePiece(它是 BPE 的一种实现,可以直接在原始文本上运行,无需预分词)。

总结#

Byte-pair Encoding(BPE)是一种巧妙的数据压缩算法,被成功应用于 NLP 的子词分词。它通过迭代地合并最高频的相邻符号对,从一个基础字符集开始,逐步构建出一个包含常见子词单元的词汇表。这种方法在词汇量、序列长度和模型泛化能力之间取得了出色的平衡,使其成为现代 NLP 模型不可或缺的预处理组件。

本文共 2213 字,创建于 Oct 22, 2025

相关标签: ByAI, LLM, Algorithms, NLP, Tokenizer, 机器学习