# Acelerar la inferencia

Los modelos de difusión son lentos en la inferencia porque la generación es un proceso iterativo en el que el ruido se refina gradualmente hasta convertirse en una imagen o un video a lo largo de un número determinado de "pasos". Para acelerar este proceso, puedes experimentar con diferentes [schedulers](../api/schedulers/overview), reducir la precisión de los pesos del modelo para cálculos más rápidos, utilizar mecanismos de atención más eficientes en memoria, entre otras cosas.

Combine y utilice estas técnicas juntas para lograr una inferencia más rápida que la obtenida al usar cualquier técnica de forma individual.

Esta guía explica cómo acelerar la inferencia.

## Tipo de datos del modelo

La precisión y el tipo de datos de los pesos del modelo afectan la velocidad de inferencia, ya que una mayor precisión requiere más memoria para cargarlos y más tiempo para realizar los cálculos. PyTorch carga los pesos del modelo en float32 o precisión completa de forma predeterminada, por lo que cambiar el tipo de datos es una forma sencilla de obtener una inferencia más rápida.

bfloat16 es similar a float16, pero es más robusto ante errores numéricos. El soporte de hardware para bfloat16 varía, pero la mayoría de las GPU modernas son capaces de admitir 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 es similar a bfloat16, pero puede ser más propenso a errores numéricos.

```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]
```

El modo [TensorFloat-32 (tf32)](https://blogs.nvidia.com/blog/2020/05/14/tensorfloat-32-precision-format/) es compatible con las GPU NVIDIA Ampere y calcula las operaciones de convolución y multiplicación de matrices en tf32. El almacenamiento y las demás operaciones se mantienen en float32. Esto permite cálculos significativamente más rápidos cuando se combina con bfloat16 o float16.

PyTorch solo habilita el modo tf32 para las convoluciones de forma predeterminada y es necesario habilitarlo explícitamente para las multiplicaciones 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]
```

Consulte la documentación de [entrenamiento con precisión mixta](https://huggingface.co/docs/transformers/en/perf_train_gpu_one#mixed-precision) para obtener más detalles.

## Atención de producto escalar

> [!TIP]
> La atención eficiente en memoria optimiza la velocidad de inferencia *y* el [uso de memoria](./memory#memory-efficient-attention)

[Scaled dot product attention (SDPA)](https://pytorch.org/docs/stable/generated/torch.nn.functional.scaled_dot_product_attention.html) implementa varios backends de atención, [FlashAttention](https://github.com/Dao-AILab/flash-attention), [xFormers](https://github.com/facebookresearch/xformers) y una implementación nativa en C++. Selecciona automáticamente el backend más óptimo para tu hardware.

SDPA está habilitado de forma predeterminada si estás usando PyTorch >= 2.0 y no se requieren cambios adicionales en tu código. Sin embargo, puedes experimentar con otros backends de atención si deseas elegir el tuyo. El ejemplo de abajo utiliza el gestor de contexto [torch.nn.attention.sdpa_kernel](https://pytorch.org/docs/stable/generated/torch.nn.attention.sdpa_kernel.html) para habilitar una atención eficiente.

```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) acelera la inferencia al compilar el código y las operaciones de PyTorch en kernels optimizados. Diffusers suele compilar los modelos más intensivos en cómputo, como UNet, transformer o VAE.

