【Neural Style Transfer】Neural Style

博主最早接触深度学习应用在艺术方向是从Neural Style开始的,但那时就是囫囵吞枣,能把代码跑起来就感觉完成了,最近觉得深度学习应用在艺术方向很有意思,又把之前接触过的一些内容翻出来,重新理解一下。
论文Paper1:Texture Synthesis Using Convolutional Neural Networks
论文地址:https://arxiv.org/pdf/1505.07376.pdf
论文译文:https://blog.csdn.net/cicibabe/article/details/70991588
论文Paper2:A Neural Algorithm of Artistic Style
论文地址:https://arxiv.org/abs/1508.06576
源码地址:https://github.com/anishathalye/neural-style
论文译文:https://blog.csdn.net/hongbin_xu/article/details/79019996
论文Paper3: Image Style Transfer Using Convolutional Neural Networks
论文地址:https://www.cv-foundation.org/openaccess/content_cvpr_2016/papers/Gatys_Image_Style_Transfer_CVPR_2016_paper.pdf
(感谢上述大佬们辛勤的翻译和无私的分享~比心!这三篇论文本质上都是一样的,都是Gatys同一时期的想法,只是侧重点不同,如果没有时间全看三篇的话可以只阅读第三篇,比较全面)

简单介绍一下Neural Style

对于Neural Style可以这样理解,有一张图像A(我们叫它内容图像,因为我们想学习图像中的Content)和图像B(我们叫它风格图像,因为我们想学习图像中的Style),那如何生成带有B风格的A图像呢?这就是Neural Style干的事情。

Paper 1: Texture Synthesis Using CNN

Gatys在2015年连发了两篇关于Neural Style和Texture Synthesis的论文,虽然两篇论文在原理上有所相似,但这对于之前手工提取纹理合成纹理的时代已经足够震撼,我们来简单的看一下这篇论文都讲了些什么。
作者认为,视觉纹理合成的目标是从一个实例纹理生成一个生成过程,然后该过程允许生成任意多个新的纹理样本。一般而言有两种生成纹理的方法:第一种方法是,对像素或原始纹理的整个区块再采样生成新纹理(这些非参数再采样技术和大量扩展或改进方法可以非常有效地生成高质量的自然纹理。然而,它们无法定义为自然纹理定义一个真正的模型);第二种纹理合成的方法是明确定义一个参数化的纹理模型(模型通常由一组图像空间统计值组成。在模型中,纹理由这些观测值的结果唯一确定,每个生成相同结果的图像应该具有相同的纹理)。所以,作者基于CNN提出了一种新的参数纹理模型来解决这一问题。

在这里插入图片描述
这篇论文里构建纹理模型和Gatys在《A Neural Algorithm of Artistic Style》构建的纹理模型几乎一样,但是这篇论文的一些实验和结果还是值得关注的。

【底层纹理和高层纹理的区别】 在最低层约束纹理表示,合成的纹理有很少的结构,与光谱噪声非常相似;随着匹配纹理表示的网络层数增加,生成图像的自然度也增加。
【纹理图像和非纹理图像生成纹理的区别】 (用ImageNet中非纹理图像生成的纹理)算法生成的纹理保留了局部空间信息,但丢弃了图像的全局空间结构。空间信息保留好的区域的大小随着用于纹理生成网络层数的增加而增加。

Paper 2: A Neural Algorithm of Artistic Style

在这里插入图片描述

【卷积是个很神奇的东西,你想让它学什么,学成什么,它就可以干什么】 也就是说,如果想让CNN来学习内容表示(Content representation)它就可以学内容;如果想让CNN来学习风格表示(Style representation)它就可以学风格。【所以在这篇论文中的后半部分在做风格重构的时候,作者认为经过VGGNet的每个CNN卷积层得到的Feature Map都是一种风格,就像不同的人看某一艺术品有不同的理解,而Feature Map就是这种理解】
但是,这篇paper的重要结论是,卷积神经网络中内容和风格的表示是可分离的。 即可以独立地操作这两种表示以产生新的、感知意义上有意义的图像。但是,图像的内容和风格也并不能完全分开,因为当一张图像的内容和另一张图像的风格融合的时候通常不存在同时完全匹配这两个约束的图像【这是也为什么损失函数会包括风格损失和内容损失的原因,我们要达到内容学习和风格学习的折中】

基本思想:

  • 随机生成一张图片x(白噪声图像);
  • 在反向传播和损失函数的作用下,不断调整生成图像x的像素值;
  • 最终得到具有图像B风格和图像A内容的新图像;

