手撕 CNN 经典网络之 VGGNet(理论篇)

Posted 红色石头Will

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了手撕 CNN 经典网络之 VGGNet(理论篇)相关的知识,希望对你有一定的参考价值。

2014年,牛津大学计算机视觉组(Visual Geometry Group)和Google DeepMind公司一起研发了新的卷积神经网络,并命名为VGGNet。VGGNet是比AlexNet更深的深度卷积神经网络,该模型获得了2014年ILSVRC竞赛的第二名,第一名是GoogLeNet(我们之后会介绍)。

论文《Very Deep Convolutional Networks for Large-Scale Image Recognition》

论文传送门:https://arxiv.org/abs/1409.1556

1. 网络结构

VGG 的结构与 AlexNet 类似,区别是深度更深,但形式上更加简单。VGG由5层卷积层、3层全连接层、1层softmax输出层构成,层与层之间使用maxpool(最大化池)分开,所有隐藏层的激活单元都采用ReLU函数。作者在原论文中,根据卷积层不同的子层数量,设计了A、A-LRN、B、C、D、E这6种网络结构。

这6种网络结构相似,都是由5层卷积层、3层全连接层组成,区别在于每个卷积层的子层数量不同,从A至E依次增加,总的网络深度从11层到19层。表格中的卷积层参数表示为“conv(感受野大小)-通道数”,例如con3-64,表示使用3x3的卷积核,通道数为64;最大池化表示为maxpool,层与层之间使用maxpool分开;全连接层表示为“FC-神经元个数”,例如FC-4096表示包含4096个神经元的全连接层;最后是softmax层。

其中,D表示著名的VGG16,E表示著名的VGG19。下面以VGG16为例,来详细剖析一下VGG的网络结构。VGG16的结构如下图所示:

VGG16总共包含16个子层,第1层卷积层由2个conv3-64组成,第2层卷积层由2个conv3-128组成,第3层卷积层由3个conv3-256组成,第4层卷积层由3个conv3-512组成,第5层卷积层由3个conv3-512组成,然后是2个FC4096,1个FC1000。总共16层,这也就是VGG16名字的由来。

1.1 输入层

VGG输入图片的尺寸是224x224x3。

1.2 第1层卷积层

第1层卷积层由2个conv3-64组成。

该层的处理流程是:卷积-->ReLU--> 卷积-->ReLU-->池化。

卷积:输入是224x224x3,使用64个3x3x3的卷积核进行卷积,padding=1,stride=1,根据公式:

(input_size + 2 * padding - kernel_size) / stride + 1=(224+2*1-3)/1+1=224

得到输出是224x224x64。

ReLU:将卷积层输出的FeatureMap输入到ReLU函数中。

卷积:输入是224x224x64,使用64个3x3x64的卷积核进行卷积,padding=1,stride=1,根据公式:

(input_size + 2 * padding - kernel_size) / stride + 1=(224+2*1-3)/1+1=224

得到输出是224x224x64。

ReLU:将卷积层输出的FeatureMap输入到ReLU函数中。

池化:使用2x2,stride=2的池化单元进行最大池化操作(max pooling)。根据公式:

(224+2*0-2)/2+1=112

每组得到的输出为112x112x64。

1.3 第2层卷积层

第2层卷积层由2个conv3-128组成。

该层的处理流程是:卷积-->ReLU--> 卷积-->ReLU-->池化。

卷积:输入是112x112x64,使用128个3x3x64的卷积核进行卷积,padding=1,stride=1,根据公式:

(input_size + 2 * padding - kernel_size) / stride + 1=(112+2*1-3)/1+1=112

得到输出是112x112x128。

ReLU:将卷积层输出的FeatureMap输入到ReLU函数中。

卷积:输入是112x112x128,使用128个3x3x128的卷积核进行卷积,padding=1,stride=1,根据公式:

(input_size + 2 * padding - kernel_size) / stride + 1=(112+2*1-3)/1+1=112

得到输出是112x112x128。

ReLU:将卷积层输出的FeatureMap输入到ReLU函数中。

池化:使用2x2,stride=2的池化单元进行最大池化操作(max pooling)。根据公式:

(112+2*0-2)/2+1=56

每组得到的输出为56x56x128。

1.4 第3层卷积层

第3层卷积层由3个conv3-256组成。

该层的处理流程是:卷积-->ReLU--> 卷积-->ReLU-->池化。

卷积:输入是56x56x128,使用256个3x3x128的卷积核进行卷积,padding=1,stride=1,根据公式:

