第三种方法叫做 Finetune和第二种方法 bottleneck方法有点像。
第二种方法的特点就是固化卷积层和池化层的参数,然后把图片放到卷积层和池化层去运算出它的结果,然后再把这个结果作为我们自己搭建的全连接层输入,训练我们自己的全连接层,最后得到这个分类的结果。
Finetune的特点它也是使用VGG16在imagenet上训练出来的权值 ,但是在训练的过程中它也会改变卷积层和池化层,它不会像bottleneck一样固化前面的卷积层和池化层,它是整个网络,卷积层,池化层,全连接层都会做一个微调,我们可以把这个学习率设置的小一点,做一个微调,然后慢慢的去改变整个网络的参数,然后使得它可以得到一个更加好的效果。
但是这个全连接层还是需要你自己训练得到的全连接层和vgg16的卷积层和池化层进行组合,再进行的一个微调,所以呢?还是先要使用bottleneck方法得到一个全连接层,再和vgg16的卷积层和池化层进行一个组合,最后进行整体的微调。
案例代码
代码运行平台为jupyter-notebook,文章中的代码块,也是按照jupyter-notebook中的划分顺序进行书写的,运行文章代码,直接分单元粘入到jupyter-notebook即可。
1.导入第三方库
from keras.applications.vgg16 import VGG16
from keras.preprocessing import image
from keras.applications.vgg16 import preprocess_input
import numpy as np
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Dropout, Flatten, Dense
from tensorflow.keras.optimizers import SGD
import os
2.载入模型并且进行组合
(1)载入vgg16模型(卷积池化层)
# 载入预训练的VGG16模型,不包括全连接层 这里需要设置一个input_shape(输入的形状)
vgg16_model = VGG16(weights='imagenet', include_top=False, input_shape=(150,150,3))
(2)载入自己训练的全连接层
# 这个全连接层和[bottleneck方法](https://blog.csdn.net/booze_/article/details/125702404?spm=1001.2014.3001.5502)
# 中的全连接层是一样的
# 搭建全连接层
top_model = Sequential()
top_model.add(Flatten(input_shape=vgg16_model.output_shape[1:]))
top_model.add(Dense(256, activation='relu'))
top_model.add(Dropout(0.5))
top_model.add(Dense(2, activation='softmax'))
# 载入训练过的权值
# 训练出来的权值
top_model.load_weights('bottleneck_fc_model.h5')
'bottleneck_fc_model.h5'
这个权值来源于bottleneck方法
(3)对网络模型的组合
model = Sequential()
# 先加入vgg16
model.add(vgg16_model)
# 在加入我们自己训练的全连接层
model.add(top_model)
3.数据集处理
# 训练集数据生成
train_datagen = ImageDataGenerator(
rescale=1./255,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True)
# 测试集数据处理
test_datagen = ImageDataGenerator(rescale=1./255)
batch_size = 32
# 生成训练数据
train_generator = train_datagen.flow_from_directory(
'../input/cat-and-dog-classify2/image/train', # 训练数据路径
target_size=(150, 150), # 设置图片大小
batch_size=batch_size # 批次大小
)
# 测试数据
test_generator = test_datagen.flow_from_directory(
'../input/cat-and-dog-classify2/image/test', # 训练数据路径
target_size=(150, 150), # 设置图片大小
batch_size=batch_size # 批次大小
)
4.模型训练
model.compile(loss='categorical_crossentropy',
optimizer=SGD(lr=1e-4, momentum=0.9),
metrics=['accuracy'])
# 统计文件个数
totalFileCount = sum([len(files) for root, dirs, files in os.walk('../input/cat-and-dog-classify2/image/train')])
model.fit_generator(
train_generator,
steps_per_epoch=totalFileCount/batch_size,
epochs=10,
validation_data=test_generator,
validation_steps=1000/batch_size,
)
运行结果:
对比bottleneck方法的运行结果,训练的网络比较复杂,更改的权值比较多,所以所耗的时间就比较长,但是可以看到它这一开始的训练出来的模型准确率就比较高,高达90%多。
总结
分类问题套路:
使用训练好的权值,然后在它权值的基础上,你把它的全连接层给去掉,加上自己的全连接层,然后你重新训练你这个分类任务。
就是当你遇到了一个图像分类问题,首先你可以使用bottleneck方法对吧,使用现有的具有较好效果模型的卷积层和池化层用来提取图像特征,然后只训练全连接层即可,再之后使用Finetune方法组合你的全连接层和现有模型的卷积层和池化层进行整体参数的微调,以达到更好的效果。