You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 00:12:42