上节课我们学习了卷积神经网络的基本原理,本节实验我们将学习用于图像风格迁移的经典的卷积神经网络模型VGG,并用caffe提供的 draw_net.py
实现模型的可视化,本节实验我们也将学习图像风格转换的算法原理。
VGG16
实验楼环境内置
CNN的经典结构始于1998年的LeNet-5,成于2012年历史性的AlexNet,从此大盛于图像相关领域,主要包括:
GoogleNet
,2014年VGG
,2014年vgg 和 googlenet 是2014年 ImageNet
(图像分类大赛) 的双雄,这两类模型结构有一个共同特点是Go deeper。
VGG网络非常深,通常有 16/19
层,称作 VGG16
和 VGG19
,卷积核大小为 3 x 3
,16和19层的区别主要在于后面三个卷积部分卷积层的数量。
本实验主要讲解VGG16。
启动终端,进入caffe下的python目录:
确认是否有 draw_net.py
文件。
获得我们提供的VGG16的网格配置文件 vgg16_train_val.prototxt
。
$ sudo wget http://labfile.oss.aliyuncs.com/courses/861/vgg16_train_val.prototxt
安装依赖包,这些都是基于python的画图工具包。
安装完毕,准备可视化VGG16模型。
$ python draw_net.py /opt/caffe/python/vgg16_train_val.prototxt ~/Desktop/vgg16.png
程序运行完成之后,你可以通过以下命令查看vgg16.png
,这个即为可视化后的VGG16。
下图是官方给出的VGG16的数据表格:
首先我们先学会看懂一些式子的表达:
Conv3-512
→ 第三层卷积后维度变成512;
Conv3_2 s=2
→ 第三层卷积层里面的第二子层,滑动步长等于2(每次移动两个格子)
有了以上的知识可以开始剖析 VGG16
了。
由于篇幅的关系我们只推演从 Input
到 Conv1
,再从 Conv1
过渡到 Conv2
的过程。
Input
到 Conv1
假如我们输入的是 300x300
的RGB图像,那么输入层接受的输入就是 300x300x3
个神经元。
图中的两个黄色表示卷积层,是VGG16网络结构十六层当中的第一层(Conv1_1)和第二层(Conv1_2),他们合称为Conv1。由上节的知识,我们可以知道卷积核大小应为 3x3x3
。经过卷积层的运算我们可以得到一维的 298x298x1
的矩阵(因为卷积核也是三维所以结果是一维
),为了在下一层中可以继续用 3x3
的卷积核做卷积,我们需要进行 Padding
操作,将图像扩充为 300x300x1
,而 VGG16
在Conv1这层中使用了64个卷积核,那么生成了64张对应不同卷积核的 feature map
,这样就得到了上图最终的结果 300x300x64
。
Conv1
的 Conv2
过渡这一步操作使用 Pooling
,使用的 池化卷积核
为 2*2*64
,步长为 2
,那么滑动的矩阵本身没有重叠;刚好减半,第三维度 64
不变。
其实之后的步骤都是类似的,根据我们刚刚画出的VGG16或者官方给出的表格,理解每一层有什么卷积核?多少个?池化的大小?步长多少?是否需要Padding?一步步思考,你就可以完全掌握VGG16的原理。
Image Style Transfer
以目前的深度学习技术,如果给定两张图像,完全有能力让计算机识别出图像具体内容。而图像的风格是一种很抽象的东西,人眼能够很有效地的辨别出不同画家不同流派绘画的风格,而在计算机的眼中,本质上就是一些像素,多层网络的实质其实就是找出更复杂、更内在的特性(features),所以图像的风格理论上可以通过多层网络来提取图像里面可能含有的一些有意思的特征。
将一幅图像的风格转移到另外一幅图像上被认为是一个图像纹理转移问题,传统上一般采用的是一些非参方法,通过一些专有的固定的方法(提取图像的亮度、低频颜色信息、高频纹理信息)来渲染。但是这些方法的问题在于只能提取底层特征而非高层抽象特征,而且往往一个程序只能做某一种风格或者某一个场景。随着CNN的日渐成熟,图像风格迁移技术也迎来了一次变革。需要注意的是,最近的很多应用型的研究成果都是将CNN渗透进各个领域,从而在普遍意义上完成一次技术的升级。
实现图像的风格转换我们需要下面几个原料:
VGG
给定一张风格图像 a 和一张普通图像 p,风格图像经过 VGG 的时候在每个卷积层会得到很多 feature maps
, 这些 feature maps 组成一个集合 A,同样的,普通图像 p 通过 VGG 的时候也会得到很多 feature maps,这些 feature maps 组成一个集合 P,然后生成一张随机噪声图像 x(在后面的实验中,其实就是普通图像 p), 随机噪声图像 x 通过 VGG 的时候也会生成很多 feature maps,这些 feature maps 构成集合 G 和 F 分别对应集合 A 和 P, 最终的优化函数是希望调整 x , 让随机噪声图像 x 最后看起来既保持普通图像 p 的内容, 又有一定的风格图像 a 的风格。
可以进行风格转换的基础就是将内容和风格区分开来,接下来我们来看CNN如何做到这一点。
Content Representation
给定一个图像 p,卷积神经网络每层使用滤波器(卷积核 filter
)对图像进行编码。在 CNN 中, 假设 layer l
有个 filters, 那么将会生成个 feature maps,每个 feature map 的维度为 , 代表 feature map 的高与宽的乘积。所以每一层 feature maps 的集合可以表示为
,表示第 i 个 filter
在 position j
上的激活值。
所以,我们可以给出 Content 的 cost function
,其中,p 是内容图像,x 是生成图像 :
对其求导后对应的激活函数为 :
有了这个公式之后要怎么做呢?
使用现在公布的训练好的某些CNN网络,随机初始化一个输入图片大小的噪声图像x,然后保持CNN参数不变,将内容图片 p 和随机图像 x 输入进网络,然后对x求导,这样,x 就会在内容上越来越趋近于p。
Style Representation
对于风格提取,我们需要用到 Gram matrix
。
Gram矩阵是计算每个通道i的feature map与每个通道j的feature map的内积。这个值可以看作代表i通道的feature map与j通道的feature map的互相关程度。而它又为什么能代表图片风格呢?
假设我们要对梵高的星空图做风格提取,在神经网络中某一层中有一个滤波器专门检测尖尖的塔顶这样的东西,另一个滤波器专门检测黑色。又有一个滤波器负责检测圆圆的东西,又有一个滤波器用来检测金黄色。
对梵高的原图做Gram矩阵,谁的相关性会比较大呢?如上图所示,“尖尖的”和“黑色”总是一起出现的,它们的相关性比较高。而“圆圆的”和“金黄色”都是一起出现的,他们的相关性比较高。
因此在风格转移的时候,其实也在内容图(待风格转换的图)里去寻找这种“匹配”,将尖尖的渲染为黑色(如塔尖),将圆圆的渲染为金黄色(如近圆的房顶)。如果我们承认“图像的艺术风格就是其基本形状与色彩的组合方式” ,这样一个假设,那么Gram矩阵能够表征艺术风格就是理所当然的事情了。
风格的抽取仍然是以层为单位的,对于风格图像 a,为了建立风格的 representation,我们先利用 Gram matrix
去表示每一层各个 feature maps 之间的关系,,是 x 的 feature maps i,j 的内积,是 a 的feature maps i,j 的内积。
利用 Gram matrix,我们可以建立每一层的关于 style 的 cost function
,
求偏导后对应的激励函数:
结合所有层,可以得到总的 cost
:
不考虑风格转换,只单独的考虑内容或者风格,可以看到如图所示: