save_pretrained can delete shards from another variant and leave stale indexes

当你在同一目录里先保存带 variant 的分片权重,再保存默认权重(或反向切换分片/单文件布局)时, save_pretrained 的旧权重清理逻辑会误删另一 variant 的分片,并可能留下过期的 index,导致原本可加载的权重再次加载时报 save_pretrained can dele

快速结论:当你在同一目录里先保存带 variant 的分片权重,再保存默认权重(或反向切换分片/单文件布局)时,save_pretrained 的旧权重清理逻辑会误删另一 variant 的分片,并可能留下过期的 index,导致原本可加载的权重再次加载时报 save_pretrained can delete shards from another variant and leave stale indexes 对应的缺文件错误。优先排查保存目录中是否存在多个 variant 混放、以及 index 与实际权重文件是否一致。

适用环境:Diffusers 0.41.0.dev0(main 分支 c5469b7);Windows 11(10.0.26200);Python 3.12.5;PyTorch 2.14.0+cpu;huggingface_hub 1.30.0;Transformers 5.16.1;Accelerate 1.14.0;safetensors 0.8.0。复现无需 GPU、无需联网下载模型,CPU 即可。

最快修复方案:暂无确认的一步修复方案。Issue 中给出的是待合并的修复范围(把清理限定到当前 variant 与序列化格式、在新保存为单文件时删除过期 index),尚未确认已合入。

注意事项:该问题影响 ModelMixin.save_pretrained 的清理逻辑,属于代码层面的缺陷;在修复合入前,仅靠重命名文件可能引入新的 index 不一致风险。Issue 中的修复方案只是提议范围,最终实现与验证以实际 PR 为准。

问题场景

在 Diffusers 中调用 ModelMixin.save_pretrained(如 UNet2DModel.save_pretrained)向同一目录多次保存模型权重时触发。典型场景:先用 variant="ema" 并设置较小的 max_shard_size 保存分片权重,确认 from_pretrained(path, variant="ema") 可正常加载;随后再向同一目录保存默认权重(不传 variant,或 max_shard_size 改为很大值使保存变为单文件),再次加载 ema 变体即失败。Issue 中另一情形是把原本分片的 checkpoint 保存为单文件,此时过期的 index 会保留,加载会按旧 index 找权重而不是新文件。

报错原文

FileNotFoundError: ...diffusion_pytorch_model-00001-of-00004.ema.safetensors

Issue 标题描述的核心问题:save_pretrained can delete shards from another variant and leave stale indexes

原因分析

可能原因:save_pretrained 中的旧权重清理循环按文件名前缀匹配分片,而不是按精确的 checkpoint 身份(variant + 序列化格式)匹配,因此保存默认权重时会把另一 variant 的分片一起删除。同时,当模型从分片布局切换为单文件保存时,原分片对应的 index(如 model.safetensors.index.json)没有同步删除,加载时仍依据旧 index 定位文件,从而出现“index 存在但权重已被删”的不一致状态。

环境排查

  • 确认 Diffusers 版本,Issue 环境为 0.41.0.dev0,commit c5469b7ceb606edd7ba6570dcd17d38590a18db6;本地版本不同则清理逻辑可能已有差异。
  • 确认保存目录内容:是否同时存在默认权重与 .ema 等 variant 分片,以及是否存在 *.index.json。
  • 确认两次 save_pretrained 的 variant 与 max_shard_size 参数,判断是否在分片与单文件之间切换。
  • 确认 PyTorch、safetensors、huggingface_hub 版本与 Issue 是否接近,便于排除其他依赖因素。
  • 该问题在 CPU、无 GPU 环境下可复现,与 CUDA、显卡无关,无需排查硬件。

解决步骤

  1. 先用 Issue 中的最小复现脚本(小型 UNet2DModel,variant="ema",先 max_shard_size="50KB" 分片保存再 max_shard_size="100MB" 默认保存)在本地确认是否能复现,避免误判环境问题。
  2. 检查保存目录中:ema 分片是否仍存在、默认权重是否写入、index 文件指向哪些权重文件,确认是否为“分片被删但 index 残留”或“单文件已生成但旧 index 未删”。
  3. 可优先尝试:在修复版本可用前,避免向同一目录反复保存不同 variant 或不同分片布局的权重,改为为每个 variant / 保存布局使用独立目录。
  4. 可优先尝试:如需在同一目录切换布局,先完整加载并重新保存到干净目录,而不是在原目录上覆盖保存。
  5. 关注 Issue 提出的修复范围是否合入(清理仅针对当前所选 variant 与序列化格式、在新保存为单文件时删除过期 index),合入后再验证。

验证方法

在干净目录中按原顺序执行“分片 + 指定 variant 保存 → 加载成功 → 默认权重保存”,随后再次用 UNet2DModel.from_pretrained(path, variant="ema") 加载,应能成功且不再出现 FileNotFoundError 指向缺失的 .ema.safetensors 分片;同时检查目录中该 variant 的分片未被删除,且在切换为单文件保存时旧 index 已被移除或与新权重一致。默认 variant 的加载也应正常。

参考来源

huggingface/diffusers #14719

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 30946

发表回复

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