Машинное обучение
Model Serving: доставка предсказаний пользователям
Когда ChatGPT запустился, ему нужно было обслуживать 100 миллионов пользователей со временем ответа менее 2 секунд. Обученная модель бесполезна, если она не может выдавать предсказания с нужной скоростью, масштабом и стоимостью. Model serving - это мост между обученной моделью и реальными пользователями.
- **Поисковые системы (Google, Yandex)** - каждый запрос проходит через десятки ML-моделей (ранжирование, спелл-чек, подсказки) за менее чем 200ms, обрабатывая миллиарды запросов в день через Triton-подобную инфраструктуру с dynamic batching и GPU-кластерами
- **Fraud detection в банках** - модель оценивает каждую транзакцию за <50ms, решая в реальном времени: пропустить или заблокировать, при этом обрабатывая тысячи транзакций в секунду через gRPC-endpoint с ONNX Runtime
- **Рекомендации Netflix и Spotify** - batch-процесс ночью пересчитывает персональные рекомендации для 200+ миллионов пользователей, а real-time слой корректирует выдачу при каждом взаимодействии - классическая lambda architecture
Предварительные знания
Как превратить обученную модель в сервис
Обучить модель и отдать её пользователям оказались двумя совершенно разными инженерными задачами. Поначалу команды вручную оборачивали сохранённую модель во Flask, и это работало, пока не накапливались трафик, бюджеты по задержкам и версии моделей. В 2016 Google выложил в открытый доступ TensorFlow Serving, систему, созданную для продакшена: она загружала несколько версий модели, подменяла их без простоя, батчила запросы ради пропускной способности и предоставляла стабильный интерфейс gRPC. Так раздача предсказаний стала полноценной задачей, а не тем, о чём вспоминают в последнюю очередь. Следующей стеной стал вендор-лок: модель, обученную в одном фреймворке, было неудобно отдавать из другого. В 2017 Microsoft и Facebook представили ONNX (Open Neural Network Exchange), общий формат, чтобы модель, обученная в PyTorch, запускалась в другом рантайме. Triton Inference Server от NVIDIA пошёл дальше, раздавая модели из множества фреймворков на одном GPU с динамическим батчингом. В основе всего этого лежит коварный повторяющийся баг: train/serve skew, когда вычисление признаков при обучении незаметно отличается от пути кода при инференсе. Модель отлично выглядит офлайн и проседает вживую, поэтому инфраструктура раздачи всё чаще переиспользует логику признаков из обучения, а не реализует её заново.
Инфраструктура serving
Обученная модель - это просто файл с весами. Чтобы она приносила пользу, нужно **доставить предсказания пользователям**. Model serving - это инфраструктура, которая принимает запросы, прогоняет данные через модель и возвращает результат. Два основных протокола: **REST API** (HTTP + JSON, универсальный, простой для отладки) и **gRPC** (Protocol Buffers, бинарный, в 2-10 раз быстрее REST для числовых данных). REST выбирают для внешних клиентов и прототипов, gRPC - для внутренних микросервисов, где важна скорость.
Следующий шаг - **контейнеризация**. Docker упаковывает модель, код и все зависимости в один образ, который одинаково работает на ноутбуке разработчика и в production-кластере. Это решает проблему "у меня на машине работает": контейнер включает точные версии Python, библиотек и самой модели.
**Масштабирование с Kubernetes:** Kubernetes автоматически управляет контейнерами: - **Horizontal Pod Autoscaler (HPA)** - добавляет реплики сервиса при росте нагрузки (например, при CPU > 70%) - **Liveness probe** - перезапускает контейнер, если /health не отвечает - **Readiness probe** - не посылает трафик, пока модель не загрузилась - **Rolling update** - обновляет модель без downtime: новые pod-ы поднимаются до того, как старые выключаются Типичная конфигурация: min 2 реплики (отказоустойчивость), max 10 (пиковая нагрузка), autoscaling по CPU или custom-метрике (latency p99).
На практике serving-инфраструктура включает не только сам API, но и **load balancer** (распределяет запросы между репликами), **model registry** (хранит версии моделей), **feature store** (предоставляет признаки для inference) и **monitoring** (отслеживает latency, throughput, ошибки). Для простых случаев достаточно FastAPI + Docker, для production-нагрузки в сотни тысяч запросов в секунду - нужен полноценный стек с Kubernetes, gRPC и специализированными serving-фреймворками.
Почему для внутренней коммуникации между ML-микросервисами часто выбирают gRPC вместо REST API?
ONNX Runtime: универсальный формат и оптимизированный inference
**ONNX (Open Neural Network Exchange)** - открытый формат для представления ML-моделей. Проблема, которую он решает: модель, обученная в PyTorch, не запускается в TensorFlow, и наоборот. ONNX - это **lingua franca** ML-моделей: конвертируете модель из любого фреймворка в .onnx файл, а затем запускаете через ONNX Runtime на любой платформе. ONNX описывает модель как **вычислительный граф** - узлы (операции: MatMul, Conv, ReLU) и рёбра (тензоры данных между ними).
**ONNX Runtime** - это движок inference от Microsoft, оптимизированный для скорости. Он не просто выполняет граф операций, а применяет **граф-оптимизации**: объединяет последовательные операции (Conv + BatchNorm + ReLU сливаются в одну), удаляет лишние копирования тензоров, оптимизирует layout данных в памяти. Результат - ускорение inference на 20-50% по сравнению с нативным выполнением в PyTorch, без изменения точности модели.
**Оптимизации ONNX Runtime:** - **Operator fusion** - объединение последовательных операций (MatMul + Add + ReLU = одна оптимизированная операция вместо трёх) - **Constant folding** - предвычисление операций с константами на этапе загрузки, а не при каждом запросе - **Memory planning** - переиспользование блоков памяти между операциями, уменьшение аллокаций - **Quantization** - конвертация float32 весов в int8 (в 2-4 раза быстрее, ~1% потери точности) Quantization особенно эффективна для CPU-inference: int8-операции в 2-4 раза быстрее float32 на современных процессорах с AVX-512 инструкциями.
ONNX Runtime - это **золотой стандарт для CPU-inference** и хороший выбор для GPU. Он поддерживает все основные фреймворки (PyTorch, TensorFlow, scikit-learn, LightGBM, XGBoost), работает на Windows, Linux, macOS, а также на мобильных устройствах и в браузере (ONNX Runtime Web). Для большинства production-задач ONNX Runtime - первое, что стоит попробовать: минимальные усилия на интеграцию, гарантированное ускорение.
Какую основную проблему решает формат ONNX в ML-инфраструктуре?
Triton Inference Server: промышленный serving
**NVIDIA Triton Inference Server** - это промышленная платформа для serving ML-моделей, которая решает проблемы, с которыми не справляется простой FastAPI-сервис. Главные возможности: **multi-model serving** (десятки моделей на одном сервере), **dynamic batching** (автоматическое объединение запросов в batch), **model ensemble** (пайплайн из нескольких моделей) и **concurrent model execution** (параллельное выполнение на GPU). Triton используют в production компании вроде Microsoft, Amazon и Uber.
**Dynamic batching** - одна из самых ценных функций Triton. Когда 100 пользователей отправляют запрос одновременно, вместо 100 отдельных inference-вызовов Triton собирает их в batch и выполняет за один проход GPU. GPU оптимизированы для параллельных вычислений, поэтому batch из 32 запросов выполняется почти за то же время, что и один запрос. Итог: throughput растёт в десятки раз при минимальном увеличении latency.
**Model Ensemble - пайплайн из моделей:** В production ML часто нужна цепочка: preprocessing -> model_1 -> postprocessing -> model_2. Triton поддерживает ensemble scheduling: 1. Пользователь отправляет сырые данные (текст, изображение) 2. Модель-препроцессор (tokenizer, resize) готовит входные тензоры 3. Основная модель делает предсказание 4. Постпроцессор форматирует результат Вся цепочка выполняется на сервере без round-trip-ов по сети. Каждый шаг может работать на разном hardware: preprocessing на CPU, inference на GPU.
**Когда нужен Triton, а когда достаточно простого FastAPI?** Если модель одна, нагрузка до 100 RPS и GPU не нужен - FastAPI + ONNX Runtime хватит. Triton оправдан, когда: несколько моделей на одном сервере, нужен dynamic batching для высокого throughput, требуется GPU scheduling между моделями, A/B testing разных версий или ensemble из нескольких моделей. Triton добавляет сложность инфраструктуры, но снимает с инженера задачи batching, scheduling и multi-model management.
Какое главное преимущество dynamic batching в Triton Inference Server?
Batch vs Real-time inference
Не все ML-задачи требуют мгновенного ответа. **Real-time inference** - модель отвечает на запрос пользователя за миллисекунды (поиск, fraud detection, автокомплит). **Batch inference** - модель обрабатывает накопленные данные пакетами, раз в час или раз в день (рекомендации, ETL, скоринг). **Streaming inference** - модель обрабатывает непрерывный поток событий (мониторинг, IoT-сенсоры). Выбор между ними определяет архитектуру, стоимость и сложность системы.
**Batch inference** - самый простой и дешёвый вариант. Запускаете скрипт по расписанию, он обрабатывает все накопленные данные и сохраняет результат в базу данных. Рекомендации Netflix: batch-процесс ночью пересчитывает рекомендации для всех пользователей, а утром пользователь видит готовый список. Не нужны постоянно работающие серверы - арендуете GPU на время batch-процесса и выключаете.
**Lambda Architecture для ML:** Комбинация batch и streaming для лучших результатов: - **Batch layer** - ночной пересчёт на полных данных (точные рекомендации) - **Speed layer** - real-time обновления на свежих событиях (пользователь купил товар - убрать его из рекомендаций) - **Serving layer** - объединяет результаты обоих слоёв Пример: рекомендации электронной коммерции. Batch-процесс ночью считает персональный каталог из 1000 товаров. Real-time слой при каждом клике переранжирует top-10 из этого каталога. Результат: актуальность real-time + глубина анализа batch.
Выбор режима inference определяется бизнес-требованиями, а не техническими предпочтениями. Fraud detection при оплате - только real-time (пользователь не будет ждать час). Рекомендации на главной странице - batch достаточно (обновляются раз в день). Мониторинг серверов - streaming (нужна непрерывная проверка, но не мгновенный ответ). Комбинация режимов (lambda architecture) даёт лучшие результаты, но увеличивает сложность системы.
Real-time inference всегда лучше batch, потому что даёт более актуальные результаты
Batch inference дешевле и эффективнее для задач, которые не требуют мгновенного ответа - рекомендации, скоринг, аналитика
Real-time inference требует постоянно работающих серверов (часто с GPU), низкой latency и высокой доступности - это дорого. Batch inference запускается по расписанию, использует ресурсы только во время выполнения и обрабатывает данные большими эффективными batch-ами. Для рекомендаций, email-рассылки, credit scoring batch даёт тот же результат при стоимости в 5-10 раз ниже. Выбор определяется бизнес-требованиями: если пользователь не ждёт ответ прямо сейчас, batch почти всегда выгоднее.
Для интернет-магазина нужна ML-система рекомендаций на главной странице, которая учитывает историю покупок. Какой режим inference оптимален?
Итоги
- **Инфраструктура serving:** REST API (FastAPI) для прототипов и внешних клиентов, gRPC для внутренних микросервисов, Docker для воспроизводимости, Kubernetes для автоматического масштабирования - от единичного endpoint до тысяч RPS
- **ONNX Runtime:** универсальный формат обмена моделями между фреймворками, граф-оптимизации (operator fusion, constant folding) и quantization (float32 -> int8) дают 2-4x ускорение inference без потери точности
- **Triton Inference Server:** промышленный multi-model serving с dynamic batching (объединение запросов в batch для GPU), model ensemble (цепочка моделей), A/B testing версий и автоматическим GPU scheduling - когда простого FastAPI уже недостаточно
- **Batch vs Real-time:** выбор режима inference определяется бизнес-задачей, а не техническими предпочтениями - как и при запуске ChatGPT, ключевой вопрос: какая скорость, масштаб и стоимость нужны для конкретных пользователей
Связанные темы
Model serving - заключительное звено в цепочке от обучения модели до реальных пользователей, связывающее MLOps-пайплайн с мониторингом production-систем:
- MLOps: пайплайны и CI/CD для ML — MLOps-пайплайн обучает модель и регистрирует её в model registry, откуда serving-инфраструктура забирает новую версию для deployment. Без автоматизированного пайплайна обновление модели в production - ручной и рискованный процесс
- Мониторинг ML-систем — Serving без мониторинга - это полёт вслепую: нужно отслеживать latency, throughput, error rate и самое важное - data drift и degradation качества модели в production
- Distributed Training — Модели, обученные на нескольких GPU (distributed training), часто требуют специальных стратегий serving: model parallelism для огромных моделей, которые не помещаются на одну GPU
- ML System Design — Выбор между batch и real-time inference, архитектура serving-слоя, trade-off latency vs throughput - всё это часть дизайна ML-системы, где serving определяет user experience
Вопросы для размышления
- Ваш стартап запускает ML-продукт с 1000 пользователей, но планирует рост до 1 миллиона. Как бы вы спроектировали serving-инфраструктуру, чтобы она масштабировалась без полной переделки на каждом этапе роста?
- Dynamic batching увеличивает throughput, но добавляет задержку (ожидание batch). Как бы вы настроили max_queue_delay для задачи fraud detection (latency < 50ms) и для рекомендаций (latency < 500ms)?
- В каких случаях lambda architecture (batch + real-time) оправдывает свою сложность, а когда проще обойтись только одним режимом inference?
Связанные уроки
- ml-45-mlops-pipeline — Serving - этап деплоя в MLOps
- ml-47-model-monitoring — Развёрнутые модели нужно мониторить
- ml-54-distributed-training — Большие модели требуют распределённого serving
- ml-55-ml-system-design — Serving - ключевой вопрос проектирования
- sd-06-load-balancer — Балансировщики масштабируют реплики инференса
- sd-10-microservices