(input_size + 2 * padding - kernel_size) / stride + 1=(56+2*1-3)/1+1=56

得到输出是56x56x256。

ReLU:将卷积层输出的FeatureMap输入到ReLU函数中。

卷积:输入是56x56x256,使用256个3x3x256的卷积核进行卷积,padding=1,stride=1,根据公式:

(input_size + 2 * padding - kernel_size) / stride + 1=(56+2*1-3)/1+1=56

得到输出是56x56x256。

ReLU:将卷积层输出的FeatureMap输入到ReLU函数中。

池化:使用2x2,stride=2的池化单元进行最大池化操作(max pooling)。根据公式:

(56+2*0-2)/2+1=28

每组得到的输出为28x28x256。

1.5 第4层卷积层

第4层卷积层由3个conv3-512组成。

该层的处理流程是:卷积-->ReLU--> 卷积-->ReLU-->池化。

卷积:输入是28x28x256,使用512个3x3x256的卷积核进行卷积,padding=1,stride=1,根据公式:

(input_size + 2 * padding - kernel_size) / stride + 1=(28+2*1-3)/1+1=28

得到输出是28x28x512。

ReLU:将卷积层输出的FeatureMap输入到ReLU函数中。

卷积:输入是28x28x512,使用512个3x3x512的卷积核进行卷积,padding=1,stride=1,根据公式:

(input_size + 2 * padding - kernel_size) / stride + 1=(28+2*1-3)/1+1=28

得到输出是28x28x512。

ReLU:将卷积层输出的FeatureMap输入到ReLU函数中。

池化:使用2x2,stride=2的池化单元进行最大池化操作(max pooling)。根据公式:

(28+2*0-2)/2+1=14

每组得到的输出为14x14x512。

1.6 第5层卷积层

第5层卷积层由3个conv3-512组成。

该层的处理流程是:卷积-->ReLU--> 卷积-->ReLU-->池化。

卷积:输入是14x14x512,使用512个3x3x512的卷积核进行卷积,padding=1,stride=1,根据公式:

(input_size + 2 * padding - kernel_size) / stride + 1=(14+2*1-3)/1+1=14

得到输出是14x14x512。

ReLU:将卷积层输出的FeatureMap输入到ReLU函数中。

卷积:输入是14x14x512,使用512个3x3x512的卷积核进行卷积,padding=1,stride=1,根据公式:

(input_size + 2 * padding - kernel_size) / stride + 1=(14+2*1-3)/1+1=14

得到输出是14x14x512。

ReLU:将卷积层输出的FeatureMap输入到ReLU函数中。

池化:使用2x2,stride=2的池化单元进行最大池化操作(max pooling)。根据公式:

(14+2*0-2)/2+1=7

每组得到的输出为7x7x512。

1.7 第1层全连接层

第1层全连接层FC4096由4096个神经元组成。

该层的处理流程是:FC-->ReLU-->Dropout。

FC:输入是7x7x512的FeatureMap,展开为7*7*512的一维向量,即7*7*512个神经元,输出为4096个神经元。

ReLU:这4096个神经元的运算结果通过ReLU激活函数中。

Dropout:随机的断开全连接层某些神经元的连接,通过不激活某些神经元的方式防止过拟合。

1.8 第2层全连接层

第2层全连接层FC4096由4096个神经元组成。

该层的处理流程是:FC-->ReLU-->Dropout。

FC:输入是4096个神经元,输出为4096个神经元。

ReLU:这4096个神经元的运算结果通过ReLU激活函数中。

Dropout:随机的断开全连接层某些神经元的连接,通过不激活某些神经元的方式防止过拟合。

1.9 第3层全连接层

第3层全连接层FC1000由1000个神经元组成,对应ImageNet数据集的1000个类别。

该层的处理流程是:FC。

FC:输入是4096个神经元,输出为1000个神经元。

1.10 softmax层

该层的流程为:Softmax

Softmax:这1000个神经元的运算结果通过Softmax函数中,输出1000个类别对应的预测概率值。

2. 全卷积网络

接着对1.7、1.8、1.9节的内容进行介绍。这三节讲的是全连接网络,VGG16在训练的时候使用的是全连接网络。然而在测试验证阶段,网络结构稍有不同,作者将全连接全部替换为卷积网络。

先介绍做法!

2.1 第1层全连接层

输入为7x7x512的FeatureMap,使用4096个7x7x512的卷积核进行卷积,由于卷积核尺寸与输入的尺寸完全相同,即卷积核中的每个系数只与输入尺寸的一个像素值相乘一一对应,根据公式:

