Вступление

В настоящее время всем нравится делать проекты с использованием машинного обучения или глубокого обучения. В этом блоге я дам вам шанс стать «Пикассо» в глубоком обучении, поскольку мы собираемся изучить метод передачи стилей с использованием глубоких сверточных нейронных сетей. мы будем использовать для этого предварительно обученную сеть VGG19.

Не волнуйтесь, это звучит сложно, но на самом деле очень просто. Вам просто нужно быть знакомым с Python, PyTorch и некоторыми материалами для глубокого обучения, такими как CNN, а также с тем, как использовать предварительно обученные сети (поскольку мы будем использовать предварительно обученную CNN для передачи нашего стиля). Я освежу ваши представления о CNN.

Что такое CNN (сверточная нейронная сеть)

Сверточный слой + функция активации, за которым следует слой объединения и линейный слой (для создания желаемого размера вывода) составляют базовые уровни CNN.

  1. Сверточный слой: он получается путем применения различных фильтров к входному изображению для выделения признаков. Количество используемых фильтров определяет глубину слоя. Функция активации применяется к выводу сверточного слоя для масштабирования.
  2. Уровень объединения. Максимальный уровень объединения уменьшает размер входных данных по осям x и y и сохраняет только наиболее активные значения пикселей. Ниже приведен пример ядра пула 2x2 с шагом 2.

Почему мы используем VGG19 для передачи стилей

Мы можем использовать любой из VGG16 и VGG19 для извлечения функций, поскольку они работают очень хорошо по сравнению с другими в случае передачи стиля. Например, здесь я использовал VGG19.

Помимо VGG, вы можете использовать SqueezeNet, он быстрее, но результаты худшие, а в случае Inception он работает хорошо, но вам нужно изменить шаг / ядра, максимальный пул на средний пул, поиск по различным комбинациям слоев. Так что VGG на данный момент лучший.

Вы можете прочитать больше здесь"

Как выполнить перенос стиля

Передача стилей использует функции 19-уровневой сети VGG, которая состоит из серии сверточных и объединяющих слоев, а также нескольких полносвязных слоев. Сверточные слои именуются стеком и их порядком в стеке. Поскольку первый сверточный слой называется conv1_1, а самый глубокий сверточный слой - conv5_4.

Передача стилей основана на разделении содержания и стиля изображения. Наша цель - создать новое изображение, содержащее стиль изображения стиля и содержимое изображения содержимого (базовое изображение).

  1. Контент (объекты и их расположение) из заданного изображения контента.
  2. Стиль (цвет и текстура) из заданного стиля изображения.

Загрузка в VGG19 (функции):

VGG19 состоит из двух частей:

  1. vgg19.features (сверточный и объединяющий слой)
  2. vgg19.classifier (последние три слоя для вывода)

Для переноса стилей нам нужна только часть функций, поэтому мы загрузим ее и зафиксируем веса.

import matplotlib.pyplot as plt
import numpy as np
import torch
import torch.optim as optim
from torchvision import transforms, models
vgg = models.vgg19(pretrained=True).features
# freeze all VGG parameters since we’re only optimizing the target image
for param in vgg.parameters():
 param.requires_grad_(False)

Загрузить стиль и изображение содержимого:

# define load_image() function which deals with images size
# load in content and style image 
content = load_image('images/x.jpg')
# Resize style to match content, makes code easier
style = load_image('images/y.jpg',shape=content.shape[-2:])
#covert this images to tensor and apply transforms

Особенности содержания и стиля:

  1. Для представления содержимого целевого изображения мы пропускаем изображение содержимого через модель и берем выходные данные слоя conv4_2, так как считается, что он содержит наиболее точные функции содержимого.
  2. Для представления стиля целевого изображения мы рассматриваем выходные данные слоев conv1_1, conv2_1, conv3_1, conv4_1 и conv5_1, опять же по той же причине, содержащей точные особенности стиля.

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

Матрица Грама вычисляется путем умножения матрицы на ее транспонирование.

Создаем холст и собираем все вместе:

