Cifar 是加拿大政府牵头投资的一个先进科学项目研究所。Hinton、Bengio和他的学生在2004年拿到了 Cifar 投资的少量资金,建立了神经计算和自适应感知项目。这个项目结集了不少计算机科学家、生物学家、电气工程师、神经科学家、物理学家、心理学家,加速推动了 Deep Learning 的进程。从这个阵容来看,DL 已经和 ML 系的数据挖掘分的很远了。Deep Learning 强调的是自适应感知和人工智能,是计算机与神经科学交叉;Data Mining 强调的是高速、大数据、统计数学分析,是计算机和数学的交叉。
Cifar-10 是由 Hinton 的学生 Alex Krizhevsky、Ilya Sutskever 收集的一个用于普适物体识别的数据集。
我们在前面的学习中,使用了MNIST和Fashion-MNIST两个数据集来练习卷积网络的分类,但是这两个数据集都是单通道的灰度图。虽然我们用彩色的几何图形作为例子讲解了卷积网络的基本功能,但是仍然与现实的彩色世界有差距。所以,本节我们将使用Cifar-10数据集来进一步检验一下卷积神经网络的能力。
图18-41是Cifar-10的样本数据。
图18-41 Cifar-10样本数据
Cifar-10 由60000张32*32的 RGB 彩色图片构成,共10个分类。50000张训练,10000张测试。分为6个文件,5个训练数据文件,每个文件中包含10000张图片,随机打乱顺序,1个测试数据文件,也是10000张图片。这个数据集最大的特点在于将识别迁移到了普适物体,而且应用于多分类(姊妹数据集Cifar-100达到100类,ILSVRC比赛则是1000类)。
但是,面对彩色数据集,用CPU做训练所花费的时间实在是太长了,所以本节将学习如何使用GPU来训练神经网络。
我们将使用Keras [ 1 ] ^{[1]} [1]来训练模型,因为Keras是一个在TensorFlow平台上经过抽象的工具,它的抽象思想与我们在前面学习过的各种Layer的概念完全一致,有利于读者在前面的基础上轻松地继续学习。环境搭建有很多细节,我们在这里不详细介绍,只是把基本步骤列出。
安装好后用pip list看一下,关键的几个包是:
Package Version
-------------------- ---------
Keras 2.2.5
Keras-Applications 1.0.8
Keras-Preprocessing 1.1.0
matplotlib 3.1.1
numpy 1.17.0
tensorboard 1.13.1
tensorflow-estimator 1.13.0
tensorflow-gpu 1.13.1
如果没有GPU,则"tensorflow-gpu"一项会是"tensorflow"。
batch_size = 32
num_classes = 10
epochs = 25
data_augmentation = True
num_predictions = 20
save_dir = os.path.join(os.getcwd(), 'saved_models')
model_name = 'keras_cifar10_trained_model.h5'
# The data, split between train and test sets:
(x_train, y_train), (x_test, y_test) = cifar10.load_data()
print('x_train shape:', x_train.shape)
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')
# Convert class vectors to binary class matrices.
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)
model = Sequential()
model.add(Conv2D(32, (3, 3), padding='same',
input_shape=x_train.shape[1:]))
model.add(Activation('relu'))
model.add(Conv2D(32, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Conv2D(64, (3, 3), padding='same'))
model.add(Activation('relu'))
model.add(Conv2D(64, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(512))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes))
model.add(Activation('softmax'))
# initiate RMSprop optimizer
opt = keras.optimizers.rmsprop(lr=0.0001, decay=1e-6)
# Let's train the model using RMSprop
model.compile(loss='categorical_crossentropy',
optimizer=opt,
metrics=['accuracy'])
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255
if not data_augmentation:
print('Not using data augmentation.')
model.fit(x_train, y_train,
batch_size=batch_size,
epochs=epochs,
validation_data=(x_test, y_test),
shuffle=True)
else:
...
在这个模型中:
为什么每一个梯队都要接一个DropOut层呢?因为这个网络结果设计已经比较复杂了,对于这个问题来说很可能会过拟合,所以要避免过拟合。如果简化网络结构,又可能会造成训练时间过长而不收敛。
在GPU上训练,每一个epoch大约需要1分钟;而在一个8核的CPU上训练,每个epoch大约需要2分钟(据笔者观察是因为并行计算占满了8个核)。所以即使读者没有GPU,用CPU训练还是可以接受的。以下是在GPU上的训练输出:
Epoch 1/25
1563/1563 [==============================] - 33s 21ms/step - loss: 1.8770 - acc: 0.3103 - val_loss: 1.6447 - val_acc: 0.4098
......
Epoch 25/25
1563/1563 [==============================] - 87s 55ms/step - loss: 0.8809 - acc: 0.6960 - val_loss: 0.7724 - val_acc: 0.7372
Test loss: 0.772429921245575
Test accuracy: 0.7372
经过25轮后,模型在测试集上的准确度为73.72%。
在CPU上训练,只设置了10个epoch,一共半个小时时间,在测试集上达到63.61%的准确率。观察val_loss和val_acc的趋势,随着训练次数的增加,还可以继续优化。
Epoch 1/10
1563/1563 [==============================] - 133s 85ms/step - loss: 1.8563 - acc: 0.3198 - val_loss: 1.5658 - val_acc: 0.4343
......
Epoch 10/10
1563/1563 [==============================] - 131s 84ms/step - loss: 1.0972 - acc: 0.6117 - val_loss: 1.0426 - val_acc: 0.6361
10000/10000 [==============================] - 7s 684us/step
Test loss: 1.042622245979309
Test accuracy: 0.6361
ch18, Level6
[1] 参考 https://keras.io/examples/cifar10_cnn/