使用 ONNX Runtime 和 Olive 加速 SD Turbo 和 SDXL Turbo 推理

发布于 2024 年 1 月 15 日
在 GitHub 上更新

介绍

SD TurboSDXL Turbo 是两个快速的生成式文本到图像模型,能够在短短一步内生成可用的图像,这比以前的 Stable Diffusion 模型通常需要的 30 多步是一个显著的改进。SD Turbo 是 Stable Diffusion 2.1 的蒸馏版本,SDXL Turbo 是 SDXL 1.0 的蒸馏版本。我们之前展示过如何使用 ONNX Runtime 加速 Stable Diffusion 推理。ONNX Runtime 不仅在使用 SD Turbo 和 SDXL Turbo 时提供性能优势,而且还使模型可以在 Python 之外的语言中使用,例如 C# 和 Java。

性能提升

在这篇文章中,我们将介绍 ONNX Runtime CUDA 和 TensorRT 执行提供程序中的优化,这些优化显著加速了 SD Turbo 和 SDXL Turbo 在 NVIDIA GPU 上的推理。

在所有测试的(批次大小,步数)组合中,ONNX Runtime 都优于 PyTorch,SDXL Turbo 模型的吞吐量提升高达 229%,SD Turbo 模型吞吐量提升高达 120%。ONNX Runtime CUDA 在动态形状方面表现出色,但在静态形状方面也比 PyTorch 有显著改进。

如何运行 SD Turbo 和 SDXL Turbo

为了使用 ONNX Runtime CUDA 执行提供程序加速推理,请访问我们在 Hugging Face 上优化的 SD TurboSDXL Turbo 版本。

这些模型由 Olive 生成,Olive 是一款易于使用的、硬件感知型的模型优化工具。请注意,为了获得最佳性能,必须通过命令行启用 fp16 VAE,如共享的优化版本所示。有关如何使用 Hugging Face 上托管的 ONNX 文件运行 SD 和 SDXL 管道的说明,请参阅 SD Turbo 使用示例SDXL Turbo 使用示例

要使用 ONNX Runtime TensorRT 执行提供程序加速推理,请按照此处的说明进行操作。

以下是使用 SDXL Turbo 模型并由文本提示引导生成图像的示例

python3 demo_txt2img_xl.py \
  --version xl-turbo \
  "little cute gremlin wearing a jacket, cinematic, vivid colors, intricate masterpiece, golden ratio, highly detailed"

Generated Gremlin Example
图 1. 使用 SDXL Turbo 通过文本提示生成的穿着夹克的小可爱小妖精图像。

请注意,示例图像是在 4 个步骤中生成的,这表明 SD Turbo 和 SDXL Turbo 能够以比以前的 Stable Diffusion 模型更少的步骤生成可用的图像。

要以用户友好的方式试用 Stable Diffusion 模型,请参阅我们的 Automatic1111 SD WebUI 的 ONNX Runtime 扩展。此扩展可以在 NVIDIA GPU 上优化执行 Stable Diffusion UNet 模型,并使用 ONNX Runtime CUDA 执行提供程序对经过 Olive 优化的模型进行推理。目前,此扩展仅针对 Stable Diffusion 1.5 进行了优化。SD Turbo 和 SDXL Turbo 模型也可以使用,但性能优化仍在进行中。

C# 和 Java 中 Stable Diffusion 的应用

利用 ONNX Runtime 的跨平台、性能和可用性优势,社区成员也贡献了自己的 Stable Diffusion 示例和 UI 工具,并使用 ONNX Runtime 进行推理。

这些社区贡献包括 OnnxStack,这是一个 .NET 库,它基于我们之前的 C# 教程构建,为用户在使用 C# 和 ONNX Runtime 进行推理时,提供了各种 Stable Diffusion 模型的多种功能。

此外,Oracle 还发布了一个使用 Java 的 Stable Diffusion 示例,它在 ONNX Runtime 之上运行推理。这个项目也基于我们的 C# 教程。

基准测试结果

我们使用 A100-SXM4-80GB 的 Standard_ND96amsr_A100_v4 VM 和配备 RTX-4090 GPU 的 联想台式机(WSL Ubuntu 20.04)对 SD Turbo 和 SDXL Turbo 模型进行了基准测试,以使用 LCM 调度器和 fp16 模型生成 512x512 分辨率的图像。结果根据以下规格测量:

  • onnxruntime-gpu==1.17.0(从源代码构建)
  • torch==2.1.0a0+32f93b1
  • tensorrt==8.6.1
  • transformers==4.36.0
  • diffusers==0.24.0
  • onnx==1.14.1
  • onnx-graphsurgeon==0.3.27
  • polygraphy==0.49.0

要复现这些结果,我们建议使用“使用示例”部分中链接的说明。

由于 SDXL Turbo 的原始 VAE 无法以 fp16 精度运行,我们在测试 SDXL Turbo 时使用了 sdxl-vae-fp16-fix。它的输出与原始 VAE 略有差异,但解码后的图像对于大多数用途来说足够接近。

静态形状的 PyTorch 管道已应用通道优先内存格式和带 reduce-overhead 模式的 torch.compile。

