深度学习实战 | 卷积神经网络LeNet手写数字识别(带手写板GUI界面)

引言

在深度学习领域,卷积神经网络(Convolutional Neural Network, CNN)是一种广泛应用于图像识别任务的神经网络结构。LeNet是一种经典的CNN结构,被广泛应用于基础的图像分类任务。本文将介绍如何使用LeNet卷积神经网络实现手写数字识别,并使用Pytorch实现LeNet手写数字识别,使用PyQt5实现手写板GUI界面,使用户能够通过手写板输入数字并进行识别。

请添加图片描述

完整代码下载:Python手写数字识别带手写板GUI界面 Pytorch代码 含训练模型 (付费资源,如果你觉得这篇博客对你有帮助,欢迎购买支持~)

1. LeNet卷积神经网络

LeNet是由Yann LeCun等人于1998年提出的卷积神经网络结构,主要用于手写字符识别。在本文中,我们将使用LeNet结构构建一个用于手写数字识别的神经网络模型。以下是LeNet的基本结构:

请添加图片描述

Layer 1: Convolutional Layer
    - Input: 28x28x1 (灰度图像)
    - Filter: 5x5, Stride: 1, Depth: 6
    - Activation: Sigmoid
    - Output: 28x28x6

Layer 2: Average Pooling Layer
    - Input: 28x28x6
    - Pooling: 2x2, Stride: 2
    - Output: 14x14x6

Layer 3: Convolutional Layer
    - Input: 14x14x6
    - Filter: 5x5, Stride: 1, Depth: 16
    - Activation: Sigmoid
    - Output: 10x10x16

Layer 4: Average Pooling Layer
    - Input: 10x10x16
    - Pooling: 2x2, Stride: 2
    - Output: 5x5x16

Layer 5: Fully Connected Layer
    - Input: 5x5x16
    - Output: 120
    - Activation: Sigmoid

Layer 6: Fully Connected Layer
    - Input: 120
    - Output: 84
    - Activation: Sigmoid

Layer 7: Output Layer
    - Input: 84
    - Output: 10 (对应0-9的数字)
    - Activation: Softmax

2. 手写数字识别实现

使用深度学习框架(例如Pytorch)构建LeNet模型:

import torch
import torch.nn as nn
import torch.nn.functional as F

class LeNet(nn.Module):
    def __init__(self):
        super(LeNet, self).__init__()
        self.conv1 = nn.Conv2d(1, 6, kernel_size=5)
        self.pool1 = nn.AvgPool2d(kernel_size=2, stride=2)
        self.conv2 = nn.Conv2d(6, 16, kernel_size=5)
        self.pool2 = nn.AvgPool2d(kernel_size=2, stride=2)
        self.fc1 = nn.Linear(16 * 5 * 5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):
        x = F.sigmoid(self.conv1(x))
        x = self.pool1(x)
        x = F.sigmoid(self.conv2(x))
        x = self.pool2(x)
        x = x.view(-1, 16 * 5 * 5)
        x = F.sigmoid(self.fc1(x))
        x = F.sigmoid(self.fc2(x))
        x = self.fc3(x)
        return F.log_softmax(x, dim=1)

并使用手写数字数据集MNIST进行训练。确保正确实现数据预处理和模型训练过程:

import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
from torch.autograd import Variable
from net import Net

if __name__ == "__main__":
    # 设置训练参数
    batch_size = 64
    epochs = 140
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

    # 数据集
    transform = transforms.Compose([transforms.ToTensor(),
                                    transforms.Normalize((0.5,), (0.5,))])
    trainset = datasets.MNIST('~/.pytorch/MNIST_data/', download=True, train=True, transform=transform)
    trainloader = torch.utils.data.DataLoader(trainset, batch_size=batch_size, shuffle=True)

    # 输出提示信息
    print("batch_size:", batch_size)
    print("data_batches:", len(trainloader))
    print("epochs:", epochs)

    # 神经网络
    net = Net().to(device)
    net.load_state_dict(torch.load('model.pth'))

    # 损失函数和优化器
    criterion = nn.NLLLoss()
    optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)

    # 训练网络
    for epoch in range(epochs):
        running_loss = 0.0
        for i, data in enumerate(trainloader, 0):
            inputs, labels = data
            inputs, labels = Variable(inputs).to(device), Variable(labels).to(device)

            # 反向传播优化参数
            optimizer.zero_grad()
            outputs = net(inputs)
            loss = criterion(outputs, labels)
            loss.backward()
            optimizer.step()
            running_loss += loss.item()

            if i % 938 == 937:    # 每轮输出损失值
                print('[epoch: %d, batches: %d] loss: %.5f' %
                      (epoch + 1, i + 1, running_loss / 2000))
                running_loss = 0.0
        torch.save(net.state_dict(), './model.pth')  # 每轮保存模型参数

    print('Finished Training')

3. 手写板GUI界面开发

模型训练完成后,为了让用户通过手写板输入数字,我们将开发一个简单直观的GUI界面。使用GUI库(例如PyQt5),创建一个窗口,包含一个手写板区域,用户可以在上面写数字。添加一个识别按钮,点击后将手写板上的数字送入LeNet模型进行识别,并在界面上显示识别结果。

以下是PyQt5代码示例:

from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys

import torch
from utils import *
from net import Net

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.title = '手写数字识别'
        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setMinimumSize(500, 400)
        self.main_widget = QWidget()
        self.main_layout = QGridLayout()
        self.main_widget.setLayout(self.main_layout)
        self.setCentralWidget(self.main_widget)
        self.canvas = Canvas()
        self.canvas.setFixedSize(300,300)
        self.label = QLabel()
        self.label.setFixedSize(100,100)
        self.label.setText('识别结果')
        self.label.setStyleSheet("font-size:15px;color:red") 
        self.clear_button = QPushButton('清除')
        self.clear_button.setFixedSize(100,50)
        self.clear_button.clicked.connect(self.canvas.clear)
        self.recognize_button = QPushButton('识别')
        self.recognize_button.setFixedSize(100,50)
        self.recognize_button.clicked.connect(self.recognize)
        self.main_layout.addWidget(self.canvas,0,0,3,1)
        self.main_layout.addWidget(self.label,0,1)
        self.main_layout.addWidget(self.clear_button,1,1)
        self.main_layout.addWidget(self.recognize_button,2,1)
    
    def recognize(self):
        self.canvas.recognize()
        self.label.setText('识别结果: ' + str(self.canvas.recognize()))

class Canvas(QLabel):
    x0=-10; y0=-10; x1=-10; y1=-10
    def __init__(self):
        super(Canvas,self).__init__()
        self.pixmap = QPixmap(300, 300)
        self.pixmap.fill(Qt.white)
        self.Color=Qt.blue
        self.penwidth=10

    def paintEvent(self,event):
        painter=QPainter(self.pixmap)
        painter.setPen(QPen(self.Color,self.penwidth,Qt.SolidLine))
        painter.drawLine(self.x0,self.y0,self.x1,self.y1)

        Label_painter=QPainter(self)
        Label_painter.drawPixmap(2,2,self.pixmap)

    def mousePressEvent(self, event):
        self.x1=event.x()
        self.y1=event.y()

    def mouseMoveEvent(self, event):
        self.x0 = self.x1
        self.y0 = self.y1
        self.x1 = event.x()
        self.y1 = event.y()
        self.update()

    def clear(self):
        self.x0=-10; self.y0=-10; self.x1=-10; self.y1=-10
        self.pixmap.fill(Qt.white)
        self.update()
    
    def recognize(self):
        arr = pixmap2np(self.pixmap)
        arr = 255 - arr[:,:,2]
        arr = clip_image(arr)
        arr = resize_image(arr)
        arr = np.expand_dims(arr, axis=0)
        arr_batch = np.expand_dims(arr, axis=0)
        tensor = torch.FloatTensor(arr_batch)
        tensor = (tensor/255 - 0.5) * 2
        possibles = net(tensor).detach().numpy()
        result = np.argmax(possibles)
        return result

