Рисуем Мону Лизу используя глубокое обучение с подкреплением
![](https://habrastorage.org/getpro/habr/upload_files/bb8/7ab/543/bb87ab543ef98e99a65f291cb3be0cd5.gif)
Пост написан специально для всех любителей искусства (и, возможно, машинного обучения).
На самом деле, специально для лучшего курса по ML.
В этом посте я хочу рассказать о том, как же научить машины рисовать так, как рисуют люди-художники, которые, используя небольшое количество мазков, создают фантастические картины.
Живопись является важной формой искусства, символизирует человеческую мудрость и творчество. Но людям трудно овладеть этим навыком, не потратив много времени на надлежащее обучение. Поэтому обучение машин рисованию является важной, но сложной задачей, которая помогает пролить свет на тайну живописи.
Сейчас мы с вами попробуем разобраться, как обучить искусственный интеллект последовательно наносить штрихи на холст, чтобы создать картину, похожую на заданное изображение. Будем называть машину, которая рисует, агентом. Кратко идею можно разделить на три пункта:
Научить агента раскладывать изображение на составляющие: агент должен проанализировать целевое изображение, понять текущее состояние холста и иметь дальновидные планы относительно будущих штрихов.
Создать пространство штрихов, которыми может пользоваться агент, учитывая различные параметры: расположение штриха, цвет, прозрачность и форма.
Создать рендер (средство визуализации), который может имитировать рисование сотен штрихов на холсте.
Давайте начнем.
Как научить агента раскладывать изображение на штрихи?
Как я уже писала, цель агента - разложение заданного целевого изображения на штрихи, которые могут воссоздать изображение на холсте (с помощью рендера). Чтобы имитировать процесс рисования, агент должен уметь прогнозировать следующий штрих на основе наблюдения за текущим состоянием холста и целевым изображением. Каждый штрих должен как можно более правильно соотноситься с предыдущим и следующим, чтобы уменьшить общее количество штрихов и быстрее нарисовать картину.
![Общая архитектура: на каждом шаге агент получает текущий холст и итоговое изображение, анализирует его, и выдает набор параметров штриха, затем рендер визуализирует его и получается следующее состояние холста. Общая архитектура: на каждом шаге агент получает текущий холст и итоговое изображение, анализирует его, и выдает набор параметров штриха, затем рендер визуализирует его и получается следующее состояние холста.](https://habrastorage.org/getpro/habr/upload_files/b13/702/4cb/b137024cbdefb57a56683654fa7b7a42.png)
Сейчас нам как раз пригодится обучение с подкреплением. Для тех, кто никогда не сталкивался с ним - обучение с подкреплением можно сравнить с дрессировкой собаки. Чтобы научить своего мохнатого друга питомца выполнять определенную команду, нужно его подкармливать вкусняшками за каждое правильное действие. Так и в машинном обучении - есть окружающая среда, которая поощряет действия агента, которые приводят к правильному результату (картине).
Более математично:
На вход в нашей задаче подается пустой холст и картина
(целевое изображение) которую мы хотим нарисовать. Агент стремится найти последовательность штрихов
такую, что рендеринг (рисование) штриха
на холсте
выдает холст
. Итоговый холст
должен быть визуально похож на целевое изображение
.
Мы моделируем нашу задачу как Марковский процесс принятия решений с пространством состояний , пространством действий
, функцией перехода
и функцией вознаграждения
. Пространство состояний
строится на основе всей возможной информации, которую агент может наблюдать в окружающей среде. Мы разделим состояние на три части:
, где
состояние холста,
целевое изображение и
номер шага.
Как это все будет работать?
Наша модель будет основана на DDPG, в которой есть две нейросетки - агент и критик.
Агент - функция
, сопоставляющая состояние действию.
Критик - оценивает ожидаемый выигрыш для агента, который совершит действие
на шаге
, согласно уравнению Беллмана:
гденаграда, предоставляемая агенту за выполнение действия
в состоянии
. Она равняется разности
(разница между
и
) и
(разница между
и
). Как считать потери я расскажу чуть позже.
В свою очередьобучен максимизировать оцененный критиком
Другими словами, агент выбирает ход для каждого состояния, а критик, основываясь на текущем холсте и целевом изображении, предсказывает ожидаемую награду за штрих. Оригинальная DDPG не очень хорошо подходит для нашей задачи, ведь для разных картин - есть разное окружение, т.е. где-то мы рисуем портрет с определенными тонами, где-то пейзаж, где-то натюрморт и тд. Есть специальные модели, например, Модель Мира, которые позволяют агенту эффективно понимать, какой мир его окружает.
Мы сделаем аналогичную вещь - рендер - с помощью которой агент сможет наблюдать смоделированную среду. Тогда он сможет изучить окружающий мир и эффективно улучшить свои действия. Модель с рендером называется Model-based DDPG. Разница между ними наглядно показана на рис. ниже.
![](https://habrastorage.org/getpro/habr/upload_files/396/9e6/bf8/3969e6bf8c611d7d3f8b3b000b1e70ef.png)
Немного меняется и Марковский процесс: теперь на шагекритик принимает состояние
, а не состояние и действие вместе. Критик по-прежнему предсказывает ожидаемое вознаграждение для агента, но теперь по следующей формуле:
Полезный мув: предсказывать сразупоследующих штрихов. Действительно, такой подход позволяет смотреть на будущее изображение на каждом шаге более обширно. Средство визуализации может отображать
штрихов одновременно, что значительно ускоряет процесс рисования. Опытным путем установлено, что
подходит лучше всего для нашей задачи.
Пора уже сказать пару слов об архитектуре наших нейросеток
Будем использовать residual структуры, по типу ResNet-18, в качестве средства извлечения признаков для агента и критика.
![архитектура агента и критика. на вход - состояние, на выход - действие/значение архитектура агента и критика. на вход - состояние, на выход - действие/значение](https://habrastorage.org/getpro/habr/upload_files/91c/0f2/203/91c0f220394c82e3e31021d769ed87de.png)
И так у нас есть 3 различных слоя:
1. CoordConv
2. Resblock x8
3. FC (Fully Connected Layer)
Разница для агента и критика только в последнем слое, где у них разные размерности выхода
![архитектура рендера. на вход - параметры штриха, на выход - визуализация такого штриха архитектура рендера. на вход - параметры штриха, на выход - визуализация такого штриха](https://habrastorage.org/getpro/habr/upload_files/af0/8c4/c63/af08c4c630d1b9f6d95646f8e934147f.png)
Нейронный рендер
FC (полносвязный слой)
Conv (свертка)
Sub-pixel - специальная штука, чтобы сделать изображение более четким
Использование нейронной сети для генерации штрихов хорошо тем, что она гибка для генерации штрихов любых стилей. А какими могут быть штрихи? И какие у них параметры? Давайте разбираться.
Насчет формы - в нашем случае штрих будет представлять собой квадратичную кривую Безье (с толщиной ~ как кисть). Форма этой кривой определяется координатами контрольных точек, а цвет, толщина и прозрачность несколькими числами. Формально: ,
где первые 6 чисел - координаты контрольных точек, - контролируют толщину и прозрачность двух конечных точек кривой, RGB - цвет.
Формула кривой Безье:
А как же сравнить текущее состояние холста и целевое изображение? Какая метрика?
Для этого мы используем Wasserstein GAN, улучшенная версия оригинальной GAN, в которой расстояние - Wasserstein-l. Оно так же называется Earth_mover dist.
![метрика между текущим изображением и целевой картинкой метрика между текущим изображением и целевой картинкой](https://habrastorage.org/getpro/habr/upload_files/939/dc1/509/939dc150943f82aae4f19d01917cc9fc.png)
Распределение - распределение текущего холста,
- целевого изображения. Функция
дискриминатор, липшицева с константой 1. Ее мы тоже отдельно обучаем.
Вместо этого можно использовать расстояние, но как покажут эксперименты, с ним результат будет хуже.
О математике достаточно поговорили, пришло время посмотреть на картинки и результаты экспериментов.
Рассмотрим 4 датасета - MNIST (рукописные цифры), SVHN (номера домов), CelebA (лица знаменитостей) и ImageNet (просто разные картинки).
Все картинки сводятся к размеру 128x128 пикселей. На каждой итерации обучения мы по очереди обновляем критика и актера. Все модели обучаются с нуля.
Изображения MNIST и SVHN - простые структуры изображений и обычное содержимое. Так что мы обучаем одного агента, который рисует 5 штрихов для изображений MNIST, и другого, который рисует 40 штрихов, для изображений SVHN.
Изображения знаменитостей имеют более сложную структуру и разнообразное содержимое, так что нам понадобится агент с 200 штрихами (как видно на рисунке ниже, в принципе, изображение похоже, но четкость пропала).
Для последнего датасета понадобится целых 400 штрихов из-за чрезвычайно сложных структур и разнообразного содержимого. Несмотря на потерю некоторых текстур, агент по-прежнему демонстрирует хорошие результаты в разложении изображения на штрихи.
Картинка ⬇
![](https://habrastorage.org/getpro/habr/upload_files/29a/441/14b/29a44114b214a68f9525a0149aa6f3e5.png)
Пара слов про скорость:
На процессоре Intel Core i7 с тактовой частотой 2,2 ГГц. и видеокарте NVIDIA можно нарисовать изображение из 200 штрихов (предсказывая по 5) примерно за 2 секунды. Достаточно быстро, не так ли?
Наша модель хорошо работает и на других типах штрихов - прямые линии, треугольники и круги. Картины похожи на целевое изображение, но кривые Безье и прямые штрихи, на мой взгляд, больше всего похожи на настоящую картину.
![](https://habrastorage.org/getpro/habr/upload_files/5fc/3bb/22b/5fc3bb22be7f1eb2e736064502dd67f9.png)
Чуть не забыла. Хочется еще сравнить нашу нейронную сеть и какую-нибудь другую.
Для примера
рисунок а) - нейросеть SPIRAL с 20 штрихами (слева) + оригинал
рисунок б) - наша архитектура с 20 штрихами (оригинал g)
Первая выглядит как очень сильно размытое изображение, а вторая - уже больше похожа на картину какого-нибудь художника.
![](https://habrastorage.org/getpro/habr/upload_files/ca3/d46/778/ca3d46778482a692577f2d16cb9196cb.png)
Рисунки (b), (c) и (g) - это наша нейросетка с 20, 200 и 1000 штрихами соответственно. А вот (d), например, использует в качестве метрики . Получается, конечно, тоже похоже на оригинал, но более размыто.
На последок хочу показать примеры рисования некоторых картин, очень залипательно!
Вот, например, рассвет:
![sunrise sunrise](https://habrastorage.org/getpro/habr/upload_files/4ac/375/907/4ac375907728ab03380814adb1c9b774.gif)
А вот подсолнухи:
![sunflower sunflower](https://habrastorage.org/getpro/habr/upload_files/9f9/e49/81c/9f9e4981cd65121ffb468b52bc03112b.gif)
И даже звездная ночь Ван Гога!
![deepdream night deepdream night](https://habrastorage.org/getpro/habr/upload_files/40f/71f/6a9/40f71f6a919dd55d2a618b8860942c40.gif)