前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >关于深度学习系列笔记十二(关于猫狗判断实验)

关于深度学习系列笔记十二(关于猫狗判断实验)

作者头像
python与大数据分析
发布2022-03-11 13:36:18
4580
发布2022-03-11 13:36:18
举报
文章被收录于专栏:python与大数据分析

首先小小的庆祝一下自己的微信公众号订阅用户已达到100人了,是小小的虚荣心也是收获也是鞭策,希望自己砥砺前行,努力进步,做到更好。

其实写文章,比较难的是对知识的沉淀,这个沉淀有多种,代码的沉淀,一件事物理解上的沉淀,甚至整合代码和文章的沉淀,要考虑他人的感受,也要在自己的能力范围内进行控制等等不一而足。

本笔记是经典的猫狗识别问题,大概25000的训练集图片加上12500的测试集图片,猫狗图片各一半,共约700多M,而之前的手写数字也不过10M多一些,对计算机处理而言都是比较耗资源的,何况这个实验的目的本来就是从小样本提升准确率。从实质上这些模型和前面的模型没有本质区别,唯一的区别是ImageDataGenerator的应用,能够把图片直接转换为浮点数向量。

可视化训练集和验证集的损失率和准确率

可以看出随着训练轮次的增加,

训练集的准确率呈对数级上升,而验证集的准确率则在第十轮左右维持在72%的准确率

训练集的损失度呈对数级下降,而验证集的损失度则在第十轮左右最低,此后不断上升

因此本例子主要还是过度拟合导致,根本原因是样本数量不足,只有2000训练集样本

在增加dropout层以后,训练准确率较之前有所下降,但验证准确率较之前有所提升达到75%。

在利用数据增强生成器训练卷积神经网络后,训练集和验证集的准确率基本是同步的,最高上升到78%

代码示例

代码语言:javascript
复制
import os, shutil
def initdata():
    #原始数据集解压目录的两个路径
    original_dataset_train_dir = 'D:/Python36/Coding/PycharmProjects/ttt/dataset/train'
    original_dataset_test_dir = 'D:/Python36/Coding/PycharmProjects/ttt/dataset/test'

    #保存较小数据集的目录
    base_dir = 'D:/Python36/Coding/PycharmProjects/ttt/dataset/small'
    os.mkdir(base_dir)

    #分别对应划分后的训练、验证和测试的目录
    train_dir = os.path.join(base_dir, 'train')
    os.mkdir(train_dir)
    validation_dir = os.path.join(base_dir, 'validation')
    os.mkdir(validation_dir)
    test_dir = os.path.join(base_dir, 'test')
    os.mkdir(test_dir)

    #猫的训练图像目录
    train_cats_dir = os.path.join(train_dir, 'cats')
    os.mkdir(train_cats_dir)
    #狗的训练图像目录
    train_dogs_dir = os.path.join(train_dir, 'dogs')
    os.mkdir(train_dogs_dir)
    #猫的验证图像目录
    validation_cats_dir = os.path.join(validation_dir, 'cats')
    os.mkdir(validation_cats_dir)
    #狗的验证图像目录
    validation_dogs_dir = os.path.join(validation_dir, 'dogs')
    os.mkdir(validation_dogs_dir)
    #猫的测试图像目录
    test_cats_dir = os.path.join(test_dir, 'cats')
    os.mkdir(test_cats_dir)
    #狗的测试图像目录
    test_dogs_dir = os.path.join(test_dir, 'dogs')
    os.mkdir(test_dogs_dir)

    #将前1000 张猫的图像复制到train_cats_dir
    fnames = ['cat.{}.jpg'.format(i) for i in range(1000)]
    for fname in fnames:
        src = os.path.join(original_dataset_train_dir, fname)
        dst = os.path.join(train_cats_dir, fname)
        shutil.copyfile(src, dst)
    #将接下来500张猫的图像复制到validation_cats_dir
    fnames = ['cat.{}.jpg'.format(i) for i in range(1000, 1500)]
    for fname in fnames:
        src = os.path.join(original_dataset_train_dir, fname)
        dst = os.path.join(validation_cats_dir, fname)
        shutil.copyfile(src, dst)
    #将接下来的500 张猫的图像复制到test_cats_dir
    fnames = ['cat.{}.jpg'.format(i) for i in range(1500, 2000)]
    for fname in fnames:
        src = os.path.join(original_dataset_train_dir, fname)
        dst = os.path.join(test_cats_dir, fname)
        shutil.copyfile(src, dst)
    #将前1000 张狗的图像复制到train_dogs_dir
    fnames = ['dog.{}.jpg'.format(i) for i in range(1000)]
    for fname in fnames:
        src = os.path.join(original_dataset_train_dir, fname)
        dst = os.path.join(train_dogs_dir, fname)
        shutil.copyfile(src, dst)
    #将接下来500张狗的图像复制到validation_dogs_dir
    fnames = ['dog.{}.jpg'.format(i) for i in range(1000, 1500)]
    for fname in fnames:
        src = os.path.join(original_dataset_train_dir, fname)
        dst = os.path.join(validation_dogs_dir, fname)
        shutil.copyfile(src, dst)
    #将接下来的500 张狗的图像复制到test_dogs_dir
    fnames = ['dog.{}.jpg'.format(i) for i in range(1500, 2000)]
    for fname in fnames:
        src = os.path.join(original_dataset_train_dir, fname)
        dst = os.path.join(test_dogs_dir, fname)
        shutil.copyfile(src, dst)
    #检查一下,看看每个分组(训练/ 验证/ 测试)中分别包含多少张图像。
    print('total training cat images:', len(os.listdir(train_cats_dir)))
    # total training cat images: 1000
    print('total training dog images:', len(os.listdir(train_dogs_dir)))
    # total training dog images: 1000
    print('total validation cat images:', len(os.listdir(validation_cats_dir)))
    # total validation cat images: 500
    print('total validation dog images:', len(os.listdir(validation_dogs_dir)))
    # total validation dog images: 500
    print('total test cat images:', len(os.listdir(test_cats_dir)))
    # total test cat images: 500
    print('total test dog images:', len(os.listdir(test_dogs_dir)))
    # total test dog images: 500

    #即整体目录和图片数量如下
    # small
    #    test
    #        cats         500
    #        dogs         500
    #    train
    #        cats         1000
    #        dogs         1000
    #    validation
    #        cats         1000
    #        dogs         1000
    return train_dir,validation_dir

