AIが作成人が改善
Riqli · ライブドキュメント · 常に更新
AIの知識と人間の実践が出会う場所。
友達と共有

Деплой и сервинг ML-моделей (TorchServe / TF Serving / FastAPI + Docker)
Введение в деплой и сервинг ML-моделей
Аннотация. Данный модуль посвящён практическим аспектам развёртывания и сервинга ML-моделей в production-среде. Рассматриваются три ключевых подхода: FastAPI + Docker для построения REST API, TorchServe для serving PyTorch-моделей и TensorFlow Serving для TensorFlow-моделей. Основной упор делается на сквозной workflow: от подготовки обученной модели до контейнеризации и запуска в кластере.
Цель курса. Сформировать практические навыки упаковки ML-моделей в Docker-контейнеры, создания inference API с помощью FastAPI и Pydantic, а также использования специализированных серверов TorchServe и TensorFlow Serving для высоконагруженных сценариев. Слушатель научится выбирать инструмент сервинга под конкретную задачу, настраивать healthcheck-эндпоинты и обеспечивать воспроизводимость окружения между обучением и production.
Результаты обучения. По завершении модуля слушатель сможет: 1) сериализовать обученную модель в формате joblib/pickle или TorchScript/SavedModel; 2) написать FastAPI-приложение с Pydantic-схемой входных данных и эндпоинтом /predict; 3) собрать Dockerfile на базе python:3.11-slim с healthcheck; 4) запустить контейнер с пробросом портов и протестировать API через curl; 5) объяснить различия между hand-written API и специализированными serving-фреймворками.
Целевая аудитория. Курс предназначен для ML-инженеров, data scientists и backend-разработчиков с опытом Python от 6 месяцев, знакомых с основами обучения моделей (scikit-learn, PyTorch или TensorFlow) и базовыми командами Linux. Предварительное знакомство с Docker желательно, но не обязательно.
FastAPI + Docker: базовый workflow сервинга
Подготовка модели к сервингу. После обучения модель необходимо сериализовать в файл, который сможет загрузить серверный процесс. Для scikit-learn-моделей стандартный подход — библиотека joblib: joblib.dump(model, 'model.joblib'). FastAPI-приложение при старте выполняет joblib.load('model.joblib') и хранит объект модели в памяти процесса. Это критично: повторная загрузка модели на каждый запрос недопустима из-за latency и нагрузки на диск.
Pydantic-схема входных данных. FastAPI использует Pydantic для валидации входящего JSON. Необходимо определить класс, наследующий BaseModel, с полями, соответствующими признакам модели. Пример для diabetes-датасета: поля age: float, sex: float, bmi: float и т.д. Pydantic автоматически проверяет типы и возвращает 422 при невалидных данных — это устраняет целый класс ошибок, связанных с неверным форматом запроса.
Создание эндпоинта /predict. Декоратор @app.post('/predict') регистрирует функцию-обработчик. Функция принимает объект Pydantic, преобразует поля в numpy-массив формы (1, n_features) и вызывает model.predict(). Результат возвращается как JSON. Важно: не используйте async def, если внутри вызывается блокирующая model.predict() — в этом случае лучше def, чтобы FastAPI выполнил функцию в threadpool.
Dockerfile для FastAPI-сервиса. Базовый образ: python:3.11-slim. Шаги: WORKDIR /app, копирование requirements.txt и установка зависимостей через pip install --no-cache-dir -r requirements.txt, затем копирование кода модели и приложения. Директива EXPOSE 8080 документирует порт. Команда запуска: CMD ['uvicorn', 'main:app', '--host', '0.0.0.0', '--port', '8080']. Опционально добавляется HEALTHCHECK CMD curl -f http://localhost:8080/health || exit 1.
Почему при сервинге ML-модели через FastAPI рекомендуется загружать модель один раз при старте приложения, а не при каждом запросе к /predict?
Однократная загрузка модели исключает повторное чтение с диска и десериализацию на каждом запросе, что критически снижает latency и нагрузку на I/O.
Десериализация модели — дорогостоящая операция, которая может занимать сотни миллисекунд. При загрузке на каждый запрос время ответа становится непредсказуемым, а пропускная способность API резко падает.
Pydantic требует, чтобы модель была доступна глобально на уровне модуля, иначе валидация не сработает.
Uvicorn автоматически перезагружает приложение при каждом запросе, и модель должна быть доступна для повторной инициализации.
FastAPI не поддерживает глобальные переменные, поэтому модель приходится загружать в каждой функции.
Какая директива Dockerfile позволяет задать команду, выполняемую при запуске контейнера с FastAPI-приложением?
CMD
CMD задаёт команду по умолчанию для запуска контейнера. В примере: CMD ['uvicorn', 'main:app', '--host', '0.0.0.0', '--port', '8080'].
RUN
EXPOSE
ENTRYPOINT
Специализированные серверы: TorchServe и TensorFlow Serving
TorchServe. Open-source фреймворк от AWS и PyTorch для сервинга PyTorch-моделей. Ключевые возможности: мультимодельный сервинг, автоматический батчинг запросов, REST API для inference, метрики для мониторинга, версионирование моделей. TorchServe позволяет описывать кастомную логику предобработки и постобработки через handlers, что удобно для нестандартных пайплайнов. Модель экспортируется в формате TorchScript или через torch-model-archiver.
TensorFlow Serving. Высокопроизводительный open-source сервер для TensorFlow-моделей, экспортированных в формате SavedModel. Поддерживает горячую замену моделей без перезапуска сервера, версионирование и gRPC/REST API. В интеграции с FastAPI TensorFlow Serving может отвечать за inference, тогда как FastAPI берёт на себя preprocessing, postprocessing и аутентификацию (например, OAuth2). Это разделение ответственности часто используется в production-архитектурах.
Когда выбирать специализированный сервер. Hand-written FastAPI-сервис достаточен для одной-двух небольших моделей с умеренной нагрузкой. Специализированные фреймворки (TorchServe, TF Serving, Triton Inference Server) оправданы при: 1) необходимости автоматического батчинга для GPU-инференса; 2) сервинге множества моделей одновременно; 3) требовании к scale-to-zero или canary-rollout; 4) использовании LLM-специфичных функций (vLLM, continuous batching).
Какую роль TensorFlow Serving может играть в архитектуре с FastAPI?
TensorFlow Serving выполняет inference, а FastAPI отвечает за preprocessing, postprocessing и аутентификацию.
Такое разделение позволяет использовать оптимизированный inference-движок TF Serving и гибкость FastAPI для обвязки: валидации, логирования, OAuth2-аутентификации.
TensorFlow Serving полностью заменяет FastAPI, поскольку имеет встроенную валидацию Pydantic.
TensorFlow Serving используется только для обучения моделей, а FastAPI — для их деплоя.
FastAPI передаёт запросы в TensorFlow Serving только через gRPC, REST не поддерживается.
Какая возможность TorchServe позволяет объединять несколько входящих запросов в один вызов модели для повышения пропускной способности?
Автоматический батчинг (automatic batching).
TorchServe группирует индивидуальные запросы в батчи перед вызовом модели, что снижает overhead на каждый отдельный inference и увеличивает throughput, особенно на GPU.
Мультимодельный сервинг (multi-model serving).
Версионирование моделей (model versioning).
Интеграция с MLflow.
Регистрация моделей и управление воркерами через Management API TorchServe
Практический пример: serving-pytorch-models (TorchServe + ResNet18)
Роль Management API в TorchServe. TorchServe предоставляет два независимых порта: 8080 (или 8081 в зависимости от конфигурации) для inference-запросов и Management API для административных операций. Management API позволяет регистрировать новые модели без перезапуска сервера, изменять количество воркеров, получать метаданные о запущенных моделях и останавливать сервис. Это критично для production-сценариев, где требуется горячая замена моделей или масштабирование под нагрузкой без downtime .
Регистрация модели через POST /models. Для добавления новой модели в работающий TorchServe используется эндпоинт /models с параметрами запроса. Пример команды: curl -X POST 'http://localhost:8080/models?url=desserts.mar&initial_workers=1'. Параметр url указывает путь к MAR-архиву (абсолютный или относительно model-store). Параметр initial_workers задаёт количество воркеров, которые будут запущены сразу после регистрации. По умолчанию initial_workers равно 0, что означает регистрацию модели без немедленного запуска inference .
Обзор проекта serving-pytorch-models. Репозиторий alvarobartt/serving-pytorch-models демонстрирует полный workflow сервинга PyTorch-модели через TorchServe на примере классификации изображений еды (Food101). В основе лежит transfer learning: предобученный ResNet18 адаптируется под 10 классов, сохраняется в формате state_dict, затем упаковывается в MAR-архив и запускается через TorchServe. Проект использует Jupyter Notebook как основную среду для обучения, а деплой выполняется через CLI-инструменты и Docker .
Просмотр списка и деталей моделей. Management API предоставляет эндпоинты для мониторинга: GET /models возвращает список всех зарегистрированных моделей, а GET /models/{model_name} — детальную информацию по конкретной модели, включая метаданные и список запущенных воркеров. Например: curl http://localhost:8080/models/desserts. Эта информация используется для проверки статуса регистрации и диагностики проблем при загрузке модели .
Определение класса ImageClassifier. Поскольку TorchServe при загрузке модели должен сопоставить архитектуру с сохранёнными весами, необходимо определить класс, точно повторяющий структуру обученной сети. В репозитории создаётся класс ImageClassifier, наследующий ResNet из torchvision.models.resnet. Инициализация: super().__init__(BasicBlock, [2,2,2,2], num_classes=10). Ключевой момент — переопределение слоя self.fc: вместо стандартного линейного слоя ResNet18 используется последовательность Linear(512, 128) → ReLU → Dropout(0.2) → Linear(128, 10) → LogSoftmax. Это соответствует архитектуре, на которой обучалась модель .
Управление количеством воркеров. TorchServe позволяет динамически изменять минимальное и максимальное количество воркеров для каждой модели. Команда curl -X PUT 'http://localhost:8080/models/desserts?min_workers=3' устанавливает минимальное число воркеров равным 3. Воркеры — это процессы, которые непосредственно выполняют inference; если воркер падает, TorchServe автоматически запускает новый, поддерживая заданный минимум. Это обеспечивает отказоустойчивость сервиса без ручного вмешательства .
Запуск TorchServe в Docker с Management API. При запуске TorchServe в Docker-контейнере через образ pytorch/torchserve:latest-gpu необходимо пробросить оба порта: -p 8080:8080 -p 8081:8081 и смонтировать директорию с моделью: -v /root/model-store:/home/model-server/model-store. После запуска контейнера без предварительной загрузки моделей Management API доступен на порту 8080 (в конфигурации по умолчанию). Регистрация моделей выполняется через curl к localhost:8080 уже после старта контейнера .
Загрузка весов и проверка совместимости. После определения класса выполняется проверка: model = ImageClassifier(); model.load_state_dict(torch.load('model/foodnet_resnet18.pth')). PyTorch выводит <All keys matched successfully>, если архитектура класса полностью совпадает с архитектурой, использованной при сохранении весов. Если хотя бы один слой отличается по размеру или имени, загрузка упадёт с ошибкой — это критический шаг для TorchServe, поскольку сервер использует тот же state_dict при инициализации модели .
Какой HTTP-метод и эндпоинт используются для регистрации новой модели в работающем TorchServe через Management API?
POST /models с параметрами url и initial_workers.