自定义BPE分词器用于RoBERTa预训练时去掩码出现多余空格问题
问题原因与解决办法
核心原因
你的自定义分词器和原生RoBERTa的核心配置不一致,导致解码时出现多余空格:
- 原生RoBERTa的
RobertaProcessing默认开启add_prefix_space=True,这个参数会让分词器给除句首外的所有词添加前缀空格对应的BPE标记(以Ġ开头的token),模型预训练时已经习惯这种词边界信号。 - 你设置了
add_prefix_space=False,但输入中<mask>前的空格会被分词器处理为独立的词边界信号,模型预测出的结果是带Ġ的token(对应前缀空格),解码时这个Ġ会转成空格,加上原句中已有的空格,就出现了两个连续空格。 - 当你把
<mask>和前面的词连写时,没有额外空格,模型预测的是不带Ġ的token,解码后自然不会多出空格。 clean_up_tokenization_spaces=True没用是因为这个参数只负责清理tokenization过程中产生的冗余空格,不处理解码时BPE标记转义出的空格。
解决办法
1. 修正分词器配置(推荐,需重新训练)
对齐原生RoBERTa的post processor配置,修改add_prefix_space=True,同时确保special tokens的设置完全匹配:
from tokenizers.models import BPE from tokenizers import ByteLevelBPETokenizer from tokenizers.processors import RobertaProcessing from tokenizers import normalizers tokenizer = ByteLevelBPETokenizer() tokenizer.normalizer = normalizers.BertNormalizer(lowercase=False) # 原生RoBERTa的special tokens顺序是["<s>", "<pad>", "</s>", "<unk>", "<mask>"],训练时直接包含 tokenizer.train_from_iterator( Data_full, vocab_size=50264, min_frequency=2, special_tokens=["<s>", "<pad>", "</s>", "<unk>", "<mask>"] ) # 启用原生RoBERTa的post processor配置 tokenizer.post_processor = RobertaProcessing( sep=("</s>", 2), cls=("<s>", 0), trim_offsets=False, add_prefix_space=True # 改为True,对齐原生配置 ) tokenizer.enable_padding( direction='right', pad_id=1, pad_type_id=1, pad_token="<pad>", length=512 )
修改后重新训练分词器和RoBERTa模型,就能和原生行为一致,不会出现多余空格。
2. 临时修复(无需重新训练)
如果暂时不想重新训练,可以在fill-mask的输出后手动清理多余空格:
result = unmasker("Capital of France is <mask>.") # 处理每个预测结果的文本 cleaned_result = [ {"sequence": res["sequence"].replace(" ", " "), **res} for res in result ] print(cleaned_result[0]["sequence"]) # 输出:Capital of France is Paris.
但这种方法属于治标不治本,可能在复杂文本中出现误处理,优先推荐第一种方法。
内容的提问来源于stack exchange,提问作者Eghbal
相关产品推荐
相关产品推荐

