当前位置: 首页 > news >正文

NLP中Subword算法:WordPiece、BPE、BBPE、SentencePiece详解以及代码实现

本文将介绍以下内容:

  • 1. Subword与传统tokenization技术的对比
  • 2. WordPiece
  • 3. Byte Pair Encoding (BPE)
  • 4. Byte-level BPE(BBPE)
  • 5. SentencePiece 以及各Subword算法代码实现

一、Subword与传统tokenization技术的对比

1. 传统tokenization技术

传统tokenization技术一般有两种方法:word(词)粒度、char(字符)粒度

1.1 word(词)粒度

传统构造词表的方法,是先对各个句子进行分词,然后再统计并选出频数最高的前N个词组成词表。通常训练集中包含了大量的词汇,以英语为例,总的单词数量在17万到100万左右。对于英文来说,word级别分词实现很简单,因为本身就有分隔符号。在中文里面word粒度,需要使用一些分词工具比如jieba、ltp等。该方案优劣势如下:

  • 优点:

    • 语义明确: 以词为粒度进行分词可以更好地保留每个词的语义,使得文本在后续处理中能够更准确地表达含义。
    • 上下文理解: 以词为粒度进行分词有助于保留词语之间的关联性和上下文信息,从而在语义分析和理解时能够更好地捕捉句子的意图。
  • 缺点:

    • OOV(Out-of-Vocabulary): 分词模型只能够使用词表中的词进行处理,无法处理词表之外的词汇。
    • 长尾效应和稀有词问题: 词表可能变的巨大,包含很多不常见的词汇,增加存储和训练成本,稀有词的训练数据有限,无法得到充分训练,进而模型不能充分理解这些词的语义。
    • 形态关系和词缀关系: 无法捕捉同一词的不同形态,也无法学习词缀在不同词汇之间的共通性,限制了模型的语言理解能力。比如look和looks在词表中将会是两个词。一方面增加了训练冗余,另一方面也造成了大词汇量问题。
1.2 char(字符)粒度

以字符为单位进行分词,就是把文本拆分成一个个单独的字符作为最小的基本单元,这种对多种语言都比较适用,比如英文、中文、印尼语等。英文就是26个字母以及其他的一些符号,中文常见、次常用字大约共有 6000多个。该方案优劣势如下:

  • 优点:
    • 通用性: 字符粒度的分词方法使用与不同的语言,不需要设计不同的规则和工具。
    • 避免OOV问题: 这种粒度的分词能够处理任何字符,无需维护词表,因此可以很好地处理一些新的词汇、专有名词等。
  • 缺点:
    • 语义信息不明确: 这种粒度的分词无法直接表达词的语义,可能在一些语义分析任务中效果比较差。
    • 效率极低: 由于文本被拆分成字符,处理粒度较小,增加了后续处理的计算成本和时间。
2. Subword(子词)粒度

目前有三种主流的Subword算法,它们分别是:Byte Pair Encoding (BPE), WordPiece和Unigram Language Model。

针对上述问题,Subword(子词)模型方法横空出世。它的划分粒度介于词与字符之间,比如可以将”looking”划分为”look”和”ing”两个子词,而划分出来的"look",”ing”又能够用来构造其它词,如"look"和"ed"子词可组成单词"looked",因而Subword方法能够大大降低词典的大小,同时对相近词能更好地处理。

接下来将分别详细介绍:WordPiece、BPE、BBPE、ULM。

二、WordPiece

请见笔者之前文章:NLP Subword 之 WordPiece 算法原理

三、Byte Pair Encoding (BPE)

请见笔者之前文章:NLP Subword 之 BPE(Byte Pair Encoding) 算法原理

四、Byte-level BPE(BBPE)

请见笔者之前文章:NLP Subword 之 BBPE(Byte-level BPE) 算法原理

五、SentencePiece 以及各Subword算法代码实现

1. 什么是 SentencePiece?

在自然语言处理(NLP)中,分词(tokenization) 是一个极为关键的步骤。传统的分词方法往往依赖语言特定的规则(比如英文依靠空格,中文依靠分词工具),而在多语言任务或需要统一处理的场景下,这种方式就显得繁琐且不够通用。

SentencePiece 是 Google 开源的一个 语言无关(language-agnostic)子词建模工具。它的“工具属性”主要体现在:

  • 端到端训练:直接基于原始语料,无需预分词或去掉空格,输出模型文件(.model)和词表(.vocab)。
  • 多算法统一接口:同一套命令/接口支持 Unigram(ULM)、BPE、Char、Word 等模型类型。
  • 推理一致性:同一模型可用于编码(encode)与解码(decode),避免预处理不一致的问题。
  • OOV 友好:支持 --byte_fallback,可以在词表未登录时回退为字节级 token,实现 Byte-level BPE(BBPE) 的效果。

需要特别说明的是:

  • SentencePiece 并没有直接提供 WordPiece 类型
  • 在实践中,通常使用 Unigram 模型近似/替代 WordPiece

2. 使用 Python SentencePiece 库分别实现 ULM、BPE、BBPE

下面通过 3 个独立的 Demo,完整展示 训练 + 推理 全流程。每个 Demo 都会:

  1. 生成一份 demo 语料;
  2. 调用 sentencepiece 训练模型;
  3. 加载模型进行推理(encode/decode);

2.1 Unigram Language Model(ULM)

Unigram 是 SentencePiece 默认与推荐的算法之一,常作为 WordPiece 的替代实现

# demo_ulm.py
import os
import sentencepiece as spm# 0) 准备语料
workdir = "./sp_ulm_work"
os.makedirs(workdir, exist_ok=True)
corpus = os.path.join(workdir, "corpus.txt")lines = ["我爱自然语言处理。","自然语言处理是人工智能的重要分支。","Hello world! This is a tiny corpus for subword training.","Emoji 测试:🙂🚀🌍,以及混合文本 NLP。",
]
with open(corpus, "w", encoding="utf-8") as f:f.write("\n".join(lines))# 1) 训练 Unigram 模型
model_prefix = os.path.join(workdir, "uni")
spm.SentencePieceTrainer.Train(input=corpus,model_prefix=model_prefix,vocab_size=800,          # demo 用小词表model_type="unigram",    # ★ 关键:Unigramcharacter_coverage=1.0
)# 2) 推理
sp = spm.SentencePieceProcessor(model_file=f"{model_prefix}.model")
test_text = "我爱NLP🚀!"
pieces = sp.encode(test_text, out_type=str)
ids = sp.encode(test_text, out_type=int)
back = sp.decode(ids)print("INPUT :", test_text)
print("PIECES:", pieces)
print("IDS   :", ids)
print("DECODE:", back)

2.2 Byte Pair Encoding(BPE)

BPE 是另一种常见的子词算法,原理是迭代合并语料中频率最高的相邻 token 对。

# demo_bpe.py
import os
import sentencepiece as spm# 0) 准备语料
workdir = "./sp_bpe_work"
os.makedirs(workdir, exist_ok=True)
corpus = os.path.join(workdir, "corpus.txt")lines = ["BPE merges rules are learned from frequent pairs.","Hello world! Byte Pair Encoding is simple and effective.","中文测试:分词、子词建模。",
]
with open(corpus, "w", encoding="utf-8") as f:f.write("\n".join(lines))# 1) 训练 BPE 模型
model_prefix = os.path.join(workdir, "bpe")
spm.SentencePieceTrainer.Train(input=corpus,model_prefix=model_prefix,vocab_size=800,model_type="bpe",        # ★ 关键:BPEcharacter_coverage=1.0
)# 2) 推理
sp = spm.SentencePieceProcessor(model_file=f"{model_prefix}.model")
test_text = "BPE 的分词效果如何?😊"
pieces = sp.encode(test_text, out_type=str)
ids = sp.encode(test_text, out_type=int)
back = sp.decode(ids)print("INPUT :", test_text)
print("PIECES:", pieces)
print("IDS   :", ids)
print("DECODE:", back)

2.3 Byte-level BPE(BBPE)

BBPE 的核心思想是 在 BPE 上增加字节级回退(byte fallback),保证任何输入都能被编码。

# demo_bbpe.py
import os
import sentencepiece as spm# 0) 准备语料
workdir = "./sp_bbpe_work"
os.makedirs(workdir, exist_ok=True)
corpus = os.path.join(workdir, "corpus.txt")lines = ["Byte-level BPE ensures any input is representable.","Emoji 测试:🙂🚀🌍。","混合语言测试:NLP 和 数据。",
]
with open(corpus, "w", encoding="utf-8") as f:f.write("\n".join(lines))# 1) 训练 BBPE 模型(本质是 BPE + byte_fallback)
model_prefix = os.path.join(workdir, "bbpe")
spm.SentencePieceTrainer.Train(input=corpus,model_prefix=model_prefix,vocab_size=800,model_type="bpe",          # 仍然是 BPEcharacter_coverage=1.0,byte_fallback=True         # ★ 关键:开启字节回退
)# 2) 推理
sp = spm.SentencePieceProcessor(model_file=f"{model_prefix}.model")
test_text = "未登录字符𝔘𝔫𝔦𝔠𝔬𝔡𝔢😊"
pieces = sp.encode(test_text, out_type=str)
ids = sp.encode(test_text, out_type=int)
back = sp.decode(ids)print("INPUT :", test_text)
print("PIECES:", pieces)
print("IDS   :", ids)
print("DECODE:", back)

