đš Diffusers â La GĂ©nĂ©ration d'Images (Stable Diffusion)
Guide complet IDEO-Lab : Pipelines, Schedulers, UNet, VAE, LoRA & ControlNet.
Vue d'ensemble
BibliothĂšque HF (comme transformers) pour la GenAI (Image/Audio).
Pourquoi diffusers ?
API unifiée pour SOTA (SD 1.5, SDXL, SD 3, ...). Modulaire.
Stable Diffusion API UnifiéeInstallation
pip install diffusers transformers accelerate (PyTorch requis).
Concept : La Diffusion (DDPM)
Processus (Noise -> Denoise). (Forward vs Reverse).
Diffusion NoiseConcept N°1 : DiffusionPipeline
L'API "facile" (haut niveau). .from_pretrained(), .to("cuda").
Concept N°2 : Le Model Hub
OĂč trouver les modĂšles (runwayml/stable-diffusion-v1-5).
TĂąche 1 : Text-to-Image (SD 1.5)
StableDiffusionPipeline. pipe(prompt).images[0].
TĂąche 2 : Image-to-Image
StableDiffusionImg2ImgPipeline. (prompt + image).
TĂąche 3 : Inpainting
StableDiffusionInpaintPipeline. (prompt, image, mask_image).
Concept N°3 : Schedulers
Les "Samplers" (Euler, DPM++ 2M Karras). (Qualité vs Vitesse).
Concept N°4 : Guidance (CFG)
guidance_scale (force du prompt), negative_prompt.
Concept N°5 : Latent Space (VAE)
Pourquoi SD est rapide (Diffusion sur Latents, pas pixels).
Latent Space VAETĂąche 4 : Stable Diffusion XL (SDXL)
Pipeline 2-stages (Base + Refiner). (Images 1024px).
SDXL RefinerConcept N°6 : LoRA
Fine-tuning (léger). .load_lora_weights(). (Ex: "Style Disney").
Concept N°7 : ControlNet
ContrÎler la génération (Poses, Canny, Depth). ControlNetModel.
Les "Guts" : UNet
Le "cerveau" de la diffusion (UNet2DConditionModel). (Le Denoising).
Les "Guts" : CLIP
L'encodeur de texte. (CLIPTextModel). (Prompt -> Embeddings).
Les "Guts" : VAE
L'encodeur/décodeur. (AutoencoderKL). (Pixel <-> Latent).
Vitrine (Qui l'utilise ?)
Stability AI, RunwayML, Adobe, (toute la R&D GenAI).
Stability AI RunwayLiens Utiles & Formation
HF Docs (diffusers), HF Blog (Tutoriels), Hugging Face Course.
Cheat-sheet
Workflow (Pipeline, Prompt, CUDA, Save).
cheat txt2imgdiffusers est la bibliothĂšque (library) de Hugging Face đ€ (comme transformers) dĂ©diĂ©e aux **modĂšles de diffusion** (GenAI).
Elle fournit une API simple et unifiée pour **télécharger, entraßner et exécuter** des modÚles SOTA (State-of-the-Art) de génération d'image et d'audio.
Elle gĂšre des modĂšles comme Stable Diffusion (1.5, XL, 3), DALL-E 2/3 (via API), Kandinsky, DeepFloyd IF, etc.
diffusers ? (Modularité)Avant diffusers, chaque nouveau modÚle de diffusion (Stable Diffusion, etc.) avait son propre dépÎt GitHub (repository), avec un code complexe, monolithique et incompatible.
diffusers rĂ©sout ce problĂšme (de la mĂȘme maniĂšre que transformers l'a fait pour BERT/GPT) :
| Force | Description |
|---|---|
| API UnifiĂ©e | La mĂȘme API (DiffusionPipeline) fonctionne pour (presque) tous les modĂšles. |
| Modularité | Sépare les composants (UNet, VAE, Scheduler). Permet de "mixer" (ex: changer le Scheduler, ajouter un ControlNet). |
| Interopérabilité | Fonctionne nativement avec PyTorch (défaut), TensorFlow, et JAX (Flax). |
| Intégration Hub | Intégration native avec le Hugging Face Hub (.from_pretrained()). |
diffusers nécessite un backend (PyTorch) et transformers (pour les encodeurs de texte comme CLIP).
Installation (pip)
# 1. (Recommandé) Installer PyTorch d'abord (avec CUDA) # (Voir le guide PyTorch 1.3) pip install torch # 2. Installer les bibliothÚques Hugging Face # (diffusers = La lib) # (transformers = Pour les Text Encoders (CLIP)) # (accelerate = Pour la gestion GPU/vitesse) pip install diffusers transformers accelerate # 3. (Optionnel: pour les Schedulers SOTA) pip install "diffusers[schedulers]"
Un modĂšle de diffusion (Denoising Diffusion Probabilistic Model - DDPM) apprend Ă **inverser** un processus. Il apprend Ă **retirer le bruit (Denoise)**.
- Phase 1 (Forward/Training) : On prend une image, on lui ajoute du bruit (Noise) en 1000 étapes, jusqu'à obtenir un "bruit pur". Le modÚle (U-Net) est entraßné à **prédire le bruit** qui a été ajouté à chaque étape.
- Phase 2 (Reverse/Inférence) : On part d'un **bruit pur** (aléatoire) et on demande au U-Net (guidé par le "prompt") de "prédire le bruit" (étape 1000), on le soustrait (légÚrement), et on répÚte (étape 999, 998...). L'image "émerge" du bruit.
Diagramme (Inférence Text-to-Image)
+-----------+
| Prompt | (ex: "A cat")
+-----------+
| (CLIP Text Encoder)
âŒ
+-----------+
| Embeddings| (Vecteurs [77, 768])
+-----------+
|
| (Guidage)
âŒ
+-----------+ +-------------+
| Bruit Pur | ->| Boucle (U-Net)| (50x Steps)
| (Latent) | | (Denoise Step)| <-- (Scheduler)
+-----------+ +-------------+
|
âŒ
+-----------+
| Latent | (Image "débruitée")
+-----------+
| (VAE Decoder)
âŒ
+-----------+
| Image (RGB)|
+-----------+
DiffusionPipeline (L'API Facile)La DiffusionPipeline (similaire à transformers.pipeline) est l'abstraction haut niveau qui gÚre **tous** les composants (VAE, U-Net, CLIP, Scheduler) pour une tùche donnée (ex: Text-to-Image).
Exemple (Chargement)
from diffusers import DiffusionPipeline
model_id = "runwayml/stable-diffusion-v1-5"
# 1. Charger le pipeline (télécharge les composants)
# (Utilise le cache local si déjà téléchargé)
pipe = DiffusionPipeline.from_pretrained(
model_id,
# (Optionnel: optimisations)
# torch_dtype=torch.float16
)
# 2. Déplacer sur GPU (ESSENTIEL)
pipe = pipe.to("cuda")
# 3. (Maintenant 'pipe' est prĂȘt Ă ĂȘtre appelĂ©)
# image = pipe(prompt).images[0]
Les modÚles (checkpoints) sont stockés sur le Hub Hugging Face (ou localement). .from_pretrained() prend l'ID du Hub.
| ModĂšle (ID du Hub) | Description |
|---|---|
runwayml/stable-diffusion-v1-5 | Le "standard" (SD 1.5). (512x512). Rapide, robuste. |
stabilityai/stable-diffusion-xl-base-1.0 | SDXL (Base). (1024x1024). Haute qualité. (Nécessite Refiner). |
stabilityai/stable-diffusion-3-medium-diffusers | SD 3 (Nouveau, 2024). GĂšre mieux le texte et les prompts complexes. |
kandinsky-community/kandinsky-2-2-decoder | ModĂšle "Kandinsky" (alternative Ă SD). |
(ModÚles fine-tunés/LoRAs...) | (Ex: dreamlike-art/dreamlike-diffusion-1.0) |
TĂąche la plus simple : Prompt (texte) -> Image.
import torch
from diffusers import StableDiffusionPipeline
# 1. Charger (SD 1.5)
pipe = StableDiffusionPipeline.from_pretrained(
"runwayml/stable-diffusion-v1-5",
torch_dtype=torch.float16 // (Optimisation FP16)
)
pipe = pipe.to("cuda")
# 2. Définir le prompt
prompt = "a high quality photo of an astronaut riding a horse on Mars"
# 3. Générer (Inférence)
# (Utilise un 'generator' pour la reproductibilité (seed))
generator = torch.Generator("cuda").manual_seed(42)
image = pipe(
prompt,
generator=generator,
num_inference_steps=30 // (Nb d'étapes de "denoising")
).images[0] // (Prend la 1Ăšre image du batch)
# 4. Sauvegarder (Image PIL)
image.save("astronaut.png")
Prend un prompt ET une image d'entrée. (ex: transformer un "croquis" en photo).
from diffusers import StableDiffusionImg2ImgPipeline
from PIL import Image
# 1. Charger le pipeline Img2Img
pipe = StableDiffusionImg2ImgPipeline.from_pretrained(
"runwayml/stable-diffusion-v1-5",
torch_dtype=torch.float16
).to("cuda")
# 2. Charger l'image d'entrée
init_image = Image.open("mon_croquis.png").convert("RGB")
init_image = init_image.resize((512, 512))
prompt = "A high quality photo of a cat, realistic"
# 3. Générer
# (strength: 0.0=garde l'image, 1.0=ignore l'image)
image = pipe(
prompt=prompt,
image=init_image,
strength=0.75, // (75% denoising)
guidance_scale=7.5
).images[0]
image.save("chat_realiste.png")
Remplir (ou remplacer) une partie d'une image, définie par un **masque (mask)**.
from diffusers import StableDiffusionInpaintPipeline
from PIL import Image
# 1. Charger le pipeline Inpaint
pipe = StableDiffusionInpaintPipeline.from_pretrained(
"runwayml/stable-diffusion-v1-5",
torch_dtype=torch.float16
).to("cuda")
# 2. Charger l'image d'entrée ET le masque
init_image = Image.open("image_originale.png").resize((512, 512))
mask_image = Image.open("masque.png").resize((512, 512))
// (Masque: Blanc = Ă changer, Noir = Ă garder)
prompt = "a cute cat sitting on a bench" // (Ce qu'on veut DANS le masque)
# 3. Générer
image = pipe(
prompt=prompt,
image=init_image,
mask_image=mask_image
).images[0]
image.save("image_modifiee.png")
Le **Scheduler** (Planificateur/Ăchantillonneur) est l'algorithme qui implĂ©mente la boucle de "denoising" (Phase 2 du diagramme 2.1). Il dĂ©termine *comment* soustraire le bruit Ă chaque Ă©tape (num_inference_steps).
Changer le Scheduler (Sampler) a un impact **massif** sur la vitesse et la qualité (certains Schedulers convergent en 10 étapes, d'autres en 50).
Scheduler (diffusers.*) | Description |
|---|---|
PNDMScheduler | (Legacy) Le défaut de SD 1.x. (50 steps). |
DDIMScheduler | (Legacy) Stable, mais lent. |
EulerAncestralDiscreteScheduler ("Euler a") | TrÚs populaire. Rapide (20-30 steps), créatif. |
DPM++ 2M Karras (DPMpp2MKarrasDiscreteScheduler) | (Recommandé) Souvent le meilleur ratio qualité/vitesse (20 steps). |
Changer le Scheduler
from diffusers import StableDiffusionPipeline, DPMSolverMultistepScheduler
model_id = "runwayml/stable-diffusion-v1-5"
pipe = StableDiffusionPipeline.from_pretrained(model_id).to("cuda")
// 1. Charger un nouveau Scheduler
pipe.scheduler = DPMSolverMultistepScheduler.from_config(
pipe.scheduler.config,
use_karras_sigmas=True
)
// 2. Générer (nécessite moins d'étapes)
image = pipe(prompt, num_inference_steps=20).images[0]
La "Classifier-Free Guidance" (CFG) est la technique qui "force" l'image Ă ressembler au prompt.
guidance_scale (Force)
"à quel point dois-tu écouter le prompt ?"
0: Ignore le prompt (image aléatoire).~7-8: (Défaut) Bon équilibre créativité/fidélité.> 10: Suit le prompt "à la lettre" (risque d'artefacts).
negative_prompt (Ăvitement)
"Ce que tu dois éviter." (Le modÚle calcule la CFG entre le prompt et le negative_prompt).
TrÚs puissant pour améliorer la qualité.
prompt = "A photo of a queen"
negative_prompt = "low quality, blurry, deformed, cartoon, ugly"
image = pipe(
prompt,
negative_prompt=negative_prompt,
guidance_scale=7.5
).images[0]
Pourquoi Stable Diffusion est-il rapide ? Il ne "diffuse" (débruite) **pas** l'image (Pixel Space, ex: 3x512x512), mais une version compressée : le **Latent Space** (ex: 4x64x64).
Le VAE (Variational Autoencoder) est le composant qui compresse (Pixel -> Latent) et décompresse (Latent -> Pixel).
Diagramme (Pipeline VAE)
(Image d'entrée: [3, 512, 512])
|
⌠(VAE Encoder)
+-------------+
| Latent | ([4, 64, 64])
+-------------+
|
âŒ
+-------------+
| Boucle | (La diffusion se passe ici,
| U-Net | c'est 48x plus petit !)
+-------------+
|
âŒ
+-------------+
| Latent | ([4, 64, 64])
| Débruité |
+-------------+
|
⌠(VAE Decoder)
+-------------+
| Image Sortie| ([3, 512, 512])
+-------------+
SDXL (Stable Diffusion XL) est une version (1024x1024) qui utilise un pipeline en 2 étapes : un modÚle Base (génÚre) et un Refiner (affine les détails).
from diffusers import DiffusionPipeline
import torch
# 1. Charger le pipeline de BASE (SDXL)
base = DiffusionPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0",
torch_dtype=torch.float16,
variant="fp16",
use_safetensors=True
).to("cuda")
# 2. Charger le pipeline REFINER
refiner = DiffusionPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-refiner-1.0",
text_encoder_2=base.text_encoder_2,
vae=base.vae,
torch_dtype=torch.float16,
use_safetensors=True,
).to("cuda")
prompt = "A majestic lion jumping from a big rock on a sunny day"
# 3. Ătape 1: BASE (GĂ©nĂšre le Latent)
# (output_type="latent" -> ne pas décoder)
image_latent = base(
prompt=prompt,
num_inference_steps=40,
output_type="latent"
).images
# 4. Ătape 2: REFINER (Affine le Latent)
image = refiner(
prompt=prompt,
num_inference_steps=20,
image=image_latent
).images[0]
image.save("sdxl_lion.png")
Le "Fine-Tuning" (ré-entraßner SD) est lourd (ex: 20GB). Les **LoRA** (Low-Rank Adaptation) sont des "patchs" (petits fichiers, ~2MB à 200MB) qui "injectent" des modifications (ex: un style artistique, un visage) dans un modÚle de base (ex: SD 1.5).
diffusers peut charger des LoRA (souvent au format .safetensors) par-dessus le pipeline.
pipe = DiffusionPipeline.from_pretrained(
"runwayml/stable-diffusion-v1-5", ...
).to("cuda")
# 1. Charger les poids LoRA (depuis le Hub ou local)
# (Ex: LoRA "Style Disney")
pipe.load_lora_weights("CiroN2022/disney-pixar")
# 2. Générer (Le prompt "trigger" le style)
prompt = "A photo of a man, disneypixar style"
image = pipe(prompt).images[0]
# (On peut désactiver le LoRA)
# pipe.unload_lora_weights()
ControlNet est un "module" qui ajoute un **contrÎle spatial** (conditionnement) à Stable Diffusion. Il "guide" la génération en forçant l'image à respecter une "carte de contrÎle".
Cartes de contrĂŽle communes :
- Canny : Contours (edge detection).
- OpenPose : Squelette (pose du corps).
- Depth : Carte de profondeur (perspective).
Exemple (ControlNet Canny)
from diffusers import StableDiffusionControlNetPipeline, ControlNetModel
import cv2, torch
from PIL import Image
# 1. Charger une image d'entrée (ex: une photo)
image = Image.open("photo.png")
# (Utiliser OpenCV (cv2) pour extraire les contours)
canny_image = cv2.Canny(np.array(image), 100, 200)
canny_image = Image.fromarray(canny_image)
# 2. Charger le ControlNet (pour Canny)
controlnet = ControlNetModel.from_pretrained(
"lllyasviel/sd-controlnet-canny",
torch_dtype=torch.float16
)
# 3. Charger le Pipeline (ControlNet)
pipe = StableDiffusionControlNetPipeline.from_pretrained(
"runwayml/stable-diffusion-v1-5",
controlnet=controlnet,
torch_dtype=torch.float16
).to("cuda")
# 4. Générer (Le prompt + la carte Canny)
prompt = "A photo of a cat in the style of Van Gogh"
image = pipe(
prompt,
image=canny_image // (L'image de contrĂŽle)
).images[0]
// (Output: Un chat style Van Gogh,
// MAIS avec la pose/forme de la photo originale)
UNetLe U-Net (UNet2DConditionModel) est le **cĆur** du modĂšle de diffusion. C'est lui qui effectue le "denoising" (dĂ©bruitage).
Il prend en entrĂ©e : le Latent bruitĂ© (ex: 4x64x64) + le Prompt (Embeddings) + le Timestep (Ătape).
Il prédit en sortie : le Bruit (Noise) à retirer (ou l'image débruitée).
CLIP)Le Text Encoder (ex: CLIPTextModel) est le composant (de transformers) qui "comprend" le prompt. Il transforme le texte (string) en vecteurs (Embeddings) que le U-Net peut utiliser comme "guidage" (conditionnement).
VAELe VAE (AutoencoderKL) est l'encodeur/décodeur (voir 4.3).
.encode(): (Pixel Space -> Latent Space). (Utilisé dans Img2Img / Inpainting)..decode(): (Latent Space -> Pixel Space). (Utilisé à la fin de Txt2Img pour générer l'image finale).
diffusers est devenu le "standard" open-source pour la R&D et la production en GenAI (Image/Audio).
| Entreprise / Projet | Cas d'usage |
|---|---|
| Stability AI | (Utilisateur principal) Base de leurs modĂšles (Stable Diffusion, SDXL, SD 3). |
| RunwayML | (Utilisateur principal) Base de leurs modĂšles (Gen-1, Gen-2) et R&D. |
| Adobe | Intégré dans des outils (ex: Photoshop GenAI, Adobe Firefly) (R&D). |
| Toute la communauté AI Art | Utilisé comme "backend" pour de nombreuses UIs (InvokeAI) et pour le "fine-tuning" (LoRAs). |
Ressources pour apprendre et travailler avec Diffusers.
| Site | Description |
|---|---|
HF Docs (diffusers) | (huggingface.co/docs/diffusers) La documentation API (officielle) de diffusers. |
HF Blog (diffusers) | (huggingface.co/blog/tags/diffusers) Des tutoriels "SOTA" (ex: ControlNet, SDXL, LoRA). |
HF Course (diffusers) | (huggingface.co/course/chapter9/1) Le cours officiel (gratuit) sur les modĂšles de Diffusion. |
import torch
from diffusers import StableDiffusionPipeline, DPMSolverMultistepScheduler
# 1. Définir le ModÚle & Device
model_id = "runwayml/stable-diffusion-v1-5"
device = "cuda"
# 2. Charger le Pipeline (Base)
pipe = StableDiffusionPipeline.from_pretrained(
model_id,
torch_dtype=torch.float16
)
# 3. (Optionnel) Changer le Scheduler (Sampler)
pipe.scheduler = DPMSolverMultistepScheduler.from_config(
pipe.scheduler.config,
use_karras_sigmas=True
)
# 4. (Optionnel) Charger un LoRA
# pipe.load_lora_weights("path_or_hub_id")
# 5. Envoyer au GPU
pipe = pipe.to(device)
# 6. Définir les Prompts
prompt = "photo of a cat, high quality"
negative_prompt = "blurry, low quality, cartoon"
# 7. (Optionnel) Seed
generator = torch.Generator(device).manual_seed(1234)
# 8. Générer (Inférence)
image = pipe(
prompt=prompt,
negative_prompt=negative_prompt,
num_inference_steps=25,
guidance_scale=7.5,
generator=generator
).images[0]
# 9. Sauvegarder
image.save("cat.png")