以下图表显示了每秒图像吞吐量与不同(批次大小,步数)组合下各种框架的对比。值得注意的是,每个条形上方的标签表示相对于 Torch Compile 的加速百分比——例如,在第一个图表中,对于(批次,步数)组合(4,1),ORT_TRT(静态)比 Torch(编译)快 31%。

我们选择使用 1 步和 4 步,因为 SD Turbo 和 SDXL Turbo 都可以在最短 1 步内生成可用的图像,但通常在 3-5 步内生成质量最佳的图像。

SDXL Turbo

下面的图表展示了 SDXL Turbo 模型在静态和动态形状下的每秒图像吞吐量。结果是在 A100-SXM4-80GB GPU 上针对不同的(批次大小,步数)组合收集的。对于动态形状,TensorRT 引擎支持批次大小 1 到 8 和图像大小 512x512 到 768x768,但它针对批次大小 1 和图像大小 512x512 进行了优化。

Throughput for SDXL Turbo on A100 Tensor Cores GPU (static shapes) Throughput for SDXL Turbo on A100 Tensor Cores GPU (dynamic shapes)

SD Turbo

接下来的两张图表展示了 SD Turbo 模型在 A100-SXM4-80GB GPU 上静态和动态形状下的每秒图像吞吐量。

Throughput for SD Turbo on A100 Tensor Cores GPU (static shapes) Throughput for SD Turbo on A100 Tensor Cores GPU (dynamic shapes)

最后一组图表展示了 SD Turbo 模型在 RTX-4090 GPU 上静态和动态形状下的每秒图像吞吐量。在此动态形状测试中,TensorRT 引擎是为批次大小 1 到 8(针对批次大小 1 优化)和固定图像大小 512x512 构建的,因为内存限制。

Throughput for SD Turbo on RTX 4090 (static shapes) Throughput for SD Turbo on RTX 4090 (dynamic shapes)

ONNX Runtime 下 SD Turbo 和 SDXL Turbo 的速度如何?

这些结果表明,在静态和动态形状下,ONNX Runtime 在所有所示的(批次,步数)组合中,其 CUDA 和 TensorRT 执行提供程序均显著优于 PyTorch。这个结论适用于两种模型尺寸(SD Turbo 和 SDXL Turbo)以及两种测试的 GPU。值得注意的是,ONNX Runtime 与 CUDA(动态形状)在(批次,步数)组合(1,4)下比 Torch Eager 快 229%。

此外,由于在大多数(批次,步数)组合下 ORT_TRT 吞吐量高于相应的 ORT_CUDA 吞吐量,使用 TensorRT 执行提供程序的 ONNX Runtime 在静态形状方面表现稍好。当用户在图定义时知道批次和图像大小(例如,用户只计划生成批次大小为 1 且图像大小为 512x512 的图像)时,通常首选静态形状。在这些情况下,静态形状具有更快的性能。但是,如果用户决定切换到不同的批次和/或图像大小,TensorRT 必须创建一个新的引擎(这意味着磁盘上的引擎文件数量会增加一倍)并切换引擎(这意味着加载新引擎会花费额外时间)。

另一方面,在使用 A100-SXM4-80GB GPU 时,ONNX Runtime 与 CUDA 执行提供程序通常是 SD Turbo 和 SDXL Turbo 模型动态形状的更好选择,但在使用 RTX-4090 GPU 时,ONNX Runtime 与 TensorRT 执行提供程序在大多数(批次,步数)组合下动态形状的表现稍好。使用动态形状的好处是,当批次和图像大小直到图执行时才可知时(例如,为一个图像运行批次大小为 1 且图像大小为 512x512,为另一个图像运行批次大小为 4 且图像大小为 512x768),用户可以更快地运行推理。在这些情况下使用动态形状时,用户只需构建并保存一个引擎,而无需在推理期间切换引擎。

GPU 优化

除了我们之前的 Stable Diffusion 博客中介绍的技术外,ONNX Runtime 还应用了以下优化措施,以获得本文所述的 SD Turbo 和 SDXL Turbo 结果:

  • 启用静态形状输入的 CUDA 图。
  • 添加 Flash Attention V2。
  • 删除文本编码器中的额外输出(保留由 clip_skip 参数指定的隐藏状态输出)。
  • 添加 SkipGroupNorm 融合,将组归一化与其前面的 Add 节点融合。

此外,我们还增加了对新功能的支持,包括用于潜在一致性模型(LCM)的 LoRA 权重。

后续步骤

未来,我们计划继续改进 Stable Diffusion 工作,更新演示以支持新功能,如 IP Adapter 和 Stable Video Diffusion。ControlNet 支持也将很快推出。

我们还在努力优化 SD Turbo 和 SDXL Turbo 在我们现有 Stable Diffusion web UI 扩展上的性能,并计划帮助将这两种模型支持添加到 ONNX Runtime 社区成员开发的 Windows UI 中。

此外,关于如何使用 C# 和 ONNX Runtime 运行 SD Turbo 和 SDXL Turbo 的教程即将发布。在此期间,请查看我们之前关于 Stable Diffusion 的教程

资源

查看本文讨论的一些资源

社区

注册登录 以评论