一、訓練模型板塊分為六個部分
1)加載數據集,數據和標簽的向量化
2)網絡構架
3)編譯模型
4)模型訓練
5)評估模型
6)數據預測
from tensorflow.keras.datasets import mnist from tensorflow.keras.utils import to_categorical from tensorflow.keras import models from tensorflow.keras import layers from tensorflow.keras import optimizers import numpy as np #1.處理輸入數據 #1.1.獲取模型訓練和測試數據 (x_train, y_train), (x_test, y_test) = mnist.load_data() #1.2.數據歸一化 #1.2.1.輸入數據歸一化 #提高模型的精度,再就是使得模型的精度更容易趨於飽和 x_train = x_train.reshape(60000, 28, 28, 1) x_train = x_train.astype('float')/255 x_test = x_test.reshape(10000, 28, 28, 1) x_test = x_test.astype('float')/255 #1.2.2.標簽向量化,為什么要標簽向量化? #相對於for循環,向量化的時間計算效率更快 y_train = to_categorical(y_train) y_test = to_categorical(y_test) #2.構建網絡 model = models.Sequential() #卷積層的作用? #1)平移不變性,從小部分出發,以此類推。2)模式的空間層次結構,在前面的基礎上層層遞進 model.add(layers.Conv2D(filters=32, kernel_size=(3, 3), activation='relu', input_shape=(28,28,1))) #為什么采用池化層 #為什么采用Maxpool2D #有利於前面卷積層的空間層次結構,減少需要處理的特征圖的元素個數,簡化計算 model.add(layers.MaxPool2D(pool_size=(2, 2))) model.add(layers.Conv2D(filters=64, kernel_size=(3, 3), activation='relu')) model.add(layers.MaxPool2D(pool_size=(2, 2))) model.add(layers.Conv2D(filters=64, kernel_size=(3, 3), activation='relu')) model.add(layers.MaxPool2D(pool_size=(2, 2))) #Flatten數據打平,變成一列,常用與卷積層到全連接層的過渡,不影響批量大小 model.add(layers.Flatten()) model.add(layers.Dense(256, activation='relu')) model.add(layers.Dense(10, activation='softmax')) #3.編譯 model.compile(optimizer=optimizers.RMSprop(lr=1e-3), loss='categorical_crossentropy', metrics=['accuracy']) #4.訓練模型 model.fit(x_train, y_train, epochs=10, batch_size=128) #5.模型測試 loss,acc = model.evaluate(x_test,y_test) print(loss,acc) #模型保存 --*.h5格式 model.save('mnistTrainOnCNN.h5')
二、手寫數字識別窗口的顯示
# 模型測試部分代碼
import tkinter as tk
import tkinter.messagebox as tkmessagebox
import numpy as np
from tensorflow.keras.models import load_model
from PIL import Image
#創建窗口類
class window(tk.Tk):
#窗口的的初始化函數
def __init__(self):
tk.Tk.__init__(self)
#在Tkinter根窗口中根據用戶需要更改窗口大小
self.resizable(0, 0)#設置(0,0)窗口無法移動
self.title('手寫數字識別系統')
self.geometry('280x280+600+300') # 設置窗體大小和位置,后面的是移動的寬和高
self.canvas = tk.Canvas(self, width=280, height=280, background='black')
#自動填充窗口的空間,expend為yes時,擴充到最大
self.canvas.pack(fill='both', expand='yes')
#表示鼠標移到某個位置所觸發的事件
self.canvas.bind('<B1-Motion>', self.on_move_press)
#用戶釋放鼠標產生的事件
self.canvas.bind('<ButtonRelease-1>', self.on_button_release)
self.r = 3 # 書寫筆畫的寬度
self.data = np.zeros([280, 280]) # 畫布圖像數據的尺寸
#手寫數字的函數定義
def on_move_press(self, event):
#創建一個長方形,outline表示邊框不設定顏色,前面兩個參數,表示左上角的坐標,后面兩個參數表示右下角坐標
self.canvas.create_rectangle(event.x - self.r, event.y - self.r, event.x + self.r, event.y + self.r, fill='white',
outline='', tag='c')
# 有筆畫部分數據設為白色,像素值=255
self.data[event.y - self.r:event.y + self.r, event.x - self.r:event.x + self.r] = 255
#設置按鈕函數
def on_button_release(self,event):
self.data = np.matrix(self.data) # 數組轉為矩陣形式
img = Image.fromarray(np.uint8(self.data)) # 格式化為PIL.Image形式
img_array = img.resize((28, 28)) # 縮放到mnist數據集樣本大小
img_array = np.reshape(img_array, (28, 28, 1)) # 將二維矩陣轉為一層的三維矩陣,如彩色圖像,應為3層
#將數字圖像矩陣數定義為1個樣本並歸一化
img_array = img_array.reshape(1, 28, 28, 1) / 255.0
# 加載模型
model = load_model('mnistTrainOnCNN.h5')
# 進行預測
prediction = model.predict(img_array)
#顯示,詢問選擇對話框
result = tkmessagebox.askokcancel(title='識別結果', message='識別的數字是:' + str(np.argmax(prediction)))
if (result == 1):
self.canvas.delete('c')
self.data[:, :] = 0
return
#主函數
if __name__ == '__main__':
w = window()
w.mainloop()#相當while語句