Stable Diffusion ONNX: полное руководство по конвертации и запуску моделей

Ошибка вида «model.onnx failed to load» или падение скорости генерации после перевода Stable Diffusion в формат ONNX почти всегда указывает на несовпадение версии ONNX Runtime, неверно выбранный execution provider или конвертацию с неподходящим opset. Прежде чем переустанавливать всё подряд, проверьте, каким именно способом модель была сконвертирована и какой бэкенд используется для инференса.

Формат ONNX (Open Neural Network Exchange) — это открытый стандарт представления нейросетей, который позволяет запускать Stable Diffusion вне привычной связки PyTorch + diffusers. Модель, переведённая в ONNX, работает через ONNX Runtime и может использовать аппаратное ускорение DirectML на Windows, CUDA на видеокартах NVIDIA, а также оптимизации под CPU. Ниже разберём, как устроен пайплайн, как корректно конвертировать веса и какие типичные проблемы возникают при запуске.

Что такое ONNX-версия Stable Diffusion и зачем она нужна

Оригинальная модель Stable Diffusion распространяется в форматах .ckpt или .safetensors и запускается через PyTorch. ONNX-версия — это та же нейросеть, экспортированная в промежуточное представление графа вычислений, которое не привязано к конкретному фреймворку.

Ключевой нюанс: Stable Diffusion — это не одна модель, а конвейер из нескольких компонентов. При конвертации в ONNX каждый из них экспортируется отдельно:

  • 📝 Text Encoder (CLIP) — преобразует текстовый промпт в эмбеддинги;
  • 🎨 UNet — основная диффузионная сеть, выполняющая шаги денойзинга;
  • 🖼️ VAE Decoder — декодирует латентное представление в итоговое изображение;
  • 🔒 VAE Encoder — нужен для режимов img2img и inpainting;
  • 🛡️ Safety Checker — опциональный фильтр контента (часто исключается).

Практическая выгода перехода на ONNX — кроссплатформенность и оптимизация инференса. ONNX Runtime умеет применять графовые оптимизации, квантование и специализированные ядра под конкретное железо. На системах без CUDA-совместимой видеокарты это зачастую единственный способ получить приемлемую скорость генерации.

Как конвертировать модель в ONNX

Самый распространённый способ — экспорт из библиотеки diffusers от Hugging Face. В ней предусмотрены механизмы сохранения пайплайна в ONNX-представление. Общий порядок действий выглядит так: загружается исходный чекпоинт, затем пайплайн сохраняется с указанием формата ONNX, после чего рядом с каждым компонентом появляется файл model.onnx.

from diffusers import StableDiffusionPipeline

pipeline = StableDiffusionPipeline.from_pretrained(

"runwayml/stable-diffusion-v1-5"

)

pipeline.save_pretrained("./sd-onnx", export=True)

Точные имена параметров и поддерживаемые опции зависят от версии библиотеки, поэтому перед конвертацией сверьтесь с документацией установленной у вас версии diffusers и пакета optimum, который отвечает за ONNX-экспорт. Несовместимость версий — частая причина ошибок вида «unsupported operator» на этапе экспорта.

☑️ Проверка перед конвертацией

Выполнено: 0 / 4
⚠️ Внимание: конвертация UNet — ресурсоёмкий процесс, который может потребовать значительного объёма оперативной памяти. На системах с малым объёмом RAM экспорт может завершаться ошибкой нехватки памяти. Закройте лишние приложения и, при необходимости, увеличьте файл подкачки перед запуском.

Запуск через ONNX Runtime: выбор execution provider

Execution provider — это бэкенд, который исполняет вычисления графа. От его выбора напрямую зависит скорость генерации. Основные варианты:

  • 🟢 CUDAExecutionProvider — для видеокарт NVIDIA; требует установленных CUDA и cuDNN совместимых версий;
  • 🔵 DmlExecutionProvider — DirectML для Windows, работает на GPU AMD, Intel и NVIDIA;
  • CPUExecutionProvider — универсальный вариант без GPU-ускорения, самый медленный.

Если провайдер недоступен (например, не установлены нужные библиотеки CUDA), ONNX Runtime молча или с предупреждением откатывается на CPU. Проверить доступные провайдеры можно одной командой:

import onnxruntime as ort

print(ort.get_available_providers())

📊 На каком железе вы запускаете Stable Diffusion ONNX?
NVIDIA GPU (CUDA)
AMD/Intel GPU (DirectML)
Только CPU
Облачный сервер

В библиотеке optimum есть готовые классы вида ORTStableDiffusionPipeline, которые берут на себя создание сессий ONNX Runtime для всех компонентов пайплайна. Это заметно упрощает код по сравнению с ручным управлением сессиями.

Сравнение форматов и бэкендов

Выбор между PyTorch-оригиналом и ONNX-версией зависит от задачи. Ориентировочное сравнение приведено ниже:

