FPGA 实现 LeNet-5 卷积神经网络 数字识别,提供4套工程源码和技术支持


FPGA 实现 LeNet-5 卷积神经网络 数字识别,提供4套工程源码和技术支持

1、前言

LeNet-5简洁

LeNet-5诞生于上世纪90年代,是CNN的开山之作,最早的卷积神经网络之一,用于手写数字识别(图像分类任务),它的诞生极大地推动了深度学习领域的发展。LeNet在多年的研究和迭代后,Yann LeCun将完成的这项开拓性成果被命名为LeNet5,并发表在论文《Gradient-Based Learning Applied to Document Recognition》上,如今的AlexNet、ResNet等都是在其基础上发展而来的,在当年是一种用于手写体字符识别的非常高效的卷积神经网络。如今的卷积神经网络模型早已沧海桑田,但作为基础入门的学习资料,LeNet-5依然在江湖中占有极其重要的一席之地;

基于Zynq7020 的设计说明

本设计提供4套vivado2019.1版本的工程源码,两套工程的区别如下:
在这里插入图片描述
本文使用Xilinx的Kirtex Zynq7000系列的Zynq7020–xc7z020clg400-2和Zynq7010–xc7z010clg400-2型号FPGA 实现LeNet-5 卷积神经网络实现数字识别实验;基于Zynq7000系列FPGA的异构特性,本设计的图像采集、图像缓存、图像处理、图像输出用 PL 端的 FPGA 逻辑实现;LeNet-5 卷积神经网络的识别功能采用 PS 端的 SDK C语言软件实现;PS 端软件将识别结果通过 AXI-Lite 总线输出给 PL 端,实现了 PS 端软件与 PL 端硬件的交互;PL 端根据 PS 端软件的识别结果,将识别到的数字输出到显示器上,实现了人机交互;PL 和 PS 端是同步实时进行的;设计所用版本为vivado2019.1;

PL 端 FPGA 逻辑设计

输入视频源采用廉价的小分辨率的ov7725或ov5640摄像头;Zynq软核通过EMIO模拟i2c总线配置ov7725或ov5640摄像头分辨率为640x480;然后将输入视频送入纯verilog代码实现的视频采集模块,将DVP视频转换为RGB888视频;然后将视频送入纯verilog代码实现的图像预处理模块,该模块在640x480图像正中心框出一块122x122大小图像区域,该区域作为输入数字图像的采集区域,是后面的LeNet-5卷积神经网络进行识别的区域;然后调用Xilinx官方的 Video In to AXI4-Stream 将RGB888视频转换为AXI4-Stream视频;然后调用Xilinx官方的 VDMA 将视频缓存进PS侧DDR3再读出,为了低延时,VDMA设置为1帧缓存,需要在SDK中配置才能使用;然后调用Xilinx官方的 Video Timing Controller 和 AXI4-Stream to Video Out 将 AXI4-Stream 视频转换为 RGB888视频;然后调用Xilinx官方的 ps_pl_axi_lite 接收 PS 端软件LeNet-5数字识别结果,送入图像后处理模块,该模块例化了10个 ROM ,存储了 0~9 的9个数字,并根据识别结果输出对应的数字到显示屏的右上角显示;然后将图像送入纯verilog代码实现的RGB转HDMI模块,该模块输出HDMI视频到显示器;

PS 端 SDK 软件设计

PS 端实现LeNet-5 卷积神经网络的识别功能,并将识别结果通过AXI-Lite 总线输出给 PL 端;首先在内存开辟一些列缓存空间,用来存储图像和LeNet-5 卷积神经网络计算的中间结果;软件先从 DDR3 中读取 28x28 大小的图像,然后存入事先开辟好的内存,由于需要识别的图像大小为122x122,所以需要取4次才能完整的取完一张图片;然后将图像送入卷积层计算,计算结果存入事先开辟好的内存;然后进行池化层计算,计算结果存入事先开辟好的内存;然后进行隐藏层计算,计算结果存入事先开辟好的内存;然后进行输出层计算,最后将输出结果通过AXI-Lite 总线输出给 PL 端;

免责声明

本工程及其源码即有自己写的一部分,也有网络公开渠道获取的一部分(包括CSDN、Xilinx官网、Altera官网以及其他开源免费获取渠道等等),若大佬们觉得有所冒犯,请私信批评教育;部分模块源码转载自上述网络,版权归原作者所有,如有侵权请联系我们删除;基于此,本工程及其源码仅限于读者或粉丝个人学习和研究,禁止用于商业用途,若由于读者或粉丝自身原因用于商业用途所导致的法律问题,与本博客及博主无关,请谨慎使用。。。

