Kaggle深度学习与卷积神经网络项目实战-猫狗分类检测数据集
一、相关介绍
在小型数据集上从头开始训练卷积网络
使用非常少的数据来训练图像分类模型是一种常见的情况,如果您曾经在专业环境中使用计算机视觉,那么您可能会在实践中遇到这种情况。
拥有“少数”样本意味着从几百到几万张图像的任何地方。作为一个实际的例子,我们将在包含4000张猫和狗(2000只猫,2000只狗)图片的数据集中,将图像分类为“狗”或“猫”。我们将使用2000张图片进行培训,1000张图片进行验证,最后1000张图片进行测试。
在本节中,我们将回顾解决这个问题的一个基本策略:根据我们仅有的少量数据从头开始训练一个新模型。我们将在2000个训练样本上天真地训练一个小型卷积神经网络,不需要任何正则化,来设定一个可以达到的基线。这将使我们的分类准确率达到71%。在这一点上,我们的主要问题是过度拟合。然后我们将介绍一种强大的数据增强技术,以减轻计算机视觉中的过拟合。通过利用数据扩展,我们将改进我们的网络,使其达到82%的准确率。
在下一节中,我们将回顾将深度学习应用于小数据集的两项更重要的技术:使用预先训练好的网络进行特征提取(这将使我们的准确率达到90%到93%),以及微调预先训练好的网络(这将使我们的最终准确率达到95%)。这三种策略——从零开始训练一个小模型,使用预先训练好的模型进行特征提取,以及对预先训练好的模型进行微调——将构成您未来的工具箱,用于解决使用小数据集进行计算机视觉的问题。
小数据问题的深度学习相关性
有时你会听到,只有当大量数据可用时,深度学习才有效。这在一定程度上是一个有效的观点:深度学习的一个基本特征是它能够在训练数据中自己找到感兴趣的特征,而不需要任何手动特征工程,并且只有在有大量训练示例的情况下才能实现这一点。这尤其适用于输入样本是高维的问题,比如图像
然而,构成“大量”样本的因素是相对的——首先是相对于你试图训练的网络的规模和深度。训练一个convnet来解决一个只有几十个样本的复杂问题是不可能的,但是如果模型很小且正则化良好,并且任务很简单,那么几百个样本可能就足够了。因为convnets学习局部的、平移不变的特征,所以它们在感知问题上非常有效。在一个非常小的图像数据集上从头开始训练convnet仍然会产生合理的结果,尽管数据相对缺乏,而不需要任何自定义的特征工程。您将在本节中看到这一点。
但更重要的是,深度学习模型本质上是高度可重用的:比如,你可以采用在大规模数据集上训练的图像分类或语音到文本模型,然后在一个显著不同的问题上重用它,只需稍加更改。具体来说,在计算机视觉的情况下,许多预先训练的模型(通常在ImageNet数据集上训练)现在可以公开下载,并且可以用来从很少的数据中引导强大的视觉模型。这就是我们下一节要做的。
现在,让我们从掌握数据开始
二、下载数据集
我们将使用的猫狗数据集没有打包在Keras中。
Keras是一个高层神经网络API,Keras由纯Python编写而成并基Tensorflow、Theano以及CNTK后端。Keras 为支持快速实验而生,能够把你的idea迅速转换为结果,如果你有如下需求,请选择Kera
- 简易和快速的原型设计(keras具有高度模块化,极简,和可扩充特性)
- 支持CNN和RNN,或二者的结合
- 无缝CPU和GPU
它由Kaggle在2013年末公开并作为一项计算视觉竞赛的一部分,当时卷积神经网络还不是主流算法。我们可以从https://www.kaggle.com/c/dogs-vs-cats/data中下载我们需要的数据集。
不出所料,2013年的猫狗Kaggle比赛中,使用卷积神经网络(convnets)的参赛者获得了冠军。最佳参赛作品的正确率可达95%。在我们自己的示例中,我们将相当接近这个精度(在下一节中),尽管我们的模型所使用的数据还不到竞争对手可用数据的10%。这个原始数据集包含25,000张狗和猫的图像(每个类有12,500张),有543MB大(压缩)。下载并解压缩后,我们将创建一个包含三个子集的新数据集:一个包含每个类1000个样本的训练集,一个包含每个类500个样本的验证集,最后一个包含每个类500个样本的测试集。
这些图片是中等分辨率的彩色jpeg。它们是这样的:
三、代码示例
1.导入keras库,并显示版本号
import keras
keras.__version__
运行结果:
import os, shutil #复制文件
# 原始目录所在的路径
# 数据集未压缩
original_dataset_dir = 'D:/Workspaces/Jupyter-notebook/datasets/mldata/kaggle_original_data'
# 我们将在其中的目录存储较小的数据集
base_dir = 'D:/Workspaces/Jupyter-notebook/datasets/mldata/cats_and_dogs_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_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_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_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_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_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_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)))
print('total training dog images:', len(os.listdir(train_dogs_dir)))
print('total validation cat images:', len(os.listdir(validation_cats_dir)))
print('total validation dog images:', len(os.listdir(validation_dogs_dir)))
print('total test cat images:', len