有效且高效的扩散
获取DiffusionPipeline以特定风格生成图像或包含您想要的内容可能很棘手。通常,您必须运行DiffusionPipeline几次才能得到您满意的图像。但是,从无到有地生成某些东西是一个计算密集型过程,尤其是在您反复运行推理时。
因此,从管道中获得最大的 *计算*(速度)和 *内存*(GPU vRAM)效率非常重要,以减少推理周期之间的时间,以便您可以更快地迭代。
本教程将引导您了解如何使用DiffusionPipeline更快、更好地生成图像。
首先加载runwayml/stable-diffusion-v1-5
模型
from diffusers import DiffusionPipeline
model_id = "runwayml/stable-diffusion-v1-5"
pipeline = DiffusionPipeline.from_pretrained(model_id, use_safetensors=True)
您将使用的示例提示是老战士首领的肖像,但请随意使用您自己的提示
prompt = "portrait photo of a old warrior chief"
速度
💡如果您没有访问GPU的权限,您可以从Colab等GPU提供商处免费使用一个!
加快推理的最简单方法之一是将管道放在GPU上,就像处理任何PyTorch模块一样
pipeline = pipeline.to("cuda")
为了确保您可以使用相同的图像并对其进行改进,请使用Generator
并为可重复性设置种子
import torch
generator = torch.Generator("cuda").manual_seed(0)
现在您可以生成图像了
image = pipeline(prompt, generator=generator).images[0]
image
此过程在T4 GPU上花费了约30秒(如果您的分配的GPU比T4更好,则可能更快)。默认情况下,DiffusionPipeline以完整的float32
精度运行推理,共50个推理步骤。您可以通过切换到较低的精度(如float16
)或运行较少的推理步骤来加快此速度。
让我们从以float16
加载模型并生成图像开始
import torch
pipeline = DiffusionPipeline.from_pretrained(model_id, torch_dtype=torch.float16, use_safetensors=True)
pipeline = pipeline.to("cuda")
generator = torch.Generator("cuda").manual_seed(0)
image = pipeline(prompt, generator=generator).images[0]
image
这次,生成图像仅花费了约11秒,比之前快了近3倍!
💡我们强烈建议始终以float16
运行您的管道,到目前为止,我们很少看到输出质量有任何下降。
另一种选择是减少推理步骤的数量。选择更有效的调度器可以帮助减少步骤数量,而不会牺牲输出质量。您可以通过调用compatibles
方法在DiffusionPipeline中找到与当前模型兼容的调度器
pipeline.scheduler.compatibles [ diffusers.schedulers.scheduling_lms_discrete.LMSDiscreteScheduler, diffusers.schedulers.scheduling_unipc_multistep.UniPCMultistepScheduler, diffusers.schedulers.scheduling_k_dpm_2_discrete.KDPM2DiscreteScheduler, diffusers.schedulers.scheduling_deis_multistep.DEISMultistepScheduler, diffusers.schedulers.scheduling_euler_discrete.EulerDiscreteScheduler, diffusers.schedulers.scheduling_dpmsolver_multistep.DPMSolverMultistepScheduler, diffusers.schedulers.scheduling_ddpm.DDPMScheduler, diffusers.schedulers.scheduling_dpmsolver_singlestep.DPMSolverSinglestepScheduler, diffusers.schedulers.scheduling_k_dpm_2_ancestral_discrete.KDPM2AncestralDiscreteScheduler, diffusers.utils.dummy_torch_and_torchsde_objects.DPMSolverSDEScheduler, diffusers.schedulers.scheduling_heun_discrete.HeunDiscreteScheduler, diffusers.schedulers.scheduling_pndm.PNDMScheduler, diffusers.schedulers.scheduling_euler_ancestral_discrete.EulerAncestralDiscreteScheduler, diffusers.schedulers.scheduling_ddim.DDIMScheduler, ]
Stable Diffusion模型默认使用PNDMScheduler,通常需要大约50个推理步骤,但像DPMSolverMultistepScheduler这样的更高效的调度器只需要大约20或25个推理步骤。使用from_config()方法加载新的调度器
from diffusers import DPMSolverMultistepScheduler
pipeline.scheduler = DPMSolverMultistepScheduler.from_config(pipeline.scheduler.config)
现在将num_inference_steps
设置为20
generator = torch.Generator("cuda").manual_seed(0)
image = pipeline(prompt, generator=generator, num_inference_steps=20).images[0]
image
太好了,您已成功将推理时间缩短至仅4秒!⚡️
内存
提高管道性能的另一个关键是消耗更少的内存,这间接意味着更高的速度,因为您通常试图最大化每秒生成的图像数量。查看一次可以生成多少图像的最简单方法是尝试不同的批次大小,直到出现OutOfMemoryError
(OOM)错误。
创建一个函数,该函数将根据提示列表和Generators
生成一批图像。确保为每个Generator
分配一个种子,以便在生成良好结果时可以重用它。
def get_inputs(batch_size=1):
generator = [torch.Generator("cuda").manual_seed(i) for i in range(batch_size)]
prompts = batch_size * [prompt]
num_inference_steps = 20
return {"prompt": prompts, "generator": generator, "num_inference_steps": num_inference_steps}
从batch_size=4
开始,并查看您消耗了多少内存
from diffusers.utils import make_image_grid
images = pipeline(**get_inputs(batch_size=4)).images
make_image_grid(images, 2, 2)
除非您拥有具有更多vRAM的GPU,否则上述代码可能会返回OOM
错误!大部分内存都被交叉注意力层占用。您可以按顺序运行此操作而不是批量运行它,以节省大量内存。您所要做的就是配置管道以使用enable_attention_slicing()函数
pipeline.enable_attention_slicing()
现在尝试将batch_size
增加到8!
images = pipeline(**get_inputs(batch_size=8)).images
make_image_grid(images, rows=2, cols=4)
以前您甚至无法生成一批4张图像,而现在您可以生成一批8张图像,每张图像大约需要3.5秒!这可能是您在不牺牲质量的情况下在T4 GPU上所能达到的最快速度。
质量
在最后两节中,您学习了如何通过使用fp16
、使用更高效的调度器减少推理步骤以及启用注意力切片以减少内存消耗来优化管道的速度。现在,您将专注于如何提高生成图像的质量。
更好的检查点
最明显的步骤是使用更好的检查点。Stable Diffusion模型是一个良好的起点,并且自其正式发布以来,也发布了几个改进版本。但是,使用更新的版本并不一定意味着您会获得更好的结果。您仍然需要自己尝试不同的检查点,并进行一些研究(例如使用负面提示)以获得最佳结果。
随着该领域的不断发展,越来越多的高质量检查点经过微调以产生特定的风格。尝试探索Hub和Diffusers Gallery以找到您感兴趣的检查点!
更优的管道组件
您还可以尝试将当前管道组件替换为更新版本。让我们尝试将 Stability AI 发布的最新 自动编码器 加载到管道中,并生成一些图像。
from diffusers import AutoencoderKL
vae = AutoencoderKL.from_pretrained("stabilityai/sd-vae-ft-mse", torch_dtype=torch.float16).to("cuda")
pipeline.vae = vae
images = pipeline(**get_inputs(batch_size=8)).images
make_image_grid(images, rows=2, cols=4)
更优的提示工程
您用于生成图像的文本提示非常重要,以至于被称为提示工程。在提示工程期间需要考虑的一些因素是
- 我想生成的图像或类似图像是如何存储在互联网上的?
- 我可以提供哪些额外的细节来引导模型朝着我想要的风格发展?
考虑到这一点,让我们改进提示以包含颜色和更高质量的细节。
prompt += ", tribal panther make up, blue on red, side profile, looking away, serious eyes"
prompt += " 50mm portrait photography, hard rim lighting photography--beta --ar 2:3 --beta --upbeta"
使用新的提示生成一批图像。
images = pipeline(**get_inputs(batch_size=8)).images
make_image_grid(images, rows=2, cols=4)
非常棒!让我们稍微调整一下第二张图像——对应于种子为1
的Generator
——通过添加一些关于主题年龄的文本。
prompts = [
"portrait photo of the oldest warrior chief, tribal panther make up, blue on red, side profile, looking away, serious eyes 50mm portrait photography, hard rim lighting photography--beta --ar 2:3 --beta --upbeta",
"portrait photo of a old warrior chief, tribal panther make up, blue on red, side profile, looking away, serious eyes 50mm portrait photography, hard rim lighting photography--beta --ar 2:3 --beta --upbeta",
"portrait photo of a warrior chief, tribal panther make up, blue on red, side profile, looking away, serious eyes 50mm portrait photography, hard rim lighting photography--beta --ar 2:3 --beta --upbeta",
"portrait photo of a young warrior chief, tribal panther make up, blue on red, side profile, looking away, serious eyes 50mm portrait photography, hard rim lighting photography--beta --ar 2:3 --beta --upbeta",
]
generator = [torch.Generator("cuda").manual_seed(1) for _ in range(len(prompts))]
images = pipeline(prompt=prompts, generator=generator, num_inference_steps=25).images
make_image_grid(images, 2, 2)
后续步骤
在本教程中,您学习了如何优化 DiffusionPipeline 以提高计算和内存效率,以及提高生成输出的质量。如果您有兴趣使您的管道更快,请查看以下资源
- 了解 PyTorch 2.0 和
torch.compile
如何能够使推理速度提高 5% 到 300%。在 A100 GPU 上,推理速度可以提高高达 50%! - 如果您无法使用 PyTorch 2,我们建议您安装 xFormers。其内存高效的注意力机制与 PyTorch 1.13.1 配合使用效果极佳,可实现更快的速度和更低的内存消耗。
- 其他优化技术,例如模型卸载,在 本指南 中有介绍。