# Acelerar a inferência

Os modelos de difusão são lentos na inferência porque a geração é um processo iterativo no qual o ruído é gradualmente refinado em uma imagem ou vídeo ao longo de um determinado número de "etapas". Para acelerar esse processo, você pode tentar experimentar diferentes [schedulers](../api/schedulers/overview), reduzir a precisão dos pesos do modelo para cálculos mais rápidos, usar mecanismos de atenção mais eficientes em termos de memória, entre outras coisas.

Combine e utilize essas técnicas em conjunto para tornar a inferência mais rápida do que ao usar qualquer técnica isoladamente.

Este guia explicará como acelerar a inferência.

## Tipo de dados do modelo

A precisão e o tipo de dados dos pesos do modelo afetam a velocidade de inferência, pois uma precisão maior exige mais memória para carregar e mais tempo para executar os cálculos. O PyTorch carrega os pesos do modelo em float32 ou precisão completa por padrão, portanto, alterar o tipo de dados é uma maneira simples de obter inferência mais rápida rapidamente.

bfloat16 é semelhante a float16, mas é mais robusto a erros numéricos. O suporte de hardware para bfloat16 varia, mas a maioria das GPUs modernas é capaz de suportar 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 é semelhante a bfloat16, mas pode ser mais suscetível a erros 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]
```

O modo [TensorFloat-32 (tf32)](https://blogs.nvidia.com/blog/2020/05/14/tensorfloat-32-precision-format/) é suportado em GPUs NVIDIA Ampere e executa as operações de convolução e multiplicação de matrizes em tf32. O armazenamento e as demais operações permanecem em float32. Isso permite computações significativamente mais rápidas quando combinado com bfloat16 ou float16.

O PyTorch habilita o modo tf32 apenas para convoluções por padrão e você precisará habilitá-lo explicitamente para multiplicações de matrizes.

```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 a documentação de [treinamento com precisão mista](https://huggingface.co/docs/transformers/en/perf_train_gpu_one#mixed-precision) para mais detalhes.

## Atenção de produto escalar

> [!TIP]
> A atenção eficiente em memória otimiza a velocidade de inferência *e* o [uso de memória](./memory#memory-efficient-attention)!

[Scaled dot product attention (SDPA)](https://pytorch.org/docs/stable/generated/torch.nn.functional.scaled_dot_product_attention.html) implementa vários backends de atenção, [FlashAttention](https://github.com/Dao-AILab/flash-attention), [xFormers](https://github.com/facebookresearch/xformers) e uma implementação nativa em C++. Ele seleciona automaticamente o backend mais otimizado para o seu hardware.

O SDPA é ativado por padrão se você estiver usando PyTorch >= 2.0 e nenhuma alteração adicional é necessária no seu código. No entanto, você pode experimentar outros backends de atenção, caso queira escolher o seu próprio. O exemplo abaixo usa o gerenciador de contexto [torch.nn.attention.sdpa_kernel](https://pytorch.org/docs/stable/generated/torch.nn.attention.sdpa_kernel.html) para habilitar a atenção 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 a inferência compilando o código e as operações do PyTorch em kernels otimizados. O Diffusers normalmente compila os modelos mais intensivos em computação, como o UNet, o transformer ou o VAE.

Ative as seguintes configurações do compilador para máxima velocidade (consulte a [lista completa](https://github.com/pytorch/pytorch/blob/main/torch/_inductor/config.py) para mais opções).

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

Carregue e compile o UNet e o VAE. Existem vários modos diferentes que você pode escolher, mas `"max-autotune"` otimiza para a velocidade mais rápida compilando para um grafo CUDA. Os grafos CUDA reduzem efetivamente o overhead ao lançar múltiplas operações de GPU por meio de uma única operação de CPU.

> [!TIP]
> Com o PyTorch 2.3.1, você pode controlar o comportamento de cache do torch.compile. Isso é particularmente benéfico para modos de compilação como `"max-autotune"`, que executa uma busca em grade sobre várias flags de compilação para encontrar a configuração ideal. Saiba mais no tutorial [Compile Time Caching in torch.compile](https://pytorch.org/tutorials/recipes/torch_compile_caching_tutorial.html).

Alterar o layout de memória para [channels_last](./memory#torchchannelslast) também otimiza a memória e a velocidade de inferência.

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

A compilação é lenta na primeira vez, mas, uma vez compilado, o processo é significativamente mais rápido. Tente usar o pipeline compilado apenas para o mesmo tipo de operações de inferência. Chamar o pipeline compilado com um tamanho de imagem diferente reativa a compilação, o que é lento e ineficiente.

### Compilação de formas dinâmicas

> [!TIP]
> Certifique-se de sempre usar a versão nightly do PyTorch para um melhor suporte.

`torch.compile` acompanha as formas e condições de entrada e, se estas forem diferentes, recompila o modelo. Por exemplo, se um modelo for compilado em uma imagem de resolução 1024x1024 e usado em uma imagem com resolução diferente, isso aciona a recompilação.

Para evitar recompilação, adicione `dynamic=True` para tentar gerar um kernel mais dinâmico e evitar recompilação quando as condições mudarem.

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

Especificar `use_duck_shape=False` instrui o compilador se ele deve usar a mesma variável simbólica para representar tamanhos de entrada que são iguais. Para mais detalhes, confira este [comentário](https://github.com/huggingface/diffusers/pull/11327#discussion_r2047659790).

Nem todos os modelos podem se beneficiar da compilação dinâmica imediatamente e podem exigir alterações. Consulte este [PR](https://github.com/huggingface/diffusers/pull/11297/) que melhorou a implementação do [AuraFlowPipeline](/docs/diffusers/v0.43.0/pt/api/pipelines/aura_flow#diffusers.AuraFlowPipeline) para se beneficiar da compilação dinâmica.

Sinta-se à vontade para abrir uma issue se a compilação dinâmica não funcionar como esperado para um modelo do Diffusers.

### Compilação regional

[Compilação regional](https://docs.pytorch.org/tutorials/recipes/regional_compilation.html) reduz a latência de inicialização ao compilar apenas o *bloco pequeno e repetido com frequência* de um modelo — tipicamente uma camada de transformer — e permite reutilizar os artefatos compilados para cada ocorrência subsequente. Para muitas arquiteturas de difusão, isso entrega as mesmas acelerações de tempo de execução que a compilação de grafo completo e reduz o tempo de compilação em 8 a 10 vezes.

Use o método [compile_repeated_blocks()](/docs/diffusers/v0.43.0/pt/api/models/overview#diffusers.ModelMixin.compile_repeated_blocks), um auxiliar que encapsula o `torch.compile`, em qualquer componente, como o modelo transformer, conforme mostrado abaixo.

```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 a compilação regional para um novo modelo, adicione um atributo `_repeated_blocks` a uma classe de modelo contendo os nomes das classes (como strings) dos blocos que você deseja compilar.

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

> [!TIP]
> Para mais exemplos de compilação regional, consulte a referência [PR](https://github.com/huggingface/diffusers/pull/11705).

Há também um método [compile_regions](https://github.com/huggingface/accelerate/blob/273799c85d849a1954a4f2e65767216eb37fa089/src/accelerate/utils/other.py#L78) no [Accelerate](https://huggingface.co/docs/accelerate/index) que seleciona automaticamente os blocos candidatos em um modelo para compilação. O restante do grafo é compilado separadamente. Isso é útil para experimentos rápidos, pois há menos opções para você definir quais blocos compilar ou ajustar as flags de compilação.

```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/v0.43.0/pt/api/models/overview#diffusers.ModelMixin.compile_repeated_blocks) é intencionalmente explícito. Liste os blocos a repetir em `_repeated_blocks` e o helper compila apenas esses blocos. Ele oferece um comportamento previsível e facilita o raciocínio sobre a reutilização do cache em uma linha de código.

### Quebras de gráfico

É importante especificar `fullgraph=True` no torch.compile para garantir que não haja quebras de grafo no modelo subjacente. Isso permite aproveitar o torch.compile sem qualquer degradação de desempenho. Para o UNet e o VAE, isso altera a forma como você acessa as variáveis 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]
```

### Sincronização de GPU

A função `step()` é [chamada](https://github.com/huggingface/diffusers/blob/1d686bac8146037e97f3fd8c56e4063230f71751/src/diffusers/pipelines/stable_diffusion_xl/pipeline_stable_diffusion_xl.py#L1228) no scheduler a cada vez que o denoiser faz uma previsão, e a variável `sigmas` é [indexada](https://github.com/huggingface/diffusers/blob/1d686bac8146037e97f3fd8c56e4063230f71751/src/diffusers/schedulers/scheduling_euler_discrete.py#L476). Quando colocada na GPU, ela introduz latência devido à sincronização de comunicação entre a CPU e a GPU. Isso se torna mais evidente quando o denoiser já foi compilado.

Em geral, os `sigmas` devem [permanecer na CPU](https://github.com/huggingface/diffusers/blob/35a969d297cba69110d175ee79c59312b9f49e1e/src/diffusers/schedulers/scheduling_euler_discrete.py#L240) para evitar a sincronização de comunicação e a latência.

> [!TIP]
> Consulte o post no 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 o desempenho com `torch.compile` em modelos de difusão.

### Benchmarks

Consulte o conjunto de dados [diffusers/benchmarks](https://huggingface.co/datasets/diffusers/benchmarks) para ver dados de latência de inferência e uso de memória para pipelines compilados.

O repositório [diffusers-torchao](https://github.com/sayakpaul/diffusers-torchao#benchmarking-results) também contém resultados de benchmarking para as versões compiladas do Flux e do CogVideoX.

## Kernels

[Kernels](https://huggingface.co/docs/kernels/index) é uma biblioteca para construir, distribuir e carregar kernels de computação otimizados no [Hub](https://huggingface.co/kernels-community). Ela suporta kernels de [atenção](./attention_backends#setattentionbackend) e kernels CUDA personalizados para operações como RMSNorm, GEGLU, RoPE e AdaLN.

O guia de [Integração com o Pipeline do Diffusers](https://github.com/huggingface/kernels/blob/main/kernel-builder/skills/cuda-kernels/references/diffusers-integration.md) mostra como integrar um kernel com a habilidade [add cuda-kernels](https://github.com/huggingface/kernels/blob/main/kernel-builder/skills/cuda-kernels/SKILL.md). Essa habilidade permite que um agente, como Claude ou Codex, escreva kernels personalizados voltados para um modelo específico e para o seu hardware.

> [!TIP]
> Instale a habilidade [add cuda-kernels](https://github.com/huggingface/kernels/blob/main/kernel-builder/skills/cuda-kernels/SKILL.md) para ensinar um agente a escrever um kernel. O post no blog [Custom kernels for all from Codex and Claude](https://huggingface.co/blog/custom-cuda-kernels-agent-skills) aborda isso em mais detalhes.

Por exemplo, um kernel RMSNorm personalizado (gerado pela skill `add cuda-kernels`) com [torch.compile](#torchcompile) acelera a geração do LTX-Video em 1,43x em um H100.

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

## Quantização dinâmica

[Quantização dinâmica](https://docs.pytorch.org/ao/main/api_reference/generated/torchao.quantization.Int8DynamicActivationInt8WeightConfig.html) melhora a velocidade de inferência ao reduzir a precisão para permitir operações matemáticas mais rápidas. Esse tipo específico de quantização determina como escalar as ativações com base nos dados em tempo de execução, em vez de usar um fator de escala fixo. Como resultado, o fator de escala está mais precisamente alinhado com os dados.

O exemplo abaixo aplica [quantização dinâmica int8](https://docs.pytorch.org/ao/main/api_reference/generated/torchao.quantization.Int8DynamicActivationInt8WeightConfig.html) ao UNet e ao VAE com a biblioteca [torchao](../quantization/torchao).

> [!TIP]
> Consulte nossa documentação de [torchao](../quantization/torchao) para saber mais sobre como usar a integração do torchao do Diffusers.

Configure as tags do compilador para a velocidade máxima.

```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 alguns camadas lineares na UNet e na VAE que não se beneficiam da quantização dinâmica com o [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]
```

## Matrizes de projeção fundidas

> [!WARNING]
> O método [fuse_qkv_projections](https://github.com/huggingface/diffusers/blob/58431f102cf39c3c8a569f32d71b2ea8caa461e1/src/diffusers/pipelines/pipeline_utils.py#L2034) é experimental e o suporte é limitado principalmente aos pipelines do Stable Diffusion. Dê uma olhada neste [PR](https://github.com/huggingface/diffusers/pull/6179) para saber mais sobre como ativá-lo para outros pipelines

Uma entrada é projetada em três subespaços, representados pelas matrizes de projeção Q, K e V, em um bloco de atenção. Essas projeções são tipicamente calculadas separadamente, mas é possível combiná-las horizontalmente em uma única matriz e realizar a projeção em uma única etapa. Isso aumenta o tamanho das multiplicações de matrizes das projeções de entrada e também melhora o impacto da quantização.

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

## Recursos

- Leia o post no 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 mais sobre como você pode combinar todas essas otimizações com [TorchInductor](https://docs.pytorch.org/docs/stable/torch.compiler.html) e [AOTInductor](https://docs.pytorch.org/docs/stable/torch.compiler_aot_inductor.html) para uma aceleração de ~2,5x usando as receitas de [flux-fast](https://github.com/huggingface/flux-fast).

    Essas receitas suportam hardware AMD e [Flux.1 Kontext Dev](https://huggingface.co/black-forest-labs/FLUX.1-Kontext-dev).
- Leia o post no blog [torch.compile e Diffusers: Um guia prático para desempenho máximo](https://pytorch.org/blog/torch-compile-and-diffusers-a-hands-on-guide-to-peak-performance/)
para maximizar o desempenho ao usar `torch.compile`.

