参考:https://pytorch.org/tutorials/advanced/neural_style_tutorial.html

具体的理论就不解释了,这里主要是解释代码:

⚠️使用的是python2.7

1.导入包和选择设备

下面是需要用来实现神经迁移的包列表:

  • torch, torch.nn, numpy (使用pytorch实现神经网络必不可少的包)
  • torch.optim (有效梯度下降)
  • PIL, PIL.Image, matplotlib.pyplot (下载和显示图像)
  • torchvision.transforms (转移PIL图像为张量)
  • torchvision.models (训练或下载预训练模型)
  • copy (深度复制模型;系统包)

代码为:

from __future__ import print_functionimport torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optimfrom PIL import Image
import matplotlib.pyplot as pltimport torchvision.transforms as transforms
import torchvision.models as modelsimport copy

接下来我们就需要去选择使用什么设备去运行网络,以及导入内容和风格图片。在大图像上运行神经迁移算法要更长时间,但是如果运行在GPU中它能够运行地更快一些。我们可以使用torch.cuda.is_available()去检测本地是否有GPU能够使用。接下来,我们将通过torch.device设置该GPU,让他能在整个教程中使用。.to(device)方法也用来将张量和模块移动到想要使用的设备上。

代码为:

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

即如果有CUDA就使用它,没有就使用CPU

2.下载图片

现在我们将导入风格和内容图片。原始的PIL图片有在0-255之间的值,但是当转换成torch张量后,他们的值就转换成了0-1.为了有相同的维度,这些图片也需要被调整大小。一个重要的细节需要被注意——来自torch库的神经网络是使用值在0-1的张量来进行训练的。如果你想要传给网络0-255张量的图片,那么激活特征映射将不能够感知想要的内容和风格。可是来自Caffe库的预训练网络就是使用0-255的张量进行训练的。

⚠️

在这个课程中需要下载两张图片:picasso.jpg 和  dancing.jpg.

下载这两个图片,并将它们添加在你本地路径的data/images目录当中

代码为:

#输出图片的期望大小
imsize = 512 if torch.cuda.is_available() else 128  # 如果使用的设备不是GPU,那么就使用小点的大小loader = transforms.Compose([transforms.Resize(imsize),  # 输入图像的规模,调整其大小transforms.ToTensor()])  # 将其转换成torch张量def image_loader(image_name):image = Image.open(image_name)# 用来满足网络的输入维度的假batch维度,即不足之处补0image = loader(image).unsqueeze(0)return image.to(device, torch.float)#下载的风格图像可很容图像
style_img = image_loader("./data/imagese/picasso.jpg")
content_img = image_loader("./data/images/dancing.jpg")#断言风格图像和内容图像是否大小一致,如果大小不一致则报错,说明需要大小一致的内容和风格图像
assert style_img.size() == content_img.size(), \"we need to import style and content images of the same size"

PIL:Python Imaging Library,Python平台的图像处理标准库

现在,让我们创建一个通过再次转换图片的复制体成PIL格式和使用plt.imshow命令显示复制体的方法来显示一张图片的函数。我们将试着显示风格和内容图像去保证他们已经成功导入

代码为:

unloader = transforms.ToPILImage()  # 将图像再次转换成PIL图像plt.ion()def imshow(tensor, title=None):  #该函数用来显示你上传的内容和风格两张图像image = tensor.cpu().clone()  # 克隆张量并不进行更改image = image.squeeze(0)      # 移除假batch维度,即删掉上面添加的0remove the fake batch dimensionimage = unloader(image)       #将图像转换成PIL图像plt.imshow(image)             #显示图像if title is not None:plt.title(title) #title用于为图片标注标题plt.pause(0.001) # 稍作停顿,以便更新绘图plt.figure()
imshow(style_img, title='Style Image')plt.figure()
imshow(content_img, title='Content Image')

图为,之后运行了以后再截自己的图:

3.损失函数

1)内容损失

我们将直接在卷积层后添加内容损失模块,该模块将用于计算内容距离。这样子每当网络传进输入图像后,该内容损失将会在期望的层次进行计算,同时计算梯度。为了使内容损失层透明,我们必须要定义一个forward函数去计算内容损失,并返回该层的输出。该计算损失降作为模型的参数进行存储

代码为:

class ContentLoss(nn.Module):def __init__(self, target,):super(ContentLoss, self).__init__()# 我们从用于动态计算梯度的树中“分离”目标内容:这是一个状态值,而不是一个变量# 否则该标准的forward方法将抛出一个errorself.target = target.detach()def forward(self, input):self.loss = F.mse_loss(input, self.target)return input

