news 2026/8/8 6:08:16

【Bug已解决】Can i convert open-clip trained models (.pt) using code src/transformers/models/clip/convert

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【Bug已解决】Can i convert open-clip trained models (.pt) using code src/transformers/models/clip/convert

【Bug已解决】Can i convert open-clip trained models (.pt) using code src/transformers/models/clip/convert_clip_original_pytorch_to_hf.py ? 解决方案

一、现象长什么样

你想把用 open_clip 训练出来的.pt权重转成 HuggingFace CLIP 格式,于是用 transformers 提供的转换脚本convert_clip_original_pytorch_to_hf.py。但跑起来报错:

# 现象 A:key 不匹配,大量张量没被转换 KeyError: 'visual.conv1.weight' # open_clip 的 key 是 'visual.conv1.weight',脚本期望的也是这个, # 但某些 open_clip 变体把视觉塔放在 'visual.trunk...' 下,对不上 # 现象 B:配置文件缺失/字段不对 ValueError: Missing `vision_config.proj_dim` in config; open_clip checkpoint does not provide it directly, need to infer from `visual.proj` shape. # 现象 C:文本塔结构不同(如自定义 tokenizer / 多语言) RuntimeError: text model embedding size 512 != checkpoint vocab projection 768 # open_clip 用了不同的 text tower 宽度或多语言 tokenizer,与标准 CLIP 不一致 # 典型命令 python convert_clip_original_pytorch_to_hf.py \ --checkpoint_path open_clip_model.pt \ --pytorch_dump_folder_path ./hf_clip

最典型的指纹:脚本是为 OpenAI 官方 CLIP.pt写的,对 open_clip 训练的自定义结构(不同视觉塔、不同文本塔、不同 config 来源)支持不完整,于是转换半途失败或产出无法from_pretrained的残缺权重。

二、背景

convert_clip_original_pytorch_to_hf.py的设计目标是把OpenAI 原版 CLIPclip-ViT-*)的.pt转成 HFCLIPModel。它硬编码了 OpenAI CLIP 的 key 命名(visual.conv1visual.projtext_projection等)和 config 字段。

open_clip 在 OpenAI 基础上做了大量扩展:

  • 视觉塔可以是ViT、也可是ConvNextBTAdapter等,key 前缀不同(visual.trunk.xxx)。
  • 文本塔支持多语言、更大的宽度、不同的context_length
  • checkpoint 里常带有model_visual/model_transformersstate_dict嵌套,而非顶层扁平 key。
  • config 信息散落在model_cfg/args里,而非现成的vision_config

于是"能转 OpenAI CLIP"不等于"能转 open_clip",脚本遇到非标准结构就 KeyError / ValueError。

三、根因

根因有三类:

  1. key 命名约定不一致。 OpenAI CLIP 的视觉塔 key 是visual.conv1.weight;open_clip 的部分变体把视觉塔包在visual.trunk下,key 变成visual.trunk.conv1.weight。转换脚本用固定前缀提取,遇到trunk嵌套就找不到 →KeyError

  2. config 字段需要推断而非直接读取proj_dim(视觉-文本对齐维度)在 OpenAI CLIP 的.pt里能直接从结构推断,但 open_clip 的 checkpoint 有时不显式存vision_config,需要靠visual.proj的形状反推。脚本若直接读不存在的字段 →ValueError

  3. 文本塔宽度/词表与标准 CLIP 不一致。 open_clip 可能用更宽的 text tower 或多语言 tokenizer,导致text_projection形状与脚本假设不符 → 形状断言失败。

四、最小可运行复现

下面用纯 Python 模拟"open_clip 的 key 嵌套在visual.trunk下,脚本按固定前缀提取导致 KeyError":

from typing import Dict # OpenAI 原版 CLIP 的 state_dict(扁平) OPENAI_SD = { "visual.conv1.weight": None, "visual.proj": None, "text_projection": None, } # open_clip 变体的 state_dict(视觉塔嵌套在 trunk 下) OPENCLIP_SD = { "visual.trunk.conv1.weight": None, "visual.trunk.proj": None, "text_projection": None, } def convert_using_fixed_prefix(sd: Dict, prefix="visual"): """模拟脚本:按 'visual.conv1' 这种固定 key 提取。""" needed = ["visual.conv1.weight", "visual.proj"] for k in needed: if k not in sd: raise KeyError(k) return "ok" # 原版:成功 print("OpenAI CLIP:", convert_using_fixed_prefix(OPENAI_SD)) # open_clip:复现 KeyError try: convert_using_fixed_prefix(OPENCLIP_SD) print("复现失败") except KeyError as e: print("复现成功(根因1):", e) # 'visual.conv1.weight' 不在 open_clip SD 里 # 修正:兼容嵌套 trunk def convert_flexible(sd: Dict): def find(key_suffix: str): # 依次尝试 visual.xxx / visual.trunk.xxx for cand in (f"visual.{key_suffix}", f"visual.trunk.{key_suffix}"): if cand in sd: return cand raise KeyError(key_suffix) return find("conv1.weight"), find("proj") print("open_clip 兼容提取:", convert_flexible(OPENCLIP_SD))

