# Accélérer l'inférence

Les modèles de diffusion sont lents à l'inférence car la génération est un processus itératif au cours duquel le bruit est progressivement affiné en une image ou une vidéo sur un certain nombre d'« étapes ». Pour accélérer ce processus, vous pouvez expérimenter avec différents [schedulers](../api/schedulers/overview), réduire la précision des poids du modèle pour des calculs plus rapides, utiliser des mécanismes d'attention plus économes en mémoire, et plus encore.

Combinez et utilisez ces techniques ensemble pour accélérer l’inférence par rapport à l’utilisation d’une seule technique à la fois.

Ce guide détaille comment accélérer l'inférence.

## Type de données du modèle

La précision et le type de données des poids du modèle influencent la vitesse d’inférence, car une précision plus élevée nécessite plus de mémoire pour le chargement et plus de temps pour effectuer les calculs. PyTorch charge les poids du modèle en float32 ou en précision complète par défaut, ce qui en fait un moyen simple d’accélérer rapidement l’inférence en changeant le type de données.

bfloat16 est similaire à float16, mais il est plus robuste aux erreurs numériques. La prise en charge matérielle de bfloat16 varie, mais la plupart des GPU modernes sont capables de prendre en charge bfloat16.

```py
import torch
from diffusers import StableDiffusionXLPipeline

pipeline = StableDiffusionXLPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0", dtype=torch.bfloat16
).to("cuda")  # or "mps", "xpu", "cpu"

prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k"
pipeline(prompt, num_inference_steps=30).images[0]
```

float16 est similaire à bfloat16 mais peut être plus sujet aux erreurs numériques.

```py
import torch
from diffusers import StableDiffusionXLPipeline

pipeline = StableDiffusionXLPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0", dtype=torch.float16
).to("cuda")  # or "mps", "xpu", "cpu"

prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k"
pipeline(prompt, num_inference_steps=30).images[0]
```

