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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM