предисловие
Что такое перенос стиля изображения? На самом деле, это уже распространено во многих приложениях APP.Например, давайте выберем свою фотографию, а затем выберем изображение стиля.После подтверждения наша фотография станет стилем, похожим на выбранное изображение.
Суть передачи стиля изображения состоит в том, чтобы выяснить особенности изображения, а затем объединить их в изображение, которое необходимо изменить, как показано на следующем рисунке, что является типичным переносом стиля.
Следовательно, сложность реализации переноса стиля изображения заключается в том, как извлечь признаки изображения, а упомянутые здесь признаки также являются стилем изображения. бумага"A Neural Algorithm of Artistic Style》Используйте CNN (Сверточная нейронная сеть), чтобы извлечь стиль изображения. Потому что мы все знаем, что CNN может извлекать изображения признаков, а затем реализовывать классификацию изображений с помощью признаков. Когда у нас есть метод извлечения стиля изображения, нам нужно только интегрировать вновь извлеченный стиль в новое изображение, чтобы реализовать передачу стиля изображения.
1. Реализация основного кода PyTorch
На самом деле, основная идея кода не сложна: использовать CNN для извлечения содержимого изображения содержимого и стиля изображения стиля, а затем ввести новое изображение. Содержание и стиль, извлеченные из входного изображения, и содержимое и стиль, извлеченные CNN, используются для расчета потерь.Измерение потерь может использовать MSE, а затем потери постепенно оптимизируются, чтобы значение потерь достигло наилучшего значения.Оптимизированный параметры выводятся, так что выходное изображение достигает цели передачи стиля.
(1) Расчет потери контента
Зачем использовать свертки для извлечения контента?
На приведенном ниже рисунке показана одна из карт объектов, извлеченных с помощью свертки, которая показывает, что вполне возможно использовать свертка как метод извлечения контента.
Код для расчета потери контента выглядит следующим образом:
class Content_loss(torch.nn.Module):
def __init__(self, weight, target):
super(Content_loss, self).__init__()
self.weight = weight
self.target = target.detach()*weight
self.loss_fn = torch.nn.MSELoss()
def forward(self, input):
self.loss = self.loss_fn(input*self.weight, self.target)
self.output = input
return self.output
def backward(self):
self.loss.backward(retain_graph = True)
return self.loss
Целью здесь является контент, извлеченный CNN из изображения контента, а вес используется для управления влиянием контента и стиля на входное изображение.Вход здесь — это наше входное изображение, и основная цель определенного обратного на самом деле для вызова метода распространения направления и возвращает наши рассчитанные потери. Расчет потерь использует MSE для измерения.
(2) Расчет потери стиля
Код для расчета потери стиля выглядит следующим образом:
class Style_loss(torch.nn.Module):
def __init__(self, weight, target):
super(Style_loss, self).__init__()
self.weight = weight
self.target = target.detach()*weight
self.loss_fn = torch.nn.MSELoss()
self.gram = gram_matrix()
def forward(self, input):
self.output = input.clone()
self.G = self.gram(input)
self.G.mul_(self.weight)
self.loss = self.loss_fn(self.G, self.target)
return self.output
def backward(self):
self.loss.backward(retain_graph = True)
return self.loss
Значения target, weight, input, back и Loss здесь аналогичны предыдущим вычислениям содержания, с той лишь разницей, что вводится матрица Грама, а стиль изображения определяется выполнением операции матрицы Грама над содержание, извлеченное CNN.
Почему матрица Грама может определять стиль изображения?
Поскольку CNN извлекает карту признаков изображения после свертки, каждое число представляет собой размер элемента исходного изображения, а матрица Грама — это операция внутреннего произведения матрицы.После операции чем больше число в карте признаков , тем больше, что эквивалентно характеристикам изображения масштабируются, чтобы выделить элементы, что эквивалентно извлечению стиля изображения.
Код для матрицы Грама выглядит следующим образом:
class gram_matrix(torch.nn.Module):
def forward(self, input):
a,b,c,d = input.size()
feature = input.view(a*b, c*d)
gram = torch.mm(feature, feature.t())
return gram.div(a*b*c*d)
(3) Создание и обучение CNN
Создайте новый код модели обучения:
content_layer = ["Conv_5","Conv_6"]
style_layer = ["Conv_1", "Conv_2", "Conv_3", "Conv_4", "Conv_5"]
content_losses = []
style_losses = []
conten_weight = 1
style_weight = 1000
new_model = torch.nn.Sequential()
model = copy.deepcopy(cnn)
gram = gram_matrix()
if use_gpu:
new_model = new_model.cuda()
gram = gram.cuda()
index = 1
for layer in list(model):
if isinstance(layer, torch.nn.Conv2d):
name = "Conv_"+str(index)
new_model.add_module(name, layer)
if name in content_layer:
target = new_model(content_img).clone()
content_loss = Content_loss(conten_weight, target)
new_model.add_module("content_loss_"+str(index), content_loss)
content_losses.append(content_loss)
if name in style_layer:
target = new_model(style_img).clone()
target = gram(target)
style_loss = Style_loss(style_weight, target)
new_model.add_module("style_loss_"+str(index), style_loss)
style_losses.append(style_loss)
if isinstance(layer, torch.nn.ReLU):
name = "Relu_"+str(index)
new_model.add_module(name, layer)
index = index+1
if isinstance(layer, torch.nn.MaxPool2d):
name = "MaxPool_"+str(index)
new_model.add_module(name, layer)
Чтобы завершить передачу стиля, нам также необходимо построить собственную сеть CNN. Сначала была мигрирована модель vgg16, удалена полносвязная часть, а затем реконструирована обучающая модель в соответствии с архитектурой модели vgg16 и добавлена расчетная часть содержания и стиля Loss. Извлечение содержимого здесь выбирает только 5 и 6 слоев свертки, а извлечение стиля выбирает только 1, 2, 3, 4 и 5 слои свертки.
(4), оптимизация определения
Оптимизированный код определения:
input_img = content_img.clone()
parameter = torch.nn.Parameter(input_img.data)
optimizer = torch.optim.LBFGS([parameter])
Зачем использовать здесь LBFGS для оптимизации?
Причина в том, что на самом деле существует несколько потерь, которые мы хотим оптимизировать, вместо того, чтобы просто оптимизировать одно значение потерь при решении проблем классификации, LBFGS может достичь лучших результатов.
(5) Обучение вновь определенной CNN
Тренировочный код выглядит следующим образом:
n_epoch = 1000
run = [0]
while run[0] <= n_epoch:
def closure():
optimizer.zero_grad()
style_score = 0
content_score = 0
parameter.data.clamp_(0,1)
new_model(parameter)
for sl in style_losses:
style_score += sl.backward()
for cl in content_losses:
content_score += cl.backward()
run[0] += 1
if run[0] % 50 == 0:
print('{} Style Loss : {:4f} Content Loss: {:4f}'.format(run[0],
style_score.data[0], content_score.data[0]))
return style_score+content_score
optimizer.step(closure)
n_epoch определяет количество раз обучения как 1000 раз и использует sl.backward() и cl.backward() для реализации обратного распространения и оптимизации параметров.
2. Улучшение
Метод переноса стиля изображения в этой статье требует раунда обучения каждый раз, когда он реализуется, а метод настройки стиля должен контролироваться весами, что не идеально для практических приложений.На самом деле нам нужна более эффективная и интеллектуальная реализация. метод. Появились методы усовершенствования, и сначала выпускаются две статьи
Fast Patch-based Style Transfer of Arbitrary Style
Visual Attribute Transfer through Deep Image Analogy
Код все еще реализуется...
Ссылки: 1.Welcome to PyTorch Tutorials
2,Краткая история передачи стиля изображения (нейронный стиль)
Полный код:JaimeTang/PyTorch-and-Neural-style-transfer
Если вы считаете, что это нормально, пожалуйста, поставьте лайк...