下載數據集
mnist數據集是一個公共的手寫數字數據集,一共有7W張28*28像素點的0-9手寫數字圖片和標簽,其中有6W張是訓練集,1W張是測試集。
from tensorflow import keras from matplotlib import pyplot as plt mnist = tf.keras.datasets.mnist (x_train, y_train), (x_test, y_test) = mnist.load_data()
其中,x_train為訓練集特征,y_train為訓練集標簽,x_test為測試集特征,y_test為測試集標簽。
數據歸一化
使本來是0-255之間的灰度值,變為0-1之間的數值,從而讓梯度變得平緩,更容易收斂找到最優解。
x_train, x_test = x_train / 255.0, x_test / 255.0
獨熱碼
y_train = keras.utils.to_categorical(y_train, 10)
y_test = keras.utils.to_categorical(y_test, 10)
進行獨熱編碼后,每個分類對應一個狀態碼,1為是,0為否。 如某張圖片標簽是6,則獨熱碼為:0 0 0 0 0 0 1 0 0 0
驗證集
從訓練集中拿出5000個樣本來作為驗證集,驗證集用於參與訓練更新梯度。
x_validation = x_train[:5000] y_validation = y_train[:5000] x_train = x_train[5000:] y_train = y_train[5000:]
搭建網絡結構
訓練之前,要將數據拉直成一維數組,把784個像素點的灰度值作為輸入特征喂入神經網絡。
第一層網絡定義128個神經元,選擇最常用的修正線性單元relu激活函數。
第二層網絡定義10個神經元,使用softmax激活函數使輸出符合概率分布。
model = keras.models.Sequential([ keras.layers.Flatten(), keras.layers.Dense(128, activation='relu'), keras.layers.Dense(10, activation='softmax') ])
編譯模型
使用多分類類別交叉熵損失函數
model.compile(loss='categorical_crossentropy', metrics=['accuracy'])
保存模型
訓練之后的模型需要保存,以便應用程序識別時調用模型。
checkpoint_save_path = "./checkpoint/mnist.ckpt" cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_save_path,save_weights_only=True, save_best_only=True)
執行訓練
數據集按32個為一批喂入神經網絡,總共迭代7次,每迭代一次測試一次准確率。
history = model.fit(x_train, y_train, batch_size=32, epochs=7, verbose=1, validation_data=(x_validation,y_validation),validation_freq=1,callbacks=[cp_callback])
評估模型
score = model.evaluate(x_test, y_test, verbose=0, batch_size=32) print('測試准確率:{}, 測試loss值: {}'.format(score[1], score[0]))
可視化acc和loss曲線
plt.rcParams['font.sans-serif']=['SimHei'] acc = history.history['accuracy'] val_acc = history.history['val_accuracy'] loss = history.history['loss'] val_loss = history.history['val_loss'] plt.subplot(1, 2, 1) plt.plot(acc, label='訓練Acc') plt.plot(val_acc, label='測試Acc') plt.title('Acc曲線') plt.legend() plt.subplot(1, 2, 2) plt.plot(loss, label='訓練Loss') plt.plot(val_loss, label='測試Loss') plt.title('Loss曲線') plt.legend() plt.show()
此時運行程序,待訓練完成后,會顯示出acc和loss的訓練圖像,同時當前目錄下會出現checkpoint文件夾。
復現網絡結構
訓練完成之后,接下來應該編寫一個應用程序,用來接收圖片,識別圖片,返回識別結果。
因此我這里新開一個py文件
from PIL import Image import numpy as np import tensorflow as tf from tensorflow import keras #首先要復現訓練時的網絡結構 model = keras.models.Sequential([ keras.layers.Flatten(), keras.layers.Dense(128, activation='relu'), keras.layers.Dense(10, activation='softmax') ])
加載模型
model_save_path = './checkpoint/mnist.ckpt' model.load_weights(model_save_path)
圖片識別
我用Photoshop畫了十張圖,用來進行識別
imgs = ['./img/p_0.jpg','./img/p_1.jpg','./img/p_2.jpg','./img/p_3.jpg','./img/p_4.jpg','./img/p_5.jpg','./img/p_6.jpg','./img/p_7.jpg','./img/p_8.jpg','./img/p_9.jpg'] for path in imgs: #讀取圖片 img = Image.open(path) img = img.resize((28, 28), Image.ANTIALIAS) img_arr = np.array(img.convert('L')) #訓練的圖片是黑底白字,但是我們識別的圖片是白底黑字,所以需要顏色取反 #將像素值轉化為0和255兩個極端值 在保留圖片有用信息的同時 濾掉背景噪聲 使圖片更干凈 for i in range(28): for j in range(28): if img_arr[i][j] < 150: img_arr[i][j] = 255 else: img_arr[i][j] = 0 # 歸一化 img_arr = img_arr / 255.0 # 添加一個維度 x_predict = img_arr[tf.newaxis, ...] # 識別 result = model.predict(x_predict) pred = tf.argmax(result[0]) print('正在識別:{} ---- > {}'.format(path, pred))
運行結果:
需要了解的是,可識別的能力取決於參與訓練的數據,mnist手寫數字圖片都是老外收集的,老外的寫法和我們的寫法具有一些區別,並且訓練集都是經過特殊處理的圖片,因此會導致我們這種大陸屌絲寫出來的數字識別率不會很理想,盡量模仿老外的書法可以提高准確率。
當然,如果用mnist中的測試集中的圖片來識別,准確率會相當高。