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

Этот пост начинается с мотивов, и я вижу основные проблемы, препятствующие масштабированию. Затем я представлю Docker как решение многих из этих проблем. Наконец, я напишу краткое введение в размещение обучающего кода в образе Docker, который можно развернуть практически где угодно. Если вас интересует только введение в Docker, смело переходите к концу.

Не связанные с ML проблемы обучения модели ML

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

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

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

Что такое Docker и как он помогает в ML?

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

Образ Docker – это решение, которое упаковывает все зависимости приложения. Приложение Docker может использовать эти образы для создания контейнеров, запускающих эти образы. Изображения действительно минимальны. Обычно вы начинаете с чего-то вроде функционального дистрибутива Linux и объявляете все программное обеспечение, которое необходимо установить для запуска вашего приложения, после чего Docker создаст ваш образ. После создания образа его можно развернуть в контейнере на любом компьютере с Linux, Windows или Mac (предупреждение: микросхемы Silicon могут вызвать проблемы). Образ не нужно пересобирать, а это означает, что кодовая база фактически «замораживается» в том виде, в каком она была построена.

Прямо сейчас вы можете подумать, что хотя образ нужно собрать только один раз, процесс выяснения всего, что вам нужно, чтобы получить пустую ОС для запуска обучающего приложения, может быть слишком сложным. К счастью, и на это есть ответ. По мере того, как Docker становился все более популярным, все больше людей использовали его и делали доступными базовые образы. Все созданные и официально поддерживаемые образы можно найти в Docker Hub. Вы можете импортировать базовый образ в свой контейнер, что дает вам преимущество в объявлении всего, что вам нужно. Например, вы можете найти образы с практически любым установленным дистрибутивом Python, а также образы с предустановленными CUDA и cuDNN.

Образы Docker облегчают упомянутые выше проблемы, не связанные с ML. Во-первых, используя сторонние созданные и протестированные образы, вы можете уменьшить нагрузку на обслуживание, связанную с физическими единицами; Вы можете быть уверены, что NVIDIA знает, как правильно установить свои драйверы. Во-вторых, создавая и развертывая обучающий код с помощью изображений, вы можете гарантировать, что код будет работать в одной и той же среде независимо от того, где он развернут. Наконец, воспроизводимость упрощается (хотя и не гарантируется), поскольку вы можете быть уверены, что код каждый раз запускается с одними и теми же версиями пакета, независимо от того, что происходит на хост-компьютерах. Более того, сохраняя версии ваших контейнеров, вы всегда сможете воспроизвести старые модели, не прибегая к магии git, чтобы вернуть свой код в прежнее состояние.

Развертывание обучения машинному обучению в контейнере Docker

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

Dockerfiles (объявления изображений) в сопроводительном коде были созданы для того, чтобы приложение можно было развернуть в AIP Google. Есть некоторые вещи, которые можно пропустить, если вам не нужна эта возможность. Есть два файла Dockerfile, один для обучения на CPU, другой для обучения на GPU. Последний также работает на процессоре, но требует дополнительной настройки. Итак, я буду использовать последний для справки.

Первым шагом в этом процессе будет обучающий код машинного обучения. Образ Docker не зависит от самого обучающего кода точно так же, как Ubuntu не зависит от вашего кода. Итак, для целей этого примера тренировочный код довольно прост, но вы можете быть уверены, что остальная часть работает с более сложными режимами обучения. Когда вы пишете свой код, вы должны хранить подробный список пакетов, которые вы используете (в идеале в файле requirements.txt или setup.cfg), чтобы вам не пришлось проверять их позже. Кроме того, имейте в виду, что ваше приложение должно работать автономно, поэтому не думайте, что у вас будет доступ ко всему, что находится на вашем собственном компьютере. Вы можете копировать данные в контейнер и из него (я расскажу об этом чуть позже), но к этому моменту вы уже можете начать думать о хранении результатов в облаке, чтобы к ним было легче получить доступ. И последнее, что нужно иметь в виду, это то, что самый простой способ запустить контейнер — это сделать это через командную строку; следовательно, удобно включить анализатор аргументов, чтобы вы могли запускать свой учебный контейнер со всеми нужными параметрами. Аргументы, используемые в этом примере, определены в функции get_args.

Далее пришло время создать образ. Ниже этого абзаца вы можете посмотреть фрагмент кода без требований Google AIP. Прежде чем мы приступим к установке чего-либо, нам нужно решить, какой базовый образ мы будем использовать. Для этого примера я решил использовать Tensorflow 2.7.0, быстрый взгляд на таблицу совместимости TF говорит мне, что мне нужны CUDA 11.2 и cuDNN 8.0. Поэтому я могу найти образ в репозитории изображений nvidia/cuda и использовать его в качестве основы. Далее нам нужно выяснить, какую версию Python получить и использовать. Опять же, из таблицы совместимости мы знаем, что можем использовать Python 3.7–3.9, для этого примера мы будем использовать 3.8. Далее нам нужно скопировать требуемый код в образ, то есть однострочник Docker. Затем мы переходим в только что скопированный каталог и устанавливаем все как редактируемый пакет с помощью pip, это также установит все необходимые зависимости Python. Наконец, мы определяем точку входа для нашего контейнера как команду python3 aip_trainer/trainer.py. Точка входа — это команда, которая будет выполняться при запуске контейнера.

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

docker build -f dockerfiles/Dockerfile-gpu -t <image-name>:<label>

Затем вы можете запустить свой образ в контейнере, выполнив:

docker run -t <image_name>:<label> --arg1 val1 --arg2 val2 ...

Если вы хотите запустить свой код на машине с графическим процессором, на этой машине должен быть установлен NVIDIA container toolkit. Затем вы сможете ускорить свой контейнер, выполнив:

docker run --runtime=nvidia -t <image_name>:<label> --arg1 val1 --arg2 val2 ...

Пройти лишнюю милю

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

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

Как только вы достаточно хорошо изучите Docker, вы сможете расширить свои знания на другие области машинного обучения. Например, изображения также используются для определения пользовательских компонентов для Kubeflow Pipelines, инструмента, который широко используется для создания конвейеров ML с учетом MLOps. С его помощью вы можете использовать пользовательские компоненты для ETL данных, предварительной обработки, обучения моделей и логического вывода.

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

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

Хотите работать в nPlan? Посетите нашу страницу вакансий!