背景:

本文主要介绍猫狗分类问题,原型取自2013年的kaggle计算机竞赛,你可以从https://www.kaggle.com/c/dogs_vs_cats/data获取必要的数据集,或者寻找其他的镜像文件。数据集包含25000张猫狗图像,这里我们选取2000张,其中,1000张训练集,500张验证集合500张测试集。

本文将采用2种方法;

(1)使用普通的CNN来训练模型;

(2)使用预训练的VGG16来训练模型。

一、使用普通的CNN来训练模型

代码清单1.1 分配路径

import os, shutiloriginal_dataset_dir = '原始数据集解压路径'
base_dir = '保存较小数据集路径'
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)validation_cats_dir = os.path.join(validation_dir, 'cats')
os.mkdir(validation_cats_dir)test_cats_dir = os.path.join(test_dir, 'cats')
os.mkdir(test_cats_dir)train_dogs_dir = os.path.join(train_dir, 'dogs')
os.mkdir(train_dogs_dir)validation_dir = os.path.join(validation_dir, 'dogs')
os.mkdir(validation_dogs_dir)test_dogs_dir = os.path.join(test_dir, 'dogs')
os.mkdir(test_dogs_dir)#将猫狗图片分别复制到对应的目录下面
fnames = ['cat.{}.jpg'.format(i) for i in range(1000)]
for fname in fnames:src = os.path.join(original_dataset_dir, fname)dst = os.path.join(train_cats_dir, fname)shutil.copyfile(src, dst)fnames = ['cat.{}.jpg'.format(i) in range(1000, 1500)]
for fname in fnames:src = os.path.join(original_dataset_dir, fname)dst = os.path.join(validation_cats_dir, fname)shutil.copyfile(src, dst)fnames = ['cat.{}.jpg'.format(i) in range(1500, 2000)]
for fname in fnames:src = os.path.join(original_dataset_dir, fname)dst = os.path.join(test_cats_dir, fname)shutil.copyfile(src, dst)fnames = ['dog.{}.jpg'.format(i) in range(1000)]
for fname in fnames:src = os.path.join(original_dataset_dir, fname)dst = os.path.join(train_dogs_dir, fname)shutil.copyfile(src, dst)fnames = ['dog.{}.jpg'.format(i) in range(1000, 1500)]
for fname in fnames:src = os.path.join(original_dataset_dir, fname)dst = os.path.join(validation_dogs_dir, fname)shutil.copyfile(src, dst)fnames = ['dog.{}.jpg'.format(i) in range(1500, 2000)]
for fname in fnames:src = os.path.join(original_dataset_dir, fname)dst = os.path.join(test_dogs_dir, fname)shutil.copyfile(src dst)

需要注意的是,在目录创建完毕后,我们应该注释掉创建的命令,以免下次运行程序时报错。

此时我们可以用下面的代码来看看每个分组分别包含多少张图像:

print('The number of training cat images is:', len(os.listdir(train_cats_dir)))
下面代码不再赘述

结果应该是猫和狗训练集 / 验证集 / 测试集各分别有1000 / 500 / 500张图像。

代码清单1.2 构建小型神经网络

from keras import models
from keras import layers
from keras import optimizersmodel = models.Sequential()
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'))model.compile(optimizer=optimizers.RMSprop(lr=1e-4),loss='binary_crossentropy',metrics=['acc'])

卷积神经网络由Conv2D层和MaxPoolingD层交替堆叠而成,因为这里的问题较为复杂,所以适当增大网络,这样既能增加网络容量,还可以进一步缩小特征图的尺寸,使其在连接Flatten层时尺寸不会太大。本节中设置图形大小为150x150(随意),所以最后图形在Flatten层之前的尺寸为7x7。

编译网络时,我们使用RMSprop优化器。因为网络最后一层是单一sigmoid单元,所以我们将使用二元交叉熵作为损失函数。基本规则如下表所示:

为模型选择正确的最后一层激活和损失函数
问题类型 最后一层激活 损失函数
二分类问题 sigmoid binary_crossentropy
多分类、单标签问题 softmax categorical_crossentropy
多分类、多标签问题 sigmoid binary_crossentropy
回归到任意值 mse
回归到0~1范围内的值 sigmoid mse或binary_crossentropy

我们来看看特征图的维度如何随着每层变化:

model.summary()
_________________________________________________________________
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
_________________________________________________________________
conv2d_5 (Conv2D)            (None, 5, 5, 128)         147584
_________________________________________________________________
max_pooling2d_5 (MaxPooling2 (None, 2, 2, 128)         0
_________________________________________________________________
flatten_1 (Flatten)          (None, 512)               0
_________________________________________________________________
dropout_1 (Dropout)          (None, 512)               0
_________________________________________________________________
dense_1 (Dense)              (None, 512)               262656
_________________________________________________________________
dense_2 (Dense)              (None, 1)                 513
=================================================================
Total params: 651,585
Trainable params: 651,585
Non-trainable params: 0
_________________________________________________________________

代码清单1.3 数据预处理

通常地,将数据输入到神经网络之前,应该将数据格式转化为经过预处理的浮点数张量。现在,数据以JEPG的形式保存在硬盘中,处理步骤大致如下:

(1)读取图像文件

(2)将JEPG文件解码为RGB像素风格

(3)将这些像素网格转化为浮点型张量

(4)将像素值从(0~255)缩小到[0-1]区间(神经网络喜欢处理较小的输入值)

Keras自带图像处理辅助工具的模块,位于keras.preprocessing.image。它包含ImageDataGenerator类,可以快速创建Python生成器,能够将硬盘上的图像文件自动转换为预处理好的张量批量。

#使用ImageDataGenerator从目录中读取图像
from keras.preprocessing.image import ImageGeneratortrain_datagen = ImageDataGenerator(rescale=1./255)
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_datagen = test_datagen.flow_from_directory(test_dir,target_size=(150, 150),batch_size=20,class_mode='binary')#看一下生成器的输出
for data_batch, labels_batch in train_generator:print('Data batch shape:', data_batch.shape)print('Labels batch shape:', labels_batch.shape)break

生成器输出如下:

('data batch shape:', (20, 150, 150, 3))
('labels batch shape:', (20,))

生成器生成了150x150的RGB图像 [ 形状为(20, 150, 150, 3) ] 与二进制标签 [ 形状为(20,) ] 组成的批量。每个批量包含20个样本(批量大小)。因为生成器会不停地生成批量,因此我们要在某个时刻让它停下来(break)。

#利用批量生成器拟合模型
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')

此时,我们使用fit_generator的方法来拟合,它在数据生成器上的效果和fit一样。第一个参数应该为Python生成器:train_generator。因为数据不断生成,所以要知道每轮需要从生成器中抽取多少样本,这就是steps_per_epoch的作用:从生成器中抽取steps_per_epoch个批量后(即运行了steps_per_epochs次梯度下降),拟合过程将进入下一个轮次。本例中,每个批量包含20个样本,所以2000个样本需要100个批量。

绘图(代码略)

由图中可以明显看出过拟合的特征,训练精度随着时间线性增加,直到接近%100。而验证精度则停留在%70~%72,。验证损失在5轮后就达到最小值,然后保持不变,而训练损失一直线性下降,直到接近0。

代码清单1.4 数据增强(data augementation)

过拟合原因是因为学习样本太少,无法训练出能够泛化到新数据的模型。我们已经知道dropout和权重衰减(L2正则化),这里我们采用数据增强,它的原理是将图像随机变换一产生新的数据(对于模型而言)。

首先我们定义一个包含dropout的新卷积神经网络:

model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(150, 150, 3)))
model.add(layers.BatchNormalization())
model.add(layers.MaxPooling2D(2, 2))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.BatchNormalization())
model.add(layers.MaxPooling2D(2, 2))
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(layers.BatchNormalization())
model.add(layers.MaxPooling2D())
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(layers.BatchNormalization())
model.add(layers.MaxPooling2D(2, 2))
model.add(layers.BatchNormalization())
model.add(layers.Flatten())
model.add(layers.Dropout(0.5))
model.add(layers.Dense(512, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))model.compile(optimizer=optimizersRMSprop(lr=1e-4),loss='binary_crossentropy',metrics=['acc'])

其中,我们在每个卷积层之间和Flatten层之前增加了BatchNormalization层,最后的准确率大概会提示%1左右。

下面,利用数据增强生成器来训练卷积神经网络:

train_datagen = ImageDataGenerator(rescale=1./255,rotation=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=32,class_mode='binary')validation_generator = test_datagen.flow_from_directory(test_dir,target_size=(150, 150),batch_size=32,class_mode='binary')history = model.fit_generator(train_generator,step_per_epoch=63,epochs=100,validation_data=validation_generator,validation_steps=50)#保存模型
model.save('cats_and_dogs_small_2.h5')

其中,rotation_range是角度值(0~180),表示图像随机旋转的角度;

width_shift和hieght_shift是图像在水平或垂直方向上平移的范围(相对于总的宽度或高度的比例);

shear_range是随机错切变换的角度;

zoom_range是图像随机缩放的范围;

horizontal_flip是随机讲一半图像水平翻转;

fill_mode是用于填充新创建像素的方法,这些新像素可能来自于旋转或宽度 / 高度平移。

随机选择图片,显示数据增强的结果:

from keras.preprocessing import imagefnames = [os.path.join(train_cats_dir, fname) for fname in os.listdir(train_cats_dir)]#选一张图像
img_path = fnames[10]#读取图像并调整大小
img = image.load_img(img_path, target_size=(150, 150))#将其转换成形状为(150, 150, 3)的Numpy数组
x = image.img_to_array(img)#将其形状改为(1, 150, 150, 3)
x = x.reshape((1,) + x.shape)#循环是无限的,需要在某个时刻停止循环
i = 0
for batch in datagen.flow(x, batch_size=1):plt.figure(i)imgplot = plt.imshow(image.array_to_img(batch[0]))i += 1if i % 4 == 0:breakplt.show()

得到的结果如下:

绘图