from keras.preprocessing.image import ImageDataGenerator

#数据预处理
def previewprocess(train_dir,validation_dir):
    #(1) 读取图像文件。
    #(2) 将JPEG 文件解码为RGB 像素网格。
    #(3) 将这些像素网格转换为浮点数张量。
    #(4) 将像素值(0~255 范围内)缩放到[0, 1] 区间(正如你所知,神经网络喜欢处理较小的输入值)。
    train_datagen = ImageDataGenerator(rescale=1./255)   #将所有图像乘以1/255 缩放
    test_datagen = ImageDataGenerator(rescale=1./255)    #将所有图像乘以1/255 缩放
    # Found 2000 images belonging to 2 classes.
    # Found 1000 images belonging to 2 classes.
    # 它生成了150×150的RGB图像[形状为(20, 150, 150, 3)]与二进制标签[形状为(20, )]组成的批量。
    # 每个批量中包含20个样本(批量大小)
    train_generator = train_datagen.flow_from_directory(
        train_dir,
        target_size=(150, 150), #将所有图像的大小调整为150×150
        batch_size=20,
        class_mode='binary')  #因为使用了binary_crossentropy损失,所以需要用二进制标签
    validation_generator = test_datagen.flow_from_directory(
        validation_dir,
        target_size=(150, 150), #将所有图像的大小调整为150×150
        batch_size=20,
        class_mode='binary')  #因为使用了binary_crossentropy损失,所以需要用二进制标签
    #train_generator和validation_generator数据格式如下:即4维数组和一个目标标签数组
    #array([[[[0.26666668, 0.27058825, 0.2509804],
    #         [0.26666668, 0.27058825, 0.2509804],
    #         [0.26666668, 0.27058825, 0.2509804],
    #         ...,
    #         [0.6745098, 0.67058825, 0.6627451],
    #         [0.65882355, 0.654902, 0.64705884],
    #         [0.64705884, 0.6431373, 0.63529414]]]],
    #      dtype=float32),
    #array([0., 1., 0., 0., 1., 1., 1., 0., 0., 1., 1., 1., 1., 0., 1., 0., 1., 1., 1., 0.],
    #      type=float32))
    #begin time= Fri May 17 14:43:46 2019
    for data_batch, labels_batch in train_generator:
        print('data batch shape:', data_batch.shape)
        #data batch shape: (20, 150, 150, 3)
        print('labels batch shape:', labels_batch.shape)
        break
    return  train_generator,validation_generator

