深入解读GoogLeNet网络结构(附代码实现)

前言

七夕了,看着你们秀恩爱,单身狗的我还是做俺该做的事吧!

在上一篇文章中介绍了VGG网络结构,VGG在2014年ImageNet 中获得了定位任务第1名和分类任务第2名的好成绩,而同年分类任务的第一名则是GoogleNet 。GoogleNet是Google研发的深度网络结构,之所以叫“GoogLeNet”,是为了向“LeNet”致敬,有兴趣的同学可以看下原文Going Deeper with Convolutions

与VGGNet模型相比较,GoogleNet模型的网络深度已经达到了22层( 如果只计算有参数的层,GoogleNet网络有22层深 ,算上池化层有27层),而且在网络架构中引入了Inception单元,从而进一步提升模型整体的性能。虽然深度达到了22层,但大小却比AlexNet和VGG小很多,GoogleNet参数为500万个( 5M ),VGG16参数是138M,是GoogleNet的27倍多,而VGG16参数量则是AlexNet的两倍多。

Inception单元结构

我们先来看一下模型中的Inception单元结构,然后在此基础上详细分析GoogleNet网络结构,这里推荐看一下我的这篇博客从Inception到Xception,卷积方式的成长之路,可以对下面的内容有更好的理解。

Inception 最初提出的版本主要思想是利用不同大小的卷积核实现不同尺度的感知,网络结构图如下:
在这里插入图片描述
Inception Module基本组成结构有四个成分。1*1卷积,3*3卷积,5*5卷积,3*3最大池化。最后对四个成分运算结果进行通道上组合,这就是Naive Inception的核心思想:利用不同大小的卷积核实现不同尺度的感知,最后进行融合,可以得到图像更好的表征。

下面通过一个具体的实例来看看整个Naive Inception单元的详细工作过程,假设在上图中Naive Inception单元的前一层输入的数据是一个32×32×256的特征图,该特征图先被复制成4份并分别被传至接下来的4个部分。我们假设这4个部分对应的滑动窗口的步长均为1,其中,1×1卷积层的Padding为0,滑动窗口维度为1×1×256,要求输出的特征图深度为128;3×3卷积层的Padding为1,滑动窗口维度为3×3×256,要求输出的特征图深度为192;5×5卷积层的Padding为2,滑动窗口维度为5×5×256,要求输出的特征图深度为96;3×3最大池化层的 Padding为1,滑动窗口维度为3×3×256。这里对每个卷积层要求输出的特征图深度没有特殊意义,仅仅举例用,之后通过计算,分别得到这4部分输出的特征图为32×32×128、32×32×192、32×32×96 和 32×32×256,最后在合并层进行合并,得到32×32×672的特征图,合并的方法是将各个部分输出的特征图相加,最后这个Naive Inception单元输出的特征图维度是32×32×672,总的参数量就是1*1*256*128+3*3*256*192+5*5*256*96=1089536

但是Naive Inception有两个非常严重的问题:首先,所有卷积层直接和前一层输入的数据对接,所以卷积层中的计算量会很大;其次,在这个单元中使用的最大池化层保留了输入数据的特征图的深度,所以在最后进行合并时,总的输出的特征图的深度只会增加,这样增加了该单元之后的网络结构的计算量。于是人们就要想办法减少参数量来减少计算量,在受到了模型 “Network in Network”的启发,开发出了在GoogleNet模型中使用的Inception单元(Inception V1),这种方法可以看做是一个额外的1*1卷积层再加上一个ReLU层。如下所示:

在这里插入图片描述

这里使用1x1 卷积核主要目的是进行压缩降维,减少参数量,从而让网络更深、更宽,更好的提取特征,这种思想也称为Pointwise Conv,简称PW。

举个例子来论证下吧。假设新增加的 1×1 的卷积的输出深度为64,步长为1,Padding为0,其他卷积和池化的输出深度、步长都和之前在Naive Inception单元中定义的一样(即上面例子中定义的一样),前一层输入的数据仍然使用同之前一样的维度为32×32×256的特征图,通过计算,分别得到这 4 部分输出的特征图维度为32×32×128、32×32×192、32×32×96 和32×32×64,将其合并后得到维度为32×32×480的特征图,将这4部分输出的特征图进行相加,最后Inception单元输出的特征图维度是32×32×480。新增加的3个 1×1 的卷积参数量是3*1*1*256*64=49152,原来的卷积核参数量是1*1*256*128+3*3*64*192+5*5*64*96=296960,总的参数量就是49152+296960=346112

在输出的结果中,32×32×128、32×32×192、32×32×96 和之前的Naive Inception 单元是一样的,但其实这三部分因为1×1卷积层的加入,总的卷积参数数量已经大大低于之前的Naive Inception单元而且因为在最大池化层之前也加入了1×1的卷积层,所以最终输出的特征图的深度也降低了,这样也降低了该单元之后的网络结构的计算量

GoogLeNet模型解读

GoogleNet网络结构(Inception V1)的网络结构如下:

在这里插入图片描述

GoogLeNet网络有22层深(包括pool层,有27层深),在分类器之前,采用Network in Network中用Averagepool(平均池化)来代替全连接层的思想,而在avg pool之后,还是添加了一个全连接层,是为了大家做finetune(微调)。而无论是VGG还是LeNet、AlexNet,在输出层方面均是采用连续三个全连接层,全连接层的输入是前面卷积层的输出经过reshape得到。据发现,GoogLeNet将fully-connected layer用avg pooling layer代替后,top-1 accuracy 提高了大约0.6%;然而即使在去除了fully-connected layer后,依然必须dropout。

