鄧 良,陳章進(jìn),2,喬 棟,屠程力
1(上海大學(xué) 微電子研究與開發(fā)中心,上海 200444)2(上海大學(xué) 計(jì)算中心,上海 200444)
E-mail:1593481663@qq.com
隨著近年來(lái)大數(shù)據(jù)的爆發(fā)與計(jì)算機(jī)性能的飛躍式的提升,人工智能的研究重新變得火熱起來(lái),神經(jīng)網(wǎng)絡(luò)算法已經(jīng)被廣泛應(yīng)用于圖像處理[1]、人臉識(shí)別[2]、語(yǔ)音識(shí)別[3]等場(chǎng)景.隨著神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)的不斷加深,對(duì)運(yùn)算平臺(tái)的資源與計(jì)算能力要求越來(lái)越高,使得通用處理器對(duì)于網(wǎng)絡(luò)模型的運(yùn)算越來(lái)越吃力.目前針對(duì)神經(jīng)網(wǎng)絡(luò)模型進(jìn)行加速的方案主要有3種:1)使用圖像處理器GPU進(jìn)行模型計(jì)算的加速,但存在著功耗高,難于集成等缺點(diǎn),只適合于大型運(yùn)算平臺(tái)或云端服務(wù)器;2)使用專用集成電路進(jìn)行模型計(jì)算的加速,具有更高性能、更低功耗的特點(diǎn),但存在設(shè)計(jì)周期長(zhǎng)、開發(fā)成本高等缺點(diǎn);3)使用FPGA進(jìn)行模型計(jì)算的加速,具有低功耗、開發(fā)周期短、靈活性高等特點(diǎn)[4],逐漸成為目前研究神經(jīng)網(wǎng)絡(luò)加速的熱門平臺(tái).
2011年Farabet等[5]人提出了一種基于FPGA的卷積神經(jīng)網(wǎng)絡(luò)處理器,該處理器在計(jì)算時(shí)可重構(gòu)數(shù)據(jù)流,包含了多個(gè)計(jì)算單元.2013年P(guān)eenmen M等[6]人在Virtex6 FPGA上實(shí)現(xiàn)了卷積神經(jīng)網(wǎng)絡(luò)的加速,使用MicroBlaze軟核處理器作為控制器.2014年Gokhale V等[7]人使用Xilinx ZYNQ FPGA設(shè)計(jì)了一種卷積神經(jīng)網(wǎng)絡(luò)加速器,該方法使用8路并行的計(jì)算單元,每個(gè)計(jì)算單元能夠進(jìn)行最大10×10的卷積計(jì)算.2016年Motamedi M等[8]人提出了輸出間并行、卷積核間并行和卷積核內(nèi)并行3種可行的并行計(jì)算方法,詳盡的總結(jié)了卷積層并行計(jì)算的設(shè)計(jì)方案.2017年Yu 等[9]人使用Winograd算法[10]實(shí)現(xiàn)卷積運(yùn)算,減少了模型計(jì)算過(guò)程中乘法器的使用數(shù)量,提高了計(jì)算的并行度,但Winograd算法通常只適用于較小的卷積神經(jīng)網(wǎng)絡(luò)模型.2019年曾成龍等[11]人提出了一種單計(jì)算引擎的神經(jīng)網(wǎng)絡(luò)加速器的設(shè)計(jì)方案,只使用單個(gè)計(jì)算引擎進(jìn)行實(shí)時(shí)配置實(shí)現(xiàn)不同卷積神經(jīng)網(wǎng)絡(luò)層的計(jì)算,大大減小對(duì)FPGA資源的消耗.
這些研究工作主要關(guān)注于對(duì)并行設(shè)計(jì)空間的探索,嘗試通過(guò)使用多計(jì)算單元計(jì)算,數(shù)據(jù)分塊與并行,使用流水計(jì)算等方法提高設(shè)計(jì)的并行度,往往需要消耗大量的資源,而沒(méi)有全面考慮到對(duì)FPGA資源的合理利用,基于FPGA的神經(jīng)網(wǎng)絡(luò)加速架構(gòu)主要有數(shù)據(jù)流處理架構(gòu)和單計(jì)算單元架構(gòu)2種[12].數(shù)據(jù)流處理架構(gòu)通常是在FPGA上實(shí)現(xiàn)神經(jīng)網(wǎng)絡(luò)模型的全部層,數(shù)據(jù)從實(shí)現(xiàn)這些層的電路中流過(guò)就完成了一次計(jì)算,因?yàn)槊恳粚拥碾娐方Y(jié)構(gòu)都經(jīng)過(guò)精心的設(shè)計(jì),能夠?yàn)槊恳粚屿`活的配置資源,提高計(jì)算的性能.但是當(dāng)計(jì)算不同的神經(jīng)網(wǎng)絡(luò)模型時(shí),需要重新配置FPGA,并且這種方法對(duì)FPGA設(shè)備的資源要求很高,對(duì)于大型的神經(jīng)網(wǎng)絡(luò)模型,很難進(jìn)行部署.單計(jì)算單元架構(gòu)的加速器通過(guò)對(duì)計(jì)算單元的配置來(lái)實(shí)現(xiàn)神經(jīng)網(wǎng)絡(luò)中不同層的計(jì)算,按照一定的配置順序就能實(shí)現(xiàn)整個(gè)神經(jīng)網(wǎng)絡(luò)的計(jì)算,當(dāng)計(jì)算不同的神經(jīng)網(wǎng)絡(luò)模型時(shí),只需要改變配置順序即可,與數(shù)據(jù)流處理架構(gòu)相比,盡管達(dá)不到最佳的計(jì)算性能,但占用資源少,靈活性與通用性強(qiáng).
本文基于FPGA平臺(tái)提出一種自定義指令集的神經(jīng)網(wǎng)絡(luò)處理器的設(shè)計(jì)方案,指令集包含了16條的運(yùn)算指令,該處理器使用128位寬的指令來(lái)控制實(shí)現(xiàn)不同計(jì)算操作,對(duì)卷積與池化系列的計(jì)算電路進(jìn)行復(fù)用,減少對(duì)FPGA資源的消耗,使用流水線CORDIC算法[13]實(shí)現(xiàn)激活函數(shù)的計(jì)算,同時(shí)本文設(shè)計(jì)了一種多端口讀寫控制模塊,處理器通過(guò)該模塊實(shí)現(xiàn)對(duì)總線數(shù)據(jù)的讀寫.
卷積神經(jīng)網(wǎng)絡(luò)[14]是神經(jīng)網(wǎng)絡(luò)中最常用到的網(wǎng)絡(luò)之一,卷積神經(jīng)網(wǎng)絡(luò)模型通常包括:卷積層、池化層、激活函數(shù)計(jì)算、全連接層等.卷積神經(jīng)網(wǎng)絡(luò)每一層的輸入通常都是一個(gè)三維矩陣,分別定義為:長(zhǎng)、寬、深度,深度有時(shí)也被表述為通道數(shù).圖1是一種常見(jiàn)的卷積神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu).

圖1 卷積神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)圖Fig.1 Convolutional neural network structure
2.1.1 卷積層運(yùn)算模型
卷積層的作用是為了提取輸入圖像的某些特征,并輸出一個(gè)新的特征圖作為下一層的輸入圖像,計(jì)算的過(guò)程通常為先卷積再經(jīng)過(guò)一個(gè)激活函數(shù)得到結(jié)果.卷積層存在4種卷積的實(shí)現(xiàn)方式:直接卷積、展開式卷積[15]、Winograd卷積和快速傅里葉卷積[16].本文中使用直接卷積的方法進(jìn)行計(jì)算.直接卷積使用卷積核與在圖像上截取到的相同尺寸的圖像進(jìn)行累乘和累加計(jì)算,計(jì)算的數(shù)學(xué)表達(dá)式為:

(1)
其中f(·)是非線性激活函數(shù),βfi表示偏移值,O(x,y)表示輸入特征圖坐標(biāo)(x,y)處的值,w(kx,ky)表示卷積核坐標(biāo)(kx,ky)上的權(quán)重值,In(x+kx,y+ky)表示輸出特征圖坐標(biāo)(x+kx,y+ky)上的值;kx,ky表示卷積核的大小,fi表示第i幅輸入特征圖,Nfi表示輸入特征圖的數(shù)目.
2.1.2 池化層運(yùn)算模型
池化層也被稱為下采樣層,通常被放置在卷積層后,根據(jù)不同的采樣規(guī)格分為最大池化與平均池化.池化層的作用是提取特征圖的局部特征,并對(duì)特征圖進(jìn)行降維,減少模型的計(jì)算時(shí)間.最大池化的表達(dá)式為式(2),平均池化的表達(dá)式為式(3):
(2)
(3)
式(3)中的fout表示輸出圖像(i,j)位置的值,fin表示輸入圖像中(i,j)位置的值,p表示池化核的尺寸.
2.1.3 激活函數(shù)介紹
激活函數(shù)能夠?qū)斎氲募?lì)進(jìn)行非線性轉(zhuǎn)換,通常跟在卷積層之后,使用激活函數(shù)能夠使網(wǎng)絡(luò)的表達(dá)能力變得更強(qiáng)大,而不是只能簡(jiǎn)單的進(jìn)行線性表達(dá).常用的激活函數(shù)有Sigmoid函數(shù)、Tanh函數(shù)和ReLu函數(shù),它們的表達(dá)式分別為式(4)、式(5)、式(6).
(4)
(5)
Relu=max(0,x)
(6)
本文中卷積層使用直接卷積的方法進(jìn)行計(jì)算,直接卷積需要在輸入圖像上進(jìn)行劃窗操作,再將窗口截取到的矩陣與卷積核進(jìn)行逐點(diǎn)累乘與累加,最后的累加值作為一次卷積的輸出值,隨著窗口在圖像上的滑動(dòng),最終完成對(duì)圖像的卷積計(jì)算.池化計(jì)算與卷積計(jì)算類似,也需要在輸入圖像上進(jìn)行劃窗操作,但截取到的窗口矩陣不再進(jìn)行累乘和累加計(jì)算,而是根據(jù)相應(yīng)的采樣規(guī)則計(jì)算窗口矩陣的值.由于卷積與池化都包含了劃窗這個(gè)操作,因此本文對(duì)電路進(jìn)行復(fù)用,通過(guò)信號(hào)*arith_type來(lái)控制實(shí)現(xiàn)卷積與池化功能.
為實(shí)現(xiàn)劃窗操作,首先需要對(duì)輸入圖像進(jìn)行行緩存,當(dāng)緩存所需窗口尺寸的行數(shù)后,再按列進(jìn)行輸出,即可實(shí)現(xiàn)開窗的操作,隨著圖像數(shù)據(jù)的串行輸入,最終達(dá)到劃窗的效果.由于卷積與池化計(jì)算的輸入圖像尺寸是不確定的,不能采用常規(guī)的條狀移位寄存器來(lái)進(jìn)行行緩存,本文中使用雙端口RAM來(lái)實(shí)現(xiàn)窗口的構(gòu)造,圖2是卷積與池化運(yùn)算模塊設(shè)計(jì)框圖.將雙口RAM進(jìn)行首尾相連,當(dāng)一個(gè)RAM緩存輸入圖像寬度個(gè)數(shù)據(jù)后,開始從當(dāng)前RAM讀取數(shù)據(jù)并寫入到下一個(gè)RAM中,當(dāng)最后一個(gè)RAM也緩存輸入圖像寬度個(gè)數(shù)據(jù)后,將所有RAM中的數(shù)據(jù)按列一拍一拍的輸出,同時(shí),圖像繼續(xù)串行輸入,從而實(shí)現(xiàn)劃窗的操作.由于圖像的數(shù)據(jù)是串行輸入的,導(dǎo)致開窗后的數(shù)據(jù)矩陣與真正需要計(jì)算的矩陣是倒置的,因此需要將開窗截取到的數(shù)據(jù)矩陣進(jìn)行一次重映射,重映射后的數(shù)據(jù)矩陣就是正確開窗后的矩陣.卷積核配置通過(guò)寫入模塊根據(jù)相關(guān)信號(hào)的控制,配置寄存器的個(gè)數(shù),形成卷積核矩陣,將從外部存儲(chǔ)器中讀取到的權(quán)重值按照順序?qū)懭氲郊拇婢矸e核矩陣中.當(dāng)卷積核與卷積域的數(shù)據(jù)都存放到相應(yīng)的寄存器后,將存放權(quán)重的寄存器矩陣與存放圖像數(shù)據(jù)的寄存器矩陣進(jìn)行逐點(diǎn)乘法計(jì)算,將計(jì)算后的值存放到一個(gè)加法樹寄存器矩陣中.當(dāng)逐點(diǎn)乘法運(yùn)算完成后,對(duì)加法樹矩陣進(jìn)行基2加法樹運(yùn)算,即每相鄰的兩個(gè)寄存器的值相加放到下一層的加法樹寄存器中,通過(guò)層層的加法運(yùn)算,最終求得加法樹矩陣中所有值的和,即為一次窗口卷積的結(jié)果,配合前邊的劃窗操作,最終實(shí)現(xiàn)對(duì)圖像的卷積計(jì)算.

圖2 卷積與池化模塊設(shè)計(jì)框圖Fig.2 Convolution and pooling module design block diagram
對(duì)于池化運(yùn)算,其劃窗操作與卷積運(yùn)算的劃窗操作相同,只需要對(duì)卷積核中的數(shù)值進(jìn)行配置即可實(shí)現(xiàn)池化運(yùn)算.當(dāng)執(zhí)行最大池化運(yùn)算時(shí),通過(guò)卷積核配置模塊將卷積核寄存器中的值都配置為1,同時(shí)基2加法樹運(yùn)算陣列不再是(a+b)運(yùn)算,而是執(zhí)行max{a,b}運(yùn)算;當(dāng)執(zhí)行平均池化運(yùn)算時(shí),通過(guò)卷積核配置模塊將卷積核寄存器中的值都配置為1,基2加法樹陣列執(zhí)行(a+b)運(yùn)算,將最終的累加和使用定點(diǎn)除法器求商,作為最后的池化結(jié)果.當(dāng)執(zhí)行卷積計(jì)算與最大池化運(yùn)算時(shí),除法器的除數(shù)設(shè)置為1.
為了使卷積神經(jīng)網(wǎng)絡(luò)的表征能力更強(qiáng),通常會(huì)在卷積計(jì)算之后使用激活函數(shù)進(jìn)行非線性映射,常見(jiàn)的激活函數(shù)包括了:Sigmoid函數(shù)、Tanh函數(shù)和ReLU函數(shù).本文基于CORDIC算法設(shè)計(jì)了一種流水線結(jié)構(gòu)的激活函數(shù)計(jì)算模塊.激活函數(shù)計(jì)算過(guò)程中最復(fù)雜的就是指數(shù)計(jì)算,以exp指數(shù)計(jì)算為例,闡述基于CORDIC算法的流水線結(jié)構(gòu)的激活函數(shù)計(jì)算模塊的設(shè)計(jì)原理.CORDIC算法的迭代表達(dá)式為式(7).其中θk表示第k次旋轉(zhuǎn)的角度,dk表示第k次旋轉(zhuǎn)的方向,x,y表示坐標(biāo),z表示角度值.
(7)


圖3 流水線CORDIC算法實(shí)現(xiàn)框圖Fig.3 Pipeline CORDIC algorithm implementation block diagram
卷積神經(jīng)網(wǎng)絡(luò)中的Sigmoid函數(shù)和Tanh函數(shù)可以通過(guò)式(4)和式(5)的指數(shù)運(yùn)算得到.因此為了實(shí)現(xiàn)Sigmoid函數(shù)與Tanh函數(shù)的流水線型計(jì)算,需要額外增加流水線型除法器.針對(duì)不同級(jí)的流水,通過(guò)CORDIC算法計(jì)算激活函數(shù)所消耗的資源,實(shí)現(xiàn)的精度有所不同,需要在精度與消耗的資源之間進(jìn)行衡量.根據(jù)實(shí)驗(yàn)測(cè)試發(fā)現(xiàn),選擇10級(jí)流水的CORDIC算法實(shí)現(xiàn)Sigmoid函數(shù)與Tanh函數(shù)的效果最好.
為了能夠?qū)Σ煌愋偷木矸e神經(jīng)網(wǎng)絡(luò)進(jìn)行加速計(jì)算,本文設(shè)計(jì)了一種基于指令集架構(gòu)的神經(jīng)網(wǎng)絡(luò)協(xié)處理器,圖4為處理器的整體框圖.處理器采用指令的形式進(jìn)行控制與計(jì)算,每一條指令的運(yùn)算結(jié)果都以二維矩陣為粒度,每一行的運(yùn)算結(jié)果都緩存在片上RAM中并最終寫入到片外存儲(chǔ)器中.處理器的運(yùn)算指令需要固化在片內(nèi)RAM中,可以通過(guò)總線進(jìn)行修改與配置,卷積神經(jīng)網(wǎng)絡(luò)中的權(quán)重值、輸入圖像的數(shù)據(jù)、中間的運(yùn)算結(jié)果都通過(guò)多端口讀寫控制模塊存儲(chǔ)到片外存儲(chǔ)器中.

圖4 協(xié)處理器總體設(shè)計(jì)框架Fig.4 Coprocessor overall design framework
在卷積神經(jīng)網(wǎng)絡(luò)中,大多數(shù)運(yùn)算都可以分為向量運(yùn)算、標(biāo)量運(yùn)算和矩陣運(yùn)算[17],如加法、乘法、激活函數(shù)的運(yùn)算可以看作是向量運(yùn)算,矩陣乘法、點(diǎn)乘可以看作是矩陣運(yùn)算,立即數(shù)的加減運(yùn)算可以看作是標(biāo)量運(yùn)算.因此本文將卷積神經(jīng)網(wǎng)絡(luò)的計(jì)算具體細(xì)分到了矩陣的加減法、乘法、非線性函數(shù)映射、二維圖像的卷積與池化運(yùn)算、矩陣與立即數(shù)的加減運(yùn)算等指令操作.為方便計(jì)算,本文中所有的運(yùn)算數(shù)據(jù)都是32位有符號(hào)的定點(diǎn)運(yùn)算,其中高16位表示整數(shù)位,低16位表示小數(shù)位.指令被設(shè)計(jì)為128位,指令結(jié)構(gòu)如表1所示.

表1 協(xié)處理器指令結(jié)構(gòu)說(shuō)明Table 1 Coprocessor instruction structure description
其中[127∶124]表示操作碼;[123∶92]表示該指令輸入數(shù)據(jù)參數(shù)1的起始地址;[91∶60]表示該指令輸入數(shù)據(jù)參數(shù)2的起始地址;[59∶28]表示輸出數(shù)據(jù)參數(shù)3的起始地址;[27∶0]根據(jù)指令的不同分別用于表示圖像的尺寸,卷積核的尺寸等運(yùn)算參數(shù).
本文設(shè)計(jì)指令執(zhí)行器,用于控制指令的順序執(zhí)行,不需要每執(zhí)行完一條指令就訪問(wèn)外部處理器.在系統(tǒng)復(fù)位后,只需向神經(jīng)網(wǎng)絡(luò)協(xié)處理器發(fā)送一條啟動(dòng)運(yùn)算的指令,處理器就能夠按照順序?qū)⒅噶頡AM中的指令全部執(zhí)行一遍.指令順序執(zhí)行器的實(shí)現(xiàn)分為兩個(gè)步驟:1)將外部發(fā)送過(guò)來(lái)的指令存儲(chǔ)到指令RAM中;2)接收到啟動(dòng)運(yùn)算指令后,按照順序獲取指令RAM中的指令,當(dāng)指令全部執(zhí)行結(jié)束后,發(fā)出運(yùn)算結(jié)束信號(hào).整個(gè)指令順序執(zhí)行器設(shè)計(jì)框圖見(jiàn)圖5,主要有指令分析模塊和順序執(zhí)行狀態(tài)機(jī)組成.指令分析模塊需要對(duì)接收到的指令進(jìn)行分析,如果是啟動(dòng)指令,則通知順序執(zhí)行狀態(tài)機(jī)啟動(dòng)神經(jīng)網(wǎng)絡(luò)計(jì)算模塊的指令調(diào)度.指令執(zhí)行狀態(tài)機(jī)在接收到指令分析模塊的啟動(dòng)命令后,會(huì)循環(huán)給出指令的地址,并獲取指令,調(diào)度計(jì)算單元開始計(jì)算,直到所有指令執(zhí)行完成.

圖5 指令執(zhí)行器設(shè)計(jì)框圖Fig.5 Instruction executor design block diagram
順序執(zhí)行狀態(tài)機(jī)由IDLE、READ、SEND、DELAY、WAIT、ADDR這6個(gè)狀態(tài)組成,各個(gè)狀態(tài)與跳轉(zhuǎn)條件說(shuō)明如下:
1)系統(tǒng)復(fù)位進(jìn)入空閑狀態(tài)IDLE;
2)在IDLE狀態(tài),如果收到啟動(dòng)運(yùn)算信號(hào),則會(huì)跳轉(zhuǎn)到READ狀態(tài);
3)在READ狀態(tài),等待3個(gè)時(shí)鐘完成指令讀取任務(wù),如果指令是無(wú)效指令,則跳轉(zhuǎn)到IDLE,否則進(jìn)入SEND狀態(tài);
4)在SEND狀態(tài),將指令發(fā)送給計(jì)算單元,并給出指令有效信號(hào),之后進(jìn)入DELAY狀態(tài);
5)在DELAY狀態(tài),等待5個(gè)時(shí)鐘周期,使計(jì)算單元接收指令和指令有效信號(hào),之后進(jìn)入WAIT狀態(tài);
6)在WAIT狀態(tài),等待計(jì)算單元完成計(jì)算,在收到計(jì)算單元給出的完成信號(hào)后,之后進(jìn)入ADDR狀態(tài);
7)在ADDR狀態(tài),對(duì)指令RAM的尋址地址加1,之后進(jìn)入READ狀態(tài).
由于外部的DDR存儲(chǔ)器通常只有一個(gè)總線接口,而在系統(tǒng)中存在多個(gè)單元需要對(duì)存儲(chǔ)器進(jìn)行讀寫,并且不同的單元對(duì)存儲(chǔ)器的訪問(wèn)速度也可能不同.本文設(shè)計(jì)一種基于異步FIFO的多端口讀寫控制器,將DDR控制的單端口分時(shí)復(fù)用,從而實(shí)現(xiàn)多個(gè)端口對(duì)一個(gè)端口的讀寫控制功能,不同的端口之間存在著優(yōu)先級(jí).圖6是2個(gè)端口寫和2個(gè)讀寫的控制器框架,想要實(shí)現(xiàn)更多的端口只需增加相應(yīng)的FIFO即可.
寫端口緩存與讀端口地址緩存有3個(gè)輸入信號(hào),分別為:地址信號(hào)、請(qǐng)求信號(hào)和緩存余量信號(hào);讀端口數(shù)據(jù)緩存有兩個(gè)輸出信號(hào),分別為數(shù)據(jù)有效信號(hào)和數(shù)據(jù)讀完信號(hào).對(duì)于寫端口,使用64bit寬度,深度為8的異步FIFO進(jìn)行數(shù)據(jù)緩存,在FIFO中每個(gè)存儲(chǔ)空間存放32bit地址與32bit數(shù)據(jù);對(duì)于讀端口,使用32bit寬度,深度為8的異步FIFO進(jìn)行緩存,在FIFO中每個(gè)存儲(chǔ)空間存放了要讀取的DDR地址.使用32bit寬度,深度為64 的異步FIFO緩存從DDR中讀取到的數(shù)據(jù).

圖6 多端口讀寫控制器設(shè)計(jì)框圖Fig.6 Multiport read-write controller design block diagram
讀寫端口選擇控制模塊主要由狀態(tài)機(jī)構(gòu)成,狀態(tài)機(jī)的跳轉(zhuǎn)邏輯如下:
1)系統(tǒng)復(fù)位后,狀態(tài)機(jī)進(jìn)入0狀態(tài);
2)在0狀態(tài),首先使能所有的讀寫端口,并按照順序掃描不同的讀寫端口,如果某個(gè)端口的異步FIFO非空,根據(jù)端口序號(hào)跳轉(zhuǎn)到1~4不同狀態(tài);
3)在1狀態(tài),處理來(lái)自寫入端口#0的寫入請(qǐng)求,生成DDR相應(yīng)的寫地址、寫請(qǐng)求信號(hào),在完成寫入操作后,撤銷DDR寫入請(qǐng)求,隨后屏蔽端口#0,使能其他端口,掃描是否有讀寫端口存在請(qǐng)求;
4)在2狀態(tài),處理來(lái)自讀取端口#1的讀取請(qǐng)求,生成DDR相應(yīng)的讀地址、讀請(qǐng)求信號(hào),在完成數(shù)據(jù)的讀取后,撤銷DDR讀取請(qǐng)求,隨后屏蔽端口#1,使能其他端口,掃描是否有讀寫端口存在請(qǐng)求;
5)在3狀態(tài),處理來(lái)自寫入端口#2的寫入請(qǐng)求,生成DDR相應(yīng)的寫地址、寫請(qǐng)求信號(hào),在完成寫入操作后,撤銷DDR寫入請(qǐng)求,隨后屏蔽端口#2,使能其他端口,掃描是否有讀寫端口存在請(qǐng)求;
6)在4狀態(tài),處理來(lái)自讀取端口#3的讀取請(qǐng)求,生成DDR相應(yīng)的讀地址、讀請(qǐng)求信號(hào),在完成數(shù)據(jù)的讀取后,撤銷DDR讀取請(qǐng)求,隨后屏蔽端口#3,使能其他端口,掃描是否有讀寫端口存在請(qǐng)求;
為了區(qū)分讀數(shù)據(jù)信號(hào)與讀數(shù)據(jù)有效信號(hào)對(duì)應(yīng)讀取端口#1還是讀取端口#3,使用一個(gè)4bit寬度,深度為64的異步FIFO進(jìn)行讀取端口選擇的緩存,運(yùn)行時(shí)鐘與端口選擇控制模塊時(shí)鐘相同.使用多端口控制器進(jìn)行讀寫端口的擴(kuò)展,要求各個(gè)讀寫端口盡可能的發(fā)起連續(xù)地址的讀寫請(qǐng)求,以達(dá)到最大的DDR讀寫帶寬利用率.每次端口選擇控制模塊切換端口的周期計(jì)算為:
(8)
其中,Ts為切換端口的周期;Nf為當(dāng)前FIFO在被選中時(shí)刻的深度,Wf為FIFO的位寬,F(xiàn)d為控制器的工作頻率,Wd為內(nèi)存的位寬,Ed為控制器的讀寫效率.
協(xié)處理器中的運(yùn)算邏輯在神經(jīng)網(wǎng)絡(luò)計(jì)算單元中實(shí)現(xiàn),計(jì)算單元由運(yùn)算控制邏輯、指令解析邏輯、指令運(yùn)算邏輯和DDR讀寫接口等部分組成.如果計(jì)算單元準(zhǔn)備就緒,就會(huì)發(fā)出Ready信號(hào),表示可以接收運(yùn)算指令,在接收到指令和指令有效信號(hào)后,解析指令的執(zhí)行類型并由控制邏輯控制計(jì)算單元開始數(shù)據(jù)的讀取與指令的運(yùn)算,神經(jīng)網(wǎng)絡(luò)計(jì)算單元設(shè)計(jì)框圖見(jiàn)圖7.讀寫地址生成模塊用于產(chǎn)生讀寫操作時(shí)DDR中的數(shù)據(jù)的地址,回寫緩存模塊用于緩存每條指令計(jì)算的結(jié)果.

圖7 神經(jīng)網(wǎng)絡(luò)計(jì)算單元設(shè)計(jì)框圖Fig.7 Design block diagram of neural network computing unit
根據(jù)指令類型的不同,計(jì)算任務(wù)可以劃分為雙矩陣逐點(diǎn)運(yùn)算(矩陣的加法、減法和點(diǎn)積運(yùn)算)、單矩陣逐點(diǎn)運(yùn)算(矩陣與立即數(shù)的加法、減法、乘法運(yùn)算以及激活函數(shù)的計(jì)算)、矩陣轉(zhuǎn)置運(yùn)算、矩陣乘法運(yùn)算和圖像的卷積與池化運(yùn)算等任務(wù).不同任務(wù)對(duì)數(shù)據(jù)的讀寫與運(yùn)算方式不同,任務(wù)間的轉(zhuǎn)換通過(guò)運(yùn)算控制邏輯實(shí)現(xiàn).運(yùn)算控制邏輯主要由有限狀態(tài)機(jī)構(gòu)成,包含了執(zhí)行不同任務(wù)的子狀態(tài)機(jī).當(dāng)系統(tǒng)復(fù)位時(shí),控制邏輯處于空閑狀態(tài),接收到指令后,根據(jù)Opcode的編碼跳轉(zhuǎn)到相應(yīng)任務(wù)的子狀態(tài)機(jī)中,通過(guò)子狀態(tài)機(jī)控制對(duì)數(shù)據(jù)的讀寫與運(yùn)算.
為提高運(yùn)算的效率,執(zhí)行每個(gè)任務(wù)時(shí)進(jìn)行邊讀邊寫的操作.執(zhí)行雙矩陣逐點(diǎn)運(yùn)算任務(wù)時(shí),先讀取參數(shù)1的一行數(shù)據(jù),然后讀取參數(shù)2的一行數(shù)據(jù),同時(shí)每讀取參數(shù)2的一個(gè)數(shù)據(jù)便與對(duì)應(yīng)的參數(shù)1的數(shù)據(jù)進(jìn)行逐點(diǎn)運(yùn)算,并將結(jié)果進(jìn)行緩存,當(dāng)一行數(shù)據(jù)全部計(jì)算完成后將結(jié)果寫回到DDR,之后開始讀取下一行的數(shù)據(jù),直到整個(gè)矩陣全部讀取完成.執(zhí)行單矩陣逐點(diǎn)運(yùn)算任務(wù)時(shí),只要先讀取參數(shù)1的數(shù)據(jù),進(jìn)行相應(yīng)的流水線運(yùn)算,對(duì)一行的數(shù)據(jù)逐點(diǎn)進(jìn)行相應(yīng)運(yùn)算的同時(shí)寫回到DDR,當(dāng)一行數(shù)據(jù)計(jì)算完成后繼續(xù)讀取下一行的數(shù)據(jù),直到參數(shù)1的數(shù)據(jù)全部計(jì)算完成.執(zhí)行矩陣轉(zhuǎn)置任務(wù)時(shí),為保證寫回的數(shù)據(jù)是按行連續(xù)的,因此在讀取數(shù)據(jù)時(shí)優(yōu)先按列讀取參數(shù)1指示的數(shù)據(jù),并直接按行寫回到DDR,直到整個(gè)矩陣完整轉(zhuǎn)置.執(zhí)行矩陣乘法任務(wù)時(shí),需要先讀取參數(shù)1指示數(shù)據(jù)的某一行,之后依次讀取參數(shù)2指示數(shù)據(jù)的每一列,在讀取參數(shù)2指示數(shù)據(jù)的同時(shí)進(jìn)行乘累加運(yùn)算,將結(jié)果進(jìn)行緩存,當(dāng)參數(shù)2 指示數(shù)據(jù)的每一列都讀取完成后,將運(yùn)算結(jié)果寫回到DDR,并開始讀取參數(shù)1指示數(shù)據(jù)的下一行,直到參數(shù)1指示的數(shù)據(jù)完全讀取.
本文中的實(shí)驗(yàn)使用Tensorflow[18]深度學(xué)習(xí)框架搭建卷積神經(jīng)網(wǎng)絡(luò),網(wǎng)絡(luò)結(jié)構(gòu)如表2,在Windows10環(huán)境下,使用Intel I5 9400 CPU+GTX1070 GPU在MNIST數(shù)據(jù)集[19]上進(jìn)行訓(xùn)練,在PYNQ-Z2開發(fā)板進(jìn)行前向推理.PYNQ-Z2開發(fā)板的芯片型號(hào)為Xilinx 的XC7Z020-1CLG400C,主要的內(nèi)部資源分為PS、PL和外設(shè)等部分,PS端包括雙核ARM Cortex-A9處理器,工作頻率為650MHz,PL端包括1.3M邏輯片,220個(gè)DSPs,同時(shí)開發(fā)板包括512MB16位總線寬度的DDR3存儲(chǔ)器,最高工作頻率為1050Mbps.

表2 卷積神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)說(shuō)明Table 2 Convolutional neural network structure description
為驗(yàn)證神經(jīng)網(wǎng)絡(luò)計(jì)算單元指令集運(yùn)算的準(zhǔn)確性,本文使用Python與UVM驗(yàn)證方法學(xué)搭建指令運(yùn)算驗(yàn)證平臺(tái),使用Modelsim軟件進(jìn)行仿真,驗(yàn)證平臺(tái)結(jié)構(gòu)如圖8所示.首先使用Python讀取卷積神經(jīng)網(wǎng)絡(luò)模型結(jié)構(gòu)文件,通過(guò)解析各個(gè)層的種類,生成相應(yīng)的處理器運(yùn)算指令;之后使用Python讀取卷積神經(jīng)網(wǎng)絡(luò)模型參數(shù)文件,將這些參數(shù)量化為32位有符號(hào)定點(diǎn)數(shù),分配到不同的內(nèi)存地址,并生成DDR初始化文件.使用Modelsim加載生成的指令文件對(duì)指令RAM存儲(chǔ)模型進(jìn)行初始化,之后加載DDR初始化文件將模型的參數(shù)初始化到DDR仿真模型中.通過(guò)將Monitor接收到的運(yùn)算結(jié)果與在Tensorflow中模型的運(yùn)算結(jié)果進(jìn)行對(duì)比,驗(yàn)證指令運(yùn)算的準(zhǔn)確性,并對(duì)計(jì)算誤差進(jìn)行統(tǒng)計(jì).
通過(guò)搭建的指令運(yùn)算驗(yàn)證平臺(tái),可以精準(zhǔn)地知道神經(jīng)網(wǎng)絡(luò)協(xié)處理器在運(yùn)算過(guò)程中每一步和最終的計(jì)算結(jié)果,以及與單精度浮點(diǎn)數(shù)運(yùn)算相比,由精度損失導(dǎo)致的相對(duì)誤差.通過(guò)進(jìn)行大量指令運(yùn)算,將運(yùn)算結(jié)果的相對(duì)誤差進(jìn)行統(tǒng)計(jì),圖9是部分指令的計(jì)算相對(duì)誤差.通過(guò)統(tǒng)計(jì)發(fā)現(xiàn),加法、點(diǎn)乘、乘法和卷積等指令的運(yùn)算結(jié)果相對(duì)誤差控制在10-4級(jí)別,激活函數(shù)的計(jì)算相對(duì)誤差控制在0.05以下,滿足神經(jīng)網(wǎng)絡(luò)協(xié)處理器的運(yùn)算需求.

圖8 協(xié)處理器驗(yàn)證平臺(tái)Fig.8 Coprocessor verification platform

圖9 部分指令運(yùn)算誤差統(tǒng)計(jì)Fig.9 Partial instruction operation error statistics
使用vivado 2018.3軟件對(duì)設(shè)計(jì)進(jìn)行綜合與時(shí)序分析,在100MHz的工作頻率下,通過(guò)時(shí)序分析,確定設(shè)計(jì)中各條關(guān)鍵路徑均滿足時(shí)序要求.表3是設(shè)計(jì)中各個(gè)模塊的資源消耗情況,BRAMs表示消耗的塊RAM;LUTs表示消耗的邏輯資源;DSPs表示消耗的DSP的數(shù)量.計(jì)算單元中存在卷積、矩陣乘法等運(yùn)算,消耗較多的DSP,而BRAM主要用于行緩存與指令的存儲(chǔ),多端口讀寫模塊使用純邏輯單元實(shí)現(xiàn).

表3 設(shè)計(jì)中各模塊資源消耗Table 3 Resource consumption of each module in the design
將設(shè)計(jì)下載到PYNQ-Z2開發(fā)板上對(duì)MINST數(shù)據(jù)集進(jìn)行分類識(shí)別,準(zhǔn)確率達(dá)98%以上,達(dá)到主流的識(shí)別準(zhǔn)確率.表4是本設(shè)計(jì)與其他卷積神經(jīng)網(wǎng)絡(luò)處理器的FPGA實(shí)現(xiàn)的結(jié)果對(duì)比,為更加全面公平的比對(duì)加速效果,增加能效比參數(shù).

表4 與文獻(xiàn)中的方案對(duì)比Table 4 Compared with the scheme in the literature
從表4中可以看出,本設(shè)計(jì)的能效為19.87GOPS.W-1,消耗24663LUTs,與文獻(xiàn)[4]的設(shè)計(jì)相比,本文的設(shè)計(jì)能效降低30%左右,消耗的資源降低60%;與文獻(xiàn)[11]的設(shè)計(jì)相比,本文的設(shè)計(jì)在達(dá)到相當(dāng)能效的條件下,消耗的資源降低80%左右;與文獻(xiàn)[20]的設(shè)計(jì)相比,本文的設(shè)計(jì)能效提高40倍,消耗的資源降低70%左右.本文的設(shè)計(jì)在達(dá)到同類設(shè)計(jì)的主流水平時(shí),消耗的邏輯資源僅為同類設(shè)計(jì)的20%,消耗的DSP資源為同類設(shè)計(jì)的20%.
本文提出一種在FPGA平臺(tái)上實(shí)現(xiàn)指令集架構(gòu)的神經(jīng)網(wǎng)絡(luò)協(xié)處理器的方案,可通過(guò)對(duì)不同神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)的解析,生成計(jì)算指令,能靈活實(shí)現(xiàn)復(fù)雜神經(jīng)網(wǎng)絡(luò)在FPGA平臺(tái)上的加速計(jì)算,縮短神經(jīng)網(wǎng)絡(luò)部署的時(shí)間;并通過(guò)硬件電路結(jié)構(gòu)的分時(shí)復(fù)用,減少對(duì)資源的消耗.方案中使用Python與UVM驗(yàn)證方法學(xué)搭建驗(yàn)證平臺(tái),驗(yàn)證了指令計(jì)算的誤差在10-4級(jí)別,滿足運(yùn)算的需求,通過(guò)在PYNQ-Z2開發(fā)板上測(cè)試,運(yùn)算能效為19.87GOPS.W-1,達(dá)到同級(jí)別設(shè)計(jì)主流水平,消耗的資源比同級(jí)別產(chǎn)品平均降低80%.本方案中的運(yùn)算使用的數(shù)據(jù)位寬為32位,為更好的降低功耗,提高計(jì)算的并行度,在后續(xù)的研究與設(shè)計(jì)中,可考慮使用16位或8位的數(shù)據(jù)進(jìn)行運(yùn)算.