Не помещайте свои модели машинного обучения в AWS EBS

(при запуске из снапшотов)

Вот что я хочу. Мне нужен AMI, который я могу запускать в инстансе Amazon EC2 (с графическим процессором), чтобы запускать модель каждое утро вторника. Экземпляр должен загрузить модель, выполнить работу и затем умереть. Я хочу, чтобы все выполнялось как можно быстрее, и я хочу быть на 100% уверен, что изображение умрет, чтобы избежать больших счетов AWS.

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

Если вы просто хотите знать, почему НЕ EBS, перейдите ко второму разделу статьи и игнорируйте код.

Шаговые функции + Лямбда + EC2

Идея состоит в том, чтобы создать рабочий процесс пошаговой функции, который будет запускаться событием вторник Cloudwatch. Рабочий процесс будет последовательно выполнять следующие действия:

  1. Запустите Lambda, который запустит экземпляр EC2; Лямбда возвращает идентификатор экземпляра, который был запущен
  2. Следите за активностью инстанса EC2; программа, работающая внутри нашего экземпляра, должна запустить действие, отправлять тактовые импульсы каждую минуту, а затем сообщать об успешном выполнении задачи.
  3. Запустите ту же Lambda, которая завершит работу экземпляра EC2, используя предоставленный идентификатор экземпляра.

Вот спецификация языка Amazon States для этого рабочего процесса.

Нет, мы передаем идентификатор AMI и действие «start» в функцию Lambda, чтобы запустить экземпляр, и идентификатор AMI, действие «stop» и сгенерированный идентификатор экземпляра для остановки экземпляра. Наша лямбда-функция должна читать строку «действие» и запускать или завершать экземпляр.

Почему EBS не подходит для моделей машинного обучения?

Моя модель ML была около 5 ГБ. Не такая уж большая модель, но эй, я не OpenAI, и они (OpenAI) меня даже не любят (все еще ждут доступа к GPT-3).

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

Я был неправ.

Загрузка модели 5 ГБ на мой настольный сервер занимает около двух минут. Та же модель заняла 20–30 минут для загрузки из EBS. Все это время графический процессор в основном спит, ожидая завершения ввода-вывода - пустая трата времени и денег.

Пожалуй, самое удивительное, что в этом нет ничего удивительного!

AWS предупреждает о сценариях, в которых образы EBS загружаются из моментальных снимков:

Для томов, созданных из моментальных снимков, блоки хранилища должны быть извлечены из Amazon S3 и записаны в том, прежде чем вы сможете получить к ним доступ. Это предварительное действие требует времени и может вызвать значительное увеличение задержки операций ввода-вывода при первом обращении к каждому блоку.

Облом! Исходя из вышеизложенного, нашей программе придется ждать, пока модель будет скопирована из S3 в EBS, каждый раз, когда мы запускаем новый экземпляр из AMI. Хотя S3 может быть быстрым, процесс синхронизации, реализованный AWS, довольно медленный.

Идеи?

Вот один.

Тома EBS - это сетевые диски. Они медленные и не предназначены для большого количества операций ввода-вывода. Для большего количества операций ввода-вывода вам понадобятся SSD-накопители с прямым подключением (без сети).

И угадай что. Экземпляры GPU поставляются с SSD-дисками, подключенными в качестве временного хранилища. Например, экземпляр g4dn.xlarge поставляется с твердотельным накопителем NVMe емкостью 125 ГБ, доступным на устройстве “/dev/nvme0n1”. Woohoo!

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

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

Как насчет стоимости трансфера? Если ваша корзина S3 и экземпляр находятся в одном регионе, вы платите 0,02 доллара США за каждый скопированный ГБ. Для 5 ГБ это 10 центов, что на 50% дешевле, чем 20 минут самого дешевого экземпляра g4dn.

Это может показаться нелогичным. Почему копировать данные при каждом запуске быстрее и дешевле, чем запускать с данными уже в образе? Собственно, так и должно быть. Большая часть содержимого томов EBS (файлы и библиотеки ОС) никогда не читается, и поэтому нет необходимости в большом количестве операций ввода-вывода. При необходимости следует использовать временное хранилище.

Приступаем к работе

Я сказал, что временный диск подключен к “/dev/nvme0n1” (согласно панели инструментов AWS), но я обнаружил, что это не так в экземпляре Ubuntu Machine Learning Base AMI.

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

sudo nano /etc/rc.local
mkfs -t xfs /dev/nvme1n1
/dev/nvme1n1 ~/<YOUR ML MODEL DIRECTORY>
sudo chmod a+x /etc/rc.local

Если вы запускаете свою программу в контейнере докера, вам также необходимо смонтировать указанный выше каталог в докере, используя флаг -v:

sudo docker run -ti — gpus all -v ~/<YOUR ML MODEL DIRECTORY>:/app/<YOUR ML MODEL DIRECTORY> — name [NAME] [IMAGE]

Уроки выучены

То, что «очевидно» должно работать, не всегда работает, но из этого может получиться хорошая статья.