# T2I-Adapter

[T2I-Adapter](https://hf.co/papers/2302.08453) 是一个轻量级适配器模型，它通过提供额外的条件输入图像（线稿、canny、草图、深度、姿态）来更好地控制图像生成。它与 ControlNet 类似，但体积要小得多（约 77M 参数，文件大小约 300MB），因为它只是将权重插入到 UNet 中，而不是复制并训练整个 UNet。

T2I-Adapter 仅支持与 Stable Diffusion XL (SDXL) 模型一起进行训练。

本指南将深入讲解 [train_t2i_adapter_sdxl.py](https://github.com/huggingface/diffusers/blob/main/examples/t2i_adapter/train_t2i_adapter_sdxl.py) 训练脚本，帮助你熟悉该脚本，并了解如何将其适配到自身的使用场景中。

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

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

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

```bash
cd examples/t2i_adapter
pip install -r requirements.txt
```

> [!TIP]
> 🤗 Accelerate 是一个用于在多个 GPU/TPU 上训练或使用混合精度训练的库。它会根据你的硬件和环境自动配置训练设置。请查看 🤗 Accelerate 的 [快速入门](https://huggingface.co/docs/accelerate/quicktour) 以了解更多信息。

初始化一个 🤗 Accelerate 环境：

```bash
accelerate config
```

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

```bash
accelerate config default
```

或者，如果你的环境不支持交互式 shell（例如 notebook），你可以使用：

```py
from accelerate.utils import write_basic_config

write_basic_config()
```

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

> [!TIP]
> 以下各节重点介绍了训练脚本中对于理解如何修改脚本至关重要的部分，但并未详细涵盖脚本的每个方面。如果您希望了解更多，请随时阅读[脚本](https://github.com/huggingface/diffusers/blob/main/examples/t2i_adapter/train_t2i_adapter_sdxl.py)，并告诉我们您是否有任何疑问或顾虑。

## 脚本参数

训练脚本提供了许多参数，帮助你自定义训练过程。所有参数及其说明都可以在 [`parse_args()`](https://github.com/huggingface/diffusers/blob/aab6de22c33cc01fb7bc81c0807d6109e2c998c9/examples/t2i_adapter/train_t2i_adapter_sdxl.py#L233) 函数中找到。该函数为每个参数提供了默认值，例如训练批次大小和学习率，但你也可以在训练命令中设置自己的值。

例如，要启用梯度累积，请在训练命令中添加 `--gradient_accumulation_steps` 参数：

```bash
accelerate launch train_t2i_adapter_sdxl.py \
  ----gradient_accumulation_steps=4
```

许多基础且重要的参数已在[文本到图像](text2image#script-parameters)训练指南中介绍，因此本指南仅聚焦于与 T2I-Adapter 相关的参数：

- `--pretrained_vae_model_name_or_path`：预训练 VAE 的路径；SDXL 的 VAE 存在数值不稳定的问题，因此该参数允许你指定一个更优的 [VAE](https://huggingface.co/madebyollin/sdxl-vae-fp16-fix)
- `--crops_coords_top_left_h` 和 `--crops_coords_top_left_w`：包含在 SDXL 裁剪坐标嵌入中的高度和宽度坐标
- `--conditioning_image_column`：数据集中条件图像所在的列
- `--proportion_empty_prompts`：将图像提示替换为空字符串的比例

## 训练脚本

与脚本参数类似，[文本到图像](text2image#training-script)训练指南中提供了训练脚本的逐步讲解。本指南则着重介绍脚本中与 T2I-Adapter 相关的部分。

训练脚本首先准备数据集。这包括对提示词进行[分词](https://github.com/huggingface/diffusers/blob/aab6de22c33cc01fb7bc81c0807d6109e2c998c9/examples/t2i_adapter/train_t2i_adapter_sdxl.py#L674)，以及对图像和条件图像[应用变换](https://github.com/huggingface/diffusers/blob/aab6de22c33cc01fb7bc81c0807d6109e2c998c9/examples/t2i_adapter/train_t2i_adapter_sdxl.py#L714)。

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

在 [`main()`](https://github.com/huggingface/diffusers/blob/aab6de22c33cc01fb7bc81c0807d6109e2c998c9/examples/t2i_adapter/train_t2i_adapter_sdxl.py#L770) 函数中，T2I-Adapter 要么从预训练适配器加载，要么进行随机初始化：

```py
if args.adapter_model_name_or_path:
    logger.info("Loading existing adapter weights.")
    t2iadapter = T2IAdapter.from_pretrained(args.adapter_model_name_or_path)
else:
    logger.info("Initializing t2iadapter weights.")
    t2iadapter = T2IAdapter(
        in_channels=3,
        channels=(320, 640, 1280, 1280),
        num_res_blocks=2,
        downscale_factor=16,
        adapter_type="full_adapter_xl",
    )
```

[optimizer](https://github.com/huggingface/diffusers/blob/aab6de22c33cc01fb7bc81c0807d6109e2c998c9/examples/t2i_adapter/train_t2i_adapter_sdxl.py#L952) 已针对 T2I-Adapter 参数完成初始化：

```py
params_to_optimize = t2iadapter.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,
)
```

最后，在 [训练循环](https://github.com/huggingface/diffusers/blob/aab6de22c33cc01fb7bc81c0807d6109e2c998c9/examples/t2i_adapter/train_t2i_adapter_sdxl.py#L1086) 中，适配器条件图像和文本嵌入被传入 UNet 以预测噪声残差：

```py
t2iadapter_image = batch["conditioning_pixel_values"].to(dtype=weight_dtype)
down_block_additional_residuals = t2iadapter(t2iadapter_image)
down_block_additional_residuals = [
    sample.to(dtype=weight_dtype) for sample in down_block_additional_residuals
]

model_pred = unet(
    inp_noisy_latents,
    timesteps,
    encoder_hidden_states=batch["prompt_ids"],
    added_cond_kwargs=batch["unet_added_conditions"],
    down_block_additional_residuals=down_block_additional_residuals,
).sample
```

如果想进一步了解训练循环的工作原理，请查看[理解流水线、模型和调度器](../using-diffusers/write_own_pipeline)教程，其中详细拆解了去噪过程的基本模式。

## 运行脚本

现在，你已准备好启动训练脚本！🚀

在此示例训练中，您将使用 [fusing/fill50k](https://huggingface.co/datasets/fusing/fill50k) 数据集。您也可以创建并使用自己的数据集（参见 [创建用于训练的数据集](create_dataset) 指南）。

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

下载以下图像，用于条件化您的训练：

```bash
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
```

> [!TIP]
> 若要使用 Weights & Biases 监控训练进度，请在训练命令中添加 `--report_to=wandb` 参数。同时，还需要在训练命令中添加 `--validation_image`、`--validation_prompt` 和 `--validation_steps`，以便跟踪结果。这对于调试模型和查看中间结果非常有用。

```bash
export MODEL_DIR="stabilityai/stable-diffusion-xl-base-1.0"
export OUTPUT_DIR="path to save model"

accelerate launch train_t2i_adapter_sdxl.py \
 --pretrained_model_name_or_path=$MODEL_DIR \
 --output_dir=$OUTPUT_DIR \
 --dataset_name=fusing/fill50k \
 --mixed_precision="fp16" \
 --resolution=1024 \
 --learning_rate=1e-5 \
 --max_train_steps=15000 \
 --validation_image "./conditioning_image_1.png" "./conditioning_image_2.png" \
 --validation_prompt "red circle with blue background" "cyan circle with brown floral background" \
 --validation_steps=100 \
 --train_batch_size=1 \
 --gradient_accumulation_steps=4 \
 --report_to="wandb" \
 --seed=42 \
 --push_to_hub
```

训练完成后，您可以使用您的 T2I-Adapter 进行推理：

```py
from diffusers import StableDiffusionXLAdapterPipeline, T2IAdapter, EulerAncestralDiscreteSchedulerTest
from diffusers.utils import load_image
import torch

adapter = T2IAdapter.from_pretrained("path/to/adapter", dtype=torch.float16)
pipeline = StableDiffusionXLAdapterPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0", adapter=adapter, dtype=torch.float16
)

pipeline.scheduler = EulerAncestralDiscreteSchedulerTest.from_config(pipe.scheduler.config)
pipeline.enable_xformers_memory_efficient_attention()
pipeline.enable_model_cpu_offload()

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, image=control_image, generator=generator
).images[0]
image.save("./output.png")
```

## 后续步骤

恭喜您训练了一个 T2I-Adapter 模型！🎉 如需了解更多：

- 阅读[使用 T2I-Adapters 实现 SDXL 的高效可控生成](https://huggingface.co/blog/t2i-sdxl-adapters)博客文章，以了解 T2I-Adapter 团队实验结果的更多详细信息。

