WordPiece 也是一种子词构建算法,我们在中文语料中使用的 BertTokenizer 就是使用这种分词算法,从这一点来看,WordPiece 算法要比 BPE 算法更加适合中文语料的分词场景。
class BertTokenizer(PreTrainedTokenizer):
Construct a BERT tokenizer. Based on WordPiece.
BPE 和 WordPiece 都是子词构建算法,他们两个最大的区别是做子词合并时,BPE 是寻找合并之后频数最高的两个子词进行合并,而 WordPiece 计算步骤如下:
https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/37842.pdf
分词的目标就是最大化训练数据的似然函数:
下图公式中,A 和 B 为待合并的两个子词:
示例代码:
import tokenizers.pre_tokenizers
from tokenizers import Tokenizer
from tokenizers.models import WordPiece
from tokenizers.trainers import WordPieceTrainer
from tokenizers.pre_tokenizers import WhitespaceSplit
def test():
document = ['我爱吃烤鸭'] * 5 + ['我也爱喝啤酒']
print(document)
# 指定分词器使用 BPE 算法模型,并设置特殊 UNK 标记
tokenizer = Tokenizer(model=WordPiece())
# 设置单词的分割方式
tokenizer.pre_tokenizer = WhitespaceSplit()
# 构建训练器
trainer = WordPieceTrainer(vocab_size=20)
# 开始训练
tokenizer.train_from_iterator(document, trainer)
# 保存分词器
tokenizer.save('./tokenizer.json')
if __name__ == '__main__':
test()
分词结果:
"vocab": {
"也": 0,
"吃": 1,
"啤": 2,
"喝": 3,
"我": 4,
"烤": 5,
"爱": 6,
"酒": 7,
"鸭": 8,
"##也": 9,
"##爱": 10,
"##喝": 11,
"##啤": 12,
"##酒": 13,
"##吃": 14,
"##烤": 15,
"##鸭": 16,
"我爱": 17,
"##吃烤": 18,
"我爱吃烤": 19
}