keras 手把手入门#1-MNIST手写数字识别 深度学习实战闪电入门

本文属转载,仅用作个人学习。

人们已经教会计算机自动找出那些重要的特征和属性, 那么下一步我们改教会计算机什么? — David 9

用深度学习框架跑过实际问题的朋友一定有这样的感觉: 太神奇了, 它竟然能自己学习重要的特征 ! 下一步我们改教会计算机什么?莫非是教会他们寻找新的未知特征

对于卷积神经网络cnn, 其中每个卷积核就是一个cnn习得的特征, 详见David 9之前的关于cnn博客

今天我们的主角是keras,其简洁性和易用性简直出乎David 9我的预期。大家都知道keras是在TensorFlow上又包装了一层,向简洁易用的深度学习又迈出了坚实的一步。

所以,今天就来带大家写keras中的Hello World , 做一个手写数字识别的cnn。回顾cnn架构:

keras 手把手入门#1-MNIST手写数字识别 深度学习实战闪电入门

我们要处理的是这样的灰度像素图:

keras 手把手入门#1-MNIST手写数字识别 深度学习实战闪电入门

识别0-9的手写数字,60来行代码就能搞定,简单易懂,全程无尿点。我们先来看单机版跑完的结果

  1. (python3_env) [email protected]:~$ python keras_mnist_cnn.py
  2. Using TensorFlow backend.
  3. x_train shape: (60000, 28, 28, 1)
  4. 60000 train samples
  5. 10000 test samples
  6. Train on 60000 samples, validate on 10000 samples
  7. Epoch 1/12
  8. 60000/60000 [==============================] - 446s - loss: 0.3450 - acc: 0.8933 - val_loss: 0.0865 - val_acc: 0.9735
  9. Epoch 2/12
  10. 60000/60000 [==============================] - 415s - loss: 0.1246 - acc: 0.9627 - val_loss: 0.0565 - val_acc: 0.9819
  11. Epoch 3/12
  12. 60000/60000 [==============================] - 389s - loss: 0.0957 - acc: 0.9717 - val_loss: 0.0493 - val_acc: 0.9842
  13. Epoch 4/12
  14. 60000/60000 [==============================] - 385s - loss: 0.0805 - acc: 0.9761 - val_loss: 0.0413 - val_acc: 0.9865
  15. Epoch 5/12
  16. 60000/60000 [==============================] - 366s - loss: 0.0708 - acc: 0.9788 - val_loss: 0.0361 - val_acc: 0.9874
  17. Epoch 6/12
  18. 60000/60000 [==============================] - 368s - loss: 0.0619 - acc: 0.9824 - val_loss: 0.0355 - val_acc: 0.9875
  19. Epoch 7/12
  20. 60000/60000 [==============================] - 363s - loss: 0.0585 - acc: 0.9826 - val_loss: 0.0345 - val_acc: 0.9875
  21. Epoch 8/12
  22. 60000/60000 [==============================] - 502s - loss: 0.0527 - acc: 0.9837 - val_loss: 0.0339 - val_acc: 0.9883
  23. Epoch 9/12
  24. 60000/60000 [==============================] - 444s - loss: 0.0501 - acc: 0.9852 - val_loss: 0.0309 - val_acc: 0.9891
  25. Epoch 10/12
  26. 60000/60000 [==============================] - 358s - loss: 0.0472 - acc: 0.9861 - val_loss: 0.0308 - val_acc: 0.9897
  27. Epoch 11/12
  28. 60000/60000 [==============================] - 358s - loss: 0.0441 - acc: 0.9872 - val_loss: 0.0330 - val_acc: 0.9893
  29. Epoch 12/12
  30. 60000/60000 [==============================] - 381s - loss: 0.0431 - acc: 0.9871 - val_loss: 0.0304 - val_acc: 0.9901
  31. Test loss: 0.0303807387119
  32. Test accuracy: 0.9901

所以我们跑的是keras_mnist_cnn.py。最后达到99%的预测准确率。首先来解释一下输出:

