Ваши ученые были так озабочены тем, смогут ли они это сделать, что даже не задумались, стоит ли им это делать

Абстрактный

В этом посте я описываю процесс создания и развертывания бота Discord на основе Python, который подключается к принадлежащему мне серверу Discord и отвечает на запросы пользователей пользовательскими изображениями аниме-персонажей, созданными искусственным интеллектом. В качестве серверной части я использую модель StyleGAN, реализованную в ONNX и развернутую в спотовом парке AWS (моя полная облачная инфраструктура использует EC2, S3 и SecretsManager). Я познакомлю читателя с высокоуровневым обсуждением модели и реализации, кодом, который я использовал для создания выводов о модели в Discord, и, наконец, облачной инфраструктурой, которую я настроил для устойчивого развертывания. Весь мой код доступен по адресу https://github.com/jfreds91/waifu_bot.

Мотивация

Этот проект начался, когда я наткнулся на This Waifu Does Not Exist (TWDNE), страстный проект Гверн Бранвен, который демонстрирует две современные модели машинного обучения, используемые для создания: а) уникальных изображений персонажей аниме (StyleGAN) и б) сопроводительное текстовое описание для каждого (ОПТ-3). Изображения ниже являются примерами, и я должен подчеркнуть, что это полностью оригинальные произведения искусства, сгенерированные нейронной сетью. Хотя в некоторых случаях они могут иметь сходство с существующими персонажами, они уникальны — нейронная сеть рисует их позу, выражение лица, цвет волос и глаз, фон и художественный стиль самостоятельно, на основе ввода случайного шума. Я нашел эту возможность невероятно впечатляющей и подумал, что моим друзьям понравится возможность использовать эту модель для создания своих собственных иллюстраций (кто бы этого не сделал), поэтому приступил к работе над кооптацией базовой модели и выяснением того, как ее развернуть. сам.

Модель

Немного контекста машинного обучения. В декабре 2018 года исследователи NVIDIA опубликовали статью о своей новой архитектуре модели нейронной сети StyleGAN. GAN, или генеративно-состязательные сети, стремятся генерировать высококачественные выходные данные (в данном случае изображения) из случайных входных данных, и StyleGAN показал себя как технологический скачок вперед, который может научиться устранять неоднозначность абстрактных целевых характеристик (таких как возраст, цвет глаз, фон). цвет) для создания чрезвычайно убедительных изображений. Когда архитектура модели была открыта в 2019 году, исследователи со всего мира смогли переобучить модель StyleGAN в соответствии со своими потребностями, а в случае с TWDNE Гверн обучил модель StyleGAN на специально подобранном наборе данных из более чем 3 миллионов данных. изображения персонажей аниме. Гверн много писал о своем процессе в своем блоге здесь. Гверн обучал StyleGAN в течение › 2 недель на 4 высококачественных графических процессорах потребительского уровня, и он и его сотрудники представили версии готовой модели Tensorflow, PyTorch и ONNX. Чтобы использовать его, мне просто нужно загрузить интересующую меня модель, а затем написать вспомогательный код для вызова модели для вывода.

Кроме того, я решил использовать модель ONNX. Он оказался самым компактным из трех (118 МБ в отличие от модели TF на 320 МБ), но я специально выбрал его, чтобы опробовать среду выполнения ONNX. ONNX — это общая платформа взаимодействия моделей, представленная Facebook и Microsoft в 2017 году, которая позволяет пользователям запускать модели, не зависящие от фреймворка, путем преобразования в собственный общий формат. В моем случае это означает, что мне не нужно беспокоиться ни о каких библиотеках, связанных с обучением модели, потому что я использую общую среду выполнения. Если кто-то придет и обучит новую версию модели, используя другую библиотеку, пока он предоставляет версию модели ONNX, для меня это просто подключи и работай.

Примечание для читателя: судя по блогу Гверна, эта реализация SyleGAN на самом деле обучается как на мужчинах, так и на женщинах — и на самом деле, во время моих экспериментов я обнаружил как традиционно женские, так и традиционно мужские результаты. Гверн также предоставила версии для трансферного обучения, обученные на наборах данных только для мужчин и женщин, но я предпочел работать с версией для мужчин и женщин.

Аниме-лицо StyleGAN на самом деле имеет мужские лица в своем наборе данных, поскольку [Gwern] не фильтровал — просто женские лица встречаются чрезвычайно часто (и также может быть, что мужские аниме-лица относительно андрогинны… [и это может быть] сложно) определить разницу между женщиной с короткими волосами и [мужчиной]).

Локальное развертывание

Имея модель в руках, моей первой задачей было написать код только для вызова модели. Я использовал библиотеку Python onnxruntime для загрузки модели и выполнения логического вывода. Модель принимает два входа: массив [512,512] случайного шума и константу «усечения», которая используется в модели для предварительной обработки шума. Константа усечения, равная 1, означает, что модель будет сбрасывать любые значения шума за пределами 1 стандартного отклонения до среднего значения генеральной совокупности, что заставляет модель генерировать более «консервативные» изображения. Увеличение члена усечения дает модели более «художественную лицензию», но рискует внести артефакты.