由于全连接网络参数多,计算量大,容易过拟合,所以GoogLeNet没有采用VGG、LeNet、AlexNet三层全连接结构,直接在Inception模块之后使用Average Pool和Dropout方法,不仅起到降维作用,还在一定程度上防止过拟合。

在Dropout层之前添加了一个7×7的Average Pool,一方面是降维,另一方面也是对低层特征的组合。我们希望网络在高层可以抽象出图像全局的特征,那么应该在网络的高层增加卷积核的大小或者增加池化区域的大小,GoogLeNet将这种操作放到了最后的池化过程,前面的Inception模块中卷积核大小都是固定的,而且比较小,主要是为了卷积时的计算方便。

GoogLeNet在网络模型方面与AlexNet、VGG还是有一些相通之处的,它们的主要相通之处就体现在卷积部分,

  • AlexNet采用5个卷积层
  • VGG把5个卷积层替换成5个卷积块
  • GoogLeNet采用5个不同的模块组成主体卷积部分

用表格的形式表示GoogLeNet的网络结构如下所示:
在这里插入图片描述
上述就是GoogLeNet的结构,可以看出,和AlexNet统一使用5个卷积层、VGG统一使用5个卷积块不同,GoogLeNet在主体卷积部分是卷积层与Inception块混合使用。另外,需要注意一下,在输出层GoogleNet采用全局平均池化,得到的是高和宽均为1的卷积层,而不是通过reshape得到的全连接层。

需要注意的是,上图中 “#3×3reduce” 和 “#5×5reduce” 表示在3×3和5×5卷积之前,使用的降维层中的1×1滤波器的数量。pool proj代表max-pooling后的投影数量(即先max-pooling,再PW降维),所有的reductions(降维)和projections(投影)也都使用激活函数ReLU。

下面就来详细介绍一下GoogLeNet的模型结构。

输入

原始输入图像为224x224x3,且都进行了零均值化的预处理操作(图像每个像素减去均值)

第一模块

第一模块采用的是一个单纯的卷积层紧跟一个最大池化层。

卷积层:卷积核大小7*7,步长为2,padding为3,输出通道数64,输出特征图尺寸为(224-7+3*2)/2+1=112.5(向下取整)=112,输出特征图维度为112x112x64,卷积后进行ReLU操作。

池化层:窗口大小3*3,步长为2,输出特征图尺寸为((112 -3)/2)+1=55.5(向上取整)=56,输出特征图维度为56x56x64。

关于卷积和池化中的特征图大小计算方式,可以参考我的博客神经网络之多维卷积的那些事

第二模块

第二模块采用2个卷积层,后面跟一个最大池化层。
在这里插入图片描述

卷积层:

  1. 先用64个1x1的卷积核(3x3卷积核之前的降维)将输入的特征图(56x56x64)变为56x56x64,然后进行ReLU操作。参数量是1*1*64*64=4096
  2. 再用卷积核大小3*3,步长为1,padding为1,输出通道数192,进行卷积运算,输出特征图尺寸为(56-3+1*2)/1+1=56,输出特征图维度为56x56x192,然后进行ReLU操作。参数量是3*3*64*192=110592

第二模块卷积运算总的参数量是110592+4096=114688,即114688/1024=112K

池化层: 窗口大小3*3,步长为2,输出通道数192,输出为((56 - 3)/2)+1=27.5(向上取整)=28,输出特征图维度为28x28x192。

第三模块(Inception 3a层)

Inception 3a层,分为四个分支,采用不同尺度,图示如下:

在这里插入图片描述
再看下表格结构,来分析和计算吧:
在这里插入图片描述

  1. 使用64个1x1的卷积核,运算后特征图输出为28x28x64,然后RuLU操作。参数量1*1*192*64=12288
  2. 96个1x1的卷积核(3x3卷积核之前的降维)运算后特征图输出为28x28x96,进行ReLU计算,再进行128个3x3的卷积,输出28x28x128。参数量1*1*192*96+3*3*96*128=129024
  3. 16个1x1的卷积核(5x5卷积核之前的降维)将特征图变成28x28x16,进行ReLU计算,再进行32个5x5的卷积,输出28x28x32。参数量1*1*192*16+5*5*16*32=15872
  4. pool层,使用3x3的核,输出28x28x192,然后进行32个1x1的卷积,输出28x28x32.。总参数量1*1*192*32=6144

将四个结果进行连接,对这四部分输出结果的第三维并联,即64+128+32+32=256,最终输出28x28x256。总的参数量是12288+129024+15872+6144=163328,即163328/1024=159.5K,约等于159K。

第三模块(Inception 3b层)

Inception 3b层,分为四个分支,采用不同尺度。

  1. 128个1x1的卷积核,然后RuLU,输出28x28x128
  2. 128个1x1的卷积核(3x3卷积核之前的降维)变成28x28x128,进行ReLU,再进行192个3x3的卷积,输出28x28x192
  3. 32个1x1的卷积核(5x5卷积核之前的降维)变成28x28x32,进行ReLU,再进行96个5x5的卷积,输出28x28x96
  4. pool层,使用3x3的核,输出28x28x256,然后进行64个1x1的卷积,输出28x28x64

将四个结果进行连接,对这四部分输出

  • 88
    点赞
  • 479
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 22
    评论
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雷恩Layne

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值