ControlNet
ControlNet ajoute un contrôle spatial aux modèles de diffusion texte-image et oriente la composition à l’aide de cartes de contours, de profondeur ou de squelettes de pose. Découvre son fonctionnement avec du code.
ControlNet est une architecture de réseau neuronal qui ajoute un contrôle spatial à un modèle de diffusion texte-image préentraîné tel que Stable Diffusion. En plus du prompt textuel, le modèle reçoit une image de conditionnement, par exemple une carte de contours, une carte de profondeur, un squelette de pose humaine ou une carte de segmentation. L’image générée suit cette structure, tandis que le prompt en détermine le contenu et le style. Un prompt comme « un chevalier en armure d’argent » associé à un squelette de pose produit un chevalier dans cette pose précise. Lvmin Zhang, Anyi Rao et Maneesh Agrawala, de l’université Stanford, l’ont présenté en 2023 dans Adding Conditional Control to Text-to-Image Diffusion Models, article qui a partagé le prix Marr du meilleur article à ICCV 2023. Les poids du modèle de base restent gelés ; ControlNet ajoute donc un contrôle sans dégrader ce que le modèle sait déjà.
Fonctionnement de ControlNet#
Stable Diffusion génère une image en débruitant progressivement un latent avec un U-Net. ControlNet verrouille ce U-Net et en crée une copie entraînable de l’encodeur, composée des 12 blocs d’encodage et du bloc central. Un petit réseau convolutif convertit d’abord l’image de conditionnement de 512×512 en une carte de caractéristiques de 64×64 correspondant au latent. La copie entraînable traite le latent avec ces caractéristiques de conditionnement, puis ses sorties sont ajoutées aux 12 connexions de saut du U-Net verrouillé et à son bloc central. Le décodeur verrouillé reçoit ainsi le signal de contrôle :
La copie est reliée au modèle verrouillé uniquement par des convolutions à zéro : des convolutions 1×1 dont les poids et les biais sont initialisés à zéro. À la première étape d’entraînement, elles produisent des zéros ; le modèle combiné se comporte donc exactement comme l’original, et aucun bruit aléatoire n’atteint les couches préentraînées. La convolution de sortie à zéro reçoit tout de même un gradient de poids non nul, puisque son entrée n’est pas nulle. La première mise à jour l’éloigne donc de zéro, et le signal de contrôle se développe à partir de là. Ce code PyTorch illustre un bloc :
import copy
import torch
from torch import nn
# A frozen block from the pretrained model and a trainable copy of it
torch.manual_seed(0)
locked = nn.Conv2d(64, 64, 3, padding=1).requires_grad_(False)
trainable = copy.deepcopy(locked).requires_grad_(True)
# Zero convolutions: 1x1 convolutions whose weights and biases start at zero
zero_in, zero_out = nn.Conv2d(64, 64, 1), nn.Conv2d(64, 64, 1)
for conv in (zero_in, zero_out):
nn.init.zeros_(conv.weight)
nn.init.zeros_(conv.bias)
x = torch.randn(1, 64, 32, 32) # features entering the block
condition = torch.randn(1, 64, 32, 32) # encoded edge, depth, or pose map
y = locked(x) + zero_out(trainable(x + zero_in(condition)))
# At step 0 the output equals the frozen block's, and only the outer zero conv gets a gradient
print(torch.equal(y, locked(x)))
y.sum().backward()
print(f"zero_in grad: {zero_in.weight.grad.norm():.1f}, zero_out grad: {zero_out.weight.grad.norm():.1f}")Il affiche True et zero_in grad: 0.0, zero_out grad: 2040.6. La sortie du bloc est identique à celle du modèle gelé, la convolution externe à zéro reçoit un gradient parce que son entrée est non nulle, et la convolution interne commence à apprendre dès que la convolution externe s’éloigne de zéro.
Types de conditionnement#
L’article original a entraîné des ControlNets distincts pour les contours Canny, les cartes de profondeur, les cartes de normales de surface, les lignes droites M-LSD, les contours souples HED, les cartes de segmentation ADE20K, les poses humaines OpenPose et les croquis des utilisateurs. Chaque image de conditionnement est extraite d’une photo de référence avec un modèle prêt à l’emploi, comme le détecteur de contours Canny d’OpenCV ou un réseau d’estimation de profondeur. Plusieurs ControlNets peuvent être appliqués simultanément, chacun avec sa propre intensité. Les modèles d’estimation de pose Ultralytics YOLO26 extraient ce type de condition de pose en prédisant 17 points clés COCO pour chaque personne, qui peuvent être dessinés sous forme de squelettes sur une toile vierge :
import cv2
import numpy as np
from ultralytics import YOLO
# Charge un modèle de pose YOLO26 qui prédit 17 points clés par personne
model = YOLO("yolo26n-pose.pt")
results = model("https://ultralytics.com/images/bus.jpg")
result = results[0]
# Dessine uniquement les squelettes sur une toile noire de la taille de la photo
skeletons = result.plot(img=np.zeros_like(result.orig_img), boxes=False)
cv2.imwrite("pose_condition.png", skeletons)L’image enregistrée montre les membres de chaque personne sous forme de lignes colorées sur fond noir, sans les couleurs, les textures ni l’arrière-plan de la photo.
ControlNet et méthodes apparentées#
- LoRA : Affine un petit ensemble de poids ajoutés pour enseigner à un modèle un nouveau style, personnage ou objet. LoRA modifie ce que le modèle dessine, tandis que ControlNet détermine où les éléments apparaissent ; les deux sont souvent combinés.
- T2I-Adapter : Solution plus légère, comptant environ 77 millions de paramètres, qui ajoute les caractéristiques de conditionnement aux caractéristiques de l’encodeur du U-Net gelé, plutôt que d’exécuter une copie complète de l’encodeur. Les adaptateurs de différentes conditions peuvent être combinés lors de la génération.
- Génération image à image : Commence le débruitage à partir d’une copie bruitée d’une photo d’entrée, de sorte que la sortie en conserve les couleurs et la disposition générale. ControlNet ne contraint que la structure extraite, comme les contours, et laisse le prompt déterminer les couleurs et les textures.
- Retouche d’image : Régénère une partie masquée de l’image pour l’harmoniser avec le reste. Cette méthode contrôle la région qui change, tandis que ControlNet contrôle la structure du contenu généré.
Applications concrètes#
- Architecture et décoration intérieure : Des croquis, des dessins au trait CAO ou des cartes de lignes M-LSD d’une pièce deviennent des rendus photoréalistes utilisant différents matériaux et styles, tout en conservant la même géométrie.
- Illustration de personnages et animation : Les squelettes de pose conservent la posture d’un personnage malgré les variations de style, et les poses extraites image par image d’une vidéo de référence produisent des séquences animées cohérentes.
- Images de produits et marketing : Les cartes de profondeur ou de contours d’une photo de produit en conservent la forme et l’emplacement, tandis que le prompt modifie le décor, l’éclairage et l’arrière-plan.
- Données synthétiques : Générer des images à partir de cartes de segmentation ou de poses produit de nouvelles images d’entraînement dont les annotations sont connues à l’avance, puisque la disposition a été définie avant la génération.
Entraîner un ControlNet#
L’entraînement nécessite des paires d’images et de leurs cartes de conditionnement, produites automatiquement en exécutant l’extracteur de conditions sur un jeu de données d’images légendées. Les poids verrouillés n’ont pas besoin d’être mis à jour par gradient ; chaque itération d’entraînement ne demande donc qu’environ 23 % de mémoire GPU supplémentaire et 34 % de temps en plus par rapport à l’optimisation de Stable Diffusion sans ControlNet. L’article rapporte un entraînement robuste sur des jeux de données allant de moins de 50 000 à plus d’un million d’images. L’entraînement révèle également une « convergence soudaine » : le modèle ignore la condition pendant des milliers d’étapes, puis commence brusquement à la suivre, généralement en moins de 10 000 étapes d’optimisation ; dans l’exemple de l’article, cela se produit à l’étape 6 133.










