姓名:张俸玺 学号:20012100022 学院:竹园三号书院
转自https://blog.csdn.net/qq_38798425/article/details/1070845889
【嵌牛导读】FPGA,可编程门阵列,作为一种较为新型的技术,为大多数人所陌生。如今,用FPGA实现神经网络成为一种热门技术话题。本文对基于FPGA的卷积神经网络实现的池化模块、全连接模块与输出模块进行了简要叙述。
【嵌牛鼻子】FPGA 卷积神经网络
【嵌牛提问】基于FPGA的卷积神经网络实现的池化模块、全连接模块和输出模块是什么?它们是如何作用的?
【嵌牛正文】
github
池化模块应该是最简单的一个模块了,池化要做的就是等待四个数据的投喂,然后吐出去一个数据。这个逻辑是不是看起来很眼熟?没错,这就是卷积模块的逻辑,卷积模块其实就是等待9个数据的投喂(假设卷积核大小是3 × 3 3\times 33×3)然后吐出去一个数据(当然这个数据只是当前通道的数据并不是最终的输出,还需要做一步处理。)
所以整体的逻辑就不再赘述了,这里只说一下池化操作。池化操作有很多种,常用的就是最大值池化和均值池化。最大值池化非常适合FPGA运算,因为仅仅为逻辑运算,比较出一个最大值就好了,这里由于池化的尺寸不大,我们使用组合逻辑在一个时钟内完成池化操作。均值池化涉及到加法操作和除法操作(向右移位操作)。
需要注意的是(感谢L·念同学提出问题),在这个项目中有两个pooling模块,其一是对应的前面所说的卷机组并行。由于卷积模块将会一次性输出足够pooling的数据,无需等待,只需要一个时钟进行比较就可以得到输出。而另一种情况是卷积模块按顺序输出数据,这样就需要每个数据等待一个时钟,因此如果是2 × 2 2\times 22×2的pooling size,那就需要等到后面3个数据的到来。
最后来说说全连接模块。这里事实上就是简化版的卷积模块,因为全连接模块就是大规模矩阵相乘,只需要按顺序把数据和权重输入就好了。这里的优化策略也和卷积层一样,主要是数据复用、DSP复用和快速矩阵乘法。由于全连接层在许多比较先进的模型里面都去掉了,他可以被globel pooling取代,性能无下降且参数量大大下降,我们也不过多讲解,而且看到程序也能看出来写到这部分程序我已经有点暴躁了,大量的组合逻辑胡乱堆砌(捂脸)。事实上我并不建议在程序里面使用FC层,尤其是涉及到FPGA实现的网络模型,FC层真的会在各个方面拖指标后腿,拉胯的不行,既然能够用更easy的方式来实现,何乐而不为呢。
输出分类器我们使用的是softmax分类器,其运算函数如下所示:
有没有发现什么?单调啊!我们输出的是经过这个函数之后的结果比较大小出来的index对吧?不经过这个函数,大小关系也不会变化对吧?所以,这里完全不需要任何计算法,直接比较就好了。为了简单,我在程序里面没有开新的模块,直接就接在了全连接的后面。
结束语。
到这里也就把所有的模块讲解完了,这是一个粗制滥造的demo,既没有做各种优化,甚至都没有按照状态机去写,其本意是得到一个可以作为给低年级学生做效果展示的东西。所以重要的不在于参考我的程序,重要的一定是整个流程,我希望能够帮助其他人来理解做这样一个项目的流程,最主要的是,很多人跟我聊到这件事的时候,产生一种恐惧心理,觉得这应该是一个很复杂的事情,真的很复杂嘛?可能刚开始写的时候不知道从何入手,会觉得很复杂,我第一次写手写数字识别的时候,光是搭一个框架写了一个月,我甚至当时觉得遥遥无期,但是等到我紧急的赶出这个demo的时候,我只需要两周。当然如果需要用到DDR,用到Flash,完美的写出注释,写出工业级代码,按照三段式状态机去写,对代码进行资源优化等,可能还需要更长的时间,但是也不会长多少,这个事情真的不难。
我希望当有人看到了这里能够告诉自己,这东西,很简单,我能行,哪怕只有一个,不像我当年一样,在黑夜中行走,不知终点在何方。