Press "Enter" to skip to content

分词器tokenizers介绍

本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢.

Byte Pair Encoding (BPE) 字节对编码

 

概述

 

字节对编码最早是在信号压缩领域提出的,后来被应用于分词任务中。在信号压缩领域中BPE过程可视化如下:

 

1_x1Y_n3sXGygUPSdfXTm9pQ

 

接下来重点介绍将BPE应用于分词任务的流程:
实现流程

根据语料库建立一个词典,词典中仅包含单个字符,如英文中就是a-z
统计语料库中出现次数最多的字符对(词典中两项的组合),然后将字符对加入到词典中
重复步骤2直到到达规定的步骤数目或者词典尺寸缩小到了指定的值。

分类

 

主要包含的 Tokenizer 有:

 

ByteLevelBPETokenizer,字节级别的 BPE (Byte Pair Encoding) 训练和 tokenize,facebook 那几个预训练模型比如 Roberta 就用的这个,应对多语言比较方便;

 

CharBPETokenizer,比字节高一个级别,字级别的 BPE,其实就是最经典 Sennrich 教授用的那个,subword-nmt;

 

SentencePieceTokenizer,现在越来越搞不清这些命名之间的关系了,不过看代码应该是在 BPE 过程之前加了一个 pretokenization 过程,先对文本进行预处理再 BPE;

 

BertWordPieceTokenizer,应该就是基于 unigram language model 那篇论文来做的。

 

BPE的优点

 

可以很有效地平衡词典尺寸和编码步骤数(将句子编码所需要的token数量)
BPE存在的缺点:

 

对于同一个句子, 例如Hello world,如图所示,可能会有不同的Subword序列。不同的Subword序列会产生完全不同的id序列表示,这种歧义可能在解码阶段无法解决。在翻译任务中,不同的id序列可能翻译出不同的句子,这显然是错误的。
在训练任务中,如果能对不同的Subword进行训练的话,将增加模型的健壮性,能够容忍更多的噪声,而BPE的贪心算法无法对随机分布进行学习。

 

Huggingface tokenizers库的介绍和使用

 

tokenizers是集合了当前最常用的分词器集合,效率和易用性也是其关注的范畴。

 

使用示例:

 

#  provides ultra-fast implementations of most current :
>>> from  import (ByteLevelBPETokenizer,
                            CharBPETokenizer,
                            SentencePieceBPETokenizer,
                            BertWordPieceTokenizer)
# Ultra-fast => they can encode 1GB of text in ~20sec on a standard server's CPU
#  can be easily instantiated from standard files
>>> tokenizer = BertWordPieceTokenizer("bert-base-uncased-vocab.txt", lowercase=True)
#  provide exhaustive outputs: tokens, mapping to original string, attention/special token masks.
# They also handle model's max input lengths as well as padding (to directly encode in padded batches)
>>> output = tokenizer.encode("Hello, y'all! How are you ?")
>>> print(output.ids, output.tokens, output.offsets)
[101, 7592, 1010, 1061, 1005, 2035, 999, 2129, 2024, 2017, 100, 1029, 102]
['[CLS]', 'hello', ',', 'y', "'", 'all', '!', 'how', 'are', 'you', '[UNK]', '?', '[SEP]']
[(0, 0), (0, 5), (5, 6), (7, 8), (8, 9), (9, 12), (12, 13), (14, 17), (18, 21), (22, 25), (26, 27),(28, 29), (0, 0)]
# Here is an example using the offsets mapping to retrieve the string corresponding to the 10th token:
>>> output.original_str[output.offsets[10]]

 

自己训练分词器

 

# You can also train a BPE/Byte-levelBPE/WordPiece vocabulary on your own files
>>> tokenizer = ByteLevelBPETokenizer()
>>> tokenizer.train(["wiki.test.raw"], vocab_size=20000)
[00:00:00] Tokenize words                 ████████████████████████████████████████   20993/20993
[00:00:00] Count pairs                    ████████████████████████████████████████   20993/20993
[00:00:03] Compute merges

 

参考

https://pypi.org/project/tokenizers/

https://www.cnblogs.com/deep-deep-learning/p/12942628.html

Be First to Comment

发表评论

电子邮件地址不会被公开。 必填项已用*标注