其实,Neural Style是一个生成的过程,所以是内容重构(Content Reconstructions)和风格重构(Style Reconstructions) 的过程。
【内容重构】需要先考虑一个问题——即图像的内容是什么? 简单粗暴来看就是像素值,但是纯像素的比较两张图像来得出两张图像内容是否一样太过于简单,所以,作者认为可以通过一个已知特定层的网络的响应来重构输入图像并可以可视化CNN在不同处理层级的信息。 在重构了输入图像后,发现低层次重构的结果几乎完美,而较高层上的重构因为具体的像素信息已经丢失。
【风格重构】同样要先考虑一个问题——即图像的风格是什么? 图像的风格可以说是包含很多内容,比如说色彩、纹理、结构、笔触等等,作者认为用卷积神经网络的各层特征图之间的互相关就可以来表示图像的风格。 在原始CNN的最高层,建立了一个新的特征空间来捕获输入图片的风格,风格表现计算了CNN不同层中不同特征之间的联系。

基础网络:VGGNet(VGG19中的16conv+5pooling,不用fc层);在图像合成方面,我们发现用平均池代替最大池操作可以改善梯度流,得到更有吸引力的结果,这就是为什么所显示的图像是用平均池生成的。

损失函数: 基于内容重构和风格重构我们来定义损失函数,采用的是平方差损失函数,损失函数 = 内容损失 L c o n t e n t L_{content} Lcontent和风格损失 L s t y l e L_{style} Lstyle的加权和 L t o t a l L_{total} Ltotal 【因为Neural Style是内容的重构和风格的重构,所以要有两方面的损失】;
假设我们输入的内容图像A为 p ⃗ \vec{p} p ,输入的风格图像B为 a ⃗ \vec{a} a ,而经过CNN网络生成的图像为 x ⃗ \vec{x} x ,则损失函数( α \alpha α β \beta β分别是内容和风格重构各自的权重参数)为:
L t o t a l ( p ⃗ , a ⃗ , x ⃗ ) = α L c o n t e n t ( p ⃗ , x ⃗ ) + β L s t y l e ( a ⃗ , x ⃗ ) L_{total}(\vec{p},\vec{a},\vec{x}) = \alpha L_{content} (\vec{p},\vec{x}) + \beta L_{style}(\vec{a},\vec{x}) Ltotal(p ,a ,x )=αLcontent(p ,x )+βLstyle(a ,x )

【解释一下损失函数】(不想深入了解的可以不看这一趴)
1.关于内容的损失函数(公式如下):
L c o n t e n t ( p ⃗ , x ⃗ , l ⃗ ) = 1 2 ∑ i , j ( F i j l − P i j l ) 2 L_{content}(\vec{p},\vec{x},\vec{l}) = \frac{1}{2} \sum_{i,j}(F_{ij}^l-P_{ij}^l)^2 Lcontent(p ,x ,l )=21i,j(FijlPijl)2其中, p ⃗ \vec{p} p x ⃗ \vec{x} x 分别代表原始图像和生成的图像, P l P^l Pl F l F^l Fl则分别是它们各自在第 l l l层的特征表示;

2.关于风格的损失函数(公式如下):
G i , j l = ∑ k F i k l F j k l G_{i,j}^l = \sum_{k} F_{ik}^l F_{jk}^l Gi,jl=kFiklFjkl 其中, G i j l G_{ij}^l Gijl表示的是CNN中第l层的第i个Feature Map和第j个Feature Map的Gram矩阵(内积计算); E l = 1 4 N l 2 M l 2 ∑ i , j ( G i j l − A i j l ) 2 E_l = \frac{1}{4N_l^2M_l^2} \sum_{i,j}(G_{ij}^l-A_{ij}^l)^2 El=4Nl2Ml21i,j(GijlAijl)2 L s t y l e ( a ⃗ , x ⃗ ) = ∑ l = 0 L w l E l L_{style}(\vec{a},\vec{x}) = \sum_{l=0}^Lw_lE_l Lstyle(a ,x )=l=0LwlEl 其中,令 a ⃗ \vec{a} a x ⃗ \vec{x} x 分别表示原始图片和生成图片, A l A^l Al G l G^l Gl 分别是他们各自在第ll 层对应的风格表示;
对上述公式进行求偏导(公式实在是太难打了就不打了,感兴趣的伙伴们可以自己回去看论文)就可以做反向传播了,即令 L t o t a l L_{total} Ltotal最小化;【原文中说:为了生成混合了照片的内容和画作的风格的图片,我们共同地最小化了一个白噪声图像在网络中某一层照片的内容表达和画作在CNN的一系列层级中的风格表达的距离之和】

最后,我们来看一下网络的整体过程(Paper3,如下图),从下图中也可以看出来,每一次的画风迁移实际上都是将完整的网络跑一遍,从前向->反向传播,所以说Neural Style速度是很慢并且没有形成固定的风格模型(这也是Neural Style虽然在风格迁移方面有了很大的突破但并不能落地生产的原因,为了突破Neural Style的速度限制,后又有了Fast Neural Style)。
在这里插入图片描述