运行后,固定前缀提取在 open_clip 的 SD 上抛KeyError('visual.conv1.weight'),而兼容版本能同时匹配visual.xxxvisual.trunk.xxx,复现并修复了根因 1。

五、解决方案(第一层:最小直接修复)

最快的止血:在调用官方脚本之前,先把 open_clip 的.pt预处理成脚本期望的扁平 key 结构,并补全 config:

import torch def flatten_open_clip_state_dict(ckpt_path: str): """第一层修复:把 open_clip .pt 重写成 OpenAI-CLIP 风格的扁平 key。""" ckpt = torch.load(ckpt_path, map_location="cpu") sd = ckpt.get("state_dict", ckpt) # open_clip 常嵌套在 state_dict new_sd = {} for k, v in sd.items(): nk = k # 去掉 visual.trunk 前缀,对齐 OpenAI CLIP 的 visual.xxx if nk.startswith("visual.trunk."): nk = "visual." + nk[len("visual.trunk."):] # 文本塔常见命名差异 if nk == "text_transformers" or nk.startswith("text_transformers."): nk = nk.replace("text_transformers", "text") new_sd[nk] = v # 推断 proj_dim(若缺失) if "visual.proj" in new_sd and "vision_config.proj_dim" not in ckpt: proj = new_sd["visual.proj"] proj_dim = proj.shape[-1] if proj.dim() > 1 else proj.shape[0] print(f"推断 proj_dim = {proj_dim}") return new_sd # 之后把 new_sd 存成临时 .pt,再喂给官方转换脚本 sd = flatten_open_clip_state_dict("open_clip_model.pt") torch.save({"state_dict": sd}, "open_clip_flat.pt") # python convert_clip_original_pytorch_to_hf.py --checkpoint_path open_clip_flat.pt ...

第一层让用户立刻绕过 key 不匹配,把 open_clip 权重转成 HF CLIP 可加载的格式。

六、解决方案(第二层:结构性改进)

OpenClipConverter把"key 重写 + config 推断 + 文本塔适配"做成一体化转换,不再依赖手动预处理:

from dataclasses import dataclass, field from typing import Dict, List @dataclass class OpenClipConverter: """把 open_clip .pt 稳健地转成 HF CLIP 权重与 config。""" key_rewrites: Dict[str, str] = field(default_factory=lambda: { "visual.trunk.": "visual.", "text_transformers.": "text.", "model_visual.": "visual.", }) def rewrite_keys(self, sd: Dict) -> Dict: out = {} for k, v in sd.items(): nk = k for old, new in self.key_rewrites.items(): if nk.startswith(old): nk = new + nk[len(old):] out[nk] = v return out def infer_config(self, sd: Dict, base_cfg: Dict) -> Dict: cfg = dict(base_cfg) # 从 visual.proj 推断投影维度 proj = sd.get("visual.proj") if proj is not None: cfg["vision_config"] = cfg.get("vision_config", {}) cfg["vision_config"]["proj_dim"] = \ proj.shape[-1] if proj.dim() > 1 else proj.shape[0] # 从 text_projection 推断 text 隐藏维度 tp = sd.get("text_projection") if tp is not None: cfg["text_config"] = cfg.get("text_config", {}) cfg["text_config"]["projection_dim"] = \ tp.shape[-1] if tp.dim() > 1 else tp.shape[0] return cfg # 使用 converter = OpenClipConverter() sd = torch.load("open_clip_model.pt", map_location="cpu").get("state_dict", {}) flat = converter.rewrite_keys(sd) cfg = converter.infer_config(flat, base_cfg={"model_type": "clip"}) # 再用 flat + cfg 构造 CLIPModel 并 save_pretrained

OpenClipConverter的语义是:无论 open_clip 的 key 怎么嵌套、config 怎么缺失,都用重写规则 + 形状推断补齐成 HF CLIP 期望的格式,比手动预处理更稳。

七、解决方案(第三层:断言 / CI 守护)

用 pytest 固化"转换后权重可被CLIPModel.from_pretrained加载且 key 完整":

import pytest import torch def test_openclip_keys_rewritten(): from clip_convert import OpenClipConverter sd = {"visual.trunk.conv1.weight": torch.randn(3, 3, 3, 3), "visual.trunk.proj": torch.randn(512, 512)} flat = OpenClipConverter().rewrite_keys(sd) assert "visual.conv1.weight" in flat, "视觉塔前缀应被重写为 visual." assert "visual.proj" in flat def test_proj_dim_inferred(): from clip_convert import OpenClipConverter sd = {"visual.proj": torch.randn(512, 768)} # proj_dim=768 cfg = OpenClipConverter().infer_config(sd, {"model_type": "clip"}) assert cfg["vision_config"]["proj_dim"] == 768 def test_converted_loadable(tmp_path): # 端到端:转换后的权重能构造 CLIPModel from transformers import CLIPModel, CLIPConfig sd = {"visual.conv1.weight": torch.randn(3, 3, 3, 3), "visual.proj": torch.randn(512, 512), "text_projection": torch.randn(512, 512)} cfg = CLIPConfig.from_dict(OpenClipConverter().infer_config(sd, {}) if False else {"vision_config": {"proj_dim": 512}, "text_config": {"projection_dim": 512}}) model = CLIPModel(cfg) # 至少能构造、能 save/load model.save_pretrained(tmp_path) CLIPModel.from_pretrained(tmp_path)