def enhenceimage(train_dir,validation_dir):
    #利用ImageDataGenerator来设置数据增强
    '''
    datagen = ImageDataGenerator(
        rotation_range=40,      #是角度值(在 0~180 范围内),表示图像随机旋转的角度范
        width_shift_range=0.2,  #是图像在水平或垂直方向上平移的范围(相对于总宽度或总高度的比例
        height_shift_range=0.2, #是图像在水平或垂直方向上平移的范围(相对于总宽度或总高度的比例
        shear_range=0.2,        #随机错切变换的角度
        zoom_range=0.2,         #是图像随机缩放的范围
        horizontal_flip=True,  #是随机将一半图像水平翻转
        fill_mode='nearest')  #是用于填充新创建像素的方法,这些新像素可能来自于旋转或宽度/高度平移
    '''
    #利用数据增强生成器训练卷积神经网络
    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,)
    test_datagen = ImageDataGenerator(rescale=1./255)
    train_generator = train_datagen.flow_from_directory(
        train_dir,
        target_size=(150, 150),
        batch_size=32,
        class_mode='binary')
    validation_generator = test_datagen.flow_from_directory(
        validation_dir,
        target_size=(150, 150),
        batch_size=32,
        class_mode='binary')
    return  train_generator,validation_generator

from keras import layers
from keras import models
def buildmodel():
    #构建模型
    model = models.Sequential()
    #4个卷积层和4个池化层以及2个全连接层
    model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(150, 150, 3)))
    model.add(layers.MaxPooling2D((2, 2)))
    model.add(layers.Conv2D(64, (3, 3), activation='relu'))
    model.add(layers.MaxPooling2D((2, 2)))
    model.add(layers.Conv2D(128, (3, 3), activation='relu'))
    model.add(layers.MaxPooling2D((2, 2)))
    model.add(layers.Conv2D(128, (3, 3), activation='relu'))
    model.add(layers.MaxPooling2D((2, 2)))
    model.add(layers.Flatten())
    model.add(layers.Dense(512, activation='relu'))
    model.add(layers.Dense(1, activation='sigmoid'))
    print(model.summary())
    return model

def buildmodelwithdropout():
    #构建模型
    model = models.Sequential()
    #4个卷积层和4个池化层以及2个全连接层
    model.add(layers.Conv2D(32, (3, 3), activation='relu',input_shape=(150, 150, 3)))
    model.add(layers.MaxPooling2D((2, 2)))
    model.add(layers.Conv2D(64, (3, 3), activation='relu'))
    model.add(layers.MaxPooling2D((2, 2)))
    model.add(layers.Conv2D(128, (3, 3), activation='relu'))
    model.add(layers.MaxPooling2D((2, 2)))
    model.add(layers.Conv2D(128, (3, 3), activation='relu'))
    model.add(layers.MaxPooling2D((2, 2)))
    model.add(layers.Flatten())
    model.add(layers.Dropout(0.5))
    model.add(layers.Dense(512, activation='relu'))
    model.add(layers.Dense(1, activation='sigmoid'))
    print(model.summary())
    return model

from keras import optimizers
# initdata()
train_generator = 'D:/Python36/Coding/PycharmProjects/ttt/dataset/small/train'
validation_generator = 'D:/Python36/Coding/PycharmProjects/ttt/dataset/small/validation'
train_generator,validation_generator=previewprocess(train_generator,validation_generator)

model=buildmodel()
modelwithdropout=buildmodelwithdropout()
#Layer (type)                 Output Shape              Param #
#=================================================================
#conv2d_1 (Conv2D)            (None, 148, 148, 32)      896
#_________________________________________________________________
#max_pooling2d_1 (MaxPooling2 (None, 74, 74, 32)        0
#_________________________________________________________________
#conv2d_2 (Conv2D)            (None, 72, 72, 64)        18496
#_________________________________________________________________
#max_pooling2d_2 (MaxPooling2 (None, 36, 36, 64)        0
#_________________________________________________________________
#conv2d_3 (Conv2D)            (None, 34, 34, 128)       73856
#_________________________________________________________________
#max_pooling2d_3 (MaxPooling2 (None, 17, 17, 128)       0
#_________________________________________________________________
#conv2d_4 (Conv2D)            (None, 15, 15, 128)       147584
#_________________________________________________________________
#max_pooling2d_4 (MaxPooling2 (None, 7, 7, 128)         0
#_________________________________________________________________
#flatten_1 (Flatten)          (None, 6272)              0
#_________________________________________________________________
#dense_1 (Dense)              (None, 512)               3211776
#_________________________________________________________________
#dense_2 (Dense)              (None, 1)                 513
#=================================================================
# 使用RMSprop 优化器。
# 因为网络最后一层是单一sigmoid单元,所以我们将使用二元交叉熵作为损失函数
#为模型选择正确的最后一层激活和损失函数
#问题类型   最后一层激活  损失函数
#二分类问题   sigmoid    binary_crossentropy
#多分类、单标签问题   softmax    categorical_crossentropy
#多分类、多标签问题   sigmoid    binary_crossentropy
#回归到任意值 无   mse
#回归到0~1 范围内的值    sigmoid    mse 或binary_crossentropy
model.compile(loss='binary_crossentropy',optimizer=optimizers.RMSprop(lr=1e-4),metrics=['acc'])
history = model.fit_generator(train_generator,steps_per_epoch=100,epochs=30,validation_data=validation_generator,validation_steps=50)
#保存模型
model.save('cats_and_dogs_small_1.h5')

