目录:
1 关于LeNet-5
2 视频演示效果
3 演示环境、算法功能、系统框图
4 FPGA实现LeNet-5推理模块的底层指标
5 识别效果测试与评述
6 大模型深度参与研发流程
正文:
1 关于LeNet-5
笔者近期在大模型的帮助下,用FPGA实现了LeNet-5的推理。
LeNet-5是经典的CNN(卷积神经网络),早期CNN的重要里程碑,用于识别图像中的手写数字字符0~9。
LeNet-5的结构简单但非常典型,仅有8层(输入层、卷积1层、池化1层、卷积2层、池化2层、全连接1层、全连接2层、输出层),各层的规模也不大,适合用于演示CNN的基本功能,适合用于实测验证CNN在FPGA上的可实现性。
2 视频演示效果
以下是用于闭环验证的实测演示视频(注意,网线已经拔掉了):
LeNet-5
01:19
基于FPGA实现LeNet-5推理的闭环验证实测视频(七段码是识别结果)
3 演示环境、算法功能、系统框图
如视频所示,FPGA开发板的摄像头插卡(插在板子上沿左侧的双排针座上)上有摄像头,摄像头采集到的视频数据流(其中屏幕上的蓝色数字是笔者操作鼠标在Windows11的“画图”软件上以粗笔+放大模式写的)由FPGA接收;笔者用VerilogHDL编写算法功能,从摄像头提供的视频图像(480x272/60Hz)中基于像素的色彩特征而识别、切分出字符区域,再将字符区域缩小为28x28的像素块、二值化为0、255的黑白图像、输入到FPGA内部的LeNet-5推理网络的入口。
FPGA内部的LeNet-5推理网络执行各层运算,得到识别结果(0~9),发送给FPGA内部的七段码生成与插入模块,由这个模块将识别结果转化为图像中固定区域的七段码,并且将七段码区域插入视频图像中预设的位置,输出到插在FPGA开发板上的LCD屏(插在板子上沿右侧的双排针座上)予以显示。
闭环验证演示环境系统框图如图1所示:
图1 基于FPGA实现LeNet-5的闭环验证演示环境系统框图
其中,蓝色模块是笔者写的,橙色模块借用自FPGA开发板厂商提供的Demo工程。
4 FPGA实现LeNet-5推理模块的底层指标
图2是FPGA(型号:XC7A100T-2FGG484I)实现的LeNet-5推理模块的资源占用量(图中的fc3层就是输出层):
图2 FPGA实现的LeNet-5模块的资源占用量
FPGA实现的LeNet-5模块工作在252MHz,经仿真测试,其传输延迟(自28x28点阵的最后一个像素输入到识别结果输出)是97.6us。
如图2所示,各层仅做了最基础的矩阵点乘并行化,采用更多乘法器可以在此基础上降低传输延迟。
5 识别效果测试与评述
实际识别的效果比演示视频要差一些。经测试10组手写字符(每组都是0~9),识别正确率80%。其中1错的次数最多,6次;然后是6,5次。
对于识别错误的字符,笔者用ILA抓取了加载到LeNet-5推理模块入口处的28x28像素点阵,将其加载到用于验证LeNet-5推理原始算法有效性(以及训练得到的网络参数集有效性)的MATLAB算法模块(此模块从MNIST测试数据集中随机选取1000对图像-标签进行验证的准确率是94.6%),计算得到的识别结果也是错误的,并且与视频中误识别的结果一致。
由此证明:实测过程中的误识别是由LeNet-5推理原始算法或(/和)训练得到的LeNet-5网络参数集(训练算法可能有缺陷)导致的,与FPGA对原始算法的实现无关。
目前分析,正确率较低的原因可能是:
1)MNIST数据集的原始数据采集工作在美国完成,我个人的书写习惯可能与数据集是书写者存在一定的差距。
2)用鼠标以放大模式在“画图”软件写字的笔画线条及其边缘存在很多曲折(不同于MNIST数据集中的日常手写笔画),导致在推理过程中形成了非预期匹配的特征。
3)采集的视频图像噪声比较多(已经在算法上采取了初步的补救措施)导致笔画像素的确认及字符区域切分存在较大误差。
笔者做这个项目的主旨是验证用FPGA实现CNN的可行性,网络参数的训练、验证并非所长,交由大模型编写代码完成。所以,当前的项目工作进度止于验证FPGA识别结果与原始的MATLAB算法模块的识别结果相同,进一步提升识别正确率的工作暂停。
6 大模型深度参与研发流程
笔者起意做这个项目,最大的堵点在于如何获取LeNet-5的网络参数,只要有了参数,CNN网络的FPGA实现只是个工作量问题。
于是,笔者在网上检索了相关的资料,借助大模型找到了训练、测试LeNet-5网络所用的MNIST数据集,然后用大模型编写、调试Python代码,基于MNIST训练数据集完成了28x28输入像素(无填充)的LeNet-5网络训练,得到了LeNet-5的网络参数。
在后续的算法(及网络参数)的有效性验证阶段、FPGA实现阶段,大模型也起到了非常重要的作用。
其中,笔者尝试用大模型写了几个VerilogHDL代码模块,初步的结论是:
简单模块写的效果还可以,经过反复修改需求、调试、纠错,得到的代码是可以用的。即,在设计者具备一定的系统视角与代码调试能力的前提下,在特定情况下的确可以减少简单模块耗费的工作时间。
对于复杂一些的、要求进行比较特殊的功能优化(例如在特定条件触发下、以特定方式预读取缓冲区)的模块,大模型对设计意图的理解能力有限,写出来的代码的bug乃至根本性错误比较多,从而导致调试、验证的工作量不可控 -- 当然,不排除是笔者的能力有限导致了这一结果。
在后期的在板联调、错误排查与纠正工作中,将大模型作为中间工具、进行数据分析的效果也很显著。