Skip to content

Stable Diffusion XL

[[open-in-colab]]

Stable Diffusion XL (SDXL) 是一种强大的文本到图像生成模型,它在三个关键方面对之前的 Stable Diffusion 模型进行了迭代:

  1. UNet 的规模扩大了3倍,SDXL 结合了第二个文本编码器(OpenCLIP ViT-bigG/14)与原始文本编码器,显著增加了参数数量
  2. 引入了尺寸和裁剪条件,以防止训练数据的丢失,并获得更多对生成图像裁剪方式的控制
  3. 引入了两阶段模型流程;基础模型(也可以作为独立模型运行)生成图像作为 精炼 模型的输入,后者添加额外的高质量细节

本指南将向你展示如何使用 SDXL 进行文本到图像、图像到图像以及图像修复。

在开始之前,请确保你已安装以下库:

py
# uncomment to install the necessary libraries in Colab
#!pip install -q diffusers transformers accelerate invisible-watermark>=0.2.0
py
pipeline = StableDiffusionXLPipeline.from_pretrained(..., add_watermarker=False)

加载模型检查点

模型权重可能存储在Hub或本地的单独子文件夹中,在这种情况下,您应使用[~StableDiffusionXLPipeline.from_pretrained]方法:

py
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")

您还可以使用[~StableDiffusionXLPipeline.from_single_file]方法从Hub或本地加载存储在单个文件格式(.ckpt.safetensors)中的模型检查点:

py
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的图像以获得最佳结果。您可以尝试将heightwidth参数设置为768x768或512x512,但低于512x512的设置可能无法正常工作。

py
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
generated image of an astronaut in a jungle

图像到图像

对于图像到图像的任务,SDXL 在图像尺寸介于 768x768 和 1024x1024 之间时表现尤为出色。传入一张初始图像,并提供一个文本提示来指导图像的生成:

py
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)
generated image of a dog catching a frisbee in a jungle

图像修复

对于图像修复,你需要原始图像和一张遮罩图,遮罩图标记了你希望在原始图像中替换的部分。创建一个提示来描述你希望用什么来替换遮罩区域。

py
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)
generated image of a deep sea diver in a jungle

优化图像质量

SDXL 包含一个专门用于去噪低噪声阶段图像的 优化模型,可以从基础模型生成更高质量的图像。使用优化模型有两种方式:

  1. 同时使用基础模型和优化模型来生成优化后的图像
  2. 使用基础模型生成图像,然后使用优化模型为图像添加更多细节(这是 SDXL 最初训练的方式)

基础模型 + 优化模型

当你同时使用基础模型和优化模型来生成图像时,这被称为 专家去噪器集合。专家去噪器集合方法相比将基础模型的输出传递给优化模型所需的总体去噪步骤更少,因此运行速度应该显著更快。然而,你将无法检查基础模型的输出,因为它仍然包含大量噪声。

作为专家去噪器集合,基础模型在高度噪声扩散阶段充当专家,而优化模型在低噪声扩散阶段充当专家。加载基础模型和优化模型:

py
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=0.8,以便基础模型执行前80%的高噪声时间步的去噪,并设置denoising_start=0.8,以便精炼模型执行后20%的低噪声时间步的去噪。基础模型的输出应为潜在空间而不是PIL图像。

py
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
generated image of a lion on a rock at night
default base model
generated image of a lion on a rock at night in higher quality
ensemble of expert denoisers

精炼模型也可以用于[StableDiffusionXLInpaintPipeline]中的图像修复:

py
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通过在图像到图像的设置中,使用精炼模型为从基础模型生成的完全去噪图像添加额外的高质量细节,从而提升了图像质量。

加载基础模型和精炼模型:

py
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")

从基础模型生成图像,并将模型输出设置为潜在空间:

py
prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k"

image = base(prompt=prompt, output_type="latent").images[0]

将生成的图像传递给精炼模型:

py
image = refiner(prompt=prompt, image=image[None, :]).images[0]
generated image of an astronaut riding a green horse on Mars
base model
higher quality generated image of an astronaut riding a green horse on Mars
base model + refiner model

对于修复(inpainting),请在[StableDiffusionXLInpaintPipeline]中加载基础模型和细化模型,移除denoising_enddenoising_start参数,并为细化模型选择较少的推理步骤。

微调条件

SDXL 的训练涉及几种额外的条件技术,这些技术被称为微调条件。这些条件包括原始图像尺寸、目标图像尺寸和裁剪参数。在推理时可以使用这些微调条件来创建高质量、居中的图像。

尺寸条件

有两种类型的尺寸条件:

  • original_size 条件来自于训练批次中的放大图像(因为丢弃那些占训练数据近40%的小图像是浪费的)。这样,SDXL 学会了高分辨率图像中不应该存在放大伪影。在推理时,你可以使用original_size来指示原始图像分辨率。使用默认值(1024, 1024)会产生更高质量的图像,这些图像类似于数据集中的1024x1024图像。如果你选择使用较低的分辨率,例如(256, 256),模型仍然会生成1024x1024的图像,但它们看起来会像数据集中低分辨率的图像(更简单的图案,模糊)。

  • target_size 条件来自于对SDXL进行微调以支持不同的图像宽高比。在推理时,如果你使用默认值(1024, 1024),你将得到一张类似于数据集中方形图像构图的图像。我们建议对target_sizeoriginal_size使用相同的值,但也可以随意尝试其他选项!

🤗 Diffusers 还允许你指定关于图像尺寸的负条件,以引导生成远离某些图像分辨率:

py
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]
Images negatively conditioned on image resolutions of (128, 128), (256, 256), and (512, 512).

裁剪条件

由之前的 Stable Diffusion 模型生成的图像有时可能会显得被裁剪过。这是因为图像在训练过程中实际上被裁剪了,以便批次中的所有图像都具有相同的大小。通过条件化裁剪坐标,SDXL 学习 到不进行裁剪 - 坐标 (0, 0) - 通常与居中的主体和完整的面部相关联(这是 🤗 Diffusers 中的默认值)。如果你想生成非居中的构图,可以尝试不同的坐标!

py
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
generated image of an astronaut in a jungle, slightly cropped

你还可以指定负的裁剪坐标,以引导生成远离某些裁剪参数:

py
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_promptnegative_prompt_2):

py
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
generated image of an astronaut in a jungle in the style of a van gogh painting

双文本编码器还支持需要单独加载的文本反转嵌入,如SDXL 文本反转部分所述。

优化

SDXL 是一个大型模型,你可能需要优化内存以使其在你的硬件上运行。以下是一些节省内存和加快推理速度的技巧。

  1. 使用 [~StableDiffusionXLPipeline.enable_model_cpu_offload] 将模型卸载到 CPU 以解决内存不足错误:
diff
- base.to("cuda")
- refiner.to("cuda")
+ base.enable_model_cpu_offload()
+ refiner.enable_model_cpu_offload()
  1. 使用 torch.compile 获得约 20% 的速度提升(你需要 torch>=2.0):
diff
+ base.unet = torch.compile(base.unet, mode="reduce-overhead", fullgraph=True)
+ refiner.unet = torch.compile(refiner.unet, mode="reduce-overhead", fullgraph=True)
  1. 如果 torch<2.0,启用 xFormers 以运行 SDXL:
diff
+ base.enable_xformers_memory_efficient_attention()
+ refiner.enable_xformers_memory_efficient_attention()

其他资源

如果你对实验 UNet2DConditionModel 的最小版本感兴趣,可以查看 minSDXL 实现,该实现使用 PyTorch 编写,并且直接兼容 🤗 Diffusers。