Module 6 — ControlNet : pose, contours, profondeur
Les modules précédents ont montré ce que le texte savait faire, et où il échouait. Il reste un plafond dur : on ne peut pas dire au modèle « la chaise, exactement dans cette pose, sous cet angle, avec ces proportions ». C'est ce que ControlNet débloque, en injectant à chaque étape de débruitage une carte structurelle — contours, profondeur, squelette — qui vient guider le U-Net en plus de la consigne texte.
Le principe : une seconde voie d'information
ControlNet a été proposé en 2023 par Lvmin Zhang. L'idée technique est frappante par sa simplicité : on duplique la moitié encodeur du U-Net, on gèle l'original, et on entraîne la copie sur une nouvelle entrée — la carte de contrôle. Les activations de la copie sont ensuite additionnées à celles de l'original à travers des couches de connexion initialisées à zéro (les fameuses zero convolutions). Cette initialisation à zéro fait que, au début de l'entraînement, ControlNet est un ajout transparent : il ne perturbe pas le modèle de base.
Résultat pratique : on peut télécharger un ControlNet entraîné pour un type de contrôle particulier (contours, pose, profondeur) et le brancher sans réentraîner SDXL ou SD 1.5. Chaque type de contrôle est un fichier de poids séparé, souvent une centaine de mégaoctets.
Les préprocesseurs : extraire la carte de contrôle
Une carte de contrôle n'est jamais fournie directement par l'utilisateur : elle est extraite d'une image de référence par un préprocesseur, algorithme dédié qui distille l'information structurelle voulue.
Trois familles couvrent la majorité des cas.
Canny produit une carte binaire des contours par le classique détecteur de John Canny (1986). C'est le contrôle le plus rigide : la génération suivra exactement les lignes détectées, ce qui verrouille silhouette, proportions et détails linéaires. Idéal quand on veut la même chaise sous des angles différents en gardant la structure exacte.
Depth produit une carte de profondeur en niveaux de gris — plus c'est clair, plus c'est proche. Elle est aujourd'hui extraite par des modèles neuronaux (MiDaS, Depth Anything) qui estiment la profondeur d'une image 2D. Le contrôle est plus souple que Canny : la génération respecte le volume et la disposition spatiale sans être forcée par des contours précis. C'est le bon choix pour transposer une scène dans un autre style tout en conservant la composition tridimensionnelle.
OpenPose extrait le squelette humain — articulations, tête, mains — sous forme de points reliés. C'est le contrôle indispensable dès qu'il y a un personnage : on peut ainsi générer une même personne dans dix poses différentes, ou reproduire une pose de référence dans un tout autre contexte.
D'autres préprocesseurs existent — HED (contours plus doux que Canny), MLSD (lignes droites pour l'architecture), Scribble (gribouillis dessiné à la main), Normal (carte de normales) — mais Canny, Depth et OpenPose couvrent 80 % des besoins.
Le poids de contrôle : l'hyperparamètre critique
Le paramètre controlnet_conditioning_scale (ou weight) règle combien la carte de contrôle tire la génération. C'est le sujet d'un piège classique.
À 1,0 — la valeur par défaut — le contrôle est fort et respecté. À 0,5, il devient une suggestion : la génération peut s'en écarter si la consigne texte l'y pousse. Au-delà de 1,3, le contrôle rigidifie tellement l'image que d'autres aspects se dégradent : les couleurs s'aplatissent, la lumière devient plate, les textures se figent.
Le symptôme du poids trop fort ressemble à celui de l'échelle de guidage trop haute (module 3), mais la cause est différente : ici, c'est la structure qui domine, pas la consigne. La bonne réaction est de baisser le poids, pas de retravailler la consigne.
Deux autres paramètres méritent d'être connus. control_guidance_start et control_guidance_end (entre 0 et 1) délimitent la fenêtre de la trajectoire pendant laquelle ControlNet agit. Un contrôle actif seulement sur la première moitié (fin à 0,5) fixe la composition, puis laisse le modèle libre pour les détails ; c'est le réglage recommandé quand on veut la pose sans imposer un rendu figé.
Un exemple complet, sur SDXL
import torch
from PIL import Image
from diffusers import StableDiffusionXLControlNetPipeline, ControlNetModel
from diffusers.utils import load_image
import cv2
import numpy as np
# Extraction Canny sur la chaise de reference.
image_ref = load_image("chaise-reference.png")
tableau = np.array(image_ref)
contours = cv2.Canny(tableau, 100, 200)
carte_canny = Image.fromarray(np.stack([contours] * 3, axis=-1))
# ControlNet Canny pour SDXL.
controlnet = ControlNetModel.from_pretrained(
"diffusers/controlnet-canny-sdxl-1.0",
torch_dtype=torch.float16,
)
pipeline = StableDiffusionXLControlNetPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0",
controlnet=controlnet,
torch_dtype=torch.float16,
).to("cuda")
image = pipeline(
prompt="une chaise scandinave, ambiance industrielle, atelier de menuiserie, "
"lumiere de fin d'apres-midi",
image=carte_canny,
controlnet_conditioning_scale=0.8,
control_guidance_end=0.7,
num_inference_steps=30,
guidance_scale=7.0,
).images[0]
image.save("chaise-controlnet-canny.png")
Deux réglages non triviaux à noter : un poids de 0,8 (au lieu du défaut 1,0) laisse un peu de liberté aux textures ; un control_guidance_end de 0,7 relâche le contrôle sur la fin de la trajectoire pour que les détails ne soient pas surdéterminés par les contours d'origine.
Combiner plusieurs ControlNet
Rien n'empêche de brancher plusieurs ControlNet sur la même génération : OpenPose pour la pose d'un personnage et Depth pour la profondeur de la scène, avec un poids réglable pour chacun. La bibliothèque diffusers accepte une liste de ControlNet et une liste de cartes d'entrée.
C'est puissant mais délicat : deux ControlNet à poids 1,0 chacun somment leurs contraintes et rigidifient très fortement la sortie. La règle empirique : plus il y a de contrôles simultanés, plus il faut baisser le poids de chacun. Deux contrôles combinés fonctionnent souvent bien à 0,6 chacun.
ControlNetControlNet demande une carte de contrôle, un modèle supplémentaire et un peu de mémoire en plus. Si le besoin est simplement « garder la même composition globale », l'image vers image à force basse (module 4) suffit et coûte moins cher. ControlNet prend le relais dès qu'on veut la même structure exacte — pose, contours, angles — avec un contenu ou un style totalement différent.
En résumé
ControlNetajoute une seconde voie au U-Net : une carte de contrôle structurelle qui guide la génération en plus de la consigne texte.- Les préprocesseurs distillent l'information :
Cannypour les contours durs,Depthpour le volume,OpenPosepour le squelette humain. - Le poids de contrôle (0,6 à 1,0 en pratique) fixe l'intensité ; trop haut, l'image se rigidifie et les couleurs s'aplatissent.
- Plusieurs
ControlNetcombinables, à condition de baisser le poids de chacun ; ne pas confondre avec image vers image, qui contraint la statistique globale, pas la structure.
Module suivant : LoRA et inversion textuelle, pour apprendre au modèle un style ou un objet spécifique à partir de quelques images seulement.