BPE 算法原理:高频子词合并的艺术
聊到 Tokenization,BPE(Byte Pair Encoding)是个绕不开的核心算法。
最早它是用来做数据压缩的——把常见字节对替换成一个新符号。后来被 NLP 大佬们捡起来,改造成了子词切分的利器。说实话,我第一次接触时也觉得挺神奇:一个压缩算法,怎么就成 NLP 标配了?
你想想看,核心思想其实就一句话:从最细的字符开始,反复合并出现频率最高的相邻对。直到词表大小满足要求,或者没有可合并的对为止。
为什么需要 BPE?
传统词表有俩硬伤:
- OOV(未登录词)问题:测试集里新词出现,词表直接崩了
- 词表太大:英语就有几十万词,存储和计算都不划算
BPE 的好处是——不管什么新词,都能拆成已知的子词。
我在项目中用过字符级模型。效果嘛……长序列训练实在太慢。BPE 刚好站在中间:比词细,比字符粗。
核心优势:BPE 在词表大小和序列长度之间找到一个平衡点。词表通常在 3w-5w,既能覆盖绝大部分常见词,又不会把句子拉得太长。
BPE 的完整流程
下面这张图,是我给学员讲 BPE 时必画的。它把整个流程串起来了:
手写一个 BPE 核心逻辑
别光看理论,我带你过一遍代码。这是我早期做分词器时写的精简版:
def bpe_corpus(corpus: list, vocab_size: int) -> dict:
# 1. 拆成字符级初始词表
vocab = {}
for word in corpus:
tokens = list(word) + ['</w>']
_str = ' '.join(tokens)
vocab[_str] = vocab.get(_str, 0) + 1
# 2. 迭代合并
current_vocab_size = len(set(' '.join(vocab.keys()).split()))
while current_vocab_size < vocab_size:
pairs = {}
for _str, freq in vocab.items():
tokens = _str.split()
for i in range(len(tokens)-1):
pair = (tokens[i], tokens[i+1])
pairs[pair] = pairs.get(pair, 0) + freq
if not pairs:
break
# 找到最高频对
best_pair = max(pairs, key=pairs.get)
# 合并
new_vocab = {}
for _str, freq in vocab.items():
new_ = _str.replace(' '.join(best_pair), ''.join(best_pair))
new_vocab[new_] = freq
vocab = new_vocab
current_vocab_size = len(set(' '.join(vocab.keys()).split()))
# 返回最终词表
final_vocab = set()
for _str in vocab:
final_vocab.update(_str.split())
return {: idx for idx, in enumerate(sorted(final_vocab))}
小技巧:我在实际项目中常用 tokenizers 库,比手写快得多。但理解这个流程很重要——很多坑都藏在细节里。
核心参数对比
做 BPE 时,有几个参数你得心里有数:
| 参数 | 作用 | 经验值 |
|---|---|---|
| 词表大小 | 最终子词数量 | 30k-50k(中英文通用) |
| 最小频率阈值 | 低于阈值的合并忽略 | 2(避免罕见情况浪费词表) |
| 特殊 | [UNK], [CLS], [SEP] 等 | 至少留 10 个位置 |
避坑指南:我曾经在词表里忘了加 </w> 这个结尾标记。结果模型分不清 "play" 和 "playing" 是否该合并——训练损失死活降不下去。折腾了两天才发现原因。
BPE 的优缺点
没有完美算法,BPE 也一样:
- 优点:词表可控、OOV 友好、实现简单
- 缺点:贪心策略,不一定全局最优。我在处理某些非粘着语(如中文)时,效果不如直接从词切起
到底什么时候用 BPE?
我个人经验:
- 英文或其他西方语言——BPE 是首选。比如 、BERT 都在用
- 代码或混合文本——BPE 对数字和特殊字符很友好
- 中文——部分场景可以用,但我更推荐 WordPiece 或 SentencePiece
你想想看,BPE 就像一把瑞士军刀。不是所有螺丝都能拧,但大部分场景都够用。理解它的合并逻辑,你再去学后续的 WordPiece 或 Unigram,会发现很多相似之处。