MLOps: упаковка и сервинг
Упаковка модели - то, где ноутбук встречается с реальностью: «пришли .pkl в чат» заканчивается тем, что у половины команды он не распаковывается, у второй - предсказывает иначе. Вопросы проверяют прод-гигиену.
// Артефакт модели это не веса. Это веса + препроцессинг + зависимости + сигнатура.
Артефакт: веса - только четверть дела
Полный артефакт: веса, препроцессинг (сериализованный вместе с моделью - sklearn Pipeline и аналоги), полный пиннинг зависимостей (lock-файл), сигнатура входа/выхода.
pickle без зафиксированного окружения - бомба: минорные версии sklearn/torch меняют сериализацию и численные результаты.
// Препроцессинг, переписанный «по памяти» на сервинге, training-serving skew, сделанный своими руками. Один код, сериализованный с моделью.
// Батч vs онлайн: батч-инференс считает прогнозы заранее по расписанию (дёшево, для ночного скоринга базы), онлайн отвечает на живой запрос за миллисекунды (рекомендации, антифрод). Выбирают по требуемой свежести прогноза и латентности.
- сигнатура модели
- схема входа/выхода - контракт для сервинга и тестов
Docker и переносимые форматы
Docker - стандарт: одинаковое окружение от ноутбука до прода. Образ собирается в CI, тегируется версией; «latest» в проде - способ не знать, что у тебя крутится.
Экспорт в ONNX (Open Neural Network Exchange)/TorchScript отвязывает инференс от трейн-фреймворка: открываются оптимизирующие рантаймы (TensorRT, ONNX Runtime) и деплой без тяжёлых зависимостей обучения.
// После любого обновления базового образа или зависимостей - прогон регрессионных предсказаний: числа умеют меняться молча.
- ONNX
- переносимый формат модели - инференс без трейн-фреймворка
Сервинг-обвязка
Сервис вокруг модели: REST/gRPC (FastAPI, Triton, TorchServe-класс), healthcheck, таймауты, лимиты памяти. Модель грузится на старте - ленивую загрузку на первом запросе оплатит первый юзер минутой ожидания.
Валидация входа обязательна: схема запроса, типы и диапазоны фичей. Мусор на входе должен давать 4xx, а не тихое предсказание по мусору.
// Прогрев после старта: первый инференс дорогой (компиляция, кэши) - прогрей синтетическим запросом до включения в балансировку.
- healthcheck / warmup
- готовность сервиса и прогрев до трафика
Как отвечать: «Как упакуешь модель для прода?»
Артефакт целиком: веса плюс сериализованный с ними препроцессинг - один код на трейн и сервинг, плюс lock-файл зависимостей и сигнатура входа-выхода. Дальше Docker-образ, собранный в CI и тегированный версией, никаких latest. Инференс по возможности экспортирую в ONNX - отвязка от трейн-фреймворка и оптимизирующие рантаймы. Обвязка: FastAPI или Triton, загрузка модели на старте с прогревом, healthcheck, таймауты и валидация входа по схеме - мусор получает 4xx, а не предсказание. И регрессионный прогон предсказаний на эталонных примерах при любом обновлении зависимостей.
Полный чек-лист от артефакта до обвязки с обоснованиями - виден человек, чей pkl уже не распаковывался у коллег.
На чём валят
- −Разослать .pkl без версий библиотек - у половины не распакуется, у второй предскажет иначе.
- −Ленивая загрузка модели на первом запросе - p99 первого юзера равен минуте.
- −Препроцессинг «по памяти» на сервинге - training-serving skew руками.
- −Обновить базовый образ без регрессионного прогона предсказаний.
Проверьте себя
Пять вопросов из банка по этой подтеме. Всего их 14, остальные разбираются в тренажёре.
- Зачем выносить модель в отдельный инференс-сервис, а не звать её функцией внутри основного бэкенда?A)Ради того, чтобы переписать всю логику модели на более быстром языке вроде C++B)Чтобы скрыть от бэкенд-команды сам факт использования машинного обучения в продуктеC)Независимый деплой, масштабирование и ресурсы (GPU, память) отдельно от бизнес-логикиD)Отдельный сервис снимает необходимость версионировать модель и мониторить её в проде
показать ответ и разбор
+C)Независимый деплой, масштабирование и ресурсы (GPU, память) отдельно от бизнес-логики// разбор: Модель и бэкенд живут в разном ритме: модели нужны GPU и много RAM, свой цикл релиза, свой скейл под свою нагрузку. Отдельный сервис (FastAPI/BentoML/Triton) даёт независимый деплой, изоляцию ресурсов и версий. Цена — сетевой вызов и своя инфраструктура, поэтому крохотную модель иногда оставляют в процессе. Версионировать и мониторить всё равно надо.
- Что практически даёт конвертация модели в TensorRT или ONNX Runtime перед выкатом?A)Заметно повышает саму метрику качества модели на отложенной валидационной выборкеB)Избавляет команду от необходимости мониторить дрифт данных и предсказаний в продакшенеC)Автоматически размечает новые данные и запускает дообучение модели по расписанию без участия человекаD)Ускоряет инференс и снижает латентность за счёт оптимизации графа и работы без тяжёлого фреймворка
показать ответ и разбор
+D)Ускоряет инференс и снижает латентность за счёт оптимизации графа и работы без тяжёлого фреймворка// разбор: Оптимизированные рантаймы (TensorRT, ONNX Runtime) сворачивают граф вычислений, делают fusion слоёв и пониженную точность (fp16/int8), убирают питон-оверхед — инференс быстрее и латентность ниже при той же архитектуре. Качество это не улучшает (квантизация иногда чуть роняет его), а мониторинг с дрифтом никуда не деваются.
- Инференс-сервис держит p99 latency 800 мс под нагрузкой при SLA 200 мс. Что из MLOps-арсенала пробовать?A)Квантизация или дистилляция, рантайм TensorRT/Triton, батчинг запросов, вынос на GPUB)Увеличить клиентский таймаут до 800 мс и считать, что проблема латентности решенаC)Переобучить модель на значительно большем датасете — это само собой снизит время ответа на запросD)Добавить агрессивные ретраи с бэкоффом на каждый медленный запрос к инференс-сервису под нагрузкой
показать ответ и разбор
+A)Квантизация или дистилляция, рантайм TensorRT/Triton, батчинг запросов, вынос на GPU// разбор: Латентность инференса режут на уровне модели и рантайма: дистилляция/квантизация уменьшают модель, TensorRT/ONNX/Triton ускоряют граф, dynamic batching поднимает throughput, GPU снимает CPU-боттлнек. Больший датасет на латентность не влияет; поднять таймаут — спрятать нарушение SLA; ретраи только добавят нагрузки и удлинят хвост latency.
- Инференс-сервис на GPU недозагружен и обрабатывает запросы по одному. Как поднять пропускную способность?A)Динамический батчинг: копить запросы за короткое окно и прогонять их пачкой — GPU заметно эффективнее на батчеB)Обрабатывать запросы ещё строже по одному, но при этом в несколько раз чаще опрашивать очередь входящих запросовC)Увеличить размер модели, чтобы она за один проход обрабатывала побольше входных данных пользователя сразу за разD)Отключить GPU и перейти на CPU — так каждый отдельный запрос будет обрабатываться немного быстрее по времени
показать ответ и разбор
+A)Динамический батчинг: копить запросы за короткое окно и прогонять их пачкой — GPU заметно эффективнее на батче// разбор: GPU эффективна на батчах: обработка по одному запросу оставляет её недозагруженной. Динамический батчинг накапливает запросы за небольшое окно (несколько мс) и прогоняет одной пачкой, резко повышая throughput ценой небольшого роста задержки — этот размен настраивают под SLA (так делают Triton/TorchServe). Учащённый опрос очереди, укрупнение модели и переход на CPU throughput не поднимут (последнее обычно ухудшит и латентность).
- Зачем брать готовый model server (Triton/TorchServe/BentoML) вместо самописной обёртки Flask вокруг модели?A)Готовые серверы работают с одной конкретной моделью, и настроить их под свою задачу не получитсяB)Разницы нет: самописный Flask вокруг model.predict эквивалентен по возможностям готовомуC)Готовый сервер нужен лишь для красивого дашборда, а на производительность и удобство эксплуатации он не влияет никакD)Дают из коробки батчинг, версионирование, метрики, поддержку GPU и форматов — не переписывать инфраструктуру под каждую модель
показать ответ и разбор
+D)Дают из коробки батчинг, версионирование, метрики, поддержку GPU и форматов — не переписывать инфраструктуру под каждую модель// разбор: Наивная Flask-обёртка вокруг model.predict быстро упирается в отсутствие батчинга, версионирования моделей, метрик/health-check, эффективной загрузки GPU, конкуррентности и поддержки форматов (ONNX/TensorRT). Готовые серверы (Triton, TorchServe, BentoML) дают это из коробки, освобождая от переизобретения инфраструктуры на каждую модель. Они конфигурируемы под разные модели, а самопис по возможностям и производительности им обычно уступает.
дальше
Теорию прочитали. Навык ставится повторением
В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, лимит только на количество вопросов в день.