特征微调有助于提高深度学习的精度,而将卷积基(就是预先训练好的卷积模型)的前面大部分层冻结,只微调(此时的学习率也应该相应的调低)顶部更抽象的层---可以理解为更细节的特征
这样可以在一定程度上提高模型的识别精度,我的实验结果比原有的精度提高了4个点左右,从90%提高到94%
下面是全部的代码,很简单.
不过有个疑问:训练出来的验证精度达不到书上说的97%,有解决的同学请留言告知一下,不慎感激!!!
#即可单独安装keras,也可以用tensorflow自带的keras
try:
from keras.applications import VGG16
from keras.preprocessing.image import ImageDataGenerator
from keras import models
from keras import layers
from keras import optimizers
except ModuleNotFoundError:
import tensorflow as tf
VGG16 = tf.keras.applications.VGG16
ImageDataGenerator = tf.keras.preprocessing.image.ImageDataGenerator
models = tf.keras.models
layers = tf.keras.layers
optimizers = tf.keras.optimizers
import os,sys
sys.path.append( os.pardir ) #为了找到上级目录common,import里面的工具
from common.file_arrange import get_dirs #自定义的小工具
import numpy as np
import matplotlib.pyplot as plt
def get_convBase( input_shape=None ):
'''
input_shape: tuple ,example:( 150,150,3 )
从网络上下载已训练的模型
'''
return VGG16(
weights='imagenet',
include_top=False,
input_shape=input_shape
)
def get_generators( directorys,target_size,batch_size ):
'''
directory: tuple ("train_path","validation_path") 分别是两个目录,一个训练样本目录,一个测试样本目录
target_size: "tuple" 缩放大小 example:( 150,150 ) 所有图像缩放成150*150像素
batch_size: "int" 每次在样本中抽取的批次大小
'''
#初始化一个训练generator对象(工厂) 使用数据增强
train_datagen = ImageDataGenerator(
rescale=1./255,
zoom_range=0.2,
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
horizontal_flip=True,
fill_mode='nearest'
)
#初始化一个测试generator实例,因为是验证推理的成功率,所以不使用数据增强
val_datagen = ImageDataGenerator( rescale=1./255 )
#得到一个用于训练的ImageDataGenerator实例
train_generator = train_datagen.flow_from_directory(
directorys[0],
target_size=target_size,
batch_size=batch_size,
interpolation='nearest',
class_mode='binary'
)
#得到一个用于验证的ImageDataGenerator实例
val_generator = val_datagen.flow_from_directory(
directorys[1],
target_size=target_size,
batch_size=batch_size,
interpolation='nearest',
class_mode='binary'
)
return train_generator,val_generator
def run_network():
train_gener, test_gener = get_generators( ( get_dirs()['train'], get_dirs()['test'] ), (150,150), 20 )
#生成一个欲训练模型
conv_base = get_convBase( ( 150,150,3 ) )
#冻结卷积层的可训练 权重
conv_base.trainable =False
model = models.Sequential()
#将预训练的模型添加到新建模型里
model.add( conv_base )
model.add( layers.Flatten() )
model.add( layers.Dense( 256,activation='relu' ) )#注意,这里不是第一层网络,所以不需要input_shape参数
#model.add( layers.Dropout(0.5) )
model.add( layers.Dense( 1,activation='sigmoid' ) )
#配置训练模型
model.compile(
optimizer=optimizers.RMSprop(lr = 2e-5),
metrics=['acc'],
loss='binary_crossentropy',
)
#将训练图片生成器.测试图片生成器送入fit_generator,并以设定的次数训练模型
history=model.fit_generator(
train_gener,
steps_per_epoch=100,
epochs=30,
validation_data=test_gener,
validation_steps=50
)
#微调模型
conv_base.trainable=True
set_trainable = False
for layer in conv_base.layers:
if layer.name == 'block5_conv1': #block5_conv1后面的层都设为可训练
set_trainable = True
if set_trainable:
layer.trainable = True
else:
layer.trainable = False
model.compile(
optimizer=optimizers.RMSprop(lr=1e-5), #以一个较小的学习率微调
loss='binary_crossentropy',
metrics=['acc']
)
history = model.fit_generator(
train_gener,
steps_per_epoch=100,
epochs=77,
validation_data=test_gener,
validation_steps=50
)
epochs = range( 1, len( history.history['acc'] ) + 1 )
plt.plot(epochs, history.history['acc'],'bo',label = 'train_acc' )
plt.plot( epochs,history.history['val_acc'], 'b',label = 'validation_Acc' )
plt.title( 'Training and validation Accuracy' )
plt.legend()
plt.figure()
plt.plot( epochs,history.history['loss'],'bo',label='Train_loss' )
plt.plot( epochs,history.history['val_loss'],'b',label='Validation_loss' )
plt.legend()
plt.show()
if __name__ == '__main__':
run_network()
#model = get_convBase( (150,150,3) )
#model.summary()