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://www.pswp.cn/pingmian/97912.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/97912.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

十一章 无界面压测

一、采用无界面压测的原因1.节约系统资源。 2.更快捷,只需要启动命令即可进行压测 3.主要是用于性能压测集成.无界面压测命令参数: -n 表示无界面压测 -t 制定你的 jmx 脚本 -l 生成 jtl 测试报告二、注意配置文件设置:输出为xml jmeter.save.s…

从零实现 Qiankun 微前端:基座应用控制子应用路由与信息交互

随着前端业务的快速发展,单体应用模式(Monolith)越来越难以支撑复杂业务场景。微前端(Micro Frontends)应运而生,它将大型应用拆解成多个子应用(Micro App),通过主应用进行统一调度和集成。 在微前端技术栈中,Qiankun(乾坤)是一个广泛使用的解决方案,基于 single…

在业务应用中集成 go-commons,实现应用+系统双指标监控

在日常 Go 服务开发中,我们通常需要同时监控 业务指标(比如 QPS、请求延迟、错误率),也需要关注 系统指标(CPU、内存、磁盘占用情况)。 过去这类场景通常要引入多个库:一个负责业务指标采集&…

容器化部署番外篇之docker网络通信06

一、四种网络模式 Bridge模式:容器的默认网关,默认新建容器的网络模式Host模式:容器和宿主机共用一个 Network,使用主机的IP:PORT就可以访问容器,但安全性不高,用得少Container模式:这个模式指定…

Linux 线程的概念

序言: 在这篇博客中我们将讲解线程的概念,如何理解线程,线程和进程的区别,线程的优缺点等,我相信你看完这篇博客后会以别样的视角重新理解线程,下面的内容全部是基于Linux操作系统的。 一、线程的概念 1…

vscode 中通义灵码显示登录过期

本文主要分享:vscode 中通义灵码显示登录过期的解决办法。vscode 中的小插件通义灵码,用的好好的,突然提示:登录过期,尝试访问网页版阿里云,登录后,关闭 vscode 重新打开,通义灵码还…

ESP32C3-MINI-1开发板踩坑记录

某东买了一个ESP32C3-MINI-1开发板,名字跟ESP官网的很像,想着应该差不多的,价格便宜17块,而官网的就贵了60还不包邮,买来才发现是巨坑。 看结论,直接到最后,前面都是我的踩坑过程。第一块板子发…

基于粒子群算法的山地环境无人机最短路径规划研究(含危险区域约束的三维优化方法)

无人机在复杂地形与危险环境中的自主路径规划是保障任务顺利执行的关键问题。本文针对山地环境下单无人机三维路径规划难题,提出了一种基于粒子群算法(PSO)的优化方法。首先,建立了包含真实地形高程、危险区域和飞行约束条件的三维…

Linux-> UDP 编程2

目录 本文说明 一:字典程序的几个问题 1:字典的本质 2:翻译功能的本质 3:让服务端和翻译功能相关联 二:字典类(Dict.hpp) 1:加载词典(Load) 2:翻译单词(Translate) 三:服务…

辉视养老方案:重塑老年生活的温馨与安心

在当今社会,随着老龄化进程的加速,如何为老年人提供更加便捷、舒适且安全的养老环境,成为了全社会共同关注的焦点。辉视养老方案应运而生,它以科技为翼,以关爱为心,通过远程探望、客控系统、信息服务、IPTV…

SQuAD:机器阅读理解领域的里程碑数据集

本文由「大千AI助手」原创发布,专注用真话讲AI,回归技术本质。拒绝神话或妖魔化。搜索「大千AI助手」关注我,一起撕掉过度包装,学习真实的AI技术! 1 什么是SQuAD? SQuAD(Stanford Question Ans…

【vim,Svelte】怎样使用 vim 编辑 Svelte 那些奇奇怪怪名字的文件?

当你要使用 vim(或者neovim)来编辑 Svelte 下面的文件时,比如这些文件: page.svelte layout.svelte$ vim page.svelte $ vim "page.svelte" $ vim page.svelte $ vim \page.svelte使用上面的命令,你会遇到这…

深入解析 HTTP 状态码

在日常的网络浏览和 Web 开发过程中,我们总会不可避免地遇到各种 HTTP 状态码。比如常见的 “404 Not Found”,它意味着我们所请求的页面不存在;还有 “500 Internal Server Error”,表示服务器端出现了错误。这些由三位数字组成的…

【C++】C++类和对象—(中)

前言:在上一篇类和对象(上)的文章中我们已经带领大家认识了类的概念,定义以及对类和对象的一些基本操作,接下来我们要逐步进入到类和对象(中)的学习。我们将逐步的介绍类和对象的核心——类和对象的六个默认成员函数。(注意:这六个…

使用python-fastApi框架开发一个学校宿舍管理系统-前后端分离项目

今天给大家分享一个我最近做的一个学校宿舍管理系统,python版,这个系统实现的功能有:首页 | 学校管理 | 宿舍楼管理 | 宿舍管理 | 学生管理 | 学生调宿 | 学生退宿 | 报修等级 | 宿舍卫生评分 | 违纪记录 | 管理员管理 。一共有11个菜单。 使…

阻塞 vs 非阻塞:程序等待的两种哲学

当程序需要等待外部操作时,是应该"干等"还是"边等边干"?为什么有些程序会卡住不动,而另一些却能流畅运行?这一切都取决于阻塞与非阻塞的编程选择!本文将为你揭示这两种模式的本质区别!…

MySQL 核心操作全解析(用户 + SHOW+DML+DCL)

MySQL 核心操作全解析(用户 SHOWDMLDCL) 基于你提供的实操笔记,我们将 MySQL 核心操作拆解为用户管理、SHOW 查询命令、DML 数据操作、TRUNCATE 与 DELETE 对比、DCL 权限控制五大模块,梳理语法逻辑、补充避坑提示,帮…

多语言编码Agent解决方案(6)-部署和使用指南

部署和使用指南 本指南提供完整的部署和使用说明,帮助您设置后端服务并在VSCode、Eclipse和IntelliJ中使用相应的插件。这个解决方案基于vLLM提供AI编码辅助,支持英语、中文和日文。 前提条件 操作系统:Linux、macOS或Windows(推荐…

滤波器的三重境界:从信号处理到自动驾驶测试的基石

在自动驾驶的宏大叙事中,我们常常聚焦于人工智能、深度学习、高精地图等"明星技术"。然而,在这些耀眼的光环背后,有一个低调却至关重要的"幕后英雄"——滤波器。它不仅是信号处理的工具,更是连接物理世界与数…

Part4.第8章:神经网络

第8章 激活函数 如果没有激活函数,不论几层的神经网络都是一个线性回归。激活函数的作用是引入非线性。