天天看点

深度学习系列笔记——贰 (基于Tensorflow Keras搭建的猫狗大战模型 二)

经过上一篇的数据处理,我们继续搭建我们的猫狗大战项目,本篇主要介绍有关模型搭建的方法,数据处理可以参考上一篇博文:深度学习系列笔记——贰 (基于Tensorflow Keras搭建的猫狗大战模型 一)

0、数据 (代码和上一篇的一样,此处不再赘述)

# 导入包
import tensorflow as tf
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras import layers
import os
import time
import matplotlib.pyplot as plt


start = time.time()

# 设置目录路径
PATH = os.path.join('D:/Desktop/catVSdog/data')  # 图片数据集的根目录
# 将目录区分位猫狗训练集和验证集
train_dir = os.path.join(PATH, 'train')  # train数据集 相对于根目录
validation_dir = os.path.join(PATH, 'validation')  # validation数据集 相对于根目录
train_cats_dir = os.path.join(train_dir, 'cats')  # train目录下的文件夹 每个会在之后分为一类
train_dogs_dir = os.path.join(train_dir, 'dogs')
validation_cats_dir = os.path.join(validation_dir, 'cats')  # validation目录下的文件夹 每个会在之后分为一类
validation_dogs_dir = os.path.join(validation_dir, 'dogs')

num_cats_tr = len(os.listdir(train_cats_dir))
num_dogs_tr = len(os.listdir(train_dogs_dir))

num_cats_val = len(os.listdir(validation_cats_dir))
num_dogs_val = len(os.listdir(validation_dogs_dir))

total_train = num_cats_tr + num_dogs_tr  # 文件数量求和 方便 后续处理和代码复用
total_val = num_cats_val + num_dogs_val

# current model accuracy: 0.9352 , val_accuracy: 0.9233
# 为方便起见,设置变量以在预处理数据集和训练网络时使用
batch_size = 32
epochs = 6
IMG_HEIGHT = 200
IMG_WIDTH = 200

# 使用实时数据增强生成一批张量图像数据。 通过通道方式获取图片
train_image_generator = ImageDataGenerator(rescale=1. / 255, rotation_range=5,
                                           horizontal_flip=True)
validation_image_generator = ImageDataGenerator(rescale=1. / 255)

train_data_gen = train_image_generator.flow_from_directory(
    batch_size=batch_size, directory=train_dir, shuffle=True,
    target_size=(IMG_HEIGHT, IMG_WIDTH), class_mode='binary')
val_data_gen = validation_image_generator.flow_from_directory(
    batch_size=batch_size, directory=validation_dir,
    target_size=(IMG_HEIGHT, IMG_WIDTH), class_mode='binary')

           

1、模型的构建

Tensorflow2.x中,我们可以利用python类的性质,搭建出各种复杂结构的网络,也可以利用函数的方式构建网络。当然最简单的,还是利用这里的tf.keras.models.Sequential,利用类似于搭建积木的方法,快速实现一个网络结构较为简单的神经网络。

model = tf.keras.models.Sequential([
    # 第一层,padding设置为SAME,则说明输入图片大小和输出图片大小是一致的
    layers.Conv2D(filters=32, kernel_size=3, strides=1, padding='same',
                  activation=tf.keras.layers.LeakyReLU(alpha=0.32), #设置激活函数,选择leakyRelu,既有relu的优点,又能有效放置出现神经元死亡,本处小于0的激活值可以调整,可以根据具体情况作出更改
                  input_shape=(IMG_HEIGHT, IMG_WIDTH, 3)),
    # 第二层
    layers.Conv2D(filters=32, kernel_size=3, strides=1, padding='same',
                  activation=tf.keras.layers.LeakyReLU(alpha=0.32)),
    # 第三层
    layers.Conv2D(filters=64, kernel_size=3, strides=1, padding='same',
                  activation=tf.keras.layers.LeakyReLU(alpha=0.64)),
    layers.MaxPooling2D(pool_size=2, strides=2),
    # 第四层
    layers.Conv2D(filters=64, kernel_size=3, strides=1, padding='same',
                  activation=tf.keras.layers.LeakyReLU(alpha=0.64)),
    layers.MaxPooling2D(pool_size=2, strides=2),
    # 第五层
    layers.Conv2D(filters=128, kernel_size=3, strides=1, padding='same',
                  activation=tf.keras.layers.LeakyReLU(alpha=0.128)),
    # 第六层
    layers.Conv2D(filters=128, kernel_size=3, strides=1, padding='same',
                  activation=tf.keras.layers.LeakyReLU(alpha=0.128)),
    layers.MaxPooling2D(pool_size=2, strides=2),

    layers.Flatten(),  # 拉直
    # 第七层
    layers.Dense(1024, activation=tf.keras.layers.LeakyReLU(alpha=0.1024)),
    layers.Dropout(rate=0.5),

    # 第八层
    layers.Dense(512, activation=tf.keras.layers.LeakyReLU(alpha=0.512)),
    layers.Dropout(rate=0.4),

    # 第九层
    layers.Dense(128, activation=tf.keras.layers.LeakyReLU(alpha=0.128)),
    layers.Dropout(rate=0.2), #dropout是一种正则化手段,即随机丢弃一定量的神经元,使之不参与本层的输出。利用dropout可以防止过拟合

    # 第十层 ,输出的为一个值,没有经过sotfmax层
    #即激活函数设置的不是tf.keras.layers.Softmax()因此这个值代表了是猫还是狗
    #与后面的from_logits=True对应,<0时为猫 ,>0为狗。
    layers.Dense(1, activation=tf.keras.layers.LeakyReLU(alpha=0.1))
])
"""
对模型进行编译,确定模型选用的优化器,此处选用随机梯度下降法作为优化方案,另外随着精确度的不断提高,还可以逐步减小模型的学习率等超参数,初始时的学习率一般设置为0.01,最后慢慢降低到1e-4至1e-5等,使得模型能够更好的优化

确定模型选用的损失函数,由于前面模型输出的只有一个值,并没有经过softmax层,因此输出的是逻辑值,故设置时需要将from_logits=True,当输出为类似于独热码的预测值时(需要结果softmax),可以设置为false。
这里若确定模型的性能度量指标,作为在训练过程中打印到控制台的性能度量,便于实时观察,
最后确定模型结构
"""
model.compile(optimizer=tf.keras.optimizers.SGD(learning_rate=0.01, momentum=0.0001),
              loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              metrics=['accuracy'])

