从GoogLeNet架构到deep dream模型

文章来源: http://blog.csdn.net/diligent_321/article/details/53292484


虽然深度神经网络在计算机视觉方面的效果非常显著,但至今还没有非常严格的理论支撑。最开始学习CNN的时候,采用的都是手写体识别的例子,对其最直观的解释即随着层数增加,所学到的特征越来越抽象(大致按照“点-> 线->角->整体轮廓”的顺序)。同样地,谷歌技术团队在训练他们的GoogLeNet网络时,为了对网络所学到的特征有更好的理解,他们在特征可视化方面做了很多努力,同时也发现了一些美轮美奂的图画(如下为其中的一些)。本文将先介绍GoogLeNet网络结构相关的理论,再讲述特征可视化部分。 


  Deep Dream神经网络,也就是GoogLeNet网络结构,它是基于Inception识别模型的。传统的卷积神经网络莫过于LeCun的LeNet-5了,如下图所示, 

  它由卷积层、下采样层和全连接层组合而成,结构层数较少。而对于大型数据集,比如ImageNet数据集,为了显著提高算法的效果,就需要增加网络的复杂度(增加层数或者每层神经元个数),来增强模型的表达能力,同时,为了防止该模型过度拟合,比较简单的方法就是在训练模型的过程中,采用dropout的策略。但是通过增加网络复杂度来提高性能的方法是有缺点的,一是在训练数据数量固定的条件下,当网络结构变复杂时,伴随而来的是模型参数增加,更容易导致过拟合问题。二是网络结构变复杂时,计算量变大,所需的硬件资源也会快速增加,更糟糕的是,如果模型增加的表达能力没有得到高效利用的时候,比如最终学到的参数接近于0,那么就是对计算资源的一种浪费。针对上述问题,最好的解决办法就是使用稀疏连接的网络架构。大部分的机器学习系统都是通过卷积操作来实现稀疏性的,但是相对于前一层的局部感受野(local receptive field),卷积操作连接仍然属于密连接(dense connections)。与此同时,全连接的优势在于允许我们利用并行计算,充分发挥GPU的性能。那么如何更好的在sparse connections和dense connections之间取得平衡呢?Christian Szegedy等大牛们想到了Inception架构。Inception架构的最初想法是在卷积网络中,如何利用局部的dense connection来学习到一个近似的最优局部稀疏结构,它在局部化(localization)和目标识别等应用中取得了很好的效果。

Inception架构介绍

  Inception架构中存在着滤波器组(filter bank),为了避免patches对齐问题,通常的做法是把滤波器的大小设定为1x1、3x3、5x5,在深度网络模型中,滤波器组的输出合并在一起构成了下一层的输入。随着Inception模块逐步堆叠,抽象程度也会增加,所以3x3、5x5滤波器的比例应该增加(因为小的滤波器模板只能得到local features, 而大的滤波器模板可以得到高层的抽象特征),而这样做却会带来计算上的瓶颈。好的解决办法就是在计算量增加较多的地方采用降维和投影操作,具体来说,先使用1×1 convolutions算子来进行降维,再进行3×3和5×5 的卷积操作。关于1×1 convolution, 可能大家跟我一样,在以前没有听说过,这里解释一下,假设有一个卷积层的输出尺寸为(batch_size, feature_map_num1, height, width),其后接的是1×1 convolutions层,且其输出尺寸为(batch_size, feature_map_num2, height, width),那么当feature_map_num1 > feature_map_num2时,就达到了降维的效果,显然这里降低的是“feature map dimension”。总的来说,将这样的Inception模块级联在一起就构成了Inception网络,该网络中有时也会采用max-pooling操作来降低feature map的分辨率。Inception架构改进前后的图如下,其中“Filter concatenation”指的是将各个滤波器输出的feature maps,沿着feature maps维度堆叠在一起。(这里的卷积操作不考虑边界效应,即卷积前后单个feature map的尺寸保持不变,所以才可以’堆叠’)。 

