`FlowMatchEulerDiscreteScheduler.set_timesteps` silently ignores explicit `timesteps` since #14011 — intended semantics change or unreleased

当你在 diffusers 里调用 FlowMatchEulerDiscreteScheduler.set_timesteps(...) 并 同时传入 自定义 sigmas 与 timesteps 时(例如 CogView4 / GLM-Image 推理管线),显式的 timesteps 会被静默丢

快速结论:当你在 diffusers 里调用 FlowMatchEulerDiscreteScheduler.set_timesteps(...) 并同时传入自定义 sigmas 与 timesteps 时(例如 CogView4 / GLM-Image 推理管线),显式的 timesteps 会被静默丢弃,调度器只按 shift 后的 sigmas 重算时间步。优先确认你使用的是 main(#14011 之后的代码)还是已发布版本。

适用环境:Issue 讨论围绕 huggingface/diffusers,涉及调度器 FlowMatchEulerDiscreteScheduler、FlowMatchLCMScheduler,以及 CogView4 / CogView4-Control / GLM-Image 管线。讨论中引用的 main commit 为 614ae4b;#14011 于 2026-07-07 合并,未进入任何发布版(v0.39.0 早于该 PR)。Issue 未提供 Python / CUDA / 显卡 / 依赖版本信息,这些未验证项不应擅自补写。

最快修复方案:暂无确认的一步修复方案。Issue 中提问者表示已准备两个方向的 PR(对齐语义或恢复显式 timesteps 分支),但截至讨论结束尚未由维护者确认采用哪一个。

注意事项:该行为仅发生在 sigmas 与 timesteps 同时传入的场景;只传 timesteps(不传 sigmas)时,时间步仍会作为网格种子并经 shift 返回,这属于 #14011 针对 SD3/Flux 的预期改动,不要误判为回归。修复方向未定,自行打补丁前请先确认维护者的结论。

问题场景

使用 diffusers 的 FlowMatchEulerDiscreteScheduler 且运行 CogView4、CogView4-Control 或 GLM-Image 相关管线时触发。这些管线会刻意同时传入整数化(integer-cast)的 timesteps 与配对的 sigmas(该机制由作者在 #10649 加入),并把 scheduler.timesteps 作为 conditioning 喂给 transformer。在 main(#14011 之后)上,传入的 timesteps 被忽略,conditioning 值与预期产生偏差。在 CogView4-6B 配置、1024×1024、10 步下,偏差最高可达 285.75 / 1000。

报错原文

FlowMatchEulerDiscreteScheduler.set_timesteps silently ignores explicit `timesteps` since #14011 — intended semantics change or unreleased

passed   : [1000.0, 889.0, 778.0, 667.0, 556.0, 445.0, 334.0, 223.0, 112.0, 1.0]
got      : [1000.0, 963.0, 919.29, 866.84, 802.75, 722.67, 619.75, 482.6, 290.73, 3.24]
max delta: 285.75

原因分析

自 #14011 合并(2026-07-07,尚未进入任何发布版)后,FlowMatchEulerDiscreteScheduler.set_timesteps 会无条件地根据 shift 后的 sigmas 重新计算 timesteps,因此显式传入的自定义 timesteps 列表被静默丢弃。可能的证据矛盾点包括:

  • docstring 仍声明 timesteps 是「Custom values for timesteps to be used for each diffusion step」,与实际行为不符。
  • 变量 is_timesteps_provided 变成 dead code。
  • 另一个 flow-match 调度器 FlowMatchLCMScheduler 在同样输入下仍会返回传入的 timesteps,导致两个调度器对同一参数的行为不一致。

讨论中的关键区分:只在同时传入 sigmas 与 timesteps时,timesteps 才完全无效(同一组 sigmas 配不同 timesteps,包括 [0.0]*10、反转列表或 None,输出逐位相同)。若只传 timesteps 不传 sigmas,则传入值会作为网格种子并被 shift,这正是 #14011 面向 SD3/Flux 的预期语义。因此本问题是否是「有意的语义变更」还是「未发布的回归」,需由维护者裁定。

环境排查

  • 确认当前 diffusers 版本:是已发布版(v0.39.0 及更早,受 #14011 影响前的旧行为)还是 main / #14011 之后的代码。
  • 确认是否在调用 set_timesteps 时同时传入了 sigmas 与 timesteps(只有这种组合才会出现静默丢弃)。
  • 确认所使用的调度器:FlowMatchEulerDiscreteScheduler 与 FlowMatchLCMScheduler 在同一参数下行为不同,需分别核对。
  • 若走 CogView4 / CogView4-Control / GLM-Image 管线,核对调度器 config(如 use_dynamic_shifting、mu、base_shift、max_shift 等)与 pipeline 传入的 timesteps / sigmas。
  • Issue 未提供 Python、CUDA、PyTorch、显卡型号与驱动版本,这些不属于已确认环境,请勿直接套用具体版本号。

解决步骤

  1. 先打印 sigmas 与 timesteps 的输入、输出,确认是否出现「input sigmas 被 shift、output timesteps == output sigmas * 1000、显式 timesteps 无任何影响」的现象。
  2. 用同一组 sigmas 配不同的 timesteps(管线值、[0.0]*10、反转列表、None)对比输出;若逐位相同,则确认属于「显式 timesteps 被丢弃」的情况。
  3. 确认当前 diffusers 是来自 main 还是发布版:若需要旧行为(显式 timesteps 生效),可临时回退到 v0.39.0 或 #14011 之前的 commit。
  4. 关注上游修复方向:提问者准备了两个方向的 PR(若「丢弃是有意语义」则同步 docstring、清理 dead code、对齐 FlowMatchLCMScheduler 与管线整数化逻辑;若「非有意」则在保留 #14011 对 timesteps-only 场景重算的前提下,恢复同时传入时的显式 timesteps 分支)。在维护者表态前,不要盲目采用其中任一补丁。
  5. 如自行临时修改源码,仅在「同时传入 sigmas 与 timesteps」的分支中保留显式值,且不要改动 timesteps-only 场景下的重算逻辑,以免引入 #14011 之外的新偏差。

验证方法

在目标环境下用问题中的复现脚本(CogView4-6B 配置、1024×1024、10 步、mu=3.25)运行,检查 sched.timesteps.tolist() 是否等于传入的 [1000.0, 889.0, 778.0, 667.0, 556.0, 445.0, 334.0, 223.0, 112.0, 1.0]。若已修复,同时应满足:output sigmas 仍等于 time_shift(mu, 1.0, input sigmas)(即 shift 行为未被破坏),且只传 timesteps 不传 sigmas 的 SD3/Flux 场景行为与 #14011 之后保持一致。

参考来源

huggingface/diffusers #14461

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 27609

发表回复

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