SentencePiece论文阅读

1. 论文

1.1 基本使用

  • SentencePiece是用于NLP训练中对句子进行token化的工具,跟语言无关, SentencePiece中包含了byte-pairencoding(BPE)unigram language model两种切分subword的算法。

  • SentencePiece中包含有四个部分:

    • Normalizer: 规一化操作,类似Unicode把字符转为统一格式。
    • Trainer: 从规一化后的语料中学习subword的切分模型。
    • Encoder: 对应预处理时的tokenization操作,把句子转为对应的subword或id。
    • Decoder: 对应后处理时的detokenization操作,把subword或id还原为原有句子

示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
% spm_train −−input=data/input.txt
−−model_prefix=spm −−vocab_size=1000
% echo "Hello world." | spm_encode
−−model=spm.model
_He ll o _world .
% echo "Hello world." | spm_encode
−−model=spm.model −−output_format=id
151 88 21 887 6
% echo "_He ll o _world ." |
spm_decode −−model=spm.model
Hello world.
% echo "151 88 21 887 6" |
spm_decode −−model=spm.model
−−input_format=id
Hello world.

1.2 设计

  • SentencePiece中的Encoder和Decoder相互对应,公式定义为Decode(Encode(Normalize(text))) = Normalize(text)。也被称为lossless tokenization
  • SentencePiece计算高效,BPE每轮需要O(N^2)的计算量,但SentencePiece实现时使用了二叉堆(优先队列),使得效率降为了O(N*log(N))
  • SentencePiece词id的管理使用--vocab_size=<size>, 相比BPE中使用合并次数的定义更通用。内置了一些词id,例如:unknown symbol(), BOS (), EOS ()和padding().
  • SentencePiece默认的规一化采用了Unicode NFKC, 在使用spm_train时指定规一化类型 --normalization_rule_name=nfkc, 也支持自定义规一化操作--normalization_rule_tsv=<file>, 例如把unicode编码[U+41 U+302 U+300]转为U+1EA64。
  • SentencePiece使用是自包含的,所有的模型参数、规则、状态都被编码到了model文件中
  • 提供了即时使用的Python、C++等API,例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// c++
#include <sentencepiece_processor.h>
#include <sentencepiece_trainer.h>
SentencePieceTrainer::Train(
"--input=input.txt "
"--model_prefix=spm "
"--vocab_size=1000");
SentencePieceProcessor sp;
sp.Load("spm.model");
std::vector<std::string> pieces;
sp.Encode("Hello world.", &pieces);
std::vector<int> ids;
sp.Encode("Hello world.", &ids);
std::string text;
sp.Decode({151, 88, 21, 887, 6}, &text);

# python
import sentencepiece as spm
params = (’--input=input.txt ’
’--model_prefix=spm ’
’--vocab_size=1000’)
spm.SentencePieceTrainer.Train(params)
sp = spm.SentencePieceProcessor()
sp.Load(’spm.model’)
print(sp.EncodeAsPieces(’Hello world.’))
print(sp.EncodeAsIds(’Hello world.’))
print(sp.DecodeIds([151, 88, 21, 887, 6]))

2. 代码

代码参考:https://github.com/google/sentencepiece

3. 参考