本文代码和部分内容参考课程:《动手学深度学习》:样式迁移
深度学习框架:MXNET(Python调用)
神经风格转换论文原文参考:A Neural Algorithm of Artistic Style
1 什么是神经风格转换
神经风格转换(也可称作“样式迁移”)是一种使用卷积神经网络自动将某一图像的样式(风格)应用到另一张图片上的技术,可以看做将某张图片自动施加滤镜的修饰技术。比如,我们可以把一张图片变为素描风格,油画风格,蜡笔风格等任何你想要的艺术风格。用神经网络实现这样一个小功能不得不说是一个挺有趣的事情。下面先展示我自己完成的一些例子:
![](https://i-blog.csdnimg.cn/blog_migrate/01d5299b12eef628b488e2557956c6eb.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/92141253e1438146c51ce9f3432a4b41.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/a107fd30686f4a2131b9ad307dd19d58.png)
![](https://i-blog.csdnimg.cn/blog_migrate/c237f8445cfa297ebe7c4ecdbe634560.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/8ab5f25d3327be3ad3fcc5680fdfabfe.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/1bf1cd9d67d566e6123331afcdfe0f1e.png)
![](https://i-blog.csdnimg.cn/blog_migrate/91fee5a1ed7df034b94459a02f0083ca.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/d5b7e0e53cad8a813ac43c3f58528d8c.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/fccb1c205bbe23ddde00420e42c7d3be.png)
![](https://i-blog.csdnimg.cn/blog_migrate/dc4a21d107709571ab32566dd0743dcb.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/208dbea2ad0055d9d1e8bfa297c6a796.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/34564be301cef259053558f3abaca371.png)
上面系列图靠左的图为内容图片(Content),居中的为风格图片(Style),最右侧为输出,即我们期望获得的图像效果。从结果来看,生成的图片效果还不错。
2 神经风格转换实现原理
首先,我们初始化合成图像,例如将其初始化成内容图像。该合成图像是样式迁移过程中唯一需要更新的变量,即神经风格转换所需迭代的模型参数。
然后,我们选择一个预训练的卷积神经网络(论文原文和本文代码均使用了VGG-19)来抽取图像的特征,其中的模型参数在训练中无须更新。深度卷积神经网络凭借多个层逐级抽取图像的特征。我们可以选择其中某些层的输出作为内容特征或样式特征。以下图为例,这里选取的预训练的神经网络含有3个卷积层,其中第二层输出图像的内容特征,而第一层和第三层的输出被作为图像的样式特征。
接下来,我们通过正向传播(实线箭头方向)计算神经风格转的损失函数,并通过反向传播(虚线箭头方向)迭代模型参数,即不断更新合成图像。
样式迁移常用的损失函数通常由3部分组成:内容损失(content loss)使合成图像与内容图像在内容特征上接近,样式损失(style loss)令合成图像与样式图像在样式特征上接近,而总变差损失(total variation loss)使生产图像各个像素点与之周围像素点的差异值降低,有助于减少合成图像中的噪点。最后,当模型训练结束时,我们输出样式迁移的模型参数,即得到最终的合成图像。
3 实现方法
3.1图片处理
首先我们导入必要的包和模块:
%matplotlib inline
import d2lzh as d2l
from mxnet import autograd, gluon, image, init, nd
from mxnet.gluon import model_zoo, nn
import time
其中d2lzh是《动手学深度学习》课程中提供的一个工具包,里面内置了大量深度学习中常用的函数,方便日常使用。
然后载入内容图片和风格图片:
content_img = image.imread('内容图片(content)的地址')
d2l.plt.imshow(content_img.asnumpy());
style_img = image.imread('风格图片(style)的地址')
d2l.plt.imshow(style_img.asnumpy());
定义图片预处理和后处理函数,预处理将图片RGB通道做标准化,并将结果变换成卷积神经网络接受的输入格式;后处理将神经网络的输出还原为图片原始格式:
# 图片RGB三通道的均值和标准差
'''这里我不是很懂,不同的图片这个值应该是不一样的,这个应该根据传入的图片分别
计算各自的均值和标准差吧,原代码直接用给出的这个值标准化内容图片和风格图片,
不过所有图片好像都可以用这个。。。而且效果还不错。。。在此提出疑问QAQ。
'''
rgb_mean = nd.array([0.485, 0.456, 0.406])
rgb_std = nd.array([0.229, 0.224, 0.225])
def preprocess(img, image_shape):
img = image.imresize(img, *image_shape)
img = (img.astype('float32') / 255 - rgb_mean) / rgb_std
return img.transpose((2, 0, 1)).expand_dims(axis=0)
def postprocess(img):
img = img[0].as_in_context(rgb_std.context)
return (img.transpose((1, 2, 0)) * rgb_std + rgb_mean).clip(0, 1)# clip用来确保像素值在0到1之间,因为神经网络可能会迭代一些负数出来哦
3.2 特征提取
和论文原文一样,使用了预训练的VGG-19神经网络,该网络使用了ImageNet数据集来训练,有空试试其他像ResNet系列,Inception系列网络的效果。
首先导入模型:
pretraind_VGG = model_zoo.vision.vgg19(pretrained=True,