Inconsistency between the tokenization of `CLIPTokenizer` and `CLIPTokenizerFast` with `openai/clip-vit-base-patch32`

当你在 Transformers 中同时加载 CLIPTokenizer 与 CLIPTokenizerFast (模型 openai/clip-vit-base-patch32 )并对比同一段文本的 token 时,二者输出不一致,通常表现为 fast 版本多出 Ġ 或把 1 这类单字符数字拆得与

快速结论:当你在 Transformers 中同时加载 CLIPTokenizerCLIPTokenizerFast(模型 openai/clip-vit-base-patch32)并对比同一段文本的 token 时,二者输出不一致,通常表现为 fast 版本多出 Ġ 或把 1 这类单字符数字拆得与 slow 版本不同。优先排查是否误用了 fast tokenizer,以及是否通过 from_slow=True 从 slow 转换生成 fast。

适用环境:Issue 中确认的环境为 transformers 4.8.2、Linux(Ubuntu 18.04 bionic)、Python 3.7.10、PyTorch 1.9.0+cu102(未使用 GPU)、TensorFlow 2.5.0(未使用 GPU)、未安装 Flax/JAX;脚本未使用 GPU,也未使用分布式或并行设置。

最快修复方案:暂无确认的一步修复方案。Issue 中尚未合并官方修复;如果只是想让 fast 版本尽量接近 slow 版本,可优先尝试将 CLIPConverter 中的 tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=False) 替换为 WhitespaceSplitByteLevel 组成的 Sequence 预分词器,但这种做法仍不能完全对齐。

注意事项:上述预分词器替换来自 Issue 中的临时方案,作者本人也说明“接近但不完全匹配正确行为”。此外,CLIP 的 BPE 与 GPT-2 不同,空格处理方式不同;原始 CLIP 还使用 ftfy 修复噪声文本,这也会影响 tokenization,目前尚不确定 fast tokenizer 能否完整支持。

问题场景

用户在 Transformers 中加载 CLIP 相关的 slow 与 fast tokenizer,并使用 openai/clip-vit-base-patch32 对同一段文本进行编码。对比对象包括 Hugging Face 的 CLIPTokenizerCLIPTokenizerFast,以及 OpenAI 原始 CLIP 仓库中的 tokenizer。用户期望 slow 与 fast 版本输出相同的 token。

报错原文

Inconsistency between the tokenization of `CLIPTokenizer` and `CLIPTokenizerFast` with `openai/clip-vit-base-patch32`

(tokens_ids_orig == tokens_ids_fast).sum() == context_length

原因分析

Issue 讨论中列出了几个导致不一致的原因:fast tokenizer 使用了 ByteLevel decoder,没有去除词尾后缀 </w>,改用 BPEDecoder 可以解决;CLIP 使用 boseos token,但当前后处理器是 ByteLevel,不会添加这些 token,改用 TemplateProcessing 可以解决;与 GPT-2 的 BPE tokenizer 不同,CLIP 的 BPE 不用 Ġ 表示空格,而是在解码时用空格替换 </w>,但 tokenizers 中的 BPE 似乎总把空格替换为 Ġ,这是剩余问题之一。

后续排查还指出,问题不只限于空格被替换为 Ġ。CLIP 原始代码中的正则预分词会诱导特定切分,fast tokenizer 需要能复现该切分,否则 12 等单字符数字的切分仍可能不同。另外,CLIP 使用 ftfy 修复文本,这也会改变 tokenization;这一点在 fast tokenizer 中如何支持尚不明确。

环境排查

  • 确认 transformers 版本是否为 4.8.2 或受影响版本。
  • 确认 Python 版本是否为 Issue 中的 3.7.10,或其他兼容版本。
  • 确认 PyTorch 版本是否为 1.9.0+cu102,实际是否使用 GPU。
  • 确认是否安装了 TensorFlow 2.5.0,是否启用 GPU。
  • 确认是否安装 Flax/JAX;Issue 环境中未安装。
  • 确认加载方式:是否直接 CLIPTokenizerFast.from_pretrained(...),还是使用 from_slow=True 转换生成。
  • 确认模型名是否为 openai/clip-vit-base-patch32,以及是否与 OpenAI 原始 CLIP 对比。
  • 确认是否使用 ftfy 对文本做预处理,以及预处理是否发生在 tokenization 之前。

解决步骤

  1. 先复现 slow 与 fast 的差异:分别用 CLIPTokenizer.from_pretrained("openai/clip-vit-base-patch32")CLIPTokenizerFast.from_pretrained("openai/clip-vit-base-patch32", from_slow=True) 加载,再对同一段文本调用 tokenize()
  2. 观察 fast 输出中是否出现 Ġ,以及词尾 </w>、单字符数字等是否与 slow 不一致。
  3. 如果只是临时验证,可优先尝试 Issue 中提出的 CLIPConverter 修改:把 tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=False) 替换为包含 WhitespaceSplitByteLevel(add_prefix_space=False)pre_tokenizers.Sequence
  4. 同时检查 CLIPConverter 中 decoder 是否应改为 BPEDecoder,以及 post-processor 是否应从 ByteLevel 改为 TemplateProcessing,以覆盖 </w> 去除和 bos/eos 添加的问题。
  5. 如果业务允许,优先在生产链路中使用 slow tokenizer,直到官方修复合并。
  6. 持续关注 Issue 讨论和对应修复是否进入正式版本,不要仅依赖临时 patch。

验证方法

分别用 CLIPTokenizerCLIPTokenizerFast 对相同文本执行 tokenize()encode(),逐项比较输出的 token 序列或 token id。重点检查 fast 输出中是否还出现多余的 Ġ,单字符数字切分是否与 slow 一致,以及 bos/eos 是否正确添加。Issue 中的验证方式是对比 (tokens_ids_orig == tokens_ids_slow).sum() == context_length(tokens_ids_orig == tokens_ids_fast).sum() == context_length 的结果。在该 Issue 的临时方案下,部分示例仍不完全一致,因此不能用“完全相等”作为唯一通过标准,需要结合官方修复状态确认。

参考来源

huggingface/transformers #12648

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 24311

发表回复

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