# define get_feature() and get content and style features only once before forming the target image
content_features = get_features(content, vgg)
style_features = get_features(style, vgg)
# calculate the gram matrices for each layer of our style representation
style_grams = {layer: gram_matrix(style_features[layer]) for layer in style_features}
# create a third "target" image and prep it for change
# it is a good idea to start of with the target as a copy of our *content* image
# then iteratively change its style
target = content.clone().requires_grad_(True)

Потеря и вес:

Толщина стиля отдельного слоя

Мы назначаем веса выходным данным каждого слоя, чтобы управлять эффектом их стиля на нашем конечном изображении. Если вам нужны более крупные артефакты стиля, вы должны дать более высокие веса исходным слоям conv1_1, conv2_1 и наоборот. Вес находится в диапазоне 0–1.

Содержание и вес стиля

Мы определяем альфа (content_weight) и бета (style_weight). Это соотношение повлияет на то, насколько стилизовано ваше окончательное изображение. Рекомендуется оставить content_weight равным 1 и изменить style_weight.

# weights for each style layer 
# weighting earlier layers more will result in *larger* style artifacts
# notice we are excluding `conv4_2` our content representation
style_weights = {'conv1_1': 1.,
                 'conv2_1': 0.75,
                 'conv3_1': 0.2,
                 'conv4_1': 0.2,
                 'conv5_1': 0.2}
content_weight = 1  # alpha
style_weight = 1e6  # beta

Потеря контента

Это среднеквадратичная разница между целевыми функциями и функциями содержимого на уровне conv4_2.

content_loss = torch.mean((target_features['conv4_2'] - content_features['conv4_2'])**2)

Утрата стиля

Для потери стиля мы вычислим матрицу граммов целевого изображения и затем сравним ее с матрицей граммов изображения стиля на слоях, используемых для извлечения признаков стиля, как conv1_1, conv2_1 и т. Д. Опять же, это среднеквадратичная разница.

Общий убыток

Он будет рассчитан путем добавления стиля и потери контента после их взвешивания с альфа- и бета-версиями.

total_loss = content_weight * content_loss + style_weight * style_loss

Наша цель здесь - минимизировать общие потери за счет повторения и обновления значений.

# for displaying the target image, intermittently
show_every = 400
# iteration hyper parameters
optimizer = optim.Adam([target], lr =0.003)
steps = 2000  # decide how many iterations to update your image (5000)
for ii in range(1, steps+1):
    
    # get the features from your target image
    target_features = get_features(target, vgg)
    
    # the content loss
    content_loss = torch.mean((target_features['conv4_2'] - content_features['conv4_2'])**2)
    
    # the style loss
    # initialize the style loss to 0
    style_loss = 0
    # then add to it for each layer's gram matrix loss
    for layer in style_weights:
        # get the "target" style representation for the layer
        target_feature = target_features[layer]
        target_gram = gram_matrix(target_feature)
        _, d, h, w = target_feature.shape
        # get the "style" style representation
        style_gram = style_grams[layer]
        # the style loss for one layer, weighted appropriately
        layer_style_loss = style_weights[layer] * torch.mean((target_gram - style_gram)**2)
        # add to the style loss
        style_loss += layer_style_loss / (d * h * w)
        
    # calculate the *total* loss
    total_loss = content_weight * content_loss + style_weight * style_loss
    
    # update your target image
    optimizer.zero_grad()
    total_loss.backward()
    optimizer.step()
   

Полный код для переноса стиля можно найти здесь

Заключение

Прочитав этот блог, вы получите обзор того, как происходит передача стилей и как работают приложения для редактирования изображений, такие как Prisma. Здесь мы использовали расчет матрицы граммов, но вы также можете улучшить передачу стиля, используя различные другие подходы, такие как сети кодировщика и декодера и т. Д.

Более того, основным недостатком этого метода является то, что мы платим время за лучшие результаты, вы также можете искать перенос стиля в реальном времени как обновление существующего.

Использованная литература:

  1. ПиТорч нано степень
  2. Https://www.cvfoundation.org/openaccess/content_cvpr_2016/papers/Gatys_Image_Style_Transfer_CVPR_2016_paper.pdf