上节《ImageNet Classification with Deep Convolutional Neural Networks》第一个典型的CNN是LeNet5网络结构,已经简单的介绍了原理和代码,本节主要介绍《ImageNet Classification with Deep Convolutional Neural Networks》AlexNet网络
1、AlexNet网络详解
该网络的亮点在于:
- 首次利用 GPU 进行网络加速训练。
- 使用了 ReLU 激活函数,而不是传统的 Sigmoid 激活函数以及 Tanh 激活函数。
- 使用了 LRN 局部响应归一化。
- 在全连接层的前两层中使用了 Dropout 随机失活神经元操作,以减少过拟合。
模型的组成:
- 输入层
- 5个卷积层
- 3个全连接层
2、模型详解
以TensorFlow为模板,卷积神经网络常用的填充模式有’VALID’和’SAME’两种,其中’VALID’为不填充模式,即对于原始的尺寸不进行填充,直接进行卷积。所以卷积计算的尺寸公式为
而’SAME’则是一种特殊的填充,保证了卷积后大小为。
(1)第一层Conv1
- 输入图像大小: 224 * 224 * 3(RGB图像),但是会将输入图像预处理为227 * 227 * 3的图像。
- 卷积核(filter)大小:11 * 11
- 卷积核个数:96
- 步长(stride):4
- padding方式:VALID
- 输出featureMap大小:55 * 55 * 96 [(227-11+0)/4+1=55]
(2)第二层Pool1
- 输入图像大小:55 * 55 * 96
- 采样大小:3 * 3
- 步长:2
- padding方式:VALID
- 输出featureMap大小:27 * 27 * 96 [(55-3)/2+1=27]
(3)第三层Conv2
- 输入图像大小: 27 * 27 * 96
- 卷积核(filter)大小:5 * 5
- 卷积核个数:256
- 步长(stride):1
- padding方式:SAME
- 输出featureMap大小:27 * 27 * 256
(4)第四层Pool2
- 输入图像大小:27 * 27 * 256
- 采样大小:3 * 3
- 步长:2
- padding方式:VALID
- 输出featureMap大小:13 * 13 * 256 [(27-3)/2+1=13]
(5)第五层Conv3
- 输入图像大小: 13 * 13 * 256
- 卷积核(filter)大小:3 * 3
- 卷积核个数:384
- 步长(stride):1
- padding方式:SAME
- 输出featureMap大小:13 * 13 * 384
(6)第六层Conv4
- 输入图像大小: 13 * 13 * 384
- 卷积核(filter)大小:3 * 3
- 卷积核个数:384
- 步长(stride):1
- padding方式:SAME
- 输出featureMap大小:13 * 13 * 384
(7)第七层Conv5
- 输入图像大小: 13 * 13 * 384
- 卷积核(filter)大小:3 * 3
- 卷积核个数:256
- 步长(stride):1
- padding方式:SAME
- 输出featureMap大小:13 * 13 * 256
(8)第八层Pool3
- 输入图像大小:13 * 13 * 256
- 采样大小:3 * 3
- 步长:2
- padding方式:VALID
- 输出featureMap大小:6 * 6 * 256 [(13-3)/2+1=6]
(9)三个全连接层,第一个:这里使用4096个神经元,对256个大小为6X6特征图,进行一个全连接,也就是将6X6大小的特征图,进行卷积变为一个特征点,然后对于4096个神经元中的一个点,是由256个特征图中某些个特征图卷积之后得到的特征点乘以相应的权重之后,再加上一个偏置得到,之后再进行一个dropout操作,也就是随机从4096个节点中丢掉一些节点信息(清0操作),然后就得到新的4096个神经元。第二个:同上,第三个:采用的是1000个神经元,然后对FC7中4096个神经元进行全连接,然后通过sofmax,得到1000个类别的概率值,也就是预测值。
3、代码实现
from keras.models import Sequential
from keras.layers import Dense, Flatten, Dropout
from keras.layers.convolutional import Conv2D, MaxPooling2D
import numpy as np
seed = 7
np.random.seed(seed)
# 创建模型序列
model = Sequential()
# 第一层卷积网络,使用96个卷积核,大小为11x11步长为4, 要求输入的图片为227x227, 3个通道,不填充,激活函数使用relu
model.add(Conv2D(96, (11, 11), strides=(4, 4), input_shape=(227, 227, 3), padding='valid', activation='relu',
kernel_initializer='uniform'))
# 池化层
model.add(MaxPooling2D(pool_size=(3, 3), strides=(2, 2)))
# 第二层卷积
model.add(Conv2D(256, (5, 5), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform'))
# 池化层
model.add(MaxPooling2D(pool_size=(3, 3), strides=(2, 2)))
# 第三层卷积
model.add(Conv2D(384, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform'))
# 第四层卷积
model.add(Conv2D(384, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform'))
# 第五层卷积
model.add(Conv2D(256, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform'))
model.add(MaxPooling2D(pool_size=(3, 3), strides=(2, 2)))
model.add(Flatten())
model.add(Dense(4096, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(4096, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(1000, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='sgd', metrics=['accuracy'])
model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) (None, 55, 55, 96) 34944
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 27, 27, 96) 0
_________________________________________________________________
conv2d_1 (Conv2D) (None, 27, 27, 256) 614656
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 13, 13, 256) 0
_________________________________________________________________
conv2d_2 (Conv2D) (None, 13, 13, 384) 885120
_________________________________________________________________
conv2d_3 (Conv2D) (None, 13, 13, 384) 1327488
_________________________________________________________________
conv2d_4 (Conv2D) (None, 13, 13, 256) 884992
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 6, 6, 256) 0
_________________________________________________________________
flatten (Flatten) (None, 9216) 0
_________________________________________________________________
dense (Dense) (None, 4096) 37752832
_________________________________________________________________
dropout (Dropout) (None, 4096) 0
_________________________________________________________________
dense_1 (Dense) (None, 4096) 16781312
_________________________________________________________________
dropout_1 (Dropout) (None, 4096) 0
_________________________________________________________________
dense_2 (Dense) (None, 1000) 4097000
=================================================================
Total params: 62,378,344
Trainable params: 62,378,344
Non-trainable params: 0
_________________________________________________________________
4、VGG16详解
1、VGG全称是Visual Geometry Group,因为是由Oxford的Visual Geometry Group提出的。AlexNet问世之后,很多学者通过改进AlexNet的网络结构来提高自己的准确率,主要有两个方向:小卷积核和多尺度。而VGG的作者们则选择了另外一个方向,即加深网络深度。
5、VGG亮点
1、小卷积核组:作者通过堆叠多个3*3的卷积核(少数使用1*1)来替代大的卷积核,以减少所需参数;
卷积与网络深度息息相关,虽然AlexNet使用了11x11和5x5的大卷积,但大多数还是3x3卷积,对于stride=4的11x11的大卷积核,理由在于一开始原图的尺寸很大因而冗余,最为原始的纹理细节的特征变化可以用大卷积核尽早捕捉到,后面更深的层数害怕会丢失掉较大局部范围内的特征相关性,后面转而使用更多3x3的小卷积核和一个5x5卷积去捕捉细节变化。而VGGNet则全部使用3x3卷积。因为卷积不仅涉及到计算量,还影响到感受野。前者关系到是否方便部署到移动端、是否能满足实时处理、是否易于训练等,后者关系到参数更新、特征图的大小、特征是否提取的足够多、模型的复杂度和参数量等。
2、小池化核:相比较于AlexNet使用的3*3的卷积核,VGG全部为2*2的卷积核;
2012年的AlexNet的pooling的kernel size全是奇数,所有池化采用kernel size=3x3,stride=2的max-pooling,而VGG使用的max-pooling的kernel size=2x2,stride=2。pooling kernel size从奇数变为偶数。小kernel带来的是更细节的信息捕获。池化做的事情是根据对应的max或者average方式进行特征筛选,max-pooling更容易捕捉图像上的变化,梯度的变化,带来更大的局部信息差异性,更好地描述边缘、纹理等构成语义的细节信息。
3、网络更深特征图更宽:卷积核专注于扩大通道数,池化专注于缩小高和宽,使得模型更深更宽的同时,计算量的增加不断放缓;
4、特征图:
参考: