Перейти к содержанию
Публикация AiManual

Оптимизация инференса Stable Diffusion на CPU Intel: от 32 до 5 секунд

Ускорьте генерацию изображений Stable Diffusion на CPU Intel Sapphire Rapids с 32,3 до 5,05 секунды. Пошаговый разбор Optimum Intel, OpenVINO, статических форм,

Коротко

Что будет в материале

  1. 01

    Почему Stable Diffusion на CPU - это реально и выгодно

  2. 02

    Базовый уровень: запуск Stable Diffusion на CPU

  3. 03

    Первый шаг ускорения: Optimum Intel и OpenVINO

  4. 04

    Статические формы: дополнительный рывок в 3,5 раза

Генерация изображения Stable Diffusion на одном серверном процессоре Intel Sapphire Rapids занимает 5,05 секунды вместо базовых 32,3 секунды. Это ускорение в 6,5 раза без GPU, достигнутое комбинацией Optimum Intel, OpenVINO, статических форм, системных настроек и Intel Extension for PyTorch с bfloat16 и AMX. Разбираем каждый шаг с цифрами, кодом и ограничениями.

Для разработчиков, которые платят за GPU-инстансы в облаке или не могут получить квоту на A100, CPU-инференс диффузионных моделей перестает быть компромиссом. Современные Xeon с матричными расширениями AMX выдают производительность, достаточную для пакетной генерации, прототипирования и API с умеренным RPS. Экономия на инфраструктуре при этом кратная: CPU-серверы дешевле GPU-аналогов в 3-7 раз в пересчете на час аренды.

Почему Stable Diffusion на CPU - это реально и выгодно

Sapphire Rapids получил Advanced Matrix Extensions (AMX), аппаратные блоки для матричных операций с типами bfloat16 и int8. Они закрывают главный bottleneck диффузионных моделей: свертки и attention-слои, которые на обычных AVX-512 инструкциях выполнялись медленно. OpenVINO и IPEX умеют автоматически маппить эти операции на AMX, что превращает серверный CPU в viable-платформу для генерации изображений.

Итоговые цифры: 32,3 секунды на стандартном PyTorch без оптимизаций, 5,05 секунды после всех шагов. Для сравнения, генерация на потребительской RTX 3060 занимает 2-4 секунды, но стоимость CPU-инстанса в 4-5 раз ниже. Если задача допускает задержку в 5-10 секунд, CPU-инференс экономически оправдан.

Схожий подход мы разбирали для NLP-моделей: ускорение PyTorch-трансформеров на Sapphire Rapids с Optimum Intel дало 60-65% прироста на одиночных предсказаниях. Для Vision Language Models есть отдельный гайд по OpenVINO и квантованию.

Базовый уровень: запуск Stable Diffusion на CPU

Стандартный сценарий выглядит так: Python, PyTorch, библиотеки diffusers и transformers, модель Stable Diffusion 1.5 или 2.1. Запуск на CPU без каких-либо оптимизаций дает около 32 секунд на одно изображение 512x512. Медленно, но это отправная точка для всех дальнейших улучшений.

Необходимые компоненты и окружение

Для воспроизведения базовой среды потребуются:

  • Python 3.10 или 3.11
  • PyTorch 2.0+ с CPU-бэкендом
  • diffusers 0.21+ и transformers 4.30+
  • Модель Stable Diffusion 1.5 или 2.1 в формате safetensors

Проблемы совместимости чаще всего возникают с версиями diffusers: API pipeline менялся между 0.18 и 0.24. Если код из старых туториалов не запускается, проверьте сигнатуру конструктора pipeline и параметры scheduler. Базовая загрузка модели:

from diffusers import StableDiffusionPipeline
import torch

pipe = StableDiffusionPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5",
    torch_dtype=torch.float32
)
pipe = pipe.to("cpu")

image = pipe("a cat sitting on a table", num_inference_steps=50).images[0]

Время инференса в этом режиме - 32,3 секунды. Причины медленной работы: PyTorch использует универсальные ядра без AMX, планировщик потоков не оптимизирован под NUMA-топологию сервера, аллокатор памяти по умолчанию создает фрагментацию при частых выделениях тензоров.

Первый шаг ускорения: Optimum Intel и OpenVINO

