Теория стилизации изображений (Neural Style Transfer)

Смотреть материал на YouTube | RuTube

На этом занятии рассмотрим довольно популярную технику переноса стиля от одного изображения к другому:

В англоязычной литературе это называется:

Neural Style Transfer

Существует множество вариантов таких алгоритмов, но мы поговорим о наиболее простом, предложенном Леоном Гатисом в 2015-м году. Вначале я расскажу общую математическую концепцию этого подхода, а затем, мы его реализуем на PyTorch.

Идея следующая. Пиксели исходного изображения рассматриваются, как настраиваемые параметры алгоритмом градиентного спуска. А критерий качества должен быть выбран так, чтобы он уменьшался по мере приближения исходного изображения к желаемому стилизованному:

Как видите, общая идея предельно проста. И, вроде бы, здесь даже нет никакой НС? Все верно, можно обойтись и без нее. Но, с нейросетью проще – именно она позволяет «понимать» степень стилизации и корректность стилизации. Чисто математически получить эту оценку крайне сложно. Поэтому нейронная сеть здесь используется при вычислении критерия качества – степени стилизации исходного изображения. И, конечно же, лучшими здесь являются сверточные НС. Фактически, критерий качества – это ключевой элемент данного алгоритма, поэтому мы с него и начнем.

В своей работе Леон Гатис разделил общий критерий качества на две независимые оценки:

  • степень соответствия преобразованного изображения исходному;
  • степень стилизации преобразованного изображения.

Эти величины вычисляются независимо друг от друга, а затем, суммируются с определенными весами для формирования общего показателя качества.

Начнем с первой оценки. Как понять: насколько отличаются два изображения? В классических алгоритмах обработки изображений не редко можно встретить сумму квадратов рассогласований между отдельными пикселями:

Но для данной задачи она не очень подходит, так как не учитывает структуру изображения, например, линии, овалы, глаза, лапы, ветки и т.п. Чтобы оценивать изображения на более предметном уровне, как раз и используется НС. В рамках нашей задачи мы воспользуемся уже готовой сверточной НС VGG19, о которой подробно говорили на прошлом занятии. Причем, мы ее будем использовать с уже обученными весами связей, которые были получены по базе изображений ImageNet, состоящей, примерно, из 10 миллионов различных полноцветных изображений. Что нам это дает? Вспоминая прошлые занятия, мы отмечали, что глубокие слои обученной сверточной НС как раз описывают изображение набором общих признаков: голова, хвост, трава, тело и т.п. Это как раз то, что нам сейчас и нужно. Мы возьмем последний сверточный слой сети VGG19 и вычислим среднюю сумму разности квадратов признаков:

Здесь  - набор признаков для формируемого изображения; - набор признаков для исходного изображения (с котиками);  - высота и ширина карты признаков (в нашем случае 14х14);  - число каналов (). Множитель перед суммой используется для нормировки, усреднения полученной величины. То есть, мы делаем следующее. Пропускаем через сеть VGG19 исходное изображение, получаем на последнем слое набор признаков . Затем, пропускаем модифицированное изображение, получаем признаки . И, потом, вычисляем показатель качества  для контента.

Я думаю принцип вычисления первого параметра, в целом, ясен. Перейдем ко второму – степени стилизации формируемого изображения.

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

Для начала нам нужно прогнать стилевое изображение через НС. И, далее, рассмотрим тензор предпоследнего слоя Conv5-1. Вытянем его в матрицу для удобства дальнейших вычислений:

Что теперь сделать с набором этих признаков, для получения числовых характеристик стиля изображения? Однозначного ответа на этот вопрос нет. Здесь исследователю нужно включать «здравый смысл», фантазию и пробовать строить некий математический алгоритм. Леон Гатис предложил перемножить полученную матрицу саму себя в транспонированном виде. В результате чего получается, так называемая, матрица Грама:

Эту матрицу можно воспринимать, как автоковариационную матрицу тензора соответствующего слоя, которая описывает линейную степень схожести карт признаков для разных фильтров (каналов). Такие матрицы вычисляются для всех выбранных сверточных слоев сети VGG19. В результате получаем набор матриц Грама для изображения со стилем:

Теперь, чтобы понять насколько сильно различаются стили между формируемым изображением и стилевым, пропускаем через НС формируемое изображение (до этого пропускали стилизованное) и для него повторяем все те же самые вычисления на тех же сверточных слоях. Получаем еще один набор матриц Грама, но уже для формируемого изображения:

Имея эти наборы матриц, величину рассогласования стилей на текущем слое НС, можно вычислить по формуле (средний квадрат ошибок):

Ее еще можно воспринимать, как квадрат евклидового расстояния между различными матрицами Грама.

Соответственно, для вычисления потерь для стиля по всем выбранным слоям логично сложить потери для каждого стиля между собой. Леон Гатис так и сформировал итоговое значение потерь:

Здесь  - весовые коэффициенты для разной степени учета различных слоев.

Все, степень расхождения по стилю мы теперь умеем вычислять. Зная потери по контенту , общий показатель качества можно записать в виде:

где  - некоторые веса, которые показывают насколько важно учитывать содержимое или стиль. Подбирая эти значения можно получать разную степень стилизации формируемого изображения.

Вот так выглядит общая идея переноса стиля на изображение. Я попытался ее привести как можно проще. Если что-то непонятно, то посмотрите этот материал еще раз, задавайте вопросы в комментариях (по возможности, я на них отвечаю). Но сначала сами попытайтесь вникнуть в детали вычисления критерия качества. А далее, поняв, как он определятся, уже используется алгоритм градиентного спуска, который меняет пиксели исходного изображения (с котиками) так, чтобы минимизировать этот показатель J:

На следующем занятии мы продолжим эту тему и реализуем этот алгоритм с использованием фреймворка PyTorch.

Видео по теме