Stable Diffusion XL
Stable Diffusion XL (SDXL) 是一种强大的文图生成模型,它以三种关键方式迭代了之前的 Stable Diffusion 模型
- UNet 的大小增加了 3 倍,并且 SDXL 将第二个文本编码器(OpenCLIP ViT-bigG/14)与原始文本编码器结合使用,从而显着增加了参数数量。
- 引入了大小和裁剪条件,以防止训练数据被丢弃并获得对生成图像裁剪方式的更多控制。
- 引入了两阶段模型流程;基础模型(也可以作为独立模型运行)生成图像作为细化模型的输入,后者添加额外的、高质量的细节。
本指南将向您展示如何使用 SDXL 进行文图生成、图图生成和修复。
在开始之前,请确保您已安装以下库
# uncomment to install the necessary libraries in Colab
#!pip install -q diffusers transformers accelerate invisible-watermark>=0.2.0
我们建议安装 invisible-watermark 库以帮助识别生成的图像。如果安装了 invisible-watermark 库,则默认情况下会使用它。要禁用水印器
pipeline = StableDiffusionXLPipeline.from_pretrained(..., add_watermarker=False)
加载模型检查点
模型权重可能存储在 Hub 或本地上的单独子文件夹中,在这种情况下,您应该使用 from_pretrained() 方法
from diffusers import StableDiffusionXLPipeline, StableDiffusionXLImg2ImgPipeline
import torch
pipeline = StableDiffusionXLPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0", torch_dtype=torch.float16, variant="fp16", use_safetensors=True
).to("cuda")
refiner = StableDiffusionXLImg2ImgPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-refiner-1.0", torch_dtype=torch.float16, use_safetensors=True, variant="fp16"
).to("cuda")
您还可以使用 from_single_file() 方法从 Hub 或本地加载存储在单个文件格式(.ckpt
或 .safetensors
)中的模型检查点
from diffusers import StableDiffusionXLPipeline, StableDiffusionXLImg2ImgPipeline
import torch
pipeline = StableDiffusionXLPipeline.from_single_file(
"https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0/blob/main/sd_xl_base_1.0.safetensors",
torch_dtype=torch.float16
).to("cuda")
refiner = StableDiffusionXLImg2ImgPipeline.from_single_file(
"https://huggingface.co/stabilityai/stable-diffusion-xl-refiner-1.0/blob/main/sd_xl_refiner_1.0.safetensors", torch_dtype=torch.float16
).to("cuda")
文图生成
对于文图生成,请传递文本提示。默认情况下,SDXL 会生成 1024x1024 的图像以获得最佳效果。您可以尝试将 height
和 width
参数设置为 768x768 或 512x512,但低于 512x512 的图像可能无法正常工作。
from diffusers import AutoPipelineForText2Image
import torch
pipeline_text2image = AutoPipelineForText2Image.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0", torch_dtype=torch.float16, variant="fp16", use_safetensors=True
).to("cuda")
prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k"
image = pipeline_text2image(prompt=prompt).images[0]
image
图图生成
对于图图生成,SDXL 特别适合 768x768 到 1024x1024 之间的图像大小。传递初始图像和文本提示来对其进行条件控制。
from diffusers import AutoPipelineForImage2Image
from diffusers.utils import load_image, make_image_grid
# use from_pipe to avoid consuming additional memory when loading a checkpoint
pipeline = AutoPipelineForImage2Image.from_pipe(pipeline_text2image).to("cuda")
url = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/sdxl-text2img.png"
init_image = load_image(url)
prompt = "a dog catching a frisbee in the jungle"
image = pipeline(prompt, image=init_image, strength=0.8, guidance_scale=10.5).images[0]
make_image_grid([init_image, image], rows=1, cols=2)
修复
对于修复,您需要原始图像和要替换原始图像中内容的掩码。创建一个提示来描述您想要替换掩码区域的内容。
from diffusers import AutoPipelineForInpainting
from diffusers.utils import load_image, make_image_grid
# use from_pipe to avoid consuming additional memory when loading a checkpoint
pipeline = AutoPipelineForInpainting.from_pipe(pipeline_text2image).to("cuda")
img_url = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/sdxl-text2img.png"
mask_url = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/sdxl-inpaint-mask.png"
init_image = load_image(img_url)
mask_image = load_image(mask_url)
prompt = "A deep sea diver floating"
image = pipeline(prompt=prompt, image=init_image, mask_image=mask_image, strength=0.85, guidance_scale=12.5).images[0]
make_image_grid([init_image, mask_image, image], rows=1, cols=3)
优化图像质量
SDXL 包含一个专门用于对低噪声阶段图像进行去噪以从基础模型生成更高质量图像的 细化模型。有两种方法可以使用细化器
- 将基础模型和细化模型一起使用以生成细化图像。
- 使用基础模型生成图像,然后随后使用细化模型向图像添加更多细节(这是 SDXL 最初训练的方式)。
基础 + 细化模型
当您将基础模型和细化模型一起使用以生成图像时,这被称为 专家去噪器集合。专家去噪器集合方法需要的整体去噪步骤比将基础模型的输出传递给细化模型要少,因此运行速度应该快得多。但是,您将无法检查基础模型的输出,因为它仍然包含大量噪声。
作为专家去噪器集合,基础模型在高噪声扩散阶段充当专家,而细化模型在低噪声扩散阶段充当专家。加载基础模型和细化模型
from diffusers import DiffusionPipeline
import torch
base = DiffusionPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0", torch_dtype=torch.float16, variant="fp16", use_safetensors=True
).to("cuda")
refiner = DiffusionPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-refiner-1.0",
text_encoder_2=base.text_encoder_2,
vae=base.vae,
torch_dtype=torch.float16,
use_safetensors=True,
variant="fp16",
).to("cuda")
要使用此方法,您需要定义每个模型在其各自阶段运行的步数。对于基础模型,这由 denoising_end
参数控制,对于细化模型,则由 denoising_start
参数控制。
denoising_end
和 denoising_start
参数应为 0 到 1 之间的浮点数。这些参数表示为调度程序定义的离散步数的比例。如果您还使用 strength
参数,它将被忽略,因为去噪步数由模型训练的离散步数和声明的分数截止值确定。
让我们设置denoising_end=0.8
,这样基础模型就会执行降噪的最初 80% 的**高噪声**时间步长,并设置denoising_start=0.8
,这样细化模型就会执行降噪的最后 20% 的**低噪声**时间步长。基础模型的输出应该在**潜在**空间中,而不是 PIL 图像。
prompt = "A majestic lion jumping from a big stone at night"
image = base(
prompt=prompt,
num_inference_steps=40,
denoising_end=0.8,
output_type="latent",
).images
image = refiner(
prompt=prompt,
num_inference_steps=40,
denoising_start=0.8,
image=image,
).images[0]
image
细化模型也可以用于StableDiffusionXLInpaintPipeline中的修复。
from diffusers import StableDiffusionXLInpaintPipeline
from diffusers.utils import load_image, make_image_grid
import torch
base = StableDiffusionXLInpaintPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0", torch_dtype=torch.float16, variant="fp16", use_safetensors=True
).to("cuda")
refiner = StableDiffusionXLInpaintPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-refiner-1.0",
text_encoder_2=base.text_encoder_2,
vae=base.vae,
torch_dtype=torch.float16,
use_safetensors=True,
variant="fp16",
).to("cuda")
img_url = "https://raw.githubusercontent.com/CompVis/latent-diffusion/main/data/inpainting_examples/overture-creations-5sI6fQgYIuo.png"
mask_url = "https://raw.githubusercontent.com/CompVis/latent-diffusion/main/data/inpainting_examples/overture-creations-5sI6fQgYIuo_mask.png"
init_image = load_image(img_url)
mask_image = load_image(mask_url)
prompt = "A majestic tiger sitting on a bench"
num_inference_steps = 75
high_noise_frac = 0.7
image = base(
prompt=prompt,
image=init_image,
mask_image=mask_image,
num_inference_steps=num_inference_steps,
denoising_end=high_noise_frac,
output_type="latent",
).images
image = refiner(
prompt=prompt,
image=image,
mask_image=mask_image,
num_inference_steps=num_inference_steps,
denoising_start=high_noise_frac,
).images[0]
make_image_grid([init_image, mask_image, image.resize((512, 512))], rows=1, cols=3)
这种专家降噪器集成方法适用于所有可用的调度器!
基础模型到细化模型
SDXL 通过使用细化模型在图像到图像的设置中向基础模型完全去噪后的图像添加额外的高质量细节,从而提高图像质量。
加载基础模型和细化模型
from diffusers import DiffusionPipeline
import torch
base = DiffusionPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0", torch_dtype=torch.float16, variant="fp16", use_safetensors=True
).to("cuda")
refiner = DiffusionPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-refiner-1.0",
text_encoder_2=base.text_encoder_2,
vae=base.vae,
torch_dtype=torch.float16,
use_safetensors=True,
variant="fp16",
).to("cuda")
您可以将 SDXL 细化器与不同的基础模型一起使用。例如,您可以使用Hunyuan-DiT或PixArt-Sigma管道生成具有更好提示遵循性的图像。生成图像后,您可以将其传递给 SDXL 细化模型以增强最终生成的质量。
从基础模型生成图像,并将模型输出设置为**潜在**空间
prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k"
image = base(prompt=prompt, output_type="latent").images[0]
将生成的图像传递给细化模型
image = refiner(prompt=prompt, image=image[None, :]).images[0]
对于修复,在StableDiffusionXLInpaintPipeline中加载基础模型和细化模型,删除denoising_end
和denoising_start
参数,并为细化器选择更少的推理步骤。
微观条件
SDXL 训练涉及几种额外的条件技术,称为微观条件。这些包括原始图像大小、目标图像大小和裁剪参数。微观条件可以在推理时使用以创建高质量的居中图像。
由于无分类器引导,您可以使用微观条件和负微观条件参数。它们在StableDiffusionXLPipeline、StableDiffusionXLImg2ImgPipeline、StableDiffusionXLInpaintPipeline和StableDiffusionXLControlNetPipeline中可用。
尺寸条件
有两种类型的尺寸条件
original_size
条件来自训练批次中上采样的图像(因为丢弃构成近 40% 的总训练数据的较小图像将是浪费的)。这样,SDXL 就会学习到高分辨率图像中不应该存在上采样伪影。在推理过程中,您可以使用original_size
来指示原始图像分辨率。使用默认值(1024, 1024)
会生成更优质的图像,这些图像类似于数据集中 1024x1024 的图像。如果您选择使用较低的分辨率,例如(256, 256)
,模型仍然会生成 1024x1024 的图像,但它们看起来像数据集中低分辨率图像(更简单的图案、模糊)。target_size
条件来自微调 SDXL 以支持不同的图像纵横比。在推理过程中,如果您使用默认值(1024, 1024)
,您将获得一个类似于数据集中正方形图像构图的图像。我们建议对target_size
和original_size
使用相同的值,但您可以随意尝试其他选项!
🤗 Diffusers 还允许您指定图像大小的负条件,以将生成引导远离某些图像分辨率
from diffusers import StableDiffusionXLPipeline
import torch
pipe = StableDiffusionXLPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0", torch_dtype=torch.float16, variant="fp16", use_safetensors=True
).to("cuda")
prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k"
image = pipe(
prompt=prompt,
negative_original_size=(512, 512),
negative_target_size=(1024, 1024),
).images[0]
裁剪条件
以前 Stable Diffusion 模型生成的图像有时可能看起来像是被裁剪的。这是因为图像在训练期间实际上会被裁剪,以便批次中的所有图像都具有相同的大小。通过对裁剪坐标进行条件化,SDXL学习到没有裁剪 - 坐标(0, 0)
- 通常与居中的主体和完整的图像相关联(这是 🤗 Diffusers 中的默认值)。如果您想生成偏离中心的构图,可以尝试不同的坐标!
from diffusers import StableDiffusionXLPipeline
import torch
pipeline = StableDiffusionXLPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0", torch_dtype=torch.float16, variant="fp16", use_safetensors=True
).to("cuda")
prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k"
image = pipeline(prompt=prompt, crops_coords_top_left=(256, 0)).images[0]
image
您还可以指定负裁剪坐标,以将生成引导远离某些裁剪参数
from diffusers import StableDiffusionXLPipeline
import torch
pipe = StableDiffusionXLPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0", torch_dtype=torch.float16, variant="fp16", use_safetensors=True
).to("cuda")
prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k"
image = pipe(
prompt=prompt,
negative_original_size=(512, 512),
negative_crops_coords_top_left=(0, 0),
negative_target_size=(1024, 1024),
).images[0]
image
为每个文本编码器使用不同的提示
SDXL 使用两个文本编码器,因此可以为每个文本编码器传递不同的提示,这可以提高质量。将您的原始提示传递给prompt
,并将第二个提示传递给prompt_2
(如果您使用负提示,请使用negative_prompt
和negative_prompt_2
)
from diffusers import StableDiffusionXLPipeline
import torch
pipeline = StableDiffusionXLPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0", torch_dtype=torch.float16, variant="fp16", use_safetensors=True
).to("cuda")
# prompt is passed to OAI CLIP-ViT/L-14
prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k"
# prompt_2 is passed to OpenCLIP-ViT/bigG-14
prompt_2 = "Van Gogh painting"
image = pipeline(prompt=prompt, prompt_2=prompt_2).images[0]
image
双文本编码器还支持需要像在SDXL 文本反转部分中解释的那样单独加载的文本反转嵌入。
优化
SDXL 是一个大型模型,您可能需要优化内存才能使其在您的硬件上运行。以下是一些节省内存并加快推理速度的技巧。
- 对于内存不足错误,使用enable_model_cpu_offload()将模型卸载到 CPU
- base.to("cuda")
- refiner.to("cuda")
+ base.enable_model_cpu_offload()
+ refiner.enable_model_cpu_offload()
- 使用
torch.compile
可提高约 20% 的速度(您需要torch>=2.0
)
+ base.unet = torch.compile(base.unet, mode="reduce-overhead", fullgraph=True)
+ refiner.unet = torch.compile(refiner.unet, mode="reduce-overhead", fullgraph=True)
- 如果
torch<2.0
,请启用xFormers来运行 SDXL
+ base.enable_xformers_memory_efficient_attention()
+ refiner.enable_xformers_memory_efficient_attention()
其他资源
如果您有兴趣尝试 SDXL 中使用的 UNet2DConditionModel 的最小版本,请查看用 PyTorch 编写的并与 🤗 Diffusers 直接兼容的 minSDXL 实现。
< > GitHub 更新