cats&dogs分类

1. 描述

  • 总述

数据集:kaggle的猫狗数据集
网络:自定义神经卷积网络
防过拟合措施:图像增强和dropout层
开发工具:jupyter+python+keras

  • 数据集说明
    原始猫狗数据集包含了25000张图像(猫狗各12500张),我们这里不适用全部数据集,我们将原始train中的cats中0~1000张图定义为training,1000-1500张定义为validation,1500-2000张定义为test;dogs同理
    在这里插入图片描述
  • 这里给出网络结构:
    在这里插入图片描述

2. 从原始数据集中的train分离出我们需要的train、validation和test

import os,shutil

original_dataset_dir="dogs-vs-cats/train"    # 原始数据集解压目录

## 创建一个一级文件夹
base_dir="dogs-vs-cats_small"    # 保存小数据集的目录
if os.path.exists(base_dir): #如果不存在small文件夹则执行
    shutil.rmtree(base_dir)
os.mkdir(base_dir)  #创建文件夹

## 创建三个二级文件夹:train、validation、test
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文件夹
train_cats_dir=os.path.join(train_dir,'cats')
os.mkdir(train_cats_dir)
## 创建train下dogs文件夹
train_dogs_dir=os.path.join(train_dir,'dogs')
os.mkdir(train_dogs_dir)

## 创建validation下cats文件夹
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)  #在训练集文件夹下定义dogs文件夹

test_cats_dir=os.path.join(test_dir,'cats');os.mkdir(test_cats_dir)  #在训练集文件夹下定义cats文件夹
test_dogs_dir=os.path.join(test_dir,'dogs');os.mkdir(test_dogs_dir)  #在训练集文件夹下定义dogs文件夹

#将原始数据集的train中cat和dog各前1000张复制到train/cats和train/dogs
for className in ["cat","dog"]:
    imageNames=["{}.{}.jpg".format(className,i) for i in range(1000)]
    for name in imageNames:
        src=os.path.join(original_dataset_dir,name)
        if className=="cat":
            dst=os.path.join(train_cats_dir,name)
        else:
            dst=os.path.join(train_dogs_dir,name)
        shutil.copyfile(src,dst)

#将原始数据集的train中cat和dog各1000~1500张复制到validation/cats和validation/dogs
for className in ["cat","dog"]:
    imageNames=["{}.{}.jpg".format(className,i) for i in range(1000,1500)]
    for name in imageNames:
        src=os.path.join(original_dataset_dir,name)
        if className=="cat":
            dst=os.path.join(validation_cats_dir,name)
        else:
            dst=os.path.join(validation_dogs_dir,name)
        shutil.copyfile(src,dst)

#将原始数据集的train中cat和dog各1500~2000张复制到test/cats和test/dogs
for className in ["cat","dog"]:
    imageNames=["{}.{}.jpg".format(className,i) for i in range(1500,2000)]
    for name in imageNames:
        src=os.path.join(original_dataset_dir,name)
        if className=="cat":
            dst=os.path.join(test_cats_dir,name)
        else:
            dst=os.path.join(test_dogs_dir,name)
        shutil.copyfile(src,dst)

3. 网络搭建

from keras import layers
from keras import models

model=models.Sequential()

# block 1
model.add(layers.Conv2D(32,(3,3),activation="relu",input_shape=(150,150,3)))
model.add(layers.MaxPool2D((2,2)))

# block 2
model.add(layers.Conv2D(64,(3,3),activation="relu"))
model.add(layers.MaxPool2D((2,2)))

# block 3
model.add(layers.Conv2D(128,(3,3),activation="relu"))
model.add(layers.MaxPool2D((2,2)))

# block 4
model.add(layers.Conv2D(128,(3,3),activation="relu"))
model.add(layers.MaxPool2D((2,2)))

# output
model.add(layers.Flatten())  #展开为向量
#--------------------------------------------------------------
# 添加dropout层
model.add(layers.Dropout(0.5))
#--------------------------------------------------------------
model.add(layers.Dense(512,activation="relu"))
model.add(layers.Dense(1,activation="sigmoid"))     

model.summary()  # 打印网络结构,可以看到网络结构表

关于最后一层激活层和损失函数(下面会定义)的选择,参考:
在这里插入图片描述

4. 配置模型(优化器)

from keras import optimizers

# loss的选择从上图可以看出二分类问题选择binary_crossentropy
model.compile(loss='binary_crossentropy',
              optimizer=optimizers.RMSprop(lr=1e-4),
              metrics=['accuracy'])
  1. 数据预处理
  • 读取图像
  • 将JPEG解码为RGB文件
  • 将RGB图像转为浮点数张量
  • 将像素缩放到0~1间(归一化)