Habilite los siguientes ajustes del compilador para obtener la máxima velocidad (consulte la [lista completa](https://github.com/pytorch/pytorch/blob/main/torch/_inductor/config.py) para más opciones).

```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
```

Cargue y compile el UNet y el VAE. Hay varios modos diferentes entre los que puede elegir, pero `"max-autotune"` optimiza para la velocidad más rápida compilando a un grafo de CUDA. Los grafos de CUDA reducen eficazmente la sobrecarga al lanzar múltiples operaciones de GPU a través de una sola operación de CPU.

> [!TIP]
> Con PyTorch 2.3.1, puedes controlar el comportamiento de la caché de torch.compile. Esto resulta especialmente beneficioso para modos de compilación como `"max-autotune"`, que realiza una búsqueda por cuadrícula sobre varias banderas de compilación para encontrar la configuración óptima. Obtén más información en el tutorial [Caché de tiempo de compilación en torch.compile](https://pytorch.org/tutorials/recipes/torch_compile_caching_tutorial.html).

Cambiar el diseño de memoria a [channels_last](./memory#torchchannelslast) también optimiza la memoria y la velocidad de inferencia.

```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 compilación es lenta la primera vez, pero una vez compilado, es significativamente más rápido. Intente usar el pipeline compilado solo para el mismo tipo de operaciones de inferencia. Llamar al pipeline compilado con un tamaño de imagen diferente vuelve a desencadenar la compilación, lo cual es lento e ineficiente.

### Compilación de formas dinámicas

> [!TIP]
> Asegúrate de usar siempre la versión nocturna de PyTorch para obtener un mejor soporte.

`torch.compile` mantiene un registro de las formas de entrada y las condiciones, y si estas son diferentes, recompila el modelo. Por ejemplo, si un modelo se compila con una imagen de resolución 1024x1024 y se utiliza con una imagen de una resolución diferente, se desencadena la recompilación.

Para evitar la recompilación, agregue `dynamic=True` para intentar generar un kernel más dinámico y así evitar la recompilación cuando cambien las condiciones.

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

Especificar `use_duck_shape=False` indica al compilador si debe usar la misma variable simbólica para representar tamaños de entrada que son iguales. Para más detalles, consulta este [comentario](https://github.com/huggingface/diffusers/pull/11327#discussion_r2047659790).

No todos los modelos pueden beneficiarse de la compilación dinámica de forma predeterminada y pueden requerir cambios. Consulte este [PR](https://github.com/huggingface/diffusers/pull/11297/) que mejoró la implementación de [AuraFlowPipeline](/docs/diffusers/main/es/api/pipelines/aura_flow#diffusers.AuraFlowPipeline) para beneficiarse de la compilación dinámica.

Siéntase libre de abrir un problema si la compilación dinámica no funciona como se espera para un modelo de Diffusers.

### Compilación regional

La [compilación regional](https://docs.pytorch.org/tutorials/recipes/regional_compilation.html) reduce la latencia de inicio en frío compilando únicamente los *bloques pequeños y repetidos con frecuencia* de un modelo, típicamente una capa de transformer, y permite reutilizar los artefactos compilados para cada ocurrencia posterior. Para muchas arquitecturas de difusión, esto ofrece las mismas mejoras de velocidad de ejecución que la compilación de todo el grafo y reduce el tiempo de compilación entre 8 y 10 veces.

Utilice el método [compile_repeated_blocks()](/docs/diffusers/main/es/api/models/overview#diffusers.ModelMixin.compile_repeated_blocks), un auxiliar que envuelve `torch.compile`, en cualquier componente, como el modelo transformer, tal como se muestra a continuación.

```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)
```

Para habilitar la compilación regional para un nuevo modelo, agregue un atributo `_repeated_blocks` a una clase de modelo que contenga los nombres de las clases (como cadenas de texto) de los bloques que desea compilar.

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

> [!TIP]
> Para más ejemplos de compilación regional, consulte la [PR](https://github.com/huggingface/diffusers/pull/11705) de referencia.

También existe un método [compile_regions](https://github.com/huggingface/accelerate/blob/273799c85d849a1954a4f2e65767216eb37fa089/src/accelerate/utils/other.py#L78) en [Accelerate](https://huggingface.co/docs/accelerate/index) que selecciona automáticamente los bloques candidatos de un modelo para compilar. El resto del grafo se compila por separado. Esto es útil para experimentos rápidos, ya que no hay tantas opciones para configurar qué bloques compilar o ajustar las banderas de compilación.

```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/es/api/models/overview#diffusers.ModelMixin.compile_repeated_blocks) es intencionalmente explícito. Enumera los bloques a repetir en `_repeated_blocks` y el helper solo compila esos bloques. Ofrece un comportamiento predecible y facilita razonar sobre la reutilización de la caché en una sola línea de código.

### Puntos de interrupción del grafo

Es importante especificar `fullgraph=True` en torch.compile para garantizar que no haya interrupciones en el grafo del modelo subyacente. Esto permite aprovechar torch.compile sin ninguna degradación de rendimiento. Para UNet y VAE, esto cambia cómo se accede a las variables de retorno.

```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]
```

### Sincronización de GPU

La función `step()` se [llama](https://github.com/huggingface/diffusers/blob/1d686bac8146037e97f3fd8c56e4063230f71751/src/diffusers/pipelines/stable_diffusion_xl/pipeline_stable_diffusion_xl.py#L1228) en el programador cada vez que el desruidador realiza una predicción, y la variable `sigmas` se [indexa](https://github.com/huggingface/diffusers/blob/1d686bac8146037e97f3fd8c56e4063230f71751/src/diffusers/schedulers/scheduling_euler_discrete.py#L476). Al colocarse en la GPU, introduce latencia debido a la sincronización de comunicación entre la CPU y la GPU. Esto se vuelve más evidente cuando el desruidador ya ha sido compilado.

En general, los `sigmas` deben [permanecer en la CPU](https://github.com/huggingface/diffusers/blob/35a969d297cba69110d175ee79c59312b9f49e1e/src/diffusers/schedulers/scheduling_euler_discrete.py#L240) para evitar la sincronización de comunicación y la latencia.

> [!TIP]
> Consulte la publicación 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/) para maximizar el rendimiento con `torch.compile` en modelos de difusión.

### Benchmarks

Consulte el conjunto de datos [diffusers/benchmarks](https://huggingface.co/datasets/diffusers/benchmarks) para ver los datos de latencia de inferencia y uso de memoria de las tuberías compiladas.

El repositorio [diffusers-torchao](https://github.com/sayakpaul/diffusers-torchao#benchmarking-results) también contiene resultados de benchmarking para las versiones compiladas de Flux y CogVideoX.

## Kernels

[Kernels](https://huggingface.co/docs/kernels/index) es una biblioteca para construir, distribuir y cargar kernels de cómputo optimizados en el [Hub](https://huggingface.co/kernels-community). Admite kernels de [attention](./attention_backends#setattentionbackend) y kernels CUDA personalizados para operaciones como RMSNorm, GEGLU, RoPE y AdaLN.

La guía de [Integración de pipelines de Diffusers](https://github.com/huggingface/kernels/blob/main/kernel-builder/skills/cuda-kernels/references/diffusers-integration.md) muestra cómo integrar un kernel con la habilidad [add cuda-kernels](https://github.com/huggingface/kernels/blob/main/kernel-builder/skills/cuda-kernels/SKILL.md). Esta habilidad permite a un agente, como Claude o Codex, escribir kernels personalizados dirigidos a un modelo específico y a tu hardware.

> [!TIP]
> Instale la habilidad [add cuda-kernels](https://github.com/huggingface/kernels/blob/main/kernel-builder/skills/cuda-kernels/SKILL.md) para enseñar a un agente a escribir un kernel. La publicación de blog [Custom kernels for all from Codex and Claude](https://huggingface.co/blog/custom-cuda-kernels-agent-skills) lo cubre en más detalle.

Por ejemplo, un kernel RMSNorm personalizado (generado por la habilidad `add cuda-kernels`) con [torch.compile](#torchcompile) acelera la generación de LTX-Video 1.43 veces en una H100.

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

## Cuantización dinámica

[Cuantización dinámica](https://docs.pytorch.org/ao/main/api_reference/generated/torchao.quantization.Int8DynamicActivationInt8WeightConfig.html) mejora la velocidad de inferencia al reducir la precisión para habilitar operaciones matemáticas más rápidas. Este tipo particular de cuantización determina cómo escalar las activaciones en función de los datos en tiempo de ejecución, en lugar de utilizar un factor de escala fijo. Como resultado, el factor de escala se alinea con mayor precisión con los datos.

El ejemplo siguiente aplica [cuantización dinámica int8](https://docs.pytorch.org/ao/main/api_reference/generated/torchao.quantization.Int8DynamicActivationInt8WeightConfig.html) al UNet y al VAE con la biblioteca [torchao](../quantization/torchao).

> [!TIP]
> Consulte nuestra documentación de [torchao](../quantization/torchao) para obtener más información sobre cómo usar la integración de torchao de Diffusers.

Configure las etiquetas del compilador para la máxima velocidad.

```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
```

Filtre algunas capas lineales en el UNet y el VAE que no se benefician de la cuantización dinámica con [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 proyección fusionadas

> [!WARNING]
> El método [fuse_qkv_projections](https://github.com/huggingface/diffusers/blob/58431f102cf39c3c8a569f32d71b2ea8caa461e1/src/diffusers/pipelines/pipeline_utils.py#L2034) es experimental y su soporte está limitado principalmente a los pipelines de Stable Diffusion. Consulta este [PR](https://github.com/huggingface/diffusers/pull/6179) para obtener más información sobre cómo habilitarlo en otros pipelines.

Una entrada se proyecta en tres subespacios, representados por las matrices de proyección Q, K y V, en un bloque de atención. Estas proyecciones suelen calcularse por separado, pero se pueden combinar horizontalmente en una única matriz y realizar la proyección en un solo paso. Esto aumenta el tamaño de las multiplicaciones de matrices de las proyecciones de entrada y también mejora el impacto de la cuantización.

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

## Recursos

- Lee la publicación de blog [Presenting Flux Fast: Making Flux go brrr on H100s](https://pytorch.org/blog/presenting-flux-fast-making-flux-go-brrr-on-h100s/) para saber más sobre cómo puedes combinar todas estas optimizaciones con [TorchInductor](https://docs.pytorch.org/docs/stable/torch.compiler.html) y [AOTInductor](https://docs.pytorch.org/docs/stable/torch.compiler_aot_inductor.html) para lograr una aceleración de ~2.5x utilizando las recetas de [flux-fast](https://github.com/huggingface/flux-fast).

    Estas recetas admiten hardware de AMD y [Flux.1 Kontext Dev](https://huggingface.co/black-forest-labs/FLUX.1-Kontext-dev).
- Lee el artículo de blog [torch.compile y Diffusers: una guía práctica para el rendimiento máximo](https://pytorch.org/blog/torch-compile-and-diffusers-a-hands-on-guide-to-peak-performance/)
para maximizar el rendimiento al usar `torch.compile`.

