RuntimeError: Cannot copy between CPU and CUDA tensors during CUDA graph capture unless the CPU tensor is pinned.

这个报错通常出现在 ComfyUI 运行 MiniMax Music 3、同时使用 GGUF 动态显存(Dynamic VRAM)加载器和 CUDA Graph 捕获时。优先排查 CUDA Graph 是否与动态卸载/反量化路径冲突,而不是先怀疑 GGUF 模型文件本身。

快速结论:这个报错通常出现在 ComfyUI 运行 MiniMax Music 3、同时使用 GGUF 动态显存(Dynamic VRAM)加载器和 CUDA Graph 捕获时。优先排查 CUDA Graph 是否与动态卸载/反量化路径冲突,而不是先怀疑 GGUF 模型文件本身。

适用环境:ComfyUI 0.34.0;Windows portable NVIDIA 构建;NVIDIA RTX 4060 8 GB VRAM;PyTorch 2.13.0(评论中给出 2.13.0+cu130);Python 3.13.14;文本编码器 minimax_music3_text_encoder_pruned_Q4_0.gguf;加载器 CLIPLoaderGGUFDynamicVRAM。另有 RTX 4080 用户在 core int8 convrot 权重下复现出纯噪声问题。

最快修复方案:Issue 中已验证的临时处理是把 MiniMax Music 3 的两条 CUDA Graph 路径都关闭:在 comfy/ldm/minimax_music/ar.py 中设置 self.model.graph_dynamic_vbar_blocks = False,并把深度解码器预取调用改为 enable_graph=False。只改其中一个不够。

注意事项:关闭 CUDA Graph 会牺牲速度,属于绕过而非根治。评论中还提到一条更完整的本地修复:在 comfy/text_encoders/llama.pyif enable_graph: 分支里恢复 #15570 的静态缓冲固定逻辑,取代 x = x.clone();该补丁属于用户本地验证,需自行评估风险。此外 8 GB 显存下 Dynamic VRAM 与 CUDA Graph 的兼容性仍是薄弱点。

问题场景

用户在 Windows portable NVIDIA 版 ComfyUI 中运行 MiniMax Music 3 工作流,文本编码器使用量化的 GGUF 模型 minimax_music3_text_encoder_pruned_Q4_0.gguf,并通过 CLIPLoaderGGUFDynamicVRAM 加载。模型加载和 AR 采样都能开始,但在自回归解码阶段、执行 Q4_0 反量化时崩溃。另一条复现路径不涉及 GGUF 节点:使用 core int8 convrot 权重时,开启 CUDA Graph 会直接输出纯噪声而不报错。

报错原文

RuntimeError: Cannot copy between CPU and CUDA tensors during CUDA graph capture unless the CPU tensor is pinned.

ComfyUI/comfy/ops.py -> tensor.dequantize()
ComfyUI-GGUF/quant_ops.py -> dequantize()
ComfyUI-GGUF/dequant.py -> dequantize_blocks_Q4_0()

CUDAMallocAsyncAllocator.cpp:
Warning: Attempting uncaptured free of a captured allocation

Fatal Python error: Aborted

原因分析

最可能的原因:ComfyUI 在 MiniMax Music 3 执行期间启用了 CUDA Graph 捕获,而 GGUF 加载器的动态卸载张量位于未 pinned 的 CPU 内存中。PyTorch 在 CUDA Graph 捕获阶段不允许 CPU 与 CUDA 张量之间进行这种拷贝,因此反量化路径被拒绝。Issue 作者给出的关键证据是:不改 GGUF 文件、加载器、反量化器或模型,只关闭 ComfyUI 自己的两条图捕获路径,生成即可稳定完成。

评论中进一步定位到一条独立于 GGUF 的静默损坏路径:804eb551(Comfy Compiler / #15861)移除了 Llama2_.forward 中用于在 torch.cuda.CUDAGraph 捕获前固定 xfreqs_cis 地址的 _comfy_cross_step_state 静态缓冲,改用 x = x.clone()。这样每个解码步都会分配新地址,图重放时 kernel 可能读取到第一步的旧地址,导致逐层输出异常、音频码随机化,最终表现为纯噪声。该结论来自用户侧的分析,属于较深层的可能原因。

环境排查

  • 确认 ComfyUI 版本(Issue 为 0.34.0)以及是否包含 #15570、#15861 相关改动。
  • 确认 PyTorch 与 CUDA 版本(Issue 为 PyTorch 2.13.0 / 2.13.0+cu130,CUDA 13.0)。
  • 确认 Python 版本(评论给出 3.13.14)。
  • 确认显卡与显存(RTX 4060 8 GB;另一复现为 RTX 4080)。
  • 确认文本编码器与加载器组合:minimax_music3_text_encoder_pruned_Q4_0.gguf + CLIPLoaderGGUFDynamicVRAM,或 core int8 convrot 加载器。
  • 确认是否开启 Dynamic VRAM(默认开启)以及是否使用了 --disable-cuda-graphs 等启动参数。
  • 确认是否涉及自定义节点;Issue 标题下未勾选“已禁用自定义节点”,因此也可能需要分离 GGUF 自定义节点变量。

解决步骤

  1. 先做对照测试:用 --disable-cuda-graphs 启动 ComfyUI,再跑同一 MiniMax Music 3 工作流。若不再崩溃或不再输出噪声,可确认与 CUDA Graph 捕获有关。
  2. comfy/ldm/minimax_music/ar.py 中把 self.model.graph_dynamic_vbar_blocks 设为 False
  3. 在同一文件中把深度解码器预取的调用改为 enable_graph=False
  4. 两步都改完后重跑工作流。Issue 作者明确说明只改 enable_graph=False 不够,错误会转移到 comfy/text_encoders/llama.py 的主 Llama/文本编码器路径,必须两条图路径都关闭。
  5. 可优先尝试更完整的本地修复:在 comfy/text_encoders/llama.pyif enable_graph: 分支中恢复 #15570 的静态缓冲固定逻辑(重新引入 _comfy_cross_step_state,按 shape/stride/dtype/device 生成 cross_step_key,用 torch.empty_like 建立 static_freqs_cis),并保留新的 core()/x.copy_(output)/malloc_scope 结构。该补丁由用户在本地验证,非官方合入。

验证方法

用同一 Q4_0 GGUF 模型和 Dynamic VRAM 配置重跑 MiniMax Music 3:不应再出现 Cannot copy between CPU and CUDA tensors during CUDA graph capture,也不再出现 Fatal Python error: Aborted;若采用本地固定补丁方案,应在保持 CUDA Graph 速度的前提下得到正确音频,而不是纯噪声。若只采用关闭图路径的绕过方案,验证生成成功的同时也应接受速度下降。

参考来源

Comfy-Org/ComfyUI #16002

molbal/ComfyUI-GGUF #17

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 24669

发表回复

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