2、相关方案推荐

卷积神经网络解决方案

我的主页有FPGA 卷积神经网络专栏,该专栏有 LeNet、 CNN、 DNN等卷积神经网络FPGA实现方案;以下是专栏地址:
点击直接前往

FPGA图像处理方案

我的主页目前有FPGA图像处理专栏,改专栏收录了我目前手里已有的FPGA图像处理方案,包括图像缩放、图像识别、图像拼接、图像融合、图像去雾、图像叠加、图像旋转、图像增强、图像字符叠加等等;以下是专栏地址:
点击直接前往

3、详细设计方案

设计架构框图

本文使用Xilinx的Kirtex Zynq7000系列的Zynq7020–xc7z020clg400-2型号FPGA 实现LeNet-5 卷积神经网络实现数字识别实验;基于Zynq7020的异构特性,本设计的图像采集、图像缓存、图像处理、图像输出用 PL 端的 FPGA 逻辑实现;LeNet-5 卷积神经网络的识别功能采用 PS 端的 SDK C语言软件实现;PS 端软件将识别结果通过 AXI-Lite 总线输出给 PL 端,实现了 PS 端软件与 PL 端硬件的交互;PL 端根据 PS 端软件的识别结果,将识别到的数字输出到显示器上,实现了人机交互;设计框图如下:
在这里插入图片描述

PL端:ov7725、ov5640摄像头及图像采集

工程源码1输入视频源采用廉价的小分辨率的ov7725摄像头;Zynq软核通过EMIO模拟i2c总线配置ov7725摄像头分辨率为640x480;然后将输入视频送入纯verilog代码实现的视频采集模块,将DVP视频转换为RGB888视频;摄像头采集部分代码如下:
在这里插入图片描述
这里采用ov7725摄像头的主要原因是他的分辨率很小,只有640x480@60Hz,卷积神经网络对输入图像的大小求小不求大,因为太大的图像耗费的运算时间很长;

工程源码2输入视频源采用廉价的小分辨率的ov5640摄像头;采用纯verilog代码实现的i2c总线配置ov5640摄像头分辨率为640x480;然后将输入视频送入纯verilog代码实现的视频采集模块,将DVP视频转换为RGB888视频;摄像头配置、采集部分代码如下:
在这里插入图片描述

PL端:图像预处理

然后将视频送入纯verilog代码实现的图像预处理模块,该模块在640x480图像正中心框出一块122x122大小图像区域,该区域作为输入数字图像的采集区域,是后面的LeNet-5卷积神经网络进行识别的区域;图像预处理模块代码如下:
在这里插入图片描述
图像预处理模块首先对输入图像进行RGB转灰度操作,将RGB888视频转为8bit的灰度图,这样有利于图像识别,因为图像识别需要的只是图像边沿和轮廓的像素信息,RGB分量显然数据量太大,灰度图则完美契合;然后图像进行框选处理,即框选出需要进行识别的区域,正如前面所说,卷积神经网络对输入图像的大小求小不求大,对于640x480的采集图像,我们并不是全部都纳入识别范围,而是选择了0图像正中心框出一块122x122大小图像区域,因为数字本身就不会太大,不太可能整个屏幕全是单个数字吧?实现的效果如下:
在这里插入图片描述

PL端:Xilinx推荐的图像缓存架构

然后调用Xilinx官方的 Video In to AXI4-Stream 将RGB888视频转换为AXI4-Stream视频;然后调用Xilinx官方的 VDMA 将视频缓存进PS侧DDR3再读出,为了低延时,VDMA设置为1帧缓存,需要在SDK中配置才能使用;然后调用Xilinx官方的 Video Timing Controller 和 AXI4-Stream to Video Out 将 AXI4-Stream 视频转换为 RGB888视频;这是一套标准的Xilinx推荐的图像缓存架构;

PL端:识别结果的 PL 与 PS 交互

调用Xilinx官方的 ps_pl_axi_lite 接收 PS 端软件LeNet-5数字识别结果,并根据识别结果,将识别到的数字输出到显示器上;axi_lite是一个轻量级总线,在SDK里直接调用API即可写数据;

PL端:图像后处理

s_pl_axi_lite 接收 PS 端软件LeNet-5数字识别结果,送入图像后处理模块,该模块例化了10个 ROM ,存储了 0~9 的9个数字,并根据识别结果输出对应的数字到显示屏的右上角显示;图像后处理模块代码如下:
在这里插入图片描述
图像后处理的核心操作是像素替换,当有识别结果输入时,在显示屏右上角显示对应的数字,否则显示原始的ov7725或ov5640采集像素;实现的效果如下:
在这里插入图片描述