GoogLeNet架构介绍

  GoogLeNet架构的核心是Inception模块,深度达到了27层,显然我们可以想到的是,在使用BP(back propagation)算法训练模型的时候,怎么克服“梯度消失”问题呢?大牛们想到了一个先验信息,层数相对较小的网络在分类问题上也可以取得不错的性能,那么深度网络中间层的特征对于分类来说,是有很强的区分能力的。通过添加辅助的分类器连接到这些中间层,不仅可以增加这些较低layers对于整个网络的最终输出的“贡献度”,从而解决梯度消失问题(事实上,有的算法在计算梯度时,采取了truncated的思想,其实质就是假定了较低layers对于网络的输出的贡献度低),还可以增强反向传播的梯度信号,对中间层进行额外的正则化操作。当然了,采用Relu激活函数对“梯度消失”现象也有一定的缓解作用。在训练阶段,总损失为主分类器的损失和辅助分类器的损失的加权求和,在测试阶段,辅助网络便被舍弃了。GoogLeNet网络的拓扑结构如下图, 

特征可视化

(1)加载和显示模型图

  因为GoogLeNet网络结构复杂,训练时间非常长,个人的话可能很难重头开始训练,幸运的是,google团队提供了他们训练好的一套模型参数,可以直接加载model graph到本地,这一部分的官方源代码比较琐碎,但语法都比较简单,这里就不细讲了。

(2)朴素的特征可视化

  关于深度神经网络的可视化,比较常见的是在训练好模型后,对某一层的权重参数进行可视化,因为权重参数实际上相当于一个空域滤波器。在这里,为了研究网络要学习输入图像中的什么特征,定义目标函数为网络中指定卷积层的指定feature map的平均值,参数为输入图像,而网络中之前学到的权值参数等为固定值(这里理解起来可能有些不太适应,大家可以结合优化问题的目标慢慢体会就好),这样就构建出了一个最大化问题,即寻找到使得某一feature map的平均值最大化的输入特征,于是便可以采用较常规的梯度上升方法来求解该问题。值得一提的是,官方源代码render_naive函数中,在计算出梯度后进行了标准化操作,这是因为deep layers相对于shallow layers的梯度可能偏小,这样做便可以使得不同层的学习速率基本相同了。当输入特征图初始化为均匀分布的随机噪声RGB图像时,在经过20次迭代更新操作之后,输入特征图像如下, 

(3)多尺度图像生成

  这里的多尺度是基于原图像尺寸而言的,具体来说,采用(2)中的方法可以学习到原始尺寸的特征图,然后对该特征图进行放大(可以采用多种插值方法,比如双线性插值),在从放大图中选择子窗口图像作为初始特征,重复以上过程。当然,这样会产生“块效应”,但可以在放大图中采用随机滑动的方式得到子窗口,从而有效地克服“块效应”问题。在经过3次这样的放大操作,每次放大图像进行了10次迭代更新操作之后,输入特征图像如下, 

(4)特征迁移

  在研究不同卷积层所学的输入特征后可以发现,deep layers要从输入图像中学习到非常复杂的特征,而与之相反,shallow layers要学到的特征相对较简单,如下左右两图分别是deep layers和shallow layers要学习到的特征图, 


  上面这张图是当输入初始化图为均匀分布的随机噪声得到的,那么如果我们初始化成特定的图像,会是什么效果呢?当然是会学习到图像中存在的一些模式,且这些模式和不同层的feature map是一一对应的。我实验了一张山水图,其处理前后的对比效果如下, 

  我也测试了一下lena图像迁移前后的效果,看着心里发慌,为了不破坏女神的形象,在这里就不贴了~

参考资料:”Going deeper with convolutions”. Christian Szegedy, Wei Liu, Yangqing Jia, etc. 
     https://github.com/tensorflow/tensorflow/blob/r0.11/tensorflow/examples/tutorials/deepdream/deepdream.ipynb


猜你喜欢

转载自blog.csdn.net/yangdelong/article/details/78374820
今日推荐