⚠️虽然这个模块命名为ContentLoss,但是它并不是一个真的PyTorch损失函数。如果你想要定义你自己的内容损失作为PyTorch损失函数,你必须创建一个autograd函数去在backward方法中重计算或手动实现梯度

2)风格损失

风格损失模块与内容损失模块的实现是相似的。它将作为一个网络中的透明层去计算该层的风格损失。为了去计算风格损失,我们需要去计算gram矩阵GXL。该gram矩阵是他的转置矩阵和一个给定矩阵相乘的结果。在该应用中,这个给定矩阵是层次L的特征映射FXL的改造版本。FXL被改造去形成F̂ XL,这是一个K*N矩阵,K是L层中特征映射的数量,N是所有垂直特征映射的长度FkXL。比如F̂ XL的第一行与第一个垂直特征映射F1XL相关

最后,必须通过将每个元素除以矩阵中元素的总数来规范化gram矩阵。这个规范化用以抵消带有N维F̂ XL矩阵将在gram矩阵中生成更大的值这一事实。这些较大的值将导致第一个层(池化层之前)在梯度下降期间产生较大的影响。风格特性往往位于网络的更深层,因此这一标准化步骤至关重要。

代码为:

def gram_matrix(input):a, b, c, d = input.size()  # a=batch size(=1)# b=number of feature maps# (c,d)=dimensions of a f. map (N=c*d)features = input.view(a * b, c * d)  # resise F_XL into \hat F_XLG = torch.mm(features, features.t())  # 计算gram产出# 我们通过在每一个特征映射中数亿元素数量的方法来规范化gram矩阵的值return G.div(a * b * c * d)

现在风格损失模块看起来几乎就像风格损失模块了。这个风格距离也是使用 GXL 和GSL均方差的方法来计算的。代码为:

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 = F.mse_loss(G, self.target)return input

4.导入模块

现在我们需要导入一个预训练神经网络。我们将使用在论文中的19层VGG网络。

VGG的PyTorch的实现是一个分成两个子序列模块的模块:features(包含卷积和池化层)和classifier(包含全连接层)。我们将使用features模块,应为我们需要独立卷积层的输出去测量内容和风格损失。在训练过程中,一些层有着与评估时不同的行为,所以我们必须使用.eval()将网络设置为评估模式,即:

cnn = models.vgg19(pretrained=True).features.to(device).eval()

除此之外,VGG网络将在每个通道都被mean=[0.485, 0.456, 0.406] 和std=[0.229, 0.224, 0.225]规范化的图片上进行训练。我们将使用他们在将图片发送到网络之前去将其规范化,即:

cnn_normalization_mean = torch.tensor([0.485, 0.456, 0.406]).to(device)
cnn_normalization_std = torch.tensor([0.229, 0.224, 0.225]).to(device)# 创建一个模块去规范化输入图像,所以我们能够轻易地将其输入到nn.Sequential
class Normalization(nn.Module):def __init__(self, mean, std):super(Normalization, self).__init__()# 使用.view方法去将mean和std值变为[C x 1 x 1]维,所以他们能够直接与形状为[B x C x H x W]的图像张量工作# B是batch大小,C是通道数,H是高,W是宽度self.mean = torch.tensor(mean).view(-1, 1, 1)self.std = torch.tensor(std).view(-1, 1, 1)def forward(self, img):#规范化imgreturn (img - self.mean) / self.std

Sequential模块包含了一个子模块的顺序列表。比如vgg19.features包含按深度的正确顺序对齐的序列(Conv2d, ReLU, MaxPool2d, Conv2d, ReLU…)。我们需要在他们检测的卷积层后面马上添加我们的内容损失和风格损失层。为了这么做,我们一定要创建一个新的Sequential模块去正确地插入内容损失和风格损失

# 想要用来计算风格/内容损失的层次深度
content_layers_default = ['conv_4']
style_layers_default = ['conv_1', 'conv_2', 'conv_3', 'conv_4', 'conv_5']def get_style_model_and_losses(cnn, normalization_mean, normalization_std,style_img, content_img,content_layers=content_layers_default,style_layers=style_layers_default):cnn = copy.deepcopy(cnn)# 规范化模块normalization = Normalization(normalization_mean, normalization_std).to(device)# 只是为了获得迭代入口或内容/风格损失content_losses = []style_losses = []# 假设cnn是一个nn.Sequential,所以我们创建了一个新的nn.Sequential去放入假设被顺序激活的模块model = nn.Sequential(normalization)i = 0  # 每次看见卷积时自增for layer in cnn.children(): //去判断cnn中的子序列是什么类型的层if isinstance(layer, nn.Conv2d):i += 1name = 'conv_{}'.format(i)elif isinstance(layer, nn.ReLU):name = 'relu_{}'.format(i)# 本地版本没有和我们下面插入的ContentLoss和StyleLoss相处地很好# 所以我们使用另一个版本来替代它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__))//只有是上面几种类型的层才会添加到规范化的model中model.add_module(name, layer)if name in content_layers: //如果该name存在于content_layers,就会为其添加内容损失的计算# 添加内容损失target = model(content_img).detach()content_loss = ContentLoss(target)model.add_module("content_loss_{}".format(i), content_loss)content_losses.append(content_loss)if name in style_layers: //如果该name存在于style_layers,就会为其添加风格损失的计算# 添加风格损失target_feature = model(style_img).detach()style_loss = StyleLoss(target_feature)model.add_module("style_loss_{}".format(i), style_loss)style_losses.append(style_loss)# 现在我们在最后一个内容和风格损失后修建层次for i in range(len(model) - 1, -1, -1): //由后向前获得model的值if isinstance(model[i], ContentLoss) or isinstance(model[i], StyleLoss):breakmodel = model[:(i + 1)]return model, style_losses, content_losses

