сеньорчикОткрыть в Telegram
← вся теориятеория к собесу · MLOps

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, остальные разбираются в тренажёре.

  1. #packaging_serving1 / 5
    Зачем выносить модель в отдельный инференс-сервис, а не звать её функцией внутри основного бэкенда?
    A)Ради того, чтобы переписать всю логику модели на более быстром языке вроде C++
    B)Чтобы скрыть от бэкенд-команды сам факт использования машинного обучения в продукте
    C)Независимый деплой, масштабирование и ресурсы (GPU, память) отдельно от бизнес-логики
    D)Отдельный сервис снимает необходимость версионировать модель и мониторить её в проде
    показать ответ и разбор
    +C)Независимый деплой, масштабирование и ресурсы (GPU, память) отдельно от бизнес-логики

    // разбор: Модель и бэкенд живут в разном ритме: модели нужны GPU и много RAM, свой цикл релиза, свой скейл под свою нагрузку. Отдельный сервис (FastAPI/BentoML/Triton) даёт независимый деплой, изоляцию ресурсов и версий. Цена — сетевой вызов и своя инфраструктура, поэтому крохотную модель иногда оставляют в процессе. Версионировать и мониторить всё равно надо.

  2. #packaging_serving2 / 5
    Что практически даёт конвертация модели в TensorRT или ONNX Runtime перед выкатом?
    A)Заметно повышает саму метрику качества модели на отложенной валидационной выборке
    B)Избавляет команду от необходимости мониторить дрифт данных и предсказаний в продакшене
    C)Автоматически размечает новые данные и запускает дообучение модели по расписанию без участия человека
    D)Ускоряет инференс и снижает латентность за счёт оптимизации графа и работы без тяжёлого фреймворка
    показать ответ и разбор
    +D)Ускоряет инференс и снижает латентность за счёт оптимизации графа и работы без тяжёлого фреймворка

    // разбор: Оптимизированные рантаймы (TensorRT, ONNX Runtime) сворачивают граф вычислений, делают fusion слоёв и пониженную точность (fp16/int8), убирают питон-оверхед — инференс быстрее и латентность ниже при той же архитектуре. Качество это не улучшает (квантизация иногда чуть роняет его), а мониторинг с дрифтом никуда не деваются.

  3. #packaging_serving3 / 5
    Инференс-сервис держит p99 latency 800 мс под нагрузкой при SLA 200 мс. Что из MLOps-арсенала пробовать?
    A)Квантизация или дистилляция, рантайм TensorRT/Triton, батчинг запросов, вынос на GPU
    B)Увеличить клиентский таймаут до 800 мс и считать, что проблема латентности решена
    C)Переобучить модель на значительно большем датасете — это само собой снизит время ответа на запрос
    D)Добавить агрессивные ретраи с бэкоффом на каждый медленный запрос к инференс-сервису под нагрузкой
    показать ответ и разбор
    +A)Квантизация или дистилляция, рантайм TensorRT/Triton, батчинг запросов, вынос на GPU

    // разбор: Латентность инференса режут на уровне модели и рантайма: дистилляция/квантизация уменьшают модель, TensorRT/ONNX/Triton ускоряют граф, dynamic batching поднимает throughput, GPU снимает CPU-боттлнек. Больший датасет на латентность не влияет; поднять таймаут — спрятать нарушение SLA; ретраи только добавят нагрузки и удлинят хвост latency.

  4. #packaging_serving4 / 5
    Инференс-сервис на GPU недозагружен и обрабатывает запросы по одному. Как поднять пропускную способность?
    A)Динамический батчинг: копить запросы за короткое окно и прогонять их пачкой — GPU заметно эффективнее на батче
    B)Обрабатывать запросы ещё строже по одному, но при этом в несколько раз чаще опрашивать очередь входящих запросов
    C)Увеличить размер модели, чтобы она за один проход обрабатывала побольше входных данных пользователя сразу за раз
    D)Отключить GPU и перейти на CPU — так каждый отдельный запрос будет обрабатываться немного быстрее по времени
    показать ответ и разбор
    +A)Динамический батчинг: копить запросы за короткое окно и прогонять их пачкой — GPU заметно эффективнее на батче

    // разбор: GPU эффективна на батчах: обработка по одному запросу оставляет её недозагруженной. Динамический батчинг накапливает запросы за небольшое окно (несколько мс) и прогоняет одной пачкой, резко повышая throughput ценой небольшого роста задержки — этот размен настраивают под SLA (так делают Triton/TorchServe). Учащённый опрос очереди, укрупнение модели и переход на CPU throughput не поднимут (последнее обычно ухудшит и латентность).

  5. #packaging_serving5 / 5
    Зачем брать готовый 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) дают это из коробки, освобождая от переизобретения инфраструктуры на каждую модель. Они конфигурируемы под разные модели, а самопис по возможностям и производительности им обычно уступает.

дальше

Теорию прочитали. Навык ставится повторением

В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, лимит только на количество вопросов в день.