赞
踩
基于深度学习的手写数字识别系统
深度学习手写数字识别是人工智能领域的一个重要研究方向,其背景可以追溯到上世纪80年代和90年代的神经网络研究。最初,研究者们通过构建多层神经网络来尝试解决手写数字识别等问题,但由于当时计算能力的限制和数据规模的不足,这些方法并没有取得很好的效果。
随着计算能力的提升、大规模数据集的出现以及深度学习算法的发展,特别是卷积神经网络(CNN)的兴起,手写数字识别取得了巨大的进步。CNN可以有效地提取图像中的特征,并且在处理二维数据(如图像)时具有很强的表现力。LeNet-5是一个里程碑式的CNN架构,最初是为了处理手写数字识别而设计的。
随着时间的推移,研究者们提出了许多改进的CNN架构,例如AlexNet、VGG、GoogLeNet和ResNet等,这些架构在图像识别任务上取得了惊人的成绩。同时,随着数据集的增大(如MNIST、SVHN、CIFAR-10等)和硬件设备的不断优化(如GPU加速),深度学习手写数字识别的性能不断提高。
此外,除了CNN之外,还有其他的深度学习模型被应用于手写数字识别,例如循环神经网络(RNN)、长短期记忆网络(LSTM)和注意力机制等。这些模型在处理序列数据(如手写数字序列)时具有优势,也为手写数字识别任务带来了新的思路和方法。
总的来说,深度学习手写数字识别的研究背景包括了神经网络的发展历程、大规模数据集的出现、深度学习算法的进步,以及硬件设备的提升,这些因素共同推动了手写数字识别技术的快速发展和应用。
觉得不错的小伙伴,感谢点赞、关注加收藏哦!更多干货内容持续更新…
关注博主的G Z H【小蜜蜂视觉】,回复【手写数字识别】即可获取下载方式
若您想获得博文中涉及的实现完整全部程序文件(包括手写数据集、py文件,模型权重文件,调试说明等),代码获取与技术指导,具体见可参考博客与视频,已将所有涉及的文件同时打包到里面,软件安装调试有具体说明,我们有专业的调试技术人员,将远程协助客户调试,具体请看安装调试说明.txt
,完整文件截图如下:
本文构建的AI手写数字识别系统基于Qt构建用户手写数字板输入。
深度学习手写体数字定位技术的目标是从输入图像中准确地定位手写的位置,通常是通过目标检测技术来实现。以下是一种常见的深度学习手写数字定位技术原理,用于获取手写数字矩形框位置:
数据准备: 首先,需要准备一个包含手写数字的训练数据集。这些数据集应该包括不同人不同风格的手写数字图像。标注数据可以通过手动标注或者自动化方法获得,本文采用多个学生建立的手写数字数据集。
网络架构: 选择一个适合车牌定位任务的深度学习网络架构。一种常见的选择是基于卷积神经网络(CNN)的架构,例如Faster R-CNN、YOLO(You Only Look Once)或SSD(Single Shot MultiBox Detector)。这些网络可以同时预测边界框的位置和类别,适用于目标检测任务。
训练: 使用准备好的训练数据集对所选网络架构进行训练。训练过程涉及将输入图像传递给网络,然后通过反向传播优化网络的权重,使其能够准确地预测车牌位置。训练数据中的每个样本都包括输入图像和相应的车牌位置标注。
预测: 在训练完成后,将训练得到的网络应用于新的图像。通过将图像输入网络,网络将输出车牌位置的预测结果,这通常是一个边界框或四个关键点的坐标。
后处理: 根据网络输出的预测结果,可以使用一些后处理技术来提高定位的准确性。例如,可以使用非极大值抑制(NMS)来抑制重叠的边界框,只保留最有可能的车牌位置。
评估和调优: 对预测结果进行评估,可以使用评价指标如IoU(Intersection over Union)来衡量预测框与真实标注框的重叠程度。根据评估结果,可以对网络架构、训练参数等进行调优,以提高定位的准确性和稳定性。
采用手写板模拟0-9的10个数字数据集,如下图所示
总共手写了600张手写数字图像,每一个图像包含至少一个手写数字
YOLOv5算法是一种单阶段目标检测算法,其网络结构主要由输入端(Input)、主干网络Backbone)、特征融合模块(Neck )和预测层(Head)4个部分组成。如下图所示。
对不同尺寸的目标进行检测时,输入图片经过处理后变成大小为640×640的图片,再输入骨干网络处理得到20×20 、40×40、80×80 三种特征图,再将三种不同尺度的特征图进行融合,使得网络学习同时兼顾目标的顶层和底层特征。
为了提升模型的泛化能力,在YOLOv5 中增加了Mosaic数据增强方式,即从一个 batch 中随机选取 4 张图片,并将图片进行随机缩放、裁剪,再拼接成一个设定边长的训练样本,作为训练集图片送入神经网络。这样做可以在不改变原来的数据集数量的基础上获得更多数据特征进行训练,既能有效提高系统的鲁棒性,也能在一定程度上减少GPU 的损耗,也可以加快网络训练速度。马赛克数据增强原理如下图所示。
YOLOv5 中的主干网络 Backbone 主要作用是提取输入图像的目标特征,使用了Focus结构作为Backbone中的基准网络,网络结构模型为CSPDarknet53 ,并通过切片操作来获得得到二倍下采样图,可以有效增强主干网络特征提取能力。
1)Focus 结构
输入的图像先经过 Focus 模块,进行切片操作,即在图片中每隔像素值进行取值,得到四张互补的输入图像,再输入骨干网络进行处理,从而达到对系统提速的效果。Focus结构如下图所示。
2)CSP 结构
YOLOv5 中的 CSP 结构主要用于增强主干网络提取深层图的信息,常用的CSP 结构主要有两种,被用于 Backbone 主干网络的是CSP1 模块,被用于特征融合Neck结构的是CSP2 模块。CSP1 模块能有效减少网络计算量和保证网络模型整体的准确性,其结构共有两个分支,一个分支连接残差组件,另一分支在卷积后通过 Concat 方式和上一分支相连接。结构如下图所示。
CBL 模块主要由图像的卷积、批量标准化操作和 Leaky_Relu 激活函数组成,如下图所示。
残差结构 Resunit 主要用于防止当网络深度加深时网络性能退化,如下图所示。
SPP 模块主要用于把输入图像送入池化层中,获得不同的池化特征值,再将这些池化特征值和原图的特征值用Concat进行连接,使得在不影响网络的训练速率的前提下,显著分离图像特征值,如下图所示。
YOLOv5中的Neck 层主要用于将 Backbone 结构中提取到的目标特征进行融合,再输入 Head 层。在YOLOv5的Neck模块中采用FPN+PAN网络结构和CSP2 模块来增加特征融合能力。其中, 特征金字塔网络(FPN),主要用于采集图像中的高层信息,并将其传递给低层,路径聚合网络(PAN),则相反,将目标位置信息由低层传递给高层,从而有效提高目标识别的准确性,如下图所示。
YOLOv5 的 Head 层主要功能是对经过 Neck 结构特征融合后的目标进行类别的判断和预测。Head 层主要包含损失函数和非极大值抑制两部分,损失函数用于评价训练时预测值与真实值之间的误差程度。其中,YOLOv5 以 GIOU_Loss 做为损失函数,其数值越小,说明模型的预测效果越好。非极大值抑制处理主要用于对最后的目标检测框进行非极大值抑制处理,保留最优目标框,提高了目标识别的准确性。
模型训练主要分为如下几步:
新人安装Anaconda环境可以参考博主写的文章Anaconda3与PyCharm安装配置保姆教程
新人安装PyTorch GPU版本可以参考博主写的文章基于conda的PyTorch深度学习框架GPU安装教程
conda create -n yolov5 python=3.8
conda activate yolov5
git clone https://github.com/ultralytics/yolov5.git
cd yolov5
pip install -r requirement.txt
# Parameters nc: 10 # number of classes depth_multiple: 0.33 # model depth multiple width_multiple: 0.50 # layer channel multiple anchors: - [10,13, 16,30, 33,23] # P3/8 - [30,61, 62,45, 59,119] # P4/16 - [116,90, 156,198, 373,326] # P5/32 # YOLOv5 v6.0 backbone backbone: # [from, number, module, args] [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 [-1, 3, C3, [128]], [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 [-1, 6, C3, [256]], [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 [-1, 9, C3, [512]], [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 [-1, 3, C3, [1024]], [-1, 1, SPPF, [1024, 5]], # 9 ] # YOLOv5 v6.0 head head: [[-1, 1, Conv, [512, 1, 1]], [-1, 1, nn.Upsample, [None, 2, 'nearest']], [[-1, 6], 1, Concat, [1]], # cat backbone P4 [-1, 3, C3, [512, False]], # 13 [-1, 1, Conv, [256, 1, 1]], [-1, 1, nn.Upsample, [None, 2, 'nearest']], [[-1, 4], 1, Concat, [1]], # cat backbone P3 [-1, 3, C3, [256, False]], # 17 (P3/8-small) [-1, 1, Conv, [256, 3, 2]], [[-1, 14], 1, Concat, [1]], # cat head P4 [-1, 3, C3, [512, False]], # 20 (P4/16-medium) [-1, 1, Conv, [512, 3, 2]], [[-1, 10], 1, Concat, [1]], # cat head P5 [-1, 3, C3, [1024, False]], # 23 (P5/32-large) [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) ]
class CnnModel(object): def __init__(self, model_path): self.weights= model_path self.data='data/shouxie.yaml' self.imgsz=(640, 640) self.conf_thres=0.5 self.iou_thres=0.45 # Load model self.device = select_device() print(self.device) self.model = DetectMultiBackend(self.weights, device=self.device, dnn=self.dnn, data=self.data, fp16=self.half) stride, self.names, pt = self.model.stride, self.model.names, self.model.pt imgsz = check_img_size(self.imgsz, s=stride) # check image size def predict(self, image_numpy_data): # Padded resize img = letterbox(image_numpy_data, 640, 32, True)[0] print(img.shape) # Convert img = img.transpose((2, 0, 1))[::-1] # HWC to CHW, BGR to RGB img = np.ascontiguousarray(img) pred = self.model(im, augment=self.augment, visualize=self.visualize) pred = non_max_suppression(pred, self.conf_thres, self.iou_thres, self.classes) detect_results = [] # Process predictions for i, det in enumerate(pred): # per image if len(det): # Rescale boxes from img_size to im0 size det[:, :4] = scale_coords(im.shape[2:], det[:, :4], image_numpy_data.shape).round() detections = det.cpu().numpy() for v in detections: detect_results.append(v) bboxes = [] scores = [] classIds = [] # [x,y,w,h,p,class] for detection in detect_results: print(detection) score = detection[4] classId = detection[5] (x1, y1, x2, y2) = detection[:4] bboxes.append([int(x1), int(y1), \ int(x2 - x1), int(y2 - y1)]) scores.append(float(score)) classIds.append(classId) print(detect_results) for *xyxy, conf, cls in reversed(det): c = int(cls) # integer class label = None if self.hide_labels else (self.names[c] if self.hide_conf else f'{self.names[c]} {conf:.2f}') annotator.box_label(xyxy, label, color=colors(c, True)) return im0
觉得不错的小伙伴,感谢点赞、关注加收藏哦!更多干货内容持续更新…
关注博主的G Z H【小蜜蜂视觉】,回复【手写数字识别】即可获取下载方式
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。