在使用了数据增强、dropout和normalization之后,模型不再过拟合,训练曲线紧紧跟着验证曲线,精度可达%83。如果再增加网络层数,精度将再提高差不多3个百分点。

目标达成

基于keras的猫狗分类(小型卷积神经网络)相关推荐

  1. 【Deep Learning】基于 Keras 的猫狗分类识别

    基于 Keras 的猫狗分类识别 更新: 本文代码github连接:https://github.com/Sdamu/Keras_pratice    本篇主要实现利用 Keras 来实现 Kaggl ...

  2. 基于tensorflow的猫狗分类

    基于tensorflow的猫狗分类 数据的准备 引入库 数据集来源 准备数据 显示一张图片的内容 搭建网络模型 构建网络 模型的编译 数据预处理 模型的拟合与评估 模型的拟合 预测一张图片 损失和精度 ...

  3. 基于Pytorch实现猫狗分类

    基于Pytorch实现猫狗分类 一.环境配置 二.数据集准备 三.猫狗分类的实例 四.实现分类预测测试 五.参考资料 一.环境配置 1.环境使用 Anaconda 2.配置Pytorch pip in ...

  4. 基于Pytorch的猫狗分类

    无偿分享~ 猫狗二分类文件下载地址 在下一章说        猫狗分类这个真是困扰我好几天,找了好多资料都是以TensorFlow的猫狗分类,但我们要求的是以pytorch的猫狗分类.刚开始我找到了也 ...

  5. 使用Keras做猫狗分类

    本文介绍一个图像分类问题,目标是得到输入图像的类别.使用的方法是训练卷积神经网络,数据集包括上千张猫和狗的图像. 使用的框架是Keras库,数据集下载:这里写链接内容 1下载test_set 和tra ...

  6. 猫狗图像识别(卷积神经网络算法,TensorFlow安装)

    目录 一.tensorflow库安装 (1)TensorFlow的历史版本与对应Python版本 (2)Python版本查询 (3)找到上面的版本框进行对应的TensorFlow下载 (4)安装成功 ...

  7. 使用keras框架进行猫狗分类

    使用keras框架进行猫狗分类 一 .卷积运算 二.准备数据集 2.1 从 Kaggle官网中下载数据集 2.2 通过脚本制作数据集分类 三.构建网络 四.数据预处理 五.使用图像增强技术 一 .卷积 ...

  8. keras_猫狗分类案例(三)_卷机神经网络的可视化(可视化类激活的热力图)

    卷机神经网络的可视化(可视化类激活的热力图) 参考:https://www.cnblogs.com/zhhfan/p/9978099.html python深度学习 可视化类激活的热力图 我还要介绍另 ...

  9. Python深度学习实例--基于卷积神经网络的小型数据处理(猫狗分类)

    Python深度学习实例--基于卷积神经网络的小型数据处理(猫狗分类) 1.卷积神经网络 1.1卷积神经网络简介 1.2卷积运算 1.3 深度学习与小数据问题的相关性 2.下载数据 2.1下载原始数据 ...

最新文章

  1. 解析java匿名内部类
  2. Dune Analytics 发布 v2 版本,新增自动实时查询刷新
  3. 在主函数中输入10个等长的字符串。用另一函数对他们排序。
  4. 机器学习之聚类——模糊聚类FCM
  5. 青少儿编程Python入门教程——Python基础知识库
  6. 微服务化小团队:让 GitLab、Jenkins 与 Sonar 碰撞出火花
  7. LARS算法探究LOL比赛各数据对胜负的影响
  8. Vgg16 + Unet 介绍
  9. linux安装trac+svn+apache+wike,搭建apache+svn+trac平台
  10. oracle直接将日期转为月份,如何使用Oracle将日期转换为周,月,季度,半年,年...
  11. Android EditText 换行 BUG (自动换行与限制行数)
  12. 《51单片机》用STC-ISP-15XX-V6.85F烧录程序的步骤
  13. python实现感知器算法
  14. 自动控制原理01 基本概念
  15. u盘数据恢复的原理_数据恢复的原理是什么?
  16. 中国车辆齿轮行业市场需求现状与前景规模预测报告2022-2028年
  17. 直播的发展前景怎么样?
  18. 比 Xshell 还好用的 SSH 客户端神器
  19. java怎样调用dll 广东精鹰软件工作室(刘正仁)
  20. 电脑录屏软件选哪个?我帮你挑选了这6款。

热门文章

  1. python 使用nacos 注册中心 注册服务
  2. 关于锁相环跟坐标变换
  3. 计算机类专业选考科目要求,新高考报考专业限制 选考科目要求
  4. 郭德纲写给儿子的信给了我很大的触动
  5. fpdisp4.exe
  6. 苹果手写笔好用吗?比较好用的ipad手写笔推荐
  7. 每天bug---用canvas实现手写签名出现轨迹错乱(重要的是苹果手机和安卓手机错乱不一致!)
  8. vue实现在一个段落内的填空题
  9. PHP正则匹配数字,字母,中文
  10. AVS3代码阅读HPM4.0(更新中)