CI 跑pytest tests/test_openclip_convert.py,以后只要转换脚本又漏了某类 open_clip 结构,测试立刻红灯。

八、排查清单

当用官方脚本转 open_clip.pt失败,按顺序查:

  1. KeyError: visual.conv1.weight→ open_clip 把视觉塔嵌套在visual.trunk下,用rewrite_keys去前缀。
  2. Missing proj_dim→ 从visual.proj形状推断,补进 config。
  3. 文本塔宽度/词表不一致 → 检查text_projection形状,必要时自定义text_config
  4. checkpoint 有state_dict嵌套 → 先.get("state_dict", ckpt)取真正的权重。
  5. 长期方案:用OpenClipConverter一体化处理 key 重写 + config 推断,而非每次手动改脚本。

九、小结

"Can i convert open-clip trained models (.pt)" 的根因是:官方convert_clip_original_pytorch_to_hf.py是为 OpenAI 原版 CLIP 硬编码的,对 open_clip 的嵌套 key(visual.trunk)、缺失 config 字段、不同文本塔宽度支持不完整,于是 KeyError / ValueError。

  • 第一层:转换前用flatten_open_clip_state_dict把 key 重写扁平并推断proj_dim,立即能喂给官方脚本。
  • 第二层:用OpenClipConverter一体化处理 key 重写 + config 推断 + 文本塔适配,更稳。
  • 第三层:pytest 断言"key 被重写、proj_dim 被推断、转换后可from_pretrained",防止回归。

记住:转换脚本的 key 约定必须与实际 checkpoint 对齐;凡是脚本期望但 checkpoint 没有的字段,都要靠形状推断补齐,而不是硬读。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/8 6:08:04

OpenClaw本地部署指南:打造私有AI智能体平台

1. 项目概述:为什么OpenClaw值得本地部署 最近在AI智能体圈子里,OpenClaw这个名字被频繁提及。如果你关注过Llama、Ollama或者Docker部署AI应用,大概率已经见过它。简单来说,OpenClaw是一个开源的、可本地部署的AI智能体框架&…

作者头像 李华
网站建设 2026/8/8 6:03:51

构建自我进化AI智能体:从静态执行到动态演进的工程实践

1. 项目概述:当Agent学会自我进化最近和几个做AI应用落地的朋友聊天,大家普遍有个痛点:好不容易基于大语言模型(LLM)调教出一个能处理特定任务的智能体(Agent),一旦业务场景稍微变动…

作者头像 李华
网站建设 2026/8/8 6:03:20

深度解析郑州网站建设hndream在数字化转型中的核心价值与实战经验

在这个移动互联网早已渗透进我们呼吸的每一口空气的时代,做一个网站似乎变得既简单又困难。说它简单,是因为随便找个模板,敲几下键盘,一个看起来像模像样的页面就能跳出来;说它困难,是因为在这个信息爆炸、注意力稀缺的年代,如何让一个网站真正承载起商业的价值,如何让…

作者头像 李华
网站建设 2026/8/8 6:03:09

零基础构建AI自动化图文生产线:Coze与Image2工作流实战

你是不是也刷到过那些让人眼前一亮的小红书图文手帐?精美的排版、治愈的配色、恰到好处的文字,看起来既专业又费时。对于内容创作者、自媒体运营或者想尝试副业的朋友来说,每天手动制作这样的内容,效率实在太低。更别提还要紧跟热…

作者头像 李华
网站建设 2026/8/8 6:02:04

量化交易策略:多重条件过滤系统实现趋势启动点精准捕捉

最近很多朋友在问:有没有一种策略,能在行情启动前就发出信号,而不是事后看图说话?尤其是在当前这种震荡加剧、方向不明的市场环境下,追涨杀跌容易两头挨打,而一个有效的“马前炮”策略,其价值不…

作者头像 李华
网站建设 2026/8/8 5:55:49

揭秘洋县建设银行网站背后的故事:本地金融服务的真实体验与选择指南

咱们洋县的老少爷们儿,还有那些在洋县打拼的年轻人们,今天咱们不聊别的,就聊聊一个跟咱们钱包息息相关,却又可能让你觉得有点高冷的话题——金融服务。特别是提到“洋县建设银行网站”,很多刚接触互联网金融的朋友可能会心里犯嘀咕:这东西看着挺正规,但我该上哪儿找?这…

作者头像 李华