Tokenizer
发布网友
发布时间:2024-09-30 06:08
我来回答
共1个回答
热心网友
时间:2024-10-04 19:11
Tokenizer是NLP任务中将自然语言文本转换为机器可理解的数字的步骤。它是文本预处理的重要部分,通过将文本转化为tokens并使用唯一的tokens生成词汇表,每个tokens在词汇表中的ID作为数字表示该token。tokens可以是单词、子单词或字符。以下是将文本转换为数字的完整过程,但我们将重点放在tokenization(模型)阶段。
基于单词的tokenization方法通过空白符和标点符号并使用特定规则将文本拆分成tokens,可以使用正则表达式或Python的split()函数实现。例如,文本“Hello world!”可以被拆分成tokens“Hello”和“world!”。Spacy和Moses是基于规则的tokenizer的两种流行选项。
基于单词的tokenization方法可能会生成非常大的词汇表(Transformer XL的词汇表大小为267,735),导致model输入和输出的embedding矩阵很大,占用大量计算资源。同时,这种方法无法解决单复数和拼写错误的问题,因此“boy”、“boys”和“knowledge”、“knowldge”在词汇表中对应不同的ID。Transformers模型的词汇表通常不超过50,000个词。
为了解决词汇表尺寸过大的问题,可以*其尺寸,只保留出现频率高的tokens,其他tokens被标记为unknown token。但这样做会丢失unknow token的信息。
字符级别的tokenization方法将文本拆分成字符,因为许多语言的字符数量很少,可以生成尺寸很小的词汇表(英语可以使用256个字符表示,但其单词数量为170,000)。这种方法能够解决unknown token和misspelled token的问题,同时降低模型的时间和空间复杂度。但在许多语言中,字符携带的语义信息较少,从而导致模型性能不佳。
子单词级别的tokenization方法介于上述两种方法之间,能够解决它们的问题,具有以下两个原则。该方法使我们知道tokens和tokenization具有相同的部分"token",其意思类似,同时,tokenization和modernization具有相同的"ization",可以在相似的语法环境中使用。这种方法能够处理unknown words。
常见的子单词级别的tokenization方法包括WordPiece(BERT)、Unigram(T5)、BPE(GPT2、RoBERTa)。这种方法能够生成合适的大小的词汇表,能够学习有意义的tokens并处理unknown token的问题。
BPE(Byte Pair Encoding)是一种简单的压缩算法,于2015年在论文《Neural Machine Translation of Rare Words with Subword Units》中被引入。其思想是重复将文本中出现频率最高的字符对替换为文本中不存在的字符,从而实现文本压缩。字符替换使用查找表来记录替换信息,解压时只需要执行反过程即可。
在NLP中使用BPE的变种进行tokenization,将词汇表中的常用单词使用单个token表示,而很少使用的单词使用两个或更多常用且有意义的token表示。token通常使用ASCII或Unicode表示,不在词汇表中的token标记为unknown,但token不能表示表情符号。因此,GPT2不使用Unicode表示token,而是使用字节,称为字节级别BPE。
BPE的训练流程如下:BPE保留获取的最终词汇表和合并规则。在使用时,先将文本拆分为单个字符形式,然后按顺序应用合并规则来合并字符,从而获得拆分的tokens。“bug”被拆分为["b","ug"],而“mug”被拆分为["UNK","ug"]。BPE生成的最终的词汇表的大小为基础词汇表的大小加上合并规则的数量。GPT的词汇表大小为40,478,其中基础词汇为478,合并规则为40,000。
GPT2使用字节作为基础词汇(字节级别BPE),从而确保所有基础字符都在词汇表中,不需要token。GPT2的词汇表大小为50,257,包括50,000个合并token、256个基础token以及1个特殊的结束文本token。
WordPiece在《Japanese and Korean Voice Search (Schuster et al., 2012)》中被提出,因用于BERT而知名。WordPiece类似于BPE,但选择进行合并的token对的逻辑不同。WordPiece为每对token对使用下面公式计算分数,选取分数最高的token对进行合并。
WordPiece倾向于合并单个token出现频率低而token对出现频率高的token,如“un”和“##able”不容易被合并,因为这两个token单独出现的频率高,而“hu”和“##gging”容易被合并,因为两个token出现频率低,而合并后的token“hugging”出现频率高。在每次迭代中,WordPiece需要计算词汇表中所有token对的分数,复杂度为O(N),其中N为当前词汇表的大小。在实现中,使用特定规则仅计算可能的token对的分数,从而减少复杂度,对于200k的词汇表可以在单个机器上几个小时内训练好。
我们仍然使用BPE的示例来解释WordPiece。第一轮没有合并ug(20/(36*20)),而是合并gs(5/(20*5))。
与BPE不同,WordPiece只保留最终的词汇表,而不保留合并规则。WordPiece进行tokenize时,迭代地使用与单词首字母相同且在词汇表中最长的token进行匹配和拆分单词,然后对剩余部分迭代执行上述操作。我们使用上面的词汇表对“hugs”进行tokenize,其中最长的token是“hug”,因此“hugs”被拆分为“hug”和“##s”,而“##s”在词汇表中也存在。
若单词中任何拆分的部分不在词汇表中,则整个单词被标记为unknown。与BPE不同,BPE中只是将单词中不在词汇表中的部分标记为unknown。(在代码中已验证,参见文章《BERT in Huggingface中的WordpieceTokenizer实现》)
Unigram是在《Subword Regularization: Improving Neural Network Translation Models with Multiple Subword Candidates (Kudo, 2018)》中被引入。与BPE和WordPiece不同,Unigram从大的词汇表开始,从中不断删除token直到达到指定大小。Unigram生成初始大词汇表的方法很多,如组合预分词器生成的单词以及corpus中出现频率高的子串。在训练过程中,迭代地从词汇表中删除损失增加最小的token。
词汇表中token出现的概率为该token出现的次数除以所有token出现的次数。Unigram将token的出现与其之前的token的出现视为独立事件。
我们仍然使用上面的示例来解释Unigram。初始状态时,“ug”出现20次,而corpus中所有token出现的总次数为210,因此,“ug”的概率为20/210。token“pug”的概率由“pu”和“g”的概率的乘积17/210 * 20/210 = 0.007710。此时的损失为169.8,如下计算。
然后,我们迭代地为每个token计算其被移除后的词汇表的损失,选择损失增加最小的token进行移除,直到达到指定的词汇表大小。我们对比移除token“pu”或“hug”的影响,移除“pu”不影响损失,而移除“hug”增加损失,所以移除“hug”。
Unigram总是保留基础字符,因此,任何单词都可以被tokenize。同时,Unigram为词汇表中的每个token保留其在训练corpus中的出现概率。当tokenize单词时,查找该单词的所有token组合方式,计算对应的概率并选择概率最大的组合方式。如:“pug”可以被拆分为“[“p”, “u”, “g”]”或“[“pu”, “g”]”或“[“p”, “ug”]”,我们计算每个组合的概率并最终选择概率最大的“[“pu”, “g”]”或“[“p”, “ug”]”。Unigram倾向于将单词拆分为尽可能少的token。
Unigram通常不直接使用,而是与SentencePiece一起使用。
上面的三种tokenization模型都假设文本中使用空白符来分割单词,但并非所有语言都这样做,如中文。解决方式之一是使用与语言相关的预分词器,如XLM,来处理。SentencePiece在《SentencePiece: A simple and language independent subword tokenizer and detokenizer for Neural Text Processing (Kudo et al., 2018)》中引入,提供了更通用的解决方法,将输入视为输入流,从而在字符之间添加空白符,然后调用Unigram来构建词汇表。
XLNetTokenizer中使用SentencePiece,因此词汇表中存在token“_”。
Huggingface提供了各种tokenizer的实现并提供了代码示例。
参考资料: