Diffusers documentation

ControlNet

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v0.43.0).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

ControlNet

ControlNet 模型是在另一个预训练模型之上训练的适配器。它通过引入额外的输入图像作为条件,从而实现对图像生成过程更精细的控制。该输入图像可以是 Canny 边缘、深度图、人体姿态等。

如果用于训练的 GPU 显存有限,建议在训练命令中启用 gradient_checkpointing、gradient_accumulation_steps 和 mixed_precision 参数。此外,还可以使用 xFormers 提供的内存高效注意力机制来降低内存占用。

本指南将深入讲解 train_controlnet.py 训练脚本,帮助你熟悉该脚本,并了解如何将其适配到自身的使用场景中。

在运行脚本之前,请确保从源代码安装该库:

git clone https://github.com/huggingface/diffusers
cd diffusers
pip install .

然后,导航到包含训练脚本的示例文件夹,并安装您正在使用的脚本所需的依赖项:

cd examples/controlnet
pip install -r requirements.txt

🤗 Accelerate 是一个用于在多个 GPU/TPU 上训练或使用混合精度训练的库。它会根据你的硬件和环境自动配置训练设置。请查看 🤗 Accelerate 的 快速入门 以了解更多信息。

初始化一个 🤗 Accelerate 环境:

accelerate config

要设置一个默认的 🤗 Accelerate 环境,而不选择任何配置:

accelerate config default

或者,如果你的环境不支持交互式 shell(例如 notebook),你可以使用:

from accelerate.utils import write_basic_config

write_basic_config()

最后,如果您想在自己的数据集上训练模型,请查看创建训练数据集指南,了解如何创建可与训练脚本配合使用的数据集。

以下各部分重点介绍了训练脚本中对于理解如何修改脚本至关重要的内容,但并未详细涵盖脚本的每个方面。如果您希望了解更多,请随时阅读脚本,并告诉我们您是否有任何疑问或顾虑。

脚本参数

训练脚本提供了许多参数,帮助你自定义训练过程。所有参数及其说明都可以在 parse_args() 函数中找到。该函数为每个参数提供了默认值,例如训练批次大小和学习率,但你也可以在训练命令中设置自己的值。

例如,若要使用 fp16 格式通过混合精度加速训练,请在训练命令中添加 --mixed_precision 参数:

accelerate launch train_controlnet.py \
  --mixed_precision="fp16"

许多基础且重要的参数已在文本到图像训练指南中介绍,因此本指南仅聚焦于与 ControlNet 相关的参数:

  • --max_train_samples:训练样本的数量;您可以降低此值以加快训练速度,但如果您想要流式处理非常大的数据集,则需要在训练命令中包含此参数以及 --streaming 参数
  • --gradient_accumulation_steps:执行反向传播之前累积的更新步数;这允许你使用比 GPU 显存通常能处理更大的批量大小进行训练

Min-SNR 加权

Min-SNR 加权策略可以通过重新平衡损失来加速收敛,从而辅助训练。训练脚本支持预测 epsilon(噪声)或 v_prediction,而 Min-SNR 与这两种预测类型均兼容。此加权策略仅支持 PyTorch。

添加 --snr_gamma 参数并将其设置为推荐值 5.0:

accelerate launch train_controlnet.py \
  --snr_gamma=5.0

训练脚本

与脚本参数类似,文本到图像训练指南中提供了训练脚本的总体介绍。本指南将重点介绍 ControlNet 脚本中的相关部分。

训练脚本中有一个 make_train_dataset 函数,用于通过图像变换和说明词元化对数据集进行预处理。您会看到,除了常规的说明词元化和图像变换外,该脚本还包含针对条件图像的变换。

如果您在 TPU 上流式传输数据集,性能可能会受到 🤗 Datasets 库的瓶颈限制,因为该库并未针对图像进行优化。为确保最大吞吐量,建议您探索其他数据集格式,例如 WebDataset、TorchData 和 TensorFlow Datasets。

conditioning_image_transforms = transforms.Compose(
    [
        transforms.Resize(args.resolution, interpolation=transforms.InterpolationMode.BILINEAR),
        transforms.CenterCrop(args.resolution),
        transforms.ToTensor(),
    ]
)

在 main() 函数中,你可以找到加载 tokenizer、text encoder、scheduler 和模型的代码。ControlNet 模型也是在这里加载的,它可以从现有权重加载,也可以从 UNet 随机初始化:

