—简述
上篇博客基于keras训练MNIST数据集-全连接网络已经详细介绍了只用全连接层训练MNIST数据集的步骤,本文将介绍使用卷积神经网络来训练MNIST数据集步骤。
1、加载MNIST数据集
MNIST数据集是由 60000 张训练图像和 10000 张测试图像组成,图像大小是 28 x 28 的灰度图像,已经预先加载在了Keras库中,其中包括4个Numpy数组。这一步同上篇全连接网络。
# 加载Keras中的MNIST数据集
from keras.datasets import mnist
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
打印数据集,如下
>> train_image.shape
(6000, 28, 28)
>> train_labels
array([5, 0, 4, ..., 6, 8], dtype=uint8)
2、图像数据预处理
要对加载的数据进行预处理,以适应网络模型要求的形状,并将所有值缩放到[ 0, 1] 之间,由于我们训练的图像是 28 x 28 的灰度图,被保存在 uint8 类型的数组中,也就是值的范围在 [0, 255] 之间,形状为 (60000, 28, 28),所以最后要转换为一个 float32 数组, 其形状变为(60000, 28, 28,1),取值范围为 0~1。其中 1 代表灰度图,RGB图像是 3。
# 准备图像数据
train_images = train_images.reshape((60000, 28, 28, 1))
train_images = train_images.astype('float32') / 255
test_images = test_images.reshape((10000, 28, 28, 1))
test_images = test_images.astype('float32') / 255
# 准备标签,需要对标签进行分类编码转换成二进制格式
train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)
3、模型定义
模块 layers 可以看作是构建网络层的工具,模块 models 可以看作是创建网络模型的一个容器,可以把创建的网络层加入到这个容器中。
# 导入数据处理模块,可以看作
from keras import models
from keras import layers
# 先定义一个空的网络结构
model = models.Sequential()
#添加卷积层,这里把卷积和池化统称为卷积层
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
#平铺,展平数据
model.add(layers.Flatten())
#添加1个Dropout层
model.add(layers.Dropout(0.5))
# 添加两个全连接层
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(10, activation='softmax'))
4、编译模型
代码很短只需一行,但需要设置三个参数,其中
- loss: 所代表的是损失函数,使网络模型训练数据朝向正确的方向前进。
- optimizer: 基于训练数据和损失函数来更新网络的机制。
- metric: 在训练和测试过程中需要监控的指标,本例只关心精度,即正确分类的图像所占的比例。
# 设置训练网络的必要参数,如果要用到其他优化器还需要导入模块 optimizers
model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy'])
5、训练模型
也就是在训练数据上拟合模型,其中前两个参数为训练数据,即,包含图像和标签的数据。
- epochs 为迭代次数,即训练整个数据集要迭代的次数,可根据机器性能设置参数,详细调参后续文章会叙述。
- batch_size 表示每次训练数据按此批量大小进行训练,也可以是其它参数,但是最好取 2 的整数倍。
注意: 这里并没有加入验证集, 因为经过测试发现加入验证集反而测试精度降低,可能是验证模型时,由于验证集的加入使得网络对输入的图像产生了“记忆”,虽然最后训练精度会提高,但会导致训练出的模型泛化能力降低。
history = model.fit(train_images, train_labels, epochs=5, batch_size=64)
# 评估模型,即在测试集上的性能
test_loss, test_acc = model.evaluate(test_images, test_labels)
可以对上述数据进行打印,如
>>print('test_acc:', test_acc)
test_acc: 0.9915
>>history_dict = history.history
>>history_dict.keys()
dict_keys(['loss', 'acc'])
训练过程如下:
6、预测图像
现在我们来预测未训练的原始图像(测试集)并显示出来,首先重新加载 MNIST 数据集,因为前面过程预处理使得图像数据格式变化。
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
predictions = model.predict(test_images)
可以将数据打印出来,得到是一个张量的形式,每个向量中包含有 10 数据,代表是 0~9 某个数字的概率。结果如下
>>print(predictions)
[[2.53999460e-10 3.13443649e-09 1.13098464e-08 ... 1.00000000e+00
1.14483745e-09 3.00820311e-08]
[7.86611736e-08 3.69769464e-06 9.99996185e-01 ... 8.06958056e-09
2.84115362e-08 4.13955599e-13]
[1.14044463e-09 9.99811947e-01 4.80392437e-09 ... 1.12551425e-04
2.76754099e-06 5.21817753e-07]
...
[9.88247845e-16 1.55450704e-11 3.51570395e-16 ... 2.98323484e-11
4.88785012e-10 6.33079411e-09]
[9.11740905e-09 1.08507071e-10 6.55652290e-13 ... 3.31231287e-09
2.15885734e-06 1.69374251e-10]
[1.36937910e-08 5.68056935e-10 1.15511334e-09 ... 1.53420720e-13
2.79600870e-10 3.93418353e-11]]
>> import numpy as np
>> np.argmax(predictions[19])
4
上述测试了测试集 test_images 中第10个图像的数字是0,为了验证是不是准确的我们将 test_images 中
第10个图像打印出来,结果如下
>> tes = test_images[19]
>> plt.imshow(tes, cmap=plt.cm.binary)
>> plt.show()
结果显示我们预测的结果是准确的。
完整代码如下:
from keras.datasets import mnist
from keras import models
from keras import layers
from keras.utils import to_categorical
#定义网络模型
model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.Flatten())
model.add(layers.Dropout(0.5))
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(10, activation='softmax'))
#加载数据集
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
train_images = train_images.reshape((60000, 28, 28, 1))
train_images = train_images.astype('float32') / 255
test_images = test_images.reshape((10000, 28, 28, 1))
test_images = test_images.astype('float32') / 255
train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)
#准备验证集
#x_val = train_images[:20000]
#partial_x_train = train_images[20000:]
#y_val = train_labels[:20000]
#partial_y_train = train_labels[20000:]
#编译
model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy'])
history = model.fit(train_images, train_labels, epochs=5, batch_size=64)
#训练,拟合
#history = model.fit(partial_x_train, partial_y_train, epochs=5, batch_size=64, validation_data=(x_val, y_val))
test_loss, test_acc = network.evaluate(test_images, test_labels)