接下来,我们选择输入图像。你可以使用一个内容图像的副本或白噪声

input_img = content_img.clone()
# 如果你想要使用白噪声,请取消下面一行的注释
# input_img = torch.randn(content_img.data.size(), device=device)# 添加原始输入图像到figure:
plt.figure()
imshow(input_img, title='Input Image')

5.梯度下降

我们使用L-BFGS算法去运行梯度下降。不像训练一个网络,我们想要训练一个输入的图像去最小化内容/风格损失。我们将创建一个PyTorch L-BFGS优化器 optim.LBFGS,然后将我们的图像作为一个张量传给他去优化

def get_input_optimizer(input_img):# 该行用于显示输入是一个需要梯度的参数optimizer = optim.LBFGS([input_img.requires_grad_()])return optimizer

最后我们必须要定义一个可以形成神经迁移的函数。对于网络的每一次迭代,它都将会传入更新后的输入并计算新的损失。我们将会运行每一个损失模块中的backward方法去动态计算他们的梯度。该优化器需要一个“封闭”函数,用于重新计算模块并返回损失

我们还有最后一个约束需要解决。网络可能尝试去为了图像优化带着超过图像的0到1张量范围值的输入。我们可以在网络每次运行时通过修正输入值为0-1之间来解决这个问题

def run_style_transfer(cnn, normalization_mean, normalization_std,content_img, style_img, input_img, num_steps=300,style_weight=1000000, content_weight=1):"""运行风格转移"""print('Building the style transfer model..')model, style_losses, content_losses = get_style_model_and_losses(cnn,normalization_mean, normalization_std, style_img, content_img)optimizer = get_input_optimizer(input_img)print('Optimizing..')run = [0]while run[0] <= num_steps:def closure():# 修正更新过的输入图像的值input_img.data.clamp_(0, 1)optimizer.zero_grad()model(input_img)style_score = 0content_score = 0for sl in style_losses:style_score += sl.lossfor cl in content_losses:content_score += cl.lossstyle_score *= style_weightcontent_score *= content_weightloss = style_score + content_scoreloss.backward()run[0] += 1if 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_scoreoptimizer.step(closure)# 最后一次修正input_img.data.clamp_(0, 1)return input_img

最后我们可以运行这个算法:

output = run_style_transfer(cnn, cnn_normalization_mean, cnn_normalization_std,content_img, style_img, input_img)plt.figure()
imshow(output, title='Output Image')# sphinx_gallery_thumbnail_number = 4
plt.ioff()
plt.show()

运行起来为:

(deeplearning2) userdeMBP:neural transfer user$ python neural_style_tutorial.py
Downloading: "https://download.pytorch.org/models/vgg19-dcbb9e9d.pth" to /Users/user/.torch/models/vgg19-dcbb9e9d.pth
100.0%
Building the style transfer model..
neural_style_tutorial.py:121: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach() or sourceTensor.clone().detach().requires_grad_(True), rather than torch.tensor(sourceTensor).self.mean = torch.tensor(mean).view(-1, 1, 1)
neural_style_tutorial.py:122: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach() or sourceTensor.clone().detach().requires_grad_(True), rather than torch.tensor(sourceTensor).self.std = torch.tensor(std).view(-1, 1, 1)
Optimizing..
run [50]:
Style Loss : 93.626976 Content Loss: 17.819944run [100]:
Style Loss : 22.882374 Content Loss: 15.977382run [150]:
Style Loss : 9.978903 Content Loss: 14.216763run [200]:
Style Loss : 5.153259 Content Loss: 12.498219run [250]:
Style Loss : 3.383650 Content Loss: 10.965824run [300]:
Style Loss : 2.633158 Content Loss: 9.868271

图像为:

