OA0
OA0 是一个探索 AI 的社区
现在注册
已注册用户请  登录
OA0  ›  代码  ›  SentencePiece — 常用的子词分词器训练与编码工具

SentencePiece — 常用的子词分词器训练与编码工具

 
  hub ·  2026-04-25 11:00:24 · 10 次点击  · 0 条评论  

SentencePiece

Build C++
Build Wheels
GitHub Issues
PyPI - Python Version
PyPI version
PyPi downloads
Contributions welcome
License
SLSA 3

SentencePiece 是一种无监督的文本分词器和去分词器,主要用于基于神经网络的文本生成系统,在模型训练前需预先确定词汇量大小。SentencePiece 实现了子词单元(例如 byte-pair-encoding (BPE) [Sennrich 等人])和 unigram 语言模型 [Kudo]),并支持直接从原始句子进行训练。SentencePiece 使我们能够构建一个完全端到端的系统,无需依赖特定语言的前处理/后处理。

这不是 Google 的官方产品。

技术亮点

  • 纯粹数据驱动:SentencePiece 从句子中训练分词和去分词模型。不一定需要预分词(例如 Moses tokenizer / MeCab / KyTea)。
  • 语言无关:SentencePiece 将句子视为 Unicode 字符序列,没有任何语言相关的逻辑。
  • 多种子词算法:支持 BPE [Sennrich 等人] 和 unigram 语言模型 [Kudo]。
  • 子词正则化:SentencePiece 实现了子词采样,用于子词正则化BPE-dropout,有助于提高 NMT 模型的鲁棒性和准确性。
  • 快速且轻量:分割速度约每秒 5 万个句子,内存占用约 6MB。
  • 自包含:只要使用相同的模型文件,就能获得相同的分词/去分词结果。
  • 直接生成词汇 ID:SentencePiece 管理词汇到 ID 的映射,可以直接从原始句子生成词汇 ID 序列。
  • 基于 NFKC 的规范化:SentencePiece 执行基于 NFKC 的文本规范化。

对于不熟悉 SentencePiece (作为软件/算法)的读者,可以阅读这篇温和的介绍

与其他实现的比较

特性 SentencePiece subword-nmt WordPiece
支持的算法 BPE, unigram, char, word BPE BPE*
开源? Google 内部
子词正则化
Python 库 (pip) N/A
C++ 库 N/A
需要预分割?
可自定义的规范化 (例如 NFKC) N/A
直接生成 ID N/A

注意:WordPiece 中使用的 BPE 算法与原始 BPE 略有不同。

概述

什么是 SentencePiece?

SentencePiece 是子词单元的一种重实现,是缓解神经机器翻译中开放词汇问题的有效方法。SentencePiece 支持两种分割方式:byte-pair-encoding (BPE) [Sennrich 等人] 和 unigram 语言模型 [Kudo]。以下是与其他实现的主要区别。

预先确定唯一标记的数量

神经机器翻译模型通常使用固定词汇量进行操作。与大多数假设无限词汇的无监督词分割算法不同,SentencePiece 训练分割模型,使得最终词汇量大小固定,例如 8k、16k 或 32k。

请注意,SentencePiece 为训练指定了最终词汇量大小,这与 subword-nmt 不同,后者使用的是合并操作的次数。合并操作的次数是 BPE 特有的参数,不适用于其他分割算法,包括 unigram、word 和 char。

从原始句子训练

以前的子词实现假设输入句子是预先分词的。这种约束对于高效训练是必需的,但使得前处理变得复杂,因为我们必须提前运行依赖语言的分词器。SentencePiece 的实现足够快,可以从原始句子训练模型。这对于训练中文和日语(词之间没有明确空格)的分词器和去分词器非常有用。

将空格视为基本符号

自然语言处理的第一步是文本分词。例如,一个标准的英语分词器会将文本 "Hello world." 分割成以下三个标记:

[Hello] [World] [.]

一个观察结果是,原始输入和分词后的序列不是可逆的。例如,"World" 和 "." 之间没有空格的信息会从分词序列中丢失,例如, Tokenize(“World.”) == Tokenize(“World .”)

SentencePiece 将输入文本仅视为 Unicode 字符序列。空格也被视为一个普通符号。为了明确地将空格作为基本标记处理,SentencePiece 首先用一个元符号 "▁" (U+2581) 转义空格,如下所示:

Hello▁World.

然后,将此文本分割成小块,例如:

[Hello] [▁Wor] [ld] [.]

由于空格在分割后的文本中得以保留,我们可以无歧义地还原文本。

  detokenized = ''.join(pieces).replace('▁', ' ')

此功能使得在不依赖语言特定资源的情况下执行去分词成为可能。

请注意,在使用标准词分割器分割句子时,我们无法应用相同的无损转换,因为它们将空格视为特殊符号。分词后的序列不保留恢复原始句子所需的信息。

  • (en) Hello world. → [Hello] [World] [.] (Hello 和 World 之间有一个空格)
  • (ja) こんにちは世界. → [こんにちは] [世界] [。] (こんにちは 和 世界 之间没有空格)

子词正则化和 BPE-dropout

子词正则化 [Kudo] 和 BPE-dropout Provilkov 等人 是简单的正则化方法,通过动态子词采样来虚拟地增强训练数据,有助于提高 NMT 模型的准确性和鲁棒性。

要启用子词正则化,您需要将 SentencePiece 库(C++ / Python)集成到 NMT 系统中,以便每次参数更新时采样一个分割,这与标准的离线数据准备不同。以下是 Python 库 的示例。您会发现 'New York' 在每次 SampleEncode (C++)encode with enable_sampling=True (Python) 调用中都被不同地分割。采样参数的详细信息见 sentencepiece_processor.h

>>> import sentencepiece as spm
>>> s = spm.SentencePieceProcessor(model_file='spm.model')
>>> for n in range(5):
...     s.encode('New York', out_type=str, enable_sampling=True, alpha=0.1, nbest_size=-1)
...
['▁', 'N', 'e', 'w', '▁York']
['▁', 'New', '▁York']
['▁', 'New', '▁Y', 'o', 'r', 'k']
['▁', 'New', '▁York']
['▁', 'New', '▁York']

安装

Python 模块

SentencePiece 提供 Python 封装,支持 SentencePiece 训练和分割。
您可以使用以下命令安装 SentencePiece 的 Python 二进制包:

pip install sentencepiece

更多详情,请参见 Python 模块

从 C++ 源码构建并安装 SentencePiece 命令行工具

构建 SentencePiece 需要以下工具和库:

  • cmake
  • C++11 编译器
  • gperftools 库(可选,可获得 10-40% 的性能提升)

在 Ubuntu 上,可以使用 apt-get 安装构建工具:

% sudo apt-get install cmake build-essential pkg-config libgoogle-perftools-dev

然后,您可以按如下方式构建和安装命令行工具:

% git clone https://github.com/google/sentencepiece.git
% cd sentencepiece
% mkdir build
% cd build
% cmake ..
% make -j $(nproc)
% sudo make install
% sudo ldconfig -v

在 OSX/macOS 上,将最后一个命令替换为 sudo update_dyld_shared_cache

使用 vcpkg 构建和安装

您可以使用 vcpkg 依赖管理器下载和安装 sentencepiece:

sudo git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install sentencepiece

vcpkg 中的 sentencepiece 端口由 Microsoft 团队成员和社区贡献者保持最新。如果版本过时,请在 vcpkg 存储库中创建问题或拉取请求

从签名的发布轮子下载并安装 SentencePiece

您可以从 GitHub 发布页面 下载轮子。
在发布过程中,我们使用 OpenSSF 的 slsa-framework/slsa-github-generator 生成 SLSA3 签名。要验证发布二进制文件:

  1. slsa-framework/slsa-verifier#installation 安装验证工具。
  2. GitHub 发布页面 下载出处文件 attestation.intoto.jsonl
  3. 运行验证器:
slsa-verifier -artifact-path <the-wheel> -provenance attestation.intoto.jsonl -source github.com/google/sentencepiece -tag <the-tag>

pip install wheel_file.whl

使用说明

训练 SentencePiece 模型

% spm_train --input=<input> --model_prefix=<model_name> --vocab_size=8000 --character_coverage=1.0 --model_type=<type>
  • --input:每行一个句子的原始语料文件。无需运行分词器、规范化器或预处理器。默认情况下,SentencePiece 使用 Unicode NFKC 规范化输入。您可以传递以逗号分隔的文件列表。
  • --model_prefix:输出模型名称前缀。会生成 <model_name>.model<model_name>.vocab 文件。
  • --vocab_size:词汇量大小,例如 8000、16000 或 32000。
  • --character_coverage:模型覆盖的字符数量,好的默认值是:对于字符集丰富的语言(如日语或中文)为 0.9995,对于字符集较小的其他语言为 1.0
  • --model_type:模型类型。从 unigram(默认)、bpecharword 中选择。使用 word 类型时,输入句子必须预先分词。

使用 --help 标志显示训练的所有参数,或参见此处了解概述。

将原始文本编码为句子片段/ID

% spm_encode --model=<model_file> --output_format=piece < input > output
% spm_encode --model=<model_file> --output_format=id < input > output

