Flo - это компания, управляемая искусственным интеллектом. Мы используем машинное обучение почти во всех частях нашего продукта, от прогнозирования цикла до автоматической модерации в сообществе. Наши модели охватывают годы разработки, изменения архитектуры, источников данных и фреймворков. Для поддержки таких разнообразных и длительных задач мы разрабатываем инфраструктуру машинного обучения и общие принципы, которые позволяют сократить время производства до 80 процентов. В этом посте мы описываем некоторые из наших подходов и инструментов, которые касаются:

  • Вычислительные ресурсы для инженеров машинного обучения
  • Единая среда разработки
  • Защита данных
  • Реестр моделей
  • Метрическое отслеживание
  • Воспроизводимость эксперимента
  • Управление версиями набора данных
  • Модель сервировки

Среда разработки

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

Kubernetes - Распределение ресурсов

Kubernetes долгое время был вариантом по умолчанию для производственных развертываний на Flo. Но его использование не ограничивается долгосрочными задачами, такими как веб-сервисы - с правильным пользовательским интерфейсом Kubernetes действует как идеальный менеджер ресурсов, позволяя инженерам запускать контейнеры разработки с таким количеством ЦП, графического процессора и памяти, которое им нужно.

Так почему бы не предоставить инженерам машинного обучения прямой доступ к консоли управления AWS? Мы рассматривали этот вариант на ранних этапах разработки нашей платформы машинного обучения, но оказалось, что чрезвычайно сложно позволить кому-либо создавать экземпляры EC2, одновременно запрещая другие потенциально опасные действия, такие как предоставление доступа к данным неправильным службам или уничтожение существующих ресурсов. Более того, созданные вручную экземпляры не управляются Terraform (инфраструктура как программный инструмент кода, используемый в Flo), и их можно легко забыть или потерять.

Настоящая проблема - дать инженерам достаточно гибкости, чтобы они могли эффективно выполнять свою работу и не причинять вреда другим. Kubernetes и правильный UI идеально подходят для этой цели.

JupyterLab - Быстрый старт

JupyterLab предоставляет как нужный нам тип пользовательского интерфейса, так и набор инструментов для быстрого старта. Обычно, когда люди упоминают Jupyter, они имеют в виду записные книжки - интерактивное веб-приложение, в котором вы пишете код, запускаете его и визуализируете результаты. Но JupyterLab - это нечто большее: запустив контейнер, вы создаете полную среду разработки с терминалом, многопроектной структурой, предустановленными пакетами и всем, что вам нужно для начала работы.

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

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

В дополнение к S3, все контейнеры JupyterLab совместно используют конфигурацию для Git, сервер отслеживания экспериментов и моделирования, механизм SQL (мы используем Presto), кластер Spark, хранилище функций и т. Д. После входа в систему пользователь получает не только аппаратные ресурсы, необходимые для его задачи. , но также и полностью настроенную среду.

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

VSCode - полная IDE, полностью удаленная

JupyterLab идеально подходит для быстрых экспериментов, но по мере роста вашей кодовой базы все начинает усложняться. Рефакторинг кода, автоматическое форматирование, работа с несколькими ветвями и многие другие практики, к которым привыкли разработчики программного обеспечения, намного проще выполнять в «традиционных» IDE. Но традиционные IDE могут работать только локально или через раздражающе медленное программное обеспечение для удаленного рабочего стола, не так ли?

Оказывается, современные IDE - или, по крайней мере, одна из них, Visual Studio Code - имеют очень широкую поддержку удаленной разработки. С помощью всего нескольких официальных расширений можно запускать пользовательский интерфейс VSCode локально, но сохранить исходный код и запустить интерпретатор на удаленном компьютере через SSH, в контейнере Docker локально или в Kubernetes. И да, удаленный контейнер может быть создан через сервер JupyterLab.

Вот что должен сделать новый инженер машинного обучения, чтобы подключить свой VSCode к удаленному контейнеру:

  • Запустите контейнер через пользовательский интерфейс JupyterLab.
  • Установите kubectl и настройте kubeconfig с достаточными разрешениями для просмотра списка запущенных модулей.
  • Установите расширения VSCode «Kubernetes» и «Remote - Containers».
  • В меню расширения Kubernetes выберите «Рабочие нагрузки → Модули →‹ имя их контейнера ›».
  • В контекстном меню выберите «Присоединить код Visual Studio».

На этом этапе инженер может открыть терминал, создать виртуальную среду, клонировать репозиторий и открыть его как каталог. За исключением нескольких незначительных отличий, UX практически идентичен таковому на локальном хосте.

Что нас поразило, когда мы впервые запустили эту конфигурацию, так это то, насколько хорошо все компоненты интегрированы. Например, VSCode автоматически определяет научный код Python и предлагает запустить удаленный сервер TensorBoard и перенаправить необходимые порты.

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

Несмотря на отличную интеграцию, некоторые привычки все же необходимо скорректировать. Например, поскольку интерпретатор работает на удаленном сервере, вывод изображений через matplotlib, например, из сценария не работает. Однако доступно несколько альтернатив, таких как сохранение графика в файл и построение графика в пользовательском интерфейсе JupyterLab или во встроенных записных книжках VSCode, как показано на изображении ниже.

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

Реестр моделей

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

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

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

  • Создать или изменить сценарий обучения
  • Обновите Dockerfile для обучающего образа, чтобы использовать этот скрипт
  • Зафиксируйте изменения и отправьте в ветку
  • Запуск обучения через конвейер CI / CD

Затем CI / CD запишет Git-хэш фиксации, запустит обучение и сохранит сгенерированный артефакт в S3, используя хеш в качестве версии модели.

Это решило некоторые из проблем, которые у нас были в то время - большинство шагов были автоматизированы, и воспроизвести их стало так же легко, как повторно запустить конвейер CI / CD. В то же время эксперименты стали длиннее и менее удобны, потому что теперь нам приходилось время от времени обновлять Dockerfile, а обучение запускалось с удаленного сервера, что затрудняло мониторинг процесса. Это решение также не касалось сериализации модели - каждый раз, когда мы добавляли новую структуру машинного обучения или изменяли предварительную обработку, нам приходилось обновлять формат хранения.

Конечно, не мы одни в этих проблемах. После некоторого исследования мы обнаружили, что MLflow - популярный инструмент для управления жизненным циклом модели машинного обучения - удовлетворяет большинство наших потребностей. В частности, Реестр моделей MLflow предоставляет унифицированный API для сериализации моделей, созданных в одной из популярных платформ машинного обучения, и сохранения их в указанном месте (локальный диск или S3). Например, чтобы сохранить модель PyTorch, можно просто написать:

my_model = ...
trainer.fit(my_model, data)
mlflow.pytorch.log_model(
    my_model,
    artifact_path="my_model",
    registered_model_name="my_model"
)

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

mlflow.pytorch.load_model("models:/my_model/12")

В следующем разделе мы также рассмотрим нашу настройку MLflow и воспроизводимость экспериментов.

Отслеживание показателей и воспроизводимость

Управление версиями модели на самом деле не имеет смысла без отслеживания показателей каждой версии. К счастью, MLflow охватывает и эту часть. В нашей настройке мы запускаем Сервер отслеживания MLflow, поддерживаемый PostgreSQL (для хранения зарегистрированных показателей) и S3 (для хранения артефактов модели).

Сервер отслеживания предоставляет пользовательский интерфейс как для моделей, так и для показателей. Например, вот экран одной из наших моделей:

Метрики привязаны к так называемым прогонам, которые, в свою очередь, объединяются в эксперименты.

С помощью MLflow вы можете регистрировать любую метрику так же просто, как mlflow.log_metric (имя, значение). Но в большинстве случаев мы регистрируем один и тот же набор значений, таких как гиперпараметры, потери, количество эпох и т. Д. MLflow дополнительно автоматизирует его, предоставляя возможности автологинга для наиболее распространенных фреймворков. Например, таблица на приведенном выше снимке экрана была создана с использованием следующего кода:

mlflow.set_experiment("content_space")
mlflow.pytorch.autolog()
with mlflow.start_run():
    trainer.fit(model, data)

Одна из самых важных частей хорошего эксперимента по машинному обучению - его воспроизводимость. В MLflow это предусмотрено функцией проекта. Однако для проектов MLflow требуется среда Conda или образ Docker. Поскольку не все команды в Flo используют эту конфигурацию, мы не хотели заставлять их переключаться, переписывать свою кодовую базу или каким-либо образом ограничивать их стиль работы. Вместо этого мы разработали небольшую библиотеку, которая регистрирует текущее состояние среды на сервере отслеживания MLflow. При каждом запуске эксперимента эта библиотека записывает:

  • Текущий коммит Git или слово «грязный», если есть незафиксированные изменения
  • Список установленных библиотек
  • Файл (то есть модуль или скрипт), из которого был запущен эксперимент.
  • Аргументы командной строки, если есть

Таким образом, любой эксперимент, который был зарегистрирован в MLflow из чистого состояния Git, можно легко повторить, независимо от того, как и в какой среде он был запущен.

Что дальше

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

В отличие от многих других компаний, работающих над одним продуктом AI, у Flo есть десятки задач, связанных с машинным обучением. Мы прогнозируем симптомы, обнаруживаем признаки проблем со здоровьем, фильтруем спам в секретных чатах, оптимизируем push-уведомления и т. Д. В то же время мы собираем данные о самочувствии пользователей, поисковых запросах, поведении в библиотеке контента, моделях активности и т. Д. Интересно то, что любой из этих источников данных может помочь в любой из этих задач. Например, если пользователь ищет «обезболивающие» в середине своего цикла, скорее всего, это связано с болезненной овуляцией или другими причинами, а не с симптомами ПМС. Средство ранжирования контента может использовать данные о состоянии цикла для определения приоритета наиболее релевантного контента для этого конкретного человека в этот конкретный момент времени.

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

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

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

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

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

Подводя итог, вот схема наиболее важных компонентов нашей инфраструктуры машинного обучения:

Мы нанимаем!

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

Если инструменты, упомянутые в статье, кажутся вам знакомыми или у вас есть альтернативы получше, приходите и присоединяйтесь к нам!