当前位置:   article > 正文

Transformers的RoBERTa model怎么使用word level的tokenizer_robertatokenizerfast.from_pretrained

robertatokenizerfast.from_pretrained

2022年8月25日更新:

昨天改了tokenizer之后以为好了,结果发现还是有问题。具体来说,用后面方法训练的tokenizer,并不能被正确加载为RobertaTokenizerFast,会导致只对输入序列中的逗号进行编码。解决方法是:用类似于

tokenizer.save(model_dir+'/wordlevel.json')

这种形式将tokenizer保存成一个json文件,然后用RobertaTokenizerFast(RoBERTa)的init function中的tokenizer_file参数指定加载tokenizer文件。具体我举一个例子(省去了pretraining部分):

  1. from transformers import RobertaTokenizerFast
  2. model_dir='Language-Model-Roberta'
  3. tokenizer1 = RobertaTokenizerFast.from_pretrained("./"+model_dir)
  4. tokenizer2 = RobertaTokenizerFast(tokenizer_file=model_dir+'/wordlevel.json')
  5. corpora_line="push r15 push r14 mov r15 , r8 push r13 push r12 mov r12 , rdi push rbp push rbx mov r14d"
  6. batch_encoding=tokenizer1(corpora_line)
  7. print(batch_encoding.tokens())
  8. print(tokenizer1.encode(corpora_line))
  9. batch_encoding=tokenizer2(corpora_line)
  10. print(batch_encoding.tokens())
  11. print(tokenizer2.encode(corpora_line))
  12. from tokenizers import Tokenizer
  13. tokenizer3 = Tokenizer.from_file(model_dir+"/wordlevel.json")
  14. print(tokenizer3.encode(corpora_line).ids)

对应的输出是:

  1. ['<s>', ',', ',', '</s>']
  2. [0, 6, 6, 2]
  3. ['push', 'r15', 'push', 'r14', 'mov', 'r15', ',', 'r8', 'push', 'r13', 'push', 'r12', 'mov', 'r12', ',', 'rdi', 'push', 'rbp', 'push', 'rbx', 'mov', 'r14d']
  4. [52, 38, 52, 36, 7, 38, 6, 58, 52, 34, 52, 42, 7, 42, 6, 22, 52, 24, 52, 18, 7, 109]
  5. [52, 38, 52, 36, 7, 38, 6, 58, 52, 34, 52, 42, 7, 42, 6, 22, 52, 24, 52, 18, 7, 109]

可以看到第一种方法是不行的!不过,博客原先的内容也有参考和总结的价值,pre-training部分也就稍微有点变化:

  1. import torch
  2. import os
  3. import shutil
  4. print(torch.cuda.is_available())
  5. ############################################################
  6. from pathlib import Path
  7. from tokenizers import Tokenizer
  8. from tokenizers.models import WordLevel
  9. from tokenizers.trainers import WordLevelTrainer
  10. repo_name="data/out"
  11. model_dir='Language-Model-Roberta'
  12. if(os.path.exists(model_dir)):
  13. shutil.rmtree(model_dir)
  14. os.mkdir(model_dir)
  15. paths = [str(x) for x in Path(repo_name).glob("**/*.static2")]
  16. tokenizer = Tokenizer(WordLevel())
  17. trainer = WordLevelTrainer(special_tokens=[
  18. "<s>",
  19. "<pad>",
  20. "</s>",
  21. "<unk>",
  22. "<mask>",
  23. ])
  24. from tokenizers.pre_tokenizers import Whitespace
  25. tokenizer.pre_tokenizer = Whitespace()
  26. tokenizer.train(files=paths,trainer=trainer)
  27. tokenizer.model.save(model_dir)
  28. merges=open(model_dir+'/merges.txt','w')
  29. tokenizer.save(model_dir+'/wordlevel.json')

2022年8月25日更新的内容就到这里,下面是原博客的内容:

---------------------------------------------------------------------------------------------------------------------------------

其实这个问题应该是很好解决的,想不到竟然花了3个多小时。相信这并不是我一个人有这样的需求,如果vacabulary很小的话,我们并不需要BPE之类的tokenizer,按道理来说应该很好换成word level的啊,但实际并不然:

按照网上到处都有的教程,例如(基于RoBERTa 训练一个MLM掩码语言模型 - 知乎),包括我自己之前的博客:使用huggingface‘s transformers预训练自己模型时报:Assertion ‘srcIndex < srcSelectDimSize‘ failed. 的解决办法_蛐蛐蛐的博客-CSDN博客,RoBERTa的tokenizer可以通过以下代码实现:

  1. import torch
  2. import os
  3. import shutil
  4. print(torch.cuda.is_available())
  5. ############################################################
  6. from pathlib import Path
  7. from tokenizers import ByteLevelBPETokenizer
  8. repo_name="data/out"
  9. model_dir='Language-Model-Roberta'
  10. if(os.path.exists(model_dir)):
  11. shutil.rmtree(model_dir)
  12. os.mkdir(model_dir)
  13. paths = [str(x) for x in Path(repo_name).glob("**/*.static")]
  14. tokenizer = ByteLevelBPETokenizer()
  15. tokenizer.train(files=paths, vocab_size=18_000, min_frequency=2, special_tokens=[
  16. "<s>",
  17. "<pad>",
  18. "</s>",
  19. "<unk>",
  20. "<mask>",
  21. ])
  22. tokenizer.save_model(model_dir)

