前言
2013年的时候,Kaggle发布了这样的一个挑战(https://www.kaggle.com/c/dogs-vs-cats):
In this competition, you'll write an algorithm to classify whether images contain either a dog or a cat. This is easy for humans, dogs, and cats. Your computer will find it a bit more difficult.
这个挑战提供了一个狗与猫的图像标注过后的数据集,不限算法,实现对含有狗与猫的图像进行分类。在学习了这么久的神经网络之后,此时第一个在脑海中浮现出来的想法肯定是使用卷积神经网络,毕竟卷积神经网络对对图像分类的任务来说是具有极大的优势的。
那么在这一篇文章中,我们将重点放在如何准备并处理这个数据集,以便Keras使用。
下载与处理数据集
Kaggle的Dogs and Cats的数据集可以从Microsoft的网站上进行下载,下载地址如下:
https://www.microsoft.com/en-us/download/details.aspx?id=54765
数据集大小:787MB
每个分类的样本有12,500个,这个样本数量对于训练一个神经网络应该是足够的。
加载和处理数据集首先需要从系统读取图片,这就需要使用到我们的os模块,os模块主要用来遍历目录和结合路径;同时处理图像数据则需要使用OpenCV(图像操作)和Numpy(数组操作)的包;最后使用Pyplot来进行图像的绘制。
import numpy as np
import os
import cv2
import matplotlib.pyplot as plt
由于OpenCV并非Anaconda集成的,因此需要单独安装。可以通过pip install opencv-python
来安装OpenCV或通过pip install opencv-contrib-python
来安装带额外功能的OpenCV版本。
在程序的最前面,我们需要指定数据集的路径与包含的类别:
data_path = "D:/dev/pythonwork/dataset/kagglecatsanddogs_3367a/PetImages/"
categories = ["Dog", "Cat"]
由于不同的卷积网络的输入基本上是固定的,而数据集中的图像大小是不一样的,因此我们需要统一所有图片的大小。统一图片的大小则需要用到Opencv的cv2.resize
函数。
首先,让我们通过cv2.imread
来读取所有的图片,而后使用cv2.resize
修改图片大小。
# 定义图像为50*50的大小
img_size = 50
train_data = []
def create_train_data():
for category in categories:
path = os.path.join(data_path, category)
class_num = categories.index(category)
for img in os.listdir(path):
try:
img_array = cv2.imread(os.path.join(path, img), cv2.IMREAD_GRAYSCALE)
new_array = cv2.resize(img_array, (img_size, img_size))
train_data.append([new_array, class_num])
except Exception as e:
pass
create_train_data()
上述代码先是定义了一个空的列表作为我们的训练集。对于这个机器学习程序来说,我们的目的是让其可以将狗与猫进行分类。因此,训练集应该有特征与标签,标签就是用来区分狗与猫的标签。由于我们前面定义的类别是一个字符串列表,因此这里需要将其转换为0或1的数字。
而且便是读取图像与处理图像。由于数据集中有一些图像坏了,从而会引起一些异常,所以这里采用try来将图像处理的语句包裹起来,如若遇到异常则跳过。
最后,运行create_train_data()
函数之后,我们得到了一个包含特征与标签的训练集。通过print(len(train_data))
来查看这个训练集发现其中一共有24946个样本。
由于在读取和处理图像的时候,是先读取Dog的图像再读取Cat的图像,因此整个train_data的前12500个样本会都是Dog,而后12500个样本则都是Cat。这样训练对机器学习程序来说会很不友好,因此,我们需要对其进行打乱(Shuffle)。
import random
random.shuffle(train_data)
运行完shuffle方法之后,我们的训练集就被成功地打乱了。
最后,让我们将准备好的训练集以特征与标签的形式保存下来。以机器学习程序的标准命名规则来以X来表示特征集,y来表示标签。
for feature, label in train_data:
X.append(feature)
y.append(label)
X = np.array(X).reshape(-1, img_size, img_size, 1) # 最后的1代表grayscale 只有1个通道
准备完成之后,将X和y通过pickle来保存下来,以便别的程序使用。
import pickle
# pickle保存数据
pickle_out = open("X.pickle", "wb")
pickle.dump(X, pickle_out)
pickle_out.close()
pickle_out = open("y.pickle", "wb")
pickle.dump(y, pickle_out)
pickle_out.close()
# pickle读取数据
pickle_in = open("X.pickle", "rb")
X = pickle.load(pickle_in)
保存完成之后,我们将会在相应的文件夹下面找到X.pickle与y.pickle文件。
在下一节中,我们通过Keras的Sequential模型来建立并训练一个卷积神经网络。