PL端:RGB 转 HDMI

然后将图像送入纯verilog代码实现的RGB转HDMI模块,该模块输出HDMI视频到显示器;RGB转HDMI模块代码如下:
在这里插入图片描述

PS端:图像获取

软件先从 DDR3 中读取 28x28 大小的图像,然后存入事先开辟好的内存,由于需要识别的图像大小为122x122,所以需要取4次才能完整的取完一张图片;代码如下:
在这里插入图片描述

PS端:卷积层计算

然后将图像送入卷积层计算,计算结果存入事先开辟好的内存;代码如下:
在这里插入图片描述
卷积模型由Python训练得到,并转换为C语言数组;卷积核详情请看注释,注释还在进一步优化中。。。

PS端:池化层计算

然后进行池化层计算,计算结果存入事先开辟好的内存;代码如下:
在这里插入图片描述
池化层详情请看注释,注释还在进一步优化中。。。

PS端:隐藏层计算

然后进行隐藏层计算,计算结果存入事先开辟好的内存;代码如下:
在这里插入图片描述
隐藏层详情请看注释,注释还在进一步优化中。。。

PS端:输出层计算

然后进行隐藏层计算,计算结果存入事先开辟好的内存;然后进行输出层计算,最后将输出结果通过AXI-Lite 总线输出给 PL 端;代码如下:
在这里插入图片描述

工程源码架构说明

工程源码架构包括PL端的Block Design逻辑设计和PS端的C语言软件设计,工程1、2、3、4的工程源码架构具有相似性,仅仅是FPGA型号与输入摄像头型号不同,所以我们仅以工程1为例介绍,其他几套工程与之类似;
工程1的Block Design如下,工程2、3、4与之类似:
在这里插入图片描述
工程1的PL端逻辑设计代码架构如下,工程2、3、4与之类似:
在这里插入图片描述
工程1的PS 端 SDK 软件工程代码架构如下,工程2、3、4与之类似:
在这里插入图片描述

4、工程源码1详解:ov7725输入,Zynq7020版本

开发板FPGA型号:Xilinx–Zynq7020–xc7z020clg400-2;
开发环境:Vivado2019.1;
输入:OV7725摄像头,分辨率配置为640x480;
输出:HDMI,分辨率配置为640x480;
工程作用:FPGA基于 LeNet-5 卷积神经网络实现数字识别;
工程的代码架构与详情请参考第三章节的《工程源码架构说明》:
工程资源消耗和功耗如下:
在这里插入图片描述

5、工程源码2详解:ov5640输入,Zynq7020版本

开发板FPGA型号:Xilinx–Zynq7020–xc7z020clg400-2;
开发环境:Vivado2019.1;
输入:ov5640摄像头,分辨率配置为640x480;
输出:HDMI,分辨率配置为640x480;
工程作用:FPGA基于 LeNet-5 卷积神经网络实现数字识别;
工程的代码架构与详情请参考第三章节的《工程源码架构说明》:
工程资源消耗和功耗如下:
在这里插入图片描述

6、工程源码3详解:ov7725输入,Zynq7010版本

开发板FPGA型号:Xilinx–Zynq7010–xc7z010clg400-2;
开发环境:Vivado2019.1;
输入:OV7725摄像头,分辨率配置为640x480;
输出:HDMI,分辨率配置为640x480;
工程作用:FPGA基于 LeNet-5 卷积神经网络实现数字识别;
工程的代码架构与详情请参考第三章节的《工程源码架构说明》:
工程资源消耗和功耗如下:
在这里插入图片描述

7、工程源码4详解:ov5640输入,Zynq7010版本

开发板FPGA型号:Xilinx–Zynq7010–xc7z010clg400-2;
开发环境:Vivado2019.1;
输入:ov5640摄像头,分辨率配置为640x480;
输出:HDMI,分辨率配置为640x480;
工程作用:FPGA基于 LeNet-5 卷积神经网络实现数字识别;
工程的代码架构与详情请参考第三章节的《工程源码架构说明》:
工程1的资源消耗和功耗如下:
在这里插入图片描述

8、工程移植说明

vivado版本不一致处理

1:如果你的vivado版本与本工程vivado版本一致,则直接打开工程;
2:如果你的vivado版本低于本工程vivado版本,则需要打开工程后,点击文件–>另存为;但此方法并不保险,最保险的方法是将你的vivado版本升级到本工程vivado的版本或者更高版本;
在这里插入图片描述
3:如果你的vivado版本高于本工程vivado版本,解决如下:
在这里插入图片描述
打开工程后会发现IP都被锁住了,如下:
在这里插入图片描述
此时需要升级IP,操作如下:
在这里插入图片描述
在这里插入图片描述