Достаточно легко; Я могу использовать numpy и PIL для генерации ввода, преобразования вывода (массива) в стандартный формат jpeg и сохранения полученного изображения. (В частности, мне нужно удалить пакетное измерение и переупорядочить оставшиеся размеры как строку/столбец/канал перед сохранением в формате jpeg.) Теперь я могу создавать аниме-персонажей на своем ноутбуке, когда захочу, и, по общему признанию, я потратил некоторое время. делать именно это.

Затем я хотел поделиться этой новообретенной силой со своими друзьями. У меня есть активный сервер Discord, где я тусуюсь с друзьями, и я решил написать простого бота, который бы жил на сервере, прослушивал ключевые слова в текстовых каналах и отвечал при вызове, генерируя и размещая изображение на канал. Для начала мне пришлось сгенерировать токен с соответствующими разрешениями, чтобы разрешить моему боту подключаться к Discord, а затем написать поддержку Python, чтобы использовать этот токен и подключаться к Discord с помощью Discord API. API позволяет мне определить объект bot, который инициирует и поддерживает соединение с моим сервером Discord. Я могу просто определить поведение своего бота, а затем вызвать bot.run(token). Запустив этот скрипт, я вижу, что мой бот внезапно появляется в сети на Discord.

Перед подключением написанный мной бот создает сеанс onnxruntime и загружает модель для логического вывода. Я написал несколько прослушивателей событий, которые запускают асинхронные действия бота в соответствии с выбранными мною ключевыми словами; основной отвечает на «$claim_waifu», запуская вывод модели, сохраняя полученное изображение в виде временного файла, а затем публикуя изображение вместе с неким художественным текстом. Операции onnxruntime сильно распараллелены, и задержка между запросом и ответом составляет всего около одной секунды.

Выделенное развертывание EC2

Это здорово, но есть проблема. Теперь у меня есть бот, который постоянно работает на моем локальном ноутбуке. Если я перезагружу свой ноутбук, или потеряю интернет, или случайно обновлю Python в своей виртуальной среде до версии 3.9, у меня будет время простоя бота, когда мои пользователи внезапно не смогут получить свои драгоценные вайфусы. Неприемлемо.

Одним из решений было бы приобрести сервер без операционной системы, установить ОС, настроить избыточность данных и сети, нанять администратора сервера для планирования и выполнения обслуживания, а затем развернуть мой сценарий оттуда. Или еще лучше, просто разверните мой скрипт в облаке — введите AWS, GCP, Azure и т. д. Я решил использовать AWS, потому что у меня уже была учетная запись.

Достаточно просто. Я могу развернуть экземпляр EC2, запускающий образ машины по моему выбору, на выбранном мной оборудовании и назначить политику безопасности, чтобы разрешить моему IP-адресу подключаться по ssh и контролировать его поведение. Я выбрал машину t2.medium, которая дала мне 4 ГБ ОЗУ — экспериментальным путем я узнал, что процесс Python на моей машине потреблял tp 3,4 ГБ ОЗУ при выполнении логического вывода, компромисс между пространством и временем, которым я доволен. Я могу развернуть его с помощью пары ключей ssh, чтобы использовать для безопасного подключения к нему, и как только он будет запущен, подключитесь по ssh к моему репозиторию git, чтобы загрузить исходный код, используйте scp, чтобы добавить все, что может отсутствовать в моем репозитории git (модель , токен Discord) и, наконец, запускаю процесс моего бота. Я настроил группу безопасности, чтобы разрешить весь исходящий трафик, поэтому EC2 без проблем устанавливает соединение с Discord API.

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

Развертывание спотового флота

Однако была еще одна проблема. Поскольку мне требовалось 4 ГБ ОЗУ, я не мог использовать оборудование, имеющее право на «уровень бесплатного пользования» (t2.micro с 1 ГБ ОЗУ дал бы мне 12 месяцев бесплатного времени работы), и поскольку экземпляр всегда должен быть up, теперь я плачу за 730 часов вычислений в месяц. Это составляет всего лишь 40 долларов в месяц, выставляемых на счет моей учетной записи AWS, что является большой платой за нарисованный компьютером вайфус, особенно с учетом того, что большую часть времени мой экземпляр EC2 просто простаивал.

Мне пришло в голову два решения.

  1. Я мог бы настроить t2.micro в качестве слушателя, который мог бы работать все время, но при необходимости вызывать функцию лямбда для выполнения логического вывода. Год бесплатного прослушивания Discord, и я плачу только за выводы, когда они мне нужны.
  2. Я мог бы перейти с выделенного инстанса EC2 на спотовый инстанс. Спотовый инстанс может сэкономить мне примерно 70 % в месяц за счет потенциальной стоимости времени безотказной работы, если спотовая доступность уменьшится.

