我使用以下参数创建了一个自定义 BPE 标记器来预训练 Roberta 模型(我尝试将其与 RoBERTa 的 BPE 默认参数对齐。):
from tokenizers.models import BPE
from tokenizers import ByteLevelBPETokenizer
from tokenizers.processors import RobertaProcessing
tokenizer = ByteLevelBPETokenizer()
tokenizer.normalizer = normalizers.BertNormalizer(lowercase = False)
tokenizer.train_from_iterator(Data_full, vocab_size = 50264, min_frequency = 2, special_tokens = ["<s>", "<pad>", "</s>", "<unk>"])
tokenizer.add_special_tokens(["<mask>"])
tokenizer.post_processor = RobertaProcessing(sep = ("</s>", 2), cls = ("<s>", 0), trim_offsets = False, add_prefix_space = False)
tokenizer.enable_padding(direction = 'right', pad_id = 1, pad_type_id = 1, pad_token = "<pad>", length = 512)
当使用此分词器预训练 Roberta 模型时,我在揭露过程中观察到异常行为:
from tokenizers import Tokenizer
from transformers import pipeline
from transformers import RobertaTokenizerFast
tokenizer_in = Tokenizer.from_file('tokenizer_file')
tokenizer_m = RobertaTokenizerFast(tokenizer_object=tokenizer_in, clean_up_tokenization_spaces=True)
unmasker = pipeline('fill-mask', model=model_m, tokenizer = tokenizer_m)
unmasker("Capital of France is <mask>.")
输出始终如下所示:
Capital of France is Paris
。我对“Paris”之前持续存在的额外空格感到好奇。我相信激活 clean_up_tokenization_spaces
选项可能会解决这个问题。我的代码中是否存在导致此问题的错误?所有解锁任务都会发生这种情况。另外,当我使用像 unmasker("Capital of France is<mask>.")
这样的命令进行测试时,质量提高了,问题似乎得到了解决。
为了消除歧义,尤其是单词开头与单词片段的歧义,分词器可以使用前导空格。
"Paris"
和 " Paris"
是两个不同的(集合)令牌,也是两个不同的嵌入。
理想情况下,模型可以区分这两种情况:
("is") -> " Paris"
("is", " ") -> "Paris"
但是,如您所见,这里的情况并非如此。 (非常)粗略地说,由于前导空格在句子结构
... in Paris
与 "Paris is ..."
中出现的频率更高,因此模型在 " Paris"
标记中比在 Paris
标记中更加确定。我假设具有更多参数(或更具体的预训练)的模型可以更好地消除这两种情况之间的歧义。
TL;DR:取消屏蔽不会创建任意前导空格。当
" Paris"
不在句子开头时,它就是要走的标记,并且掩码也应包含前导空格。
注意:
clean_up_tokenization_spaces
与标点符号特别相关,例如" ?" -> "?", " ,"->","
。我认为对于常见的分词器来说它是 True,因为 False 会创建更不自然的句子。
它不会清理普通单词的前导空格。