python风格迁移_CNN 风格迁移实战(附python代码)

本文详述如何使用Python和CNN实现风格迁移,通过VGG16模型结合内容损失、风格损失和总变差损失,将指定风格应用到输入图像上,保留内容并转换风格。
摘要由CSDN通过智能技术生成

c0de9884968b?from=groupmessage

在今天的文章中,我们会建立一个很棒的风格迁移网络。为了做到这一点,我们需要深入地了解 CNN 和卷积层的工作原理。在文章结束时,你将会创建一个风格迁移网络,这个网络能够在保留原始图像的同时将新样式应用到它上面。

c0de9884968b?from=groupmessage

波士顿天际线和梵高的繁星之夜混合效果

风格迁移

在开始之前,先明确一下我们的目标。

我们将风格迁移定义为改变图像风格同时保留它的内容的过程。

给定一张输入图像和样式图像,我们就可以得到既有原始内容又有新样式的输出图像。在 Leon A. Gaty 的论文 A Neural Algorithm of Artistic Style 中有所描述。

输入图像 + 样式图像 -> 输出图像(风格化)

工作方式

准备输入图像和风格图像并将它们调整为相同的大小。

加载预训练的卷积神经网络(VGG16)。

区分负责样式的卷积(基本形状,颜色等)和负责内容的卷积(特定于图像的特征),将卷积分开可以单独地处理内容和样式。

优化问题,也就是最小化:

内容损失(输入和输出图像之间的距离 - 尽力保留内容)

风格损失(风格和输出图像之间的距离 - 尽力应用新风格)

总变差损失(正则化 - 对输出图像进行去噪的空间平滑度)

最后设置梯度并使用 L-BFGS 算法进行优化。

实现

输入

# 旧金山

san_francisco_image_path = "https://www.economist.com/sites/default/files/images/print-edition/20180602_USP001_0.jpg"

# 输入可视化

input_image = Image.open(BytesIO(requests.get(san_francisco_image_path).content))

input_image = input_image.resize((IMAGE_WIDTH, IMAGE_HEIGHT))

input_image.save(input_image_path)

input_image

这就是旧金山的天际线

c0de9884968b?from=groupmessage

风格

然后定义一个风格图像。

# Tytus Brzozowski

tytus_image_path = "http://meetingbenches.com/wp-content/flagallery/tytus-brzozowski-polish-architect-and-watercolorist-a-fairy-tale-in-warsaw/tytus_brzozowski_13.jpg"

# 风格图像可视化

st

以下是一个基于PyTorch实现的图像风格迁移Python代码示例: ```python import torch import torch.nn as nn import torch.optim as optim import torchvision.transforms as transforms import torchvision.models as models from PIL import Image import matplotlib.pyplot as plt # 定义图像处理函数 loader = transforms.Compose([ transforms.Resize((512, 512)), # 调整图像大小 transforms.ToTensor() # 转换为张量 ]) unloader = transforms.ToPILImage() # 将张量转换为图像 # 定义图像加载函数 def image_loader(image_name): image = Image.open(image_name) image = loader(image).unsqueeze(0) return image.to(device, torch.float) # 定义模型 class ContentLoss(nn.Module): def __init__(self, target): super(ContentLoss, self).__init__() self.target = target.detach() def forward(self, input): self.loss = nn.functional.mse_loss(input, self.target) return input class StyleLoss(nn.Module): def __init__(self, target_feature): super(StyleLoss, self).__init__() self.target = gram_matrix(target_feature).detach() def forward(self, input): G = gram_matrix(input) self.loss = nn.functional.mse_loss(G, self.target) return input def gram_matrix(input): a, b, c, d = input.size() features = input.view(a * b, c * d) G = torch.mm(features, features.t()) return G.div(a * b * c * d) class Normalization(nn.Module): def __init__(self, mean, std): super(Normalization, self).__init__() self.mean = torch.tensor(mean).view(-1, 1, 1) self.std = torch.tensor(std).view(-1, 1, 1) def forward(self, img): return (img - self.mean) / self.std # 定义模型 class StyleTransferModel(nn.Module): def __init__(self, content_img, style_img, cnn=models.vgg19(pretrained=True).features.to(device).eval(), content_layers=['conv_4'], style_layers=['conv_1', 'conv_2', 'conv_3', 'conv_4', 'conv_5']): super(StyleTransferModel, self).__init__() self.content_layers = content_layers self.style_layers = style_layers self.content_losses = [] self.style_losses = [] self.model = nn.Sequential(Normalization([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])) i = 0 for layer in cnn.children(): if isinstance(layer, nn.Conv2d): i += 1 name = 'conv_{}'.format(i) elif isinstance(layer, nn.ReLU): name = 'relu_{}'.format(i) layer = nn.ReLU(inplace=False) elif isinstance(layer, nn.MaxPool2d): name = 'pool_{}'.format(i) elif isinstance(layer, nn.BatchNorm2d): name = 'bn_{}'.format(i) else: raise RuntimeError('Unrecognized layer: {}'.format(layer.__class__.__name__)) self.model.add_module(name, layer) if name in content_layers: target = self.model(content_img).detach() content_loss = ContentLoss(target) self.model.add_module("content_loss_{}".format(i), content_loss) self.content_losses.append(content_loss) if name in style_layers: target_feature = self.model(style_img).detach() style_loss = StyleLoss(target_feature) self.model.add_module("style_loss_{}".format(i), style_loss) self.style_losses.append(style_loss) for i in range(len(self.model) - 1, -1, -1): if isinstance(self.model[i], ContentLoss) or isinstance(self.model[i], StyleLoss): break self.model = self.model[:(i + 1)] def forward(self, x): return self.model(x) # 定义图像风格迁移函数 def style_transfer(content_img_path, style_img_path, num_steps=300, style_weight=100000, content_weight=1): content_img = image_loader(content_img_path) style_img = image_loader(style_img_path) input_img = content_img.clone() optimizer = optim.LBFGS([input_img.requires_grad_()]) model = StyleTransferModel(content_img, style_img).to(device) print('Start style transfer...') run = [0] while run[0] <= num_steps: def closure(): input_img.data.clamp_(0, 1) optimizer.zero_grad() model(input_img) style_score = 0 content_score = 0 for sl in model.style_losses: style_score += sl.loss for cl in model.content_losses: content_score += cl.loss style_score *= style_weight content_score *= content_weight loss = style_score + content_score loss.backward() run[0] += 1 if run[0] % 50 == 0: print("run {}:".format(run)) print('Style Loss : {:4f} Content Loss: {:4f}'.format( style_score.item(), content_score.item())) print() return style_score + content_score optimizer.step(closure) input_img.data.clamp_(0, 1) return input_img # 定义图像显示函数 def imshow(tensor, title=None): image = tensor.cpu().clone() image = image.squeeze(0) image = unloader(image) plt.imshow(image) if title is not None: plt.title(title) plt.pause(0.001) # 设置设备 device = torch.device("cuda" if torch.cuda.is_available() else "cpu") # 运行图像风格迁移 output = style_transfer('content.jpg', 'style.jpg') # 显示结果 plt.figure() imshow(output, title='Output Image') # 保存结果 output_img = unloader(output.cpu().clone().squeeze(0)) output_img.save('output.jpg') ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值