导读:在自然语言处理(NLP)领域,分词是文本预处理中的一个关键步骤。分词的目的是将文本分解成有意义的单元,以便模型能够更好地理解和处理。传统的分词方法通常基于固定词汇表,如基于单词的分词。然而,这种方法在处理未知单词和稀有单词时存在局限性。为了解决这一问题,BPE算法应运而生。BPE算法是一种基于子词(subword)的分词方法,能够将单词分解成更小的子词单元,从而提高模型的泛化能力和灵活性。
1
算法原理
BPE(Byte Pair Encoding) 算法是一种基于频率的子词分割方法,其核心思想是将单词分解成更小的子词单元,这些子词单元可以是完整的单词、单词的前缀、后缀或中间部分。这种方法在处理未知单词和稀有单词时特别有效,因为它可以将这些单词分解成已知的子词单元,从而提高模型的泛化能力。
2
实现步骤
假设我们有一个训练语料 D,其中每个单词 w 由字符序列 w=c1,c2,…,cn组成。BPE 算法的目标是构建一个子词词汇表 V,使得每个单词 w 可以被分割成子词单元 w=v1,v2,…,vm,其中 vi∈V。
step 1 : 初始化词汇表
将所有字符(Unicode)作为初始词汇表的基本单元。

step 2 : 统计字符对频率
对训练语料中的每个单词,统计相邻字符对的出现频率。

step 3 : 合并最频繁字符对
将最频繁的字符对作为一个新单元加入词汇表,并更新训练语料中的分割方式。

其中,cici+1 是在 Vt 中最频繁的字符对。
step 4 : 更新训练语料

重复上述过程,直到词汇表大小达到预设值 ∣V ∣=K。
假设有一个简单的训练语料库,包含以下单词及其频率:
{'hug': 10, 'pug': 5, 'pun': 12, 'bun': 4, 'hugs': 5}
每次迭代的结果示例如下:

3
python实现
下面通过python代码实现上述示例:
from collections import defaultdict, Counter
def get_stats(vocab):
"""统计字符对的频率"""
pairs = defaultdict(int)
for word, freq in vocab.items():
symbols = word.split()
for i in range(len(symbols) - 1):
pairs[symbols[i], symbols[i+1]] += freq
return pairs
def merge_vocab(pair, vocab_in):
"""合并字符对并更新词汇表"""
vocab_out = {}
bigram = ' '.join(pair)
replacement = ''.join(pair)
for word in vocab_in:
w_out = word.replace(bigram, replacement)
vocab_out[w_out] = vocab_in[word]
return vocab_out
def bpe(vocab, num_merges):
"""执行 BPE 迭代"""
print("Initial vocab:")
print(vocab)
print("\n")
for i in range(num_merges):
pairs = get_stats(vocab)
if not pairs:
break
# 找到最频繁的字符对
best_pair = max(pairs, key=pairs.get)
print(f"Iteration {i+1}: Merging {best_pair} with frequency {pairs[best_pair]}")
# 合并字符对并更新词汇表
vocab = merge_vocab(best_pair, vocab)
print("Updated vocab:")
print(vocab)
print("\n")
return vocab
# 初始词汇表
vocab = {
'h u g': 10,
'p u g': 5,
'p u n': 12,
'b u n': 4,
'h u g s': 5
}
# 执行 BPE,假设进行 3 次合并
final_vocab = bpe(vocab, num_merges=3)得到结果如下:

4
优缺点
优势:通过数据驱动的方式有效平衡词汇表大小与未登录词问题。它能够将罕见词拆解为高频子词组合(如将“hugs”分解为“hug”和“s”),既压缩了词表规模,又提升了模型对未知词汇的泛化能力,尤其适用于形态丰富的语言或需要处理复合词的场景。无需依赖语言学规则的特点,在多语言任务中表现灵活,例如机器翻译中可统一处理不同语言的子词单元。
局限性:由于完全依赖统计频率,合并顺序的敏感性可能导致结果不稳定(如优先合并“u-g”而非“h-u”会生成不同子词),且生成的子词可能缺乏明确的语义解释性(如“ug”单独无意义)。此外,低频字符对的覆盖不足可能导致长尾词汇仍需以原子形式存在,而合并次数的设定依赖人工经验,需反复调参才能达到理想效果。
另外,BPE可以用于中文,但需要针对中文的语言特性进行适配。中文以汉字为基本单位,每个汉字本身具有独立语义,BPE可通过统计高频共现的汉字组合(如“中国”“北京”)生成子词,既能压缩词表规模(如从数万汉字减少到数千子词),又能解决未登录词问题(如将新词“元宇宙”拆解为“元”+“宇宙”)。然而,中文没有天然的空格分隔,BPE需以单字为起点逐步合并,可能产生无意义子词(如“的的”合并为冗余单元)或割裂语义连贯的固定搭配(如“巧克力”被拆为“巧”+“克力”)。实际应用中,BPE常与预分词技术结合,或通过限制子词长度、调整合并优先级来平衡效率与语义完整性,在机器翻译、预训练模型(如中文BERT)等场景中已得到有效验证。
参考文献:
1、Zouhar, V., Meister, C., Gastaldi, J. L., Du, L., Vieira, T., Sachan, M., & Cotterell, R. (2024). A Formal Perspective on Byte-Pair Encoding. arXiv preprint arXiv:2306.16837.
2、Lian, H., et al. (2024). Scaffold-BPE: Enhancing Byte Pair Encoding with Simple and Effective Scaffold Token Removal. arXiv preprint arXiv:2404.17808.
3、Sennrich, R., Haddow, B., & Birch, A. (2015). Neural Machine Translation of Rare Words with Subword Units. arXiv preprint arXiv:1508.07909.
后台回复“BPE”可免费获得上述论文和代码