转自文章:手撕 CNN 经典网络之 VGGNet(理论篇) (qq.com)
2014年,牛津大学计算机视觉组(Visual Geometry Group)和Google DeepMind公司一起研发了新的卷积神经网络,并命名为VGGNet。VGGNet是比AlexNet更深的深度卷积神经网络,该模型获得了2014年ILSVRC竞赛的第二名。
1.网络结构
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,表示使用3×3的卷积核,通道数为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层卷积层由2个conv3-64(64个3*3卷积核)组成。
该层的处理流程是:卷积–>ReLU–> 卷积–>ReLU–>池化。
卷积: 输入是224x224x3,使用64个3×3的卷积核进行卷积,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个3×3的卷积核进行卷积,padding=1,stride=1,根据公式:
(input_size + 2 * padding – kernel_size) / stride + 1=(224+2*1-3)/1+1=224
得到输出是224x224x64。
ReLU: 将卷积层输出的FeatureMap输入到ReLU函数中,为特征图添加非线性关系。
池化: 使用2×2,stride=2的池化单元进行最大池化操作(max pooling)。根据公式:
(224+2*0-2)/2+1=112
每组得到的输出为112x112x64。
1.3.第二层卷积层
第2层卷积层由2个conv3-128组成。
该层的处理流程是:卷积–>ReLU–> 卷积–>ReLU–>池化。
卷积: 输入是112x112x64,使用128个3×3的卷积核进行卷积,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函数中。
池化: 使用2×2,stride=2的池化单元进行最大池化操作(max pooling)。根据公式:
(112+2*0-2)/2+1=56
每组得到的输出为56x56x128。
1.4 第3层卷积层
第3层卷积层由3个conv3-256组成。
该层的处理流程是:卷积–>ReLU–> 卷积–>ReLU–>池化。
卷积: 输入是56x56x128,使用256个3×3的卷积核进行卷积,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函数中。
池化: 使用2×2,stride=2的池化单元进行最大池化操作(max pooling)。根据公式:
(56+2*0-2)/2+1=28
每组得到的输出为28x28x256。
1.5 第4层卷积层
第4层卷积层由3个conv3-512组成。
该层的处理流程是:卷积–>ReLU–> 卷积–>ReLU–>池化。
卷积: 输入是28x28x256,使用512个3×3的卷积核进行卷积,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函数中。
池化: 使用2×2,stride=2的池化单元进行最大池化操作(max pooling)。根据公式:
(28+2*0-2)/2+1=14
每组得到的输出为14x14x512。
1.6 第5层卷积层
第5层卷积层由3个conv3-512组成。
该层的处理流程是:卷积–>ReLU–> 卷积–>ReLU–>池化。
卷积: 输入是14x14x512,使用512个3×3的卷积核进行卷积,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函数中。
池化: 使用2×2,stride=2的池化单元进行最大池化操作(max pooling)。根据公式:
(14+2*0-2)/2+1=7
每组得到的输出为7x7x512。
1.7 第1层全连接层
第1层全连接层FC4096由4096个神经元组成。
该层的处理流程是:FC–>ReLU–>Dropout。
FC:输入是7x7x512的FeatureMap,展开为77512的一维向量,即77512=25088个神经元,输出为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个7×7的卷积核进行卷积,由于卷积核尺寸与输入的尺寸完全相同,即卷积核中的每个系数只与输入尺寸的一个像素值相乘一一对应,根据公式:
(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与类别的数量相同,空间分辨率2×2依赖于输入图像尺寸。然后将得分图进行空间平均化(求和池化),得到的还是1x1x1000。最后对1000个通道的得分进行比较,取较大值作为预测类别。
这样做的好处就是大大减少特征位置对分类带来的影响。
举个简单的例子:
从上图我们可以看出,猫在原图片中不同的位置,如果使用全连接层很容易使得剪裁之后的图片丢失关键目标。然而使用全卷积层,对原图片直接进行卷积,最终得分图经过求和池化后得到的得分都是1,即不管猫在图片的什么位置,都能判定这张图片中有猫,保证分类正确。保留原图,使用全卷积层,相当于猫在哪我不管,我只要猫,于是我让模型去把这个猫找到,实际就是把feature map整合成一个值,这个值大,就有猫,这个值小,那就可能没猫!和这个猫在图片哪里关系不大了,鲁棒性大大增强。
3. VGG网络特点
3.1 结构简洁
虽然VGG层数较多,总的网络深度从11层到19层,但是它的整体结构还是相对简单。概括来说,VGG由5层卷积层(每个卷积层的子层数量不同)、3层全连接层、softmax输出层构成,层与层之间使用maxpooling(最大化池)分开,所有隐层的激活单元都采用ReLU函数。
3.2 小卷积核
小卷积核是VGG的一个重要特点,VGG没有采用AlexNet中比较大的卷积核尺寸(如7×7),而是通过降低卷积核的大小(3×3),增加卷积子层数来达到同样的性能(VGG:从1到4卷积子层,AlexNet:1子层)。
VGG使用多个较小卷积核(3×3)的卷积层代替一个卷积核较大的卷积层,VGG作者认为两个3×3的卷积堆叠获得的感受野大小,相当一个5×5的卷积;而3个3×3卷积的堆叠获取到的感受野相当于一个7×7的卷积。示意图如下所示:
使用3×3小卷积核的好处有两个方面:
一是大幅度减少模型参数数量。例如使用2个3×3的卷积核代替1个5×5的卷积核,通道数为C,1个5×5的卷积核参数量为55C,2个3×3的卷积核参数量为233*C,参数两减小了28%。另外,小卷积核选取小的 stride可以防止较大的stride导致细节信息的丢失。
二是多层卷积层(每个卷积层后都有非线性激活函数),增加非线性,提升模型性能。
此外,我们注意到在VGG网络结构D中,还使用了1×1卷积核,1×1卷积核可以在不改变感受野的情况下,增加模型的非线性(后面的非线性激活函数)。同时,还可以用它来整合各通道的信息,并输出指定通道数。通道数减小即降维,通道数增加即升维。
3.3 小池化核
相比AlexNet的3×3的池化核,VGG全部采用2×2的池化核。
3.4 通道数更多,特征度更宽
每个通道代表着一个FeatureMap,更多的通道数表示更丰富的图像特征。VGG网络第一层的通道数为64,后面每层都进行了翻倍,最多到512个通道,通道数的增加,使得更多的信息可以被提取出来。
3.5 层数更深
使用连续的3×3小卷积核代替大的卷积核,网络的深度更深,并且对边缘进行填充,卷积的过程并不会减小图像尺寸。仅使用小的2×2池化单元,减小图像的尺寸。
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个5×5卷积核来代替B的2个3×3卷积核,结果显示多个小卷积核比单个大卷积核效果要好。