google/sentencepiece
GitHub: google/sentencepiece
Google 开源的神经网络文本分词器,支持 BPE 和 unigram 算法,可直接从原始文本训练子词模型。
Stars: 11691 | Forks: 1334
# SentencePiece
[](https://github.com/google/sentencepiece/actions/workflows/cmake.yml)
[](https://github.com/google/sentencepiece/actions/workflows/wheel.yml)
[](https://github.com/google/sentencepiece/issues)

[](https://badge.fury.io/py/sentencepiece)
[](https://pypi.org/project/sentencepiece/)
[](CONTRIBUTING.md)
[](https://opensource.org/licenses/Apache-2.0)
[](https://slsa.dev)
SentencePiece 是一个无监督的文本分词器和去分词器,主要用于
基于神经网络的文本生成系统,其中词汇表大小
在神经网络模型训练之前是预先确定的。SentencePiece 实现了
**子词单元** (例如,**字节对编码 (BPE)** [[Sennrich et al.](https://www.aclweb.org/anthology/P16-1162)]) 和
**unigram 语言模型** [[Kudo.](https://arxiv.org/abs/1804.10959)])
并扩展了直接从原始句子训练的功能。SentencePiece 允许我们构建一个不依赖于特定语言预处理/后处理的纯端到端系统。
**这不是一个官方的 Google 产品。**
## 技术亮点
- **纯数据驱动**: SentencePiece 从句子中训练分词和去分词
模型。并不总是需要预分词 ([Moses tokenizer](https://github.com/moses-smt/mosesdecoder/blob/master/scripts/tokenizer/tokenizer.perl)/[MeCab](http://taku910.github.io/mecab/)/[KyTea](http://www.phontron.com/kytea/))。
- **语言独立**: SentencePiece 将句子仅视为 Unicode 字符序列。没有依赖语言的逻辑。
- **多种子词算法**: 支持 **BPE** [[Sennrich et al.](https://www.aclweb.org/anthology/P16-1162)] 和 **unigram 语言模型** [[Kudo.](https://arxiv.org/abs/1804.10959)]。
- **子词正则化**: SentencePiece 为 [子词正则化](https://arxiv.org/abs/1804.10959) 和 [BPE-dropout](https://arxiv.org/abs/1910.13267) 实现了子词采样,这有助于提高 NMT 模型的鲁棒性和准确性。
- **快速且轻量级**: 分割速度约为 50k 句/秒,内存占用约为 6MB。
- **自包含**: 只要使用相同的模型文件,就能获得相同的分词/去分词结果。
- **直接生成词汇表 ID**: SentencePiece 管理词汇表到 ID 的映射,可以直接从原始句子生成词汇表 ID 序列。
- **基于 NFKC 的归一化**: SentencePiece 执行基于 NFKC 的文本归一化。
对于不熟悉 SentencePiece 软件/算法的人,可以阅读[这里的入门介绍](https://medium.com/@jacky2wong/understanding-sentencepiece-under-standing-sentence-piece-ac8da59f6b08)。
## 与其他实现的比较
| 特性 | SentencePiece | [subword-nmt](https://github.com/rsennrich/subword-nmt) | [WordPiece](https://arxiv.org/pdf/1609.08144.pdf) |
| :-------------------------------------- | :--------------------------------------------: | :-----------------------------------------------------: | :-----------------------------------------------: |
| 支持的算法 | BPE, unigram, char, word | BPE | BPE\* |
| 开源软件? | 是 | 是 | Google 内部使用 |
| 子词正则化 | [是](#subword-regularization-and-bpe-dropout) | 否 | 否 |
| Python 库 | [是](python/README.md) | 否 | 不适用 |
| C++ 库 | [是](doc/api.md) | 否 | 不适用 |
| 需要预分割? | [否](#whitespace-is-treated-as-a-basic-symbol) | 是 | 是 |
| 可自定义归一化 (例如, NFKC) | [是](doc/normalization.md) | 否 | 不适用 |
| 直接 ID 生成 | [是](#end-to-end-example) | 否 | 不适用 |
注意,WordPiece 中使用的 BPE 算法与原始 BPE 略有不同。
## 概述
### 什么是 SentencePiece?
SentencePiece 是**子词单元**的重新实现,这是缓解神经机器翻译中开放词汇表问题的有效方法。SentencePiece 支持两种分割方式,**字节对编码 (BPE)** [[Sennrich et al.](http://www.aclweb.org/anthology/P16-1162)] 和 **unigram 语言模型** [[Kudo.](https://arxiv.org/abs/1804.10959)]。以下是与其他实现的高级差异。
#### 唯一 Token 的数量是预先确定的
神经机器翻译模型通常使用固定的词汇表进行操作。大多数假设无限词汇表的无监督分词算法不同,SentencePiece 训练分割模型时,使得最终的词汇表大小是固定的,例如 8k、16k 或 32k。
请注意,SentencePiece 指定训练的最终词汇表大小,这与使用合并操作次数的 [subword-nmt](https://github.com/rsennrich/subword-nmt) 不同。
合并操作的数量是 BPE 特有的参数,不适用于其他分割算法,包括 unigram、word 和 character。
#### 从原始句子训练
以前的子词实现假设输入句子是经过预分词的。这个约束是为了高效训练所必需的,但这使得预处理变得复杂,因为我们必须提前运行依赖语言的分词器。
SentencePiece 的实现速度足够快,可以从原始句子训练模型。这对于训练中文和日文的分词器和去分词器非常有用,因为这些语言的单词之间不存在显式的空格。
#### 空格被视为基本符号
自然语言处理的第一步是文本分词。例如,一个标准的英语分词器会将文本 "Hello world." 分割成以下三个 Token。
一个观察结果是,原始输入和分词后的序列**不能可逆地转换**。例如,“World”和“.”之间没有空格的信息在分词后的序列中丢失了,因为例如 `Tokenize(“World.”) == Tokenize(“World .”)`
SentencePiece 将输入文本仅视为 Unicode 字符序列。空格也被当作普通符号处理。为了将空格显式地作为基本 Token 处理,SentencePiece 首先使用元符号 "▁" (U+2581) 对空格进行转义,如下所示。
然后,这段文本被分割成小块,例如:
由于空格保留在分割后的文本中,我们可以毫无歧义地对文本进行去分词。
```
detokenized = ''.join(pieces).replace('▁', ' ')
```
此功能使得无需依赖特定语言的资源即可执行去分词。
请注意,当使用标准分词器分割句子时,我们无法应用相同的无损转换,因为它们将空格视为特殊符号。分词后的序列不保留恢复原始句子所需的信息。
- (en) Hello world. → [Hello] [World] [.] \(Hello 和 World 之间有空格\)
- (ja) こんにちは世界。 → [こんにちは] [世界] [。] \(こんにちは 和 世界 之间没有空格\)
#### 子词正则化和 BPE-dropout
子词正则化 [[Kudo.](https://arxiv.org/abs/1804.10959)] 和 BPE-dropout [Provilkov et al](https://arxiv.org/abs/1910.13267) 是简单的正则化方法,通过实时子词采样虚拟地增加训练数据,这有助于提高 NMT 模型的准确性和鲁棒性。
要启用子词正则化,您需要将 SentencePiece 库
([C++](doc/api.md#sampling-subword-regularization)/[Python](python/README.md)) 集成到 NMT 系统中,以便为每次参数更新采样一个分割,这与标准的离线数据准备不同。以下是 [Python 库](python/README.md) 的示例。您会发现 'New York' 在每次 `SampleEncode (C++)` 或 `enable_sampling=True 的 encode (Python)` 调用中的分割方式都不同。采样参数的详细信息可以在 [sentencepiece_processor.h](src/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 提供了支持 SentencePiece 训练和分割的 Python 封装。
您可以使用以下命令安装 SentencePiece 的 Python 二进制包。
```
pip install sentencepiece
```
更多详情,请参见 [Python 模块](python/README.md)
### 从 C++ 源码构建并安装 SentencePiece 命令行工具
构建 SentencePiece 需要以下工具和库:
- [cmake](https://cmake.org/)
- C++11 编译器
- [gperftools](https://github.com/gperftools/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](https://github.com/Microsoft/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 仓库上[创建 issue 或 pull request](https://github.com/Microsoft/vcpkg)。
### 从签名的发布 wheels 下载并安装 SentencePiece
您可以从 [GitHub 发布页面](https://github.com/google/sentencepiece/releases/latest) 下载 wheel。
我们在发布过程中使用 OpenSSF 的 [slsa-framework/slsa-github-generator](https://github.com/slsa-framework/slsa-github-generator) 生成 [SLSA3 签名](slsa.dev)。要验证发布的二进制文件:
1. 从 [slsa-framework/slsa-verifier#installation](https://github.com/slsa-framework/slsa-verifier#installation) 安装验证工具。
2. 从 [GitHub 发布页面](https://github.com/google/sentencepiece/releases/latest) 下载来源文件 `attestation.intoto.jsonl`。
3. 运行验证器:
```
slsa-verifier -artifact-path -provenance attestation.intoto.jsonl -source github.com/google/sentencepiece -tag
```
pip install wheel_file.whl
## 使用说明
### 训练 SentencePiece 模型
```
% spm_train --input= --model_prefix= --vocab_size=8000 --character_coverage=1.0 --model_type=
```
- `--input`: 每行一句的**原始**语料库文件。无需运行
分词器、归一化器或预处理器。默认情况下,SentencePiece 使用 Unicode NFKC 对输入进行归一化。您可以传递逗号分隔的文件列表。
- `--model_prefix`: 输出模型名称前缀。将生成 `.model` 和 `.vocab`。
- `--vocab_size`: 词汇表大小,例如 8000、16000 或 32000
- `--character_coverage`: 模型覆盖的字符数量,良好的默认值为:`0.9995` 适用于日语或中文等字符集丰富的语言,`1.0` 适用于其他字符集较小的语言。
- `--model_type`: 模型类型。可选 `unigram` (默认)、`bpe`、`char` 或 `word`。使用 `word` 类型时,输入句子必须经过预分词。
使用 `--help` 标志显示所有训练参数,或查看[此处](doc/options.md)获取概览。
### 将原始文本编码为句子片段/ID
```
% spm_encode --model= --output_format=piece < input > output
% spm_encode --model= --output_format=id < input > output
```
使用 `--extra_options` 标志插入 BOS/EOS 标记或反转输入序列。
```
% spm_encode --extra_options=eos (add only)
% spm_encode --extra_options=bos:eos (add and )
% spm_encode --extra_options=reverse:bos:eos (reverse input and add and )
```
SentencePiece 通过 `--output_format=(nbest|sample)_(piece|id)` 标志支持 nbest 分割和分割采样。
```
% spm_encode --model= --output_format=sample_piece --nbest_size=-1 --alpha=0.5 < input > output
% spm_encode --model= --output_format=nbest_id --nbest_size=10 < input > output
```
### 将句子片段/ID 解码为原始文本
```
% spm_decode --model= --input_format=piece < input > output
% spm_decode --model= --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"
...
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= --output=
标签:Bash脚本, BPE, C++, DLL 劫持, Google, IPv6支持, LLM, NLP, Nuclei, Python, SentencePiece, Unigram, Unmanaged PE, 大语言模型, 子词算法, 开源库, 搜索引擎爬虫, 数据擦除, 数据预处理, 文本分词器, 无后门, 无监督学习, 机器翻译, 深度学习, 特征工程, 神经网络文本生成, 端到端系统, 词表构建, 逆向工具