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

2022-04-14 08:07:22 浏览数 (1)

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 实战篇)

0 人点赞