Tokenizer adds an additional space after the added token

这个报错通常发生在使用基于 SentencePiece/Metaspace 的 tokenizer(如 NLLB-200)并通过 add_tokens() 添加词表外片段后,当新增 token 后面紧跟其他字符(而不是空格)时,tokenizer 会在新增 token 之后额外插入一个空格。优先排查

快速结论:这个报错通常发生在使用基于 SentencePiece/Metaspace 的 tokenizer(如 NLLB-200)并通过 add_tokens() 添加词表外片段后,当新增 token 后面紧跟其他字符(而不是空格)时,tokenizer 会在新增 token 之后额外插入一个空格。优先排查 tokenizer 的 prepend_scheme 配置与新增 token 的边界处理。

适用环境:Transformers 4.35.2;Linux x86_64(glibc2.35);Python 3.10.12;huggingface_hub 0.19.4;safetensors 0.4.1;accelerate 0.25.0;PyTorch 2.1.0+cu121(脚本未使用 GPU);TensorFlow 2.15.0;Flax 0.7.5(CPU);Jax/JaxLib 0.4.23。复现模型为 facebook/nllb-200-distilled-600M,使用自定义脚本复现。

最快修复方案:在加载 tokenizer 后,将 pre_tokenizers 的 Metaspace 配置改为 prepend_scheme="first"(Issue 维护者给出的手动修复写法:tokenizer.pre_tokenizers.Metaspace(replacement="▁", add_prefix_space=True, prepend_scheme="first")),可优先尝试。Issue 中确认的彻底修复方向是在 tokenization_nllb.py 中把 Metaspace(prepend_scheme="always") 改为 prepend_scheme="first",并参照 convert_slow_tokenizer.py 中的 _get_prepend_scheme 做向后兼容处理。

注意事项:维护者明确表示完整修复属于破坏性变更(breaking change),因此默认行为不会改变,只能手动开启;该行为已存在多年,改动后可能与既有训练模型的分词结果不完全一致,使用前应自行评估影响。上述手动改写属于 Issue 中所述修复方向,尚未在评论中给出回归测试结果,建议在正式使用前用自己的数据验证。

问题场景

用户使用 AutoTokenizer 加载 facebook/nllb-200-distilled-600M,并指定 src_lang="eng_Latn"、tgt_lang="zho_Hans",随后调用 tokenizer.add_tokens(["abcd"]) 添加自定义 token。当输入文本中新增 token 后面紧跟其他字符(例如 abcdgym)而不是空格时,分词与解码结果会在新增 token 之后多出一个空格;而新增 token 后面本来就有空格时表现正常。用户的实际目标是给中文添加 token,因为中文词语之间没有空格分隔。

报错原文

Tokenizer adds an additional space after the added token

复现输出表现为:'abcdgym' 解码为 'abcd gym'(新增 token 后被插入一个空格)。

原因分析

根据 Issue 中的定位,原因可能在于 NLLB 的 src/transformers/models/nllb/tokenization_nllb.py 使用了 Metaspace(prepend_scheme="always") 作为 pre-tokenizer/decoder,它会在每个切分前加上 ▁,包括新增 token 之后紧接着的文本,从而在解码时表现为多出一个空格。同仓库中的 SeamlessM4T(tokenization_seamless_m4t.py)已使用 prepend_scheme="first"。由于新增 token 会在分词算法应用前被单独隔离处理,这一点也可能放大了该现象。

环境排查

  • 确认 Transformers 版本(Issue 复现为 4.35.2),以及问题在 main 分支上是否仍然复现。
  • 确认 tokenizer 型号为 NLLB 系列(facebook/nllb-200-distilled-600M),并检查其 pre_tokenizers 中 Metaspace 的 prepend_scheme 取值。
  • 确认新增 token 是否位于词中间且后面不跟空格,这是触发问题的关键输入形态。
  • 确认是否与其他已添加 token 存在重叠(例如 abcd 与 gyma 同时出现在 gymabcd 中),Issue 指出当前实现按从左到右匹配,重叠优先级尚无法可靠控制。
  • Python、PyTorch、CUDA 版本与本问题无直接因果关系,Issue 未给出与这些版本相关的证据。

解决步骤

  1. 用 AutoTokenizer.from_pretrained 正常加载 NLLB tokenizer,并调用 add_tokens() 添加自定义 token。
  2. 在分词前手动调整 pre-tokenizer,将其 Metaspace 设为 prepend_scheme="first":tokenizer.pre_tokenizers.Metaspace(replacement="▁", add_prefix_space=True, prepend_scheme="first")。这是维护者在关闭 Issue 时给出的手动修复写法,可优先尝试。
  3. 如果希望从源码层面修复,可将 tokenization_nllb.py 中的 prepend_scheme="always" 改为 "first",并参照 convert_slow_tokenizer.py 中 _get_prepend_scheme 的做法,用 legacy 风格判断保证向后兼容;同时补充对应测试。
  4. 如需在改动前规避,可让新增 token 后面始终保留空格,但这对中文等无空格文本不适用,仅作为临时对照。
  5. 若涉及多个可重叠的新增 token,注意当前无法指定分词优先级,维护者表示会先检查最长匹配,但 Issue 中未确认可靠的可配置方案。

验证方法

用 Issue 中的复现脚本重新分词并解码:对 'I like to walk abcdgym along the beach' 和 'I like to walk gymabcd along the beach',检查 tokenizer.decode(tokenizer.encode(sent)[1:-1]) 的输出中新增 token 之后是否仍被插入空格。若 'abcdgym' 不再解码为 'abcd gym',且原有带空格场景的行为未发生意外变化,即可认为修复生效。

参考来源

huggingface/transformers #28218

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 29662

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注