CIFAR-10 物体识别

CIFAR-10 数据集共包含 60000 彩色(RGB)图像,尺寸 32*32。

这些图片总共可分为 10 个分类,用 Python 字典可表示如下:

{ 0 : 'airplane', 
  1 : 'automobile',
  2 : 'bird',
  3 : 'cat',
  4 : 'deer',
  5 : 'dog',
  6 : 'frog',
  7 : 'horse',
  8 : 'ship',
  9 : 'truck' }

60000 张图片中,有 50000 张用作训练集,10000 张用于测试。

CIFAR-10 数据集包含很多用于训练机器学习与计算机视觉算法的图片集,它是目前机器学习研究领域使用最广泛的数据集之一。

CIFAR 的全称是 Canadian Institute For Advanced Research,即加拿大高等研究院,致力于建立和维护研究复杂领域的全球研究网络。该机构另外还有一个叫 CIFAR-100 的数据集。这个数据集中有 100 个分类,每个分类有 600 张图片。

除了 CIFAR 以外,有关计算机视觉比较著名的还有 ImageNet 项目。ImageNet 是一个拥有超过 2 万个类别,超过 1400 万张标注图像的大型视觉数据库。

ImageNet 每年会举办一次大规模视觉识别挑战赛(ILSVRC),这项比赛自 2012 年由 AlexNet 夺得冠军之后,就成了深度卷积神经网络大放异彩的舞台。深度神经网络发展至 2015 年,其准确率甚至超过了人类。因此,ImageNet 宣布,2018 年将引入更难的新挑战——3D 图像。

本次实验将通过 Keras 构建一个我们自己的深度神经网络模型,然后使用 CIFAR-10 数据集进行训练,最后评价其准确度。 

一、模块导入

导入 numpy。搭建 Keras 的 Sequential 模型,导入 Sequential 类。要导入的其他类也位于他们各自的模块中。

import numpy as np
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPool2D
from keras.preprocessing.image import ImageDataGenerator
from keras.utils import np_utils

现在我们要载入 CIFAR-10 数据集。实际上,Keras “内置”了 CIFAR-10 数据集,我们可以直接用 Python 导入。虽然数据集已经“内置”了,但 Keras 要到我们用的时候才会真正下载,毕竟这个数据集还是挺大的。现在我们来载入它。

如果稍后你运行的时候,没有看到 CIFAR-10 下载的过程,那就是本实验的服务器已经提前为你下载好了。

可以看到上述代码从 CIFAR-10 中取出了总共 4 个变量,这样应证了我们第 1.1 节中的关键信息:60000 张图片中,有 50000 张用作训练集,10000 张用于测试。

from keras.datasets import cifar10
(X_train, y_train), (X_test, y_test) = cifar10.load_data()

三、探索数据集

如果你之前没有实际接触过数据集,不要紧,Keras 操作数据集实际上就是在操作 Numpy 数组。

我们首先可以观察一下 CIFAR-10 训练集中的“图片”,我们在末尾添加代码:

print('X_train.shape:', X_train.shape)

 

这行代码可以在稍后我们运行 cifar.py 时输出 X_train 的“形状”。具体的输出结果我们将在小节末尾解释。我们再加一行来查看训练集中的标签:

print('y_train.shape:', y_train.shape)

 

在查看形状之后,我们详细看看第一张“图片”以及它的标签:

print('X_train[0]:', X_train[0], '\ny_train[0]:', y_train[0])

 

运行查看

保存、退出 nano 之后,我们运行 cifar.py 来查看输出结果,输入命令:

python3 cifar.py

 

你会得到很长的一串输出结果,我们分别分析。

前 2 行是这样的:

X_train.shape: (50000, 32, 32, 3)

y_train.shape: (50000, 1)

 

X_train 是训练集中的图片,50000 代表图片的数量;32, 32 代表图片的尺寸,即 32*32;3 表示通道数,由于图片是 RGB 彩色图片,因此有 3 个通道。如果你使用其他库作为 Keras 的后端,此处可能会输出不同的内容,但基本上都是这些信息。

y_train 是训练集的标签,数量 50000 个,和图片数量等同。

输出的最后一行是这样的:

y_train[0]: [6]

 

y_train[0] 是训练集第一张图片的标签,第 1.1 节中介绍过,CIFAR-10 共有 10 个分类,其中第 6 个是 frog,青蛙,说明训练集的第一张图片是青蛙。

输出的中间还有一长串:

X_train[0]: [[[ 59  62  63]

  [ 43  46  45]

  [ 50  48  43]

  ...

  [158 132 108]

  [152 125 102]

  [148 124 103]]

 [[ 16  20  20]

  [  0   0   0]

  [ 18   8   0]

  ...

 

这实际上就是第一张“图片”,不过是“计算机眼中的图片”。图实际上是这样的:

    peb5csbcrs

我们已经知道,这张图片的标签是青蛙,仔细一看,确实是一张青蛙的图片。

探索过数据集之后,我们确定了实验的目标:我们的神经网络所要做的事情,就是根据“图片”,预测图片所属的分类;而我们优化模型的目标,则是让模型根据训练集中的图片进行预测的同时,调整参数,使模型预测的结果逼近训练集的标签。

当然了,深度神经网络拥有数量庞大的参数,本实验中,我们需要借用 Keras 的高级 API 来完成训练。

3.1 数据预处理

本小节将带大家探索 CIFAR-10 数据集。输入命令 `nano cifar.py` 打开 nano,继续编辑 cifar.py。

2.4 小节“数据集探索”中,我们输出了很多信息,为了方便查看本小节的输出信息,我们先在末尾写一行代码,用来输出 5 行空行,以及一个标题:

print('\n\n\n\n\n数据预处理')

 

一些代码工作

我们先来定义几个变量,在后面的代码中,它们将作为常量被使用。

height, width, nb_class = 32, 32, 10

 

分别是图片的高度、宽度,以及分类的数目。

之后我们要对训练集和测试集的图片,即 X 部分做归一化。

X_train = X_train / 255.

X_test = X_test / 255.

 

除了处理图片 X 之外,我们还需要处理标签 y:

y_train = np_utils.to_categorical(y_train, nb_class)

y_test = np_utils.to_categorical(y_test, nb_class)

 

最后,我们要遵循少量多次的原则,将数据“喂”给神经网络。通过 Python 的生成器,我们可以很轻松地实现这一需求。Keras 则为我们实现了一个图像数据生成器:

gen = ImageDataGenerator()

 

上述代码完成了数据的预处理。

 

我们复制 2.4 小节“数据集探索”中用于输出的代码,比较一下预处理前和预处理后,数据集的差别:

print('X_train.shape:', X_train.shape)

print('y_train.shape:', y_train.shape)

print('X_train[0]:', X_train[0], '\ny_train[0]:', y_train[0])

 

保存(按下 Ctrl + O,再按下回车)并退出(Ctrl + X)。

 

运行查看

输入 python3 cifar.py 运行 cifar.py,可以看到“数据预处理”后的输出信息,我们来和之前对比一下。

 

X_train 现在变成了这样:

X_train[0]: [[[0.23137255 0.24313725 0.24705882]

  [0.16862745 0.18039216 0.17647059]

  [0.19607843 0.18823529 0.16862745]

...

 

而执行之前 X_train 是这样的:

X_train[0]: [[[ 59  62  63]

  [ 43  46  45]

  [ 50  48  43]

 

对比可以发现,归一化处理之后的数据,范围归到了 0~1 之间。较小的范围可以减少模型在优化过程中的搜索空间,能有效提升图像分类的准确率。

 

处理后的标签 y_train[0] 形如:

y_train[0]: [0. 0. 0. 0. 0. 0. 1. 0. 0. 0.]

 

包含 10 个数字,从第 0 位开始数,第 6 个元素是 1,其余皆为 0,那么我们就认为这个标签是 6,即青蛙。这样做的原因很简单,分类器对于一张图片的分类,其输出的结果并不是绝对、确定的。

比如对一张青蛙的图片,分类器认为它是青蛙的几率是 80%,它是鸟的几率为 10%,是飞机的概率为 0.01%,等等等等。最终,分类器会返回它认为图片属于各个分类的可能性,这些可能性加在一起就是 100%,程序可以根据哪一个分类的可能性最高,将图片归为该分类。

训练集中有 50000 个这样的标签,因此整个训练集标签矩阵的形状由 (50000, 1) 变为了 (50000, 10),第二项的 10 和分类的数目相同。

 

3.2 搭建神经网络

本小节将带大家搭建神经网络。输入命令 nano cifar.py 打开 nano,继续编辑 cifar.py。

前面两小节我们输出了很多信息,为了方便查看本小节的输出信息,我们先在末尾写一行代码,用来输出 5 行空行,以及一个标题:

print('\n\n\n\n\n搭建网络')

 

一些代码工作

首先我们要生成一个全新的 Sequantial 模型:

model = Sequential()

 

之后我们通过 Keras model 的 add() 方法,先添加输入层:

model.add(Conv2D(32, 3, padding='same', input_shape=X_train.shape[1:], activation='relu'))

 

然后添加卷积和池化层:

model.add(Conv2D(32, 3, activation='relu'))
model.add(MaxPool2D(2))

 

在卷积层和池化层之后,我们要添加一个 Dropout 层。Dropout 层的作用是在训练过程中,每次更新参数,都随机断开一定的神经元(也可以说是使一部分神经元失活,因此 Dropout 层也叫失活层)。添加 Dropout 层是一种有效的防止过拟合的方法。

model.add(Dropout(0.25))

 

之后依然是卷积、池化与失活:

model.add(Conv2D(64, 3, padding='same', activation='relu'))
model.add(Conv2D(64, 3, activation='relu'))
model.add(MaxPool2D(2))
model.add(Dropout(0.25))

 

在这之后,我们要添加一个 Flatten 层,或者叫展开层,它可将高维的张量展开,变成一个一维张量(即向量)。

model.add(Flatten())

 

之后是全连接层、失活层,以及输出层:

model.add(Dense(512, activation='relu'))
model.add(Dropout(0.5))

model.add(Dense(nb_class, activation='softmax'))

 

通过模型的 summary,我们可以从输出信息中得到关于我们搭建的神经网络的一些信息。

model.summary()

 

保存(按下 Ctrl + O,再按下回车)并退出(Ctrl + X)。

 

运行查看

保存、退出 nano 之后,我们运行 cifar.py。输入命令:

python3 cifar.py

 

上述代码搭建的神经网络,如果通过 keras.utils.vis_utils 中的 plot_model 可视化工具可以得到这样的图片,供大家参考:

CIFAR-10 物体识别_第1张图片

4.1 使用凸优化模块训练模型

本小节将带大家训练模型。输入命令 `nano cifar.py` 打开 nano,继续编辑 cifar.py。

前面两小节我们输出了很多信息,为了方便查看本小节的输出信息,我们先在末尾写一行代码,用来输出 5 行空行,以及一个标题:

print('\n\n\n\n\n使用凸优化模块训练模型')

 

 

模型的训练是最耗时、耗资源的环节,幸亏有 Keras,我们需要做的事情却非常少。

我们选用 categorical_crossentropy 作为我们的损失函数,或者叫目标函数,这是一个多分类中比较常用的损失函数。

model.compile(loss='categorical_crossentropy', optimizer='Adam', metrics=['accuracy'])

 

最后调用模型的训练方法:

batch_size = 32
model.fit_generator(gen.flow(X_train, y_train, batch_size=batch_size),
                    steps_per_epoch=X_train.shape[0] // batch_size,
                    epochs=20, verbose=1, validation_data=(X_test, y_test))

 

上述代码使用 X_test, y_test,即测试集,作为验证数据进行训练。这段代码会执行很长一段时间,完成之后,我们就训练好了属于我们自己的神经网络。

注意,这里不用保存退出。训练模型会花费大量时间,本节的内容将和下一节的代码一起运行。

 

 

4.2 使用模型进行预测

前面两小节我们输出了很多信息,为了方便查看本小节的输出信息,我们先在末尾写一行代码,用来输出 5 行空行,以及一个标题:

print('\n\n\n\n\n使用模型进行预测')

 

 

现在我们可以试试模型的效果了,我们选取测试集 X_test 的前 10 张图片,用训练好的模型进行预测:

y_preds = model.predict(X_test[:10])

 

为了方便查看输出结果,我们创建一个字典,将标签的值和分类的名字对应起来:

cifar10_cats = {0: 'airplane', 1: 'automobile', 2: 'bird', 3: 'cat', 4: 'deer', 5: 'dog',

                6: 'frog', 7: 'horse', 8: 'ship', 9: 'truck'}

 

通过以下代码,我们可以比对前 10 张图的真实标签与预测结果:

for i in range(10):

    print('正确结果: {}\n预测结果: {}\n'.format(cifar10_cats[np.argmax(y_test[i])], 

                                            cifar10_cats[np.argmax(y_preds[i])]))

 

保存(按下 Ctrl + O,再按下回车)并退出(Ctrl + X),然后输入命令,训练并预测,注意,训练会消耗大量时间:

python3 cifar.py

 

你可能感兴趣的:(深度学习,神经网络,python,计算机视觉,tensorflow,机器学习)