使用 --extra_options 标志插入 BOS/EOS 标记或反转输入序列。

% spm_encode --extra_options=eos (仅添加 </s>)
% spm_encode --extra_options=bos:eos (添加 <s> 和 </s>)
% spm_encode --extra_options=reverse:bos:eos (反转输入并添加 <s> 和 </s>)

SentencePiece 支持使用 --output_format=(nbest|sample)_(piece|id) 标志的 nbest 分割和分割采样。

% spm_encode --model=<model_file> --output_format=sample_piece --nbest_size=-1 --alpha=0.5 < input > output
% spm_encode --model=<model_file> --output_format=nbest_id --nbest_size=10 < input > output

将句子片段/ID 解码为原始文本

% spm_decode --model=<model_file> --input_format=piece < input > output
% spm_decode --model=<model_file> --input_format=id < input > output

使用 --extra_options 标志逆序解码文本。

% spm_decode --extra_options=reverse < input > output

端到端示例

% spm_train --input=data/botchan.txt --model_prefix=m --vocab_size=1000
unigram_model_trainer.cc(494) LOG(INFO) Starts training with :
input: "../data/botchan.txt"
... <snip>
unigram_model_trainer.cc(529) LOG(INFO) EM sub_iter=1 size=1100 obj=10.4973 num_tokens=37630 num_tokens/piece=34.2091
trainer_interface.cc(272) LOG(INFO) Saving model: m.model
trainer_interface.cc(281) LOG(INFO) Saving vocabs: m.vocab

% echo "I saw a girl with a telescope." | spm_encode --model=m.model
▁I ▁saw ▁a ▁girl ▁with ▁a ▁ te le s c o pe .

% echo "I saw a girl with a telescope." | spm_encode --model=m.model --output_format=id
9 459 11 939 44 11 4 142 82 8 28 21 132 6

% echo "9 459 11 939 44 11 4 142 82 8 28 21 132 6" | spm_decode --model=m.model --input_format=id
I saw a girl with a telescope.

您可以看到原始输入句子从词汇 ID 序列中得到了恢复。

导出词汇表

% spm_export_vocab --model=<model_file> --output=<output file>

<output file> 存储词汇表和发射对数概率的列表。词汇 ID 对应于该文件中的行号。

重新定义特殊元标记

默认情况下,SentencePiece 使用 Unknown (<unk>)、BOS (<s>) 和 EOS (</s>) 标记,其 ID 分别为 0、1 和 2。我们可以在训练阶段如下重新定义此映射:

% spm_train --bos_id=0 --eos_id=1 --unk_id=5 --input=... --model_prefix=... --character_coverage=...

当设置 -1 的 ID 时,例如 bos_id=-1,此特殊标记被禁用。请注意,未知 ID 不能禁用。我们可以将 padding (<pad>) 的 ID 定义为 --pad_id=3

如果您想分配其他特殊标记,请参见使用自定义符号

词汇表限制

spm_encode 接受 --vocabulary--vocabulary_threshold 选项,以便 spm_encode 仅生成也出现在词汇表中(至少具有一定频率)的符号。此功能的背景在 subword-nmt 页面 中描述。

用法基本上与 subword-nmt 相同。假设 L1 和 L2 是两种语言(源语言/目标语言),训练共享的 spm 模型,并为每种语言获取生成的词汇表:

% cat {train_file}.L1 {train_file}.L2 | shuffle > train
% spm_train --input=train --model_prefix=spm --vocab_size=8000 --character_coverage=0.9995
% spm_encode --model=spm.model --generate_vocabulary < {train_file}.L1 > {vocab_file}.L1
% spm_encode --model=spm.model --generate_vocabulary < {train_file}.L2 > {vocab_file}.L2

使用 shuffle 命令只是为了以防万一,因为 spm_train 默认加载语料库的前 1000 万行。

然后使用 --vocabulary 选项分割训练/测试语料库:

% spm_encode --model=spm.model --vocabulary={vocab_file}.L1 --vocabulary_threshold=50 < {test_file}.L1 > {test_file}.seg.L1
% spm_encode --model=spm.model --vocabulary={vocab_file}.L2 --vocabulary_threshold=50 < {test_file}.L2 > {test_file}.seg.L2

高级主题

相关项目

以下是与 SentencePiece 相关的项目。它们独立维护。如果需要添加,请发送拉取请求 (PR)。
- SentencePiece 的 Java 工具/绑定

10 次点击  ∙  0 人收藏  
登录后收藏  
0 条回复
关于 ·  帮助 ·  PING ·  隐私 ·  条款   
OA0 - Omni AI 0 一个探索 AI 的社区
沪ICP备2024103595号-2
耗时 32 ms
Developed with Cursor