Le mode [TensorFloat-32 (tf32)](https://blogs.nvidia.com/blog/2020/05/14/tensorfloat-32-precision-format/) est pris en charge sur les GPU NVIDIA Ampere et il calcule les opérations de convolution et de multiplication matricielle en tf32. Le stockage et les autres opérations sont conservés en float32. Cela permet des calculs nettement plus rapides lorsqu'il est combiné avec bfloat16 ou float16.

PyTorch n’active le mode tf32 par défaut que pour les convolutions et il est nécessaire de l’activer explicitement pour les multiplications de matrices.

```py
import torch
from diffusers import StableDiffusionXLPipeline

torch.backends.cuda.matmul.allow_tf32 = True

pipeline = StableDiffusionXLPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0", dtype=torch.bfloat16
).to("cuda")  # or "mps", "xpu", "cpu"

prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k"
pipeline(prompt, num_inference_steps=30).images[0]
```

Consultez la documentation sur l'[entraînement en précision mixte](https://huggingface.co/docs/transformers/en/perf_train_gpu_one#mixed-precision) pour plus de détails.

## Attention par produit scalaire

> [!TIP]
> L'attention à mémoire efficace optimise la vitesse d'inférence *et* [l'utilisation de la mémoire](./memory#memory-efficient-attention) !

[L'attention par produit scalaire mis à l'échelle (SDPA)](https://pytorch.org/docs/stable/generated/torch.nn.functional.scaled_dot_product_attention.html) implémente plusieurs backends d'attention, [FlashAttention](https://github.com/Dao-AILab/flash-attention), [xFormers](https://github.com/facebookresearch/xformers) et une implémentation C++ native. Il sélectionne automatiquement le backend le plus optimal pour votre matériel.

SDPA est activé par défaut si vous utilisez PyTorch >= 2.0 et aucune modification supplémentaire de votre code n'est requise. Vous pouvez toutefois expérimenter avec d'autres backends d'attention si vous souhaitez en choisir un vous-même. L'exemple ci-dessous utilise le gestionnaire de contexte [torch.nn.attention.sdpa_kernel](https://pytorch.org/docs/stable/generated/torch.nn.attention.sdpa_kernel.html) pour activer une attention efficace.

```py
from torch.nn.attention import SDPBackend, sdpa_kernel
import torch
from diffusers import StableDiffusionXLPipeline

pipeline = StableDiffusionXLPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0", dtype=torch.bfloat16
).to("cuda")  # or "mps", "xpu", "cpu"

prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k"

with sdpa_kernel(SDPBackend.EFFICIENT_ATTENTION):
  image = pipeline(prompt, num_inference_steps=30).images[0]
```

## torch.compile

[torch.compile](https://pytorch.org/tutorials/intermediate/torch_compile_tutorial.html) accélère l’inférence en compilant le code et les opérations PyTorch en noyaux optimisés. Diffusers compile généralement les modèles les plus gourmands en calcul, comme le UNet, le transformer ou le VAE.

Activez les paramètres de compilateur suivants pour une vitesse maximale (reportez-vous à la [liste complète](https://github.com/pytorch/pytorch/blob/main/torch/_inductor/config.py) pour plus d'options).

```py
import torch
from diffusers import StableDiffusionXLPipeline

torch._inductor.config.conv_1x1_as_mm = True
torch._inductor.config.coordinate_descent_tuning = True
torch._inductor.config.epilogue_fusion = False
torch._inductor.config.coordinate_descent_check_all_directions = True
```

Chargez et compilez le UNet et le VAE. Plusieurs modes sont disponibles, mais `"max-autotune"` optimise la vitesse maximale en compilant vers un graphe CUDA. Les graphes CUDA réduisent efficacement le surcoût en lançant plusieurs opérations GPU via une seule opération CPU.

> [!TIP]
> Avec PyTorch 2.3.1, vous pouvez contrôler le comportement de mise en cache de torch.compile. Cela est particulièrement bénéfique pour les modes de compilation tels que `"max-autotune"`, qui effectue une recherche sur grille sur plusieurs drapeaux de compilation afin de trouver la configuration optimale. En savoir plus dans le tutoriel [Compile Time Caching in torch.compile](https://pytorch.org/tutorials/recipes/torch_compile_caching_tutorial.html).

Changer la disposition de la mémoire en [channels_last](./memory#torchchannelslast) optimise également la mémoire et la vitesse d'inférence.

```py
pipeline = StableDiffusionXLPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0", dtype=torch.float16
).to("cuda")  # or "mps", "xpu", "cpu"
pipeline.unet.to(memory_format=torch.channels_last)
pipeline.vae.to(memory_format=torch.channels_last)
pipeline.unet = torch.compile(
    pipeline.unet, mode="max-autotune", fullgraph=True
)
pipeline.vae.decode = torch.compile(
    pipeline.vae.decode,
    mode="max-autotune",
    fullgraph=True
)

prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k"
pipeline(prompt, num_inference_steps=30).images[0]
```

La compilation est lente la première fois, mais une fois compilé, le pipeline est nettement plus rapide. Essayez d'utiliser le pipeline compilé uniquement pour le même type d'opérations d'inférence. Appeler le pipeline compilé avec une taille d'image différente relance la compilation, ce qui est lent et inefficace.

### Compilation de formes dynamiques

> [!TIP]
> Assurez-vous d'utiliser toujours la version nocturne de PyTorch pour un meilleur support.

`torch.compile` suit les formes des entrées et les conditions, et si celles-ci diffèrent, il recompile le modèle. Par exemple, si un modèle est compilé sur une image de résolution 1024x1024 puis utilisé sur une image de résolution différente, cela déclenche une recompilation.

Pour éviter la recompilation, ajoutez `dynamic=True` afin de générer un noyau plus dynamique et d'éviter ainsi la recompilation lorsque les conditions changent.

```diff
+ torch.fx.experimental._config.use_duck_shape = False
+ pipeline.unet = torch.compile(
    pipeline.unet, fullgraph=True, dynamic=True
)
```

Spécifier `use_duck_shape=False` indique au compilateur s'il doit utiliser la même variable symbolique pour représenter les tailles d'entrée identiques. Pour plus de détails, consultez ce [commentaire](https://github.com/huggingface/diffusers/pull/11327#discussion_r2047659790).

Tous les modèles ne bénéficient pas nécessairement de la compilation dynamique dès l’origine et peuvent nécessiter des modifications. Consultez cette [PR](https://github.com/huggingface/diffusers/pull/11297/) qui a amélioré l’implémentation de [AuraFlowPipeline](/docs/diffusers/main/fr/api/pipelines/aura_flow#diffusers.AuraFlowPipeline) afin de tirer parti de la compilation dynamique.

N'hésitez pas à ouvrir un ticket si la compilation dynamique ne fonctionne pas comme prévu pour un modèle Diffusers.

### Compilation régionale

[La compilation régionale](https://docs.pytorch.org/tutorials/recipes/regional_compilation.html) réduit la latence de démarrage à froid en ne compilant que les *blocs petits et fréquemment répétés* d'un modèle - généralement une couche de transformer - et permet de réutiliser les artefacts compilés pour chaque occurrence ultérieure. Pour de nombreuses architectures de diffusion, cela offre les mêmes gains de vitesse d'exécution que la compilation du graphe complet et réduit le temps de compilation de 8 à 10 fois.

Utilisez la méthode [compile_repeated_blocks()](/docs/diffusers/main/fr/api/models/overview#diffusers.ModelMixin.compile_repeated_blocks), un utilitaire qui encapsule `torch.compile`, sur n'importe quel composant, tel que le modèle transformer, comme indiqué ci-dessous.

```py
# pip install -U diffusers
import torch
from diffusers import StableDiffusionXLPipeline

pipeline = StableDiffusionXLPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0",
    dtype=torch.float16,
).to("cuda")  # or "mps", "xpu", "cpu"

# compile only the repeated transformer layers inside the UNet
pipeline.unet.compile_repeated_blocks(fullgraph=True)
```

Pour activer la compilation régionale pour un nouveau modèle, ajoutez un attribut `_repeated_blocks` à une classe de modèle contenant les noms de classes (sous forme de chaînes de caractères) des blocs que vous souhaitez compiler.

```py
class MyUNet(ModelMixin):
    _repeated_blocks = ("Transformer2DModel",)  # ← compiled by default
```

> [!TIP]
> Pour plus d’exemples de compilation régionale, consultez la [PR](https://github.com/huggingface/diffusers/pull/11705) de référence.

Il existe également une méthode [compile_regions](https://github.com/huggingface/accelerate/blob/273799c85d849a1954a4f2e65767216eb37fa089/src/accelerate/utils/other.py#L78) dans [Accelerate](https://huggingface.co/docs/accelerate/index) qui sélectionne automatiquement les blocs candidats d'un modèle à compiler. Le reste du graphe est compilé séparément. C'est utile pour des expériences rapides, car il y a moins d'options pour définir quels blocs compiler ou ajuster les drapeaux de compilation.

```py
# pip install -U accelerate
import torch
from diffusers import StableDiffusionXLPipeline
from accelerate.utils import compile_regions

pipeline = StableDiffusionXLPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0", dtype=torch.float16
).to("cuda")  # or "mps", "xpu", "cpu"
pipeline.unet = compile_regions(pipeline.unet, mode="reduce-overhead", fullgraph=True)
```

[compile_repeated_blocks()](/docs/diffusers/main/fr/api/models/overview#diffusers.ModelMixin.compile_repeated_blocks) est volontairement explicite. Énumérez les blocs à répéter dans `_repeated_blocks` et l’assistant ne compile que ces blocs. Il offre un comportement prévisible et un raisonnement simple sur la réutilisation du cache en une seule ligne de code.

### Interruptions de graphe

Il est important de spécifier `fullgraph=True` dans torch.compile pour s'assurer qu'il n'y a pas de coupures de graphe dans le modèle sous-jacent. Cela vous permet de tirer parti de torch.compile sans aucune dégradation des performances. Pour le UNet et le VAE, cela modifie la manière dont vous accédez aux variables de retour.

```diff
- latents = unet(
-   latents, timestep=timestep, encoder_hidden_states=prompt_embeds
-).sample

+ latents = unet(
+   latents, timestep=timestep, encoder_hidden_states=prompt_embeds, return_dict=False
+)[0]
```

### Synchronisation GPU

La fonction `step()` est [appelée](https://github.com/huggingface/diffusers/blob/1d686bac8146037e97f3fd8c56e4063230f71751/src/diffusers/pipelines/stable_diffusion_xl/pipeline_stable_diffusion_xl.py#L1228) sur le planificateur à chaque fois que le débruiteur effectue une prédiction, et la variable `sigmas` est [indexée](https://github.com/huggingface/diffusers/blob/1d686bac8146037e97f3fd8c56e4063230f71751/src/diffusers/schedulers/scheduling_euler_discrete.py#L476). Lorsqu'elle est placée sur le GPU, elle introduit une latence en raison de la synchronisation de communication entre le CPU et le GPU. Cela devient plus évident lorsque le débruiteur a déjà été compilé.

En général, les `sigmas` doivent [rester sur le CPU](https://github.com/huggingface/diffusers/blob/35a969d297cba69110d175ee79c59312b9f49e1e/src/diffusers/schedulers/scheduling_euler_discrete.py#L240) pour éviter la synchronisation de communication et la latence.

> [!TIP]
> Consultez le billet de blog [torch.compile and Diffusers: A Hands-On Guide to Peak Performance](https://pytorch.org/blog/torch-compile-and-diffusers-a-hands-on-guide-to-peak-performance/) pour maximiser les performances avec `torch.compile` pour les modèles de diffusion.

### Benchmarks

Consultez le jeu de données [diffusers/benchmarks](https://huggingface.co/datasets/diffusers/benchmarks) pour consulter les données de latence d'inférence et d'utilisation de la mémoire des pipelines compilés.

Le dépôt [diffusers-torchao](https://github.com/sayakpaul/diffusers-torchao#benchmarking-results) contient également des résultats de benchmark pour les versions compilées de Flux et CogVideoX.

## Kernels

[Kernels](https://huggingface.co/docs/kernels/index) est une bibliothèque pour construire, distribuer et charger des noyaux de calcul optimisés sur le [Hub](https://huggingface.co/kernels-community). Elle prend en charge les noyaux [attention](./attention_backends#setattentionbackend) et les noyaux CUDA personnalisés pour des opérations telles que RMSNorm, GEGLU, RoPE et AdaLN.

Le guide [Diffusers Pipeline Integration](https://github.com/huggingface/kernels/blob/main/kernel-builder/skills/cuda-kernels/references/diffusers-integration.md) montre comment intégrer un noyau avec la compétence [add cuda-kernels](https://github.com/huggingface/kernels/blob/main/kernel-builder/skills/cuda-kernels/SKILL.md). Cette compétence permet à un agent, comme Claude ou Codex, d'écrire des noyaux personnalisés ciblant un modèle spécifique et votre matériel.

> [!TIP]
> Installez la compétence [add cuda-kernels](https://github.com/huggingface/kernels/blob/main/kernel-builder/skills/cuda-kernels/SKILL.md) pour apprendre à un agent à écrire un noyau. L'article de blog [Custom kernels for all from Codex and Claude](https://huggingface.co/blog/custom-cuda-kernels-agent-skills) aborde ce sujet en détail.

Par exemple, un noyau RMSNorm personnalisé (généré par la compétence `add cuda-kernels`) avec [torch.compile](#torchcompile) accélère la génération de LTX-Video de 1,43 fois sur une H100.

<iframe src="https://huggingface.co/datasets/docs-benchmarks/kernel-ltx-video/embed/viewer/default/train" frameborder="0" width="100%" height="560px"
>

## Quantification dynamique

[La quantification dynamique](https://docs.pytorch.org/ao/main/api_reference/generated/torchao.quantization.Int8DynamicActivationInt8WeightConfig.html) améliore la vitesse d'inférence en réduisant la précision afin de permettre des opérations mathématiques plus rapides. Ce type de quantification détermine comment mettre à l'échelle les activations en fonction des données au moment de l'exécution, plutôt que d'utiliser un facteur d'échelle fixe. En conséquence, le facteur d'échelle est plus précisément aligné sur les données.

L'exemple ci-dessous applique la [quantification dynamique int8](https://docs.pytorch.org/ao/main/api_reference/generated/torchao.quantization.Int8DynamicActivationInt8WeightConfig.html) au UNet et au VAE avec la bibliothèque [torchao](../quantization/torchao).

> [!TIP]
> Consultez notre documentation [torchao](../quantization/torchao) pour en savoir plus sur l'utilisation de l'intégration torchao de Diffusers.

Configurez les balises du compilateur pour une vitesse maximale.

```py
import torch
from torchao import apply_dynamic_quant
from diffusers import StableDiffusionXLPipeline

torch._inductor.config.conv_1x1_as_mm = True
torch._inductor.config.coordinate_descent_tuning = True
torch._inductor.config.epilogue_fusion = False
torch._inductor.config.coordinate_descent_check_all_directions = True
torch._inductor.config.force_fuse_int_mm_with_mul = True
torch._inductor.config.use_mixed_mm = True
```

Filtrez certaines couches linéaires du UNet et du VAE qui ne bénéficient pas de la quantification dynamique à l'aide de [dynamic_quant_filter_fn](https://github.com/huggingface/diffusion-fast/blob/0f169640b1db106fe6a479f78c1ed3bfaeba3386/utils/pipeline_utils.py#L16).

```py
pipeline = StableDiffusionXLPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0", dtype=torch.bfloat16
).to("cuda")  # or "mps", "xpu", "cpu"

apply_dynamic_quant(pipeline.unet, dynamic_quant_filter_fn)
apply_dynamic_quant(pipeline.vae, dynamic_quant_filter_fn)

prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k"
pipeline(prompt, num_inference_steps=30).images[0]
```

## Matrices de projection fusionnées

> [!WARNING]
> La méthode [fuse_qkv_projections](https://github.com/huggingface/diffusers/blob/58431f102cf39c3c8a569f32d71b2ea8caa461e1/src/diffusers/pipelines/pipeline_utils.py#L2034) est expérimentale et son support est limité, principalement aux pipelines Stable Diffusion. Consultez ce [PR](https://github.com/huggingface/diffusers/pull/6179) pour en savoir plus sur la manière de l’activer pour d’autres pipelines.

Une entrée est projetée dans trois sous-espaces, représentés par les matrices de projection Q, K et V, au sein d'un bloc d'attention. Ces projections sont généralement calculées séparément, mais vous pouvez les combiner horizontalement en une seule matrice et effectuer la projection en une seule étape. Cela augmente la taille des multiplications de matrices des projections d'entrée et améliore également l'impact de la quantification.

```py
pipeline.fuse_qkv_projections()
```

## Ressources

- Lisez le billet de blog [Presenting Flux Fast: Making Flux go brrr on H100s](https://pytorch.org/blog/presenting-flux-fast-making-flux-go-brrr-on-h100s/) pour en savoir plus sur la manière de combiner toutes ces optimisations avec [TorchInductor](https://docs.pytorch.org/docs/stable/torch.compiler.html) et [AOTInductor](https://docs.pytorch.org/docs/stable/torch.compiler_aot_inductor.html) afin d’obtenir un gain de vitesse d’environ 2,5x en utilisant les recettes de [flux-fast](https://github.com/huggingface/flux-fast).

    Ces recettes prennent en charge le matériel AMD et [Flux.1 Kontext Dev](https://huggingface.co/black-forest-labs/FLUX.1-Kontext-dev).
- Lisez le billet de blog [torch.compile et Diffusers : un guide pratique pour des performances optimales](https://pytorch.org/blog/torch-compile-and-diffusers-a-hands-on-guide-to-peak-performance/)
pour maximiser les performances lors de l'utilisation de `torch.compile`.