КритерийPyTorch (ckpt/safetensors)ONNX + CUDAONNX + DirectML
Совместимость железаЛюбое, где есть PyTorchТолько NVIDIAЛюбой GPU с DirectX 12
Оптимизации графаОграниченныеДа, через ORTДа, через ORT
Поддержка кастомных моделейШирокая (LoRA, ControlNet)Требует конвертацииТребует конвертации
Простота установкиСредняяЗависит от версий CUDAСравнительно простая на Windows

Обратите внимание: точные цифры производительности сильно зависят от конкретной видеокарты, разрешения генерации, числа шагов и применённых оптимизаций, поэтому универсальных значений «ускорения в N раз» не существует. Сравнивать стоит на своём железе и своих типовых параметрах генерации.

Типичные ошибки и их диагностика

Большинство проблем с ONNX-моделями Stable Diffusion сводится к нескольким повторяющимся сценариям. Начинать диагностику стоит с текста ошибки — он почти всегда указывает на этап, где произошёл сбой.

Ошибки загрузки графа («invalid model», «unsupported opset») означают, что модель экспортирована с версией opset, которую не понимает установленный ONNX Runtime. Решение — обновить onnxruntime до актуальной версии или переконвертировать модель с совместимым opset.

Падение по памяти (out of memory) при загрузке UNet указывает на нехватку видеопамяти. Возможные меры без потери качества результата: снизить разрешение генерации, использовать оптимизированные сессии с float16-весами, если они предусмотрены вашим пайплайном.

⚠️ Внимание: квантование и перевод весов в float16 уменьшают потребление памяти, но могут заметно изменить детализацию и цветопередачу итогового изображения. Перед массовой генерацией сравните результат с полновесной версией на одном и том же сиде и промпте.

Чёрный или пустой результат при корректной работе кода чаще связан не с ONNX, а с параметрами: слишком высокий guidance scale, несовместимый шедулер или повреждённый VAE. Проверьте генерацию на минимальном наборе параметров, чтобы локализовать источник.

Как проверить целостность ONNX-файла

Используйте onnx.checker.check_model("model.onnx") — функция валидирует структуру графа без запуска инференса. Если проверка проходит, а генерация всё равно падает, проблема в провайдере или параметрах, а не в файле модели.

Оптимизация скорости генерации

После того как модель стабильно запускается, имеет смысл заняться производительностью. Основные рычаги:

  • ⚡ Включение графовых оптимизаций при создании сессии (уровень оптимизации задаётся в настройках сессии ONNX Runtime);
  • 🧮 Экспорт или конвертация весов в float16 для GPU-инференса;
  • 📉 Уменьшение числа шагов диффузии в связке с подходящим шедулером;
  • 🧷 Фиксация размеров входных тензоров при экспорте, чтобы избежать лишних перекомпиляций графа.

Отдельно стоит упомянуть режимы оптимизации под конкретные GPU-архитектуры, которые предоставляет ONNX Runtime для CUDA и DirectML: их включение и эффект зависят от версии рантайма и драйверов, поэтому проверяйте актуальную документацию под вашу связку железа и ПО.

Ограничения ONNX-формата для Stable Diffusion

Главное ограничение — экосистема. Огромное количество community-расширений (LoRA, ControlNet, кастомные сэмплеры) разрабатывается в первую очередь под PyTorch и Automatic1111/ComfyUI. Для ONNX-пайплайна каждую такую надстройку придётся либо конвертировать отдельно, либо искать готовую ONNX-версию.

Второй момент — динамика размеров. Если модель экспортирована под фиксированное разрешение, генерация в других размерах потребует либо повторного экспорта, либо экспорта с динамическими осями, что усложняет процесс и не всегда поддерживается всеми провайдерами одинаково хорошо.

Часто задаваемые вопросы

Можно ли конвертировать любой чекпоинт с Civitai в ONNX?

Технически большинство чекпоинтов на базе SD 1.5 или SDXL конвертируются стандартным способом через diffusers, если они загружаются как обычный пайплайн. Модели с нестандартной архитектурой или встроенными расширениями могут потребовать ручной доработки экспорта.

Что быстрее: ONNX Runtime или PyTorch с xFormers?

Однозначного ответа нет — результат зависит от видеокарты, версий библиотек и параметров генерации. Корректный способ узнать — замерить оба варианта на своём железе с одинаковыми настройками.

Работает ли ONNX-версия Stable Diffusion на CPU?

Да, через CPUExecutionProvider, но скорость генерации будет существенно ниже, чем на GPU. Для CPU-инференса имеет смысл снижать разрешение и число шагов, а также рассмотреть квантованные варианты модели.

Почему после конвертации картинка отличается от PyTorch-версии?

Небольшие расхождения возможны из-за различий в реализации операторов, округления при float16 и отличий в шедулере. Если результат меняется кардинально — проверяйте соответствие шедулера, сида и параметров guidance.

Нужно ли конвертировать Safety Checker?

Нет, этот компонент опционален. Большинство локальных пайплайнов работают без него, и его исключение немного упрощает и ускоряет инференс.