论文看完了我们来跑一下代码好啦

首先要配一些环境(代码是基于tensorflow的);

[TensorFlow](https://www.tensorflow.org/versions/master/get_started/os_setup.html#download-and-setup)
[NumPy](https://github.com/numpy/numpy/blob/master/INSTALL.rst.txt)
[SciPy](https://github.com/scipy/scipy/blob/master/INSTALL.rst.txt)
[Pillow](http://pillow.readthedocs.io/en/3.3.x/installation.html#installation)

然后要下载预训练好的VGGNet模型(需要放在根目录下);

[Pre-trained VGG network][net] (MD5 `106118b7cf60435e6d8e04f6a6dc3657`)

然后就可以run这个代码啦!没错,就是run!疯狂run!

python neural_style.py --content ./examples/c9.jpg 
                       --styles ./examples/s17.jpg 
                       --output c7-s9.jpg 

也可以查它的各种参数改参数设置,比如说迭代次数、权重等等;

python neural_style.py --h
usage: neural_style.py [-h] --content CONTENT --styles STYLE [STYLE ...]
                       --output OUTPUT [--iterations ITERATIONS]
                       [--print-iterations PRINT_ITERATIONS]
                       [--checkpoint-output OUTPUT]
                       [--checkpoint-iterations CHECKPOINT_ITERATIONS]
                       [--progress-write] [--progress-plot] [--width WIDTH]
                       [--style-scales STYLE_SCALE [STYLE_SCALE ...]]
                       [--network VGG_PATH]
                       [--content-weight-blend CONTENT_WEIGHT_BLEND]
                       [--content-weight CONTENT_WEIGHT]
                       [--style-weight STYLE_WEIGHT]
                       [--style-layer-weight-exp STYLE_LAYER_WEIGHT_EXP]
                       [--style-blend-weights STYLE_BLEND_WEIGHT [STYLE_BLEND_WEIGHT ...]]
                       [--tv-weight TV_WEIGHT] [--learning-rate LEARNING_RATE]
                       [--beta1 BETA1] [--beta2 BETA2] [--eps EPSILON]
                       [--initial INITIAL]
                       [--initial-noiseblend INITIAL_NOISEBLEND]
                       [--preserve-colors] [--pooling POOLING] [--overwrite]

我们来看一下Neural Style的效果如何,华丽丽的上图!
在这里插入图片描述

详解Neural Style的代码

如果只是单纯的跑个demo,或者这是了解一下Neural Style是做什么的,那么上述的内容就可以应付一下了,若果想要更深层次的了解Neural Style的训练和代码,可以继续看这一部分。
先放上大佬们详解代码的博客,大佬们写的超级好,而且无私的分享出来,感恩大佬,在这篇博客里不会写特别详细,只是把我自己觉得需要注明的地方记录了一下,还是再次推荐去看大佬们详解的博客!
@Quanfita大佬的博客:https://blog.csdn.net/qq_30611601/article/details/79007202#commentsedit
@XlyPb大佬的博客:https://blog.csdn.net/wspba/article/details/53994649
【------摘自大佬的博客,侵权立删------】
TensorFlow版本的源码主要包含了三个文件:neural_style.py, stylize.py和 vgg.py。我们来看一下这三个文件都干了些什么事情。
【vgg.py文件】 看名字就知道是VGGNet网络的文件,定义了模型网络(定义了下载与训练模型、卷积层、池化层和数据预处理)以及相关计算;
【stylize.py文件】 核心代码,包含了训练、优化等过程。一上来先定义了Content_layers和Style_layers分别是哪些层
【neural_style.py文件】 外部接口函数,定义了函数的主要参数以及部分参数的默认值,包含对图像的读取和存贮,对输入图像进行resize,权值分配等操作,并将参数以及resize的图片传入stylize.py中。

最后的最后,给大家安利几个博客,也是我这篇博客的参考资料:
@李嘉铭的知乎专栏 https://zhuanlan.zhihu.com/p/26746283 【这个作者是写的画风迁移(Neural Style)简史,很有必要了解一下】
@Quanfita大佬的博客:https://blog.csdn.net/qq_30611601/article/details/79007202#commentsedit
@XlyPb大佬的博客:https://blog.csdn.net/wspba/article/details/53994649
@AI之路大佬的博客 https://blog.csdn.net/u014380165/article/details/76286047
再次感谢大佬们的分享和小伙伴们的支持!这也是我们开博客以来第一次写专栏系列的内容,还请大家多多包容多多支持!我们下篇专栏博客见啦~

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值