token-BPE算法概述
现代大语言模型的分词基础
token-BPE算法概述
BPE算法概述
BPE(Byte Pair Encoding) 是一种数据压缩算法,后来被OpenAI等团队引入自然语言处理领域,用于构建子词(subword)词汇表。它是现代大语言模型(如GPT系列)分词器的核心基础。
核心思想
BPE的核心思想是:通过迭代合并频率最高的字符对,逐步构建出更长的子词单元。
核心优势:在字符级(粒度太细,序列过长)和词级(无法处理未登录词)之间找到平衡,有效处理:
- 罕见词/未登录词(OOV)
- 形态变化丰富的语言
- 拼写错误和变体
算法步骤详解
第一步:初始化
将训练语料中的每个单词拆分为字符序列,并在末尾添加特殊的词尾标记 </w>。
原始语料:
"low" × 5次, "lower" × 2次, "newest" × 6次, "widest" × 3次
初始化后:
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
"low" × 5次, "lower" × 2次, "newest" × 6次, "widest" × 3次
初始化后:
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): 7 (5+2)
(o, w): 7 (5+2)
(w, </w>): 5
(w, e): 2
(e, r): 2
(l, o): 7 (5+2)
(o, w): 7 (5+2)
(w, </w>): 5
(w, e): 2
(e, r): 2
第三步:合并最高频字符对
将频率最高的字符对合并为一个新符号,加入词汇表。
第1轮合并:(e, s) 出现 9 次 → 合并为 "es"
第2轮合并:(es, t) 出现 9 次 → 合并为 "est"
第3轮合并:(l, o) 出现 7 次 → 合并为 "lo"
第4轮合并:(lo, w) 出现 7 次 → 合并为 "low"
第2轮合并:(es, t) 出现 9 次 → 合并为 "est"
第3轮合并:(l, o) 出现 7 次 → 合并为 "lo"
第4轮合并:(lo, w) 出现 7 次 → 合并为 "low"
第四步:迭代直至满足停止条件
重复合并过程,直到:
- 达到预定的词汇表大小(如32,000、50,000)
- 或没有可合并的字符对
编码(分词)过程
训练完成后,对新文本进行分词时采用贪心最长匹配策略:
输入:"lowest"
尝试匹配词汇表中最长的子词:
1. 尝试 "lowest" → 不在词表
2. 尝试 "lowe" → 不在词表
3. 尝试 "low" → ✅ 在词表
4. 剩余 "est" → ✅ 在词表
最终分词结果:["low", "est"]
尝试匹配词汇表中最长的子词:
1. 尝试 "lowest" → 不在词表
2. 尝试 "lowe" → 不在词表
3. 尝试 "low" → ✅ 在词表
4. 剩余 "est" → ✅ 在词表
最终分词结果:["low", "est"]
BPE的变体与演进
| 算法 | 特点 | 代表应用 |
|---|---|---|
| 原始BPE | 贪心合并,基于频率 | GPT-2, RoBERTa |
| WordPiece | 基于似然增益而非频率 | BERT, DistilBERT |
| Unigram | 概率模型,从大到小剪枝 | T5, AlBERT |
| SentencePiece | 语言无关,直接处理原始文本 | XLNet, Marian NMT |
实际应用示例
以GPT-2的分词器为例:
import tiktoken
# GPT-2使用的BPE分词器
enc = tiktoken.get_encoding("gpt2")
text = "Tokenization is the process of breaking down text."
tokens = enc.encode(text)
print(f"文本: {text}")
print(f"Token数量: {len(tokens)}")
print(f"字符数量: {len(text)}")
print(f"压缩比: {len(text)/len(tokens):.2f}")
# GPT-2使用的BPE分词器
enc = tiktoken.get_encoding("gpt2")
text = "Tokenization is the process of breaking down text."
tokens = enc.encode(text)
print(f"文本: {text}")
print(f"Token数量: {len(tokens)}")
print(f"字符数量: {len(text)}")
print(f"压缩比: {len(text)/len(tokens):.2f}")
BPE的优缺点
| ✅ 优点 | ❌ 缺点 |
|---|---|
| 有效处理未登录词 | 对多语言支持不够均衡(英语token更短) |
| 词汇表大小可控 | 无法理解语义,纯统计方法 |
| 可复现、确定性强 | 对空格敏感,"hello"和" hello"是不同token |
| 平衡词级和字符级粒度 | 处理数字、代码时可能产生碎片化token |
总结
BPE算法通过迭代合并高频字符对,构建出高效的子词词汇表,解决了传统词级分词的OOV问题。它是现代大语言模型的基石技术之一,理解BPE有助于深入掌握Tokenizer的工作原理,以及为什么LLM在某些文本(如非英语、数字序列)上表现特殊。
← 返回 2. Pre-training