Premiers pas avec Hugging Face Diffusers
Configurez Hugging Face Diffusers avec SDXL, générez des images, ajustez les paramètres, réduisez l’usage mémoire du GPU et créez une API FastAPI pour votre app JavaScript.
Hugging Face Diffusers est une bibliothèque Python qui permet d’exécuter des modèles de diffusion d’images, de vidéo et d’audio sur votre propre matériel. Elle regroupe l’encodeur de texte, le scheduler, le réseau de débruitage et le VAE dans un unique objet pipeline, que vous appelez avec un prompt.
Les API d’images hébergées permettent de démarrer facilement. Puis arrivent les factures à l’image, les limites de débit ralentissent votre prototype, et vous voulez comprendre ce que fait réellement le modèle. Exécuter le modèle en local règle ces trois problèmes, mais la plupart des tutoriels partent du principe que vous maîtrisez déjà PyTorch.
Ce guide s’adresse aux développeurs JavaScript. Il vous accompagne de l’installation jusqu’à votre première image, explique les paramètres importants, montre comment faire tenir le modèle sur des GPU plus modestes, et se termine par un endpoint FastAPI que votre frontend appelle avec fetch(). Les exemples ciblent Diffusers v0.42.1.
Points clés
- Chargez
stabilityai/stable-diffusion-xl-base-1.0avecDiffusionPipeline.from_pretrained(..., dtype=torch.float16)et déplacez-le vers"cuda"sur les GPU NVIDIA ou vers"mps"sur Apple Silicon. - SDXL base 1.0 est distribué sous la licence CreativeML Open RAIL++-M. Lisez-la avant de publier des images générées.
- Un
torch.Generatorinitialisé avec une seed rend les résultats reproductibles : vous pouvez ainsi modifier un seul paramètre à la fois et en observer l’effet. - Si le modèle ne tient pas en mémoire GPU, appelez d’abord
enable_model_cpu_offload(). La documentation de Diffusers qualifie le déchargement CPU séquentiel d’extrêmement lent. - Chargez le pipeline une seule fois au démarrage du serveur et réutilisez-le pour chaque requête. Ne le chargez jamais dans un gestionnaire de requête.
Qu’est-ce que Hugging Face Diffusers ?
Diffusers est la bibliothèque de Hugging Face dédiée aux modèles de diffusion. Son abstraction centrale est DiffusionPipeline, qui regroupe les composants dont un modèle a besoin :
- un ou plusieurs encodeurs de texte qui transforment le prompt en embeddings
- un scheduler qui pilote l’algorithme de débruitage
- un UNet ou un diffusion transformer qui prédit le bruit à chaque étape
- un VAE qui décode le résultat en pixels
Si vous découvrez le Hub, les Inference Providers ou les Spaces, lisez d’abord A Quick Guide to Hugging Face for Developers. Si vous souhaitez faire de l’inférence sans aucun backend Python, Transformers.js exécute les modèles directement dans le navigateur, même s’il couvre un ensemble de modèles différent.
De quel matériel Diffusers a-t-il besoin ?
Diffusers fonctionne sur trois types de machines. Un GPU NVIDIA est de loin le plus rapide, un Mac Apple Silicon fonctionne via le backend "mps" de PyTorch, et un simple CPU fonctionne également, mais très lentement.
| Matériel | Chaîne de périphérique | dtype | À quoi s’attendre |
|---|---|---|---|
| GPU NVIDIA | "cuda" | torch.float16 | Rapide |
| Mac Apple Silicon | "mps" | torch.float16 | Fonctionne, plus lent qu’un GPU NVIDIA dédié |
| CPU uniquement | "cpu" | torch.float32 | Fonctionne, très lent |
Le Quickstart liste "cuda", "mps", "xpu" et "cpu" comme périphériques cibles. Diffusers propose également un guide dédié à Apple Silicon (MPS). Ce helper sélectionne le périphérique et le dtype adaptés à la machine courante :
import torch
if torch.cuda.is_available():
device, dtype = "cuda", torch.float16
elif torch.backends.mps.is_available():
device, dtype = "mps", torch.float16
else:
device, dtype = "cpu", torch.float32
Installer Diffusers et générer une première image
Générer une première image avec Hugging Face Diffusers se fait en trois étapes : installer Diffusers avec PyTorch, charger SDXL, puis appeler le pipeline avec un prompt et enregistrer .images[0].
Depuis la v0.42.0, Diffusers nécessite Python 3.11 ou une version ultérieure, et il est testé avec PyTorch 2.6 ou une version ultérieure. Suivez le guide d’installation pour configurer un environnement virtuel, puis installez les paquets. Les encodeurs de texte de SDXL sont des modèles CLIP issus de Transformers : installez donc également cette bibliothèque :
uv pip install "diffusers[torch]>=0.42.1" transformers
# or: pip install "diffusers[torch]>=0.42.1" transformers
En utilisant les variables device et dtype du helper ci-dessus, générez une image :
import torch
from diffusers import DiffusionPipeline
pipeline = DiffusionPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0",
dtype=dtype,
).to(device)
prompt = "isometric pixel-art coffee shop at dusk, warm window light, rain on the street"
image = pipeline(prompt).images[0]
image.save("first.png")
image est une image PIL : .save() écrit donc un fichier PNG sur le disque. L’identifiant du modèle correspond au nom complet du checkpoint sur le Hub, préfixe d’organisation stabilityai/ compris.
Licence : SDXL base 1.0 est distribué sous la licence CreativeML Open RAIL++-M. Lisez-la avant d’utiliser des images générées dans un produit, et vérifiez la licence de tout autre modèle que vous utiliseriez à la place.
Quels sont les paramètres SDXL les plus importants ?
Quatre arguments du pipeline SDXL déterminent l’essentiel du résultat : num_inference_steps, guidance_scale, generator et height / width. Fixez d’abord la seed, puis modifiez un seul argument à la fois.
generator = torch.Generator().manual_seed(42)
image = pipeline(
prompt,
num_inference_steps=30,
guidance_scale=7.0,
height=1024,
width=1024,
generator=generator,
).images[0]
num_inference_stepsdéfinit le nombre de passes de débruitage. Davantage d’étapes prennent plus de temps et ajoutent généralement des détails, jusqu’à ce que les gains plafonnent.guidance_scaledéfinit à quel point le modèle suit fidèlement le prompt. Des valeurs élevées collent davantage au texte, mais des valeurs trop élevées peuvent produire un rendu surtraité.generatorfixe le bruit de départ. Avec le même modèle, les mêmes paramètres et le même matériel, un générateur initialisé avec une seed reproduit la même image.height/widthdéfinissent la taille de sortie en pixels. Les images plus grandes nécessitent plus de mémoire et plus de temps.
La référence du pipeline SDXL liste tous les arguments ainsi que leurs valeurs par défaut.
Changer de scheduler
Le scheduler détermine la manière dont le bruit est retiré à chaque étape, et chaque scheduler propose un compromis différent entre vitesse et qualité. Remplacez-le sur un pipeline déjà chargé avec from_config(), en lui passant la configuration existante afin que les paramètres correspondant au checkpoint restent cohérents :
from diffusers import DPMSolverMultistepScheduler
pipeline.scheduler = DPMSolverMultistepScheduler.from_config(pipeline.scheduler.config)
generator = torch.Generator().manual_seed(42)
image = pipeline(prompt, num_inference_steps=20, generator=generator).images[0]
Le guide des Schedulers utilise exactement ce pattern avec SDXL. La référence de DPMSolverMultistepScheduler indique qu’il produit des échantillons de haute qualité en une vingtaine d’étapes environ. Gardez la seed fixe lorsque vous comparez des schedulers, afin que le scheduler soit la seule variable qui change entre les deux images.
Comment faire tenir SDXL sur des GPU plus modestes ?
Si SDXL déclenche des erreurs de mémoire insuffisante (out-of-memory), essayez ces quatre solutions d’optimisation mémoire de Diffusers dans l’ordre : déchargement du modèle sur le CPU, tiling du VAE, slicing du VAE et quantification 4 bits. Chaque étape économise davantage de mémoire, au prix d’une vitesse moindre.
- Déchargement du modèle sur le CPU. Supprimez
.to(device)et appelezpipeline.enable_model_cpu_offload(). Chaque modèle n’est alors placé en entier sur le GPU que pendant son exécution. - Tiling du VAE.
pipeline.vae.enable_tiling()décode les grandes images par tuiles. Le guide sur la mémoire précise que cela peut entraîner de légères variations de tons entre les tuiles. - Slicing du VAE.
pipeline.vae.enable_slicing()décode un lot une image à la fois. Cette option n’est utile que si vous générez plusieurs images en un seul appel. - Quantification 4 bits. Installez
bitsandbyteset ajoutez une courte configuration :
from diffusers.quantizers import PipelineQuantizationConfig
quant_config = PipelineQuantizationConfig(
quant_backend="bitsandbytes_4bit",
quant_kwargs={"load_in_4bit": True, "bnb_4bit_quant_type": "nf4", "bnb_4bit_compute_dtype": torch.float16},
components_to_quantize=["unet"],
)
pipeline = DiffusionPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0",
dtype=torch.float16,
quantization_config=quant_config,
)
pipeline.enable_model_cpu_offload()
La présentation de la quantification documente PipelineQuantizationConfig et ses backends. Diffusers a ajouté la quantification bitsandbytes sur MPS dans la v0.39.0 : cette approche n’est donc pas limitée à CUDA. Sur Apple Silicon, bitsandbytes nécessite PyTorch 2.9 ou une version ultérieure, soit davantage que la version de référence PyTorch 2.6 mentionnée plus haut.
Évitez enable_sequential_cpu_offload(), sauf si aucune autre solution ne suffit. C’est l’option qui économise le plus de mémoire, mais le guide sur la mémoire la qualifie d’extrêmement lente. Par ailleurs, un pipeline chargé avec device_map doit appeler reset_device_map() avant que vous n’utilisiez .to() ou l’une des deux méthodes de déchargement.
Appeler Hugging Face Diffusers depuis une application web
Pour utiliser Diffusers depuis un frontend, encapsulez le pipeline dans un petit serveur HTTP. Le serveur doit charger le modèle une seule fois au démarrage et renvoyer des octets PNG. Installez fastapi et uvicorn, puis enregistrez ce code dans main.py :
import io, threading
from contextlib import asynccontextmanager
import torch
from diffusers import DiffusionPipeline
from fastapi import FastAPI, Response
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
state = {}
lock = threading.Lock()
@asynccontextmanager
async def lifespan(app: FastAPI):
state["pipe"] = DiffusionPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0", dtype=torch.float16
).to("cuda") # or "mps"
yield
state.clear()
app = FastAPI(lifespan=lifespan)
app.add_middleware(CORSMiddleware, allow_origins=["http://localhost:5173"],
allow_methods=["POST"], allow_headers=["*"])
class GenerateRequest(BaseModel):
prompt: str
seed: int | None = None
@app.post("/generate")
def generate(req: GenerateRequest):
gen = torch.Generator().manual_seed(req.seed) if req.seed is not None else None
with lock:
image = state["pipe"](req.prompt, generator=gen).images[0]
buf = io.BytesIO()
image.save(buf, format="PNG")
return Response(content=buf.getvalue(), media_type="image/png")
Lancez-le avec uvicorn main:app. Le code s’appuie sur trois fonctionnalités de FastAPI :
- Le gestionnaire lifespan charge le modèle une seule fois, avant que le serveur n’accepte la moindre requête.
from_pretrained()est bien trop lent pour être appelé à chaque requête. - Comme
generateest une simple fonctiondef, FastAPI l’exécute dans un pool de threads au lieu de bloquer la boucle d’événements. - Le verrou garantit que les requêtes utilisent le GPU une par une.
CORSMiddleware autorise l’origine de votre frontend de développement à appeler l’endpoint.
Côté frontend, utilisez fetch() pour demander l’image, lisez le corps de la réponse sous forme de Blob et affichez-le avec URL.createObjectURL() :
async function generate(prompt, seed, img) {
const res = await fetch("http://localhost:8000/generate", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ prompt, seed }),
});
if (!res.ok) throw new Error(`Generation failed: ${res.status}`);
if (img.src.startsWith("blob:")) URL.revokeObjectURL(img.src);
img.src = URL.createObjectURL(await res.blob());
}
La génération prend des secondes, et non des millisecondes. Affichez un état de chargement, désactivez le bouton d’envoi tant qu’une requête est en cours, et transmettez un signal AbortController si les utilisateurs peuvent annuler. Avant de servir les PNG générés à de vrais visiteurs, réduisez leur poids avec le compresseur d’images d’OpenReplay.
Prochaines étapes
Une fois le pipeline chargé sur le bon périphérique, Diffusers ne demande que très peu de code : un identifiant de modèle, un dtype, un prompt et une seed. Générez une première image avec SDXL, fixez la seed et ajustez un paramètre à la fois. Si la mémoire vient à manquer, appliquez dans l’ordre les étapes de déchargement et de quantification. Placez ensuite l’endpoint FastAPI derrière votre frontend. À partir de là, le guide sur la mémoire et le guide des Schedulers détaillent les compromis à considérer lorsque vous optimisez pour la production.
FAQ
Où Diffusers stocke-t-il les poids des modèles téléchargés ?
from_pretrained() enregistre les fichiers du modèle dans le cache du Hugging Face Hub et les réutilise lors des exécutions suivantes, sans les télécharger à nouveau. Par défaut, le cache se trouve dans ~/.cache/huggingface/hub. Définissez la variable d'environnement HF_HUB_CACHE pour déplacer uniquement le cache des modèles. Définissez HF_HOME pour déplacer l'ensemble des données Hugging Face, ce qui place le cache dans HF_HOME/hub. Vous pouvez également passer un argument cache_dir pour choisir un emplacement lors d'un chargement ponctuel.
Pourquoi une même seed donne-t-elle une image différente sur une autre machine ?
Une seed ne reproduit fidèlement une image que sur le même matériel avec la même version de PyTorch. Les GPU CUDA utilisent un générateur de nombres aléatoires différent de celui des CPU, et la multiplication matricielle sur GPU est moins déterministe. Le guide sur la reproductibilité de Diffusers recommande de passer un générateur CPU lorsque les résultats doivent être identiques, ce que crée torch.Generator() par défaut. Même ainsi, un résultat identique n'est pas garanti d'un modèle de GPU ou d'une version de PyTorch à l'autre.
La quantification 4 bits avec bitsandbytes fonctionne-t-elle sur un Mac Apple Silicon ?
Oui, avec les versions récentes. Diffusers a ajouté la quantification bitsandbytes sur MPS dans la v0.39.0, et bitsandbytes 0.50.0 a rendu l'ensemble de ses configurations 4 bits et LLM.int8() compatibles avec MPS. Le support MPS de bitsandbytes nécessite PyTorch 2.9 ou une version ultérieure, soit davantage que la version minimale PyTorch 2.6 requise par Diffusers. Sur macOS 26 et versions ultérieures, l'installation du paquet kernels active des kernels Metal plus rapides.
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.
Star on GitHub12k