Transformers的RoBERTa model怎么使用word level的tokenizer

2022年8月25日更新:

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

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

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

from transformers import RobertaTokenizerFast

model_dir='Language-Model-Roberta'
tokenizer1 = RobertaTokenizerFast.from_pretrained("./"+model_dir)
tokenizer2 = RobertaTokenizerFast(tokenizer_file=model_dir+'/wordlevel.json')

corpora_line="push r15 push r14 mov r15 , r8 push r13 push r12 mov r12 , rdi push rbp push rbx mov r14d"

batch_encoding=tokenizer1(corpora_line)
print(batch_encoding.tokens())
print(tokenizer1.encode(corpora_line))

batch_encoding=tokenizer2(corpora_line)
print(batch_encoding.tokens())
print(tokenizer2.encode(corpora_line))

from tokenizers import Tokenizer
tokenizer3 = Tokenizer.from_file(model_dir+"/wordlevel.json")
print(tokenizer3.encode(corpora_line).ids)

对应的输出是:

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

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

import torch
import os
import shutil
print(torch.cuda.is_available())

############################################################
from pathlib import Path
from tokenizers import Tokenizer
from tokenizers.models import WordLevel
from tokenizers.trainers import WordLevelTrainer

repo_name="data/out"

model_dir='Language-Model-Roberta'
if(os.path.exists(model_dir)):
    shutil.rmtree(model_dir)
os.mkdir(model_dir)

paths = [str(x) for x in Path(repo_name).glob("**/*.static2")]
tokenizer = Tokenizer(WordLevel())
trainer = WordLevelTrainer(special_tokens=[
    "<s>",
    "<pad>",
    "</s>",
    "<unk>",
    "<mask>",
])

from tokenizers.pre_tokenizers import Whitespace
tokenizer.pre_tokenizer = Whitespace()

tokenizer.train(files=paths,trainer=trainer)

tokenizer.model.save(model_dir)
merges=open(model_dir+'/merges.txt','w')
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可以通过以下代码实现:

import torch
import os
import shutil
print(torch.cuda.is_available())

############################################################
from pathlib import Path
from tokenizers import ByteLevelBPETokenizer

repo_name="data/out"

model_dir='Language-Model-Roberta'
if(os.path.exists(model_dir)):
    shutil.rmtree(model_dir)
os.mkdir(model_dir)

paths = [str(x) for x in Path(repo_name).glob("**/*.static")]
tokenizer = ByteLevelBPETokenizer()
tokenizer.train(files=paths, vocab_size=18_000, min_frequency=2, special_tokens=[
    "<s>",
    "<pad>",
    "</s>",
    "<unk>",
    "<mask>",
])

tokenizer.save_model(model_dir)

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

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

import torch
import os
import shutil
print(torch.cuda.is_available())

############################################################
from pathlib import Path
from tokenizers import Tokenizer
from tokenizers.models import WordLevel
from tokenizers.trainers import WordLevelTrainer

repo_name="data/out"

model_dir='Language-Model-Roberta'
if(os.path.exists(model_dir)):
    shutil.rmtree(model_dir)
os.mkdir(model_dir)

paths = [str(x) for x in Path(repo_name).glob("**/*.static2")]
tokenizer = Tokenizer(WordLevel())
trainer = WordLevelTrainer(special_tokens=[
    "<s>",
    "<pad>",
    "</s>",
    "<unk>",
    "<mask>",
])

from tokenizers.pre_tokenizers import Whitespace
tokenizer.pre_tokenizer = Whitespace()

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的过程,训练部分的完整代码是:

import torch
import os
import shutil
print(torch.cuda.is_available())

############################################################
from pathlib import Path
from tokenizers import Tokenizer
from tokenizers.models import WordLevel
from tokenizers.trainers import WordLevelTrainer

repo_name="data/out"

model_dir='Language-Model-Roberta'
if(os.path.exists(model_dir)):
    shutil.rmtree(model_dir)
os.mkdir(model_dir)

paths = [str(x) for x in Path(repo_name).glob("**/*.static2")]
tokenizer = Tokenizer(WordLevel())
trainer = WordLevelTrainer(special_tokens=[
    "<s>",
    "<pad>",
    "</s>",
    "<unk>",
    "<mask>",
])

from tokenizers.pre_tokenizers import Whitespace
tokenizer.pre_tokenizer = Whitespace()

tokenizer.train(files=paths,trainer=trainer)

tokenizer.model.save(model_dir)
merges=open(model_dir+'/merges.txt','w')

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

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

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340