跳转至
图像与视频生成推理手册 服务 下载 notebook

引擎选型与部署:diffusers、ComfyUI、xDiT 与推理框架

文生图、文生视频的推理栈正在从"研究代码 + 脚本"走向真正的推理引擎:diffusers 是模型定义和参考实现,ComfyUI 是把生成流程组装成图的执行器,xDiT 是多卡并行的加速层,TensorRT 走的是编译优化路线,而 SGLang Diffusion、vLLM-Omni 这些则把 LLM 服务那套调度和批处理搬了过来。这一章把它们各自解决的问题、擅长的场景和互相的关系讲清楚,再给出几种典型部署形态(在线交互、离线批量、端侧)的配法,以及上线前的检查清单。

自测:能答上来就可以跳过本章

  1. diffusers 和 ComfyUI 分别是什么层次的东西?它们能一起用吗?
  2. xDiT 在栈里的位置是什么?它和 diffusers 的关系?
  3. TensorRT 对扩散模型能提多少?代价是什么?
  4. SGLang Diffusion、vLLM-Omni 这类"LLM 推理框架做生成"的价值在哪?
  5. 在线交互、离线批量、端侧三种部署形态的配置各有什么不同?
自测参考答案(先自己答,再展开对照)
  1. diffusers 是模型库和参考实现:模型定义、调度器、pipeline 组装、权重加载,是几乎所有上层的基础;ComfyUI 是图执行器:把编码、去噪、解码、ControlNet、放大这些节点连成图,面向工作流和非程序员,底层大量复用 diffusers 的组件或自己的实现。可以一起用,很多 ComfyUI 的自定义节点就是在包 diffusers。
  2. 加速层:接管去噪网络的前向,把 CFG 并行、序列并行(USP)、PipeFusion 等并行策略应用到 diffusers 的模型上,并集成缓存和量化;它不管调度和服务。
  3. 把 UNet / DiT 编译成优化过的引擎(算子融合、精度选择、固定形状),SDXL 上 1.5~2×,FP8 下更多。代价:编译时间长、形状固定(每个分辨率一个引擎)、插件(LoRA、ControlNet)要特殊处理、调试困难。
  4. 把 LLM 服务已经成熟的那套——请求调度、按阶段流水、批处理、多模型、OpenAI 式 API、可观测性——用到生成模型上,并把扩散和 LLM 放在同一个引擎里(自回归视频模型、多模态统一模型需要这个);单次生成的 kernel 级性能它们大多复用 xDiT / diffusers 的实现。
  5. 在线交互:延迟优先,少步或缓存,多卡一组,预览,严格的超时和取消;离线批量:吞吐优先,每卡一个请求、队列深、可以用完整模型多步;端侧:显存和功耗优先,INT4 / NF4、小模型、蒸馏、CoreML / NPU 后端。

栈的分层

服务与调度   SGLang Diffusion · vLLM-Omni · 自研服务(队列、API、多模型、可观测)
            ──────────────────────────────────────────────────────────────
工作流       ComfyUI(节点图)· 自研 pipeline 编排
            ──────────────────────────────────────────────────────────────
加速         xDiT(并行)· TeaCache / FBCache(缓存)· SageAttention · Nunchaku(W4A4)· TensorRT(编译)
            ──────────────────────────────────────────────────────────────
模型与参考   diffusers(模型定义、调度器、pipeline、权重)· 各家官方代码
            ──────────────────────────────────────────────────────────────
运行时       PyTorch · CUDA · FlashAttention / cuDNN / cuBLAS
组件 解决什么 不解决什么 适合
diffusers 模型、调度器、pipeline、权重加载、基本的 offload / 分块 服务、调度、多卡并行(有限) 所有人的起点;研究、原型、自研的基础
ComfyUI 把生成流程做成可视化的图;生态里几乎所有插件 多租户服务、调度、并行 创作工作流、快速试验、小规模部署
xDiT 多卡并行(USP、PipeFusion、CFG 并行)、缓存、部分量化 请求调度、API 视频模型的单次生成加速
TensorRT / TRT-LLM 的扩散支持 编译优化、FP8 / INT8、固定形状极致性能 灵活性、插件、快速迭代 固定模型固定分辨率的高吞吐线上服务
Nunchaku / SVDQuant W4A4 量化 kernel 其他 消费级卡
SGLang Diffusion、vLLM-Omni LLM 式的服务层:调度、批处理、多模型、API、与 LLM 共引擎 单次生成的 kernel 级性能(复用下层) 生产服务,尤其多模态统一的场景

