如果数据集太小的话不管怎么去加工处理,总会出现过拟合问题,使得精度不会那么的高,所以就要引入预训练过的模型了,预训练的模型通常是大数量的数据训练过的,而且特点就在于挑选的预训练模型是和现有问题有着相似性的。
这里使用的是一个简单且老的模型vgg16,这个模型和我们之前使用的架构很相似。使用预训练的网络有两种方法,即特征提取和微调模型。
首先,在之前的学习中,卷积神经网络包括两个部分,第一部分由卷积层和池化层组成,第二部分是一个展开的分类器,第一部分简单把他叫做卷积基。后面的分类器是为了给训练好的模型分类使用,它本身的泛用性不是那么的强,这个简单思考就会明白,所以通常使用卷积基来做重复使用。
还有就是问题的相似度。从逻辑上来看,层数越少,训练的特征就越简单。所以相似性越高,已有模型可用的层就越多,如果新问题和已有模型的相似度不高,可以考虑少用几层已有模型的结构。
现在可以看具体的实现过程了。
from keras.applications import VGG16 conv_base = VGG16(weights='imagenet',
include_top=False, input_shape=(150, 150, 3))
导入vgg16,设置卷积基相关参数,其中weights:None代表随机初始化,即不加载预训练权重。'imagenet’代表加载预训练权重
;include_top代表是否使用第二部分分类器,这里不使用。因为是猫狗问题,自己加就行;最后就是输入尺寸了。
用summary方法看一下网络的架构,发现很眼熟:
<>Layer (type) Output Shape Param #
input_1 (InputLayer) (None, 150, 150, 3) 0
block1_conv1 (Conv2D) (None, 150, 150, 64) 1792
block1_conv2 (Conv2D) (None, 150, 150, 64) 36928
block1_pool (MaxPooling2D) (None, 75, 75, 64) 0
block2_conv1 (Conv2D) (None, 75, 75, 128) 73856
block2_conv2 (Conv2D) (None, 75, 75, 128) 147584
block2_pool (MaxPooling2D) (None, 37, 37, 128) 0
block3_conv1 (Conv2D) (None, 37, 37, 256) 295168
block3_conv2 (Conv2D) (None, 37, 37, 256) 590080
block3_conv3 (Conv2D) (None, 37, 37, 256) 590080
block3_pool (MaxPooling2D) (None, 18, 18, 256) 0
block4_conv1 (Conv2D) (None, 18, 18, 512) 1180160
block4_conv2 (Conv2D) (None, 18, 18, 512) 2359808
block4_conv3 (Conv2D) (None, 18, 18, 512) 2359808
block4_pool (MaxPooling2D) (None, 9, 9, 512) 0
block5_conv1 (Conv2D) (None, 9, 9, 512) 2359808
block5_conv2 (Conv2D) (None, 9, 9, 512) 2359808
block5_conv3 (Conv2D) (None, 9, 9, 512) 2359808
<>block5_pool (MaxPooling2D) (None, 4, 4, 512) 0
Total params: 14,714,688
Trainable params: 14,714,688
Non-trainable params: 0
最后的输出为4,4,512,所以在这个基础上加一个密集链接分类器,就可以实现二分类的问题解决,但现在面临的问题就是优化模型的问题。
这个模型无法使用数据增强,要使用的话必须在这个模型顶部加一个dense层,这就会导致模型训练的计算消耗大大增加了。后面会分别分析不使用和使用数据增强的两种方法。