# Точность и компиляция

Снижение точности и компиляция — два способа ускорить инференс в Diffusers. Загрузите веса в `bfloat16` или `float16`, затем скомпилируйте денуайзер (UNet или трансформер) с помощью `torch.compile` или региональной компиляции.

## Тип данных модели

Точность и тип данных весов модели влияют на скорость инференса, поскольку более высокая точность требует больше памяти для загрузки и больше времени для выполнения вычислений. Diffusers загружает веса модели в `float32`, если вы не указываете `dtype`, поэтому смена типа данных — простой способ быстро ускорить инференс.

`bfloat16` похож на `float16`, но более устойчив к численным ошибкам. Поддержка `bfloat16` на уровне аппаратного обеспечения различается, однако большинство современных GPU способны работать с `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` похож на `bfloat16`, но более подвержен численным ошибкам.

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

Режим [TensorFloat-32](https://blogs.nvidia.com/blog/2020/05/14/tensorfloat-32-precision-format/) (`tf32`) поддерживается на GPU NVIDIA Ampere и новее. Он выполняет операции свёртки и матричного умножения в формате `tf32`. Хранение данных и остальные операции остаются в формате `float32`. Это ускоряет операции, выполняемые в `float32`, поэтому режим наиболее полезен, когда конвейер или его часть работают в `float32`.

PyTorch по умолчанию включает режим `tf32` только для свёрток, поэтому для матричных умножений его нужно включить явно.

```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.float32
).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]
```

См. документацию по [обучению с смешанной точностью](https://huggingface.co/docs/transformers/en/perf_train_gpu_one#mixed-precision) для получения дополнительных сведений.

## Масштабированное внимание на основе скалярного произведения

[Scaled dot product attention (SDPA)](https://pytorch.org/docs/stable/generated/torch.nn.functional.scaled_dot_product_attention.html) является механизмом внимания по умолчанию в PyTorch 2.0 и более поздних версиях, через `AttnProcessor2_0` или `native` бэкенд диспетчера внимания. PyTorch выбирает ядро SDPA для вашего оборудования. О FlashAttention, SageAttention, xFormers, Hub-ядрах и других бэкендах см. [Attention backends](./attention_backends).

## torch.compile

[torch.compile](https://pytorch.org/tutorials/intermediate/torch_compile_tutorial.html) ускоряет инференс, компилируя код и операции PyTorch в оптимизированные ядра. Обычно компилируют денуизер, который определяет время выполнения, — `pipeline.unet` или `pipeline.transformer`, а иногда и VAE.

Включите следующие настройки компилятора для максимальной скорости (см. [полный список](https://github.com/pytorch/pytorch/blob/main/torch/_inductor/config.py) для других вариантов).

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

Загрузите и скомпилируйте denoiser и VAE. Для UNet-пайплайнов, таких как Stable Diffusion XL, используйте `pipeline.unet`, а для пайплайнов Flux и DiT — `pipeline.transformer`. Доступно несколько режимов, но `"max-autotune"` ищет самые быстрые ядра и использует CUDA graphs. CUDA graphs снижают накладные расходы, запуская несколько операций на GPU через одну операцию на CPU.

Изменение раскладки памяти на [channels_last](./memory#torchchannelslast) также может ускорить модели с преобладанием свёрток, такие как UNet и VAE. Сначала проведите бенчмаркинг, так как некоторые модели работают медленнее.

```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.unet = torch.compile(
    pipeline.unet, mode="max-autotune", fullgraph=True
)
pipeline.vae.to(memory_format=torch.channels_last)
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]
```

Компиляция выполняется медленно при первом запуске, особенно с `"max-autotune"`, поскольку компилятор ищет ядра, а затем продолжает использовать тот же объект скомпилированного конвейера (см. [Кэширование времени компиляции](https://docs.pytorch.org/tutorials/recipes/torch_compile_caching_tutorial.html) и [Конфигурация кэширования](https://docs.pytorch.org/tutorials/recipes/torch_compile_caching_configuration_tutorial.html), чтобы настроить поведение кэширования). Вызов скомпилированного конвейера с другим размером изображения запускает повторную компиляцию.

### Компиляция динамических форм

`torch.compile` отслеживает формы входных данных и условия, и если они отличаются, пересобирает модель. Например, если модель была скомпилирована для изображения с разрешением 1024x1024, а затем используется с изображением другого разрешения, это вызывает повторную компиляцию.

Чтобы избежать повторной компиляции, добавьте `dynamic=True`, чтобы попытаться сгенерировать более динамичное ядро и избежать повторной компиляции при изменении условий.

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

Указание `use_duck_shape=False` сообщает компилятору, следует ли использовать одну и ту же символьную переменную для представления входных размеров, которые совпадают. Подробнее см. в этом [комментарии](https://github.com/huggingface/diffusers/pull/11327#discussion_r2047659790).

Не все модели могут получать преимущества от динамической компиляции «из коробки» и могут требовать изменений. См. этот [PR](https://github.com/huggingface/diffusers/pull/11297/), в котором была улучшена реализация [AuraFlowPipeline](/docs/diffusers/main/ru/api/pipelines/aura_flow#diffusers.AuraFlowPipeline) для использования преимуществ динамической компиляции.

Если динамическая компиляция не работает как ожидается для модели Diffusers, не стесняйтесь создать issue.

### Региональная компиляция

[Региональная компиляция](https://docs.pytorch.org/tutorials/recipes/regional_compilation.html) сокращает задержку холодного запуска, компилируя только *небольшие и часто повторяющиеся блоки* модели — как правило, слой трансформера — и позволяет переиспользовать скомпилированные артефакты для каждого последующего вхождения. Для многих архитектур диффузии это обеспечивает сопоставимое с компиляцией всего графа ускорение времени выполнения и может сократить время компиляции в 8–10 раз.

Используйте метод [compile_repeated_blocks()](/docs/diffusers/main/ru/api/models/overview#diffusers.ModelMixin.compile_repeated_blocks) — вспомогательный, который оборачивает `torch.compile` — для денойзера. Вызывайте его на `pipeline.unet` или `pipeline.transformer` в зависимости от пайплайна.

```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"
pipeline.unet.compile_repeated_blocks(fullgraph=True)
```

Чтобы включить региональную компиляцию для новой модели, установите `_repeated_blocks` в имена классов повторяющихся блоков (строки). Для UNet в SDXL используйте `BasicTransformerBlock`. Трансформерные денойзеры указывают имена классов своих повторяющихся блоков аналогичным образом.

```py
_repeated_blocks = ["BasicTransformerBlock"]
```

В [Accelerate](https://huggingface.co/docs/accelerate/index) также есть метод [compile_regions](https://github.com/huggingface/accelerate/blob/273799c85d849a1954a4f2e65767216eb37fa089/src/accelerate/utils/other.py#L78), который автоматически выбирает блоки модели для компиляции. Остальная часть графа компилируется отдельно. Это удобно для быстрых экспериментов, так как вам не нужно настраивать, какие именно блоки компилировать, или подбирать флаги компиляции.

```bash
pip install -U accelerate
```

```py
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/ru/api/models/overview#diffusers.ModelMixin.compile_repeated_blocks) намеренно явен. Перечислите блоки, подлежащие повторению, в `_repeated_blocks`, и вспомогательная функция скомпилирует только эти блоки. Это обеспечивает предсказуемое поведение и позволяет легко рассуждать о повторном использовании кэша в одной строке кода.

### Разрывы графа

Установите `fullgraph=True`, чтобы torch.compile выдавал ошибку при разрыве графа, а не молча разбивал его, что снижает ускорение.

### Синхронизация GPU

После каждого предсказания денойзера пайплайн вызывает метод `step` планировщика, который обращается к `sigmas`. Если хранить `sigmas` на GPU, это может вызывать синхронизацию CPU↔GPU на каждом шаге. Эта стоимость легко упускается из виду, пока денойзер не скомпилирован. Рекомендуется оставлять `sigmas` на CPU (планировщики Diffusers, такие как Euler, уже делают это).

### Бенчмарки

См. датасет [diffusers/benchmarks](https://huggingface.co/datasets/diffusers/benchmarks), чтобы ознакомиться с данными о задержке инференса и использовании памяти для скомпилированных пайплайнов.

Репозиторий [diffusers-torchao](https://github.com/sayakpaul/diffusers-torchao#benchmarking-results) также содержит результаты бенчмарков для скомпилированных версий Flux и CogVideoX.

## Ядра

[Kernels](https://huggingface.co/docs/kernels/index) — это библиотека для создания, распространения и загрузки оптимизированных вычислительных ядер на [Hub](https://huggingface.co/kernels-community). Она поддерживает ядра [attention](./attention_backends#set-a-backend-on-the-model) и пользовательские CUDA-ядра для операций, таких как RMSNorm, GEGLU, RoPE и AdaLN.

The [Diffusers Pipeline Integration](https://github.com/huggingface/kernels/blob/main/kernel-builder/skills/cuda-kernels/references/diffusers-integration.md) guide shows how to integrate a kernel with the [add cuda-kernels](https://github.com/huggingface/kernels/blob/main/kernel-builder/skills/cuda-kernels/SKILL.md) skill. This skill enables an agent, like Claude or Codex, to write custom kernels targeted towards a specific model and your hardware. The [Custom kernels for all from Codex and Claude](https://huggingface.co/blog/custom-cuda-kernels-agent-skills) post has more detail.

Например, пользовательское ядро RMSNorm (сгенерированное навыком `add cuda-kernels`) в сочетании с [torch.compile](#torchcompile) ускоряет генерацию LTX-Video в 1,43 раза на H100.

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

## Динамическое квантование

Динамическая квантизация активаций int8 доступна в [torchao](../quantization/torchao). Используйте [TorchAoConfig](/docs/diffusers/main/ru/api/quantization#diffusers.TorchAoConfig) с конфигурацией, например [`Int8DynamicActivationInt8WeightConfig`](https://docs.pytorch.org/ao/stable/api_reference/generated/torchao.quantization.Int8DynamicActivationInt8WeightConfig.html), или API `quantize_` из torchao. Не используйте устаревший помощник `apply_dynamic_quant`.

## Сквозные матрицы проекций

> [!WARNING]
> `~DiffusionPipeline.fuse_qkv_projections` является экспериментальным.

Входные данные проецируются в три подпространства, представленные матрицами проекций Q, K и V, в блоке внимания. Обычно эти проекции вычисляются отдельно, но их можно объединить по горизонтали в единую матрицу и выполнить проекцию за один шаг. Это увеличивает размер матричных умножений для входных проекций и также улучшает влияние квантования.

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

## Дальнейшие шаги

- Ознакомьтесь с [статьей в блоге «Presenting Flux Fast: Making Flux go brrr on H100s»](https://pytorch.org/blog/presenting-flux-fast-making-flux-go-brrr-on-h100s/), чтобы узнать, как можно объединить все эти оптимизации с [TorchInductor](https://docs.pytorch.org/docs/stable/torch.compiler.html) и [AOTInductor](https://docs.pytorch.org/docs/stable/torch.compiler_aot_inductor.html) для ускорения примерно в 2,5 раза, используя рецепты из [flux-fast](https://github.com/huggingface/flux-fast).

    Эти рецепты поддерживают оборудование AMD и [Flux.1 Kontext Dev](https://huggingface.co/black-forest-labs/FLUX.1-Kontext-dev).

- Refer to the [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/) blog post for maximizing performance with `torch.compile` for diffusion models.