这里先吐槽一点:从tokenizer的document中(Tokenizers)是看不到这个类的,但是网上所有的教程都是这么用,竟然也能正常跑起来。

我就很想当然地以为,按照相同的格式换成其他tokenizer即可,但实际上并不是这样,经过参考tokenizer的GitHub Readme文件,可以写成如下的形式:

  1. import torch
  2. import os
  3. import shutil
  4. print(torch.cuda.is_available())
  5. ############################################################
  6. from pathlib import Path
  7. from tokenizers import Tokenizer
  8. from tokenizers.models import WordLevel
  9. from tokenizers.trainers import WordLevelTrainer
  10. repo_name="data/out"
  11. model_dir='Language-Model-Roberta'
  12. if(os.path.exists(model_dir)):
  13. shutil.rmtree(model_dir)
  14. os.mkdir(model_dir)
  15. paths = [str(x) for x in Path(repo_name).glob("**/*.static2")]
  16. tokenizer = Tokenizer(WordLevel())
  17. trainer = WordLevelTrainer(special_tokens=[
  18. "<s>",
  19. "<pad>",
  20. "</s>",
  21. "<unk>",
  22. "<mask>",
  23. ])
  24. from tokenizers.pre_tokenizers import Whitespace
  25. tokenizer.pre_tokenizer = Whitespace()
  26. tokenizer.train(files=paths,trainer=trainer)

不得不说,和上面相比,差别有点大啊(例如:tokenizer = Tokenizer(WordLevel()),以及必需要加tokenizer.pre_tokenizer = Whitespace()这一行)。但是GitHub上并没有说怎么保存这个tokenizer,如果这时候用:

tokenizer.save_model(model_dir)

就会报错:

AttributeError: 'tokenizers.Tokenizer' object has no attribute 'save_model'

心中不禁草泥马啊。那换成save_pretrained呢(例如3-3 Transformers Tokenizer API 的使用 - 知乎)?还是会报错:

AttributeError: 'tokenizers.Tokenizer' object has no attribute 'save_pretrained'

这个其实也是可以预料到了,因为上面这个tokenizer是transformers中的(from transformers import AutoTokenizer),也不理解为啥会这么混乱!

如果参考tokenizer的文档换成save呢:Tokenizer

会报错说:

Exception: Is a directory (os error 21)

言下之意,通过save可以保存成一个文件。从之前说的RoBERTa的示例代码可以知道, 需要再重新加载的tokenizer需要在一个文件夹下,所以这个也不行。

又找了找,发现了这里的举例:transformers的tokenizer - 知乎

tokenizer.model.save(model_dir)

果然这个时候可以保存到这个model_dir文件夹了。但是如果就这样,还是会报错:

TypeError: expected str, bytes or os.PathLike object, not NoneType

在网上看到了这篇博客:避坑系列-transformers - 我就是叶子吖 - 博客园

我去,这个原因我也是醉了,所以最后手动建立一个空白的merges.txt文件,然后就可以正常保存和使用这个tokenizer了。呵呵呵呵呵,最后总结一下训练和使用这个tokenizer的过程,训练部分的完整代码是:

  1. import torch
  2. import os
  3. import shutil
  4. print(torch.cuda.is_available())
  5. ############################################################
  6. from pathlib import Path
  7. from tokenizers import Tokenizer
  8. from tokenizers.models import WordLevel
  9. from tokenizers.trainers import WordLevelTrainer
  10. repo_name="data/out"
  11. model_dir='Language-Model-Roberta'
  12. if(os.path.exists(model_dir)):
  13. shutil.rmtree(model_dir)
  14. os.mkdir(model_dir)
  15. paths = [str(x) for x in Path(repo_name).glob("**/*.static2")]
  16. tokenizer = Tokenizer(WordLevel())
  17. trainer = WordLevelTrainer(special_tokens=[
  18. "<s>",
  19. "<pad>",
  20. "</s>",
  21. "<unk>",
  22. "<mask>",
  23. ])
  24. from tokenizers.pre_tokenizers import Whitespace
  25. tokenizer.pre_tokenizer = Whitespace()
  26. tokenizer.train(files=paths,trainer=trainer)
  27. tokenizer.model.save(model_dir)
  28. merges=open(model_dir+'/merges.txt','w')

使用的时候还和之前一样:

  1. from transformers import RobertaTokenizerFast
  2. tokenizer = RobertaTokenizerFast.from_pretrained("./"+model_dir, max_len=512)

然后就可以愉快地训练RoBERTa了。不得不说,这些库的设计,和文档的组织形式,还是有很多无力吐槽的地方啊。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/249510
推荐阅读