两个趋势:加速层在往下沉(xDiT 的并行、TeaCache 这些逐渐被 diffusers 和推理框架原生集成),服务层在往 LLM 框架靠(扩散和自回归生成在同一个引擎里调度)。

怎么选

决定因素是场景,不是哪个"最快":

import unicodedata

SCENES = {   # 每个场景对六种能力的需要程度(1~5)
    "研究 / 原型":     {"延迟": 1, "吞吐": 1, "灵活": 5, "插件": 4, "多卡": 1, "运维": 1},
    "创作工具(单机)": {"延迟": 3, "吞吐": 1, "灵活": 4, "插件": 5, "多卡": 1, "运维": 2},
    "在线交互服务":     {"延迟": 5, "吞吐": 3, "灵活": 2, "插件": 3, "多卡": 4, "运维": 5},
    "离线批量生成":     {"延迟": 1, "吞吐": 5, "灵活": 2, "插件": 2, "多卡": 2, "运维": 4},
    "视频生成服务":     {"延迟": 4, "吞吐": 3, "灵活": 2, "插件": 1, "多卡": 5, "运维": 5},
}
STACKS = {   # 每个栈提供的能力(1~5)
    "diffusers":  {"延迟": 2, "吞吐": 2, "灵活": 5, "插件": 4, "多卡": 1, "运维": 1},
    "ComfyUI":    {"延迟": 2, "吞吐": 2, "灵活": 4, "插件": 5, "多卡": 1, "运维": 2},
    "xDiT":       {"延迟": 4, "吞吐": 3, "灵活": 3, "插件": 2, "多卡": 5, "运维": 2},
    "TensorRT":   {"延迟": 5, "吞吐": 5, "灵活": 1, "插件": 2, "多卡": 2, "运维": 3},
    "LLM 式框架":  {"延迟": 4, "吞吐": 4, "灵活": 2, "插件": 2, "多卡": 4, "运维": 5},
}
def score(need, have):
    return sum(min(have[k], need[k]) for k in need) / sum(need.values())   # 需要的能力里被满足的比例

def pad(text, width):   # 中文占两列,按显示宽度对齐
    shown = sum(2 if unicodedata.east_asian_width(c) in "WF" else 1 for c in text)
    return text + " " * max(0, width - shown)

print((pad("场景", 18) + "".join(pad(name, 12) for name in STACKS)).rstrip())
for scene, need in SCENES.items():
    print((pad(scene, 18) + "".join(pad(f"{score(need, have):.0%}", 12) for have in STACKS.values())).rstrip())
输出
场景              diffusers   ComfyUI     xDiT        TensorRT    LLM 式框架
研究 / 原型       100%        92%         69%         54%         62%
创作工具(单机)  81%         94%         75%         62%         69%
在线交互服务      50%         55%         77%         73%         91%
离线批量生成      56%         62%         75%         88%         94%
视频生成服务      45%         50%         85%         70%         95%

(打分是经验性的,用来说明"按场景选",不是排行榜。)读法:研究和创作选灵活和插件多的(diffusers、ComfyUI);在线和离线服务选服务层成熟的(LLM 式框架)或编译路线(TensorRT);视频服务一定要有多卡并行(xDiT 或集成了它的框架)。

三种部署形态

在线交互

用户在等,延迟第一:

  • 模型:少步蒸馏版(Turbo / Lightning / schnell)出草稿,完整模型精修;或者完整模型 + 缓存;
  • 单次生成:FP8 + 编译 + CUDA Graph + SageAttention;视频用多卡一组;
  • 服务:按预计耗时排队、分池、取消、预览(见生成服务的调度);
  • 超时与降级:排队超过阈值就降分辨率 / 步数或拒绝;
  • 形状:固定支持的分辨率档位(编译和 CUDA Graph 都要求)。

离线批量

没人在等,吞吐和成本第一:

  • 每卡一个请求,队列尽量深,不用多卡并行(通信开销是净损失);
  • 完整模型、完整步数,质量优先;可以用 batch(同一提示词多张);
  • 省钱手段:便宜的卡(L40S、4090 集群)、抢占式实例、夜间排程;
  • 把文本编码、去噪、VAE 解码分到不同的卡池,各自满载。

端侧

显存、功耗和包体第一:

  • 模型:SD 1.5 / SDXL 的蒸馏版、小 DiT(SANA 这类高压缩 VAE 的模型)、INT4 / NF4 权重;
  • 后端:CoreML(Apple)、NPU 运行时、ONNX Runtime、llama.cpp 生态里的 stable-diffusion.cpp;
  • 步数 2~8,分辨率 512~768;
  • 文本编码器是显存大头:用小的(CLIP 而不是 T5)或者量化。