Я выбрал решение 2 по нескольким причинам. Во-первых, переход на более сложную инфраструктуру EC2-Lambda потребует вдумчивого рефакторинга кода и дополнительного тестирования, а также создаст больше потенциальных точек отказа (дополнительная сеть и управление активами с моей стороны). Кроме того, потенциально это может привести к задержке из-за динамической загрузки модели в Lambda или дополнительной передачи файлов из Lambda в EC2. С другой стороны, переход на спотовый инстанс позволил бы мне сохранить весь мой код почти точно таким же и сохранить текущее поведение с риском потерять мой инстанс, если спотовая цена поднимется выше установленного порога, но есть способы смягчить это.

Войдите в Спот флот. Запрос спотовой группы позволяет мне определить целевую емкость рабочей нагрузки и набор правил, которые AWS будет использовать для выполнения этой емкости с помощью выделенных инстансов EC2, спотовых инстансов или того и другого. В моем случае мне нужен только один спотовый инстанс за раз, но я могу написать запрос, который позволит AWS выбирать из множества типов оборудования, которые соответствуют моим потребностям. Таким образом, например, если нет доступных спотовых инстансов t2.medium (AWS сообщает о 5–10% простоя спотовых инстансов t2.medium), я могу перенести свою рабочую нагрузку на t3.medium, t2.large и т. д. иногда это может означать немного более высокую плату за спотовые инстансы (на момент написания статьи спотовые инстансы t3.medium стоят 0,0125 долл. США в час, а t3.large — 0,025 долл. США в час), но я могу указать, чтобы AWS всегда выбирал вариант с наименьшей стоимостью, и я также могу установить потолок того, сколько я готов предложить. Все спотовые инстансы в аппаратных классах, которые я в итоге выбрал, по-прежнему обходятся дешевле, чем выделенный t2.medium, поэтому даже переход на более крупный инстанс по-прежнему дает мне экономию средств. Если бы я хотел, я мог бы даже разрешить моему флоту использовать выделенные инстансы, если бы не было доступных спотовых инстансов, чтобы гарантировать постоянное время безотказной работы, но пока я пропущу это.

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

Чтобы автоматизировать развертывание бота, мне нужен был способ разместить мой код на экземпляре. Я мог бы добавить ssh пару ключей ssh ​​к экземпляру и использовать его для клонирования моего репозитория git, как я делал ранее, но немного более простой подход — просто сохранить заголовок моей главной ветки git в S3 и позволить экземпляру получить его из там. Таким образом, я также могу хранить свою модель ONNX вместе со своим кодом (не рекомендуется использовать github для хранения файлов данных) и позволить EC2 получать все из одного места. Каждый раз, когда я вношу новые изменения в свой репозиторий кода, мне просто нужно гидратировать определенную мной корзину S3 — это также можно автоматизировать (например, с помощью действий github).

Здесь я создал корзину S3 для размещения своего кода и модели. Обратите внимание, что теперь у меня есть папка aws/ — раньше ее не было. Мне пришлось сделать одно небольшое дополнение к моей кодовой базе, чтобы это заработало.

Помните, мне нужен был токен для подключения к Discord? Это еще одна вещь, которую я бы не хотел хранить в github. Если бы кто-то получил этот токен, он мог бы сам подключиться к моему Discord. Локально я читал файл учетных данных .gitignore, содержащий токен, но я не хочу публиковать этот файл на S3. Лучше использовать Менеджер секретов, ресурс AWS, предназначенный именно для этой цели. Я ввел свою личную информацию в AWS Secrets Manager и создал вспомогательный скрипт Python в новой папке aws/, чтобы читать из нее, если не удается найти исходный файл учетных данных. Все, что мне нужно было сделать дальше, это изменить роль шаблона запуска, чтобы разрешить доступ к Secrets Manager, что достаточно просто.

Теперь все готово для моего определения шаблона запуска. Я создаю свои требования к ОС, оборудованию и паре ключей здесь:

И я ввожу свой сценарий запуска здесь:

Сценарий запуска устанавливает пакеты, необходимые для запуска среды выполнения ONNX, загружает мой код с S3, устанавливает Python и pip, устанавливает необходимые пакеты Python из моего файла требований и запускает моего бота, вывод которого перенаправляется в файл журнала.

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

Как видите, я запросил группу с целевой емкостью 1 инстанс, с 0 по требованию, что означает, что он всегда будет выбирать спотовый инстанс. Я выбрал несколько типов экземпляров, которые могут поддерживать моего бота, и выбрал стратегию распределения «самая низкая цена». Спотовый инстанс t3.medium в настоящее время является самым дешевым, но если это изменится или если доступность t3.medium уменьшится, моя группа остановит мой текущий инстанс t3.medium и развернет следующий дешевый вариант.

Вывод

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

Еще раз, я хотел бы выразить особую признательность моему другу и коллеге Stuart Minshull, старшему облачному архитектору Amazon Web Services, который консультировал меня по общей архитектуре и лучшим практикам, которые я использовал в этом проекте!

Репозиторий github: https://github.com/jfreds91/waifu_bot