# ControlNet

Les modèles [ControlNet](https://hf.co/papers/2302.05543) sont des adaptateurs entraînés sur la base d'un autre modèle pré-entraîné. Ils permettent un contrôle plus fin de la génération d'images en conditionnant le modèle avec une image d'entrée supplémentaire. Cette image d'entrée peut être un contour canny, une carte de profondeur, une pose humaine, et bien d'autres.

Si vous entraînez sur un GPU doté d’une vRAM limitée, vous devriez essayer d’activer les paramètres `gradient_checkpointing`, `gradient_accumulation_steps` et `mixed_precision` dans la commande d’entraînement. Vous pouvez également réduire votre empreinte mémoire en utilisant une attention efficace en mémoire avec [xFormers](../optimization/attention_backends).

Ce guide examine le script d’entraînement [train_controlnet.py](https://github.com/huggingface/diffusers/blob/main/examples/controlnet/train_controlnet.py) afin de vous familiariser avec celui-ci et de vous montrer comment l’adapter à votre propre cas d’usage.

Avant d'exécuter le script, assurez-vous d'installer la bibliothèque à partir du code source :

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

Puis accédez au dossier d'exemple contenant le script d'entraînement et installez les dépendances requises pour le script que vous utilisez :

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

> [!TIP]
> 🤗 Accelerate est une bibliothèque qui vous aide à entraîner sur plusieurs GPU/TPU ou avec une précision mixte. Elle configure automatiquement votre configuration d'entraînement en fonction de votre matériel et de votre environnement. Consultez le [tour rapide](https://huggingface.co/docs/accelerate/quicktour) de 🤗 Accelerate pour en savoir plus.

Initialiser un environnement 🤗 Accelerate :

```bash
accelerate config
```

Pour configurer un environnement 🤗 Accelerate par défaut sans choisir de configuration :

```bash
accelerate config default
```

Sinon, si votre environnement ne prend pas en charge un shell interactif, comme un notebook, vous pouvez utiliser :

```py
from accelerate.utils import write_basic_config

write_basic_config()
```

Enfin, si vous souhaitez entraîner un modèle sur votre propre jeu de données, consultez le guide [Create a dataset for training](create_dataset) pour apprendre à créer un jeu de données compatible avec le script d'entraînement.

> [!TIP]
> Les sections suivantes mettent en évidence les parties du script d'entraînement importantes pour comprendre comment le modifier, mais elles ne couvrent pas tous les aspects du script en détail. Si vous souhaitez en savoir plus, n'hésitez pas à lire le [script](https://github.com/huggingface/diffusers/blob/main/examples/controlnet/train_controlnet.py) et à nous faire part de vos questions ou préoccupations.

## Paramètres du script

Le script d’entraînement fournit de nombreux paramètres pour vous aider à personnaliser votre session d’entraînement. Tous les paramètres et leurs descriptions se trouvent dans la fonction [`parse_args()`](https://github.com/huggingface/diffusers/blob/64603389da01082055a901f2883c4810d1144edb/examples/controlnet/train_controlnet.py#L231). Cette fonction fournit des valeurs par défaut pour chaque paramètre, telles que la taille du lot d’entraînement et le taux d’apprentissage, mais vous pouvez également définir vos propres valeurs dans la commande d’entraînement si vous le souhaitez.

Par exemple, pour accélérer l’entraînement avec la précision mixte en utilisant le format fp16, ajoutez le paramètre `--mixed_precision` à la commande d’entraînement :

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

De nombreux paramètres de base et importants sont décrits dans le guide d’entraînement [Text-to-image](text2image#script-parameters), ce guide se concentre donc uniquement sur les paramètres pertinents pour ControlNet :

- `--max_train_samples` : le nombre d'échantillons d'entraînement ; vous pouvez le réduire pour accélérer l'entraînement, mais si vous souhaitez diffuser des jeux de données très volumineux, vous devrez inclure ce paramètre ainsi que le paramètre `--streaming` dans votre commande d'entraînement
- `--gradient_accumulation_steps` : nombre d'étapes de mise à jour à accumuler avant la rétropropagation ; cela permet d'entraîner avec une taille de lot supérieure à ce que la mémoire de votre GPU peut généralement gérer

### Pondération Min-SNR

La stratégie de pondération [Min-SNR](https://huggingface.co/papers/2303.09556) peut aider à l'entraînement en rééquilibrant la perte pour atteindre une convergence plus rapide. Le script d'entraînement prend en charge la prédiction de `epsilon` (bruit) ou de `v_prediction`, mais Min-SNR est compatible avec les deux types de prédiction. Cette stratégie de pondération n'est prise en charge que par PyTorch.

Ajoutez le paramètre `--snr_gamma` et définissez-le à la valeur recommandée de 5,0 :

```bash
accelerate launch train_controlnet.py \
  --snr_gamma=5.0
```

## Script d'entraînement

Comme pour les paramètres du script, un aperçu général du script d’entraînement est fourni dans le guide d’entraînement [Text-to-image](text2image#training-script). En revanche, ce guide se concentre sur les parties pertinentes du script ControlNet.

Le script d'entraînement comporte une fonction [`make_train_dataset`](https://github.com/huggingface/diffusers/blob/64603389da01082055a901f2883c4810d1144edb/examples/controlnet/train_controlnet.py#L582) pour prétraiter le jeu de données avec des transformations d'images et la tokenisation des légendes. Vous remarquerez qu'en plus de la tokenisation habituelle des légendes et des transformations d'images, le script inclut également des transformations pour l'image de conditionnement.

> [!TIP]
> Si vous diffusez un jeu de données sur un TPU, les performances peuvent être limitées par la bibliothèque 🤗 Datasets, qui n’est pas optimisée pour les images. Pour garantir un débit maximal, il est recommandé d’explorer d’autres formats de jeux de données tels que [WebDataset](https://github.com/webdataset/webdataset), [TorchData](https://github.com/pytorch/data) et [TensorFlow Datasets](https://www.tensorflow.org/datasets/tfless_tfds).

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

Dans la fonction [`main()`](https://github.com/huggingface/diffusers/blob/64603389da01082055a901f2883c4810d1144edb/examples/controlnet/train_controlnet.py#L713), vous trouverez le code de chargement du tokenizer, de l'encodeur de texte, du scheduler et des modèles. C'est également ici que le modèle ControlNet est chargé, soit à partir de poids existants, soit initialisé aléatoirement à partir d'un UNet :

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

L'[optimizer](https://github.com/huggingface/diffusers/blob/64603389da01082055a901f2883c4810d1144edb/examples/controlnet/train_controlnet.py#L871) est configuré pour mettre à jour les paramètres de ControlNet :

```py
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,
)
```

Enfin, dans la [boucle d'entraînement](https://github.com/huggingface/diffusers/blob/64603389da01082055a901f2883c4810d1144edb/examples/controlnet/train_controlnet.py#L943), les embeddings de texte de conditionnement et l'image sont transmis aux blocs inférieurs et intermédiaires du modèle ControlNet :

```py
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,
)
```

Si vous souhaitez en savoir plus sur le fonctionnement de la boucle d’entraînement, consultez le tutoriel [Comprendre les pipelines, les modèles et les planificateurs](../using-diffusers/write_own_pipeline), qui détaille le schéma de base du processus de débruitage.

## Lancer le script

Vous êtes maintenant prêt à lancer le script d'entraînement ! 🚀

Ce guide utilise le jeu de données [fusing/fill50k](https://huggingface.co/datasets/fusing/fill50k), mais n'oubliez pas que vous pouvez créer et utiliser votre propre jeu de données si vous le souhaitez (voir le guide [Créer un jeu de données pour l'entraînement](create_dataset)).

Définissez la variable d’environnement `MODEL_NAME` sur un identifiant de modèle du Hub ou un chemin vers un modèle local, et `OUTPUT_DIR` sur l’emplacement où vous souhaitez enregistrer le modèle.

Téléchargez les images suivantes pour conditionner votre entraînement avec :

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

Une dernière chose avant de lancer le script ! Selon le GPU dont vous disposez, il peut être nécessaire d’activer certaines optimisations pour entraîner un ControlNet. La configuration par défaut de ce script nécessite environ 38 Go de vRAM. Si vous entraînez sur plus d’un GPU, ajoutez le paramètre `--multi_gpu` à la commande `accelerate launch`.

Sur un GPU de 16 Go, vous pouvez utiliser l'optimiseur 8 bits de bitsandbytes et le gradient checkpointing pour optimiser votre session d'entraînement. Installez bitsandbytes :

```py
pip install bitsandbytes
```

Ensuite, ajoutez le paramètre suivant à votre commande d'entraînement :

```bash
accelerate launch train_controlnet.py \
  --gradient_checkpointing \
  --use_8bit_adam \
```

Sur un GPU de 12 Go, vous aurez besoin de l’optimiseur 8 bits de bitsandbytes, du gradient checkpointing, de xFormers, et vous devrez définir les gradients sur `None` au lieu de zéro afin de réduire votre consommation mémoire.

```bash
accelerate launch train_controlnet.py \
  --use_8bit_adam \
  --gradient_checkpointing \
  --enable_xformers_memory_efficient_attention \
  --set_grads_to_none \
```

Sur un GPU de 8 Go, vous devrez utiliser [DeepSpeed](https://www.deepspeed.ai/) pour décharger certains tenseurs de la vRAM vers le CPU ou le NVME afin de permettre l’entraînement avec moins de mémoire GPU.

Exécutez la commande suivante pour configurer votre environnement 🤗 Accelerate :

```bash
accelerate config
```

Lors de la configuration, confirmez que vous souhaitez utiliser DeepSpeed stage 2. Il devrait désormais être possible d'entraîner avec moins de 8 Go de vRAM en combinant DeepSpeed stage 2, la précision mixte fp16 et le déchargement des paramètres du modèle et de l'état de l'optimiseur sur le CPU. L'inconvénient est que cela nécessite plus de RAM système (~25 Go). Consultez la [documentation DeepSpeed](https://huggingface.co/docs/accelerate/usage_guides/deepspeed) pour plus d'options de configuration. Votre fichier de configuration devrait ressembler à ceci :

```bash
compute_environment: LOCAL_MACHINE
deepspeed_config:
  gradient_accumulation_steps: 4
  offload_optimizer_device: cpu
  offload_param_device: cpu
  zero3_init_flag: false
  zero_stage: 2
distributed_type: DEEPSPEED
```

Vous devez également remplacer l’optimiseur Adam par défaut par la version optimisée de DeepSpeed, [`deepspeed.ops.adam.DeepSpeedCPUAdam`](https://deepspeed.readthedocs.io/en/latest/optimizers.html#adam-cpu), pour un gain de vitesse significatif. L’activation de `DeepSpeedCPUAdam` exige que la version de la chaîne d’outils CUDA de votre système soit identique à celle installée avec PyTorch.

Les optimiseurs 8 bits de bitsandbytes ne semblent pas être compatibles avec DeepSpeed pour le moment.

C'est tout ! Vous n'avez pas besoin d'ajouter de paramètres supplémentaires à votre commande d'entraînement.

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

Une fois l’entraînement terminé, vous pouvez utiliser votre nouveau modèle pour l’inférence !

```py
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) est un puissant modèle de génération d’images à partir de texte qui produit des images haute résolution et qui ajoute un second encodeur de texte à son architecture. Utilisez le script [`train_controlnet_sdxl.py`](https://github.com/huggingface/diffusers/blob/main/examples/controlnet/train_controlnet_sdxl.py) pour entraîner un adaptateur ControlNet pour le modèle SDXL.

Le script d’entraînement SDXL est abordé plus en détail dans le guide [Entraînement SDXL](sdxl).

## Étapes suivantes

Félicitations pour l'entraînement de votre propre ControlNet ! Pour en savoir plus sur l'utilisation de votre nouveau modèle, les guides suivants peuvent s'avérer utiles :

- Apprenez à [utiliser un ControlNet](../using-diffusers/controlnet) pour l'inférence sur une variété de tâches.