#编译、训练、保存带dropout模式的模型
modelwithdropout.compile(loss='binary_crossentropy',optimizer=optimizers.RMSprop(lr=1e-4),metrics=['acc'])
historywithdropout = modelwithdropout.fit_generator(train_generator,steps_per_epoch=100,epochs=30,validation_data=validation_generator,validation_steps=50)
#保存模型
modelwithdropout.save('cats_and_dogs_small_1_withdropout.h5')

#和上面同样的模型,只是增强了图片样本
train_generator = 'D:/Python36/Coding/PycharmProjects/ttt/dataset/small/train'
validation_generator = 'D:/Python36/Coding/PycharmProjects/ttt/dataset/small/validation'

train_generator,validation_generator=enhenceimage(train_generator,validation_generator)
modelwithenhencedropout=buildmodelwithdropout()
modelwithenhencedropout.compile(loss='binary_crossentropy',optimizer=optimizers.RMSprop(lr=1e-4),metrics=['acc'])
historywithenhencedropouthistory = modelwithenhencedropout.fit_generator(train_generator,steps_per_epoch=100,epochs=30,validation_data=validation_generator,validation_steps=50)
modelwithenhencedropout.save('cats_and_dogs_small_1_withehencedropout.h5')

#可视化训练集和验证集的损失率和准确率
# 可以看出随着训练轮次的增加,
# 训练集的准确率呈对数级上升,而验证集的准确率则在第十轮左右维持在72%的准确率
# 训练集的损失度呈对数级下降,而验证集的损失度则在第十轮左右最低,此后不断上升
# 因此本例子主要还是过度拟合导致,根本原因是样本数量不足,只有2000训练集样本
# 在增加dropout层以后,训练准确率较之前有所下降,但验证准确率较之前有所提升达到75%。
# 在利用数据增强生成器训练卷积神经网络后,训练集和验证集的准确率基本是同步的,最高上升到78%
#150s 2s/step - loss: 0.0340 - acc: 0.9900 - val_loss: 1.1205 - val_acc: 0.7190
#153s 2s/step - loss: 0.2005 - acc: 0.9245 - val_loss: 0.6639 - val_acc: 0.7500
#244s 2s/step - loss: 0.4792 - acc: 0.7687 - val_loss: 0.4896 - val_acc: 0.7494
import matplotlib.pyplot as plt
acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']
accwithdropout = historywithdropout.history['acc']
val_accwithdropout = historywithdropout.history['val_acc']
losswithdropout = historywithdropout.history['loss']
val_losswithdropout = historywithdropout.history['val_loss']
accwithenhencedropout = historywithenhencedropouthistory.history['acc']
val_accwithenhencedropout = historywithenhencedropouthistory.history['val_acc']
losswithenhencedropout = historywithenhencedropouthistory.history['loss']
val_losswithenhencedropout = historywithenhencedropouthistory.history['val_loss']

epochs = range(1, len(acc) + 1)
plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.plot(epochs, accwithdropout, 'bo', label='Training acc withdropout',color='red')
plt.plot(epochs, val_accwithdropout, 'b', label='Validation acc withdropout',color='red')
plt.plot(epochs, accwithenhencedropout, 'bo', label='Training acc withenhencedropout',color='yellow')
plt.plot(epochs, val_accwithenhencedropout, 'b', label='Validation acc withenhencedropout',color='yellow')
plt.title('Training and validation accuracy')
plt.legend()
plt.figure()
plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.plot(epochs, losswithdropout, 'bo', label='Training loss withdropout',color='red')
plt.plot(epochs, val_losswithdropout, 'b', label='Validation loss withdropout',color='red')
plt.plot(epochs, losswithenhencedropout, 'bo', label='Training loss withenhencedropout',color='yellow')
plt.plot(epochs, val_losswithenhencedropout, 'b', label='Validation loss withenhencedropout',color='yellow')
plt.title('Training and validation loss')
plt.legend()
plt.show()
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-05-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 python与大数据分析 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档