if __name__ == '__main__':
    net = Net()
    net.load_state_dict(torch.load('model.pth'))
    app = QApplication(sys.argv)
    win = MainWindow()
    win.show()
    sys.exit(app.exec_())

这个例子中,用户可以在手写板上写数字,点击识别按钮后,程序将手写板上的数字送入LeNet模型进行识别,并在界面上显示识别结果。

通过本文的实践,你可以学到如何使用LeNet卷积神经网络实现手写数字识别,以及如何结合GUI开发一个手写板界面,更直观地进行数字识别交互。希望这篇博客对有所帮助。

完整代码下载:Python手写数字识别带手写板GUI界面 Pytorch代码 含训练模型 (付费资源,如果你觉得这篇博客对你有帮助,欢迎购买支持~)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/368767.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

前端学习之路(3) JavaScript中的代理(Proxy)与反射(Reflect)

定义与概念 JavaScript中的Proxy与Reflect是ES6中引入的新特性,它们可以帮助我们更高效地控制对象。 代理(Proxy)是一种设计模式,它允许我们在访问对象的同时,添加一些额外的操作。代理对象与被代理对象实现相同的接…

【开源】基于JAVA+Vue+SpringBoot的教学资源共享平台

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 课程档案模块2.3 课程资源模块2.4 课程作业模块2.5 课程评价模块 三、系统设计3.1 用例设计3.2 类图设计3.3 数据库设计3.3.1 课程档案表3.3.2 课程资源表3.3.3 课程作业表3.3.4 课程评价表 四、系统展…

如何在Python中设置HTTP代理:探秘网络世界的“魔法门“

嗨,各位Python的魔法师们!今天,我们要探索如何在Python中设置HTTP代理,让我们的网络请求飞得更远! 首先,我们要明白什么是HTTP代理。简单说,它就像一个中转站,帮我们转发请求给目标…

双非本科准备秋招(14.3)—— java线程

