CNN经典模型——VGGNet
VGGNet结构
VGGNet 是牛津大学视觉几何组(Visual Geometry Group)和 GoogleDeepMind 公司的研究员一起研发的的深度卷积神经网络。在ImageNet大型视觉识别挑战 ILSVRC 2014 中获得物体检测任务第一名和图像分类任务第二名(图像分类第一名是 GoogLeNet)。它最主要的贡献就是展示了卷积神经网络的深度与其性能之间的关系,实验结果证实了增加网络的深度可以一定程度上影响网络最终的性能。直到现在,VGG仍然被广泛用于提取图像特征。
VGGNet的整体结构:
相比于AlexNet,VGGNet的层次更加深了。以VGG-16为例,VGG-16 网络没有那么多超参数,这是一种只需要专注于构建卷积层的简单网络,说它简单是因为它的结构足够清晰,VGG16由5块卷积层(共13个卷积操作)、3层全连接层、softmax输出层构成,层与层之间使用Maxpooling,所有隐层的激活函数都采用ReLU函数。
(注:这里所说的“5块卷积层”是按隔开的卷积层算的,实际VGG16共13个卷积层。)
该网络的具体结构如下:
- 1、第一个卷积块,进行两次卷积,Kernel=(3,3,64),Padding=1,Stride=1,输入224x224x3的图像,每次卷积后都经过一个ReLu,之后图像尺寸变为224x224x64。然后作Maxpooling,池化单元尺寸为2x2,Padding=0,Stride=2,池化后的图像尺寸减半为112x112x64。
- 2、第二个卷积块,进行两次卷积,Kernel=(3,3,128),Padding=1,Stride=1,输入为上一层输出112x112x64,每次卷积后都经过一个ReLu,之后图像尺寸变为112x112x128。然后作Maxpooling,池化单元尺寸为2x2,Padding=0,Stride=2,池化后的图像尺寸减半为56x56x128。
- 3、第三个卷积块,进行三次卷积,Kernel=(3,3,256),Padding=1,Stride=1,输入为上一层输出56x56x128,每次卷积后都经过一个ReLu,之后图像尺寸变为56x56x256。然后作Maxpooling,池化单元尺寸为2x2,Padding=0,Stride=2,池化后的图像尺寸减半为28x28x256。
- 4、第四个卷积块,进行三次卷积,Kernel=(3,3,512),Padding=1,Stride=1,输入为上一层输出28x28x256,每次卷积后都经过一个ReLu,之后图像尺寸变为28x28x512。然后作Maxpooling,池化单元尺寸为2x2,Padding=0,Stride=2,池化后的图像尺寸减半为14x14x512。
- 5、第五个卷积块,进行三次卷积,Kernel=(3,3,512),Padding=1,Stride=1,输入为上一层输出14x14x512,每次卷积后都经过一个ReLu,之后图像尺寸仍为14x14x512。然后作Maxpooling,池化单元尺寸为2x2,Padding=0,Stride=2,池化后的图像尺寸减半为7x7x512。
- 6、全连接部分:上一层输出首先经过一个4096个Kernel=(7,7,512)的卷积(非线性变换),经过Relu后得到1x1x4096,再与一层1x1x4096进行全连接,输出经过ReLu,再与1x1x1000进行全连接通过softmax输出1000个预测结果。
注:卷积层和全连接层的唯一区别就是卷积层的神经元和输入是局部联系的,并且同一个通道内的不同神经元共享权值。这里卷积层和第一个全连接层的计算实际上相同,因此可以将其等效为卷积层,只要将卷积核大小设置为输入空间大小即可:例如这里输入为7x7x512,第一层全连接层输出4096,我们可以将其看作卷积核大小为7x7,步长为1,没有填充,输出为1x1x4096的卷积层。而且全连接层也可以看做1x1卷积核卷积的结果。这样的好处在于输入图像的大小不再受限制,不管前面处理如何最终都处理为4096个参数的全连接层,因此可以高效地对图像作滑动窗式预测;而且相比于全连接层的计算量比较大,等效卷积层的计算量减小了,这样既达到了目的又十分高效。
顺便说一下,VGG-16 的这个数字 16,就是指在这个网络中卷积层和全连接层共16层。这确实是个很大的网络,总共包含约 1.38 亿个参数,即便以现在的标准来看都算是非常大的网络。但 VGG-16 的结构并不复杂,这点非常吸引人,而且这种网络结构很规整,都是几个卷积层后面跟着可以压缩图像大小的池化层,池化层缩小图像的高度和宽度。同时,卷积层的过滤器数量变化存在一定的规律,由 64 翻倍变成 128,再到 256 和 512。无论如何,每一步都进行翻倍,或者说在每一组卷积层进行过滤器翻倍操作,正是设计此种网络结构的另一个简单原则。这种相对简单一致的网络结构对研究者很有吸引力。
VGG原文献下载:VGGNet原英文文献下载
VGGNet的Trick
- 1、多使用3x3的Kernel
2次3x3的卷积相当于一个5x5Kernel的卷积,而且相当于多做了一次非线性变换,并且参数数目减少28%。这是为什么呢?以下图为例:
在无Padding,Stride=1的情况下,一个5x5的原图像经过一个5x5的卷积核后变为1x1,同样经过两个3x3的卷积核也可以变成1x1,这说明2个3x3和一个5x5有相同的视野域,而且用两次3x3卷积还能多一次非线性变换,这一定程度上会增强模型的泛化能力。且两个3x3卷积核的参数相对数为:,而一个5x5卷积核参数相对数为:,所以一般常用3x3的卷积核(小的卷积核代替大的卷积核);
- 2、使用2x2池化核
这是出于简单和一致性的考虑,相比AlexNet的3x3的池化核,VGG全部采用2x2的池化核,而且性能也不错; - 3、通道数多、层数更深、特征图更宽
VGG网络第一层的通道数为64,后面每层都进行了翻倍,最多到512个通道,通道数的增加,使得更多的信息可以被提取出来。由于卷积核专注于扩大通道数、池化专注于缩小宽和高,使得模型架构上更深更宽的同时,控制了计算量的增加规模; - 4、全连接层可以等效为1x1的卷积核进行卷积。
VGG-16的Keras实现
下面在Keras框架下搭建VGG-16网络:
def VGG_16(weights_path=None):
model = Sequential()
model.add(ZeroPadding2D((1,1),input_shape=(3,224,224)))#卷积输入层,指定了输入图像的大小
model.add(Convolution2D(64, 3, 3, activation='relu'))#64个3x3的卷积核,生成64*224*224的图像,激活函数为relu
model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(64, 3, 3, activation='relu'))#再来一次卷积 生成64*224*224
model.add(MaxPooling2D((2,2), strides=(2,2)))#pooling操作,相当于变成64*112*112
model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(128, 3, 3, activation='relu'))
model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(128, 3, 3, activation='relu'))
model.add(MaxPooling2D((2,2), strides=(2,2)))#128*56*56
model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(256, 3, 3, activation='relu'))
model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(256, 3, 3, activation='relu'))
model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(256, 3, 3, activation='relu'))
model.add(MaxPooling2D((2,2), strides=(2,2)))#256*28*28
model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(512, 3, 3, activation='relu'))
model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(512, 3, 3, activation='relu'))
model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(512, 3, 3, activation='relu'))
model.add(MaxPooling2D((2,2), strides=(2,2)))#512*14*14
model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(512, 3, 3, activation='relu'))
model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(512, 3, 3, activation='relu'))
model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(512, 3, 3, activation='relu'))
model.add(MaxPooling2D((2,2), strides=(2,2))) #到这里已经变成了512*7*7
model.add(Flatten())#这里有点问题
model.add(Dense(4096, activation='relu'))#全连接层有4096个神经核,参数个数就是4096*25088
model.add(Dropout(0.5))#0.5的概率抛弃一些连接
model.add(Dense(4096, activation='relu'))#再来一个全连接
model.add(Dropout(0.5))
model.add(Dense(1000, activation='softmax'))
if weights_path:
model.load_weights(weights_path)
return model
小结:
1、通过增加深度能一定程度上有效地提升性能;
2、VGG16,从头到尾只有3x3卷积与2x2池化,简单一致;
3、卷积可代替全连接,以适应各种尺寸的图片