1. 程式人生 > >keras實現mnist資料集手寫數字識別

keras實現mnist資料集手寫數字識別

經過幾天的爬坑,“東搞西搞”終於把深度學習的“HELLO,WORLD”做出來了,以下是自己的實戰過程:

關於keras識別手寫數字的入門準備:

2.Mnist資料集的準備

3.匯入資料集測試

4.實現baseline模型:

5.實現簡單的卷積神經網路

一. Tensorflow環境的安裝

這裡我們只講CPU版本,使用 Anaconda 進行安裝

a.首先我們要安裝 Anaconda

連結:https://pan.baidu.com/s/1AxdGi93oN9kXCLdyxOMnRA 密碼:79ig

過程如下:

第一步:點選next

第二步:I Agree

第三步:Just ME

第四步:自己選擇一個恰當位置放它就好

第五步:建議只選擇第二個

第六步:就直接install啦啦啦啦,然後你就可以上手萬能庫了

b.找到Anaconda prompt,然後

以管理員的身份開啟終端

c.按照以下步驟在 Anaconda 環境中安裝 TensorFlow:

  1. 通過呼叫以下命令建立名為 tensorflow 的 conda 環境:

C:> conda create -n tensorflow pip python=3.5

  1. 通過發出以下命令啟用 conda 環境:

C:> activate tensorflow (tensorflow)C:> # Your prompt should change

  1. 發出相應命令以在 conda 環境中安裝 TensorFlow。要安裝僅支援 CPU 的 TensorFlow 版本,請輸入以下命令:

(tensorflow)C:> pip install --ignore-installed --upgrade tensorflow

d.測試tensorflow的安裝

啟動Anaconda prompt(同樣是以管理員身份開啟)終端。

如果您是通過 Anaconda 進行安裝,請啟用您的 Anaconda 環境。

終端輸入 activate tensorflow即可

然後再輸入python

如:

在 Python 互動式 shell 中輸入以下幾行簡短的程式程式碼:

>>> import tensorflow as tf

>>> hello = tf.constant('Hello, TensorFlow!')

>>> sess = tf.Session()

>>> print(sess.run(hello))

如果系統輸出以下內容,說明您可以開始編寫 TensorFlow 程式了:

Hello, TensorFlow!

完成以上步驟,你就把tensorflow搭建好了......

二.安裝keras

a.首先,擔心我們anaconda裡面各個包未更新到最新,所以我們以管理員的身份開啟Anaconda終端,輸入 conda update conda,執行完後,再輸入:conda update --all

b.然後我們啟用我們的tensorflow環境:activate tensorflow

c.然後我們就可以輸入:pip install keras

三.完成上述步驟,我們就可以來試下載入keras裡面的mnist資料集了

# 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個圖片: 
這裡寫圖片描述

好了接下來我們對上述程式碼進行進一步的解釋:

from keras.datasets import mnist 這裡是從keras的datasets中匯入mnist資料集
import matplotlib.pyplot as plt  這裡是將matplotlib.pyplot重名為plt
(X_train, y_train), (X_test, y_test) = mnist.load_data()#
所以這裡返回的是手寫圖片的兩個tuple,第一個tuple儲存的是我們已經人工分類好的圖片,也就是每一張圖片都有自己對應的標籤,然後可以拿來訓練,第二個tuple儲存的是我們還沒分類的圖片,在第一個tuple訓練完後,我們可以把第二個tuple利用神經網路進行分類,根據實驗結果的真實值與我們的預測值進行對比得到相應的損失值,再利用反向傳播進行引數更新,再進行分類,然後重複前述步驟直至損失值最小
# plot 4 images as gray scale
plt.subplot(331)
這個subplot函式的作用是確定影象的位置以及影象的個數,前兩個3的意思是可以放9張圖片,如果變成221的話,就是可以放4張圖片,然後後面的1,是確定影象的位置,處於第一個,以下的subplot同理
plt.imshow(X_test[0], cmap=plt.get_cmap('gray'))
這裡個把圖片顯示出來
X_train儲存的是影象的畫素點組成的list資料型別,這裡面又由一個二維的list(28 x 28的畫素點值)和一個對應的標籤list組成,y_train儲存的是對應影象的標籤,也就是該影象代表什麼數字
plt.subplot(332)
plt.imshow(X_train[1], cmap=plt.get_cmap('gray'))
plt.subplot(333)
plt.imshow(X_train[2], cmap=plt.get_cmap('gray'))
plt.subplot(334)
plt.imshow(X_train[3], cmap=plt.get_cmap('gray'))
plt.subplot(335)
plt.imshow(X_train[4], cmap=plt.get_cmap('gray'))
plt.subplot(336)
plt.imshow(X_train[5], cmap=plt.get_cmap('gray'))
plt.subplot(337)
plt.imshow(X_train[6], cmap=plt.get_cmap('gray'))
plt.subplot(338)
plt.imshow(X_train[7], cmap=plt.get_cmap('gray'))
plt.subplot(339)
plt.imshow(X_train[8], cmap=plt.get_cmap('gray'))
在這裡imshow函式的官方文件:https://matplotlib.org/api/_as_gen/matplotlib.pyplot.imshow.html#matplotlib.pyplot.imshow
我們這裡第一個引數是圖片的畫素點值組成的陣列(列表),第二個引數是指明圖片的色彩
# show the plot
plt.show()最後這裡官方文件是這樣說的:Display a figure. When running in ipython with its pylab mode, display all figures and return to the ipython prompt.,所以我們可以知道show函式是把所有圖片都展示出來。

上述程式碼展示的結果是:

多層感知機的baseline模型

在實現卷積神經網路這種複雜的模型之前,先實現一個簡單但效果也不錯的模型:多層感知機。這種模型也叫含隱層的神經網路。模型的效果可以使錯誤率達到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() #載入資料

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')
#資料集是3維的向量(instance length,width,height).對於多層感知機,模型的輸入是二維的向量,因此這
#裡需要將資料集reshape,即將28*28的向量轉成784長度的陣列。可以用numpy的reshape函式輕鬆實現這個過
#程。

#給定的畫素的灰度值在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。

  1. 第一層是卷積層。該層有32個feature map,或者叫濾波器,作為模型的輸入層,接受[pixels][width][height]大小的輸入資料。feature map的大小是5*5,其輸出接一個‘relu’啟用函式。
  2. 下一層是pooling層,使用了MaxPooling,大小為2*2。
  3. 下一層是Dropout層,該層的作用相當於對引數進行正則化來防止模型過擬合。
  4. 接下來是全連線層,有128個神經元,啟用函式採用‘relu’。
  5. 最後一層是輸出層,有10個神經元,每個神經元對應一個類別,輸出值表示樣本屬於該類別的概率大小。
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會自動提取特徵,學習到更好的分類效果。