Ideogram4: allow the text conditioning projection to be hoisted out of the denoising loop

当你在 diffusers 中用 Ideogram4Transformer2DModel 跑 Ideogram 4 推理(尤其 1024² 以上、启用 bitsandbytes 4 bit 量化的 llm_cond_proj )时,每个去噪步都会重复对固定的 encoder_hidden_state

快速结论:当你在 diffusers 中用 Ideogram4Transformer2DModel 跑 Ideogram 4 推理(尤其 1024² 以上、启用 bitsandbytes 4 bit 量化的 llm_cond_proj)时,每个去噪步都会重复对固定的 encoder_hidden_states 做归一化和投影,表现为显存峰值偏高甚至 OOM;核心报错描述为:Ideogram4: allow the text conditioning projection to be hoisted out of the denoising loop。优先排查:是否每步都在重复执行这段投影、能否只算一次并复用。

适用环境:Issue 中确认的复现/测量环境为:diffusers 提交 7685bffe8904;显卡 A100(2048²,峰值 26.835333 GiB)、L40S(1024²,峰值 18.189322 GiB)、A10 24 GiB(2048² 原始路径 OOM);量化路径为 bitsandbytes NF4 的 4 bit llm_cond_proj。Issue 未给出 Python、CUDA、PyTorch 版本,不要按其他版本自行假设。

最快修复方案:暂无确认的一步修复方案。Issue 讨论确认了根因是投影在 forward 内每步重复执行,并给出了“把投影提到去噪循环外、只算一次”的修改方向,但没有合入的现成补丁或官方命令。

注意事项:按 Issue 的分析,这需要 API 变更:调用方在进入 forward 之前就构造了 (1, 16896, 53248) 的条件张量;若在内部跳过被掩码的行,会改变 GEMM 的 M 维度,从而切换 NF4 kernel 并改变像素输出。要保证逐位一致,必须保留行数(例如 minimum_projection_rows)。该 opt-in 路径不兼容 torch.compile(fullgraph=True),默认路径不受影响。上述均为讨论中的设计,尚未验证为正式 API。

问题场景

用户在 24 GB 显卡上对 Ideogram 4 推理做性能分析时发现:Ideogram4Transformer2DModel.forward 每一步去噪都会重新执行 self.llm_cond_norm(encoder_hidden_states) 与 self.llm_cond_proj(encoder_hidden_states) * llm_token_mask,而 encoder_hidden_states 在整个生成过程中是固定的。条件张量宽 53,248 行,仅 512 行携带文本;在 2048² 下相当于 16,896 行里有 16,384 行被投影后丢弃,分类器自由引导(CFG)还额外带来一个全零分支。在 4 bit NF4 的 llm_cond_proj 下,这等于每一步都跑一次宽 NF4 GEMM,形成不必要的显存与算力开销。该问题以 feature-request 形式提出,讨论确认根因,标签涉及 quantization、bitsandbytes、models。

报错原文

Ideogram4: allow the text conditioning projection to be hoisted out of the denoising loop

Issue 中与显存直接相关的原始现象描述为:At 2048² the unmodified path OOMs on an A10’s 24 GiB. The hoisted path completes.

原因分析

最可能的原因是:文本条件投影被写在 forward 的每步执行路径里,而输入在整个去噪循环中不变,导致重复计算与重复显存分配。Issue 对比数据(bitsandbytes NF4,提交 7685bffe8904)显示,把投影提到循环外后,2048²(A100)峰值从 26.835333 GiB 降到 17.378107 GiB(约 −9.457 GiB),1024²(L40S)从 18.189322 GiB 降到 16.053430 GiB(约 −2.136 GiB),且在三种提示词长度、三个种子上共 18 次生成中 latents、像素与 OCR 的 SHA-256 完全一致。另需注意:窗口化跳过被掩码行虽能省 GEMM,但会改变核行为并导致像素变化,不能作为无损修复。

环境排查

  • 确认 diffusers 版本/提交是否与 Issue 的 7685bffe8904 相近,或是否已包含该投影提取改动。
  • 确认所用模型类确实是 Ideogram4Transformer2DModel,并检查 forward 中是否存在每步执行 llm_cond_norm / llm_cond_proj 的代码。
  • 确认是否启用 bitsandbytes 4 bit(NF4)量化 llm_cond_proj,非量化路径的收益未在 Issue 中测量。
  • 确认显存峰值测量分辨率:2048² 与 1024² 的增益不同,2048² 更明显。
  • 确认是否使用 torch.compile;如打算改用 opt-in 路径,注意它与 fullgraph=True 不兼容。
  • Python、CUDA、PyTorch 版本 Issue 未提供,无法按具体版本给结论。

解决步骤

  1. 先复现并定位:在 Ideogram4Transformer2DModel.forward 中确认 llm_cond_norm 与 llm_cond_proj 是否在去噪每步执行,并用显存峰值或 profiler 记录当前基线(2048² 与 1024² 各一次)。
  2. 按 Issue 讨论的方向修改:进入去噪循环前,对携带文本的位置一次性完成投影;循环内通过 encoder_hidden_states_projected=True 之类的 opt-in 标志告知 transformer 条件已投影。该 API 形状来自 Issue 提议,尚未确认合入。
  3. 保持默认路径不变:不要默认改动未开启标志的调用路径,避免影响现有用户与 torch.compile。
  4. 若要保证逐位一致:投影时保留默认路径的行数(Issue 提议参数 minimum_projection_rows),使量化 NF4 选择同一 kernel。
  5. 无文本位置的无条件分支,按 Issue 建议可直接传 encoder_hidden_states=None,而不是宽全零张量。
  6. 修改后运行 make style、make quality、make fix-copies 及该模型 CPU 测试,并比对 latents、像素、OCR 的哈希与修改前是否一致。
  7. 如果不想自行改源码,可优先尝试降低生成分辨率、减少 CFG 第二分支开销等临时方式缓解显存,但这些并非 Issue 验证过的修复。

验证方法

在相同固定种子、相同提示词长度下分别用修改前后运行 2048² 与 1024² 生成,对比 latents、像素与 OCR 的 SHA-256 应完全一致;同时记录显存峰值,2048² 应明显下降(Issue 实测 A100 上约降低 9.457 GiB),原先在 A10 24 GiB 上 OOM 的 2048² 应能完成。若哈希不一致,优先检查是否改变了 GEMM 的行数或切换了 NF4 kernel。

参考来源

huggingface/diffusers #14405

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 29507

发表回复

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