计算机竞赛 题目:基于卷积神经网络的手写字符识别 - 深度学习
文章目录
- 0 前言
- 1 简介
- 2 LeNet-5 模型的介绍
- 2.1 结构解析
- 2.2 C1层
- 2.3 S2层
- S2层和C3层连接
- 2.4 F6与C5层
- 3 写数字识别算法模型的构建
- 3.1 输入层设计
- 3.2 激活函数的选取
- 3.3 卷积层设计
- 3.4 降采样层
- 3.5 输出层设计
- 4 网络模型的总体结构
- 5 部分实现代码
- 6 在线手写识别
- 7 最后
0 前言
🔥 优质竞赛项目系列,今天要分享的是
基于卷积神经网络的手写字符识别
该项目较为新颖,适合作为竞赛课题方向,学长非常推荐!
🧿 更多资料, 项目分享:
https://gitee.com/dancheng-senior/postgraduate

1 简介
该设计学长使用python基于TensorFlow设计手写数字识别算法,并编程实现GUI界面,构建手写数字识别系统。
这是学长做的深度学习demo,大家可以用于竞赛课题。
这里学长不会以论文的形式展现,而是以编程实战完成深度学习项目的角度去描述。
项目要求:主要解决的问题是手写数字识别,最终要完成一个识别系统。
设计识别率高的算法,实现快速识别的系统。
2 LeNet-5 模型的介绍
学长实现手写数字识别,使用的是卷积神经网络,建模思想来自LeNet-5,如下图所示:

2.1 结构解析
这是原始的应用于手写数字识别的网络,我认为这也是最简单的深度网络。
LeNet-5不包括输入,一共7层,较低层由卷积层和最大池化层交替构成,更高层则是全连接和高斯连接。
LeNet-5的输入与BP神经网路的不一样。这里假设图像是黑白的,那么LeNet-5的输入是一个32*32的二维矩阵。同
时,输入与下一层并不是全连接的,而是进行稀疏连接。本层每个神经元的输入来自于前一层神经元的局部区域(5×5),卷积核对原始图像卷积的结果加上相应的阈值,得出的结果再经过激活函数处理,输出即形成卷积层(C层)。卷积层中的每个特征映射都各自共享权重和阈值,这样能大大减少训练开销。降采样层(S层)为减少数据量同时保存有用信息,进行亚抽样。
2.2 C1层
第一个卷积层(C1层)由6个特征映射构成,每个特征映射是一个28×28的神经元阵列,其中每个神经元负责从5×5的区域通过卷积滤波器提取局部特征。一般情况下,滤波器数量越多,就会得出越多的特征映射,反映越多的原始图像的特征。本层训练参数共6×(5×5+1)=156个,每个像素点都是由上层5×5=25个像素点和1个阈值连接计算所得,共28×28×156=122304个连接。
2.3 S2层
S2层是对应上述6个特征映射的降采样层(pooling层)。pooling层的实现方法有两种,分别是max-pooling和mean-
pooling,LeNet-5采用的是mean-
pooling,即取n×n区域内像素的均值。C1通过2×2的窗口区域像素求均值再加上本层的阈值,然后经过激活函数的处理,得到S2层。pooling的实现,在保存图片信息的基础上,减少了权重参数,降低了计算成本,还能控制过拟合。本层学习参数共有1*6+6=12个,S2中的每个像素都与C1层中的2×2个像素和1个阈值相连,共6×(2×2+1)×14×14=5880个连接。
S2层和C3层连接
S2层和C3层的连接比较复杂。C3卷积层是由16个大小为10×10的特征映射组成的,当中的每个特征映射与S2层的若干个特征映射的局部感受野(大小为5×5)相连。其中,前6个特征映射与S2层连续3个特征映射相连,后面接着的6个映射与S2层的连续的4个特征映射相连,然后的3个特征映射与S2层不连续的4个特征映射相连,最后一个映射与S2层的所有特征映射相连。
此处卷积核大小为5×5,所以学习参数共有6×(3×5×5+1)+9×(4×5×5+1)+1×(6×5×5+1)=1516个参数。而图像大小为28×28,因此共有151600个连接。
S4层是对C3层进行的降采样,与S2同理,学习参数有16×1+16=32个,同时共有16×(2×2+1)×5×5=2000个连接。
C5层是由120个大小为1×1的特征映射组成的卷积层,而且S4层与C5层是全连接的,因此学习参数总个数为120×(16×25+1)=48120个。
2.4 F6与C5层
F6是与C5全连接的84个神经元,所以共有84×(120+1)=10164个学习参数。
卷积神经网络通过通过稀疏连接和共享权重和阈值,大大减少了计算的开销,同时,pooling的实现,一定程度上减少了过拟合问题的出现,非常适合用于图像的处理和识别。
3 写数字识别算法模型的构建
3.1 输入层设计
输入为28×28的矩阵,而不是向量。

