基於TensorFlow實現MNIST手寫體數字識別

1. 背景描述

1.1 數據源介紹

數據源說明:60000訓練集 + 10000測試集
圖中的每個數字都是[28,28]的二階數組表示,每個位點上的值是顏色的深度[0-255] ~ [白色-黑色]。根據規範化處理,我們後面會將灰度值縮放到[0,1]。
在這裏插入圖片描述
使用程序獲取數據

from keras.datasets import mnist
# 注意keras的默認路徑是~/.keras/datasets,下面的數據會自動從S3上下載到~/.keras/datasets/mnist/mnist.npz路徑下進行加載
(x_train, y_train), (x_test, y_test) = mnist.load_data(path='mnist/mnist.npz')
import matplotlib.pyplot as plt

fig = plt.figure()
for i in range(0,15,1):
    plt.subplot(3,6,i+1) # 繪製前15個手寫體數字,以3行6列子圖形式展示
    plt.tight_layout() # 自動適配
    plt.imshow(x_train[i], cmap='Greys') # 使用灰色顯示像素灰度值
    plt.title("Label: {}".format(y_train[i])) # 設置標籤爲子圖標題

在這裏插入圖片描述
數據源地址:http://yann.lecun.com/exdb/mnist/index.html,這裏有詳細介紹。

1.2 實驗目標

很簡單,看上面的圖每張圖上有一個label,一起來玩猜label啊。

2. 算法原理

2.1 感知機

找個最簡單的例子來理解下感知機。兩個輸入,一個規則,實現邏輯與、邏輯或。可以看到適合做二分類
在這裏插入圖片描述

2.2 前向傳播

不說過於複雜的原理了,能把人給繞暈,直接看下面的這個簡單的3層網絡吧。計算第二層的輸出值。這裏不過多贅述,這個到處都能找到。
在這裏插入圖片描述
上面的計算可以歸結爲下面的公式。
在這裏插入圖片描述
在這裏插入圖片描述

2.3 後向傳播

BP算法的基本思想是通過損失函數對模型參數進行求導。這裏我就不羅列公式了,網上很多。

2.4 激勵函數

現在用的比較多的是Sigmoid和ReLU
在這裏插入圖片描述

3. 基於TensorFlow的算法實現

接下來我們來到核心就是使用TensorFlow進行實現了。

3.1 模型定義

我們定義如下的模型,輸入–> 隱含層1:512個節點 --> 隱含層2:512個節點 --> 輸出10個數的概率,選擇概率最大的那個。
在這裏插入圖片描述

3.2 可視化輸入

一樣的配方,還是先看下輸入分佈,比較有安全感,哈哈~~

from keras.datasets import mnist
import numpy as np
import matplotlib.pyplot as plt

# 導入數據
(x_train, y_train), (x_test, y_test) = mnist.load_data('mnist/mnist.npz')
# 將圖像本身從[28,28]轉換爲[784,]
X_train = x_train.reshape(60000, 784)
X_test = x_test.reshape(10000, 784)
# 將數據類型轉換爲float32
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')
# 數據歸一化
X_train /= 255
X_test /= 255
# 統計測試數據中每個數字的分佈
label, count = np.unique(y_train, return_counts=True)
print(label, count)
## 輸出: [0 1 2 3 4 5 6 7 8 9] [5923 6742 5958 6131 5842 5421 5918 6265 5851 5949]

看上面的輸出結果展示不是很友好,我們使用下面的圖來展示
在這裏插入圖片描述

3.3 數據編碼

這裏我們有9個數字,需要一種規則來進行數字編碼。編碼後佔用空間比較小。常見的三種編碼方式,如下圖,我們這裏的9個數字是完全獨立的,正好可以用one_hot的這種編碼;在有相關性的場景下,可能這種就不合適了。前面的兩種其實是有一種距離的概念,001-010和001-110的距離可能是不一樣的,編碼對於模型的訓練結果是很大的影響的。

Binary Gray code One-hot
000 000 00000001
001 001 00000010
010 011 00000100
011 010 00001000
100 110 00010000
101 111 00100000
110 101 01000000
111 100 10000000

實現起來比較簡單,因爲Keras已經提供了這種方法

from keras.utils import np_utils
n_classes = 10
Y_train = np_utils.to_categorical(y_train, n_classes)
Y_test = np_utils.to_categorical(y_test, n_classes)
print(Y_train[0],Y_train[0])

3.4 使用Keras實現模型

from keras.models import Sequential
from keras.layers.core import Dense, Activation

# 創建模型
model = Sequential()
model.add(Dense(512, input_shape=(784,)))
model.add(Activation('relu'))                            

model.add(Dense(512))
model.add(Activation('relu'))

model.add(Dense(10))
model.add(Activation('softmax'))

# 編譯模型
model.compile(loss='categorical_crossentropy', metrics=['accuracy'], optimizer='adam')

# 模型訓練
history = model.fit(X_train,
                    Y_train,
                    batch_size=128,
                    epochs=5,
                    verbose=2,
                    validation_data=(X_test, Y_test))

訓練完成後對模型進行可視化,可以看見test數據集合的準確率一開始就比較高,因爲用的是第一次已經訓練好的模型進行的測試。
在這裏插入圖片描述

4. TODO

1、對於真是的項目而言,數據肯定不可能這樣的乾淨,還有很多數據預處理的工作需要做。
2、這裏直接採用的高層的keras模型來進行實現,省略了很多模型的內部實現。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章