FPGA型号不一致处理

如果你的FPGA型号与我的不一致,则需要更改FPGA型号,操作如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
更改FPGA型号后还需要升级IP,升级IP的方法前面已经讲述了;

其他注意事项

1:由于每个板子的DDR不一定完全一样,所以MIG IP需要根据你自己的原理图进行配置,甚至可以直接删掉我这里原工程的MIG并重新添加IP,重新配置;
2:根据你自己的原理图修改引脚约束,在xdc文件中修改即可;
3:纯FPGA移植到Zynq需要在工程中添加zynq软核;

9、上板调试验证并演示

准备工作

Zynq7000系列开发板,你可以用自己的开发板,也可以用本博主提供的开发板;
OV7725或者OV5640摄像头;
HDMI显示器;
打印一张0~9的数字的纸张,字体要加粗,可以用我资料包里的文档打印,打印出来如下:
在这里插入图片描述
将显示器中的采集区域对着数字,移动摄像头对准,如下:
在这里插入图片描述

输出静态演示

以工程1为例,识别结果如下,工程2、3、4与之类似:
在这里插入图片描述
在这里插入图片描述

输出动态演示

以工程1为例,录制了一个小视频,输出动态演示如下,工程2、3、4与之类似:

LeNet-5数字识别

10、福利:工程源码获取

