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