Optimum Intel - это обертка Hugging Face над инструментами оптимизации Intel. Для Stable Diffusion она предоставляет класс OVStableDiffusionPipeline, который конвертирует модель в формат OpenVINO IR и запускает инференс через OpenVINO Runtime. Результат: 2-кратное ускорение, время падает с 32,3 до примерно 16 секунд.

Как работает OpenVINO в контексте Stable Diffusion

OpenVINO конвертирует PyTorch-модель в промежуточное представление (IR), оптимизирует граф вычислений и подбирает эффективные примитивы для конкретного CPU. Для UNet, главного вычислительного блока Stable Diffusion, это означает замену стандартных сверток на oneDNN-примитивы, которые используют AVX-512 и, при наличии, AMX. OpenVINO также поддерживает динамические формы, что позволяет менять размер батча без переконвертации.

Код для запуска через Optimum Intel:

from optimum.intel import OVStableDiffusionPipeline

pipe = OVStableDiffusionPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5",
    export=True
)

image = pipe("a cat sitting on a table", num_inference_steps=50).images[0]

При первом запуске модель конвертируется в OpenVINO IR, это занимает 1-2 минуты. Последующие запуски используют кэшированный IR. Время инференса - около 16 секунд. Прирост достигается без изменения кода модели, только за счет смены рантайма.

Статические формы: дополнительный рывок в 3,5 раза

Динамические формы в OpenVINO позволяют менять размер входных тензоров, но вносят накладные расходы на проверку размерностей и перепланировку вычислений. Если размер изображения фиксирован, например 512x512, можно применить статические формы и получить дополнительное ускорение в 3,5 раза. Время падает с 16 до примерно 4,6 секунды.

Когда статические формы применимы

Статические формы работают, когда размеры входных данных постоянны. Для Stable Diffusion это означает фиксированное разрешение генерации и фиксированный размер батча. Если требуется переменный размер, есть два пути: держать несколько моделей с разными статическими формами или использовать динамические формы с меньшей оптимизацией. Для API с предсказуемой нагрузкой статические формы - оптимальный выбор.

Настройка статических форм в OpenVINO выполняется через параметры конвертации:

from optimum.intel import OVStableDiffusionPipeline

pipe = OVStableDiffusionPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5",
    export=True,
    compile=False
)

# Фиксируем размеры для UNet
pipe.unet.reshape(batch_size=1, height=512, width=512)
pipe.unet.compile()

После фиксации размеров OpenVINO генерирует специализированный код без проверок на лету. Это дает основной прирост на этапе статических форм.

Системные оптимизации: jemalloc, libiomp, numactl

Без изменения кода модели можно получить почти 3-кратный прирост за счет настройки окружения. Три инструмента: jemalloc, libiomp и numactl. В комбинации с предыдущими шагами время снижается до 1,7 секунды.

jemalloc - альтернативный аллокатор памяти, который уменьшает фрагментацию при частых выделениях и освобождениях небольших блоков. Для диффузионных моделей, где на каждом шаге создаются и удаляются десятки тензоров, это критично. libiomp - библиотека OpenMP от Intel, которая эффективнее стандартной GNU OpenMP распределяет потоки по ядрам. numactl управляет привязкой процессов к ядрам и памяти NUMA, предотвращая дорогие удаленные обращения к памяти.

Пример команды запуска с системными оптимизациями

LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so \
OMP_NUM_THREADS=16 \
numactl --cpunodebind=0 --membind=0 \
python script.py

Эта команда загружает jemalloc вместо стандартного аллокатора, ограничивает число потоков OpenMP до 16 и привязывает процесс к первому NUMA-узлу. На двухсокетных серверах привязка к одному узлу особенно важна: обращение к памяти соседнего сокета добавляет 40-60% задержки.

Отдельный случай - CPU-only движки для LLM. Проект Project Zero на чистом C99 показывает, как системный подход к памяти и потокам дает 36 токенов/с на Xeon без каких-либо внешних библиотек.

Intel Extension for PyTorch (IPEX): bfloat16 и AMX

IPEX - расширение PyTorch, оптимизированное под процессоры Intel. Оно автоматически использует bfloat16 для вычислений и AMX для матричных операций. В комбинации с предыдущими методами достигается итоговое время 5,05 секунды.

bfloat16 - 16-битный формат с плавающей запятой, который сохраняет динамический диапазон float32, но теряет точность мантиссы. Для диффузионных моделей потеря качества изображения минимальна, а скорость вычислений на AMX вырастает кратно. IPEX применяет bfloat16 автоматически через ipex.optimize.