福利:工程代码的获取
代码太大,无法邮箱发送,以某度网盘链接方式发送,
资料获取方式:私,或者文章末尾的V名片。
网盘资料如下:
在这里插入图片描述
此外,有很多朋友给本博主提了很多意见和建议,希望能丰富服务内容和选项,因为不同朋友的需求不一样,所以本博主还提供以下服务:
在这里插入图片描述

  • 44
    点赞
  • 91
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
LeNet-5神经网络 C源代码,这个写的比较好,可以用gcc编译去跑,结合理论可以对深度学习有更深刻的了解 介绍 根据YANN LECUN的论文《Gradient-based Learning Applied To Document Recognition》设计的LeNet-5神经网络,C语言写成,不依赖任何第三方库。 MNIST手写字符集初代训练识别率97%,多代训练识别率98%。 DEMO main.c文件为MNIST数据集的识别DEMO,直接编译即可运行,训练集60000张,测试集10000张。 项目环境 该项目为VISUAL STUDIO 2015项目,用VISUAL STUDIO 2015 UPDATE1及以上直接打开即可编译。采用ANSI C编写,因此源码无须修改即可在其它平台上编译。 如果因缺少openmp无法编译,请将lenet.c中的#include和#pragma omp parallel for删除掉即可。 API #####批量训练 lenet: LeNet5的权值的指针,LeNet5神经网络的核心 inputs: 要训练的多个图片对应unsigned char二维数组的数组,指向的二维数组的batchSize倍大小内存空间指针。在MNIST测试DEMO中二维数组为28x28,每个二维数组数值分别为对应位置图像像素灰度值 resMat:结果向量矩阵 labels:要训练的多个图片分别对应的标签数组。大小为batchSize batchSize:批量训练输入图像(二维数组)的数量 void TrainBatch(LeNet5 *lenet, image *inputs, const char(*resMat)[OUTPUT],uint8 *labels, int batchSize); #####单个训练 lenet: LeNet5的权值的指针,LeNet5神经网络的核心 input: 要训练的图片对应二维数组 resMat:结果向量矩阵 label: 要训练的图片对应的标签 void Train(LeNet5 *lenet, image input, const char(*resMat)[OUTPUT],uint8 label); #####预测 lenet: LeNet5的权值的指针,LeNet5神经网络的核心 input: 输入的图像的数据 labels: 结果向量矩阵指针 count: 结果向量个数 return 返回值为预测的结果 int Predict(LeNet5 *lenet, image input, const char(*labels)[LAYER6], int count); #####初始化 lenet: LeNet5的权值的指针,LeNet5神经网络的核心
### 回答1: LeNet-5是一种经典的卷积神经网络模型,常用于手写数字识别任务。HLS(High-Level Synthesis)是针对FPGA设计的一种高级综合工具,它可以将高级语言如C/C++代码转化为硬件描述语言。 要实现LeNet-5模型的HLS版本,我们可以按照以下步骤进行: 1. 首先,我们需要将LeNet-5的网络结构进行转换,以适应HLS工具的要求。LeNet-5由两个卷积层、两个池化层和三个全连接层组成。我们需要将这些层的相应操作转化为HLS中的硬件描述。例如,卷积操作可以使用HLS中的乘法器和加法器实现,池化操作可以使用选择器进行。 2. 接下来,我们可以使用HLS工具中的数据流和并行指令来优化LeNet-5的实现。通过合理地划分和并行化计算以及使用流水线技术,可以提高模型的效率和速度。 3. 在转换为HLS代码后,我们可以使用HLS工具提供的仿真功能进行测试和验证。通过在测试数据上运行HLS代码,我们可以确保模型在硬件上的实现与预期输出一致。 4. 最后,我们可以将HLS代码综合为目标FPGA设备上的位文件。通过将生成的位文件加载到FPGA上,我们就可以在硬件平台上运行LeNet-5模型进行手写数字识别任务了。 总之,通过使用HLS工具,我们可以将LeNet-5模型从C语言代码转化为硬件实现,并在FPGA上运行,以提高其性能和效率。这种转换过程需要注意HLS工具的特性和限制,并进行适当的优化和测试,以确保模型的正确性和可靠性。 ### 回答2: Lenet-5是一种经典的卷积神经网络CNN)结构,由Yann LeCun在1998年提出。要在HLS(高层次综合)中实现Lenet-5,主要需要将Lenet-5网络结构转换为可在HLS工具中使用的硬件描述语言(HDL)。 Lenet-5网络结构主要包含七个层级:两个卷积层,两个池化层和三个全连接层。在HLS实现Lenet-5时,每个层级都需要进行适当的转换。 首先是卷积层。在HLS中,可以使用具有适当参数的卷积内核来表示卷积层。通过在HDL描述文件中定义卷积核的大小、步长和填充,可以实现卷积层。 第二是池化层。池化层的操作可以通过在HDL描述文件中定义池化区域的大小和类型来实现。常用的是最大池化和平均池化。 第三是全连接层。全连接层可以通过使用适当的权重矩阵和偏置向量来实现。在HLS中,可以使用乘法和加法操作来实现全连接层。 最后,在HLS工具中,需要将输入数据流和输出数据流与适当的处理单元(如DSP、BRAM等)进行连接,以实现完整的Lenet-5网络结构。 实现完成后,可以对HLS代码进行综合、优化和验证,以生成可在FPGA上运行的硬件实现。在FPGA上运行Lenet-5可以进行图像分类、目标检测等任务。 总而言之,要在HLS中实现Lenet-5,需要将Lenet-5网络结构转化为HDL代码,并对其进行综合、优化和验证,最终生成可在FPGA上运行的硬件实现。这样就能够利用硬件加速的方式快速处理Lenet-5网络的图像识别任务。 ### 回答3: Lenet-5是一个经典的卷积神经网络模型,常用于手写数字识别任务。HLS(High-Level Synthesis)是一种用于FPGA(Field-Programmable Gate Array)的高级综合工具,可以将C/C++代码转化为硬件描述语言(HDL)。 实现Lenet-5模型的HLS过程主要包括以下几个步骤: 1. 定义Lenet-5的网络结构:Lenet-5由两个卷积层、两个池化层和三个全连接层组成。在C代码中,我们需要定义网络的各层结构、参数和激活函数。 2. 数据预处理:在Lenet-5中,输入图像为32x32的灰度图像。我们可以使用C代码读取输入图像,并对其进行预处理,如图像缩放和归一化等操作。 3. 卷积计算:在C代码中,我们可以使用循环嵌实现卷积计算。对于每个卷积层,我们需要定义卷积核的大小和数量,并对输入图像进行卷积操作。卷积操作可以通过计算每个卷积核与输入图像的点积得到输出特征图。 4. 池化计算:在C代码中,我们可以使用循环嵌实现池化计算。对于每个池化层,我们需要定义池化窗口的大小和步长,并对卷积层的输出特征图进行池化操作。常用的池化操作有最大池化和平均池化,可以根据需求选择适合的池化方法。 5. 全连接计算:在C代码中,我们可以使用矩阵乘法和激活函数来实现全连接计算。对于每个全连接层,我们需要定义权重矩阵和偏置向量,并对前一层的输出进行矩阵乘法运算,然后通过激活函数进行非线性映射。 6. 输出结果:在C代码中,我们可以将最后一个全连接层的输出结果与标签进行比较,计算损失并进行反向传播。 通过以上步骤,我们可以使用C语言编写Lenet-5模型的HLS实现。在完成C代码编写后,可以使用HLS工具将C代码转化为HDL代码,以便在FPGA上进行硬件加速计算。这样可以实现Lenet-5模型的高效部署和运行,提高模型的执行速度和计算效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

9527华安

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值