测试样本格式是28*28像素的1通道,灰度图,数量为60000个样本。

测试集是10000个样本。

一次epoch是一次完整迭代(所有样本都训练过),这里我们用了12次迭代,最后一次迭代就可以收敛到99.01%预测准确率了。

loss是训练集损失值.  acc是训练集准确率。val_loss是测试集上的损失值,val_acc是测试集上的准确率。

接下来我们看代码:

  1. from __future__ import print_function
  2. import keras
  3. from keras.datasets import mnist
  4. from keras.models import Sequential
  5. from keras.layers import Dense, Dropout, Flatten
  6. from keras.layers import Conv2D, MaxPooling2D
  7. from keras import backend as K

一开始我们导入一些基本库,包括:

  • mnist数据源
  • Sequential类,可以封装各种神经网络层,包括Dense全连接层,Dropout层,Cov2D 卷积层,等等。
  • 我们都知道keras支持两个后端TensorFlow和Theano,可以在$HOME/.keras/keras.json中配置。

接下来,我们准备训练集和测试集,以及一些重要参数:

  1. # batch_size 太小会导致训练慢,过拟合等问题,太大会导致欠拟合。所以要适当选择
  2. batch_size = 128
  3. # 0-9手写数字一个有10个类别
  4. num_classes = 10
  5. # 12次完整迭代,差不多够了
  6. epochs = 12
  7. # 输入的图片是28*28像素的灰度图
  8. img_rows, img_cols = 28, 28
  9. # 训练集,测试集收集非常方便
  10. (x_train, y_train), (x_test, y_test) = mnist.load_data()
  11. # keras输入数据有两种格式,一种是通道数放在前面,一种是通道数放在后面,
  12. # 其实就是格式差别而已
  13. if K.image_data_format() == 'channels_first':
  14. x_train = x_train.reshape(x_train.shape[0], 1, img_rows, img_cols)
  15. x_test = x_test.reshape(x_test.shape[0], 1, img_rows, img_cols)
  16. input_shape = (1, img_rows, img_cols)
  17. else:
  18. x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)
  19. x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)
  20. input_shape = (img_rows, img_cols, 1)
  21. # 把数据变成float32更精确
  22. x_train = x_train.astype('float32')
  23. x_test = x_test.astype('float32')
  24. x_train /= 255
  25. x_test /= 255
  26. print('x_train shape:', x_train.shape)
  27. print(x_train.shape[0], 'train samples')
  28. print(x_test.shape[0], 'test samples')
  29. # 把类别0-9变成2进制,方便训练
  30. y_train = keras.utils.np_utils.to_categorical(y_train, num_classes)
  31. y_test = keras.utils.np_utils.to_categorical(y_test, num_classes)

然后,是令人兴奋而且简洁得令人吃鲸的训练构造cnn和训练过程:

  1. # 牛逼的Sequential类可以让我们灵活地插入不同的神经网络层
  2. model = Sequential()
  3. # 加上一个2D卷积层, 32个输出(也就是卷积通道),**函数选用relu,
  4. # 卷积核的窗口选用3*3像素窗口
  5. model.add(Conv2D(32,
  6. activation='relu',
  7. input_shape=input_shape,
  8. nb_row=3,
  9. nb_col=3))
  10. # 64个通道的卷积层
  11. model.add(Conv2D(64, activation='relu',
  12. nb_row=3,
  13. nb_col=3))
  14. # 池化层是2*2像素的
  15. model.add(MaxPooling2D(pool_size=(2, 2)))
  16. # 对于池化层的输出,采用0.35概率的Dropout
  17. model.add(Dropout(0.35))
  18. # 展平所有像素,比如[28*28] -> [784]
  19. model.add(Flatten())
  20. # 对所有像素使用全连接层,输出为128,**函数选用relu
  21. model.add(Dense(128, activation='relu'))
  22. # 对输入采用0.5概率的Dropout
  23. model.add(Dropout(0.5))
  24. # 对刚才Dropout的输出采用softmax**函数,得到最后结果0-9
  25. model.add(Dense(num_classes, activation='softmax'))
  26. # 模型我们使用交叉熵损失函数,最优化方法选用Adadelta
  27. model.compile(loss=keras.metrics.categorical_crossentropy,
  28. optimizer=keras.optimizers.Adadelta(),
  29. metrics=['accuracy'])
  30. # 令人兴奋的训练过程
  31. model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs,
  32. verbose=1, validation_data=(x_test, y_test))

