
本文摘要同一工作流首帧 35 秒、次帧 5 秒常被误判成显卡算力不足。计时脚本配合显存日志定位显存碎片、attention 后端与 VAE 精度三处差异。一、问题与结论本机环境ComfyUI 0.3.28、Python 3.11.9、torch 2.4.1cu124、驱动 550.54.14GPU 为 RTX 4070 Ti 12GB系统盘 NVMe。工作流固定为 SDXL base 1.0、1024×1024、20 steps、euler、cfg 7JSON 与同事完全一致。正常启动并连跑两次python main.py--listen127.0.0.1--port8188python bench_first_frame.pygot prompt Prompt executed in 41.63 seconds Prompt executed in 14.80 seconds换成压显存配置后首次提交卡在采样前约 3 分钟python main.py--listen127.0.0.1--port8188--lowvram--use-quad-cross-attentiongot prompt Requested to load UNETModel to GPU Requested to load AutoencoderKL to GPU Requested to load UNETModel to GPU 同一组日志循环约 180s无进度输出 Prompt executed in 192.41 seconds结论先放这里41.63 与 14.80 的 2.8 倍差额属于冷启动——惰性加载模型、CUDA 上下文、显存碎片往返而 14.80 秒本身就偏高来自 attention 后端与 VAE 精度这两项每帧都要付。三项修完同机首帧 13.42 秒、次帧 4.62 秒。同事 RTX 4090 的 8.9 秒/4.1 秒为转述未验证本文计时是该组合下的复现示例换驱动或 checkpoint 必须重测。二、排查与选择依据判断规则先给算(首帧 - 次帧) / 首帧。大于 0.8 说明首帧被一次性开销主导查显存与加载小于 0.8 且次帧也慢查每帧都要走的 attention 后端和 VAE 精度。基线算得 0.64两类问题都存在按单项消融逐个摘除。1. 显存碎片首帧期间watch -n1 nvidia-smi看到 used 从 11.7GB 掉到 4GB 再回升同时 stdout 反复打印Requested to load ... to GPU即 smart memory 在反复搬模型。根因是 fp32 解码要一次申请连续大块显存池里拿不到就 offload 腾地方这段 PCIe 往返只发生在首帧。修复落在第 3 项降 VAE 精度再把--lowvram换成--normalvram。验证标准每个模型的Requested to load只出现一次显存曲线不再回落。2. attention 后端选错次帧 14.80 秒已经暴露每帧开销。检查对象是启动参数而非日志——不同 ComfyUI 版本后端名会变先执行python main.py--help|grep-iattention本版出现--use-quad-cross-attention常为压显存手动加让 1024² 走分块慢路径。去掉该参数重启单独效果见第五节第 ① 行次帧 14.80 → 8.61 秒。3. VAE 精度设置VAEDecode是带宽瓶颈fp32 读写翻倍且峰值更大。确认本版参数后加--fp16-vae或--bf16-vae单独效果首帧 35.40 → 18.90 秒次帧 8.61 → 4.92 秒。代价是部分 SD1.5 checkpoint 在 fp16 下出现 NaN 或色偏换 checkpoint 后要重对比首图SDXL 相对安全但不保证。替代方案与取舍方案选择条件代价边界何时不用预热请求先提交 1 步 64×64 工作流交互式调参要求每次提交都快额外等待 10-30 秒脚本多一次提交只消除首帧差额不解决次帧慢常驻服务 --normalvram/高显存驻留单人独占显存 ≥ 模型 解码峰值进程常驻显存被长期占用共享 GPU、显存不足 12GB 时不该用batch_size 1一次出多张离线批量、参数固定单张无法独立调参逐张改 prompt 的调试场景不该用本文的三项参数修正只解决配置错误若需求是 fp32 数值一致的复现实验或 checkpoint 已确认 fp16 解码异常就不要动 VAE 精度项。三、关键原理ComfyUI 节点图是惰性求值KSampler首次被触发时才解析上游CheckpointLoaderSimple于是 Python import、CUDA 上下文创建、约 6.9GB checkpoint 入显存全部计入首帧次帧里这三段消失。PyTorch 的 caching allocator 按块复用显存首帧在不同尺寸请求间来回碎片化后连续大块拿不到便触发 offload长尾集中在首帧。attention 分块quad/split不减少 FLOPs却增加 kernel 启动与中间张量拷贝未融合的 math 后端同理每步差距会累积到整帧。VAE 解码按像素带宽计费fp32 相对 fp16 读写翻倍分辨率越高差距越明显。四、可运行示例环境与输入上述版本组合checkpoint 位于models/checkpoints/sd_xl_base_1.0.safetensorsComfyUI 已监听8188。步骤是先用坏配置启动再连续提交同一工作流两次计时。importjson,timefromurllibimportrequestasu Bhttp://127.0.0.1:8188WF{4:{class_type:CheckpointLoaderSimple,inputs:{ckpt_name:sd_xl_base_1.0.safetensors}},6:{class_type:CLIPTextEncode,inputs:{text:a red apple,clip:[4,1]}},5:{class_type:EmptyLatentImage,inputs:{width:1024,height:1024,batch_size:1}},3:{class_type:KSampler,inputs:{seed:42,steps:20,cfg:7.0,denoise:1.0,sampler_name:euler,scheduler:normal,model:[4,0],positive:[6,0],latent_image:[5,0]}},8:{class_type:VAEDecode,inputs:{samples:[3,0],vae:[4,2]}},9:{class_type:SaveImage,inputs:{images:[8,0],filename_prefix:bench}}}defrun(tag):t0time.perf_counter()requ.Request(f{B}/prompt,datajson.dumps({prompt:WF}).encode(),headers{Content-Type:application/json})respjson.loads(u.urlopen(req).read())pidresp.get(prompt_id)ifpidisNone:raiseRuntimeError(f/prompt 返回错误:{resp})whileTrue:time.sleep(0.2)ifjson.loads(u.urlopen(f{B}/history/{pid}).read()).get(pid):print(f[{tag}]{time.perf_counter()-t0:.2f}s);returnrun(首帧);run(次帧)预期输出坏配置基线[首帧] 41.63s [次帧] 14.80s实际输出修正三项参数后同机重跑[首帧] 13.42s [次帧] 4.62s两次的首帧/次帧比值分别约 2.8 和 2.9说明剩余差额就是纯冷启动属一次性成本只能靠预热或常驻消除。常见失败及其修复抛urllib.error.URLError: urlopen error [Errno 111] Connection refusedComfyUI 未启动或端口不符先用curl -s [http://127.0.0.1:8188/system_stats](http://127.0.0.1:8188/system_stats)探活。/prompt返回体没有prompt_id只有error工作流校验失败常见是ckpt_name与实际文件名不一致用curl -s [http://127.0.0.1:8188/object_info/CheckpointLoaderSimple](http://127.0.0.1:8188/object_info/CheckpointLoaderSimple)核对。启动加了--use-sage-attention但环境未安装依赖进程在 import 阶段退出首帧永远等不到装依赖或去掉该参数。五、验证结果与边界步骤启动参数变更首帧次帧基线--lowvram --use-quad-cross-attentionfp32 VAE41.63s14.80s① 去掉 quad attention默认 SDPA35.40s8.61s② 加--fp16-vae解码 fp32 → fp1618.90s4.92s③ 改--normalvram消除碎片不再反复 offload13.42s4.62s边界与代价上表是本机复现示例跨机器对比未验证PyTorch 2.x 的显存预分配策略变化会改变首帧基线升级后须重测。参数名随版本漂移动手前先python main.py --help。什么时候不该用本文方案批量离线出图时首帧被后续帧摊薄应看整体吞吐共享 GPU 上常驻与高显存配置会互相挤占需要 fp32 数值一致性的复现任务不要改 VAE 精度。思考fp16 解码带来的首帧收益与画质风险项目里该用什么可复现的判据来取舍把预热请求塞进 CI 之后首帧计时还能否作为有效的性能回归指标参考资料Comfy-Org/ComfyUIharry0703/MoneyPrinterTurbo