ПОЧЕМУ ИНФЕРЕНС ВНЕЗАПНО СТАЛ ГЛАВНОЙ СТАТЬЁЙ РАСХОДОВ
Тренировка — разовое событие. Инференс крутится 24/7 и платит за себя каждым запросом. К 2026 году у большинства команд косты сместились именно в сторону serving: модель уже обучена или взята готовой, а дальше вопрос — сколько токенов в секунду вы выжимаете из арендованной H100 за 2–3 доллара в час.
Разница между наивным model.generate() в чистом PyTorch и грамотно собранным пайплайном на TensorRT или vLLM — это не 10–20%. Это разы. По замерам сообщества continuous batching в vLLM даёт кратный рост пропускной способности против статического батчинга, а TensorRT на трансформерах-энкодерах регулярно срезает латентность в 2–5 раз относительно eager-режима. Игнорировать оптимизацию — значит переплачивать за железо в разы. Свежие релизы инструментов и движков отслеживаются в каталоге REDDYX.
ONNX: УНИВЕРСАЛЬНЫЙ ПЕРЕХОДНИК
ONNX (Open Neural Network Exchange) — это формат-контракт. Вы обучили модель в PyTorch, а гоните её в C#-бэкенде, на мобилке или на CPU-only-сервере — ONNX разрывает связку «фреймворк тренировки = фреймворк рантайма».
Где ONNX Runtime реально выигрывает
- CPU и edge. Для классических моделей, эмбеддеров, небольших энкодеров ORT на CPU часто быстрее и легче, чем тащить весь PyTorch.
- Провайдеры исполнения. Один и тот же
.onnxзапускается через CPUExecutionProvider, CUDA, TensorRT, OpenVINO, DirectML — код почти не меняется. - Кроссязычность. Python, C++, C#, Java, JS/WASM в браузере.
Базовый экспорт и запуск выглядят так:
import torch, onnxruntime as ort
import numpy as np
# экспорт из PyTorch
dummy = torch.randn(1, 3, 224, 224)
torch.onnx.export(
model, dummy, "model.onnx",
input_names=["input"], output_names=["logits"],
dynamic_axes={"input": {0: "batch"}, "logits": {0: "batch"}},
opset_version=18,
)
# инференс через ORT с приоритетом TensorRT -> CUDA -> CPU
sess = ort.InferenceSession(
"model.onnx",
providers=["TensorrtExecutionProvider", "CUDAExecutionProvider", "CPUExecutionProvider"],
)
out = sess.run(None, {"input": np.random.randn(8, 3, 224, 224).astype(np.float32)})
print(out[0].shape)
Ключевой момент — dynamic_axes. Без него граф зафиксирует batch=1, и вы упрётесь в стену при батчинге. Прописывайте динамику по batch и sequence сразу.
TENSORRT: КОГДА НУЖНА МИНИМАЛЬНАЯ ЛАТЕНЦИЯ НА GPU
TensorRT — движок NVIDIA, который берёт граф и перекомпилирует его под конкретную архитектуру GPU: сливает слои (layer fusion), подбирает оптимальные ядра под ваши размерности (kernel auto-tuning), выкидывает лишние транспозиции. Результат — «плоский» оптимизированный engine, заточенный под одну карту.
Сильные и слабые стороны
- Плюс: лучшая латентность на одиночных и малых батчах, отличная поддержка FP16/INT8/FP8 на Ada и Hopper.
- Плюс: для генеративных LLM есть TensorRT-LLM с in-flight batching и paged KV-cache.
- Минус: engine привязан к архитектуре GPU и часто к версии — собранное под H100 не переедет на A100 без пересборки.
- Минус: сборка долгая (минуты), а INT8 требует калибровки на репрезентативных данных.
Практичный путь в 2026 — не писать TensorRT руками, а собирать engine из ONNX через trtexec:
# сборка FP16-движка из ONNX с динамическим батчем
trtexec \
--onnx=model.onnx \
--saveEngine=model_fp16.engine \
--fp16 \
--minShapes=input:1x3x224x224 \
--optShapes=input:8x3x224x224 \
--maxShapes=input:32x3x224x224 \
--builderOptimizationLevel=5
Указывайте три профиля shape — min/opt/max. Движок оптимизируется именно под optShapes, поэтому ставьте туда самый частый рабочий батч.
vLLM: THROUGHPUT-МАШИНА ДЛЯ LLM
Если задача — обслуживать большую языковую модель множеству пользователей, TensorRT-LLM и vLLM решают одну боль: KV-cache и батчинг. vLLM сделал это первым и остаётся дефолтным выбором за счёт двух идей.
PagedAttention
Классический KV-cache требует непрерывный кусок памяти под каждый запрос и резервирует его по максимальной длине — отсюда огромная фрагментация и простой памяти. PagedAttention хранит KV страницами, как виртуальная память в ОС. Итог — фрагментация падает до единиц процентов, а в тот же объём VRAM влезает заметно больше одновременных запросов.
Continuous batching
Вместо ожидания, пока весь батч добежит до конца генерации, vLLM подкидывает новые запросы на каждом шаге декодирования. GPU не простаивает между разной длиной ответов — отсюда кратный рост токенов в секунду под нагрузкой.
Поднять OpenAI-совместимый сервер — одна команда:
# запуск сервера vLLM с квантизацией и тензорным параллелизмом
python -m vllm.entrypoints.openai.api_server \
--model meta-llama/Llama-3.1-8B-Instruct \
--quantization awq \
--tensor-parallel-size 2 \
--max-model-len 8192 \
--gpu-memory-utilization 0.90
# запрос как к OpenAI
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"meta-llama/Llama-3.1-8B-Instruct",
"messages":[{"role":"user","content":"Объясни PagedAttention в двух предложениях"}]}'
Крутите --gpu-memory-utilization вверх, пока не начнёте ловить OOM — чем больше памяти под KV-cache, тем длиннее очередь одновременных запросов.
КВАНТИЗАЦИЯ: БЕСПЛАТНОЕ УСКОРЕНИЕ (ПОЧТИ)
Снижение точности весов — самый дешёвый способ ускориться и влезть в меньшую карту. В 2026 набор устоялся:
- FP16/BF16 — дефолт, почти без потерь качества, база для всего остального.
- INT8 / SmoothQuant — хороший баланс, требует калибровки; заметное ускорение на матричных ядрах.
- INT4 (AWQ, GPTQ) — вес модели в разы меньше, 70B влезает в одну карту; для чат-нагрузок деградация обычно в пределах шума.
- FP8 — на Hopper/Ada даёт скорость INT8 при качестве ближе к FP16; становится дефолтом на новом железе.
Правило практика: начинайте с FP16, при нехватке памяти переходите на AWQ INT4 и обязательно прогоняйте свой eval-сет. Бенчмарки «в среднем без потерь» ничего не говорят про вашу конкретную задачу.
СРАВНЕНИЕ: ЧТО КОГДА БРАТЬ
| Критерий | ONNX Runtime | TensorRT / TRT-LLM | vLLM |
|---|---|---|---|
| Основной сценарий | Классика, эмбеддеры, edge, CPU | Минимальная латентность на GPU NVIDIA | Serving LLM с высоким throughput |
| Железо | CPU, GPU, мобилки, браузер | Только GPU NVIDIA | Преим. GPU NVIDIA (+ поддержка др.) |
| Сила | Портируемость, кроссязычность | Латентность, layer fusion, FP8/INT8 | PagedAttention, continuous batching |
| Слабость | Не топ по пиковой скорости LLM | Привязка к GPU, долгая сборка | Заточен под LLM, не для классики |
| Батчинг | Статический | In-flight (в TRT-LLM) | Continuous (динамический) |
| Порог входа | Низкий | Высокий | Низкий (одна команда) |
Частая рабочая связка: ONNX как формат обмена, TensorRT как execution provider под него для CV-моделей, а vLLM отдельно для всего, что связано с генерацией текста.
ТИПИЧНЫЕ ГРАБЛИ 2026
- Забыли dynamic_axes. Модель работает на batch=1 и падает на проде под нагрузкой.
- Меряют латентность без прогрева. Первые запросы включают компиляцию ядер и загрузку — всегда делайте warmup и меряйте p50/p95, а не «одно число».
- Переехали TensorRT-engine на другую карту. Не переносится — пересобирайте под целевой GPU.
- Квантовали и не проверили качество. INT4 может уронить именно ваш узкий домен, даже если общий бенчмарк держится.
- Задрали max-model-len до предела. Каждый лишний токен контекста ест VRAM под KV-cache и режет число параллельных запросов.
КАК ПОДОЙТИ К ВЫБОРУ СТЕКА
Коротко, по типу нагрузки:
- CV / классификация / эмбеддинги, нужна портируемость → ONNX Runtime, при GPU — с TensorRT-провайдером.
- Одна модель, критична латентность на NVIDIA → TensorRT (или TRT-LLM для генеративных).
- LLM-чат/API на много пользователей → vLLM, квантизация AWQ, continuous batching.
- Смешанный парк железа, часть без GPU → ONNX как общий знаменатель.
Замеряйте на своих данных и своём железе — универсального лидера нет, есть правильный инструмент под конкретный профиль запросов.
Частые вопросы
Что быстрее для инференса — ONNX, TensorRT или vLLM?
Зависит от задачи. Для минимальной латентности одной модели на GPU NVIDIA быстрее TensorRT. Для максимального throughput при обслуживании LLM выигрывает vLLM за счёт continuous batching. ONNX Runtime — лучший универсальный выбор для CPU, edge и классических моделей.
Можно ли использовать ONNX и TensorRT вместе?
Да, это стандартная практика. Модель экспортируют в ONNX, а затем запускают через TensorrtExecutionProvider в ONNX Runtime или собирают TensorRT-engine из ONNX через trtexec. ONNX выступает промежуточным форматом.
Сильно ли квантизация в INT4 роняет качество LLM?
Для большинства чат-нагрузок деградация от AWQ/GPTQ INT4 обычно в пределах шума, но на узких доменах может быть заметной. Всегда прогоняйте собственный eval-сет после квантизации — общие бенчмарки не гарантируют результат на вашей задаче.
Что такое PagedAttention в vLLM простыми словами?
Это способ хранить KV-cache страницами, как виртуальная память в операционной системе, вместо одного непрерывного блока на запрос. Это резко снижает фрагментацию VRAM и позволяет обслуживать больше запросов одновременно на том же GPU.
Инструменты serving меняются буквально еженедельно — новые квантизации, движки и форки появляются постоянно. Чтобы не пропустить свежий релиз, который сэкономит вам половину GPU-бюджета, загляните в Telegram-канал REDDYX AI — новые репозитории каждые 30-60 минут.