Перенос стиля - это процесс, при котором мы перекомпоновываем изображение в стиле другого изображения путем переноса художественного стиля с одного изображения на другое с помощью сверточной нейронной сети.
Это выглядит так:
Это фотография Пабло Пикассо, рисующего быка на листе стекла, но изображение было перерисовано нейронной сетью с использованием художественного стиля другой картины.
Вы можете посмотреть полное видео здесь: https://www.youtube.com/watch?v=FzvTLEB_3KY
Довольно круто, правда?
Это короткий фрагмент из фильма 1950 года бельгийского режиссера Поля Хэзертса «Визит в Пикассо», в котором Пикассо демонстрирует свое мастерство.
Каждый кадр видео был обработан нейронной сетью Artistic Style Transfer. В результате получается гипнотический и сказочный эпизод, в котором мы видим, как Пикассо рисует своего быка, но визуальный стиль постоянно меняется, поскольку программное обеспечение плавно переключается между разными художественными стилями.
Таким образом, по своей сути, перенос стиля - это процесс, который берет изображение, которое мы называем изображением содержимого, и объединяет его с художественным стилем второго изображения, называемого изображением стиля. . В результате получается смешанное изображение:
Вы можете видеть, что исходный пейзаж все еще виден на смешанном изображении, но цвета, текстуры и визуальный стиль взяты из изображения стиля.
Для передачи художественного стиля нам в первую очередь понадобится полностью обученный классификатор изображений. Популярным выбором является сверточная нейронная сеть VGG19. Мы можем загрузить эту сеть из Интернета и загрузить ее в приложение.
Итак, вот как работает процесс переноса стиля.
Мы начинаем с показа изображения содержимого нейронной сети и измерения активации функции в самом глубоком сверточном слое нейронной сети. Мы будем рассматривать этот уровень активации как базовый. Когда мы показываем сети другие изображения, мы получим активацию другой функции в самом глубоком слое. Разница между базовым и фактическим уровнями активации называется потерей контента. Он определяет, насколько видны элементы изображения содержимого.
Мы также можем измерить художественный стиль, показывая изображение стиля в сети, а затем вычисляя матрицу Грамма активации функции в самом глубоком сверточном слое. Это создает основу для стиля.
Когда мы показываем сети случайное изображение, разница между базовой линией стиля и матрицей Грамма фактического уровня активации называется потерей стиля. Он определяет, какая часть художественного стиля из изображения стиля видна.
Полный процесс обучения теперь очень прост:
- Покажите нейронной сети изображения контента и стиля и рассчитайте базовые уровни контента и стиля.
- Покажите случайное изображение нейронной сети и рассчитайте потерю контента и потерю стиля.
- Настройте пиксели в случайном изображении, чтобы уменьшить потерю содержимого и стиля. Повторяйте, пока потеря не станет приемлемой.
Мы можем показывать случайные изображения нейронной сети, добавляя слой сновидений. Это просто плотный входной слой с тремя сетевыми узлами на пиксель изображения (по одному для каждого цветового канала). Во время обучения эти узлы настраиваются, что эффективно создает изображение, минимизирующее потерю содержимого и стиля.
Процесс выглядит так:
Посмотрим, смогу ли я создать приложение для переноса стилей на C # с библиотекой Microsoft Cognitive Toolkit.
Я начну с создания нового консольного приложения с нуля с помощью NET Core:
$ dotnet new console -o StyleTransferDemo
Теперь я установлю пакет CNTK:
$ dotnet add package CNTK.Gpu
Библиотека CNTK.GPU - это Cognitive Toolkit от Microsoft, который может обучать и запускать глубокие нейронные сети. Он будет обучать и запускать глубокие нейронные сети с помощью вашего графического процессора. Для этого вам понадобится графический процессор NVidia и графические драйверы Cuda.
Если у вас нет графического процессора NVidia или подходящих драйверов, библиотека откатится и вместо этого будет использовать ЦП. Это сработает, но обучение нейронных сетей займет значительно больше времени.
CNTK - это низкоуровневая тензорная библиотека для построения, обучения и запуска глубоких нейронных сетей. Код для построения глубокой нейронной сети может быть немного подробным, поэтому я разработал небольшую оболочку под названием CNTKUtil, которая поможет мне писать код быстрее.
Вы можете скачать файлы CNTKUtil здесь и сохранить их в новой папке CNTKUtil на том же уровне, что и папка проекта.
Теперь из папки проекта консоли я могу создать ссылку на проект следующим образом:
$ dotnet add reference ../CNTKUtil/CNTKUtil.csproj
Теперь я готов начать писать код. Я отредактирую файл Program.cs с помощью кода Visual Studio и добавлю следующий код:
Код вызывает NetUtil.CurrentDevice для отображения вычислительного устройства, которое будет использоваться для обучения нейронной сети.
Затем я использую вспомогательный класс StyleTransfer и дважды вызываю LoadImage, чтобы загрузить изображение содержимого и изображение стиля.
Теперь мне нужно сообщить CNTK, какую форму имеют входные данные, на которых я буду тренировать нейронную сеть:
Я тренирую нейронную сеть со слоем сновидения, который имеет ту же ширину и высоту, что и содержимое и стиль изображений. Итак, мой входной тензор равен imageWidth, умноженному на imageHeight, умноженному на 3 цветовых канала, и каждый пиксельный канал представляет собой float, который можно обучать индивидуально.
Мой следующий шаг - спроектировать нейронную сеть. Я собираюсь использовать сеть VGG19, но оставлю только сверточные слои для обнаружения контента и потери стиля:
Обратите внимание, как я сначала вызываю VGG19, чтобы загрузить всю сеть VGG19 и заморозить все слои. Затем я вызываю StyleTransferBase, который удаляет классификатор и сохраняет только сверточную базу для переноса стиля.
Затем мне нужно настроить метки для обучения нейронной сети. Эти метки представляют собой значения активации функции и матрицы Грамма в слоях контента и стиля нейронной сети, когда я показываю ей контент, соответственно, изображение стиля:
Вычисление меток на основе модели и изображений содержимого и стиля - сложная операция, но, к счастью, есть удобный метод под названием CalculateLabels, который делает все это автоматически. Результатом является массив float [] [], который содержит желаемые уровни активации в слоях контента и стилей, которые позволят нейронной сети узнать, что передача стиля была достигнута.
Нейронная сеть почти готова. Все, что мне нужно добавить, это слой сновидений для создания смешанного изображения:
Слой сновидений - это входной слой для нейронной сети, представляющий изображение, в котором каждый пиксель является индивидуально обучаемым параметром. В процессе обучения цвета пикселей в слое сновидений будут меняться, чтобы получить смешанное изображение.
Затем мне нужно сообщить CNTK, какую форму будет иметь выходной тензор нейронной сети. Эта форма немного сложна, потому что я смотрю на активацию функций и значения матрицы Грамма в слоях содержимого и стиля нейронной сети. Но я могу программно вычислить форму вот так:
Этот код вызывает GetContentAndStyleLayers для доступа к слоям контента и стилей в сети VGG19, перебирает все метки в массиве меток и создает массив переменных CNTK с правильным Shape.
Теперь мне нужно настроить функцию потерь для обучения нейронной сети. Эта функция потерь должна измерять значения активации функции и матрицы Грамма в слоях содержимого и стиля нейронной сети и сравнивать их со значениями базовой активации и матрицы Грамма, когда сеть просматривает контент и изображения стиля:
Функция потерь для переноса стиля довольно сложна, но, к счастью, я могу настроить ее с помощью одного вызова CreateLossFunction, предоставив модель, слои содержимого и стиля, а также переменную метки CNTK.
Затем мне нужно решить, какой алгоритм использовать для обучения нейронной сети. Есть много возможных алгоритмов, полученных из Gradient Descent, которые я могу использовать здесь.
Я собираюсь использовать AdamLearner. Вы можете узнать больше об алгоритме Адама здесь: https: //machinelearningmastery.com/adam ...
Я почти готов к тренировкам. Мой последний шаг - настроить трейнер для расчета потерь в каждую тренировочную эпоху:
Метод GetTrainer настраивает трейнер, который будет отслеживать потери в процессе переноса стиля.
Теперь я наконец готов приступить к обучению нейронной сети!
Я добавлю следующий код:
Я обучаю сеть для 300 эпох, используя пакет обучения, настроенный методом CreateBatch. Метод TrainMiniBatch обучает нейронную сеть за одну эпоху. И каждые 50 эпох я отображаю убыток, вызывая метод PreviousMinibarchLossAverage.
Теперь нейронная сеть полностью обучена, а потери стиля и контента минимальны. Теперь мне нужно извлечь изображение из нейронной сети:
Этот код устанавливает пробную партию с помощью CreateBatch. Обычно я оцениваю нейронную сеть в этом пакете и делаю прогнозы для меток. Но поскольку изображение, которое меня интересует, на самом деле хранится в слое сновидения, я могу извлечь его прямо из пакета с помощью вызова InferImage.
Теперь у меня есть значение для каждого пикселя в массиве float [], поэтому я вызываю конструктор Mat, чтобы проецировать эти значения на 8-битное трехканальное цветное изображение и вызвать метод ImShow для визуализации изображения на экране.
Обратите внимание, что Mat и ImShow являются функциями OpenCV. OpenCV - это гибкая библиотека изображений, используемая CNTKUtil для реализации передачи стилей.
Наконец, я вызываю WaitKey, чтобы изображение оставалось на экране после завершения работы приложения, и у меня было время полюбоваться результатами переноса стиля.
Теперь я готов запустить приложение. Сначала я перейду в папку CNTKUtil и скомпилирую проект:
$ dotnet build -o bin/Debug/netcoreapp3.0 -p:Platform=x64
Обратите внимание, как я указываю платформу x64, потому что для библиотеки CNTK требуется 64-разрядная сборка.
Теперь я могу сделать то же самое в папке StyleTransferDemo:
$ dotnet build -o bin/Debug/netcoreapp3.0 -p:Platform=x64
Это создаст мое приложение. Обратите внимание, как я снова указываю платформу x64.
Теперь я могу запустить приложение:
$ dotnet run
Приложение загрузит нейронную сеть VGG19, подготовит ее к передаче стиля, добавит слой сновидений, загрузит контент и изображения стиля, обучит сеть для 300 эпох и будет постоянно настраивать слой сновидений, пока потери контента и стиля не станут минимальными.
Посмотрите, вот мой первый запуск:
Изображение содержимого - это изображение моего профиля, которое отображается в правом верхнем углу. Образ стиля - известная кубистическая картина Любови Поповой, которая видна справа внизу. Слева - сгенерированное смешанное изображение.
Выглядит отлично! Нейронная сеть создала красивое сочетание моего аватарка и кубистического стиля живописи Поповой.
Попробуем еще раз:
Узнаешь стиль имиджа? Это знаменитая картина Винсента Ван Гога "Звездная ночь". Нейронная сеть перекрасила мой аватар, используя его знаменитые триповые синие завитки и желтые блики.
Хорошо, еще одно:
Теперь я использую знаменитую картину Эдварда Мунка «Крик» в качестве стилевого изображения. Что вы думаете о результате?
Итак, это мои результаты. Не стесняйтесь использовать код и создавать собственные изображения стиля с помощью C # и CNTK.
Эта статья основана на домашнем задании из моего курса машинного обучения: Глубокое обучение с C # и C NTK .