BPE、WordPiece、SentencePiece
tokenize的目标是将输入的文本流, 切分成一个个子串,使得每个子串具有相对完整的语义,便于学习embedding表达和后续模型的使用。
tokenize三种粒度:word、subword、char
word/词:最自然的语言单元,中文需要分词算法。由于词汇表较大,存在长尾现象,词汇表可能超大。常规的词汇表,一般大小不超过5万。
char/字符:最基本的字符。字符的数量是少量有限的,由于字符数量太小,在为每个字符学习嵌入向量表示的时候,每个向量容纳太多的语义信息,学习困难。
subword/子词级别:介于字符和单词之间,平衡了词汇量和语义独立性。常用词应该保持原状,生僻词应该拆分成子词以共享token压缩空间。
常用tokenize算法
- BPE(Byte-Pair Encoding)
- WordPiece
- SentencePiece
Model | Type of Tokenizer |
BERT | WordPiece |
GPT-2 | BPE |
XLNet | SentencePiece |
ALBERT | SentencePiece |
T5 | SentencePiece |
BPE:字节对编码。核心思想在于将最常出现的子词对合并,直到词汇表达到预定大小时停止。
- 依赖于预分词器pretokenizer完成初步的切分。pretokenizer可以是简单基于空格,也可以基于规则
- 分词后,统计每个词的词频
- 建立基础词汇表,包括所有的字符
- 根据规则,分别考察2-gram, 3-gram的基本字符组合。将高频的n-gram组合依次加入到词汇表中,直到词汇表达到预定大小停止
- 最终词汇表的大小 = 基础字符词汇表大小 + 合并串的数量(例如:GPT, 40478 = 478(基础字符) + 40000(merges))
WordPiece
子词粒度的tokenize算法subword tokenization algorithm。例如BERT、DistilBERT、Electra均使用它。
其原理同BPE接近,在做合并之时,不是根据最高频的组合,而是寻找最大化训练数据似然的merge。
Unigram
与BPE或者WordPiece不同, Unigram的算法思想从一个巨大的词汇表出发,再逐渐删除trimdown其中的词汇,直到size满足预定义。
初始的词汇表采用所有预分词器分出来的词,再加上所有高频的子串。每次从词汇表中删除词汇的原则是使预定义的损失最小。训练时,计算loss的公式为:。
SentencePiece
将一个句子看作一个整体,再切分成片段,而没有保留天然的词语的概念。
把空格space也当作一种 特殊字符来处理,再用BPE或者Unigram算法来构造词汇表。
SentencePiece与Unigram算法联合使用, 例如ALBERT、XLNet、Marian、T5
切分实例与代码分析
BertTokenizer / WordPiece
【BertTokenizer, 基于WordPiece算法, base版本的词汇表大小为21128】
from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained('bert-base-chinese')
tokens = tokenizer.encode("我是一个好人")
- 在BertTokenizer中,用##符号表示非开头的子词
- 标点符号、生僻字等未出现的token被[UNK]代替
- 中文基本拆分成了字的形式
from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained('bert-base-chinese')
print(tokenizer) # tokenizer信息打印
tokens = tokenizer.encode("我是一个好人")
print(tokens) # encode编码