PYNQ中实现SoftMax函数加速器
孙齐伟
本文引用地址:http://www.amcfsurvey.com/article/201905/401026.htm(西南交通大学 信息科学与技术学院,四川 成都 611756)
摘要:SoftMax函数通常在深度学习中作为激活函数使用,但其计算涉及自然指数和除法运算,传统PC机上计算较慢,拖累了一个神经网络的训练。本文针对自然指数运算的特点,提出了一种名为基底拆分法的新方法。该方法将SoftMax函数中自然指数计算拆分为多个由查找表实现的特定基底上,通过这种方法,一个复杂的自然指数计算过程即可由查找表过程和乘法过程实现。这种方法有效的降低了硬件复杂度以及逻辑传播延时。由于该方法中使用了自定义的数据结构,因此本文采用了CPU + FPGA的架构,通过合理分工,加速SoftMax函数计算。同时,本文将基于这种方法设计的IP核在PYNQ-Z2开发板上进行了板级调试。
关键词:PYNQ,ZYNQ,SoftMax,AXI总线,异构计算
* 本作品获得第二届“全国大学生集成电路创新创业大赛”全国一等奖
0 引言
Xilinx推出的ZYNQ系列FPGA中嵌入了一颗双核ARM,既能发挥FPGA的定制特性,也能发挥处理器的通用特性,而且两个部分之间接口丰富、官方文档齐全,可玩性极高。同时相应的开发板也很多。传统的ZYNQ开发板(Zedboard等)需要结合vivado和SDK两大工具分别对PL、PS端进行硬件和软件开发。本次我介绍的平台为PYNQ开发板可使用Python将软件操作和硬件控制进行无缝衔接,目前已经出到Z2版本,由依元素进行代理销售,999块极具性价比。
PYNQ是Xilinx一项旨在使用Python和一些lib让SoC开发更加简单的开源项目,以我的理解其本质是Python的一些第三方库,是对PS端操作的封装。传统的ZYNQ开发板也能使其变为PYNQ开发板,当引入Python后就可以使用一些Python中强大的第三方库了例如Numpy、Matplotlib等。
1 SoftMax函数介绍及计算方案介绍
SoftMax 函数是神经网络中的一种输出层函数,计算输出层的值,主要用于神经网络最后一层。其表达式如下所示:
设计中的关键问题是 自然指数的计算 ,传统的方案有:
(1)查表法:同等规格定点数下精度极高,但若要在较大范围上计算需要消耗大量资源。
(2)CORDIC:利用迭代特性,资源复用,占用资源极小,常用于计算器中,但在大规模计算中需要进行流水线化改造,且需要想办法克服最大旋转角度限制的问题。
(3)泰勒级数展开:也即多项式拟合,该法较为灵活,多项式次数越高精度越高,划分区间越细精度越高,是较为常用的方法。
本文针对指数计算的特性,设计了一种原理简单的计算方案,并且通过了板级测试。根据其计算特性称其为基底查表法。
在十进制中,若要计算3.68的自然指数我们可以通过公式(1)分别计算e3,e0.6,e0.08,所以可以事先将需要的自然指数值存在ROM表中,计算时将待计算数字通过基底拆分分别得到个位、十分位、百分位,并作为ROM的寻址地址,最后将查表得到的值进行乘法操作即可得到最终结果。但数字电路中实现十进制取整取余操作时较为复杂的,因此实际使用时对二进制情况进行了优化。
图2为基于二进制移位操作的基底拆分示意图,待计算的16bit数据,高三位表示的是小数点的位置信息,低十三位为数据位。经过左移并按照人为设计的格式输出即可还原数据。这种方法仅采用移位操作进行基底划分,因此硬件结构简单、传播延时小。
工程中设计的IP核内部结构,见图3。
其中的关键流水线如图4。
大致原理就是如此,可以看出这种方法也是很灵活的,可以通过简单地增加ROM和乘法器数量即可扩大计算范围,而且精度可以通过增减ROM表存储的定点数位宽进行改变,乘法器可以使用ZYNQ中的DSP资源来提高性能。本次设计的范围针对[-10,10]。
2 误差结果
测试时分别使用[-10,10],[-5,5]两个区间中4096个点进行误差分析,大致过程如图5。
最后得到的绝对误差图,见图6。
误差在10^-7数量级上,可以说是很小了。
3 IP核接口介绍
深度学习又被称为炼丹,究其原因就是其训练速度较慢,因此考虑深度学习中的加速问题十分有意义。FPGA由于其定制特性,可以通过逻辑门电路十分高效的完成计算过程。
本次我使用FPGA实现了一款AXI接口的激活函数softmax的加速器,并且通过PYNQ开发板对其进行验证同时完成了精度测试。输入输出均为AXI总线形式,内部采用了一个AXI_S和一个AXI_M,其中,输入AXI_S用于ARM端向ip核传递写地址、读地址、数据个数、输出数据16/8bit切换,AXI_M完成对PS端DDR的读写操作,这样设计的目的是为了最大化减小ARM端的工作量,使整个系统更加高效,因为AXI_M可以主动的读写AXI_S并且AXI_S只能被动的被AXI_M进行读写,这个过程设计好后无需ARM端干预。其结构图如图7所示。
因此涉及的操作为 GPIO口操作,AXI写操作,DDR操作。这里原本设计采用ZYNQ上的AXI-HP端口,但是调试时发现该端口在数据格式配置为32 bit时仍采用的64bit数据位,估计是个bug,因此不得不换成AXI-GP端口了。
(1)从ARM引出的两个GPIO一个作为复位信号,另一个作为触发信号
(2)AXI_M接口,用于配置ip核的一些信息。
4 任务划分
为了充分发挥ARM对通用任务的处理特性以及PL的定制特性,本次设计的系统中PS完成了读取数据、数据的定点化和数据移动任务,PL端利用其定制化特性完成计算的加速。整体结构框图如图8。
图中的CPU即为ARM,工作时将模拟输入的数据写入DDR,并且完成定点化工作。图中硬件即为PL端设计的加速器,其工作分为两个阶段,一是计算元素的自然指数值并对其进行求和,二是利用第一个阶段的自然指数值和和做除法求得每个元素的softmax值。
5 PYNQ平台的优势
我的设计在曾在传统的ZYNQ开发板上进行过调试。设计好硬件后需要结合SDK工具对ARM核进行C语言开发,结果最后需要通过串口返回PC机进行处理。
在SDK中返回的数据,返回的数据经过上位机的处理才能得到想要的误差数据,较为繁琐。
但PYNQ不一样,PYNQ上使用了Jupyter可以使用浏览器进行在线Pyhthon编程,而且Python中numpy科学计算库可以只使用3句话就实现softmax的高精度计算,结合pynq的相应库可以实现软件处理和硬件控制的无缝衔接,PL端加载bit文件、PL端控制、软件计算、matplotlib绘制均使用Python完成,最后的结果都可以在网页中显示出来,极其方便。
图中我使用了matplotlib库将软件计算结果与硬件计算结果进行了绝对误差计算,可直接在网页中显示出图像,更加形象化。本次我的设计中,使用PYNQ完成了 从SD卡中读入数据,数据定点化,数据写入DDR,控制PL端进行加速计算,读DDR,将软件结果与硬件结果对比通过误差散点图来测试设计的IP核的精度。
ZYNQ与PYNQ平台的差异可通过对比两个平台的系统框图得到
可以看出,传统ZYNQ通常为裸机开发,而且PYNQ一般为在自身运行的Ubuntu上进行Python开发,因此PYNQ相对而言上手简单加上一些强大的第三方库的支持使用起来也十分方便、有趣。
6 PYNQ使用方法
一些基础操作可以参考官方Get Start我总结有如下步骤:
(1)vivado中设计PL端的硬件结构--PC操作,如图13。
(2)vivado导出设计tcl文件和bit文件--PC操作
write_bd_tcl -force C:/Users/Administrator/Desktop/test.tcl
(3)将tcl文件和bit文件放入PYNQ中--PC操作,如图14。
windows上运行 \pynq 即可通过sdb功能连接PYNQ开发板,进行文件移动
(4)使用Overlay将bit文件进行加载--PYNQPython操作
overlay = Overlay('/home/xilinx/pynq/overlays/softmax/design_1.bit')
至此设计就初始化在PL端,使用Python控制相应外设即可。
7 Python中相关lib的基本使用
1.Overlay
from pynq import Overlayov
overlay = Overlay('/home/xilinx/pynq/overlays/softmax/design_1.bit')
用于加载比特流文件至PL端
2.GPIO
from pynq import GPIO
rst = GPIO(GPIO.get_gpio_pin(0), 'out')
triggle = GPIO(GPIO.get_gpio_pin(1), 'out')
triggle.write(1)
rst.write(1)
rst.write(0)
rst.write(1)
操作PS端的GPIO口,操作的是64bit的PS-PL端的EMIO
3.Xlnk
from pynq import Xlnk
xlnk = Xlnk()
buf = xlnk.cma_array(shape=(num,), dtype=np.uint32, cacheable=0)
addr = buf.physical_address
结合numpy在DDR中分配空间,用于PL端AXI_M使用其中physical_address可以得到DDR中的物理地址在分配空间时,有个cacheable属性,由于PS和PL端都要对DDR进行操作,所以为了防止PS的cache导致读到的数据未被更新,所以通常需要关闭缓存功能。
4.AXI从端操作
myip = overlay.axi_s_control_0
myip.write(0x00,addr)
myip.write(0x04,addr)
myip.write(0x08,num)
myip.write(0x0c,bool_16)
myip.read(0x08)
其中axi_s_control_0是我AXI_S的模块名称,这个是python从导出的原理图tcl文件读出的,因此需要保证tcl和bit文件的一致性,而且需要两者同名
注:这些信息都在上文提到的Get Start连接中可以找到,具体请参考官方的说明。
8 结论
此次借助“全国大学生集成电路创新创业大赛”契机,我们分别在传统ZYNQ和PYNQ平台上完成了SoftMax函数的异构计算加速,获得了比较好的效果。
在传统的ZYNQ平台上开发SoC需要具备数字电路和ARM嵌入式开发知识,比较偏向于底层。反观PYNQ平台,利用Python这一优美的语言对ZYNQ操作的封装极大的降低了开发难度,同时结合Python强大的第三方库,可玩性极高。
当今数字电路工程师仅仅掌握数字集成电路的知识是远远不够的,项目开发更加需要复合型人才。我在项目中采用Verilog作为硬件开发语言,使用HLS做雏形开发,同时使用Python及Matlab进行建模及数据分析,使用的软件工具有Xilinx的VIVADO、ISE,以及Synopsys的DC,ICC,Synplify。可以看出仅仅掌握一门技能是远远不够支撑一个项目的。时代在进步,科技在发展,因此数字IC工程师应该保持住学习的状态,就比如说近几年大火的深度学习,十几年前这个领域还是没有人愿意去碰的,但现在该领域已经让很多停滞不前的方向又迎来新春。
世界上还是存在很多机会的,但机会都是留给有准备的人。
附件:本文设计的softmax ip核在PYNQ运行所需的所有文件https://pan.baidu.com/s/1OuaoS34nIp4Ci96gMCEmug 密码:ifme
本文来源于科技期刊《电子产品世界》2019年第6期第69页,欢迎您写论文时引用,并注明出处
评论