Чему мы научились, создавая платформу MLOps с ограниченными средствами в DPG Media в Нидерландах

Однократное развертывание модели машинного обучения — простая задача; многократно внедрять модели машинного обучения в производство намного сложнее. Для решения этого сложного процесса появилась концепция MLOps (Machine Learning Operations). MLOps представляет собой конвергенцию методов DevOps, машинного обучения и разработки программного обеспечения. Здесь необходимо несколько нюансов, но лучшее определение того, что именно влечет за собой MLOps, — это открытое обсуждение и поле битвы для поставщиков за продвижение своих продуктов. Для краткости я лучше перейду к нашей истории MLOps.

Наш путь к MLOps начался примерно в сентябре 2021 года. Наша команда была создана всего шесть месяцев назад, и мы начали с нескольких унаследованных проектов. На бумаге цель нашей команды была проста: мы должны были предоставить платформу обработки данных и машинного обучения для онлайн-сервисов, части DPG Media, ориентированной на веб-сайты и сообщества. Наше «портфолио» состояло из дюжины брендов, среди которых были: популярный сайт технических новостей и его сообщество, два портала по трудоустройству, сообщество для будущих родителей, несколько сайтов, где можно было купить подержанные автомобили, и еще парочка с похожие аудитории. Это относится к остальной части поста.

В то время часть команды машинного обучения состояла только из Data Scientist и меня, инженера по машинному обучению. Нас обоих наняли с разницей в две недели, совершенно новых для организации, в которой мы должны были работать.

Тогда наш производственный ландшафт машинного обучения (я использую этот термин снисходительно) выглядел следующим образом:

  • Задание рекомендаций для предоставления предложений пользователям, работающим в Spark через Airflow для бренда №1.
  • Модель ценовых предложений, дающая предложения по автомобилям, также запущенная из Airflow в качестве пакетного задания для бренда № 2.
  • Модель для целевой аудитории в Databricks в виде запланированной записной книжки, которая снова выполняется как пакетное задание для бренда № 3.
  • Единое фляжное приложение на EC2, которое загружало в память различные модели для облегчения демонстрации и демонстрации проектов для различных брендов.

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

Два специалиста по данным, которые сейчас ушли, выполнили все предыдущие проекты. Большинство их проектов работали в Jupyter Notebooks, а приложение Flask, которое их обслуживало, размещалось на EC2 и часто зависало. Один сервер MLflow работал на EC2, но он устарел, и с ним были некоторые проблемы с безопасностью. Проект Databricks был всего лишь одной записной книжкой, даже без контроля версий. Мы даже не знали, кто заплатил за кластер, на котором у нас была запланирована работа.

Нашей команде нужно было масштабироваться, брать больше проектов и тратить совсем немного времени на поддержку старых. Мы не могли позволить себе продолжать в том же духе, особенно если мы хотели проводить вывод в реальном времени. Стали появляться хорошие возможности для машинного обучения, и наши клиенты требовали живые модели. Необходимость структурированного подхода к MLOps очевидна.

Составление плана

Мы могли рассчитывать на некоторую помощь инженеров данных (в нашей команде было четыре выделенных инженера данных), архитекторов и системных инженеров DPG, но было ясно, что мы сами должны владеть платформой. Наши дата-инженеры, в частности, были натянуты, у них были свои сроки и миграции. В будущем нам нужно было управлять и обновлять наши системы. Мы должны были владеть им сами.

Мы организовали несколько мозговых штурмов внутри нашей команды и взяли интервью у нескольких архитекторов в организации. Медленно, но верно вещи становились все более высеченными на камне и менее нацарапанными на белой доске в каком-то темном углу на пятом этаже нашего офиса. Мы хотели дать MLflow еще один шанс и попытаться сохранить как можно больше на AWS. В конце концов, было ясно, что AWS SageMaker развивается в сторону более зрелой платформы. Один из руководителей другой команды убедил нас адаптировать Terraform (или какую-то форму IaC) на раннем этапе. Поскольку наши инженеры данных уже использовали Terraform, это стало краеугольным камнем нашей платформы.

