基于FPGA实现YOLO V2模型计算加速实例分析
一. 神经网络基本算子的FPGA实现
1. 加速逻辑方案整体设计
在神经网络加速设计开始之前,需要先确定神经网络的网络结构和各层级参数,避免因在FPGA开发中途修改网络结构或层级参数而造成大量的资源重复投入和延期。前期的网络结构和参数定型阶段可以在通用神经网络开发平台通过GPU或CPU进行算法效果认证,效果符合预期后再进行进一步的FPGA加速设计。
通常,下图所示的神经网络模型和参数分析后,可以把神经网络需要加速计算的任务按计算加速的层级划分为整体神经网络加速、单层神经网络加速、神经网络算子加速三个层次。如下图所示的神经网络算子层通常包含矩阵卷积、矩阵乘法、Hadamard积等基本计算单元;常见单层神经网络通常有卷积层、池化层、全连接层、其他非线性函数层等;整体神经网络可以通过单层神经网络搭建,常见的有LeNet、VGGNet、ResNet等。
YOLO V2网络模型结构:
神经网络加速设计分层示意图:
当然,也可以把神经网络按需要加速任务的灵活性和加速性能的需求不同,分层设计:
(1) 专用神经网络加速。
(2) 可配置神经网络加速。
(3) 神经网络算子加速。
按灵活性和加速性进行分层设计,示意图如加速云三层神经网络加速设计示意图所示,图中L1层为神经网络算子加速,L2层为可配置神经网络加速,L3层为专用神经网络加速。其中,L3层专用神经网络加速性能高,但加速灵活性差;L1层神经网络算子加速灵活性够高,但加速效果相对较差;L2层可配置神经网络加速效果理想,灵活性高。
加速云三层神经网络加速设计示意图:
2. 卷积算子设计
当前大多数深度学习模型中的卷积层运算下式所示:
表示输入通道数为m、输出通道数(也即卷积神经元数量)为n的卷积运算。其特点是:层运算过程中,数据会被多次使用(每个神经元用一次),而卷积参数只参与一次。
下式为特殊情况,表示一个神经元内的多个卷积内核之间参数共享。其特点是:层运算过程中,数据会被多次使用(每个神经元用一次),卷积参数也会多次参与(每个输入数据用一次)。
一个卷积算子设计示例:
PE选择54 × 54的点乘,既可以配置成1个7 × 7的卷积算子,又可以配置成2个5 × 5的卷积算子,还可以配置成5个3 × 3的卷积算子,从而适应不同神经网络层对卷积算子的不同设计需求。
为了平衡卷积算子IP对图像和卷积参数访存带宽的需求,同时也为了提高数据复用性,并充分发挥FPGA内各计算单元的性能,当图像达到一定大小时,需要对数据结构进行必要的分割和调整,可按块分割,也可按行分割,如图所示。
卷积算子设计的数据调整示例:
分割后的图像可以同时送往不同的卷积IP同时计算,下图为卷积算子设计的横向分割计算示意图。
卷积算子设计的横向分割计算示意图:
卷积算子的计算部分通常用FPGA内的DSP资源实现。下图为一个3 × 3卷积算子设计的FPGA实现DSP结构图,其中3 × 3卷积用9个DSP做点乘运算和加法运算。
下图为抽象出的5 × 5点乘计算结构,其中乘法部分使用了5个FPGA内DSP单元,相加部分可以单独调用DSP进行相加,也可以复用乘法部分使用的DSP内部加法器进行相加。
5 × 5点乘计算结构:
下图所示的卷子算子IP通过12个5 × 5点乘算子级联,兼容实现了12个Conv2 × 2、6个Conv3 × 3、3个Conv4 × 4、2个Conv5 × 5、1个Conv6 × 6或者1个Conv7 × 7所需的乘加运算,共计占用60个DSP。
卷子算子IP架构设计示例:
3. 全连接算子设计
全连接层(Fully Connected Layers,FC)在整个卷积神经网络中起到“分类器”的作用。如果说卷积层、池化层和激活函数层等操作是将原始数据映射到隐层特征空间的话,全连接层则起到将学到的“分布式特征表示”映射到样本标记空间的作用。
在实际使用中,全连接的核心操作就是矩阵向量乘积,全连接算子的计算通常就是 m × k维特征图向量与参数矩阵k × n进行矩阵乘法运算,输出为新的m × n维特征图,如下图所示。
全连接算子计算示意图A:
卷积神经网络中全连接层算子在计算时,m大部分等于1,即通常是1 × k维特征图向量与参数矩阵k × n进行矩阵乘法运算,输出为新的1 × n维特征图,如下图所示。
而矩阵乘运算通常在FPGA中采用DSP来实现其乘法和加法部分,下图为5 × 5加乘计算结构,它实现了[a0, a1, a2, a3, a4]与[b0, b1, b2, b3, b4]的点乘求和计算。
其中,乘法部分使用了5个FPGA内DSP单元来实现按点分别相乘,然后将相乘的结果通过5个DSP分级相加来实现求和;相加部分可以单独调用DSP实现,也可以复用乘法部分使用的DSP内部加法器实现,后者可以更高效地利用FPGA内的DSP资源,并可以在相同的芯片上实现更高性能的计算,但对设计者的设计水平和设计经验要求比较高。
4. 池化算子设计
池化层本质上就是对数据进行分区采样,把一个大的矩阵采样成一个小的矩阵。池化层的输入一般来源于上一个卷积层,其可在减小计算量的同时防止过拟合。
在神经网络计算中,常用的池化方法有最大池化和均值池化两种,最大池化即对局部池化域取最大值,均值池化即对局部池化域中的所有值取平均值。下图为2 × 2最大池化和均值池化示意图。
二. FPGA YOLO V2的顶层设计
1. YOLO V2模型简介
经典的目标检测网络RCNN(Regions with CNN features)系列在进行目标检测时分为两步,目标识别和目标分类。Faster-RCNN是把目标识别和目标分类作为一个网络的两个分支分别输出,从而大大缩短了计算时间;而YOLO系列则把这两个分支都省了,只用一个网络同时输出目标的位置和分类。YOLO把每张图片分成S × S个方格,对每个方格输出一个B × 5 + C维的数组。
YOLO V2是YOLO V1的升级版本,是为了提高物体定位的精准性和召回率,该模型应用时的简化过程如下图所示。相比于YOLO V1,YOLO V2提高了训练图像的分辨率,引入了Faster-RCNN中的思想(Anchor box),对网络结构的设计进行了改进,其输出层使用卷积层替代YOLO的全连接层,并联合使用COCO物体检测标注数据和ImageNet物体分类标注数据训练物体检测模型。YOLO V2在继续保持处理速度的基础上,在预测更准确(Better)、速度更快(Faster)、识别对象更多(Stronger)这三个方面进行了改进。YOLO V2网络结构具体的改进列表如下表所示。
YOLO V2模型示意图:
YOLO V2网络结构改进列表:
经过网络结构改进后,得到的YOLO V2网络在小尺寸图像检测中的成绩优秀,输入为228像素 × 228像素时,检测帧率达到90FPS(Frame Per Secend,每秒帧率),mAP(mean Average Precision,平均精度)几乎和Faster-RCNN的水准相同,这使得其在低性能GPU、高帧率视频、多路视频场景中更加适用。在大尺寸图像检测中,YOLO V2达到了先进水平,在VOC2007 上mAP为78.6%,仍然高于平均水准,而且检测的种类有9000多种。下图是Pascal VOC2007上YOLO V2和其他网络的成绩对比。
在VOC2012上对YOLO V2网络进行训练,YOLO V2的精度达到了73.4%,并且速度更快。同时和Faster -RCNN、SSD、ResNet进行对比,YOLO V2的成绩同样非常优秀。下图是YOLO V2在Pascal VOC2012上的成绩与其他网络的成绩对比。
2. OLO V2模型结构
大多数目标检测的框架是建立在VGG16基础上的,VGG16在ImageNet上能达到90%的top5(准确度排在前五的数值),但是单张图像需要30.69 billion 浮点运算。YOLO V2是依赖于DarkNet19的排名前五的类别包含实际结果的准确率结构,该模型在ImageNet上能达到91%的top5,并且单张图像只需要5.58 billion 浮点运算。DarkNet的结构图如下图所示。
本次的YOLO V2是基于大小为224 × 224的图像,其网络模型及参数如下图所示。
3. YOLO V2的FPGA实现设计
YOLO V2网络主要由23个卷积层、5个池化层和1个Softmax层组成。整个YOLO V2网络在FPGA内部实现的整体结构如下图所示。
FPGA顶层设计:
FPGA YOLO V2系统上电后,整体动作流程如下:
(1) 系统启动后,PC软件启动时通过PCIEL PeripheraL(Component Interconnect Expree, 一种高速串行计算机扩展总线标准)接口将YOLO V2算法中每一个卷积层的卷积核参数预存至DDR4中,并设置系统寄存器,完成初始化操作。
(2) PC软件启动计算时,先以3帧图像为一组(图像大小为224 × 224)将图像数据写入到FPGA内部的图像数据缓存中,然后启动FPGA系统进行运算。FPGA在完成YOLO V2网络所有层的计算后,再将计算结果上传给软件。
3) 当上层软件检测到FPGA内部的图像缓存区为空闲状态时,会继续将图像数据更新至缓存中,使FPGA系统再次启动新一轮的计算。
其流程示意图如图所示:
三. FPGA YOLO V2的模块设计
YOLO V2一般包含卷积、偏置、归一化/缩放/激活、池化、Softmax五种处理,前四种处理基本每层都有,只是参数不同。因此,可以设计一个通用模块来完成这四种处理,再配合一个数据双向缓存来进行各层计算,如下图所示。
FPGA YOLO V2模块设计示意图:
1. 卷积
1 × 1的卷积较为简单,以下主要讨论3 × 3的情况(5 × 5、7 × 7的情况其方法类似),下图所示。
上图中,输出图像的每个数据由3 × 3个输入数据和3 × 3个系数做点乘得到。每个3 × 3的系数窗口对输入图像做2D滤波(系数窗口在图像上滑动),重复计算多个滤波器组,可得到相应的输出结果,如图:
3 × 3卷积必须适应不同大小的图像,同时并行度也要可变:
适应图像大小的卷积原理:
点乘是矩阵运算的一个基本单元,3 × 3卷积就是一个9维点乘。n维点乘由n次乘法和n-1次加法组成,其示意图如下:
采用脉动结构可以提升FPGA实现的效率,Intel在设计软件中提供了点乘的IP,支持定点和浮点两种结构,如图:
卷积的实现可以调用Quartus自带的IP实现,下图所示。
其具体流程为:
(1) 调用altera_fp_functions IP;
(2) 选择Scalar Product函数;
(3) 根据滑窗的大小,设置输入的向量个数(3 × 3,输入为9);
(4) 产生 HDL后,在设计中就可以直接调用。
2. YOLO V2偏置、归一化/缩放/激活
除了卷积,YOLO V2的每个层还需要做偏置、归一化/缩放/激活等处理,如图7-30所示。由于FPGA的DSP模块是先乘后加结构,为了节省资源,必须将如下算法进行合并,以匹配FPGA的DSP结构。
FPGA的DSP结构
对应归一化、缩放和偏置,按如图7-31所示方式合并,v1和bia1为转换后FPGA输入的参数。
偏置/缩放/归一化函数的实现可以调用Quartus自带的IP实现,如图所示。
调用Quartus自带的IP实现偏置/缩放/归一化函数:
其具体实现流程为:
(1) 调用altera_mult_add IP;
(2) 设置乘和加的参数(有无预加、累加、级联……);
(3) 设置输入、输出的寄存模式和流水级数;
(4) 产生 HDL后,在设计中就可以直接调用。
3. 激活函数
激活函数的实现可以调用Quartus自带的IP实现,如图所示。
其具体实现流程为:
(1) 调用altera_fp_functions:Exp/Log/Pow;
(2) 通常选择指数函数;
(3) 设置性能、资源参数;
(4) 产生HDL后,在设计中就可以直接调用。
例如,以常见的激活函数Sigmoid为例:
四. FPGA YOLO V2的系统和RTL仿真
如图所示,设计者先用深度学习工具(TensorFlow/Caffe)对YOLO V2进行训练,得到相应各层的图像数据和权重,然后在MATLAB中用基于Intel提供的FPGA工具DSP Builder进行YOLO V2的算法建模,完成后可用 Simulink 做算法仿真以及用ModelSim做RTL仿真。
下图显示了基于DSP Builder的通用算法设计流程,设计者可以在MATLAB中搭建YOLO V2的模型(第一步);完成算法仿真和性能优化后(第二步),可以产生Quartus工程;编译后,即可下载到FPGA板上进行调试(第三步)。
五. FPGA YOLO V2系统时序优化
下表是YOLO V2网络在Intel Arria 10芯片上所使用的资源量。
另外,还可以通过优化RTL的设计,提高FPGA内部的吞吐率和降低信号线的延时。
(1) 吞吐率:系统每一个时钟周期能够处理的数据数量。为了获得更高的吞吐率就需要减少组合逻辑延时,在组合逻辑中间插入寄存器,也就是流水线设计。
(2) 延时:数据从输入系统到输出系统总共需要的时间。为了获得更短的延时,可以减少组合逻辑延时,或者删减路径上的寄存器。第二种方法显然不利于系统获得更好的性能。
1. 插入寄存器
插入寄存器(Pipeline)即在数据传输的过程中,让数据经过多级触发器,并减小数据在触发器单元之间的连线长度。此方法会增加信号的时滞(Clock Latency),会导致结果输出延长几个周期,但插入几个寄存器后,降低了寄存器之间信号的延时,使系统能在更高频率时钟下正确运行,在不违反设计规格以及功能不受影响的情况下可以这么做,如图所示。
插入寄存器:
2. 并行化设计
并行化设计的思想是将一个逻辑函数分解为几个小一些的逻辑函数进行并行计算,从而减少关键路径上的延时,如下图所示。
并行化设计:
综合结果如图所示:
3. 均衡设计
均衡设计的思想是把关键路径上的组合逻辑取出一部分放在最短线路(Short Path)上,从而缩短关键路径的延时。
4. 减少信号扇出
较大扇出同样会增加信号路径延时。为提升系统性能,合理地控制信号的扇出能够有效减小信号的延时,如图所示。
减少信号扇出示意图:
5. 优化数据信号路径
通过优化数据流的路径可缩短关键路径,并可提升系统性能。重新布局和关键路径在一起的路径,从而使关键路径上的逻辑门可以更靠近目标寄存器。
六. 性 能 对 比
1. S10 的检测流程
一块插有FPGA板卡的计算机可以看作一个“异构计算装置”,即在同一台计算机系统中有两种以上架构差异很大的计算装置。常见的计算装置包括CPU、GPU、协处理器、DSP、ASIC、FPGA等。
例如,一般的计算都是在CPU上进行的,但是当处理大量图像数据时,CPU的架构设计限制了其同时处理大量数据的能力;而FPGA板卡的“并行处理”可以极大地加速数据的处理速度。例如,一帧图像如果按照传统的处理方式,则是按像素来处理的;但是当并行处理时,它被分解成不同的区域,由不同的进程同时进行处理,然后将处理后的结果按照之前的分割方式拼凑在一起。处理过程虽然变复杂了,但是大大提高了效率。
使用FPGA进行处理时,首先将训练好的权重转换成二进制文件保存到指定路径,将预处理好的数据直接送给FPGA的检测接口。S10板卡开启三个线程,第一个线程将图像送入板卡进行检测;第二个线程读取板卡的检测结果,并将其保存在内存列表中,返回给Demo程序;第三个线程从列表中读取检测结果进行非极大值抑制(Non Maximum Suppression,NMS),去除多余的和得分很低的检测框,然后对检测结果进行可视化。这部分的编程采用“混合编程”,利用C++ 对图像进行读取处理,而Python端进行结果的转换和展示。其整体流程如图所示。
S10板卡的检测流程:
2. 检测结果
FPGA板卡检测的权重是由GPU训练好并转换得到的,因此两者在检测精度上没有太大的差别。具体的检测案例可视化结果如图所示。
基于GPU和FPGA板卡的YOLO V2的目标检测案例可视化结果:
3. 与GPU的性能对比
在FPGA板卡不丢失检测精度的情况下,我们主要对比S10和GPU在性能和功耗方面的差异。S10三通道板卡的主频为200 MHz,芯片集成2753 KLE和9.2T Flops单精度浮点处理能力,最大支持64 GB DDR4内存容量,支持153.6 GB/s的访问带宽。此时,板卡的功率维持在80 W左右,板卡温度在38℃左右,可以持续长时间工作。而显卡GeForce GTX1080的显存频率为10 GHz,拥有2560个CUDA处理器,单精度浮点运算能力是9T Flops,拥有8 GB GDDR5X显存,显卡位宽为256b,带宽为320 GB/s。
对比时,为了忽略不同计算机在内存读取方面的差异性,我们首先将一张超大的遥感图像读入内存,然后进行滑块分割后送给检测网络检测。例如对要进行检测的大小为23 618 × 10 064像素的图像进行“有重叠的分割”,分割成大小为300 × 300像素的小图,滑窗移动的步长为200,得到的小图的数量为3773。S10和GPU的性能对比如表所示。