本文由「大千AI助手」原创发布,专注用真话讲AI,回归技术本质。拒绝神话或妖魔化。搜索「大千AI助手」关注我,一起撕掉过度包装,学习真实的AI技术!
BPE(Byte Pair Encoding)是一种基于统计的子词分词算法 ,最初由Philip Gage于1994年提出用于数据压缩。2015年,Sennrich等人将其引入自然语言处理领域,解决传统分词方法的OOV问题并优化词汇表大小。如今BPE已成为GPT系列、BERT等主流预训练模型的标配分词方案。
1. 背景与动机
1.1 传统分词方法的局限性
传统NLP分词主要存在三种方案:
- 词级分词:词汇表过大,OOV问题严重
- 字符级分词:序列过长,语义单元破碎
- BPE折中方案:在词汇表大小与语义完整性间取得平衡
1.2 BPE的核心优势
BPE通过迭代合并高频字符对构建子词单元,使模型能够:
- 处理未见词和罕见词 📝
- 学习词缀关系(如"old"/"older"/"oldest")
- 控制词汇表大小,提升训练效率 ⚡
本文由「大千AI助手」原创发布,专注用真话讲AI,回归技术本质。拒绝神话或妖魔化。搜索「大千AI助手」关注我,一起撕掉过度包装,学习真实的AI技术!
往期文章推荐:
- 20.LayerNorm(层归一化)详解:原理、实现与应用
- 19.MinHashLSH 详解:高维数据相似性搜索与去重的关键技术
- 18.Jaccard相似度:集合相似性的经典度量
- 17.HOSVD(高阶奇异值分解):高维数据的"解剖术"
- 16.分布式奇异值分解(SVD)详解
- 15.LSA(潜在语义分析):原理、实现与应用
- 14.Netflix Prize竞赛:推荐系统的里程碑与机器学习革命的催化剂
- 13.雅可比SVD算法:高精度矩阵分解的经典方法
- 12.随机SVD:大规模矩阵分解的高效算法
- 11.QR算法:矩阵特征值计算的基石
- 10.Householder变换:线性代数中的镜像反射器
- 9.Frobenius范数:矩阵分析的万能度量尺
- 8.截断奇异值分解(Truncated SVD)详解:原理、应用与Python实践
- 7.线性代数中的特征向量:矩阵的"DNA方向"
- 6.奇异值分解(SVD):数据科学的"瑞士军刀"
- 5.CLIP模型全解析:从对比学习到零样本识别的革命
- 4.XLM-R模型:大规模跨语言表示的突破与实践
- 3.GELU(高斯误差线性单元)激活函数全面解析
- 2.神经网络中的随机高斯初始化技术
- 1.Metropolis接受准则:随机模拟与优化中的关键基石
2. BPE算法原理
2.1 基本概念
BPE的核心思想是:从字符开始,逐步合并最高频的相邻符号对,形成更有意义的子词单元。
2.2 算法步骤
- 预处理 :将单词拆分为字符序列,添加终止符
</w> - 统计频率:计算所有相邻符号对的出现频率 📊
- 迭代合并:重复合并最高频符号对,直到达到目标词汇表大小
- 生成词表:最终得到包含字符、子词和完整词的混合词汇表
2.3 终止符的重要性
终止符</w>用于区分词中子词与词尾子词。例如:
"st"无终止符:可出现在词首("st ar")"st</w>"有终止符:仅出现在词尾("wide st</w>")
3. BPE算法实现
3.1 Python实现示例
python
import re
import collections
def get_stats(vocab):
"""统计相邻符号对频率"""
pairs = collections.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, v_in):
"""合并指定符号对"""
v_out = {}
bigram = re.escape(' '.join(pair))
# 只匹配完整的符号对(前后无其他字符)
p = re.compile(r'(?<!\S)' + bigram + r'(?!\S)')
for word in v_in:
w_out = p.sub(''.join(pair), word)
v_out[w_out] = v_in[word]
return v_out
# 初始化词汇表
vocab = {
'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
}
print("初始词汇表:", vocab)
# 执行5次合并
num_merges = 5
for i in range(num_merges):
pairs = get_stats(vocab)
if not pairs:
break
best = max(pairs, key=pairs.get)
vocab = merge_vocab(best, vocab)
print(f'迭代 {i+1}: 合并 {best} -> {"".join(best)}')
print(f'更新后: {list(vocab.keys())}')
3.2 编码与解码
- 编码:将单词匹配为词表中的最长可能子词
- 解码 :简单拼接所有子词,将
</w>替换为空格
4. BPE在NLP中的应用
4.1 主流模型中的BPE
- OpenAI GPT系列:直接采用BPE分词
- Facebook RoBERTa:基于BPE改进
- BERT:使用BPE变体WordPiece
4.2 解决OOV问题示例
对于单词"unhappiness",BPE可能分词为:
"un", "happi", "ness"
即使模型未见过完整单词,也能通过子词理解其含义。
5. BPE变体与改进
5.1 WordPiece算法
- 核心改进:基于最大似然增益而非频率进行合并
- 应用:BERT、ALBERT等模型采用
5.2 SentencePiece
- 核心改进:将空格视为普通字符,支持无空格语言
- 优势:适用于中文、日文等语言 📝
5.3 BPE-Dropout
- 核心改进:训练时随机跳过部分合并,增强模型鲁棒性
- 效果:提供正则化,改善泛化能力
6. 优缺点分析
✅ 优点
- 平衡词汇表:避免词级分词的OOV问题和字符级分词的序列过长问题
- 多语言支持:字符级初始化使其适用于各种语言 🌍
- 语义捕捉:能够学习词缀关系和形态变化
❌ 缺点
- 数据依赖:分词质量高度依赖训练语料
- 贪婪合并:可能产生非最优分词结果
- 固定词表:无法动态适应新领域词汇
7. 总结与展望
BPE作为子词分词的基础算法,通过简单的合并策略解决了NLP中的关键挑战。随着大语言模型的发展,BPE及其变体将继续在以下方向演进:
- 动态词汇表:适应不断变化的语言使用
- 多模态扩展:处理代码、数学公式等非自然语言数据
- 效率优化:加速大规模语料的分词过程
本文由「大千AI助手」原创发布,专注用真话讲AI,回归技术本质。拒绝神话或妖魔化。搜索「大千AI助手」关注我,一起撕掉过度包装,学习真实的AI技术!