创建和运行线程 1、使用Thread Slf4j(topic "c.Test1")public class Test1 {public static void main(String[] args) {Thread t new Thread("t1") {Overridepublic void run() {log.debug("running");}};t.start();​log.debug("runnin…

LeetCode.1686. 石子游戏 VI

题目 题目链接 分析 本题采取贪心的策略 我们先假设只有两个石头a,b, 对于 Alice 价值分别为 a1,a2, 对于 Bob 价值而言价值分别是 b1,b2 第一种方案是 Alice取第一个,Bob 取第二个,Alice与Bob的价值差是 c1 a1 - b1&#xf…

Unity3d Shader篇(二)— 片元漫反射着色器解析

文章目录 前言一、片元漫反射着色器是什么?1. 片元漫反射着色器的工作原理2. 顶点漫反射着色器和片元漫反射着色器的比较顶点漫反射着色器优点:缺点: 片元漫反射着色器优点:缺点: 二、使用步骤1. Shader 属性定义2. Su…

【奶奶看了都会】《幻兽帕鲁》云服务器部署教程

在帕鲁的世界,你可以选择与神奇的生物「帕鲁」一同享受悠闲的生活,也可以投身于与偷猎者进行生死搏斗的冒险。帕鲁可以进行战斗、繁殖、协助你做农活,也可以为你在工厂工作。你也可以将它们进行售卖,或肢解后食用。 《幻兽帕鲁》官…

PostgreSQL 也很强大,为何在中国大陆,MySQL 成为主流,PostgreSQL 屈居二线呢?

问题: PostgreSQL 也很强大,为何在中国大陆,MySQL 成为主流,PostgreSQL 屈居二线呢?PostgreSQL 能否替代 MySQL? 当我们讨论为何 MySQL 在中国大陆成为主流而 PostgreSQL 屈居二线时, 我们其实…

在conda 虚拟环境中快速卸载安装包(操作详解)

手动卸载虚拟环境中的安装包 1.卸载已经安装的安装包(不指定版本好) pip uninstall 包名 2.卸载指定的安装包 pip uninstall 包名版本号 注意 “” 不是 “” 批量快速卸载 写一个txt文件,例如aaa.txt。官网一般是requirements.txt&…

NLP_统计语言模型的发展历程

文章目录 统计语言模型发展的里程碑: 上半部分是语言模型技术的进展;下半部分则是词向量(词的表示学习)技术的发展。其中,词向量表示的学习为语言模型提供了更高质量的输入信息(词向量表示) 1…

AI新工具(20240203) 文心一言APP数字分身;HuggingChat Assistants等

文心一言APP数字分身-一键生成专属数字分身 文心一言数字分身是一项新功能,用户只需一张照片和录制三句语音,就能创建一个专属的数字分身。这个数字分身还支持个性化定义名称、声音、MBTI性格等,用户可以选择是否公开自己的数字分身。这个功…

11 插入排序和希尔排序

1. 插入排序 基本思想 直接插入排序是一种简单的插入排序法,基本思想: 把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列 在玩扑克牌时,就用…

虚拟存储器

第五章:虚拟存储器 常规存储管理方式的特征 一次性 驻留性 局部性原理 程序在执行时将呈现出局部性特征,即在一较短的时间内,程序的执行仅局限于某个部分,相应地,它所访问的存储空间也局限于某个区域 时间局限性 …

创建一个Vue项目(含npm install卡住不动的解决)

目录 1 安装Node.js 2 使用命令提示符窗口创建Vue 2.1 打开命令提示符窗口 2.2 初始Vue项目 2.2.1 npm init vuelatest 2.2.2 npm install 3 运行Vue项目 3.1 命令提示符窗口 3.2 VSCode运行项目 1 安装Node.js 可以看我的这篇文章《Node.js的安装》 2 使用命令提示…

【定位·HTML】

定位布局可以分为以下四种: 静态定位(inherit) 相对定位(relative) 绝对定位(absolute) 固定定位(fixed) 一般的标签元素不加任何定位属性时,默认都属于静态…

STM32标准库——(9)TIM编码器接口

1.编码器接口简介 Encoder Interface 编码器接口编码器接口可接收增量(正交)编码器的信号,根据编码器旋转产生的正交信号脉冲,自动控制CNT自增或自减,从而指示编码器的位置、旋转方向和旋转速度每个高级定时器和通用定…

linux ln命令-linux软链接、硬链接-linux软、硬链接的区别(二):软链接

0、序 上一篇:linux ln命令-linux软链接、硬链接-linux软、硬链接的区别(一):硬链接 描述了硬链接相关内容,本篇主要描述软链接。 1、软链接 符号链接也称软链接,是将一个路径名链接到一个文件。这些文件是一种特别类型的文件。…

已解决!AttributeError: ‘Sequential‘ object has no attribute ‘session‘ 问题

博主猫头虎的技术世界 🌟 欢迎来到猫头虎的博客 — 探索技术的无限可能! 专栏链接: 🔗 精选专栏: 《面试题大全》 — 面试准备的宝典!《IDEA开发秘籍》 — 提升你的IDEA技能!《100天精通Golang》…

【Android新版本兼容】onBackPressed()方法被弃用的解决方案

提示:此文章仅作为本人记录日常学习使用,若有存在错误或者不严谨得地方欢迎指正。 文章目录 一、使用 AndroidX API 实现预测性返回手势1.1 添加依赖1.2 启用返回手势1.3 注册OnBackPressedCallback()方法来处理返回手势 一、使用 AndroidX API 实现预测…

React | Center 组件

在 Flutter 中有 Center 组件,效果就是让子组件整体居中,挺好用。 React 中虽然没有对应的组件,但是可以简单封装一个: index.less .container {display: flex;justify-content: center;align-items: center;align-content: ce…