在深度学习方面,Keras提供了这样一个能够非常方便地搭建神经网络的工具,而且很容易快速上手。mnist手写数字识别是神经网络入门后的一个非常容易上手做的一个程序,尤其是在使用了深度学习框架后,不论是DNN还是CNN,都很简单。这篇文章里,我将介绍一下,使用keras实现mnist手写数字识别的程序。通过这篇文章,你应该就能够学会如何通过keras搭建自己的神经网络了。
整个程序的代码思路来源于GitHub 上别人的一个小项目:
https://gist.github.com/alexcpn/0683bb940cae510cf84d5976c1652abd
首先我们需要导入一些python库
1.numpy
import numpy as np
这是python中用于数值计算的库,很多用python做数学建模的应该都不会没有听说过这个库,可以进行矩阵运算以及高维的数组运算,用它来做,比用n个for循环的效率不知道高到哪里去了。
然后我们需要设置一下随机数种子
np.random.seed(123)
2.keras
# 从keras模型里面导入序贯模型 from keras.models import Sequential # 从keras封装好的层里面导入dense全连接层、Dropout正则化层、Activation激活层和Flatten扁平化层 from keras.layers import Dense, Dropout, Activation, Flatten # 从keras封装好的层里面导入二维卷积层和二维最大池化层 from keras.layers import Convolution2D, MaxPooling2D from keras.utils import np_utils from keras.datasets import mnist
每一行代码的用途我已经写在了注释里面,其中np_utils在后面会用它将不同类别的标签稀疏正交化
3.导入数据
我们可以看到,原作者是通过keras内置的数据集来训练的,但是因为那个数据集存放在亚马逊云服务器上,在中国大陆我们没办法下载下来,会提示下载失败。我这里有一份下载好的数据集:
然后通过numpy读入数据:
def load_data(path='mnist.npz'): f = np.load(path) x_train, y_train = f['x_train'], f['y_train'] x_test, y_test = f['x_test'], f['y_test'] f.close() return (x_train, y_train), (x_test, y_test) # 将数据读入 (X_train, y_train), (X_test, y_test) = load_data()
我们可以查看一下数据的格式,输入输出维度
print(X_train.shape,y_train.shape,X_test.shape,y_test.shape)
4.数据可视化
有时候,为了方便,或者更直观,我们往往需要将数据可视化。对于图像数据来说,可视化就是家常便饭了,而且也是最容易可视化的一类数据之一。这里我们需要用到一个强大的绘图库matplotlib,同样,做过数学建模以及仿真的应该都用过这类库,尤其是用过matlab的话。
import matplotlib.pyplot as plt # plot 4 images as gray scale plt.subplot(221) print(y_train[4545],y_train[1],y_train[2],y_train[3]) plt.imshow(X_train[4545], 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()
然后我们就可以看到许多手写的数字图片了。
5.数据预处理
往往我们拿到的数据,都需要进行一些处理,在不同的场景下,有不同的处理方法。这里的mnist数据集是已经处理过的,我们只需要将其转为我们所需的输入格式即可。
X_train = X_train.reshape(X_train.shape[0], 1, 28, 28) X_test = X_test.reshape(X_test.shape[0], 1, 28, 28)
6.转换数据类型并且规范化
X_train = X_train.astype('float32') X_test = X_test.astype('float32') X_train /= 255 X_test /= 255
7.将标签稀疏正交化
Y_train = np_utils.to_categorical(y_train, 10) Y_test = np_utils.to_categorical(y_test, 10)
8.建立神经网络模型
# 序贯模型 model = Sequential() # 添加二维卷积层,卷积核32,尺寸3X3,使用relu作为激活函数 model.add(Convolution2D(32,(3,3),activation='relu',data_format='channels_first',input_shape=(1,28,28))) model.add(Convolution2D(32, 3, 3, activation='relu')) # 最大池化层,尺寸是2X2 model.add(MaxPooling2D(pool_size=(2,2))) # 正则化层,训练时随机中断一定比例的神经网络的连接,防止过拟合 model.add(Dropout(0.25)) # 扁平化,将二维数据压缩到一维平面 model.add(Flatten()) # 全连接层 model.add(Dense(128, activation='relu')) model.add(Dropout(0.5)) # 输出层,使用softmax作为激活函数实现分类 model.add(Dense(10, activation='softmax'))# output 10 classes corresponds to 0 to 9 digits we need to find # 编译模型,损失函数使用多类别的交叉熵,优化器是adam,并且添加一个accuracy的评价指标 model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
9.训练模型
终于到了最激动人心的时刻,我想,没有什么比看到自己搭建的神经网络能够训练并且逐渐取得越来越高的准确率更让人激动了。这时候,我们只需等待就可以了。2个epoch正确率差不多能够达到96%以上,如果想要更高,可以设为10个epoch。
# 这里的batch大小是32,迭代2个epoch model.fit(X_train, Y_train,batch_size=32, nb_epoch=2, verbose=1)
10.训练完成,评估模型
训练完成后,我们需要保存一下训练好的权重,以方便以后使用,到时候使用load_weights即可。还要测试一下准确率,想一下如果准确率低了会是什么问题导致的,是过拟合了还是欠拟合了等。
# 保存权重 model.save_weights('mn.model') # 评估模型 score = model.evaluate(X_test, Y_test, verbose=0) print(score) # 在具体的一个数据上看看是不是对的 k = np.array(X_train[4545]) #seven print(k.shape) y= k.reshape(1,1,28,28) print(y.shape) prediction = model.predict(y) print(prediction) class_pred = model.predict_classes(y) print(class_pred) plt.subplot(111) plt.imshow(X_train[4545][0], cmap=plt.get_cmap('gray')) plt.show()
如果没问题,就会看到分类是正确的。
在这篇文章里,我并没有过多去讲述什么是全连接层,什么是卷积层以及什么是最大池化层以及如何调参等,本文只是为了给新手入门。关于这些,是需要很多知识和经验的,我相信有更多更好的文章,谷歌一下百度一下就都不少,相信你可以学会的。
版权声明本博客的文章除特别说明外均为原创,本人版权所有。欢迎转载,转载请注明作者及来源链接,谢谢。本文地址: https://blog.ailemon.net/2018/05/11/deep-learning-mnist-handwritten-digit-recognition-by-keras/ All articles are under Attribution-NonCommercial-ShareAlike 4.0 |