从先进的计算机视觉出现的 Alexnet 开始,人们开始尝试不同的架构。牛津大学工程科学系的 Karen simonyan 和 Andrew Zisserman 在对 ImageNet Challenge 2014 的数据集进行了一些实验后提出了非常深的卷积网络:VERY DEEP CONVOLUTIONAL NETWORKS FOR LARGE-SCALE IMAGE RECOGNITION
引言
VGG16 是一种 CNN(卷积神经网络),被认为是迄今为止最好的计算机视觉模型之一。该模型的创建者评估了网络结构并使用具有非常小 (3 × 3) 卷积滤波器的架构增加了深度,这显示出对现有技术配置的显著改进。他们将深度推到了 16-19 个权重层,使其大约有“1.38 亿”个可训练参数。VGG16 可用于目标检测和分类,能够对 1000 个不同类别的图像进行分类,且易于与迁移学习搭配使用。
VGG-16 的架构
VGG16中的16指的是有16的带权重的层。在 VGG16 中有 13 个卷积层、5 个 Max Pooling 层和 3 个 Dense 层,总计 21 个层,但它只有 16 层有权重,即可学习参数层。
VGG16 将输入图像大小设置为 224、244 和 3 个 RGB 通道
VGG16 最独特的地方在于,他们没有使用大量的超参数,而是专注于具有非常小尺寸(stride 为 1 - 3*3 滤波器)的卷积层,并且始终使用stride 为2 - 2*2 滤波器进行“SAME”填充和最大池化操作。
Conv-1 层有 64 个滤波器,Conv-2 有 128 个滤波器,Conv-3 有 256 个滤波器,Conv 4 和 Conv 5 有 512 个滤波器。
三个全连接 (FC) 层跟在一堆卷积层之后:前两个层各有 4096 个通道;第三个执行 1000 个 ILSVRC 类别分类,因此包含 1000 个通道(每个类一个);最后一层是 softmax 层。
在每一层之后,他们添加了 ReLU 激活函数,该函数“负责”避免梯度消失,因为它不会同时激活所有神经元。
原始研究论文中的表格
随着更多层的添加(添加的层以粗体显示),配置的深度从左 (A) 到右 (E) 增加。卷积层参数表示为“convhreceptive field sizei-hnumber of channelsi”。为简洁起见,未写出 ReLU 激活函数。
参数数量(百万)
下面是我在 FER 2013 数据集上基于 VGG-16 的项目 ——“面部情绪检测”,输入图像的大小为 48*48*1 ,将其分类为 7 类(情绪)。
def FER_vgg16_model(input_shape=(48, 48, 1)):
visible = Input(shape=input_shape, name='input')
num_classes = 7
# 1stblock with 2 conv
conv1_1 = Conv2D(64, kernel_size=3, activation='relu', padding='same', name='conv1_1')(visible)
conv1_1 = BatchNormalization()(conv1_1)
conv1_2 = Conv2D(64, kernel_size=3, activation='relu', padding='same', name='conv1_2')(conv1_1)
conv1_2 = BatchNormalization()(conv1_2)
pool1_1 = MaxPooling2D(pool_size=(2, 2), name='pool1_1')(conv1_2)
drop1_1 = Dropout(0.3, name='drop1_1')(pool1_1)
# the 2-nd block with 2 conv
conv2_1 = Conv2D(128, kernel_size=3, activation='relu', padding='same', name='conv2_1')(drop1_1)
conv2_1 = BatchNormalization()(conv2_1)
conv2_2 = Conv2D(128, kernel_size=3, activation='relu', padding='same', name='conv2_2')(conv2_1)
conv2_2 = BatchNormalization()(conv2_2)
pool2_1 = MaxPooling2D(pool_size=(2, 2), name='pool2_1')(conv2_2)
drop2_1 = Dropout(0.3, name='drop2_1')(pool2_1)
# the 3-rd block with 3 conv
conv3_1 = Conv2D(256, kernel_size=3, activation='relu', padding='same', name='conv3_1')(drop2_1)
conv3_1 = BatchNormalization()(conv3_1)
conv3_2 = Conv2D(256, kernel_size=3, activation='relu', padding='same', name='conv3_2')(conv3_1)
conv3_2 = BatchNormalization()(conv3_2)
conv3_3 = Conv2D(256, kernel_size=3, activation='relu', padding='same', name='conv3_3')(conv3_2)
conv3_3 = BatchNormalization()(conv3_3)
pool3_1 = MaxPooling2D(pool_size=(2, 2), name='pool3_1')(conv3_3)
drop3_1 = Dropout(0.3, name='drop3_1')(pool3_1)
# the 4-rd block with 3 conv
conv4_1 = Conv2D(512, kernel_size=3, activation='relu', padding='same', name='conv4_1')(drop3_1)
conv4_1 = BatchNormalization()(conv4_1)
conv4_2 = Conv2D(512, kernel_size=3, activation='relu', padding='same', name='conv4_2')(conv4_1)
conv4_2 = BatchNormalization()(conv4_2)
conv4_3 = Conv2D(512, kernel_size=3, activation='relu', padding='same', name='conv4_3')(conv4_2)
conv4_3 = BatchNormalization()(conv4_3)
pool4_1 = MaxPooling2D(pool_size=(2, 2), name='pool4_1')(conv4_3)
drop4_1 = Dropout(0.2, name='drop4_1')(pool4_1)
# the 5-rd block with 3 conv
conv5_1 = Conv2D(512, kernel_size=3, activation='relu', padding='same', name='conv5_1')(drop4_1)
conv5_1 = BatchNormalization()(conv5_1)
conv5_2 = Conv2D(512, kernel_size=3, activation='relu', padding='same', name='conv5_2')(conv5_1)
conv5_2 = BatchNormalization()(conv5_2)
conv5_3 = Conv2D(512, kernel_size=3, activation='relu', padding='same', name='conv5_3')(conv5_2)
conv5_3 = BatchNormalization()(conv5_3)
pool5_1 = MaxPooling2D(pool_size=(2, 2), name='pool5_1')(conv5_3)
drop5_1 = Dropout(0.2, name='drop5_1')(pool5_1)
# Flatten and output
flatten = Flatten(name='flatten')(drop5_1)
FC1 = Dense(4096, activation="relu", name='FullyConnected1')(flatten)
drop6_1 = Dropout(0.1, name = 'drop6_1')(FC1)
FC2 = Dense(4096, activation="relu", name='FullyConnected2')(drop6_1)
drop7_1 = Dropout(0.1, name='drop7_1')(FC2)
FC3 = Dense(1000, activation="relu", name='FullyConnected3')(drop7_1)
drop8_1 = Dropout(0.1, name='drop8_1')(FC3)
ouput = Dense(num_classes, activation='softmax', name='output')(drop8_1)
# create model
model = Model(inputs=visible, outputs=ouput)
return model
对于每个卷积层:
Filter = 3*3
Stride = 1
Padding = same
对于每个最大池化层:
Filter = 2*2
Stride= 2
Alexnet 存在的问题
它的层数较少,因此无法提取比较深层的特征。此外,他们在每一层中选择固定滤波器的数目和步幅进行卷积和池化操作。
VGG-16 相对于 Alexnet 的优势
在每个卷积层中,滤波器的 size 为 3*3,stride为 1,使用“same”的方式进行填充,最大池化层的 size 为2*2,stride 为2。
由于 VGG-16 是相对比较深层的神经网络,它将从图像中提取更多特征,而且梯度消失的问题在 ReLU 激活函数的加入后得到了有效的解决。
VGG-16 是一个“系统的”神经网络,它具有相同的步长和滤波器,每个模块独立地进行卷积和池化操作。
vgg-16 和 vgg-19 之间的区别是 vgg-19 多了 3 个卷积层,这使得它的性能比 vgg16 好一些。
· END ·
HAPPY LIFE