赞
踩
看好的开源文档就像发现宝藏一般,决定记录一下不走丢。
这个应该会是一个系列 ,因为博主看的文档都是NLP方向的,所以称之为NLP文档挖宝,有内味了没 :-)
此次推荐的文档是transformers包下tokenizer的综述性文档[1],它介绍了整个tokenizer的进化历程,以及tokenizer在不同预训练模型中使用的差异。对这个知识点感兴趣的朋友强烈推荐去看一下官方文档,会对整个tokenizer有更体系化的认识。
在nlp领域中tokenizer主要用于文本的预处理,能够将句子级文本转化为词级的文本,然后用于接下来的词向量转化,这个过程可以叫他token转化,或者直接叫tokenizer。总的来看,Tokenizer在转化策略上大致分为三种,可以按照最后token转化结果的粒度分为:词级(word level),字母级(character level)和子词级(subword level),目前主要流行的方法是子词级转化。
接下来,我们将总结在官方文档中的tokenizer的进化史部分,并展示一种使用tokenizer的最简单的方法。
使用词级分隔的一般是面向用空格作为分隔的语言,例如英语、俄语等。
直接使用空格作为分隔。
使用空格和标点作为分隔。
使用空格、标点和一定的分词规则。
词级处理能够松散地(loosely)完成分词,例如中文、日文就使用字作为单位进行词表示,但是同时带来了词表过大的问题,使得程序在训练时的内存和显存占用过多,所以需要一种生成更小词表的方法。于是有限的字母级处理方式被提出。
但是,从实验表现上看效果并不好,因为没有字母上下文而单看字母,其意义是模糊的,比如“t”相比“today”,就缺少了很多的含义。因此,一种能融合词级和字母级的处理方法子词级被提出。
子词级处理的目标是,将稀有词划分为更有意义的字词,在凝集性(agglutinative)的语言中更有效,例如土耳其语,一个词由多个词缀组成。
字词的处理分为以下几种
Transformers包中有各种各样的tokenizer方法,通过from_pretrained方法可以快速获取词表配置。我们可以使用AutoTokenizer类来自动识别我们提供的预训练模型路径下的词表类别。下面以bert和roberta的预训练模型引入为例:
- from transformers import AutoTokenizer # 引入AutoTokenizer
-
- # bert
- bert_pre_path = 'bert-base-uncased'
- bert_tokenizer = AutoTokenizer.from_pretrained(bert_pre_path)
-
- # roberta
- roberta_pre_path = 'roberta_base'
- roberta_tokenizer = AutoTokenizer.from_pretrained(roberta_pre_path)
·【注意】此处有坑。因为每种预训练模型有不同的tokenizer方法,所以通过AutoTokenizer加载出来的预训练模型还是有区别的,这里需要提前知道各种预训练模型使用的tokenizer方法,才能使用这种便捷方法。
- """:class:`~transformers.AutoTokenizer` is a generic tokenizer class
- that will be instantiated as one of the tokenizer classes of the library
- when created with the `AutoTokenizer.from_pretrained(pretrained_model_name_or_path)`
- class method.
- The `from_pretrained()` method takes care of returning the correct tokenizer class instance
- based on the `model_type` property of the config object, or when it's missing,
- falling back to using pattern matching on the `pretrained_model_name_or_path` string:
- - `t5`: T5Tokenizer (T5 model)
- - `distilbert`: DistilBertTokenizer (DistilBert model)
- - `albert`: AlbertTokenizer (ALBERT model)
- - `camembert`: CamembertTokenizer (CamemBERT model)
- - `xlm-roberta`: XLMRobertaTokenizer (XLM-RoBERTa model)
- - `longformer`: LongformerTokenizer (AllenAI Longformer model)
- - `roberta`: RobertaTokenizer (RoBERTa model)
- - `bert`: BertTokenizer (Bert model)
- - `openai-gpt`: OpenAIGPTTokenizer (OpenAI GPT model)
- - `gpt2`: GPT2Tokenizer (OpenAI GPT-2 model)
- - `transfo-xl`: TransfoXLTokenizer (Transformer-XL model)
- - `xlnet`: XLNetTokenizer (XLNet model)
- - `xlm`: XLMTokenizer (XLM model)
- - `ctrl`: CTRLTokenizer (Salesforce CTRL model)
- - `electra`: ElectraTokenizer (Google ELECTRA model)"""

比如上面的bert_tokenizer就有ids_to_tokens这个方法,可以获取对应的词表映射关系,但是roberta_tokenizer是通过decoder方法进行映射的。如果想写一个一体化的程序,就要在词表这里设置一个判断进行进一步的区分。
- itos = tokenizer.ids_to_tokens if 'ids_to_tokens' in tokenizer.__dict__ \
- else tokenizer.decoder
之前看bert、albert的论文的时候,subword、wordpiece、BPE在脑子里散乱的存储着,现在总算成了体系。
小小的tokenizer都有这么多花样,妙啊。不由感叹知识让我自由,不受条框的限制,要不然就被一个Auto唬住了。
后续可以看一下tokenizer的源码,一个类两千多行,很壮观。内部使用了__call__方法直接让tokenizer类可以当成方法用,答案尽在:'./transformers/tokenization_utils_base.py' line 1551。核心还是调用了'batch_encode_plus'……不过这些都是后话了。
[1] transformers官网文档中的tokennizer进展总结:https://huggingface.co/transformers/tokenizer_summary.html
[2] 浅谈Byte-Level BPE:https://zhuanlan.zhihu.com/p/146114164
[3] Transformer 理解Tokenizer: https://blog.csdn.net/weixin_42167712/article/details/110727139
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。