当然Keras有一个图像处理辅工具的模块,位于keras.preprocessing.image,特别是包含了ImageDataGenerator类,可以创建python生成器,将硬盘上的图像自动转换为与处理好的张量批量.
这里使用了python的生成器

  • python生成器
def generator():
    i=0
    while True:
        i+=1
        yield i

for item in generator():
    print(item)
    if item>4:
        break
 """
 yield像是一个暂停键,并带有return功能:当运行到yield时,返回i值;
 当下次再调用该函数时,用yield的下一句开始运行(并非从i=0开始,而是从
 while True?开始),并且i还是上次i的值
 """

数据预处理代码:

from keras.preprocessing.image import ImageDataGenerator
from keras.preprocessing import image
import matplotlib.pyplot as plt

train_datagen=ImageDataGenerator(rescale=1./255,
                                 rotation_range=40,        #随机旋转的角度范围(0~180°)     range代表范围
                                width_shift_range=0.2,    # width_shift/height_shift:在图像水平或垂直方向上平移的范围(按总宽总高比例)
                                height_shift_range=0.2,   
                                shear_range=0.2,          # 随机错切变换的角度
                                zoom_range=0.2,           # 图像随机缩放的范围
                                horizontal_flip=True,     # 随机将一半图像水平翻转
                                )  # 将所有图像乘以1/255缩放,归一化

validation_datagen=ImageDataGenerator(rescale=1./255)


#--------------------------------------------------------------------------
# 显示随机增强后的训练图像
# fnames=[os.path.join(train_cats_dir,fname) for fname in os.listdir(train_cats_dir)]
# img_path=fnames[3]
# img=image.load_img(img_path,target_size=(150,150))  # 读取图片并调整大小
# x=image.img_to_array(img)   #转为(150,150,3)的Numpy数组
# x=x.reshape((1,)+x.shape)   #改变形状为(1,150,150,3)
# i=0
# for batch in train_datagen.flow(x,batch_size=1):
#     plt.figure(i)
#     imgplot=plt.imshow(image.array_to_img(batch[0]))
#     i+=1
#     if i%4==0:
#         break
# plt.show()
#--------------------------------------------------------------------------

# 参数分别指目标目录、调整为多少尺寸、batch_size、标签类型(因为使用了binary_crossentropy损失,所以需要用二进制标签)
train_generator=train_datagen.flow_from_directory(train_dir,
                                                 target_size=(150,150),
                                                  batch_size=20,
                                                  class_mode="binary"
                                                 )
validation_generator=validation_datagen.flow_from_directory(validation_dir,
                                                 target_size=(150,150), 
                                                  batch_size=20,
                                                  class_mode="binary"
                                                 )

# 查看train_generator产生的数据和标签的性质
for data_batch,labels_batch in train_generator:
    print("data batch shape:",data_batch.shape)
    print("lables batch shape:",labels_batch.shape)
    break

可以看到data_batch和labels_batch的形状:
在这里插入图片描述

5. 开始训练

在这里传入的数据和标签不再是以前的直接传入,而是使用生成器传入。fit_generator:API描述

fit_generator(generator,
         steps_per_epoch=None,  #一个epoch从generator产生的总步数,本例中一个generator是20张,故=2000/20=100,需要100次generator
         epochs=1,
         verbose=1,            # 日志显示模式: 0 = 安静模式, 1 = 进度条, 2 = 每轮一行。
         callbacks=None,
         validation_data=None,
         validation_steps=None,    #同steps_per_epoch,仅当validation_data为生成器才可用
         class_weight=None,
         max_queue_size=10,
         workers=1,
         use_multiprocessing=False,
         shuffle=True,          #是否在每轮迭代之前打乱 batch 的顺序
         initial_epoch=0)  

代码:

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

效果如下:
在这里插入图片描述

6.保存模型

model.save("cats_and_dogs_small_V3.h5")  # 保存到脚本文件所在目录

7.可视化

history实际上是一个字典,对于epoch=4的结果,history内容如下:
在这里插入图片描述
所以使用plt以epoch为横坐标,相关指标为纵坐标画图即可

import matplotlib.pyplot as plt
acc=history.history['accuracy']
print("训练最佳精度:",max(acc))
val_acc=history.history['val_accuracy']
print("验证最佳精度:",max(val_acc))

loss=history.history['loss']
val_loss=history.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.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.title('Training and validation loss')
plt.legend()  #创建图例

plt.show()

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我是一个对称矩阵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值