Я присоединился к сообществу MLOps, чтобы узнать больше об инструментах, и провел пару бесед с поставщиками. Начали ходить на встречи. К счастью, у нас была команда корпоративной поддержки AWS, которая также могла помочь нам, поскольку мы уже являемся крупным пользователем AWS. Появилось множество идей, возможно, даже слишком много. Сцена MLOps была (до сих пор) немного запутанной, и этого и следовало ожидать; для нас было важно двигаться быстро и решать, что для нас важнее всего.

В конце концов мы решили, что принципы платформы будут примерно следующими:

  • Делайте все в Terraform,если только мы не можем...
  • Старайтесь придерживаться сетки данных (которую наша организация адаптировала в 2021 году), если только...
  • По возможности используйте управляемые службы, если только...
  • Перейдите на бессерверную версию, если только...
  • Избегайте Kubernetes как можно дольше
  • Создавайте по ходу работы и переносите старые проекты, когда мы их пересматриваем

Артефакты моделей и отслеживание экспериментов и наш первый MLOOPS

Несмотря на намерение мигрировать только тогда, когда это необходимо, одной из первых вещей, которые мы попытались, было перенести сервер MLflow на AWS Fargate и иметь базу данных на AWS RDS вместо того, чтобы работать на том же экземпляре EC2, что и сервер. Для каждого бизнес-подразделения мы решили разместить по одному экземпляру с отдельными серверами для тестирования и производства. С четырьмя BU это будет означать почти идентичные настройки 4 x 2.

Это оказалось довольно дорогой идеей (8 копий этой установки, все со своими собственными балансировщиками нагрузки и базами данных!), И количество проектов, которые мы делали, еще далеко не оправдывало этого. Позже мы сведем это число к двум случаям. Начинать с такого масштаба означало также разбираться с terraform, эластичными балансировщиками нагрузки, IAM и route 53. Кривая обучения была довольно крутой, и много времени было потрачено на ознакомление со всеми различными частями AWS.

Наш первый ML-OOPS пытался настроить массу (дорогих) экземпляров и поддерживать их задолго до того, как они понадобятся.

Для экспериментов (блокноты Jupyter) мы решили использовать экземпляры Notebook AWS SageMaker. Экземпляры ноутбуков поставлялись со сценарием жизненного цикла, который устанавливал правильный UR MLflow в качестве переменной среды. Мы создали несколько сценариев для их массового обновления, а также для мониторинга самих ноутбуков, например, для создания оповещения в наших неактивных каналах, если кто-то оставил свой экземпляр в нерабочее время.

Развертывание модели и обучение

Вскоре пришло время развернуть наши первые модели. Мы использовали конечные точки модели SageMaker и остановились на настройке шлюза Lambda и API. SageMaker, по сути, может быть универсальным магазином для развертывания, хотя вы платите больше за развертывание собственных экземпляров EC2 и размещение собственных моделей. Это дороже, чем пытаться запустить все самостоятельно в кластере Kubernetes, которым вы управляете самостоятельно. Тем не менее, вы получаете много за премию, которую вы платите. SageMaker обрабатывает различные стратегии развертывания, автомасштабирование и позволяет нам выбирать типы графических процессоров, когда это необходимо.

Наши модели были легко развернуты с помощью SageMaker SDK как из локальной, так и из облачной среды (например, ноутбук Jupyter или Airflow). AWS Lambda дал нам дополнительный контроль над входом и выходом в модель, а API Gateway предоставил спокойный интерфейс, который мы могли использовать с ключами API для наших пользователей. Кроме самой модели, все элементы развертывались через terraform, а добавление новых моделей заключалось в простом добавлении модуля terraform, в основном с указанием имени и того, откуда брать код лямбды. Это также означало, что мы могли улучшить (предварительную) обработку модели без изменения конечной точки SageMaker и настроить CI/CD для лямбда-выражений отдельно.

Обучающие задания также были делегированы SageMaker. Потребовались значительные усилия, чтобы создать шаблон для наших первых нескольких учебных заданий ML (модели LSTM для категоризации текста, созданные с помощью TensorFlow) и зарегистрировать их в MLflow из внутри контейнера учебного задания. Мы сделали общий шаблон для обучающих заданий. SageMaker достаточно самоуверен в отношении того, как он хочет получать учебные задания, а это означает, что вам необходимо придерживаться определенных соглашений платформы — даже при использовании TensorFlow. К счастью, внутри службы моделей SageMaker по-прежнему используется TensorFlow Extended для моделей TensorFlow, поэтому с SavedModels есть некоторая интуитивно понятная работа.

