【声明】本文是 blog 的翻译和个人的学习笔记
近些年由于理论知识的硬件的快速发展,使得深度学习达到了空前的火热。深度学习已经在很多方面都成功得到了应用,尤其是在图像识别和分类领域,机器识别图像的能力甚至超过了人类。
本文用深度学习 Python 库 keras 实现深度学习入门教程 mnist 手写数字识别。mnist 手写数字识别是机器学习和深度学习领域的 "hello world",MNIST 数据集是手写数字的数据集合,训练集规模为 60000,测试集为 10000。
本文的内容包括:
MNIST 问题是由 Yann LeCun, Corinna Cortes 和 Christopher Burges 为了评估机器学习模型而设立的。问题的数据集是从一些 National Institute of Standards and Technology (NIST) 的文档中得来,是计算机视觉入门级的数据集,它包含各种手写数字图片:
它也包含每一张图片对应的标签,告诉我们这个是数字几。比如,上面这四张图片的标签分别是 5,0,4,1。
每张图片是 28*28 像素(共 784 个像素)。对于一般的图片像素通道通常是 3 维,即 rgb, 代表 red、green、blue 三个颜色通道,而 MNIST 数据集的像素通道只有一位即为灰度值,每一个像素值在 0 到 1 之间表示这个像素的灰度,0 表示白色,1 表示黑色。图片的类别标签是这个图片的数字,取值范围为 0-9. 因此 MNIST 问题是一个多分类的问题,类别为 10。
现在好的分类结果可是使错误率降到 1% 以下。接近最好效果的错误率大约为 0.2%,可用大规模的 CNN 实现。
Keras 提供了实现深度学习所需要的绝大部分函数库,可实现多种神经网络模型,并可加载多种数据集来评价模型的效果。下面的代码会自动加载数据,如果是第一次调用,数据会保存在你的 hone 目录下~/.keras/datasets/mnist.pkl.gz,大约 15MB。
- # Plot ad hoc mnist instances
- from keras.datasets import mnist
- import matplotlib.pyplot as plt
- # load (downloaded if needed) the MNIST dataset
- (X_train, y_train), (X_test, y_test) = mnist.load_data()
- # plot 4 images as gray scale
- plt.subplot(221)
- plt.imshow(X_train[0], cmap=plt.get_cmap('gray'))
- plt.subplot(222)
- plt.imshow(X_train[1], cmap=plt.get_cmap('gray'))
- plt.subplot(223)
- plt.imshow(X_train[2], cmap=plt.get_cmap('gray'))
- plt.subplot(224)
- plt.imshow(X_train[3], cmap=plt.get_cmap('gray'))
- # show the plot
- plt.show()
上面的代码加载了数据集并画出了前 4 个图片:
在实现卷积神经网络这种复杂的模型之前,先实现一个简单但效果也不错的模型:多层感知机。这种模型也叫含隐层的神经网络。模型的效果可以使错误率达到 1.87%。
第一步是加载所需要的库
- import numpy
- from keras.datasets import mnist
- from keras.models import Sequential
- from keras.layers import Dense
- from keras.layers import Dropout
- from keras.utils import np_utils
设定随机数种子,保证结果的可重现性
- seed = 7
- numpy.random.seed(seed)
加载数据
- (X_train, y_train),
- (X_test, y_test) = mnist.load_data()
数据集是 3 维的向量(instance length,width,height). 对于多层感知机,模型的输入是二维的向量,因此这里需要将数据集 reshape,即将 28*28 的向量转成 784 长度的数组。可以用 numpy 的 reshape 函数轻松实现这个过程。
- num_pixels = X_train.shape[1] * X_train.shape[2]
- X_train = X_train.reshape(X_train.shape[0], num_pixels).astype('float32')
- X_test = X_test.reshape(X_test.shape[0], num_pixels).astype('float32')
给定的像素的灰度值在 0-255,为了使模型的训练效果更好,通常将数值归一化映射到 0-1。
- X_train = X_train / 255
- X_test = X_test / 255
最后,模型的输出是对每个类别的打分预测,对于分类结果从 0-9 的每个类别都有一个预测分值,表示将模型输入预测为该类的概率大小,概率越大可信度越高。由于原始的数据标签是 0-9 的整数值,通常将其表示成 0ne-hot 向量。如第一个训练数据的标签为 5,one-hot 表示为 [0,0,0,0,0,1,0,0,0,0]。
- y_train = np_utils.to_categorical(y_train)
- y_test = np_utils.to_categorical(y_test)
- num_classes = y_test.shape[1]
现在需要做得就是搭建神经网络模型了,创建一个函数,建立含有一个隐层的神经网络。
- # define baseline model
- def baseline_model():
- # create model
- model = Sequential()
- model.add(Dense(num_pixels, input_dim=num_pixels, kernel_initializer='normal', activation='relu'))
- model.add(Dense(num_classes, kernel_initializer='normal', activation='softmax'))
- # Compile model
- model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
- return model
模型的隐含层含有 784 个节点,接受的输入长度也是 784(28*28),最后用 softmax 函数将预测结果转换为标签的概率值。
将训练数据 fit 到模型,设置了迭代轮数,每轮 200 个训练样本,将测试集作为验证集,并查看训练的效果。
- # build the model
- model = baseline_model()
- # Fit the model
- model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=10, batch_size=200, verbose=2)
- # Final evaluation of the model
- scores = model.evaluate(X_test, y_test, verbose=0)
- print("Baseline Error: %.2f%%" % (100-scores[1]*100))
训练和测试结果如下:
Train on 60000 samples, validate on 10000 samples
Epoch 1/10
6s - loss: 0.2789 - acc: 0.9210 - val_loss: 0.1416 - val_acc: 0.9578
Epoch 2/10
5s - loss: 0.1117 - acc: 0.9677 - val_loss: 0.0917 - val_acc: 0.9707
Epoch 3/10
5s - loss: 0.0717 - acc: 0.9796 - val_loss: 0.0787 - val_acc: 0.9767
Epoch 4/10
6s - loss: 0.0502 - acc: 0.9859 - val_loss: 0.0741 - val_acc: 0.9767
Epoch 5/10
5s - loss: 0.0372 - acc: 0.9890 - val_loss: 0.0681 - val_acc: 0.9788
Epoch 6/10
5s - loss: 0.0269 - acc: 0.9925 - val_loss: 0.0625 - val_acc: 0.9808
Epoch 7/10
5s - loss: 0.0208 - acc: 0.9948 - val_loss: 0.0619 - val_acc: 0.9814
Epoch 8/10
6s - loss: 0.0140 - acc: 0.9970 - val_loss: 0.0639 - val_acc: 0.9799
Epoch 9/10
5s - loss: 0.0108 - acc: 0.9978 - val_loss: 0.0597 - val_acc: 0.9812
Epoch 10/10
5s - loss: 0.0080 - acc: 0.9985 - val_loss: 0.0591 - val_acc: 0.9813
Baseline Error: 1.87%
前面介绍了如何加载训练数据并实现一个简单的单隐层神经网络,并在测试集上取得了不错的效果。现在要实现一个卷积神经网络,想要在 MNIST 问题上取得更好的效果。
卷积神经网络(CNN)是一种深度神经网络,与单隐层的神经网络不同的是它还包含卷积层、池化层、Dropout 层等,这使得它在图像分类的问题上有更优的效果。详细的 CNN 教程可以参见斯坦福大学的 cs231n 课程讲义,中文版链接
第一步依然是导入需要的函数库
- import numpy
- from keras.datasets import mnist
- from keras.models import Sequential
- from keras.layers import Dense
- from keras.layers import Dropout
- from keras.layers import Flatten
- from keras.layers.convolutional import Conv2D
- from keras.layers.convolutional import MaxPooling2D
- from keras.utils import np_utils
- from keras import backend as K
- K.set_image_dim_ordering('th')
设定随机数种子
- seed = 7
- numpy.random.seed(seed)
将数据集 reshape,CNN 的输入是 4 维的张量(可看做多维的向量),第一维是样本规模,第二维是像素通道,第三维和第四维是长度和宽度。并将数值归一化和类别标签向量化。
- # load data
- (X_train, y_train), (X_test, y_test) = mnist.load_data()
- # reshape to be [samples][pixels][width][height]
- X_train = X_train.reshape(X_train.shape[0], 1, 28, 28).astype('float32')
- X_test = X_test.reshape(X_test.shape[0], 1, 28, 28).astype('float32')
- X_train = X_train / 255
- X_test = X_test / 255
- # one hot encode outputs
- y_train = np_utils.to_categorical(y_train)
- y_test = np_utils.to_categorical(y_test)
- num_classes = y_test.shape[1]
接下来构造 CNN。
- def baseline_model():
- # create model
- model = Sequential()
- model.add(Conv2D(32, (5, 5), input_shape=(1, 28, 28), activation='relu'))
- model.add(MaxPooling2D(pool_size=(2, 2)))
- model.add(Dropout(0.2))
- model.add(Flatten())
- model.add(Dense(128, activation='relu'))
- model.add(Dense(num_classes, activation='softmax'))
- # Compile model
- model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
- return model
接着开始训练模型
- # build the model
- model = baseline_model()
- # Fit the model
- model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=10, batch_size=200, verbose=2)
- # Final evaluation of the model
- scores = model.evaluate(X_test, y_test, verbose=0)
- print("Baseline Error: %.2f%%" % (100-scores[1]*100))
训练和测试结果如下:
Train on 60000 samples, validate on 10000 samples
Epoch 1/10
137s - loss: 0.2329 - acc: 0.9340 - val_loss: 0.0820 - val_acc: 0.9742
Epoch 2/10
140s - loss: 0.0736 - acc: 0.9781 - val_loss: 0.0466 - val_acc: 0.9842
Epoch 3/10
138s - loss: 0.0531 - acc: 0.9839 - val_loss: 0.0432 - val_acc: 0.9860
Epoch 4/10
145s - loss: 0.0404 - acc: 0.9876 - val_loss: 0.0389 - val_acc: 0.9872
Epoch 5/10
135s - loss: 0.0335 - acc: 0.9893 - val_loss: 0.0341 - val_acc: 0.9886
Epoch 6/10
133s - loss: 0.0275 - acc: 0.9915 - val_loss: 0.0308 - val_acc: 0.9893
Epoch 7/10
133s - loss: 0.0233 - acc: 0.9926 - val_loss: 0.0363 - val_acc: 0.9880
Epoch 8/10
137s - loss: 0.0204 - acc: 0.9937 - val_loss: 0.0320 - val_acc: 0.9889
Epoch 9/10
139s - loss: 0.0167 - acc: 0.9945 - val_loss: 0.0294 - val_acc: 0.9893
Epoch 10/10
139s - loss: 0.0143 - acc: 0.9957 - val_loss: 0.0310 - val_acc: 0.9907
Baseline Error: 0.93%
可以看出相对于单隐层神经网络,CNN 的效果有很大提升,error rate 从 1.87% 降到了 0.93%。
上面实现了一个只含有一层卷积层和 pooling 层的 CNN,为了实现更好的分类效果,可以添加多层的 Convolution2D 和 MaxPooling2D,CNN 会自动提取特征,学习到更好的分类效果。
来源: http://blog.csdn.net/sunyangwei1993/article/details/73998297