前言
本文主要CNN系列论文解读——GoogLeNet简介、模型结构、网络结构的代码实现等。原文发表于语雀文档,排版更好看
【论文解读】CNN深度卷积神经网络-GoogLeNetwww.yuque.com
更多CNN论文解读系列:
【论文解读】CNN深度卷积神经网络-AlexNet
【论文解读】CNN深度卷积神经网络-VGG
【论文解读】CNN深度卷积神经网络-Network in Network
【论文解读】CNN深度卷积神经网络-GoogLeNet
【论文解读】CNN深度卷积神经网络-ResNet
【论文解读】CNN深度卷积神经网络-DenseNet
有用的话,请点个赞哦:)
1.简介
GoogLeNet是2014年Christian Szegedy等人在2014年大规模视觉挑战赛(ILSVRC2014)上使用的一种全新卷积神经网络结构,于2015年在CVPR发表了论文《Going Deeper with Convolutions》。在这之前的AlexNet、VGG等结构都是通过增大网络的深度(层数)来获得更好的训练效果,但层数的增加会带来很多负作用,比如overfit、梯度消失、梯度爆炸等。inception的提出则从另一种角度来提升训练结果:能更高效的利用计算资源,在相同的计算量下能提取到更多的特征,从而提升训练结果。
1.1 资源下载
📎【2015】【GoogLeNet】Szegedy_Going_Deeper_With_2015_CVPR_paper.pdf
2.Abstract
Abstract
We propose a deep convolutional neural network architecture codenamed Inception that achieves the new state of the art for classification and detection in the ImageNet Large Scale Visual Recognition Challenge 2014(ILSVRC14). The main hallmark of this architecture is theimproved utilization of the computing resources inside the network. By a carefully crafted design, we increased thedepth and width of the network while keeping the computational budget constant. To optimize quality, the architectural decisions were based on the Hebbian principle and the intuition of multi-scale processing. One particular in carnation used in our submission for ILSVRC14 is called GoogLeNet, a 22 layers deep network, the quality of which is assessed in the context of classification and detection.
翻译
我们提出了一种代号为Inception的深度卷积神经网络体系结构,该体系结构在ImageNet大规模视觉识别挑战赛2014(ILSVRC14)中实现了分类和检测的最新技术水平。 该体系结构的主要特点是提高了网络内部计算资源的利用率。 通过精心设计,我们在保持计算预算不变的情况下增加了网络的深度和宽度。 为了优化质量,架构决策基于Hebbian原则和多尺度处理的灵感。 在我们提交的ILSVRC14中使用的网络结构中的一个特殊名称是GoogLeNet,这是一个22层的深度网络,其质量在分类和检测领域都进行了评估。
3.网络结构
3.1 示意图
整体架构
上图为主要包含Inception块+辅助分类器的GoogLeNet结构示意图
Inception块
上图为Inception块示意图 (a)为普通的Inception块;(b)为带有1×1卷积的,可以对输入通道降维的Inception块
3.2 Inception块特点
- Inception块之间可以堆叠使用。
- 添加了1×1卷积,降低输入的通道维度,避免参数过量影响训练
- 多卷积核+池化的并行结构,通过合并层进行串联,实际上让网络具备了自动选择的能力,而不是人为地设置卷积或池化,或决定卷积核的尺寸。
针对同一个输入层,在Inception块中有四条并行的线路,其中前1~3个是1×1卷积层,第4个是一个MaxPooling池化层,这四条线路最后的输出拥有相同的shape和不同的channel通道数。于是,这些输出最后可在channel维度进行合并。 例如:28×28×64,28×28×128,28×28×32,28×28×32。 通道合并层的shape:28×28×256(64+128+32+32)
3.3 layer设计
GoogLeNet是作者团队在参加2014大规模视觉挑战赛时送去参加的几种Inception结构的模型之一。该网络设计时考虑了计算效率和实用性,故可以在单个设备上运行推理,对低内存设备比较友好。 整个网络使用了9个Inception块,结构排布如表格中所示:
整个网络深度为22层(参数层共计22层),maxpool池化层5层。还添加了网络中间一些辅助分类器具,这是考虑到由于深度较深,整个模型训练完成可能耗时较长,且浅层网络可能对中间层产生的特征具有较强识别能力,故添加了辅助分类器可以在模型训练的中间阶段就进行分类。在整个训练过程中,辅助分类器对于损失的以0.3的权重加到总损失中;推断时,辅助网络将被丢弃。
4.论文解读
1.介绍
论文先提到了两点: 1.在过去的几年中,由于深度学习和卷积神经网络的发展,图像分类和目标检测的能力得到显著提高。不仅仅是得益于硬件提升、更大的数据集和模型,而很重要一部分是得益于新的思想、新算法和网络结构的改进。2014年提交参赛ILSVRC 2014的网络结构GoogLeNet就是一种典型的新型网络,其参数量甚至比2012年Krizhevsky等人的AlexNet少12倍;还有在目标检测方面的R-CNN算法,并不是采用了更大更深的网络,而是得益于架构设计和经典CV的协同作用。 2.随着移动端和嵌入式设备的不断发展,算法效率和参数数量的控制越来越重要,我们需要考虑模型和算法在实际场景下的应用。
然后阐述了本论文的重点: 本文主要阐述名为Inception深度神经网络架构,其得名源于Network in Network以及“We need to go deeper”这个网络热点。在他们看来,deep有两层含义:1.表示以“初始模块”的形式引入新的架构,2.字面意义上的网络层数够深。通过该架构,作者团队活动了2014(ILSVRC14)的冠军,并大幅领先其他网络架构。
2.相关工作
Serre等人受灵长类视觉皮层神经科学模型的启发,使用一系列不同大小的固定Gabor过滤器来处理多个尺寸。在这里,作者使用了类似的策略。Inception架构中的所有filter都是学习来的,通过Inception块的堆叠,整个GoogLeNet的layer深度达到了22层。 作者团队借鉴了在Network in Network中使用的1×1卷积,这里的目的有2个,其中最主要的用来降维,通 过降低通道数来削减参数量。这样带来的效果是:同等参数量的模型,可达到更深和更宽。 最后作者提到了当前最新的由Girshick等人提出的目标检测模型R-CNN,总体可以将目标检测归纳为两个步骤,即two stage方法:1.利用低层次线索(如颜色和纹理),以一种类别不可知的方式生成物体的候选框bounding box;2.使用CNN分类器将所有候选框中的物体进行分类。作者表示,他们在检测方面的提及针对这两个阶段都进行了改进。
3.动机和深层次考虑
提高卷积神经网络模型表现的最直接方法——增加网络尺寸,这主要包括两方面:
- 1.增加layer数量,增加深度
- 2.增加网络width宽度
但是尺寸的增加也带来两个问题:
- 1.更大的参数规模,更容易过拟合
- 2.模型训练时占用更多计算机资源
论文里指出,解决这两个问题有个基础方法:引入稀疏型。用稀疏的layer代替全连接层,甚至在卷积内部。因为除了模仿生物系统外,根据Arora[2]等人的开创新工作,此举将有着充分的理论基础。他们的研究表明:如果数据集的概率分布可由一个大型的、非常稀疏的神经网络表示,那么可通过分析上一层激活信息的统计指标和将高度相关的神经元聚类来逐层地构建最佳网络拓扑。不幸的是,今天计算机的基础架构导致此类计算时效率很低,但是此类架构再未来可能会有一席之地。**作者表示Inception网络结构最初是源于一个案例研究,用于分析基于上述构想所构造的视觉网络的稀疏结构的效果,机缘巧合地发现其在定位和目标检测的任务中特别有效,虽然如此,对其有效性是否源于最初构想,任然需要进行更彻底的分析和验证。
4.结构细节
Inception结构的主要思想是考虑如何近似地估计卷积视觉网络的最佳局部稀疏结构,并方便地用Dense组件来实现它。Arora[2]等人提出了一种逐层构建的方法,即分析上一层的相关统计量,并将其聚类为具有高度相关性的unit单元组。这些聚合的单元组又成为了下一层的输入。于是这里是用一组filter来实现类似操作,通过filter提取上一层的特征信息,并在通道维上串联聚合,形成一整个concactanation连结层(见Inception块示意图中)
文中提到,目前固定Inception块中filter尺寸固定在1×1,3×3,5×5的原因是出于便利性考虑,因为大尺寸filter和小尺寸filter的混合会导致卷积后的尺寸对齐不太方便。 ** 还有,为什么给出的Inception模块分为两种结构,因为(a)类结构,由于层层叠加,容易导致在连结层的通道数暴增,为了解决此问题,需要在每一个Inception块用filter组进行特征提取前,先用1×1卷积进行降维处理,于是有了(b)类的Inception结构
总体而言,一个Inception网络,是一个由Inception块层层堆叠,中间穿插偶尔的Max pooling(stride 2)将尺寸减半的网络结构。出于训练性能开销的考虑,也可以在网络的较低层级部分使用传统的卷积层,而在较高层级上使用Inception块。
6.训练方法论
模型训练采用了DistBelief分布式机器学习系统对GoogleNet进行了训练(Cpu)。论文表示使用高端GPU,可以在1周内完成模型的训练。训练采用了0.9动量的异步随机梯度下降,固定学习率(每8个迭代学习率降低4%),另外使用各个各个尺寸的图片(数据增强)对于降低过拟合很有用。
9.总结
作者在论文中表示,用现有的dense结构来组合构建出最佳的稀疏结构,是改善计算机视觉神经网络的可行方法。与较浅和较窄的网络结构相比,该方法的优点在于计算量适度增加的情况下显著提高网络效果。在目标检测领域,尽管没有利用上下文和bounding box回归,我们的效果还是很好,进一步表面Inception结构的优越性,未来将在此基础上继续研究更加精细和自动化地方式来创造稀疏结构用以促进各领域的工作
5.代码实现
这里使用tensorflow2.0实现网络结构,而不是完整的训练,在《动手学深度学习》-tf2.0版一书中,有完整的训练代码。完整训练可参考:含并行连结的网络(GoogLeNet)
定义Inception块
import tensorflow as tf
class Inception(tf.keras.layers.Layer):
def __init__(self,c1, c2, c3, c4):
super().__init__()
# 线路1,单1 x 1卷积层
self.p1_1 = tf.keras.layers.Conv2D(c1, kernel_size=1, activation='relu', padding='same')
# 线路2,1 x 1卷积层后接3 x 3卷积层
self.p2_1 = tf.keras.layers.Conv2D(c2[0], kernel_size=1, padding='same', activation='relu')
self.p2_2 = tf.keras.layers.Conv2D(c2[1], kernel_size=3, padding='same',
activation='relu')
# 线路3,1 x 1卷积层后接5 x 5卷积层
self.p3_1 = tf.keras.layers.Conv2D(c3[0], kernel_size=1, padding='same', activation='relu')
self.p3_2 = tf.keras.layers.Conv2D(c3[1], kernel_size=5, padding='same',
activation='relu')
# 线路4,3 x 3最大池化层后接1 x 1卷积层
self.p4_1 = tf.keras.layers.MaxPool2D(pool_size=3, padding='same', strides=1)
self.p4_2 = tf.keras.layers.Conv2D(c4, kernel_size=1, padding='same', activation='relu')
def call(self, x):
p1 = self.p1_1(x)
p2 = self.p2_2(self.p2_1(x))
p3 = self.p3_2(self.p3_1(x))
p4 = self.p4_2(self.p4_1(x))
return tf.concat([p1, p2, p3, p4], axis=-1) # 在通道维上连结输出
构造整个网络
GoogLeNet跟VGG一样,在主体卷积部分中使用5个模块(block),每个模块之间使用步幅为2的3×3最大池化层来减小输出高宽。第一模块使用一个64通道的7×7卷积层。
b1 = tf.keras.models.Sequential()
b1.add(tf.keras.layers.Conv2D(64, kernel_size=7, strides=2, padding='same', activation='relu'))
b1.add(tf.keras.layers.MaxPool2D(pool_size=3, strides=2, padding='same'))
第二模块使用2个卷积层:首先是64通道的1×1卷积层,然后是将通道增大3倍的3×3卷积层。它对应Inception块中的第二条线路。
b2 = tf.keras.models.Sequential()
b2.add(tf.keras.layers.Conv2D(64, kernel_size=1, padding='same', activation='relu'))
b2.add(tf.keras.layers.Conv2D(192, kernel_size=3, padding='same', activation='relu'))
b2.add(tf.keras.layers.MaxPool2D(pool_size=3, strides=2, padding='same'))
第三模块串联2个完整的Inception块。第一个Inception块的输出通道数为64+128+32+32=256,其中4条线路的输出通道数比例为64:128:32:32=2:4:1:1。其中第二、第三条线路先分别将输入通道数减小至96/192=1/2和16/192=1/12后,再接上第二层卷积层。第二个Inception块输出通道数增至128+192+96+64=480,每条线路的输出通道数之比为128:192:96:64=4:6:3:2。其中第二、第三条线路先分别将输入通道数减小至128/256=1/2和32/256=1/8。
b3 = tf.keras.models.Sequential()
b3.add(Inception(64, (96, 128), (16, 32), 32))
b3.add(Inception(128, (128, 192), (32, 96), 64))
b3.add(tf.keras.layers.MaxPool2D(pool_size=3, strides=2, padding='same'))
第四模块更加复杂。它串联了5个Inception块,其输出通道数分别是:192+208+48+64=512、160+224+64+64=512、128+256+64+64=512、112+288+64+64=528和256+320+128+128=832。 这些线路的通道数分配和第三模块中的类似,首先含3×3卷积层的第二条线路输出最多通道,其次是仅含1×1卷积层的第一条线路,之后是含5×5卷积层的第三条线路和含3×3最大池化层的第四条线路。其中第二、第三条线路都会先按比例减小通道数。这些比例在各个Inception块中都略有不同。
b4 = tf.keras.models.Sequential()
b4.add(Inception(192, (96, 208), (16, 48), 64))
b4.add(Inception(160, (112, 224), (24, 64), 64))
b4.add(Inception(128, (128, 256), (24, 64), 64))
b4.add(Inception(112, (144, 288), (32, 64), 64))
b4.add(Inception(256, (160, 320), (32, 128), 128))
b4.add(tf.keras.layers.MaxPool2D(pool_size=3, strides=2, padding='same'))
第五模块有输出通道数为256+320+128+128=832和384+384+128+128=1024的两个Inception块。其中每条线路的通道数的分配思路和第三、第四模块中的一致,只是在具体数值上有所不同。需要注意的是,第五模块的后面紧跟输出层,该模块同NiN一样使用全局平均池化层来将每个通道的高和宽变成1。最后我们将输出变成二维数组后接上一个输出个数为标签类别数的全连接层。
b5 = tf.keras.models.Sequential()
b5.add(Inception(256, (160, 320), (32, 128), 128))
b5.add(Inception(384, (192, 384), (48, 128), 128))
b5.add(tf.keras.layers.GlobalAvgPool2D())
net = tf.keras.models.Sequential([b1, b2, b3, b4, b5, tf.keras.layers.Dense(1000)])
下面演示各个模块之间的输出的形状变化。
X = tf.random.uniform(shape=(1, 224, 224, 3))
for layer in net.layers:
X = layer(X)
print(layer.name, 'output shape:\t', X.shape)
输出:
sequential output shape: (1, 56, 56, 64)
sequential_1 output shape: (1, 28, 28, 192)
sequential_2 output shape: (1, 14, 14, 480)
sequential_3 output shape: (1, 7, 7, 832)
sequential_6 output shape: (1, 1024)
dense_1 output shape: (1, 1000)
6.总结
通过创新性的Inception模块和较为复杂的网络设计,使得作者团队在ILSVRC14上力压VGGNet夺冠。而GoogLeNet作为Inception模块设计的代表,有很多值得学习的地方。通过并行的filter将输入特征提取并在通道维上进行串联合并,构成下一层的输入,再将Inception块层层叠加。通过这种方式引入了稀疏型、模拟了卷积视觉网络的最佳拓扑结构。同时也让网络具备了自动选择的能力,而不是人为地设置卷积或池化,或决定卷积核的尺寸。 为了降低整体参数量,借鉴了Network in Network中的思想,在Inception块中添加了1×1卷积,有效降低了特征的维度,避免了参数爆炸。