Buckets:

mishig's picture
|
download
raw
19.4 kB

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

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

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

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

bfloat16 похож на float16, но более устойчив к численным ошибкам. Поддержка bfloat16 на уровне аппаратного обеспечения различается, однако большинство современных GPU способны работать с bfloat16.

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, но более подвержен численным ошибкам.

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 (tf32) поддерживается на GPU NVIDIA Ampere и новее. Он выполняет операции свёртки и матричного умножения в формате tf32. Хранение данных и остальные операции остаются в формате float32. Это ускоряет операции, выполняемые в float32, поэтому режим наиболее полезен, когда конвейер или его часть работают в float32.

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

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]

См. документацию по обучению с смешанной точностью для получения дополнительных сведений.

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

Scaled dot product attention (SDPA) является механизмом внимания по умолчанию в PyTorch 2.0 и более поздних версиях, через AttnProcessor2_0 или native бэкенд диспетчера внимания. PyTorch выбирает ядро SDPA для вашего оборудования. О FlashAttention, SageAttention, xFormers, Hub-ядрах и других бэкендах см. Attention backends.

torch.compile

torch.compile ускоряет инференс, компилируя код и операции PyTorch в оптимизированные ядра. Обычно компилируют денуизер, который определяет время выполнения, — pipeline.unet или pipeline.transformer, а иногда и VAE.

Включите следующие настройки компилятора для максимальной скорости (см. полный список для других вариантов).

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 также может ускорить модели с преобладанием свёрток, такие как UNet и VAE. Сначала проведите бенчмаркинг, так как некоторые модели работают медленнее.

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", поскольку компилятор ищет ядра, а затем продолжает использовать тот же объект скомпилированного конвейера (см. Кэширование времени компиляции и Конфигурация кэширования, чтобы настроить поведение кэширования). Вызов скомпилированного конвейера с другим размером изображения запускает повторную компиляцию.

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

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

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

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

Указание use_duck_shape=False сообщает компилятору, следует ли использовать одну и ту же символьную переменную для представления входных размеров, которые совпадают. Подробнее см. в этом комментарии.

Не все модели могут получать преимущества от динамической компиляции «из коробки» и могут требовать изменений. См. этот PR, в котором была улучшена реализация AuraFlowPipeline для использования преимуществ динамической компиляции.

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

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

Региональная компиляция сокращает задержку холодного запуска, компилируя только небольшие и часто повторяющиеся блоки модели — как правило, слой трансформера — и позволяет переиспользовать скомпилированные артефакты для каждого последующего вхождения. Для многих архитектур диффузии это обеспечивает сопоставимое с компиляцией всего графа ускорение времени выполнения и может сократить время компиляции в 8–10 раз.

Используйте метод compile_repeated_blocks() — вспомогательный, который оборачивает torch.compile — для денойзера. Вызывайте его на pipeline.unet или pipeline.transformer в зависимости от пайплайна.

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. Трансформерные денойзеры указывают имена классов своих повторяющихся блоков аналогичным образом.

_repeated_blocks = ["BasicTransformerBlock"]

В Accelerate также есть метод compile_regions, который автоматически выбирает блоки модели для компиляции. Остальная часть графа компилируется отдельно. Это удобно для быстрых экспериментов, так как вам не нужно настраивать, какие именно блоки компилировать, или подбирать флаги компиляции.

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() намеренно явен. Перечислите блоки, подлежащие повторению, в _repeated_blocks, и вспомогательная функция скомпилирует только эти блоки. Это обеспечивает предсказуемое поведение и позволяет легко рассуждать о повторном использовании кэша в одной строке кода.

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

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

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

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

Бенчмарки

См. датасет diffusers/benchmarks, чтобы ознакомиться с данными о задержке инференса и использовании памяти для скомпилированных пайплайнов.

Репозиторий diffusers-torchao также содержит результаты бенчмарков для скомпилированных версий Flux и CogVideoX.

Ядра

Kernels — это библиотека для создания, распространения и загрузки оптимизированных вычислительных ядер на Hub. Она поддерживает ядра attention и пользовательские CUDA-ядра для операций, таких как RMSNorm, GEGLU, RoPE и AdaLN.

The Diffusers Pipeline Integration guide shows how to integrate a kernel with the add cuda-kernels 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 post has more detail.

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

Xet Storage Details

Size:
19.4 kB
·
Xet hash:
4c719bd0b8dde33008200194882f71d0c3a000a6ed328898413bb58e634a3507

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.