Что такое ONNX Runtime и когда он выгоден для LLM?
Краткий тезис
ONNX Runtime (ORT) — это кроссплатформенный движок инференса для моделей в формате ONNX. Он оптимизирует выполнение за счёт слияния операций (graph fusion), квантизации и аппаратно-зависимых бэкендов. Для LLM ORT выгоден в сценариях гибридного CPU/GPU деплоя, на edge-устройствах и при необходимости низкой задержки на разнородном железе. Однако для чистого GPU с высокой пропускной способностью (batch inference) ORT уступает специализированным решениям вроде vLLM или TensorRT-LLM.
1. Термин: ONNX Runtime (ORT)
ONNX Runtime — это высокопроизводительный движок для запуска моделей машинного обучения, представленных в формате Open Neural Network Exchange (ONNX). ONNX — открытый стандарт для представления моделей, поддерживаемый Microsoft, Facebook, AWS и другими. ORT может работать на CPU, GPU (CUDA, ROCm, DirectML), NPU и мобильных процессорах.
Ключевые возможности ORT
- Оптимизация графа вычислений — retrieval|автоматическое слияние операций, удаление лишних узлов, перестановка для лучшей локализации данных.
- Квантизация — снижение точности весов (INT8, FP16) для ускорения и уменьшения памяти.
- Исполнение через аппаратные бэкенды — CUDA Execution Provider для NVIDIA GPU, DirectML для Windows, OpenVINO для Intel, TensorRT для NVIDIA.
- Кроссплатформенность — Windows, Linux, macOS, Android, iOS, WebAssembly.
Для LLM ORT поддерживает модели трансформеров через интеграцию с HuggingFace Optimum и специальный пакет onnxruntime-genai, который добавляет оптимизации для генерации текста (кэширование KV, beam search).
2. Формат ONNX и его преимущества
ONNX — это промежуточное представление модели (IR), которое отделяет архитектуру от фреймворка обучения. Модель из PyTorch, TensorFlow или JAX экспортируется в ONNX-граф, после чего ORT может выполнять его на любом поддерживаемом бэкенде.
Преимущества для LLM
- Переносимость — одна модель работает на CPU, GPU, NPU без переписывания кода.
- Оптимизация графа — ORT применяет десятки пассов (например, слияние слоёв attention, удаление лишних transpose), которые могут ускорить инференс на 20–50% по сравнению с наивным запуском.
- Квантизация — ORT поддерживает Dynamic Quantization (квантизация весов на лету) и Static Quantization (с калибровочным датасетом). Для LLM часто используют INT8 квантизацию, снижающую размер модели в 2 раза при минимальной потере качества.
Пример экспорта модели GPT-2 в ONNX:
from transformers import GPT2Model, GPT2Tokenizer
import torch
model = GPT2Model.from_pretrained("gpt2")
dummy_input = torch.randint(0, 1000, (1, 128)) # batch=1, seq_len=128
torch.onnx.export(
model,
dummy_input,
"gpt2.onnx",
input_names=["input_ids"],
output_names=["last_hidden_state"],
dynamic_axes={"input_ids": {0: "batch", 1: "seq"}},
opset_version=17
)
3. Оптимизация графа (Graph Optimization)
ORT автоматически применяет ряд оптимизаций к ONNX-графу:
| Оптимизация | Описание | Влияние на LLM |
|---|---|---|
| Fusion | Слияние последовательных операций (например, MatMul + Add + ReLU → единый узел) | Уменьшает число вызовов ядер, снижает latency |
| Constant Folding | Вычисление константных подграфов на этапе загрузки | Ускоряет первый проход (warm-up) |
| Layout Optimization | Перестановка тензоров для лучшего использования кэша | До 10% ускорения на CPU |
| Memory Pattern | Переиспользование буферов для промежуточных результатов | Снижает пиковое потребление памяти |
Для LLM особенно важна оптимизация attention: ORT может заменить стандартный attention на FlashAttention (если бэкенд поддерживает) или слить операции QKV.
4. Квантизация в ORT
ORT поддерживает два подхода к квантизации:
- Dynamic Quantization — веса квантизуются в INT8 при загрузке, активации остаются в FP32. Простота, но меньший прирост скорости.
- Static Quantization — требует калибровочного датасета для подбора диапазонов активаций. Даёт лучшее ускорение (до 2x на CPU).
Пример квантизации модели через Optimum
from optimum.onnxruntime import ORTQuantizer
from optimum.onnxruntime.configuration import AutoQuantizationConfig
quantizer = ORTQuantizer.from_pretrained("gpt2-onnx")
dqconfig = AutoQuantizationConfig.avx512_vnni(is_static=False)
quantizer.quantize(save_dir="gpt2-quantized", quantization_config=dqconfig)
Влияние на LLM INT8 квантизация снижает размер модели с 7B до ~3.5GB (для FP16 → INT8), что позволяет запускать LLM на устройствах с ограниченной памятью. На CPU ускорение может достигать 2–3x, на GPU — 1.2–1.5x.
5. Кроссплатформенность и аппаратные бэкенды
ORT поддерживает множество Execution Providers (EP):
| EP | Аппаратура | Особенности для LLM |
|---|---|---|
| CUDA | NVIDIA GPU | Использует cuBLAS, Tensor Cores. Поддерживает FP16, INT8 |
| TensorRT | NVIDIA GPU | Дополнительная оптимизация через TensorRT (слияние слоёв, kernel auto-tuning) |
| DirectML | Windows GPU (AMD, Intel, NVIDIA) | Работает через DirectX 12, подходит для игровых карт |
| OpenVINO | Intel CPU, GPU, NPU | Оптимизирован для Intel, поддерживает INT8 |
| CoreML | Apple Neural Engine | Для iOS/macOS |
| XNNPACK | ARM CPU (Android, iOS) | Использует NEON-инструкции |
Выгода для LLM одна и та же ONNX-модель может работать на сервере с NVIDIA GPU (CUDA EP), на ноутбуке с Intel CPU (OpenVINO EP) и на смартфоне (CoreML EP) — без переобучения.
6. Сравнение ORT с другими runtime
| Характеристика | ONNX Runtime | vLLM | TensorRT-LLM | PyTorch eager |
|---|---|---|---|---|
| Основной фокус | Кроссплатформенность | Высокая пропускная способность GPU | Максимальная производительность NVIDIA GPU | Гибкость разработки |
| Поддержка LLM | Через Optimum/onnxruntime-genai | Нативная (PagedAttention, continuous batching) | Нативная (in-flight batching, FP8) | Прямой запуск |
| Квантизация | INT8, FP16, (INT4 экспериментально) | INT8, FP8, AWQ, GPTQ | INT4, INT8, FP8 | Через torch.quantization |
| Кроссплатформенность | Отличная (CPU, GPU, NPU, mobile) | Только NVIDIA GPU | Только NVIDIA GPU | Зависит от бэкенда |
| Производительность (pure GPU) | Хорошая, но уступает vLLM при batch > 1 | Лучшая для throughput | Лучшая для latency на NVIDIA | Базовая |
| Простота деплоя | Средняя (нужен экспорт в ONNX) | Высокая (pip install + запуск) | Низкая (сборка, настройка) | Высокая |
Вывод ORT — универсальный инструмент, но не лучший для специализированных сценариев.
7. Когда ORT выгоден для LLM
7.1 Гибридный CPU/GPU деплой
Если часть запросов обрабатывается на CPU (например, при перегрузке GPU), ORT позволяет без переключения модели запускать инференс на обоих устройствах. Это полезно для agentic RAG, где агенты могут динамически выбирать ресурсы.
7.2 Edge-устройства и мобильные платформы
ORT с бэкендами XNNPACK, CoreML, OpenVINO позволяет запускать LLM на Raspberry Pi, iPhone или Intel NUC. Например, Microsoft Phi-3-mini (3.8B) в ONNX формате работает на CPU с задержкой < 1 сек на токен.
7.3 Мультиплатформенная поставка
Если продукт должен работать на Windows, Linux, macOS и Android — ORT единый runtime для всех платформ.
7.4 Сценарии с низкой latency (single request)
Для одного запроса (batch=1) ORT на GPU может быть быстрее vLLM, так как не требует накладных расходов на continuous batching. Это актуально для real-time агентов.
7.5 Интеграция с существующей инфраструктурой
Многие компании уже используют ONNX для других моделей (CV, NLP). Добавление LLM в тот же пайплайн упрощает поддержку.
8. Когда ORT невыгоден для LLM
- Pure GPU с высокой пропускной способностью — vLLM или TensorRT-LLM дают в 2–5 раз больше токенов в секунду за счёт PagedAttention и continuous batching.
- Очень большие модели (70B+) — ORT не поддерживает тензорный параллелизм (TP) и pipeline parallelism из коробки. Для таких моделей нужны специализированные системы (vLLM с TP, DeepSpeed).
- Сложные сэмплинг-стратегии — ORT не поддерживает top-k, top-p, temperature напрямую; требуется обёртка на Python, что добавляет latency.
- Динамические графы — ORT оптимизирует статический граф. Если модель меняет структуру (например, branching), производительность падает.
9. Интеграция с HuggingFace Optimum и onnxruntime-genai
Optimum — библиотека для экспорта и оптимизации моделей HuggingFace в ONNX. Позволяет одним вызовом export() получить ONNX-модель.
onnxruntime-genai — расширение ORT для генеративных моделей. Добавляет:
- Кэширование KV-кэша.
- Поддержку beam search и greedy decoding.
- Оптимизированные ядра для attention.
Пример запуска LLM через onnxruntime-genai
import onnxruntime_genai as og
model = og.Model("phi-3-mini-onnx")
tokenizer = og.Tokenizer(model)
prompt = "What is ONNX Runtime?"
input_ids = tokenizer.encode(prompt)
params = og.GeneratorParams(model)
params.set_search_options(max_length=200)
params.input_ids = input_ids
generator = og.Generator(model, params)
while not generator.is_done():
generator.compute_logits()
generator.generate_next_token()
output = generator.get_sequence(0)
print(tokenizer.decode(output))
10. Практические рекомендации
| Сценарий | Рекомендуемый runtime |
|---|---|
| Сервер NVIDIA GPU, batch > 1 | vLLM или TensorRT-LLM |
| Гибрид CPU/GPU, edge, mobile | ONNX Runtime |
| Прототипирование, быстрое тестирование | PyTorch eager |
| Мультиплатформенный продукт | ONNX Runtime |
| Максимальная latency на одном запросе | ONNX Runtime (GPU) или TensorRT-LLM |
Пет-проект для закрепления
Задача Развернуть небольшую LLM (например, Phi-3-mini) на CPU с помощью ONNX Runtime и сравнить latency с PyTorch.
Инструменты
- Python, HuggingFace Transformers, Optimum, ONNX Runtime, onnxruntime-genai.
- Модель:
microsoft/Phi-3-mini-4k-instruct. - Метрики: время генерации 100 токенов, пиковое использование памяти.
Шаги:
- Экспортировать модель в ONNX через Optimum:
optimum-cli export onnx --model microsoft/Phi-3-mini-4k-instruct phi-3-onnx - Запустить инференс через PyTorch (baseline):
- Замерить время генерации 100 токенов с
generate().
- Замерить время генерации 100 токенов с
- Запустить инференс через ONNX Runtime (onnxruntime-genai):
- Использовать код из раздела 9.
- Применить INT8 квантизацию (Dynamic Quantization) и повторить замеры.
- Построить таблицу сравнения:
Ожидаемый результат Ускорение в 2–2.5x на CPU при квантизации, снижение памяти вдвое. Понимание trade-off между точностью и скоростью.
Связь с другими вопросами
| Вопрос | Тема |
|---|---|
| 318 | Что такое vLLM и как он ускоряет инференс LLM? |
| 319 | TensorRT-LLM: особенности и сравнение с vLLM |
| 321 | Методы квантизации LLM (GPTQ, AWQ, GGUF) |
| 322 | Дистилляция знаний для LLM |
| 323 | Прунинг (pruning) моделей: когда оправдан? |
| 317 | Развёртывание LLM на edge-устройствах |
Навигация
- Предыдущий: 319
- Следующий: 321
- Индекс: 00. Индекс разборов