(input_size + 2 * padding - kernel_size) / stride + 1=(7+2*0-7)/1+1=1

得到输出是1x1x4096。相当于4096个神经元,但属于卷积层。

2.2 第2层全连接层

输入为1x1x4096的FeatureMap,使用4096个1x1x4096的卷积核进行卷积,由于卷积核尺寸与输入的尺寸完全相同,即卷积核中的每个系数只与输入尺寸的一个像素值相乘一一对应,根据公式:

(input_size + 2 * padding - kernel_size) / stride + 1=(1+2*0-1)/1+1=1

得到输出是1x1x4096。相当于4096个神经元,属于卷积层。

2.3 第2层全连接层

输入为1x1x4096的FeatureMap,使用1000个1x1x4096的卷积核进行卷积,由于卷积核尺寸与输入的尺寸完全相同,即卷积核中的每个系数只与输入尺寸的一个像素值相乘一一对应,根据公式:

(input_size + 2 * padding - kernel_size) / stride + 1=(1+2*0-1)/1+1=1

得到输出是1x1x1000。相当于1000个神经元,属于卷积层。

得到1x1x1000的输出之后,最后经过softmax层进行预测类别。

2.4 为什么要将全连接层转变为全卷积层?

作者将三个全连接层转成了1个7×7,和 2 个 1×1 的卷积层。从下图可以看到,以第一个全连接层为例,要转卷积层,FC6的输入是 7×7×512,输出是4096(也可以看做 1×1×4096),那么就要对输入在尺寸上(宽高)降维(从7×7 降到 1×1)和深度(channel 或者 depth)升维(从512 升到4096)。把7×7降到1×1,使用大小为 7×7的卷积核就好了,卷积核个数设置为4096,即卷积核为7×7×4096(下图中的[7×7×512]×4096 表示有 4096 个 [7×7×512] 这样的卷积核,7×7×4096 是简写形式忽略了输入的深度),经过对输入卷积就得到了最终的 1×1×4096 大小的 feature map。

为什么要在模型测试的时候将全连接层转变为全卷积层呢?最直接的原因是让网络模型可以接受任意大小的尺寸。

我们在前面介绍的时候限定了网络输入图片的尺寸是224x224x3。如果后面三个层都是全连接,遇到宽高大于224的图片就需要进行图片的剪裁、缩放或其它处理,使图片尺寸统一到224x224x3,才能符合后面全连接层的输入要求。但是,我们并不能保证每次裁剪都能将图片中的关键目标保留下来,可能裁剪去的部分恰好包含了目标,造成裁减丢失关键目标信息,影响模型的测试精度。

(输出是一个分类得分图,通道的数量和类别的数量相同,空间分辨率依赖于输入图像尺寸。最终为了得到固定尺寸的分类得分向量,将分类得分图进行空间平均化(求和——池化)。我们同样使用水平翻转来对测试集进行数据增强;在原始图像和翻转图像上的soft-max分类概率的平均值作为这幅图像的最终得分。)

使用全卷积层,即使图片尺寸大于224x224x3,最终经过softmax层得到的得分图就不是1x1x1000,例如是2x2x1000,这里的通道1000与类别的数量相同,空间分辨率2x2依赖于输入图像尺寸。然后将得分图进行空间平均化(求和池化),得到的还是1x1x1000。最后对1000个通道的得分进行比较,取较大值作为预测类别。

这样做的好处就是大大减少特征位置对分类带来的影响。

举个简单的例子:

从上图我们可以看出,猫在原图片中不同的位置,如果使用全连接层很容易使得剪裁之后的图片丢失关键目标。然而使用全卷积层,对原图片直接进行卷积,最终得分图经过求和池化后得到的得分都是1,即不管猫在图片的什么位置,都能判定这张图片中有猫,保证分类正确。保留原图,使用全卷积层,相当于猫在哪我不管,我只要猫,于是我让模型去把这个猫找到,实际就是把feature map整合成一个值,这个值大,就有猫,这个值小,那就可能没猫!和这个猫在图片哪里关系不大了,鲁棒性大大增强。

3. VGG网络特点

3.1 结构简洁

虽然VGG层数较多,总的网络深度从11层到19层,但是它的整体结构还是相对简单。概括来说,VGG由5层卷积层(每个卷积层的子层数量不同)、3层全连接层、softmax输出层构成,层与层之间使用maxpooling(最大化池)分开,所有隐层的激活单元都采用ReLU函数。

3.2 小卷积核

