深度学习是一种强大的技术,它使得开发者能够提升机器的性能。人类如何记住一项任务是如何完成的?通过不断练习和重复执行这项任务,人类最终能够熟练地快速准确地完成任务。大脑中的神经元经过一段时间的训练后能够自动触发并执行任务。同样,深度学习也遵循这种方法来解决问题。深度学习算法使用不同类型的神经网络架构来解决各种问题。
在本文中,将使用MNIST数据集来实现一个手写数字识别应用程序。将使用一种特殊的深度神经网络——卷积神经网络(CNN)。最后,还将构建一个图形用户界面(GUI),用户可以直接在界面上绘制数字并立即识别它。此外,还涵盖了如何在Python中实现手写识别,以展示这些手写代码是如何实现的。让开始吧。
手写数字识别是指赋予机器识别人类手写数字的能力。对于机器来说,这不是一项容易的任务,因为手写数字并不完美,人与人之间的差异很大,而且可以用许多不同的风格书写。
要运行这个项目,需要具备深度学习基础知识,特别是使用Keras库、Tkinter库进行GUI构建,以及Python编程。以下是安装所需库的命令:
pip install numpy
pip install tensorflow
pip install keras
pip install pillow
在市面上成千上万的数据集中,MNIST是机器学习和深度学习爱好者最受欢迎的数据集之一。MNIST数据集包含超过60,000张手写数字的培训图像,从0到9,以及超过10,000张用于测试的图像。因此,MNIST数据集中有10个不同的类别。手写数字的图像显示为28×28的矩阵,每个单元格包含一个灰度像素值。
1. 导入库和数据集
在项目开始时,导入所有需要的模块来训练模型。可以轻松地导入数据集并开始工作,因为Keras库已经包含了许多数据集,MNIST就是其中之一。调用mnist.load_data()函数来获取带有标签的训练数据和测试数据。
import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Flatten, Dropout, Conv2D, MaxPooling2D
from keras import backend as K
# 导入数据集
(x_train, y_train), (x_test, y_test) = mnist.load_data()
模型不能直接处理图像数据,因此需要执行一些基本操作并处理数据,使其准备好用于神经网络。训练数据的维度是(60000*28*28)。需要为CNN模型增加一个维度,因此将矩阵重塑为形状(60000*28*28*1)。
x_train = x_train.reshape(x_train.shape[0], 28, 28, 1)
x_test = x_test.reshape(x_test.shape[0], 28, 28, 1)
input_shape = (28, 28, 1)
# 将类别向量转换为二进制类别矩阵
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255
现在是为这个基于Python的数据科学项目创建CNN模型的时候了。卷积层和池化层是CNN模型的两个轮子。CNN之所以能够成功地解决图像分类问题,是因为它适用于网格结构化数据。将使用Adadelta优化器进行模型编译。
batch_size = 128
num_classes = 10
epochs = 10
model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=input_shape))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(256, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='softmax'))
model.compile(loss=keras.losses.categorical_crossentropy, optimizer=keras.optimizers.Adadelta(), metrics=['accuracy'])
hist = model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, verbose=1, validation_data=(x_test, y_test))
print("模型已成功训练")
model.save('mnist.h5')
print("将模型保存为mnist.h5")
score = model.evaluate(x_test, y_test, verbose=0)
print('测试损失:', score[0])
print('测试准确率:', score[1])
from keras.models import load_model
from Tkinter import *
import Tkinter successful as tk
import win32gui
from PIL import ImageGrab, Image
import numpy as np
model = load_model('mnist.h5')
def predict_digit(img):
# 调整图像大小至28x28像素
img = img.resize((28,28))
# 将rgb转换为灰度
img = img.convert('L')
img = np.array(img)
# 重塑模型归一化
img = img.reshape(1,28,28,1)
img = img/255.0
# 预测类别
res = model.predict([img])[0]
return np.argmax(res), max(res)
class App(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.x = self.y = 0
# 创建元素
self.canvas = tk.Canvas(self, width=200, height=200, bg="black", cursor="cross")
self.label = tk.Label(self, text="Analyzing..", font=("Helvetica", 48))
self.classify_btn = tk.Button(self, text="Searched", command=self.classify_handwriting)
self.button_clear = tk.Button(self, text="Dlt", command=self.clear_all)
# 网格结构
self.canvas.grid(row=0, column=0, pady=2, sticky=W)
self.label.grid(row=0, column=1, pady=2, padx=2)
self.classify_btn.grid(row=1, column=1, pady=2, padx=2)
self.button_clear.grid(row=1, column=0, pady=2)
self.canvas.bind("", self.draw_lines)
def clear_all(self):
self.canvas.delete("all")
def classify_handwriting(self):
Hd = self.canvas.winfo_id()
rect = win32gui.GetWindowRect(Hd)
im = ImageGrab.grab(rect)
digit, acc = predict_digit(im)
self.label.configure(text= str(digit)+', '+ str(int(acc*100))+'%')
def draw_lines(self, event):
self.x = event.x
self.y = event.y
r=8
self.canvas.create_oval(self.x-r, self.y-r, self.x + r, self.y + r, fill='black')
app = App()
.mainloop()