3.2 激活函数的选取
Sigmoid函数具有光滑性、鲁棒性和其导数可用自身表示的优点,但其运算涉及指数运算,反向传播求误差梯度时,求导又涉及乘除运算,计算量相对较大。同时,针对本文构建的含有两层卷积层和降采样层,由于sgmoid函数自身的特性,在反向传播时,很容易出现梯度消失的情况,从而难以完成网络的训练。因此,本文设计的网络使用ReLU函数作为激活函数。

3.3 卷积层设计
学长设计卷积神经网络采取的是离散卷积,卷积步长为1,即水平和垂直方向每次运算完,移动一个像素。卷积核大小为5×5。
3.4 降采样层
学长设计的降采样层的pooling方式是max-pooling,大小为2×2。
3.5 输出层设计
输出层设置为10个神经网络节点。数字0~9的目标向量如下表所示:

4 网络模型的总体结构

5 部分实现代码
使用Python,调用TensorFlow的api完成手写数字识别的算法。
注:我的程序运行环境是:Win10,python3.。
当然,也可以在Linux下运行,由于TensorFlow对py2和py3兼容得比较好,在Linux下可以在python2.7中运行。
#!/usr/bin/env python2# -*- coding: utf-8 -*-#import modulesimport numpy as npimport matplotlib.pyplot as plt#from sklearn.metrics import confusion_matriximport tensorflow as tfimport timefrom datetime import timedeltaimport mathfrom tensorflow.examples.tutorials.mnist import input_datadef new_weights(shape):return tf.Variable(tf.truncated_normal(shape,stddev=0.05))def new_biases(length):return tf.Variable(tf.constant(0.1,shape=length))def conv2d(x,W):return tf.nn.conv2d(x,W,strides=[1,1,1,1],padding='SAME')def max_pool_2x2(inputx):return tf.nn.max_pool(inputx,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')#import datadata = input_data.read_data_sets("./data", one_hot=True) # one_hot means [0 0 1 0 0 0 0 0 0 0] stands for 2print("Size of:")print("--Training-set:\t\t{}".format(len(data.train.labels)))print("--Testing-set:\t\t{}".format(len(data.test.labels)))print("--Validation-set:\t\t{}".format(len(data.validation.labels)))data.test.cls = np.argmax(data.test.labels,axis=1) # show the real test labels: [7 2 1 ..., 4 5 6], 10000valuesx = tf.placeholder("float",shape=[None,784],name='x')x_image = tf.reshape(x,[-1,28,28,1])y_true = tf.placeholder("float",shape=[None,10],name='y_true')y_true_cls = tf.argmax(y_true,dimension=1)# Conv 1layer_conv1 = {"weights":new_weights([5,5,1,32]),"biases":new_biases([32])}h_conv1 = tf.nn.relu(conv2d(x_image,layer_conv1["weights"])+layer_conv1["biases"])h_pool1 = max_pool_2x2(h_conv1)# Conv 2layer_conv2 = {"weights":new_weights([5,5,32,64]),"biases":new_biases([64])}h_conv2 = tf.nn.relu(conv2d(h_pool1,layer_conv2["weights"])+layer_conv2["biases"])h_pool2 = max_pool_2x2(h_conv2)# Full-connected layer 1fc1_layer = {"weights":new_weights([7*7*64,1024]),"biases":new_biases([1024])}h_pool2_flat = tf.reshape(h_pool2,[-1,7*7*64])h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat,fc1_layer["weights"])+fc1_layer["biases"])# Droupout Layerkeep_prob = tf.placeholder("float")h_fc1_drop = tf.nn.dropout(h_fc1,keep_prob)# Full-connected layer 2fc2_layer = {"weights":new_weights([1024,10]),"biases":new_weights([10])}# Predicted classy_pred = tf.nn.softmax(tf.matmul(h_fc1_drop,fc2_layer["weights"])+fc2_layer["biases"]) # The output is like [0 0 1 0 0 0 0 0 0 0]y_pred_cls = tf.argmax(y_pred,dimension=1) # Show the real predict number like '2'# cost function to be optimizedcross_entropy = -tf.reduce_mean(y_true*tf.log(y_pred))optimizer = tf.train.AdamOptimizer(learning_rate=1e-4).minimize(cross_entropy)# Performance Measurescorrect_prediction = tf.equal(y_pred_cls,y_true_cls)accuracy = tf.reduce_mean(tf.cast(correct_prediction,"float"))with tf.Session() as sess:init = tf.global_variables_initializer()sess.run(init)train_batch_size = 50def optimize(num_iterations):total_iterations=0start_time = time.time()for i in range(total_iterations,total_iterations+num_iterations):x_batch,y_true_batch = data.train.next_batch(train_batch_size)feed_dict_train_op = {x:x_batch,y_true:y_true_batch,keep_prob:0.5}feed_dict_train = {x:x_batch,y_true:y_true_batch,keep_prob:1.0}sess.run(optimizer,feed_dict=feed_dict_train_op)# Print status every 100 iterations.if i%100==0:# Calculate the accuracy on the training-set.acc = sess.run(accuracy,feed_dict=feed_dict_train)# Message for printing.msg = "Optimization Iteration:{0:>6}, Training Accuracy: {1:>6.1%}"# Print it.print(msg.format(i+1,acc))# Update the total number of iterations performedtotal_iterations += num_iterations# Ending timeend_time = time.time()# Difference between start and end_times.time_dif = end_time-start_time# Print the time-usageprint("Time usage:"+str(timedelta(seconds=int(round(time_dif)))))test_batch_size = 256def print_test_accuracy():# Number of images in the test-set.num_test = len(data.test.images)cls_pred = np.zeros(shape=num_test,dtype=np.int)i = 0while i < num_test:# The ending index for the next batch is denoted j.j = min(i+test_batch_size,num_test)# Get the images from the test-set between index i and jimages = data.test.images[i:j, :]# Get the associated labelslabels = data.test.labels[i:j, :]# Create a feed-dict with these images and labels.feed_dict={x:images,y_true:labels,keep_prob:1.0}# Calculate the predicted class using Tensorflow.cls_pred[i:j] = sess.run(y_pred_cls,feed_dict=feed_dict)# Set the start-index for the next batch to the# end-index of the current batchi = jcls_true = data.test.clscorrect = (cls_true==cls_pred)correct_sum = correct.sum()acc = float(correct_sum) / num_test# Print the accuracymsg = "Accuracy on Test-Set: {0:.1%} ({1}/{2})"print(msg.format(acc,correct_sum,num_test))# Performance after 10000 optimization iterationsoptimize(num_iterations=10000)print_test_accuracy()savew_hl1 = layer_conv1["weights"].eval()saveb_hl1 = layer_conv1["biases"].eval()savew_hl2 = layer_conv2["weights"].eval()saveb_hl2 = layer_conv2["biases"].eval()savew_fc1 = fc1_layer["weights"].eval()saveb_fc1 = fc1_layer["biases"].eval()savew_op = fc2_layer["weights"].eval()saveb_op = fc2_layer["biases"].eval()np.save("savew_hl1.npy", savew_hl1)np.save("saveb_hl1.npy", saveb_hl1)np.save("savew_hl2.npy", savew_hl2)np.save("saveb_hl2.npy", saveb_hl2)np.save("savew_hl3.npy", savew_fc1)np.save("saveb_hl3.npy", saveb_fc1)np.save("savew_op.npy", savew_op)np.save("saveb_op.npy", saveb_op)
运行结果显示:测试集中准确率大概为99.2%。