Мы организовали наши обучающие задания из Airflow и явно не включали переобучение при слиянии кода. Некоторые из наших моделей довольно дорогие, некоторые нет, но почти все требуют больших вычислительных ресурсов или хранилища. При необходимости перед запланированным запуском мы можем просто активировать dag и запустить конвейер.

Мониторинг и оповещение

Последним пунктом в нашем списке покупок AWS был мониторинг и оповещение. Сначала мы опробовали Amazon Managed Prometheus и Amazon Managed Grafana, надеясь, что сможем каким-то образом получить туда данные, которые мы видели в CloudWatch, и сэкономить на наших расходах на CloudWatch. Оказалось, что это возможно с инструментами экспортера. Мы нацелились на YACE (еще один экспортер облачных часов), но это должно было где-то жить. Где-то скоро будет EC2, а позже и ECS.

У нас также были некоторые показатели, поступающие от одного из наших бизнес-подразделений, которые нам нужно было отслеживать самим. Это означало, что нам нужен был какой-то интерфейс, с которым они могли бы взаимодействовать. Сначала это казалось возможным благодаря возможности удаленной записи Managed Prometheus, но нам нужно было больше контроля, и мы все равно настраивали YACE (который Prometheus должен был очищать каждые пять минут). Мы решили переместить YACE и Prometheus в кластер ECS и настроить Remote Write плюс pushgateway для получения метрик из-за пределов нашей среды. Наконец, мы отказались от Amazon Managed Prometheus.

К сожалению, YACE не поддерживал все сервисы AWS, которые мы использовали. Нам не хватало экспорта для SageMaker, и мы были в полном неведении относительно конечных точек нашей модели. К счастью, экземпляр Grafana, управляемый Amazon, также получает статистику из CloudWatch, опять же с небольшой надбавкой.

В Amazon Managed Grafana мы создали универсальную панель мониторинга, которую преобразовали в шаблон, взяв модель json и настроив ее параметрами. Как только это было сделано, мы развернули информационные панели для каждой модели через terraform. К сожалению, Amazon Managed Grafana требует ключ API для работы нашего terraform и ci/cd, максимальный срок действия которого составляет 30 дней. Мы настроили Lambda с ротацией ключей для уничтожения и повторного создания ключа каждые 29 дней и сохранения его в секрете AWS, который мы можем запросить в нашем коде терраформирования. Результатом этого является то, что при развертывании модели мы теперь можем автоматически генерировать API, средства мониторинга и ведения журналов, а также настраиваемую информационную панель в течение нескольких секунд.

Поскольку Grafana также может быть настроена на отправку оповещений, когда метрики превышают определенный порог, эта настройка также позволяет нам запускать оповещения о проблемах и пересылать их в slack или OpsGenie. Поскольку нас по-прежнему было двое, мы составили график дежурств, в котором каждый из нас брал на дежурство по неделе. Хитрость заключается в том, чтобы никогда не определять предупреждение с высоким приоритетом.

Полученные результаты

Получившаяся в результате инфраструктура довольно легковесна, и внимательный читатель заметит, что на самом деле она не стремится полностью автоматизировать что-либо от начала до конца. В настоящее время у нас есть около 15 моделей, развернутых для логического вывода в реальном времени, через год командой из двух человек. Выше представлен вид платформы, ориентированный на AWS, а приведенный ниже план с использованием шаблона AI Infrastructure Alliance дает обзор функций стека на данный момент.

Мы хотели быть гибкими и чувствовали, что переход на более сложную структуру «сделай все за нас» может быть более ограничивающим и более дорогостоящим. Мы стараемся не делать сильных предположений. Например, не каждый проект получает свежие данные или имеет доступ к отзывам с производства. Возможно, нам не разрешено постоянно хранить прогнозы. Не все модели развернуты в SageMaker (некоторые прекрасно работают в Lambda!).

Как и в недавнем посте Лака Лакшманана (триггерно озаглавленном Нет, вам не нужны MLOps) и ставшей теперь известной серии блогов MLOps без особых операций (Вам не нужна большая лодка), у нас есть платформа, которая стремится к простоте.

