1. 程式人生 > 其它 >0-9的手寫數字識別

0-9的手寫數字識別

一、訓練模型板塊分為六個部分

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語句