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模型來進行實現,省略了很多模型的內部實現。