"""
此处设置断点续训练的功能,当模型较大时,可能需要很多次训练才能达到较为不错的结果,因此这里添加此功能,便于调试和多次训练
"""
#设置检查点,使得模型可以存储和重新载入,需要提前创建出checkpoint文件夹作为模型保存的路径,根据实际需求也可以设置为其他的文件夹
checkpoint_save_path = "./checkpoint/demo_function_model.ckpt"
if os.path.exists(checkpoint_save_path + '.index'):
    print('-------------load the model-----------------')
    model.load_weights(checkpoint_save_path)
    #如果检查点存在,则导入上一次训练得到的模型的权重,只载入权重,可以方便我们在调试过程中更换优化器,选择不同的优化方案


    
#这里设置
cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_save_path,
                                                 save_weights_only=True,
                                                 save_best_only=True)

history = model.fit( 
#执行训练过程,返回训练的结果,其中包含每一轮的准确率和损失值
    train_data_gen, #传入训练集数据的生成器,便于高效利用显存和GPU性能
    steps_per_epoch=total_train // batch_size, #设置每轮训练所用的步长
    epochs=epochs, #设置迭代的轮数
    validation_data=val_data_gen, #传入验证集数据的生成器
    validation_steps=total_val // batch_size, 
    callbacks=[cp_callback], #设置检查点返回的值,便于断点续训
)

# 输出模型信息,该语句会打印出模型的参数及相关设置,也会统计出模型的参数总数量
model.summary()

end = time.time() #同前面的start结合,计算本次(多个epoch)模型训练总耗时
print("This  %d epochs cost time: %f s , average %f s per epoch" % (epochs, (end - start), (end - start) / epochs))

# 保存模型 ,当模型训练到较为令人满意时,使用下列语句保存模型
# model.save('model',save_format='tf') #model为模型保存的名称

           

2、利用history返回的数据生成训练过程的acc,loss变化曲线

# 可视化训练过程
acc = history.history['accuracy']
val_acc = history.history['val_accuracy']

loss = history.history['loss']
val_loss = history.history['val_loss']

epochs_range = range(epochs)

plt.figure(figsize=(10, 10))
plt.subplot(1, 2, 1)
plt.plot(epochs_range, acc, label='Training Accuracy')
plt.plot(epochs_range, val_acc, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')

plt.subplot(1, 2, 2)
plt.plot(epochs_range, loss, label='Training Loss')
plt.plot(epochs_range, val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()

# 记录模型优化过程及准确率
logFilePath = './/checkpoint//model_log.txt'
if os.path.isfile(logFilePath):
    print("Log file exists.")
    logWriter = open(logFilePath, 'a')
else:
    print("Log file does not exists. Make it .")
    logWriter = open(logFilePath, 'w')

#打印训练日志
logWriter.write('Training finish at : ' + str(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) + '\n')
logWriter.write('model id : ' + str(model.name) + '\n')
logWriter.write('Total epoch : ' + str(epochs) + '\n')
logWriter.write('These epochs cost time (second) : ' + str((end - start)) + '\n')
logWriter.write('Training accuracy  : ' + '\n          ' + str(history.history['accuracy']) + '\n')
logWriter.write('Validation accuracy: ' + '\n          ' + str(history.history['val_accuracy']) + '\n')
logWriter.write('---------------------------------------------------------------------------\n')
logWriter.write('\n')
print("Log text has been successfully written down.")
logWriter.close()
           

3、总结

本篇利用keras的Sequential,快速搭建出一个简单的卷积神经网络模型,用于识别猫和狗的图片。

下一篇将总结整个项目的全部代码,并利用训练得到的模型,对测试图片进行相应的预测。

深度学习系列笔记——贰 (基于Tensorflow Keras搭建的猫狗大战模型 三)

继续阅读