小卷积核是VGG的一个重要特点,VGG没有采用AlexNet中比较大的卷积核尺寸(如7x7),而是通过降低卷积核的大小(3x3),增加卷积子层数来达到同样的性能(VGG:从1到4卷积子层,AlexNet:1子层)。

VGG使用多个较小卷积核(3x3)的卷积层代替一个卷积核较大的卷积层,VGG作者认为两个3x3的卷积堆叠获得的感受野大小,相当一个5x5的卷积;而3个3x3卷积的堆叠获取到的感受野相当于一个7x7的卷积。示意图如下所示:

使用3x3小卷积核的好处有两个方面:

一是大幅度减少模型参数数量。例如使用2个3x3的卷积核代替1个5x5的卷积核,通道数为C,1个5x5的卷积核参数量为5*5*C,2个3x3的卷积核参数量为2*3*3*C,参数两减小了28%。另外,小卷积核选取小的 stride可以防止较大的stride导致细节信息的丢失。

二是多层卷积层(每个卷积层后都有非线性激活函数),增加非线性,提升模型性能。

此外,我们注意到在VGG网络结构D中,还使用了1x1卷积核,1x1卷积核可以在不改变感受野的情况下,增加模型的非线性(后面的非线性激活函数)。同时,还可以用它来整合各通道的信息,并输出指定通道数。通道数减小即降维,通道数增加即升维。

3.3 小池化核

相比AlexNet的3x3的池化核,VGG全部采用2x2的池化核。

3.4 通道数更多,特征度更宽

每个通道代表着一个FeatureMap,更多的通道数表示更丰富的图像特征。VGG网络第一层的通道数为64,后面每层都进行了翻倍,最多到512个通道,通道数的增加,使得更多的信息可以被提取出来。

3.5 层数更深

使用连续的3x3小卷积核代替大的卷积核,网络的深度更深,并且对边缘进行填充,卷积的过程并不会减小图像尺寸。仅使用小的2x2池化单元,减小图像的尺寸。

3.6 全连接转卷积

这部分内容在全卷积网络已经介绍过了。

3.7 模型参数

A、A-LRN、B、C、D、E这6种网络结构的深度虽然从11层增加至19层,但参数量变化不大,这是由于基本上都是采用了小卷积核,参数主要集中在全连接层。

3.8 其他

A-LRN网络结构使用了LRN层(local response normalization,局部响应归一化),这在AlexNet网络中也使用过。但是作者实验发现使用LRN并没有带来性能的提升,因此在其它组的网络中均没再出现LRN层。

从11层的A到19层的E,网络深度增加对top1和top5的错误率下降很明显。

VGG作者用B网络和一个较浅网络比较,较浅网络用1个5x5卷积核来代替B的2个3x3卷积核,结果显示多个小卷积核比单个大卷积核效果要好。

关于VGG的更多细节和实验对比结果,建议大家直接看原论文!

手撕 CNN 系列:

手撕 CNN 经典网络之 LeNet-5(理论篇)

手撕 CNN 经典网络之 LeNet-5(MNIST 实战篇)

手撕 CNN 经典网络之 LeNet-5(CIFAR10 实战篇)

手撕 CNN 经典网络之 LeNet-5(自定义实战篇)

手撕 CNN 经典网络之 AlexNet(理论篇)

手撕 CNN 经典网络之 AlexNet(PyTorch 实战篇)

如果觉得这篇文章有用的话,麻烦点个在看或转发朋友圈!


推荐阅读

(点击标题可跳转阅读)

干货 | 公众号历史文章精选

我的深度学习入门路线

我的机器学习入门路线图

重磅

AI有道年度技术文章电子版PDF来啦!

扫描下方二维码,添加 AI有道小助手微信,可申请入群,并获得2020完整技术文章合集PDF(一定要备注:入群 + 地点 + 学校/公司。例如:入群+上海+复旦。 

长按扫码,申请入群

(添加人数较多,请耐心等待)

感谢你的分享,点赞,在看三  

以上是关于手撕 CNN 经典网络之 VGGNet(理论篇)的主要内容,如果未能解决你的问题,请参考以下文章

手撕 CNN 经典网络之 VGGNet(PyTorch实战篇)

手撕 CNN 经典网络之 VGGNet(PyTorch实战篇)

手撕 CNN 经典网络之 VGGNet(PyTorch实战篇)

手撕 CNN 经典网络之 AlexNet(理论篇)

手撕 CNN 经典网络之 AlexNet(理论篇)

手撕 CNN 经典网络之 AlexNet(理论篇)