Три способа вывести ML-модели в продакшн

Kate

Administrator
Команда форума
Я — Виталий Цымбалюк, специалист в области Data Science, спикер NIXMultiConf. В этой статье я расскажу о нескольких способах развертывания моделей ML в продакшене, основываясь на опыте нашей команды. Оговорюсь сразу: основные критерии, по которым были выбраны эти подходы — простота настройки, скорость работы и полнота функционала. Я коснусь и узких мест, с которыми мы столкнулись, и расскажу, какие решения в итоге применили.

Статья будет полезна как инженерам Data Science, так и ML Ops. Ознакомившись с этим материалом, вы сможете настраивать простой и быстрый continuous delivery в рамках ML.

Зачастую в Data Science отправка моделей Machine Learning в продакшен остается на втором плане, ведь это последний этап. До него нужно собрать данные, выбрать потенциальные алгоритмы решения задач, проверить множество разных гипотез, возможно, провести эксперименты. Даже когда вроде как задача решена, и мы видим первые результаты — стоило бы кричать «Ура, триумф, победа». Однако, нет — модель еще надо как-то заставить работать. При чем не в рамках какого-нибудь jupiter notebook, а в реальном приложении, с реальной нагрузкой и реальными пользователями. Более того, этап продакшена также подразумевает два момента. Первый — возможность замены модели ML на более новую, желательно не останавливая приложение (hot swap). Второй — настроить права доступа к модели и запустить одновременно несколько ее версий.

В проектах нашей команды мы попробовали множество подходов для моделей, созданных и обученных на различных ML frameworks. Я уделю внимание вариантам, которые мы чаще всего используем на практике.

Перед тем, как прийти к инструментам сервинга, мы пробовали создавать самописные web-приложения, подгружая в них натренированные модели. Но в таком варианте мы столкнулись с некоторыми проблемами. В частности, приходилось разбираться с внутренней реализацией многопоточности в web-приложении, которое конфликтовало с реализацией ML, и продумывать начальную загрузку моделей. Так как это длительный процесс, приложение доступно для работы не сразу после запуска. Кроме того, возникли трудности с одновременной работой нескольких пользователей, с разграничением доступа, с рестартом приложения после тренировки новой версии модели. После перехода на специализированные библиотеки эти проблемы теперь в прошлом.

Tensorflow Serving​

Вероятно, это лучший способ взаимодействия с моделями, созданными с помощью Tensorflow. Хотя мы также использовали этот framework для работы с моделями, созданными в Pytorch и сконвертированными в Tensorflow через промежуточный формат onnx.

Основные достоинства Tensorflow Serving:

  • Поддержка работы с версиями. Очень легко настроить работу так, чтобы одновременно запустились, например, несколько версий одной модели. Так можно проводить A/B тестирование или держать QA/Dev версии.
  • Возможность горячей замены моделей без остановки сервиса. Для нас очень полезная функция. С ее помощью мы можем, не останавливая сервис, подложить в папку с моделями новую версию — и tensorflow serving дождется, когда копирование модели завершится, подгрузит новую версию, развернет ее и «потушит» предыдущую. Для пользователей все это произойдет незаметно, даже если активно ведется взаимодействие с моделью.
  • Автогенерация REST и gRPC API для работы с моделями. Это, наверное, самая полезная фишка библиотеки. Не нужно писать никаких сервисов. Доступ ко всем моделям генерируется автоматически. Есть также метод для получения метаданных о моделях. Обычно мы используем его, когда разворачиваем сторонние модели, и нам нужно узнать форматы входных данных. Когда нужно ускорить работу, используем gRPC. Данный протокол функционирует значительно быстрее, чем REST.
  • Работа в Docker и Kubernetes. На данный момент наш основной способ работы с serving заключается в использовании Docker контейнера. Serving мы подгружаем в отдельном контейнере, в который копируем конфигурационный файл с описанием наших моделей. Затем подключаем Docker volume, в котором находятся сами модели. Этот же Docker volume применяется в других контейнерах (у нас был вариант его использования в jupiter и в отдельном приложении), где у нас при необходимости происходит тренировка новых моделей. Сейчас эта схема хорошо себя зарекомендовала и активно используется в нескольких наших проектах.
  • Возможность масштабирования. Эту функцию мы пока только изучаем и в будущем собираемся использовать. В теории, Tensorflow serving можно запустить в Kubernetes (например, в Google cloud) и держать наш serving за LoadBalancer. Так что нагрузка на модели будет делиться на несколько инстансов.
Недостатки:

  • Сложно развернуть модель, созданную вне Tensorflow (sklearn, lightGBM, XGBoost). Несмотря на то, что их расширения поддерживаются, придется самостоятельно писать код на C++.
  • Нужно побеспокоиться о security. Как вариант, закрыть доступ к Tensorflow Serving из сети и оставить к нему доступ только для своих сервисов, в которых уже будет реализована, например, аутентификация. В нашем подходе с развертыванием в Docker мы, как правило, закрываем все порты для контейнера с serving. Как результат, обращаться к моделям можно только из других контейнеров, развернутых в той же подсети. Docker-compose отлично справляется с такой связкой контейнеров.
