深度学习实战:基于卷积神经网络的猫狗识别
本文记录了第一个基于卷积神经网络在图像识别领域的应用:猫狗图像识别。主要内容包含:
- 数据处理
- 神经网络模型搭建
- 数据增强实现
本文中使用的深度学习框架是Keras;
图像数据来自kaggle官网:https://www.kaggle.com/c/dogs-vs-cats/data
数据处理
数据量
数据集包含25000张图片,猫和狗各有12500张;创建每个类别1000个样本的训练集、500个样本的验证集和500个样本的测试集
注意:只取出部分的数据进行建模
创建目录
In [1]:
1 | import os, shutil |
In [2]:
1 | current_dir = !pwd # 当前目录 |
Out[2]:
1 | '/Users/peter/Desktop/kaggle/kaggle_12_dogs&cats/dogs-vs-cats' |
创建新的目录来存储需要的数据集:
1 | base_dir = current_dir[0] + '/cats_dogs_small' |
1 | # 分别创建训练集、验证集和测试集的目录 |
数据集复制
In [5]:
1 |
|
In [6]:
1 | # 500张当做验证集valiation |
In [7]:
1 | # 500张当做测试集test |
In [8]:
1 | # 针对dog的3个同样操作 |
检查数据
针对猫狗两个类别中查看每个集(训练、验证、测试)中分别包含多少张图像:
构建神经网络
复习一下卷积神经网络的构成:Conv2D层(使用relu激活函数) + MaxPooling2D层 交替堆叠构成。
当需要更大的图像和更复杂的问题,需要再添加一个 Conv2D层(使用relu激活函数) + MaxPooling2D层。
这样做的好处:
- 增大网络容量
- 减少特征图的尺寸
需要注意的是:猫狗分类是二分类问题,所以网络的最后一层是使用sigmoid激活的单一单元(大小为1的Dense层)
在网络中特征图的深度在逐渐增大(从32到128),但是特征图的尺寸在逐渐减小(从150-150到7-7)
- 深度增加:原始图像更复杂,需要更多的过滤器
- 尺寸减小:更多的卷积和池化层对图像在不断地压缩和抽象
网络搭建
In [15]:
1 | import tensorflow as tf |
模型编译(优化)
网络最后一层是单一sigmoid单元,使用二元交叉熵作为损失函数
In [16]:
1 | # 原文:from keras import optimizers |
数据预处理
数据输入到神经网络之前必须先转成浮点数张量。
keras有个处理图像的模块:keras.preprocessing.image。
它包含ImageDataGenerator类,可以快速创建Python生成器,将图形文件处理成张量批量
插播知识点:如何理解python中的生成器?
数据预处理
- 读取文件
- 将文件JPEG文件转成RGB像素网络
- 像素网格转成浮点数张量
In [18]:
1 | from keras.preprocessing.image import ImageDataGenerator |
In [19]:
1 | for data_batch, labels_batch in train_generator: |
生成器的输出是150-150的RGB图像和二进制标签,形状为(20,)组成的批量。每个批量包含20个样本(批量的大小)。
生成器会不断地生成这些批量,不断地循环目标文件夹中的图像。
keras模型使用fit_generator方法来拟合生成器的效果。模型有个参数steps_per_epoch参数:从生成器中抽取steps_per_epoch个批量后,拟合进入下一轮。
本例中:总共是2000个样本,每个批量是20个样本,所以需要100个批量
模型拟合
In [20]:
1 | history = model.fit_generator( |
保存模型
In [21]:
1 |
损失和精度曲线
In [22]:
1 | import matplotlib.pyplot as plt |
In [23]:
1 | history_dict = history.history # 字典形式 |
In [24]:
1 | acc = history_dict["acc"] |
In [25]:
1 | epochs = range(1, len(acc)+1) |
小结:得到过拟合的结论
- 随着时间的增加,训练精度在不断增加,接近100%,而验证精度则停留在70%
- 验证的损失差不多在第6轮后达到最小值,后面一定轮数内保持不变,训练的损失一直下降,直接接近0
数据增强-data augmentation
什么是数据增强
数据增强也是解决过拟合的一种方法,另外两种是:
- dropout
- 权重衰减正则化
什么是数据增强:从现有的训练样本中生成更多的训练数据,利用多种能够生成可信图像的随机变化来增加数据样本。
模型在训练时候不会查看两个完全相同的图像
设置数据增强
In [26]:
1 | datagen = ImageDataGenerator( |
显示增强后图像
In [27]:
1 | from keras.preprocessing import image |
In [28]:
1 | # 读取图片并调整大小 |
包含Dropout层的新卷积神经网络
数据增强来训练网络的话,网络不会看到两次相同的输入。但是输入仍是高度相关的,不能完全消除过拟合。
可以考虑添加一个Dropout层,添加到密集分类连接器之前
In [29]:
1 | import tensorflow as tf |
利用数据增强器来训练卷积神经网络(报错解决)
关于报错解决:我们训练图像有2000张,验证图像1000张,和1000张测试图像。
- steps_per_epoch=100,batch_size=32,如此数据应该是3200张,很明显输入训练数据不够。
- validation_steps=50,batch_size=32,如此数据应该是1600张,很明显验证数据不够。
因此,改为steps_per_epoch=2000/32≈63,validation_steps=1000/32≈32。
In [44]:
1 | # 训练数据的增强 |
模型的保存:
1 | # 保存模型 |
损失和精度曲线
In [46]:
1 | history_dict = history.history # 字典形式 |
具体的绘图代码:
1 | epochs = range(1, len(acc)+1) |
结论:在使用了数据增强之后,模型不再拟合,训练集曲线紧跟着验证曲线;而且精度也变为81%,相比未正则之前得到了提高。