上线前的检查清单

检查项 怎么验 常见问题
固定种子的可复现 同一请求跑两次比 PSNR batch 组成不同、注意力后端不同(见采样器与调度器)
各分辨率档位的编译 / 引擎 启动时预热所有档位,记录首次延迟 漏了一档,上线后第一个请求卡几十秒
显存峰值 最大分辨率 + 最多插件 + VAE 解码一起压测 去噪没问题,解码时 OOM
调度器实例隔离 并发请求下比较和单跑的结果 多步调度器状态串了
取消的资源释放 取消后看显存和队列 显存没释放、worker 卡死
插件兼容 每个 LoRA / ControlNet 在量化 / 编译版本上各跑一次 融合破坏了量化权重;编译图里没有旁路
质量回归 固定一组提示词 + 种子,和基线比 LPIPS / 人工看 缓存阈值或量化让某类图退化
过载行为 压到 1.5 倍容量看 P99 和拒绝率 长任务堵死队列

怎么讲清楚

讲"文生图服务的技术选型",先分层:diffusers 是模型与参考实现,ComfyUI 是工作流执行器,xDiT 等是加速层,TensorRT 是编译路线,SGLang Diffusion / vLLM-Omni 是把 LLM 服务层搬过来。再按场景说:研究和创作要灵活和插件,在线服务要服务层成熟或编译路线,视频必须多卡并行。然后给三种形态的要点:在线交互延迟优先(少步 / 缓存、多卡一组、预览取消、固定分辨率档位),离线批量吞吐优先(每卡一个请求、队列深、便宜的卡),端侧显存优先(小模型、INT4、CoreML / NPU)。最后提两个趋势:加速在下沉、服务在向 LLM 框架靠拢。

练习

  1. 给 SCENES 加一个"多模态统一服务(同一引擎既做文生图又做 VLM 问答)"的场景,它最需要哪些维度?哪个栈得分最高?为什么?
参考答案

最需要"运维"(多模型、统一 API、调度)和"多卡",灵活和插件次要。LLM 式框架得分最高——它们本来就是为多模型、多请求类型的调度设计的,而且自回归视频 / 统一多模态模型需要和 LLM 共享 KV Cache 和调度器。这正是 SGLang Diffusion、vLLM-Omni 出现的原因。

  1. 一个在线服务支持 512² / 768² / 1024² 三档,用 TensorRT。要准备几个引擎?如果再加 2 个 LoRA 和 1 个 ControlNet 呢?
参考答案

每档一个引擎(3 个);CFG 的 batch=2 要和 batch=1 分开的话再翻倍。LoRA 若融合进权重,每个 LoRA 组合要单独的引擎(组合爆炸),所以要么用支持动态 LoRA 的编译方式(旁路作为引擎输入),要么限制组合;ControlNet 是另一个网络,单独一个引擎、每档一个。引擎数量会很快变成运维负担,这是编译路线的主要代价。

  1. 离线批量生成 10 万张 SDXL 1024² 的图,有 8 张 H100 和 32 张 4090 两种选择,怎么算哪个更划算?
参考答案

算每张图的成本:按算账一章估 SDXL 一张图 H100 约 3 秒、4090 约 15~18 秒;8 张 H100 每小时约 9600 张,32 张 4090 约 7000 张;再乘各自的小时价。离线任务不在乎延迟,所以只比"每张图的钱",通常 4090 这类消费级卡更便宜;要注意 4090 的显存(24 GB)够 SDXL 但 FLUX 要 FP8。

小结

  • 栈分四层:diffusers(模型与参考实现)→ ComfyUI(工作流)→ xDiT / 缓存 / 量化 / TensorRT(加速)→ SGLang Diffusion、vLLM-Omni(LLM 式服务层);加速在下沉、服务在向 LLM 框架靠拢。
  • 选型按场景:研究和创作要灵活与插件,在线服务要成熟的服务层或编译路线,视频必须有多卡并行。
  • 三种形态:在线交互延迟优先(少步 / 缓存、多卡一组、预览与取消、固定分辨率档位),离线批量吞吐优先(每卡一个请求、队列深、便宜的卡),端侧显存优先(小模型、INT4、专用后端)。
  • 上线前验:可复现、各档位预热、显存峰值(含 VAE 解码)、调度器隔离、取消释放、插件兼容、质量回归、过载行为。

发现错误或有更好的写法?在 GitHub 上编辑此页提交问题