Тем не менее, у нас было много потребностей при создании платформы. Диаграмма высокого уровня жизненного цикла машинного обучения с нанесенными на карту нашими потребностями показывает, что теперь мы покрываем большинство из них.

Мысли вперед

Итак, теперь мы много говорили о том, что мы создали и как это вписывается в общую картину. Что ждет нас дальше?

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

Будучи медиа-компанией, у нас есть модели, которые работают с текстом, изображениями, потоками кликов, графиками, векторами и табличными данными. Некоторые модели используют несколько типов данных. Модели могут включать что угодно, от XGBoost и Random Forests до Transformers и различных рекуррентных нейронных сетей и сверточных нейронных сетей. Как мы могли вообще надеяться построить или купить что-то для тестирования всех типов данных и всех моделей?

Еще одна проблема, которую необходимо решить, — это сокращение времени холодного запуска наших лямбда-функций. Лямбда-функции — это функции как службы, которые запускаются при вызове. После первого вызова лямбда остается активной в течение примерно 15 минут, если не последует другой вызов, до максимального срока службы около двух часов. При выделении ресурсов и образа для лямбды в первый раз происходит холодный пуск. Иногда это несколько секунд, но добавьте импорт TensorFlow в Lambda, и вы не удивитесь, увидев тайм-аут ваших API.

Это жизненный факт, присущий использованию лямбда-выражений, но это означает, что нам или пользователю API нужна обработка ошибок, чтобы справляться с ними, если они продолжаются слишком долго. Хотя рекомендуется не использовать лямбда-выражения для небольших объемов трафика, это, безусловно, самый дешевый вариант, который у нас есть, и он помогает компенсировать надбавку к стоимости, которую мы имеем для SageMaker. Кроме того, они невероятно просты в обслуживании. Однако то, является ли холодный запуск проблемой, полностью зависит от бизнес-контекста и объема запросов.

Я надеюсь в какой-то момент отказаться от нашего собственного MLflow. Он не имеет доступа на основе ролей. Это означает, что каждый пользователь может видеть (и удалять) каждую модель, и пользователям нужно будет просмотреть потенциально сотни моделей, чтобы найти ту, которую они ищут. Существует также когнитивная нагрузка для его использования; любой Data Scientist, использующий его, должен будет активно уделять внимание настройке своего эксперимента и вызову таких вещей, как mlflow.log или mlflow.autolog. Поскольку мы не используем возможность развертывания с MLflow на SageMaker, мы можем переключиться на один из многих других инструментов в этой нише. Мы буквально используем MLflow только как способ отслеживать прошлые запуски модели.

Заключительные мысли

Таким образом, в этом посте я рассказал о нашем процессе создания стека MLOps, соответствующего нашим потребностям. Мы использовали сервисы AWS и инструменты с открытым исходным кодом, чтобы выбрать набор инструментов, который позволит нам справиться с большинством наших сценариев использования. Он будет продолжать развиваться с течением времени по мере развития нашей команды. Наши основные выводы:

  • Перейдите на управляемые услуги и не оглядывайтесь назад. Если ваша команда относительно небольшая, рекомендуетсяперейти на управляемые услуги, чтобы у вас не было таких накладных расходов.
  • Получите Sagemaker. Sagemakerотлично подходит для небольших команд и отлично подходит для развертывания (не обновлений, но об этом в другой раз), но требуется некоторое время, чтобы привыкнуть к нему.
  • Плывите по течению. Airflow и MLFlow — отличные инструменты в стеке машинного обучения, потому что они позволяют оркестровать и вести учет машинного обучения, что опять же позволяет вам сосредоточиться на наиболее важной работе.
  • Инфраструктура как код — это 10-кратный облачный мультипликатор. Нет, серьезно. Удивительно, как много работы избавил нас от Terraform.

Я надеюсь, что это полностью открытое обсуждение позволит другим командам определиться со своим стеком и оценить свои потребности. Надеемся, что в будущем платформы и инструменты, которые мы использовали, станут более зрелыми и лучше интегрируются.

Этот пост получил помощь от Gido Schoenmacker, Joost de Wit, Kim Sterenborg и Amine Ben Slama.

Джеффри Луппес — инженер по машинному обучению в компании DPG Media в Амстердаме, Нидерланды.