查看混淆矩阵

6 在线手写识别


7 最后
🧿 更多资料, 项目分享:
https://gitee.com/dancheng-senior/postgraduate
相关文章:
计算机竞赛 题目:基于卷积神经网络的手写字符识别 - 深度学习
文章目录 0 前言1 简介2 LeNet-5 模型的介绍2.1 结构解析2.2 C1层2.3 S2层S2层和C3层连接 2.4 F6与C5层 3 写数字识别算法模型的构建3.1 输入层设计3.2 激活函数的选取3.3 卷积层设计3.4 降采样层3.5 输出层设计 4 网络模型的总体结构5 部分实现代码6 在线手写识别7 最后 0 前言…...
关于flink重新提交任务,重复消费kafka的坑
异常现象1 按照以下方式设置backend目录和checkpoint目录,fsbackend目录有数据,checkpoint目录没数据 env.getCheckpointConfig().setCheckpointStorage(PropUtils.getValueStr(Constant.ENV_FLINK_CHECKPOINT_PATH)); env.setStateBackend(new FsStat…...
Win11右键恢复Win10老版本
Win11右键恢复Win10老版本 最近自己更新了windows11的OS,整体感觉都是不错的,但是就是每次右键菜单我都要再次点击下展开更多选项,这对追求极简主义的我,就是不爽, 手动恢复win10操作吧! 第一种:创建文件(简单快速) 1.新建一个resoreRightKey.reg文件,并在里面填入如下代码 W…...
ur机械臂30003端口socket通信踩坑(double类型数据怎么解析)
坑的由来 都知道在网络通信时要把网络字节序转化为主机字节序才行,但是c里的标准库函数ntohl默认是转换32位字节序的数据,也就是说默认是转换float类型的数据;而ur机械臂30003端口发送的是double类型的数据,没法直接用ntohl进行转…...
代理IP与Socks5代理的技术奇妙之旅
随着数字化时代的崛起,网络工程师们日益承担着维护网络稳定性和保护数据安全的重任。在这个充满挑战的世界里,代理IP与Socks5代理技术成为了他们的秘密武器,本文将带您踏上一段技术奇妙之旅,深入了解这两项技术在不同领域中的应用…...
自动化测试定位不到元素?可能是 frame 在搞鬼
很多人在用Splinter或Selenium定位页面元素的时候会遇到定位不到的问题,明明元素就在那儿,就是定位不到,这种情况很有可能是frame在搞鬼。 说白了就是网站上的网页A,又嵌入了其他网页B。你访问了网页A,在里面可以看到…...
uni-app 开发中,监听 input 键盘事件获取不到按下按键值怎么办?
uniapp 开发 H5 时,无法监听按钮键盘事件的原因以及解决方法。 问题描述: 不少 uni-app 开发者在使用 input 组件时,监听 keyup 事件时,获取不到键盘的 keyCode。编写的代码如下: <template><input keyup&…...
【juc】countdownlatch实现并发网络请求
目录 一、截图示例二、代码示例2.1 测试代码2.2 接口代码 一、截图示例 二、代码示例 2.1 测试代码 package com.learning.countdownlatch;import lombok.extern.slf4j.Slf4j; import org.springframework.web.client.RestTemplate;import java.util.Arrays; import java.uti…...
在供应链管理中,如何做好库存分析?库存分析有哪些监控指标?
在供应链管理中,库存分析是其重要的一环。库存分析的方法繁杂且广泛,选择正确的方法才能更好的进行库存分析,下面就为大家盘点一些常用的库存分析方法和监控指标,全程干货,建议收藏! 01 如何进行库存分析&…...
黑豹程序员-架构师学习路线图-百科:Database数据库
文章目录 1、什么是Database2、发展历史3、数据库排行网4、总结 1、什么是Database 当今世界是一个充满着数据的互联网世界,各处都充斥着大量的数据。即这个互联网世界就是数据世界。 支撑这个数据世界的基石就是数据库,数据库也可以称为数据的仓库。 …...
你相信光吗?黑灯工厂重新相信“光”
你知道“黑灯工厂”吗?望文生义,所谓黑灯工厂,就是可以不需要照明的工厂。全程流水线自动化生产,无人干预、无人值守,工厂变成黑匣子,原材料进去,成品出来,流水线上百分百自动化。 完…...
Ubuntu 20.04使用源码安装nginx 1.14.0
nginx安装及使用(详细版)是一篇参考博文。 http://nginx.org/download/可以选择下载源码的版本。 sudo wget http://nginx.org/download/nginx-1.14.0.tar.gz下载源代码。 sudo tar xzf nginx-1.14.0.tar.gz进行解压。 cd nginx-1.14.0进入到源代码…...
springboot框架拦截器中HttpServletRequest 请求如何区分是图片上传流还是普通的字符流?
在Spring Boot框架中的拦截器(Interceptor)中,可以通过检查Content-Type请求头来区分图片上传流和普通的字符流。 当客户端发送POST请求并携带文件时,Content-Type请求头通常会包含multipart/form-data或者类似的值。这表明该请求…...
简单聊聊 TCP 协议
简单聊聊 TCP 协议 如何实现可靠传输 ?完全可靠存在比特差错存在丢包流水线可靠数据传输协议回退N步 (GBN)选择重传 (ARQ) 小结 TCPTCP 连接报文段结构序号和确认号 可靠数据传输避免重传超时时间加倍快速重传回退N步还是选择重传 流量控制连接管理拥塞控制拥塞原因拥塞控制方…...
钡铼BL124PN:简单快速转换Profinet到Ethernet/IP
钡铼技术BL124PN是一款高性能的Profinet转Ethernet/IP网关设备。该网关专为工业自动化领域设计,用于实现不同协议之间的互连和通信。BL124PN采用可靠稳定的硬件和先进的通信技术,具有以下主要特点: 协议转换能力:BL124PN能够将Pr…...
【golang】go 空结构体 详解 空结构体内容占用及大小
一、空结构体基础 空结构实例 和 空结构体变量 本质是一样的 1、所有空结构体地址都是一样的2、大小都为0(最独特的) package mainimport ("fmt""time""unsafe" )type EST struct { }func main() {// 一、基础// 空结构…...
身为产品经理该如何向客户推广API商品数据接口
在当今数字化的时代,API(Application Programming Interface,应用程序编程接口)已成为各种软件应用程序之间交互数据的主要方式。API商品数据接口作为一种特殊类型的API,能够让不同的系统之间共享商品数据,…...
【数据结构】460. LFU 缓存
460. LFU 缓存 解题思路 get操作 返回key对应的val 然后增加对应的freq插入操作 如果key已经存在 直接进行更新 如果不存在 但是容器已经满了 直接进行删除freq最小的Key 之后进行插入 class LFUCache {// key到 val的映射 KVHashMap<Integer,Integer> keyToVal;// …...
文字转语音播报模块(一):阿里云nls服务使用示例
一、业务场景 最近笔者在业务中涉及到语音告警的模块,需要讲告警内容以文件或流形式返回给前端进行语音播报,具体的分析与处理如下 二、业务分析 首先告警内容提示信息这里做的处理是通过专门字段去存储、编辑,根据拟定好的代码逻辑判断是…...
Vscode配置C#编程环境(win10)
目录 1、安装好Vscode 2、下载安装.NetCore SDK 3、配置C#环境 3.1 打开Vscode并下载扩展 3.2 Vscode中打开文件夹并配置环境 3.3 调试运行 1、安装好Vscode 2、下载安装.NetCore SDK 官网如下,下载完成后双击打开一路走到底就行.NetCore SDK官网 软件显示安…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...
Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区。编辑器中应用变更时的操作范围,就是以模型选区为基准来…...
安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...
[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...
蓝桥杯3498 01串的熵
问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798, 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...
MySQL 8.0 事务全面讲解
以下是一个结合两次回答的 MySQL 8.0 事务全面讲解,涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容,并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念(ACID) 事务是…...
C++ 设计模式 《小明的奶茶加料风波》
👨🎓 模式名称:装饰器模式(Decorator Pattern) 👦 小明最近上线了校园奶茶配送功能,业务火爆,大家都在加料: 有的同学要加波霸 🟤,有的要加椰果…...
PHP 8.5 即将发布:管道操作符、强力调试
前不久,PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5!作为 PHP 语言的又一次重要迭代,PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是,借助强大的本地开发环境 ServBay&am…...