3. 小结
  1. SentencePiece 是一个通用的子词建模工具,它屏蔽了语言差异,让我们直接在原始语料上训练子词模型。
  2. 它支持 Unigram(ULM)、BPE、Char、Word 等模型类型,但 没有直接的 WordPiece;通常用 Unigram 来近似/替代 WordPiece。
  3. 通过 byte_fallback 参数,SentencePiece 可以在 BPE 模型上实现 BBPE 的能力,从而覆盖任意输入字符(如 emoji、稀有符号)。

文章转载自:

http://7dtDsE8j.rntby.cn
http://Te1BIIYv.rntby.cn
http://2KVGSOLJ.rntby.cn
http://rPjSJSLz.rntby.cn
http://t07DhvyE.rntby.cn
http://3bLs4Rpk.rntby.cn
http://wGYBSEC5.rntby.cn
http://DRxl32Ab.rntby.cn
http://ln8A02cy.rntby.cn
http://xLR4sfQ3.rntby.cn
http://mLz1bs9L.rntby.cn
http://ReMjM8FG.rntby.cn
http://FSwGXOIF.rntby.cn
http://x1ngylvo.rntby.cn
http://KyhTyCkD.rntby.cn
http://ybFM3Rid.rntby.cn
http://7vjeF7pv.rntby.cn
http://5shWA6Z2.rntby.cn
http://yRJHvSp0.rntby.cn
http://XQsCO6FA.rntby.cn
http://Rk26fn8n.rntby.cn
http://x4TvOPV2.rntby.cn
http://jmBg7UWt.rntby.cn
http://50NRp8FB.rntby.cn
http://DxGYFPad.rntby.cn
http://IgJNaWHl.rntby.cn
http://fkdiSmJq.rntby.cn
http://d8NVuV8q.rntby.cn
http://qGnqW7eg.rntby.cn
http://O2dlwhmJ.rntby.cn
http://www.dtcms.com/a/387772.html

相关文章:

  • 解决Dify部署痛点:Docker镜像源优化配置指南
  • 达梦数据库模式
  • Pytorch笔记
  • SQL 数值函数速查:ROUND、CEIL、FLOOR、MOD 怎么用?
  • GPT-5-Codex 正式发布:迈向真正的“自主编程”时代
  • 直播美颜灯MCU控制方案开发设计分享
  • 数据结构(C语言篇):(十六)插入排序
  • 点亮第一个LED灯
  • Python环境》开发环境搭建
  • 【猛犸AI科技】无人机UAV边缘计算MEC实验
  • 【Datawhale25年9月组队学习:llm-preview+Task1:大模型介绍与环境配置】
  • 【MySQL】体系结构
  • Gated Attention 论文阅读
  • Git 命令行教程:配置 SSH 密钥高效克隆与管理项目
  • 机器学习和数据科学的开源 Python 库-Streamlit
  • Roo Code 的Enhance Prompt「增强提示」功能详解
  • 检测IP是否正常的方法
  • JMeter线程组
  • Flink基于Paimon的实时湖仓解决方案的演进
  • 29、生成模型入门-从数据重构到智能创造
  • Dokcer的安装(ubuntu-20.04.6):
  • 梳理Axios请求的过程和 Vite 代理配置
  • 元宇宙与电竞产业:沉浸式交互重构电竞全链条生态
  • 【pycharm】index-tts2:之二 :ubuntu24.04重建UV虚拟环境
  • 点评项目(Redis中间件)数据操作相关知识总结
  • 从0死磕全栈第九天:Trae AI IDE一把梭,使用react-query快速打通前后端接口调试
  • 【论文阅读】MIDAS: 多模态交互式数字人合成,通过实时自回归视频生成
  • 为什么React Native 中点到了却不动
  • 学习React-13-useLayoutEffect
  • Redis-更新策略