用Keras进行猫狗识别(四)

使用数据增强+特征提取+微调模型来训练模型

背景

  在上一篇文章我们引用了VGG16模型,通过删除其全连接层,再加上自己的全连接层进行训练,达到了90%的正确率。但是还有一种方法,就是微调模型,这个方法配合特征提取可以达到一个更好的高度。

  什么是微调模型呢?就是通过解冻VGG16最后的几层,通过与训练好的全连接层联合训练的方式,来达到我们的目的,也就是对已经训练好的网络进行微调。
  为什么只解冻后边几层呢?如果了解过卷积神经网络的话,我们可以知道,网络越是靠后,它提取出来的特征越是笼统,越是靠前,它提取的特征越散,总结来说修改哪里其实都是能提高正确率的,但是,修改前边的网络性价比很低,相比于修改后边的网络,效果不是那么显著,而且我觉得牵一发而动全身,前边的网络都改了后边的怎么能不改呢。

数据准备

猫狗识别的数据,kaggle比赛
训练集2000张
验证集1000张

步骤

  1. 在已经训练好的网络上添加自定义网络。(特征提取)
  2. 冻结基网络
  3. 训练所添加的部分
  4. 解冻基网络的一些层
  5. 联合训练解冻的这些层和添加的部分

在猫狗识别(三)中,我们实现了前三个步骤,使用VGG16网络+自己写一个全连接层,冻结VGG16网络后进行训练,训练好后将VGG16的卷积块5解冻,调小学习率,再进行训练。

代码

代码的改动不多,主要分为下边几个部分:

卷积块5的解冻:

conv_base.trainable = True

set_trainable = False
for layer in conv_base.layers:
    if layer.name == 'block5_conv1':
        set_trainable = True
    if set_trainable == True:
        layer.trainable = True
    else :
        layer.trainable = False

添加层:

model = models.Sequential()
model.add(conv_base)
model.add(layers.Flatten())
model.add(connection_layer)

中间加了一个扁平层,是因为卷积基输出的是一个多维数组,而我们训练全连接层的时候,设置的输入为44512的一维数组。所以转化一下就好了。

调小学习率

平滑图表
因为最终的输出曲线幅度过大,所以为了方便读取,所以通过一个函数使其平滑。
函数如下:

def smooth_curve(points, factor=0.6):
    smooth_points = []
    for point in points:
        if smooth_points:
            previous = smooth_points[-1]
            smooth_points.append(previous * factor + point * (1 - factor))
        else:
            smooth_points.append(point)
    return smooth_points

其中factor表示平滑度,越高越平滑,取值为[0,1]

整体代码如下

from keras.applications import VGG16

conv_base = VGG16(
    weights='imagenet',#指定模型初始化检查点
    include_top=False,#指定模型最后是否包含密集连接器
    input_shape=(150,150,3)#指定输入到网络中图像的形状
    )

#设置VGG16第五卷积块解冻,使其可训练
conv_base.trainable = True

set_trainable = False
for layer in conv_base.layers:
    if layer.name == 'block5_conv1':
        set_trainable = True
    if set_trainable == True:
        layer.trainable = True
    else :
        layer.trainable = False

#导入之前训练好的全连接层
from keras.models import  load_model

connection_layer = load_model('./cats_and_dogs.h5')
connection_layer.trainable = True

import os
#指定地址
base_dir = 'F:\DeepLearn\cat_and_dog'
train_dir = os.path.join(base_dir,'train')
test_dir = os.path.join(base_dir,'test')
validation_dir = os.path.join(base_dir,'check')

#配置模型并训练,将之前特征提取训练好的模型和VGG16联合训练
from keras import layers
from keras import models

model = models.Sequential()
model.add(conv_base)
model.add(layers.Flatten())
model.add(connection_layer)


from keras.preprocessing.image import ImageDataGenerator
from keras import optimizers
train_datagen = ImageDataGenerator(
    rescale=1./255,
    rotation_range=40,
    width_shift_range=0.2,
    height_shift_range=0.2,
    shear_range=0.2,
    zoom_range=0.2,
    horizontal_flip=True,
    fill_mode='nearest')

test_datagen = ImageDataGenerator(rescale=1./255)

train_generator = train_datagen.flow_from_directory(
    train_dir,
    target_size=(150, 150),
    batch_size=20,
    class_mode='binary')

validation_generator = test_datagen.flow_from_directory(
    validation_dir,
    target_size=(150, 150),
    batch_size=20,
    class_mode='binary')

model.compile(loss='binary_crossentropy',
    optimizer=optimizers.RMSprop(lr=1e-5),#因为只是微调模型,所以调小学习率
    metrics=['acc'])

history = model.fit_generator(
    train_generator,
    steps_per_epoch=100,
    epochs=40,
    validation_data=validation_generator,
    validation_steps=50)

#保存模型
model.save('cats_and_dogs_small.h5')


#画出结果
import matplotlib.pyplot as plt

#查看变量,发现history.history中就只有这四个值,分别是准确度,验证集准确度,损失,验证集损失
acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']
epochs = range(1, len(acc) + 1)

#画两个图,分别是正确率和损失
#平滑函数,输入一组数,输出平滑函数
#原理:当前数 = 前一个数 * factor + 当前数 * factor
#(ps:平滑是平滑了,但是我个人觉得factor不能调的太大,不然就失去图表本身的意义了)
def smooth_curve(points, factor=0.6):
    smooth_points = []
    for point in points:
        if smooth_points:
            previous = smooth_points[-1]
            smooth_points.append(previous * factor + point * (1 - factor))
        else:
            smooth_points.append(point)
    return smooth_points

#正确率
plt.figure(1)
plt.plot(epochs, smooth_curve(acc), 'bo', label='Training acc')
plt.plot(epochs, smooth_curve(val_acc), 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.legend()
plt.savefig('acc2.png')
plt.show()
#损失
plt.figure(2)
plt.plot(epochs, smooth_curve(loss), 'bo', label='Training loss')
plt.plot(epochs, smooth_curve(val_loss), 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend()
plt.savefig('loss2.png')
plt.show()

输出结果

在这里插入图片描述
在这里插入图片描述
这里用的是训练三十批次,输出的平滑度设置的是0.5,和程序中的不一样,想要的到好的结果,需要经常调整参数

发布了33 篇原创文章 · 获赞 21 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_39226755/article/details/89890071
今日推荐