Что такое AMX и почему это важно

AMX (Advanced Matrix Extensions) - набор инструкций в Sapphire Rapids для ускорения матричных операций, ключевых для нейросетей. В отличие от AVX-512, который оперирует векторами, AMX работает с тайловыми регистрами 16x16 и выполняет матричные умножения за одну инструкцию. IPEX задействует AMX автоматически при наличии процессора с поддержкой.

Пример кода с IPEX:

import intel_extension_for_pytorch as ipex
from diffusers import StableDiffusionPipeline
import torch

pipe = StableDiffusionPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5",
    torch_dtype=torch.bfloat16
)
pipe = pipe.to("cpu")

pipe.unet = ipex.optimize(pipe.unet, dtype=torch.bfloat16)
pipe.vae = ipex.optimize(pipe.vae, dtype=torch.bfloat16)

image = pipe("a cat sitting on a table", num_inference_steps=50).images[0]

IPEX также включает оптимизированный планировщик потоков и улучшенные ядра для сверток. При использовании IPEX без OpenVINO время составляет около 8-10 секунд, в комбинации с OpenVINO и системными настройками - 5,05 секунды.

Сравнение всех методов и итоговые результаты

Сводная таблица по шагам оптимизации:

МетодВремя инференсаУскорение
Базовый PyTorch на CPU32,3 с1x
+ Optimum Intel и OpenVINO16,0 с2x
+ Статические формы4,6 с7x
+ Системные оптимизации1,7 с19x
+ IPEX с bfloat16 и AMX5,05 с6,4x

Цифры требуют пояснения. Время 1,7 секунды достигнуто при комбинации OpenVINO, статических форм и системных оптимизаций. Итоговые 5,05 секунды - это комбинация всех методов, включая IPEX, но с несколько иной конфигурацией. Разница объясняется тем, что IPEX и OpenVINO конкурируют за ресурсы и не всегда дают аддитивный эффект. Наибольший прирост дают статические формы и системные оптимизации, они же требуют минимальных изменений кода.

Для практического выбора: если нужен быстрый результат с минимальными усилиями - Optimum Intel с OpenVINO. Если нужна максимальная скорость - добавляйте статические формы и системные настройки. IPEX имеет смысл, когда вы остаетесь в экосистеме PyTorch и не хотите конвертировать модель в OpenVINO IR.

Похожая логика оптимизации применима и к другим моделям. В разборе DeepSeek-V4-Flash на одном B300 видно, как выбор конфигурации влияет на итоговую производительность даже на топовом железе.

Ограничения и подводные камни

Результаты специфичны для архитектуры Sapphire Rapids. На Ice Lake или AMD EPYC прирост будет меньше, так как AMX отсутствует. Проверяйте поддержку инструкций через lscpu перед внедрением.

Версии библиотек критичны. Optimum Intel 1.8 и OpenVINO 2023.1 дают один результат, Optimum Intel 1.12 и OpenVINO 2024.0 - другой. Фиксируйте версии в requirements.txt и тестируйте после каждого обновления.

bfloat16 снижает точность вычислений. Для большинства промптов разница в качестве изображения незаметна, но на сложных сценах с мелкими деталями могут появляться артефакты. Если качество критично, используйте float32 с OpenVINO без IPEX.

Большие батчи упираются в пропускную способность памяти. При батче 4 и выше прирост от оптимизаций снижается, так как модель упирается в DRAM, а не в compute. Это та же ловушка, что описана в разборе иллюзии оптимизации CPU-инференса: изолированное ускорение ядра не всегда транслируется в end-to-end прирост.

Заключение: CPU как viable option для Stable Diffusion

Комбинация Optimum Intel, OpenVINO, статических форм, системных оптимизаций и IPEX сокращает время генерации с 32,3 до 5,05 секунды на одном CPU Intel Sapphire Rapids. Для многих сценариев этого достаточно: прототипирование, пакетная генерация, API с умеренной нагрузкой.

Начните с Optimum Intel и OpenVINO, это 2-кратное ускорение за 10 минут работы. Добавьте статические формы, если размер изображений фиксирован. Настройте jemalloc и numactl, если сервер многосокетный. IPEX используйте, когда остаетесь в PyTorch и нужен bfloat16. Тестируйте каждую оптимизацию отдельно и замеряйте end-to-end время, а не только время отдельных слоев.

Подписаться на канал