今天我們的主角是keras,其簡潔性和易用性簡直出乎David 9我的預期。大家都知道keras是在TensorFlow上又包裝了一層,向簡潔易用的深度學習又邁出了堅實的一步。
所以,今天就來帶大家寫keras中的Hello World , 做一個手寫數字識別的cnn。回顧cnn架構:
我們要處理的是這樣的灰度像素圖:
我們先來看跑完的結果(在Google Colab上運行):
x_train shape: (60000, 28, 28, 1) 60000 train samples 10000 test samples Train on 60000 samples, validate on 10000 samples Epoch 1/12 60000/60000 [==============================] - 12s 193us/step - loss: 0.2672 - acc: 0.9166 - val_loss: 0.0648 - val_acc: 0.9792 Epoch 2/12 60000/60000 [==============================] - 9s 146us/step - loss: 0.0892 - acc: 0.9731 - val_loss: 0.0433 - val_acc: 0.9866 Epoch 3/12 60000/60000 [==============================] - 9s 146us/step - loss: 0.0666 - acc: 0.9796 - val_loss: 0.0353 - val_acc: 0.9874 Epoch 4/12 60000/60000 [==============================] - 9s 146us/step - loss: 0.0578 - acc: 0.9829 - val_loss: 0.0327 - val_acc: 0.9887 Epoch 5/12 60000/60000 [==============================] - 9s 146us/step - loss: 0.0483 - acc: 0.9856 - val_loss: 0.0295 - val_acc: 0.9901 Epoch 6/12 60000/60000 [==============================] - 9s 146us/step - loss: 0.0433 - acc: 0.9869 - val_loss: 0.0313 - val_acc: 0.9895 Epoch 7/12 60000/60000 [==============================] - 9s 146us/step - loss: 0.0379 - acc: 0.9879 - val_loss: 0.0267 - val_acc: 0.9913 Epoch 8/12 60000/60000 [==============================] - 9s 147us/step - loss: 0.0353 - acc: 0.9891 - val_loss: 0.0263 - val_acc: 0.9913 Epoch 9/12 60000/60000 [==============================] - 9s 146us/step - loss: 0.0327 - acc: 0.9904 - val_loss: 0.0275 - val_acc: 0.9905 Epoch 10/12 60000/60000 [==============================] - 9s 146us/step - loss: 0.0323 - acc: 0.9898 - val_loss: 0.0260 - val_acc: 0.9914 Epoch 11/12 60000/60000 [==============================] - 9s 147us/step - loss: 0.0286 - acc: 0.9913 - val_loss: 0.0283 - val_acc: 0.9909 Epoch 12/12 60000/60000 [==============================] - 9s 147us/step - loss: 0.0267 - acc: 0.9922 - val_loss: 0.0268 - val_acc: 0.9906 Test loss: 0.026836299882206368 Test accuracy: 0.9906
所以我們跑的是keras_mnist_cnn.py。最后達到99%的預測准確率。首先來解釋一下輸出:
測試樣本格式是28*28像素的1通道,灰度圖,數量為60000個樣本。
測試集是10000個樣本。
一次epoch是一次完整迭代(所有樣本都訓練過),這里我們用了12次迭代,最后一次迭代就可以收斂到99.06%預測准確率了。
接下來我們看代碼:
from __future__ import print_function import keras from keras.datasets import mnist from keras.models import Sequential from keras.layers import Dense, Dropout, Flatten from keras.layers import Conv2D, MaxPooling2D from keras import backend as K
一開始我們導入一些基本庫,包括:
- minst數據集
- Sequential類,可以封裝各種神經網絡層,包括Dense全連接層,Dropout層,Cov2D卷積層,等等
- 我們都直到Keras支持兩個后端TensorFlow和Theano,可以在
$HOME/.keras/keras.json
中配置
接下來,我們准備訓練集和測試集,以及一些重要參數:
# batch_size 太小會導致訓練慢,過擬合等問題,太大會導致欠擬合。所以要適當選擇 batch_size = 128 # 0-9手寫數字一個有10個類別 num_classes = 10 # 12次完整迭代,差不多夠了 epochs = 12 # 輸入的圖片是28*28像素的灰度圖 img_rows, img_cols = 28, 28 # 訓練集,測試集收集非常方便 (x_train, y_train), (x_test, y_test) = mnist.load_data() # keras輸入數據有兩種格式,一種是通道數放在前面,一種是通道數放在后面, # 其實就是格式差別而已 if K.image_data_format() == 'channels_first': x_train = x_train.reshape(x_train.shape[0], 1, img_rows, img_cols) x_test = x_test.reshape(x_test.shape[0], 1, img_rows, img_cols) input_shape = (1, img_rows, img_cols) else: x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1) x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1) input_shape = (img_rows, img_cols, 1) # 把數據變成float32更精確 x_train = x_train.astype('float32') x_test = x_test.astype('float32') x_train /= 255 x_test /= 255 print('x_train shape:', x_train.shape) print(x_train.shape[0], 'train samples') print(x_test.shape[0], 'test samples') # 把類別0-9變成獨熱碼 y_train = keras.utils.np_utils.to_categorical(y_train, num_classes) y_test = keras.utils.np_utils.to_categorical(y_test, num_classes)
然后,是令人興奮而且簡潔得令人吃鯨的訓練構造cnn和訓練過程:
# 牛逼的Sequential類可以讓我們靈活地插入不同的神經網絡層 model = Sequential() # 加上一個2D卷積層, 32個輸出(也就是卷積通道),激活函數選用relu, # 卷積核的窗口選用3*3像素窗口 model.add(Conv2D(32, activation='relu', input_shape=input_shape, nb_row=3, nb_col=3)) # 64個通道的卷積層 model.add(Conv2D(64, activation='relu', nb_row=3, nb_col=3)) # 池化層是2*2像素的 model.add(MaxPooling2D(pool_size=(2, 2))) # 對於池化層的輸出,采用0.35概率的Dropout model.add(Dropout(0.35)) # 展平所有像素,比如[28*28] -> [784] model.add(Flatten()) # 對所有像素使用全連接層,輸出為128,激活函數選用relu model.add(Dense(128, activation='relu')) # 對輸入采用0.5概率的Dropout model.add(Dropout(0.5)) # 對剛才Dropout的輸出采用softmax激活函數,得到最后結果0-9 model.add(Dense(num_classes, activation='softmax')) # 模型我們使用交叉熵損失函數,最優化方法選用Adadelta model.compile(loss=keras.metrics.categorical_crossentropy, optimizer=keras.optimizers.Adadelta(), metrics=['accuracy']) # 令人興奮的訓練過程 model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, verbose=1, validation_data=(x_test, y_test))
完整地訓練完畢之后,可以計算一下預測准確率:
score = model.evaluate(x_test, y_test, verbose=0) print('Test loss:', score[0]) print('Test accuracy:', score[1])