Автор статьи рассказывает, как за неделю создал Text2Art.com — генератор изображений на основе VQGAN+CLIP, способный рисовать пиксель-арт и живопись, а также изображать то, что вы напишете в текстовом поле.  Для интерфейса используется Gradio, модель работает на сервере FastAPI, а системой очереди сообщений служит Firebase. Подробностями делимся к старту курса по ML и DL. Если вам понравился проект, вы можете проголосовать за него здесь. Не так давно генеративные картины и NFT штурмом захватили мир. Это стало возможным после значительного прогресса OpenAI в генерации изображения из текста. Ранее в этом году OpenAI анонсировал DALL-E, мощный генератор изображений из текстов.  Чтобы проиллюстрировать, насколько хорошо работает DALL-E, посмотрите рисунки, сгенерированные DALL-E по запросу "a professional high quality illustration of a giraffe dragon chimera, "a giraffe imitating a dragon", "a giraffe made of dragon". К сожалению, DALL-E не был выпущен в массы. Вместо него была опубликована модель, которая творит магию DALL-E, — CLIP. CLIP или Contrastive Image-Language Pretraining — это мультимодальная сеть, объединяющая текст и изображения.  Одним словом, CLIP способен оценить, насколько хорошо изображение соответствует надписи или наоборот.  Это крайне полезно в управлении генератором, чтобы создать изображение, точно соответствующее введённому тексту. В фильме "DALL-E"  CLIP используется, чтобы ранжировать сгенерированные изображения и входные изображения с наивысшим баллом (самые похожие на тектовый запрос). Через несколько месяцев после анонса фильма DALL-E был опубликован новый генератор изображений-трансформеров под названием VQGAN (Vector Quantized GAN). Сочетание VQGAN с CLIP даёт качество, аналогичное DALL-E. С момента обнародования предварительно обученной модели VQGAN сообщество создало множество удивительных картин. Вот примеры: Я был поражён результатами и захотел поделиться ими со своими друзьями. Но, поскольку не так много людей готовы погрузиться в код ради генерации картин, я решил сделать Text2Art.com — сайт, где любой может просто ввести подсказку и сгенерировать нужное изображение, не сталкиваясь с кодом воочию. Итак, как работает VQGAN+CLIP? VQGAN генерирует изображение, а CLIP измеряет, насколько оно соответствует запросу. Затем генератор использует обратную связь от модели CLIP, чтобы сгенерировать более точные изображения. Процедура повторяется, пока оценка CLIP не станет достаточно высокой. Я не буду рассказывать о внутренней работе VQGAN или CLIP. Но, если вы хотите получить более глубокие объяснения VQGAN, CLIP или DALL-E, обратитесь к этим удивительным ресурсам, которые я нашёл: Иллюстрированный VQGAN; Объяснение DALL-E; Объяснение научной работы о CLIP на видео. VQGAN+CLIP — это только пример того, на что способно объединение генератора изображений с CLIP. Однако вы можете заменить VQGAN на любой генератор. Появилось много вариантов X + CLIP, таких как StyleCLIP (StyleGAN + CLIP), CLIPDraw (векторный генератор), BigGAN + CLIP и многие другие, даже AudioCLIP, который работает со звуком, а не изображениями. Я воспользуюсь кодом из репозитория clipit от dribnet, этот код генерирует изображения при помощи VQGAN+CLIP в несколько простых строк (обновление: clipit мигрировал на pixray). Его рекомендуется запускать на Google Colab: VQGAN+CLIP требует много памяти GPU. Вот блокнот Colab.  Прежде всего, если вы работаете на Colab, убедитесь, что вы изменили тип рантайма на GPU, вот так: Установим кодовую базу и зависимости: "!" — это специальная команда в Google Colab, которая означает, что команда будет запущена в bash, а не в python. После установки библиотек мы можем просто импортировать clipit и запустить эти несколько строк кода для генерации картины с помощью VQGAN+CLIP.  Просто замените текстовую подсказку на любую другую. Кроме того, вы можете задать clipit такие параметры, как количество итераций, ширина, высота, модель генератора, хотите ли вы генерировать видео или нет, и многие другие. Чтобы больше узнать об опциях, вы можете посмотреть исходный код. Вот код генерации: Когда вы запустите код, он сгенерирует изображение. На каждой итерации сгенерированное изображение будет приближаться к тексту, который вы ввели. Вот так можно установить количество итераций, им управляет iterations: В любом случае нужно генерировать изображение для каждой итерации, поэтому можно сохранить эти изображения и создать анимацию самой генерации. Для этого добавьте make_video=True перед применением настроек. Получится этот ролик: Размер изображения устанавливается опцией size=(width, height). Сенерируем баннерное изображение с разрешением 800x200. Обратите внимание, что более высокое разрешение требует большего объёма памяти GPU. Можно генерировать и пиксель-арт. Для этого используется рендерер CLIPDraw за сценой с некоторыми инженерными решениями, такими как ограничение цветов палитры, пикселизация и т.д. Просто включите опцию use_pixeldraw=True. Из-за смещения в CLIP добавление определённых ключевых слов к подсказке может придать определённый эффект генерируемому изображению. Например, добавление слова "unreal engine"  к текстовой подсказке, как правило, создаёт реалистичное изображение или HD стиль. Добавление определённых названий сайтов, таких как "deviantart", "artstation"  или "flickr", обычно делает результаты более эстетичными. Мне больше всего нравится использовать ключевое слово "artstation”, так как я считаю, что помогает создать лучшие картины. Кроме того, вы можете использовать ключевые слова, чтобы обусловить художественный стиль: "pencil sketch”, "low poly" или даже имя художника — "Thomas Kinkade" или "James Gurney”. Чтобы узнать больше о влиянии различных ключевых слов, вы можете ознакомиться с изображением, которое показывает более 200 слов на 4 темы. Gradio — это библиотека Python, которая упрощает построение демонстраций ML до нескольких строк кода. Демоверсия требует меньше 10 минут работы. Кроме того, вы можете запустить Gradio в Colab, и он сгенерирует ссылку для совместного использования на домене Gradio. Ссылкой можно поделиться. Gradio имеет некоторые ограничения, но я считаю, что это самая подходящая библиотека, когда вы просто хотите продемонстрировать одну функцию. Ниже код простого пользовательского интерфейса для приложения Text2Art. Думаю, что он достаточно понятен, но, если вам нужно больше объяснений, смотрите документацию Gradio. Как только вы запустите эту программу в Google Colab или локально, она создаст ссылку, которой можно поделиться, демонстрация будет общедоступной. Не нужно использовать туннелирование SSH вроде ngrok. Кроме того, Gradio также предлагает хостинг за 7 долларов в месяц. Однако Gradio хорошо подходит только для демонстрации одной функции. Создание кастомного сайта с дополнительными функциями, такими как галерея, вход в систему или даже просто пользовательский CSS, довольно ограничено или вообще невозможно. Одно быстрое решение — создать демонстрационный сайт отдельно от пользовательского интерфейса Gradio, затем — встроить интерфейс Gradio через iframe. Я попробовал этот метод, но осознал один важный недостаток: я не могу персонализировать части, которые должны взаимодействовать с самим приложением ML: валидацию ввода, пользовательский прогресс-бар и т. д., невозможны с iframe. И я решил создать API. Чтобы сделать API быстрее, вместо Flask я воспользовался FastAPI. Кода меньше, а ещё он автоматически генерирует документацию со Swagger UI, что позволяет тестировать API с помощью простого пользовательского интерфейса.  Кроме того, FastAPI поддерживает асинхронные функции и, как утверждается, он быстрее, чем Flask. Вот код, который я написал для выполнения функции ML на сервере FastAPI: После определения сервера мы можем запустить его с помощью uvicorn. Кроме того, поскольку Google Colab предоставляет доступ к своему серверу только через интерфейс Colab, мы должны использовать Ngrok, чтобы сделать сервер FastAPI публичным.  Код для запуска и демонстрации сервера: Запустив сервер, мы можем перейти к Swagger UI (добавив /docs в сгенерированный ngrok URL) и протестировать API. При тестировании API я понял, что вывод может занять от 3 до 20 минут в зависимости от качества/итераций. Три минуты само по себе уже считается очень долгим для HTTP-запроса, и пользователи могут не захотеть ждать так долго.  Я решил, что установка вывода в качестве фоновой задачи и отправка пользователю электронного письма после получения результата лучше подходят для этой задачи. Теперь, когда мы определились с планом, напишем функцию для отправки письма. Сначала я использовал почтовый API SendGrid, но после исчерпания квоты бесплатного использования (100 писем в день) перешёл на API Mailgun, который входит в пакет GitHub Student Developer Pack, разрешая студентам отправлять 20 000 писем в месяц.  Вот код для отправки электронного письма с вложением изображения с помощью API Mailgun: Далее мы изменим код нашего сервера, чтобы использовать фоновые задачи в FastAPI и отправить результат по электронной почте в фоновом режиме. С помощью приведённого выше кода сервер быстро ответит на запрос сообщением "Task is processed in the background" вместо того, чтобы ждать завершения генерации и ответа с изображением. Когда генерация завершится, сервер по электронной почте отправит пользователю результат. Теперь, когда всё вроде бы заработало, я создал фронтенд и поделился сайтом со своими друзьями. Однако при тестировании с несколькими пользователями я обнаружил, что есть проблема параллелизма. Когда второй пользователь делает запрос на сервер, в то время как первая задача всё ещё обрабатывается, вторая задача каким-то образом завершает текущий процесс, вместо того чтобы создать параллельный процесс или очередь. Не было уверенности, что вызвало проблему, возможно, это было использование глобальных переменных в коде clipit, а возможно, нет. Я быстро понял, что мне нужно реализовать систему очереди сообщений. По результатам поисков в Google большинство рекомендует RabbitMQ или Redis. Однако я не был уверен, можно ли установить RabbitMQ или Redis на Google Colab: для этого, похоже, требуется разрешение sudo.  В конце концов, я решил использовать Google Firebase, потому что хотел закончить проект как можно скорее, а с Firebase я знаком лучше всего. В основном, когда пользователь пытается сгенерировать рисунок во фронтенде, он добавляет запись в queue, которая описывает задачу (введённый текст, тип изображения, размер и т. д.). С другой стороны, мы запустим сценарий на Google Colab, который будет постоянно прослушивать новую запись в очереди и обрабатывать задания одно за другим.  На фронте нужно только добавить новую задачу в очередь. Убедитесь, что правильно настроили Firebase на фронтенде: Мы сделали это! Теперь, когда пользователь попытается создать рисунок на фронтенде, он добавит новую задачу в очередь. Затем рабочий скрипт на сервере Colab обработает задания в очереди, одно за другим. Вы можете заглянуть в репозиторий GitHub, чтобы увидеть весь код. Лучше понять нейросети и научиться решать проблемы бизнеса с их помощью вы сможете на наших курсах: Курс «Machine Learning и Deep Learning» (6 месяцев) Профессия Data Scientist (24 месяца) Также вы можете перейти на страницы из каталога, чтобы увидеть, как мы готовим специалистов в других направлениях.  DALL-E  CLIP  CLIP-VQGAN  StyleCLIP  Flask против FastAPI Data Science и Machine Learning Профессия Data Scientist Профессия Data Analyst Курс «Математика для Data Science» Курс «Математика и Machine Learning для Data Science» Курс по Data Engineering Курс «Machine Learning и Deep Learning» Курс по Machine Learning Python, веб-разработка Профессия Fullstack-разработчик на Python Курс «Python для веб-разработки» Профессия Frontend-разработчик Профессия Веб-разработчик Мобильная разработка Профессия iOS-разработчик Профессия Android-разработчик Java и C# Профессия Java-разработчик Профессия QA-инженер на JAVA Профессия C#-разработчик Профессия Разработчик игр на Unity От основ — в глубину Курс «Алгоритмы и структуры данных» Профессия C++ разработчик Профессия Этичный хакер А также: Курс по DevOps