完整地训练完毕之后,可以计算一下预测准确率:

  1. score = model.evaluate(x_test, y_test, verbose=0)
  2. print('Test loss:', score[0])
  3. print('Test accuracy:', score[1])

整个cnn的MNIST手写数字识别就训练完毕了,是不是非常简单,如果觉得注释还不够详尽,请自己试试源码感受下,或者看看我们文章的底部参考文献。

keras_mnist_cnn.py 完整源码:

  1. '''Trains a simple convnet on the MNIST dataset.
  2. Gets to 99.25% test accuracy after 12 epochs
  3. (there is still a lot of margin for parameter tuning).
  4. 16 seconds per epoch on a GRID K520 GPU.
  5. '''
  6. from __future__ import print_function
  7. import keras
  8. from keras.datasets import mnist
  9. from keras.models import Sequential
  10. from keras.layers import Dense, Dropout, Flatten
  11. from keras.layers import Conv2D, MaxPooling2D
  12. from keras import backend as K
  13. batch_size = 128
  14. num_classes = 10
  15. epochs = 12
  16. # input image dimensions
  17. img_rows, img_cols = 28, 28
  18. # the data, shuffled and split between train and test sets
  19. (x_train, y_train), (x_test, y_test) = mnist.load_data()
  20. if K.image_data_format() == 'channels_first':
  21. x_train = x_train.reshape(x_train.shape[0], 1, img_rows, img_cols)
  22. x_test = x_test.reshape(x_test.shape[0], 1, img_rows, img_cols)
  23. input_shape = (1, img_rows, img_cols)
  24. else:
  25. x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)
  26. x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)
  27. input_shape = (img_rows, img_cols, 1)
  28. x_train = x_train.astype('float32')
  29. x_test = x_test.astype('float32')
  30. x_train /= 255
  31. x_test /= 255
  32. print('x_train shape:', x_train.shape)
  33. print(x_train.shape[0], 'train samples')
  34. print(x_test.shape[0], 'test samples')
  35. # convert class vectors to binary class matrices
  36. y_train = keras.utils.np_utils.to_categorical(y_train, num_classes)
  37. y_test = keras.utils.np_utils.to_categorical(y_test, num_classes)
  38. model = Sequential()
  39. model.add(Conv2D(32,
  40. activation='relu',
  41. input_shape=input_shape,
  42. nb_row=3,
  43. nb_col=3))
  44. model.add(Conv2D(64, activation='relu',
  45. nb_row=3,
  46. nb_col=3))
  47. # model.add(MaxPooling2D(pool_size=(2, 2)))
  48. model.add(MaxPooling2D(pool_size=(2, 2)))
  49. model.add(Dropout(0.35))
  50. model.add(Flatten())
  51. model.add(Dense(128, activation='relu'))
  52. model.add(Dropout(0.5))
  53. model.add(Dense(num_classes, activation='softmax'))
  54. model.compile(loss=keras.metrics.categorical_crossentropy,
  55. optimizer=keras.optimizers.Adadelta(),
  56. metrics=['accuracy'])
  57. model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs,
  58. verbose=1, validation_data=(x_test, y_test))
  59. score = model.evaluate(x_test, y_test, verbose=0)
  60. print('Test loss:', score[0])
  61. print('Test accuracy:', score[1])

 

参考文献:

  1. https://github.com/fchollet/keras/tree/master/examples
  2. https://keras.io/backend/

本文章属于“David 9的博客”原创,如需转载,请联系微信: david9ml,或邮箱:[email protected]

或直接扫二维码:

keras 手把手入门#1-MNIST手写数字识别 深度学习实战闪电入门