转载于:https://www.cnblogs.com/wanghui-garcia/p/10537970.html

pytorch例子学习——NEURAL TRANSFER USING PYTORCH神经迁移相关推荐

  1. Pytorch基础学习(第一章-PyTorch基础概念)

    课程一览表: 目录 一..pytorch简介 ​二.环境配置 1.pycharm 2.annaconda 3.安装pytorch 三.张量简介与创建 1.张量的概念 2.Tensor--直接创建 3. ...

  2. pytorch 入门学习 实现线性回归-5

    pytorch 入门学习实现线性回归 使用pytorch实现线性回归 import numpy as np import matplotlib.pyplot as plt import torch#p ...

  3. PyTorch 深度学习实践 第13讲

    PyTorch 深度学习实践 第13讲 引言 代码 结果 引言 近期学习了B站 刘二大人的PyTorch深度学习实践,传送门PyTorch 深度学习实践--循环神经网络(高级篇),感觉受益匪浅,发现网 ...

  4. # PyTorch学习笔记(15)--神经网络模型训练实战

    PyTorch学习笔记(15)–神经网络模型训练实战     本博文是PyTorch的学习笔记,第15次内容记录,主要是以一个实际的例子来分享神经网络模型的训练和测试的完整过程. 目录 PyTorch ...

  5. 实战例子_Pytorch官方力荐新书《Pytorch深度学习实战指南》pdf及代码分享

    PyTorch是目前非常流行的机器学习.深度学习算法运算框架.它可以充分利用GPU进行加速,可以快速的处理复杂的深度学习模型,并且具有很好的扩展性,可以轻松扩展到分布式系统.PyTorch与Pytho ...

  6. PyTorch 1.0 中文官方教程:用例子学习 PyTorch

    译者:bat67 最新版会在译者仓库首先同步. 作者:Justin Johnson 这个教程通过自洽的示例介绍了PyTorch的基本概念. PyTorch主要是提供了两个核心的功能特性: 一个类似于n ...

  7. PyTorch框架学习二十——模型微调(Finetune)

    PyTorch框架学习二十--模型微调(Finetune) 一.Transfer Learning:迁移学习 二.Model Finetune:模型的迁移学习 三.看个例子:用ResNet18预训练模 ...

  8. pytorch深度学习-微调(fine tuning)

    微调(fine tuning) 首先举一个例子,假设我们想从图像中识别出不同种类的椅子,然后将购买链接推荐给用户.一种可能的方法是先找出100种常见的椅子,为每种椅子拍摄1,000张不同角度的图像,然 ...

  9. PyTorch深度学习-跟着小土堆学习

    目录 学习视频链接 一些问题 P4:Python/PyTorch学习中两大法宝函数-dir().help() P5:PyCharm及Jupyter使用及对比 P6:PyTorch加载数据初认识 P7: ...

  10. 《PyTorch深度学习实践》

    [<PyTorch深度学习实践>完结合集] https://www.bilibili.com/video/BV1Y7411d7Ys/?share_source=copy_web&v ...

最新文章

  1. java接口如何定义常量 c_在Java接口中怎样访问定义的常量呢?
  2. Xcode 上使用Reveal调试界面
  3. 第十六界智能车竞赛:这问题怎么越来越多了呢?
  4. TCP滑动窗口(Sliding Window)原理
  5. vim树形目录NERDTree
  6. lamp/lnmp实例
  7. opencv笔记(3):图像镜像
  8. tornado框架的get方法传递参数
  9. Oracle语句连接查询
  10. Python删除文件夹和建立文件夹
  11. Mac做深度学习开发【从无到有】
  12. NodeMCU实现远程控制LED灯
  13. Android 工具
  14. 改进版艾宾浩斯单词背诵计划表
  15. 疯狂的程序员 41-50
  16. 计算机桌面图片怎么设置大小,怎样设置电脑桌面背景与屏幕大小相同 这些知识你不一定知道...
  17. 【CSS 书写模式 (Writing modes )】
  18. ArrayList集合学生管理系统,java笔试基础题
  19. STM32(3)——外部中断的使用
  20. LeetCode题解系列--309. Best Time to Buy and Sell Stock with Cooldown

热门文章

  1. 2015-2016 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2015) Adjoin the Networks (树的直径)
  2. python生成Excel透视表
  3. 酷站60个漂亮可用的外文站点欣赏(经典推荐)
  4. MySQL功能大全(细品)
  5. MasterCAM快捷功能大全
  6. mac 显示及隐藏文件的方法
  7. CSS——响应式网页(Bootstrap)
  8. python求平方函数图像_求平方 python
  9. axios http请求报错: Request failed with status code 400
  10. 优麒麟 20.04 LTS Pro安装Canon LBP2900打印机