if args.controlnet_model_name_or_path:
    logger.info("Loading existing controlnet weights")
    controlnet = ControlNetModel.from_pretrained(args.controlnet_model_name_or_path)
else:
    logger.info("Initializing controlnet weights from unet")
    controlnet = ControlNetModel.from_unet(unet)

optimizer 已配置为更新 ControlNet 参数:

params_to_optimize = controlnet.parameters()
optimizer = optimizer_class(
    params_to_optimize,
    lr=args.learning_rate,
    betas=(args.adam_beta1, args.adam_beta2),
    weight_decay=args.adam_weight_decay,
    eps=args.adam_epsilon,
)

最后,在 训练循环 中,条件文本嵌入和图像会被传入 ControlNet 模型的 down 和 mid 块:

encoder_hidden_states = text_encoder(batch["input_ids"])[0]
controlnet_image = batch["conditioning_pixel_values"].to(dtype=weight_dtype)

down_block_res_samples, mid_block_res_sample = controlnet(
    noisy_latents,
    timesteps,
    encoder_hidden_states=encoder_hidden_states,
    controlnet_cond=controlnet_image,
    return_dict=False,
)

如果想进一步了解训练循环的工作原理,请查看理解流水线、模型和调度器教程,其中详细拆解了去噪过程的基本模式。

运行脚本

现在,你已准备好启动训练脚本!🚀

本指南使用 fusing/fill50k 数据集,但请记住,如果您愿意,也可以创建并使用自己的数据集(参见 为训练创建数据集 指南)。

将环境变量 MODEL_NAME 设置为 Hub 上的模型 ID 或本地模型的路径,并将 OUTPUT_DIR 设置为你希望保存模型的位置。

下载以下图像,用于条件化您的训练:

wget https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/controlnet_training/conditioning_image_1.png
wget https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/controlnet_training/conditioning_image_2.png

在运行脚本之前,还有一件事!根据你所使用的 GPU,你可能需要启用某些优化来训练 ControlNet。此脚本的默认配置大约需要 38GB 的 vRAM。如果你使用多块 GPU 进行训练,请在 accelerate launch 命令中添加 --multi_gpu 参数。

16GB
12GB
8GB

在 16GB 的 GPU 上,你可以使用 bitsandbytes 8 位优化器和梯度检查点来优化训练过程。安装 bitsandbytes:

pip install bitsandbytes

然后,在训练命令中添加以下参数:

accelerate launch train_controlnet.py \
  --gradient_checkpointing \
  --use_8bit_adam \
export MODEL_DIR="stable-diffusion-v1-5/stable-diffusion-v1-5"
export OUTPUT_DIR="path/to/save/model"

accelerate launch train_controlnet.py \
 --pretrained_model_name_or_path=$MODEL_DIR \
 --output_dir=$OUTPUT_DIR \
 --dataset_name=fusing/fill50k \
 --resolution=512 \
 --learning_rate=1e-5 \
 --validation_image "./conditioning_image_1.png" "./conditioning_image_2.png" \
 --validation_prompt "red circle with blue background" "cyan circle with brown floral background" \
 --train_batch_size=1 \
 --gradient_accumulation_steps=4 \
 --push_to_hub

训练完成后,您就可以使用新训练的模型进行推理了!

from diffusers import StableDiffusionControlNetPipeline, ControlNetModel
from diffusers.utils import load_image
import torch

controlnet = ControlNetModel.from_pretrained("path/to/controlnet", dtype=torch.float16)
pipeline = StableDiffusionControlNetPipeline.from_pretrained(
    "path/to/base/model", controlnet=controlnet, dtype=torch.float16
).to("cuda")  # or "mps", "xpu", "cpu"

control_image = load_image("./conditioning_image_1.png")
prompt = "pale golden rod circle with old lace background"

generator = torch.manual_seed(0)
image = pipeline(prompt, num_inference_steps=20, generator=generator, image=control_image).images[0]
image.save("./output.png")

Stable Diffusion XL

Stable Diffusion XL (SDXL) 是一个强大的文本生成图像模型,能够生成高分辨率图像,并在其架构中增加了第二个文本编码器。使用 train_controlnet_sdxl.py 脚本为 SDXL 模型训练 ControlNet 适配器。

SDXL 训练脚本在 SDXL 训练 指南中有更详细的介绍。

后续步骤

恭喜您训练了自己的 ControlNet!如需了解如何使用您的新模型,以下指南可能对您有所帮助:

  • 了解如何在多种任务中使用 ControlNet 进行推理。
Update on GitHub