# -*- coding: utf-8 -*-
“””
Created on Sun Aug 1 16:22:47 2021
@author: Yang Hongyun
“””
#构建卷积神经网络模型代码
import tensorflow as tf
import keras #keras框架导入
from keras.datasets import mnist #数据集
from keras.layers import Dense,Dropout,Flatten,Conv2D,MaxPool2D,Input #神经网络层导入
from keras.models import Sequential #模型类型:Sequential序列模型和Model函数模型
#加载mnist数据集,(x_train,y_train)为训练样本, (x_test,y_test)测试样本
(x_train,y_train),(x_test,y_test)=mnist.load_data()
#数据归一化处理,将0~255归一化至 0~1之间,使得数据乘法运算也在0~1之间
#若已知样本数量,可以将-1改为具体样本数量=60000
x_train=x_train.reshape(-1,28,28,1)/255.0 #注意是255.0,发生浮点数运算,不是255
#若已知测试样本数量,可以将-1改为样本数量=10000
x_test=x_test.reshape(-1,28,28,1)/255.0
#标签转one hot操作,将所有数据从1,2,3,4,…标注改编为
# 如 1 表达为【0,1,0,0,0,0,0,0,0,0】
# 如 5 表达为【0,0,0,0,0,1,0,0,0,0】
y_train=keras.utils.to_categorical(y_train,num_classes=10) #10个类别
y_test =keras.utils.to_categorical(y_test,num_classes=10)
#搭建网络模型—全连接层
model=Sequential() #模型实例化
#向模型添加CNN层,其中默认卷积核的内容是随机的,当然也可以手工设计卷积核内容
model.add(Conv2D(filters=32,#卷积核的数量,会影响计算量
kernel_size=(3,3), #卷积核大小,卷积运算后图像大小=28-3+1=26
input_shape=(28,28,1), #样本尺寸,若为RGB图像=(28,28,3)
strides=(1,1),
activation=’relu’,
padding=’valid’ #有效尺寸,另一个参数’same’
))
model.add(MaxPool2D(pool_size=(2,2)))
#数据打平,变成一列
model.add(Flatten())
#向模型中添加Dense层—分类层
model.add(Dense(units=32,activation=’relu’))
#输出层,手写数字共0~9十个类别
model.add(Dense(units=10,activation=’softmax’))
print(model.summary())#模型编译—训练设置
model.compile(loss=’categorical_crossentropy’,optimizer=’adam’,metrics=[‘accuracy’])
#启动训练
model.fit(
x=x_train,
y=y_train,
batch_size=64,#每轮都是60000个样本,但不能将6万样本一次训练,那样所需内存过大,所以设置batch_size为每次训练样本数
epochs=10,#训练多少轮次
)
#模型测试
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
import tensorflow
from keras.models import load_model
from PIL import Image
class window(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.resizable(0, 0)
self.title(‘手写数字识别系统’)
self.geometry(‘280×280+600+300’) #窗体大小和位置
self.canvas=tk.Canvas(self, width=280,height=280,background=’black’)
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=5 #书写笔画的宽度
self.data=np.zeros([280,280]) #画布图像数据的尺寸
def on_move_press(self,event):
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()