ControlNet
ControlNet aggiunge il controllo spaziale ai modelli di diffusione da testo a immagine, guidando la composizione con mappe dei bordi, di profondità o scheletri di posa. Scopri come funziona, con il codice.
ControlNet è un'architettura di rete neurale che aggiunge un controllo spaziale a un modello di diffusione da testo a immagine preaddestrato, come Stable Diffusion. Oltre al prompt testuale, riceve un'immagine di condizionamento, come una mappa dei bordi, una mappa di profondità, uno scheletro della posa umana o una mappa di segmentazione; l'immagine generata segue quella struttura, mentre il prompt ne determina contenuto e stile. Un prompt come "un cavaliere in armatura d'argento", abbinato a uno scheletro della posa, produce un cavaliere esattamente in quella posa. Lvmin Zhang, Anyi Rao e Maneesh Agrawala della Stanford University l'hanno introdotto nel 2023 nell'articolo Adding Conditional Control to Text-to-Image Diffusion Models, che ha condiviso il Marr Prize per il miglior articolo all'ICCV 2023. I pesi del modello di base restano congelati, così ControlNet aggiunge il controllo senza compromettere ciò che il modello già conosce.
Come funziona ControlNet#
Stable Diffusion genera un'immagine eliminando ripetutamente il rumore da una rappresentazione latente tramite una U-Net. ControlNet blocca questa U-Net e ne crea una copia addestrabile dell'encoder, composta dai 12 blocchi di codifica e dal blocco centrale. Una piccola rete convoluzionale converte innanzitutto l'immagine di condizionamento 512×512 in una mappa delle caratteristiche 64×64 che corrisponde alla rappresentazione latente. La copia addestrabile elabora la rappresentazione latente insieme a queste caratteristiche di condizionamento; i suoi output vengono aggiunti alle 12 connessioni di salto della U-Net bloccata e al relativo blocco centrale, così il decoder bloccato riceve il segnale di controllo:
La copia si collega al modello bloccato solo tramite convoluzioni a zero: convoluzioni 1×1 i cui pesi e bias iniziano a zero. Al primo passaggio di addestramento producono valori zero, quindi il modello combinato si comporta esattamente come l'originale e nessun rumore casuale raggiunge i livelli preaddestrati. La convoluzione a zero in uscita riceve comunque un gradiente dei pesi diverso da zero, perché il suo input non è zero; il primo aggiornamento la sposta quindi da zero e da lì il segnale di controllo cresce. Questo codice PyTorch mostra un blocco:
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}")Stampa True e zero_in grad: 0.0, zero_out grad: 2040.6. L'output del blocco è identico a quello del modello congelato, la convoluzione a zero esterna riceve un gradiente perché il suo input è diverso da zero e quella interna inizia ad apprendere quando la convoluzione esterna si è spostata da zero.
Tipi di condizionamento#
L'articolo originale ha addestrato ControlNet separati per i bordi Canny, le mappe di profondità, le mappe delle normali di superficie, le linee rette M-LSD, i bordi sfumati HED, le mappe di segmentazione ADE20K, le pose umane OpenPose e gli schizzi degli utenti. Ogni immagine di condizionamento viene estratta da una foto di riferimento con un modello pronto all'uso, come il rilevatore di bordi Canny di OpenCV o una rete di stima della profondità; è possibile applicare contemporaneamente più ControlNet, ciascuno con un'intensità propria. I modelli Ultralytics YOLO26 per la stima della posa estraggono questo tipo di condizionamento della posa e prevedono 17 keypoint COCO per ogni persona, rappresentabili come scheletri su una tela vuota:
import cv2
import numpy as np
from ultralytics import YOLO
# Carica un modello di stima della posa YOLO26 che prevede 17 keypoint per persona
model = YOLO("yolo26n-pose.pt")
results = model("https://ultralytics.com/images/bus.jpg")
result = results[0]
# Disegna solo gli scheletri su una tela nera delle stesse dimensioni della foto
skeletons = result.plot(img=np.zeros_like(result.orig_img), boxes=False)
cv2.imwrite("pose_condition.png", skeletons)L'immagine salvata mostra le braccia e le gambe di ogni persona come linee colorate su sfondo nero, senza i colori, le trame e lo sfondo della foto.
ControlNet e metodi correlati#
- LoRA: Perfeziona un piccolo insieme di pesi aggiunti per insegnare al modello un nuovo stile, personaggio o oggetto. LoRA modifica ciò che il modello disegna, mentre ControlNet stabilisce dove collocare gli elementi; spesso le due tecniche vengono combinate.
- T2I-Adapter: Un'alternativa più leggera, con circa 77 milioni di parametri, che aggiunge le caratteristiche di condizionamento a quelle dell'encoder della U-Net congelata invece di eseguire una copia completa dell'encoder. Gli adapter per diverse condizioni possono essere combinati durante la generazione.
- Generazione da immagine a immagine: Inizia a eliminare il rumore da una copia dell'immagine di input a cui è stato aggiunto rumore, quindi l'output eredita i colori e la disposizione generale della foto. ControlNet vincola solo la struttura estratta, come i bordi, e lascia al prompt la scelta dei colori e delle trame.
- Ritocco delle immagini: Rigenera una parte mascherata di un'immagine per armonizzarla con il resto. Stabilisce quale regione modificare, mentre ControlNet controlla la struttura del contenuto generato.
Applicazioni nel mondo reale#
- Architettura e interior design: Schizzi, disegni CAD a linee o mappe di linee M-LSD di una stanza diventano rendering fotorealistici con materiali e stili diversi, mantenendo la stessa geometria.
- Illustrazione di personaggi e animazione: Gli scheletri della posa mantengono fissa la postura di un personaggio tra diverse varianti di stile; le pose estratte fotogramma per fotogramma da un video di riferimento generano sequenze animate coerenti.
- Immagini di prodotto e marketing: Le mappe di profondità o dei bordi di una foto di prodotto ne mantengono la forma e la posizione, mentre il prompt modifica l'ambientazione, l'illuminazione e lo sfondo.
- Dati sintetici: Generare immagini da mappe di segmentazione o pose produce nuove immagini di addestramento con etichette note in anticipo, perché la disposizione è stata specificata prima della generazione.
Addestramento di ControlNet#
L'addestramento richiede coppie di immagini e relative mappe di condizionamento, prodotte automaticamente eseguendo l'estrattore della condizione su un dataset di immagini con didascalie. Non servono aggiornamenti del gradiente per i pesi bloccati, quindi ogni iterazione di addestramento richiede solo circa il 23% di memoria GPU in più e il 34% di tempo in più rispetto all'ottimizzazione di Stable Diffusion senza ControlNet; l'articolo riporta un addestramento robusto su dataset che vanno da meno di 50.000 a oltre un milione di immagini. Durante l'addestramento si osserva anche una "convergenza improvvisa": il modello ignora la condizione per migliaia di passaggi e poi inizia bruscamente a seguirla, di solito entro 10.000 passaggi di ottimizzazione; nell'esempio dell'articolo ciò avviene al passaggio 6.133.










