第一部分 设计概述 /Design Introduction
1.1设计目的与应用
随着人工智能的发展,神经网络正被逐步应用于智能安防、自动驾驶、医疗等各行各业。目标识别作为人工智能的一项重要应用也拥有着巨大的前景,随着深度学习的普及和框架的成熟,卷积神经网络模型的识别精度越来越高。有名的LeNet-5手写数字识别网络,精度达到99%,AlexNet模型和VGG-16模型的提出突破了传统图像识别算法,GooLeNet和ResNet推动了卷积神经网络的应用。
但是神经网络的发展也给我们带来了更多挑战,权重参数越来越多,计算量越来越大导致了复杂的模型很难移植到移动端或嵌入式设备中,且嵌入式环境对功耗、实时性、存储都有着严格的约束。因此如何将卷积神经网络部署到嵌入式设备中是一件非常有意义的事情。目前神经网络在传统嵌入式设备上绝大部分是基于ARM平台,神经网络在ARM上部署时存在的巨大问题是算力的不足。GPU主要应用于神经网络训练阶段,对环境和库的依赖性较大,国内技术积累较弱,难以实现技术自主可控。ASIC 是为特定需求而专门定制优化开发的架构,灵活性较差,缺乏统一的软硬件开发环境,开发周期长且造价极高所以基于FPGA的硬件加速平台是时候发挥它的优势了,FPGA由于独特的架构被广泛的应用与实时信号处理、图像处理领域,其并行性也为卷积神经网络提供了巨大算力。
传统的RTL开发FPGA流程相比缓慢,不如软件的开发效率高,所以HLS运营而生,使用高层次语言来进行转换为底层的硬件代码,极大的加快开发进程。因此项目选用HLS工具来实现算法中的加速IP核,将SSD目标检测网络移植到FPGA硬件平台上, 对于硬件加速过程中的算法并行性,在本设计中主要采用两个方式:对层内的运算并行化,将多个通道的数据进行分块,每一块内的通道同时进行运算,最后将结果累加在一起。对于模块的运算采用HLS并行优化,对数组核循环添加优化指令进行优化。整个系统采用PYNQ的软件框架来实现,为SSD目标检测算法提供了硬件加速方案,充分发挥了FPGA的并行性。
1.2 SSD目标检测算法原理
SSD,Single Shot Multi Box Detector,于2016年提出,是经典的单阶段目标检测模型之一。它的精度可以媲美FasterRcnn双阶段目标检测方法,速度却达到了59FPS(512x512,TitanV),单阶段目标检测方法的目标检测和分类是同时完成的,其主要思路是利用CNN提取特征后,均匀地在图片的不同位置进行密集抽样,抽样时可以采用不同尺度和长宽比,物体分类与预测框的回归同时进行,整个过程只需要一步,所以其优势是速度快。
SSD采用的主干网络是VGG网络,VGG是由Simonyan 和Zisserman在文献《Very Deep Convolutional Networks for Large Scale Image Recognition》中提出卷积神经网络模型,其名称来源于作者所在的牛津大学视觉几何组(Visual Geometry Group)的缩写。该模型参加2014年的 ImageNet图像分类与定位挑战赛,取得了优异成绩:在分类任务上排名第二,在定位任务上排名第一。
图1.VGG16网络结构
这里的VGG网络相比普通的VGG网络有一定的修改,主要修改的地方就是:
1、将VGG16的FC6和FC7层转化为卷积层。
2、去掉所有的Dropout层和FC8层;
3、新增了Conv6、Conv7、Conv8、Conv9。
图2.SSD主干网络结构
上图展示了SSD的主干网络结构,整个网络为全卷积网络结构,SSD将VGG16的两个全连接层转换成了普通的卷积层,池化层POOL5由原来的stride=2,kernel大小2x2变成stride=1,kernel大小3x3,为了不改变特征图大小同时获得更大的感受野,Conv6改为空洞卷积,diliation=6,输入的图片经过了改进的VGG网络(Conv1->fc7)和几个另加的卷积层(Conv6->Conv9)进行特征提取。
从图2我们可以看出,SSD将conv4_3、conv7、conv6_2、conv7_2、conv8_2、conv9_2都连接到了最后的检测分类层做回归,6个特征图分别预测不同大小和长宽比的边界框,具体细节如图3。
图3.SSD特征提取网络
SSD为每个检测层都预定义了不同大小的先验框(prior boxes),Conv4_3、Conv8_2和Conv9_2分别有4个先验框,而Conv7、conv7_2和Conv8_2分别有6种先验框,即对应于特征图上的每个像素,都会生成4或6个prior box.
在浅层的神经网络里,只能看到图片的细节和纹理信息,就如管中窥豹。随着网络层数的加深,相当于把图片往后移动一段距离。这样才能够感知到图片的整体信息。低层卷积可以捕捉到更多的细节信息,高层卷积可以捕捉到更多的抽象信息。低层特性更关心“在哪里”,但分类准确度不高,而高层特性更关心“是什么”,但丢失了物体的位置信息。SSD正是利用不同尺度检测图片中不同大小和类别的目标物体,获得了很好的效果。
1.3 作品展示
第二部分 系统组成及功能说明 /System Construction & Function Description
2.1 系统功能
实现了SSD目标检测网络在PYNQ平台上的移植,能够实现人、自行车、汽车、马、飞机等20类目标的检测。输入任意大小图像,能够输出图像中所含目标,并输出目标具体位置。
2.2 系统框图
系统框图如下所示:包含卷积模块、池化模块、L2范数模块。CPU控制各个模块的运行,存取地址,通道数设置等参数,完成整个SSD特征提取网络,并将各个特征层的数据存储在DDR内存中,最后CPU对输出结果进行softmax运算识别出图片中存在的目标种类,并根据输出计算出框图所在的位置。池化模块和L2范数模块是通过AXI-Stream数据流的形式对输入数据进行处理,卷积模块以M_AXI端口同时读取特征数据和权重数据。
2.3 模块划分
卷积模块:
为了提高模块的通用性,对模块的输入参数约束为AXI_LITE的端口,方便CPU对模块进行控制,权重特征及偏置数据连接到3个HP口同时读取数据。具体的参数如下
设置并行数量K=8时,约束最内层循环II=1,最终得到的资源消耗如下表:
当设置并行数量K=32时,约束最内层循环II=1,消耗的资源如下表:
考虑到硬件的资源,最终选择了设置K=8路并行处理。
池化模块:
为了实现流水线的操作,第一步先对输入特征进行横向的池化,两个两个进行比较,留下较大的那个值,第二步再对纵向池化,纵向池化时需要第一行的值进行缓存,再将第二行的值与其比较,可以使用bram来保存中间值。
L2 范数模块
根据范数计算的公式,第一步需要对每个通道像素值平方后累加,再开根号。可以将这个计算以流水线的形式对每个通道的像素值进行累加存放到数组中,这个过程同样可以对多个通道同时操作,增加并行性,等到所有的通道都计算完成后,将所得到的值存入DDR内存地址中,等待下一步使用。
第二步同样使用流水线的形式取出特征像素和上一步中DDR中存放的数据,进行除法操作,之后再写回DDR。这样就完成了整个L2范数流水线的计算。下图分别为K=16和K=32时消耗资源的对比,可以看出当K变大时,消耗的LUT资源变得很大,在项目中由于该模块只使用了一次,因此只将K取为8。
2.4 设计优化
并行设计:
为了提高数据的传输效率和FPGA的并行特性,我们将特征在内存中的排布方式变为下图的方式,其中一个长方体子块代表一个数据子块,位宽为16*K,K的值可以改变。即每次存取特征数据K个通道的像素值,同时存取K个权重子块的数据进行运算,
量化设计
因为FPGA并不比擅长对浮点数进行运算,如果特征和权重数据都使用浮点数则会导致资源的消耗特别厉害,因此为了解决这个问题,采用定点数的形式对所有的数据进行定点化处理。为了获取权重及特征的小数精度,要对训练好的权重数据进行统计,对于不同层的权重使用不同精度的定点数,同时要在前向网络时对数据集中所有数据进行统计,获取每一层特征数据的精度范围,将这些精度保留作为卷积模块的输入参数。在所有模块中的计算都是直接使用定点数进行运算。
下图为提取的部分权重小数点精度和偏置小数点精度,可以发现大部分小数点的位数都很高。所以只需要很少的比特去表示整数位。
2.5 Python 网络搭建
第一步.通过PYNQ调用卷积和池化单元完成主干特征网络的实现
#layer 1
Run_Conv(conv,3,64,3,3,1,1,1,1,0,image,0,vgg1_1w,15,vgg1_1b,14,vgg1_1,5)
Run_Conv(conv,64,64,3,3,1,1,1,1,0,vgg1_1,5,vgg1_2w,15,vgg1_2b,15,vgg1_2,3)
Run_Pool(pool,dma,64,2,2,vgg1_2,vgg1_p)
#layer 2
Run_Conv(conv,64,128,3,3,1,1,1,1,0,vgg1_p,3,vgg2_1w,15,vgg2_1b,15,vgg2_1,2)
Run_Conv(conv,128,128,3,3,1,1,1,1,0,vgg2_1,2,vgg2_2w,15,vgg2_2b,15,vgg2_2,2)
Run_Pool(pool,dma,128,2,2,vgg2_2,vgg2_p)
#layer 3
Run_Conv(conv,128,256,3,3,1,1,1,1,0,vgg2_p,2,vgg3_1w,15,vgg3_1b,15,vgg3_1,2)
Run_Conv(conv,256,256,3,3,1,1,1,1,0,vgg3_1,2,vgg3_2w,15,vgg3_2b,15,vgg3_2,2)
Run_Conv(conv,256,256,3,3,1,1,1,1,0,vgg3_2,2,vgg3_3w,15,vgg3_3b,15,vgg3_3,2)
Run_Pool(pool,dma,256,2,2,vgg3_3,vgg3_cp)
#layer 4
Run_Conv(conv,256,512,3,3,1,1,1,1,0,vgg3_cp,2,vgg4_1w,15,vgg4_1b,15,vgg4_1,2)
Run_Conv(conv,512,512,3,3,1,1,1,1,0,vgg4_1,2,vgg4_2w,15,vgg4_2b,15,vgg4_2,4)
Run_Conv(conv,512,512,3,3,1,1,1,1,0,vgg4_2,4,vgg4_3w,15,vgg4_3b,15,vgg4_3,5)
Run_Pool(pool,dma,512,2,2,vgg4_3,vgg4_p)
#layer 5
Run_Conv(conv,512,512,3,3,1,1,1,1,0,vgg4_p,5,vgg5_1w,15,vgg5_1b,15,vgg5_1,6)
Run_Conv(conv,512,512,3,3,1,1,1,1,0,vgg5_1,6,vgg5_2w,15,vgg5_2b,15,vgg5_2,7)
Run_Conv(conv,512,512,3,3,1,1,1,1,0,vgg5_2,7,vgg5_3w,15,vgg5_3b,12,vgg5_3,7)
Run_Pool_Soft_padding(512,3,3,vgg5_3,vgg5_p)
#exter 1 dilation
Run_Conv(conv,512,1024,3,3,1,1,1,1,1,vgg5_p,7,ex1_1w,15,ex1_1b,15,ex1_1,9)
Run_Conv(conv,1024,1024,1,1,1,1,0,1,0,ex1_1,9,ex1_2w,15,ex1_2b,15,ex1_2,11)
#exter 2
Run_Conv(conv,1024,256,1,1,1,1,0,1,0,ex1_2,11,ex2_1w,15,ex2_1b,15,ex2_1,12)
Run_Conv(conv,256,512,3,3,2,2,1,1,0,ex2_1,12,ex2_2w,15,ex2_2b,15,ex2_2,11)
#exter 3
Run_Conv(conv,512,128,1,1,1,1,0,1,0,ex2_2,11,ex3_1w,15,ex3_1b,15,ex3_1,11)
Run_Conv(conv,128,256,3,3,2,2,1,1,0,ex3_1,11,ex3_2w,15,ex3_2b,15,ex3_2,10)
#exter 4
Run_Conv(conv,256,128,1,1,1,1,0,1,0,ex3_2,10,ex4_1w,15,ex4_1b,15,ex4_1,10)
Run_Conv(conv,128,256,3,3,1,1,0,1,0,ex4_1,10,ex4_2w,15,ex4_2b,15,ex4_2,10)
#exter 5
Run_Conv(conv,256,128,1,1,1,1,0,1,0,ex4_2,10,ex5_1w,15,ex5_1b,15,ex5_1,10)
Run_Conv(conv,128,256,3,3,1,1,0,1,0,ex5_1,10,ex5_2w,15,ex5_2b,15,ex5_2,9)
第二步.对特定检测层卷积得到分类预测和回归预测数据
#Loc
Run_Conv(conv,1024,24,3,3,1,1,1,0,0,ex1_2,11,l2,15,l2b,15,L2,12)
Run_Conv(conv,512,24,3,3,1,1,1,0,0,ex2_2,11,l3,15,l3b,15,L3,12)
Run_Conv(conv,256,24,3,3,1,1,1,0,0,ex3_2,10,l4,15,l4b,15,L4,12)
Run_Conv(conv,256,16,3,3,1,1,1,0,0,ex4_2,10,l5,15,l5b,15,L5,12)
Run_Conv(conv,256,16,3,3,1,1,1,0,0,ex5_2,9,l6,15,l6b,15,L6,12)
#Conf
Run_Conv(conv,1024,126,3,3,1,1,1,0,0,ex1_2,11,c2,15,c2b,15,C2,10)
Run_Conv(conv,512,126,3,3,1,1,1,0,0,ex2_2,11,c3,15,c3b,15,C3,10)
Run_Conv(conv,256,126,3,3,1,1,1,0,0,ex3_2,10,c4,15,c4b,15,C4,10)
Run_Conv(conv,256,84,3,3,1,1,1,0,0,ex4_2,10,c5,15,c5b,15,C5,10)
Run_Conv(conv,256,84,3,3,1,1,1,0,0,ex5_2,9,c6,15,c6b,15,C6,10)
第三部分 完成情况及性能参数 /Final Design & Performance Parameters
(作品已实现的功能及性能指标)
目前作品在功能上已经完成了所预定的功能:实现SSD目标检测网络在PYNQ上的部署,能够做到输入一幅图像,输出图中的目标,并找到目标所在的位置。
因为对特征权重数据使用了量化的方法,大幅度减少了资源的消耗。下图对比了将部分输入参数改为int类型后消耗的资源情况,可以看到消耗的DSP资源是定点数的一倍多。
虽然项目达到了部分预期的效果,但也存在着一些问题,目前虽然对FPGA模块设计了并行计算,但是工作时钟频率却没有达到预期的100MHz,只使用了50MHz,计算一幅图像需要花费好几分钟的时间。下一步的工作希望能够继续学习如何能够提高HLS电路的工作频率,同时进一步提高数据并行的数量,以此来提高目标检测的速度。
免责声明:本文为转载,非本网原创内容,不代表本网观点。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
如有疑问请发送邮件至:bangqikeconnect@gmail.com