На данный момент, если сравнить Tensorflow и Pytorch, то у второго до недавнего времени не было возможности сервить модель кем-нибудь подобным на Tensorflow Serving. Даже в его официальной документации приводили пример работы через flask сервис. А для Tensorflow даже этого делать не надо, так как serving сам создает такой сервис. Что касается недостатков, то они для нас имели значение на старте нашего знакомства с serving. Сейчас же в той архитектуре, которую мы используем, они для нас несущественны.

Triton Inference Server​

Другой популярный опенсорсный фреймворк развертывания моделей от Nvidia. Данный инструмент позволяет развертывать оптимизированные под GPU и CPU модели как локально, так и в облаке. Он поддерживает протоколы REST и GRPC. В нем также есть возможность включать TIS как C-библиотеку на конечных устройствах прямо в приложения.

Главные достоинства Triton Inference Server:

  • Возможность развертывания моделей, натренированных с помощью различных фреймворков глубокого обучения. Речь идет про TensorRT, TensorFlow GraphDef, TensorFlow SavedModel, ONNX, PyTorch TorchScript и OpenVINO. Поддерживается как TensorFlow 1.x, так и TensorFlow 2.x версия. Triton также поддерживает такие форматы моделей, как TensorFlow-TensorRT и ONNX-TensorRT.
  • Параллельная работа и «горячая» замена развернутых моделей.
  • Поддерживает не только модели глубокого обучения. Triton предоставляет API, позволяющий использовать любые алгоритмы, реализованные на Python или C++. При этом все преимущества, которыми обладают deep learning модели развернутые на Triton, сохраняются.
  • Model Pipelines. Когда развернуты несколько моделей, и одни из них ожидают данные от других, модели могут объединяться в последовательности. Отправка запроса на такую совокупность моделей вызовет их последовательное выполнение с передачей данных от одной модели к другой.
  • Возможность интегрировать Triton как компонент (C-библиотеку) в приложение.
  • Развертывание. Проект имеет ряд docker-образов, который постоянно актуализируется и расширяется. В связке с Kubernetes он является отличным решением для развертывания масштабируемой среды для production.
  • Ряд метрик, позволяющих мониторить состояние моделей и сервера.
Из нашего опыта добавим, что хорошо себя показывает связка Triton Server + TensorRT Engine, так как данный формат позволяет добиться максимальной производительности от моделей. Однако здесь следует учесть, как минимум, два момента. Во-первых, TensorRT Engine должен быть скомпилирован на устройстве с такими же GPU/CPU, какие будут использоваться в среде развертывания Triton. Во-вторых, если у вас кастомная модель, вы можете столкнуться с необходимостью самостоятельно реализовывать недостающие операции.

Что касается последнего, это действительно характерно для случаев использования каких-либо нестандартных sota моделей. В случае же использования популярных моделей в сети можно найти ряд TensorRT имплементаций. Например, для проекта, где нам необходимо было натренировать object-detection алгоритм на Рytorch, и развернуть его на Triton, мы использовали связку Pytorch -> TensorRT -> Triton. Реализацию модели на TensoRT взяли отсюда — TensorRTx. Вас тоже может заинтересовать данный репозиторий, поскольку он содержит множество актуальных имплементаций, поддерживаемых разработчиками.

PMML (Predictive Model Markup Language)​

На самом деле PMML — это не библиотека сервинга, а формат сохранения моделей, в котором уже сейчас можно сохранить scikit learn, tensorflow, pytorch, xgboost, lightgbm и многие другие модели ML. В своей практике мы использовали данный формат для выгрузки обученной модели lightgbm и конвертирования результата в jar файл с помощью jpmml транспиллера. В результате у нас получается полностью работоспособная модель, которую можно загрузить в Java/Scala коде и сразу использовать.

В нашем случае главная цель применения такого подхода была в получении очень быстрого ответа от модели. И действительно, в отличии от той же модели на Python, время ответа уменьшилось примерно в 20 раз. Второе преимущество подхода заключается в уменьшении самого размера модели — в транспиллированном виде ее размер стал меньше в три раза. Из недостатков — так как это полностью программный способ работы с моделями, все возможности перетренировки и подмены моделей необходимо предусматривать самостоятельно.

В заключение отмечу, что перечисленные выше три варианта — это не серебряные пули, и за кадром остались и другие подходы. Сейчас мы присматриваемся к TorchServe и пробуем в некоторых проектах решения на основе Azure ML. Названные здесь способы — это то, что хорошо зарекомендовало себя на большинстве наших проектов. Они довольно просты в настройке и внедрении и не требуют много времени. Чтобы получить готовое решение, справиться с ними может и ML-инженер. Конечно, от проекта к проекту требования бывают разные, и каждый раз приходится решать, какой из методов развертывания ML подойдет в конкретном случае. В особо сложных ситуациях однозначно придется кооперироваться с инженерами ML Ops и, возможно, создавать целый ML комбайн из различных методов и сервисов.

 
Сверху