韋蘇倫,陶青川
(四川大學(xué)電子信息學(xué)院,成都 610065)
作為一種人工神經(jīng)網(wǎng)絡(luò),卷積神經(jīng)網(wǎng)絡(luò)被廣泛應(yīng)用于圖像、語(yǔ)音識(shí)別[1]等各種智能識(shí)別系統(tǒng)。隨著卷積神經(jīng)網(wǎng)絡(luò)的發(fā)展,各種各樣的網(wǎng)絡(luò)層出不窮,并且被應(yīng)用到越來(lái)越復(fù)雜的場(chǎng)景當(dāng)中。但隨著網(wǎng)絡(luò)復(fù)雜性的增加以及隨之而來(lái)的龐大計(jì)算量,運(yùn)行卷積神經(jīng)網(wǎng)絡(luò)的計(jì)算設(shè)備也需要更好的性能。傳統(tǒng)的CPU 并不適用于矩陣運(yùn)算占主導(dǎo)的模型訓(xùn)練和推理,GPU 雖然滿足這一特性,但對(duì)于一些嵌入式設(shè)備來(lái)說(shuō)還需要更低的功耗[2]。FPGA 作為可編程邏輯器件,具有功耗低、性能高、靈活性好的特點(diǎn),因此更加適用于卷積神經(jīng)網(wǎng)絡(luò)硬件加速的開(kāi)發(fā)研究[3],Verilog 開(kāi)發(fā)門(mén)檻比較高,開(kāi)發(fā)周期相對(duì)較長(zhǎng),這極大影響了卷積神經(jīng)網(wǎng)絡(luò)在FPGA中部署的普及。
軟件工程師們應(yīng)該更多考慮的是大的架構(gòu),而非某個(gè)單獨(dú)部件或逐周期運(yùn)行,HLS 工具[4]的出現(xiàn)也是源自于此,它是一種代碼綜合技術(shù),具體是指采用C、C++等高級(jí)編程語(yǔ)言進(jìn)行程序編寫(xiě),而不是傳統(tǒng)的Verilog 語(yǔ)言,這大大提高了FPGA 的開(kāi)發(fā)速度。本文應(yīng)用HLS 高層次綜合工具,基于輕量化的原則選擇了Mobile?Netv2 網(wǎng)絡(luò),在賽靈思的FPGA 開(kāi)發(fā)板Kria KV260 上實(shí)現(xiàn)了一個(gè)卷積神經(jīng)網(wǎng)絡(luò)加速器,通過(guò)數(shù)據(jù)的串并轉(zhuǎn)換,充分利用AXI 總線帶寬,利用pingpong 緩存技術(shù)實(shí)現(xiàn)數(shù)據(jù)的讀寫(xiě)與計(jì)算的并行操作,同時(shí)在卷積計(jì)算中使用分組分塊計(jì)算進(jìn)一步提高推理的速度。
本文使用賽靈思的Kria KV260 FPGA 開(kāi)發(fā)板作為實(shí)驗(yàn)板卡,Kria KV260 是賽靈思專為AI視覺(jué)設(shè)計(jì)的入門(mén)級(jí)FPGA 開(kāi)發(fā)板。它的設(shè)計(jì)是一種模塊化的設(shè)計(jì)方式,分為FPGA 板卡以及接口部分,其中FPGA 板卡部分是K26 SoM,它采用Zynq UltraScale+ MPSoC 架構(gòu),包含4 核ARM Cortex-A53 處理器,提供256 K 個(gè)系統(tǒng)邏輯單元和1.2 K 個(gè)DSP 單元。在軟件開(kāi)發(fā)環(huán)境方面,使用賽靈思的統(tǒng)一軟件平臺(tái)Vitis 以及高層次綜合工具Vivado HLS作為編譯測(cè)試環(huán)境。
神經(jīng)網(wǎng)絡(luò)模型方面使用的是MobileNetv2[5]。作為經(jīng)典輕量化網(wǎng)絡(luò)的MobileNet,自誕生就被廣泛應(yīng)用于工業(yè)界。它是一種構(gòu)造體量小、低延時(shí)的網(wǎng)絡(luò)結(jié)構(gòu),對(duì)于很多移動(dòng)和嵌入式設(shè)備的圖像應(yīng)用都比較適合。MobileNet 是由谷歌團(tuán)隊(duì)提出的應(yīng)用于移動(dòng)端或者嵌入式設(shè)備中的輕量級(jí)神經(jīng)網(wǎng)絡(luò),在準(zhǔn)確率只有極小幅降低的情況下,大量減少參數(shù)與運(yùn)算量。MobileNet 的特點(diǎn)是提出了深度可分離卷積,其還可被拆分成兩個(gè)子模塊:逐通道卷積(depthwise convolu?tion)與逐點(diǎn)卷積層(pointwise convolution)。
表1 KV260板卡資源
圖1 KV260開(kāi)發(fā)板俯視圖
對(duì)于傳統(tǒng)卷積來(lái)說(shuō),若卷積核大小為Dk,數(shù)量為N,圖像的尺寸為Df,圖像和卷積核的通道深度為M,那么對(duì)于N個(gè)卷積操作來(lái)說(shuō),總的計(jì)算量如公式(1)所示。
而對(duì)于深度可分離卷積神經(jīng)網(wǎng)絡(luò)來(lái)說(shuō),其計(jì)算量包括逐通道卷積和逐點(diǎn)卷積兩部分,如公式(2)、(3)、(4)所示。
其中,CostDW和CostPW分別為
所以可計(jì)算出傳統(tǒng)卷積與深度可分離卷積的計(jì)算量比值,由公式(5)可知,后者的計(jì)算效率明顯高于傳統(tǒng)卷積。
MobileNetv2 是MobileNetv1 的升級(jí)版,在MobileNetv1 的深度可分離卷積基礎(chǔ)上,新增加了線性瓶頸和倒殘差結(jié)構(gòu),其中倒殘差結(jié)構(gòu)如圖2所示。
圖2 MobileNetv2倒殘差結(jié)構(gòu)
在倒殘差結(jié)構(gòu)中,先用小的1*1 卷積升維,通過(guò)3*3 的逐通道卷積提取特征,最后再使用1*1 卷積降維,呈兩頭小、中間大的梭型結(jié)構(gòu)。為了提升精度,在倒殘差結(jié)構(gòu)中,前兩個(gè)激活函數(shù)使用ReLU6 來(lái)代替ReLU,最后使用線性激活函數(shù)。
本文的總體設(shè)計(jì)基于vivado HLS 高層次綜合[6]和PYNQ 平臺(tái)[7]。由HLS 工具通過(guò)C++語(yǔ)言實(shí)現(xiàn)卷積神經(jīng)網(wǎng)絡(luò)的IP 核,通過(guò)仿真和綜合之后可以打包zip 核文件,通過(guò)vivado 平臺(tái)導(dǎo)入HLS 的zip 文件進(jìn)行塊設(shè)計(jì)、布線和整體編譯得到硬件平臺(tái)的.bit 和.hwh 文件,這是PL 部分的設(shè)計(jì)。PS 端可以使用C++語(yǔ)言在Vitis 中進(jìn)行主機(jī)端的代碼編寫(xiě)或者使用Python 語(yǔ)言在PYNQ中進(jìn)行編寫(xiě),進(jìn)而控制數(shù)據(jù)的輸入與輸出并與PL 部分進(jìn)行計(jì)算與交互,其數(shù)據(jù)傳輸?shù)慕Y(jié)構(gòu)如圖3所示。
圖3 數(shù)據(jù)傳輸結(jié)構(gòu)
首先通過(guò)S_AXI_lite 接口將主機(jī)端與FPGA相連接,通過(guò)讀取和寫(xiě)入S_AXI_lite 端的控制寄存器來(lái)控制PL 端的行為,一般用來(lái)傳輸控制和狀態(tài)寄存器以及讀寫(xiě)的地址等。對(duì)于輸入的圖像數(shù)據(jù)、權(quán)重和偏置等數(shù)據(jù)則使用存儲(chǔ)器映射接口M_AXI 來(lái)進(jìn)行傳輸,M_AXI 存儲(chǔ)器映射接口可以支持最高4 K字節(jié)的突發(fā)量,并且具有獨(dú)立的讀取和寫(xiě)入的通道,因此單個(gè)接口也可以同時(shí)執(zhí)行讀取和寫(xiě)入的操作。在傳輸讀寫(xiě)地址之后,通過(guò)M_AXI接口將經(jīng)過(guò)主機(jī)端映射存到全局存儲(chǔ)器中的數(shù)據(jù)讀取至PL內(nèi)核中進(jìn)行計(jì)算。
為了加快推理速度,可以進(jìn)行BN 融合,即將BN 層參數(shù)和卷積層參數(shù)融合在一起,這樣在模型訓(xùn)練之后的推理階段就可省去BN 層的計(jì)算[8]。
考慮到MobileNetv2 結(jié)構(gòu)的重復(fù)性,將整個(gè)網(wǎng)絡(luò)分成三個(gè)部分來(lái)設(shè)計(jì):Bottleneck 部分、Bottleneck 之前以及之后的部分。在每個(gè)部分也有基礎(chǔ)的計(jì)算單元,如普通二維卷積、深度卷積、逐點(diǎn)卷積、殘差結(jié)構(gòu)以及全劇平均池化層等,本文將這些基礎(chǔ)單元單獨(dú)設(shè)計(jì)成IP計(jì)算核。
加速器總的系統(tǒng)結(jié)構(gòu)塊設(shè)計(jì)如圖4 所示,左邊是HLS 設(shè)計(jì)導(dǎo)出的5 個(gè)IP 核,中間從上往下分別是ZYNQ 的中心處理模塊和時(shí)鐘與復(fù)位信號(hào)模塊,右邊的兩列則是傳輸總線AXI 的相關(guān)模塊,對(duì)塊設(shè)計(jì)進(jìn)行綜合之后得到總的資源使用情況,如圖5所示。
圖4 加速器整體塊設(shè)計(jì)
圖5 綜合資源占用情況
1.3.1 pingpong操作
在兩個(gè)計(jì)算模塊之間傳遞數(shù)據(jù)時(shí),由于前一個(gè)模塊需要等待下一個(gè)模塊計(jì)算完成才能交付數(shù)據(jù),造成了一定的性能損失,所謂ping?pong 操作是指設(shè)置緩沖來(lái)進(jìn)行交替存儲(chǔ),進(jìn)而實(shí)現(xiàn)讀、算、寫(xiě)的同步。
數(shù)據(jù)的分塊計(jì)算使得多個(gè)模塊之間的計(jì)算滿足上述情況,所以設(shè)置兩個(gè)buffer來(lái)實(shí)現(xiàn)數(shù)據(jù)的pingpong 操作,buffer 的大小根據(jù)不同IP 核進(jìn)行獨(dú)立設(shè)置。pingpong操作的計(jì)算原理如圖6所示。
圖6 pingpong操作原理
1.3.2 for循環(huán)展開(kāi)
HLS 可以使用Unroll 指令對(duì)for 循環(huán)進(jìn)行展開(kāi),for 循環(huán)在默認(rèn)狀態(tài)下是折疊狀態(tài)的,即在電路里中每一次循環(huán)都會(huì)分時(shí)地使用同一套電路。使用Unroll 可以對(duì)for 循環(huán)的代碼區(qū)進(jìn)行循環(huán)體展開(kāi),將之前的電路復(fù)制多份,實(shí)現(xiàn)以資源換取并行的計(jì)算邏輯,如圖7 所示。Unroll 允許完全展開(kāi)或部分展開(kāi),其中部分展開(kāi)需要指定循環(huán)因子factor=N,即把循環(huán)展開(kāi)N倍來(lái)減少循環(huán)迭代。
圖7 Unroll循環(huán)展開(kāi)原理
1.3.3 多精度計(jì)算優(yōu)化
在IP核中采用的是AP_FIX16的精度進(jìn)行存儲(chǔ)和運(yùn)算,這就有可能會(huì)因?yàn)閿?shù)據(jù)精度過(guò)低以及數(shù)值溢出而產(chǎn)生一些計(jì)算誤差,并有可能在深度神經(jīng)網(wǎng)絡(luò)中持續(xù)積累這種誤差。于是本文在考慮資源占用的同時(shí),采用多精度數(shù)據(jù)的方式來(lái)避免這種精度的溢出:將輸入與輸出設(shè)置為AP_FIX16的數(shù)據(jù)類型,然后在計(jì)算卷積的過(guò)程中,擴(kuò)大精度來(lái)保存臨時(shí)的數(shù)值,并在最后輸出時(shí)恢復(fù)為最開(kāi)始的精度。
1.3.4 計(jì)算分組分塊
由于網(wǎng)絡(luò)模型的參數(shù)量比較大,直接使用FPGA 中片上資源來(lái)保存每一層所有的數(shù)據(jù)并不是一個(gè)好的方法,所以本文對(duì)網(wǎng)絡(luò)的各個(gè)模塊用數(shù)據(jù)分組分塊的方式來(lái)計(jì)算,以降低片內(nèi)資源的占用,并配合pingpong 操作等優(yōu)化方式進(jìn)行并行計(jì)算,其過(guò)程如圖8所示。
圖8 分組分塊計(jì)算
1.3.5 流水線優(yōu)化
流水線的設(shè)計(jì)思想是新的輸入數(shù)據(jù)在前面的數(shù)據(jù)計(jì)算完成之前就能提前處理,例如有一個(gè)復(fù)雜電路,它需要固定的時(shí)間周期才能得出最后的穩(wěn)定結(jié)果,我們將其拆解為N個(gè)步驟,第一個(gè)步驟計(jì)算完成后將結(jié)果存起來(lái)傳送給第二個(gè)步驟,然后緊接著繼續(xù)往第一個(gè)步驟輸入數(shù)據(jù),以此類推,用這種方式實(shí)現(xiàn)流水線優(yōu)化的并行處理,如圖9所示。
圖9 流水線加速時(shí)序
1.3.6 加法器樹(shù)優(yōu)化
在一次卷積計(jì)算過(guò)程中涉及到多次加法的運(yùn)算,這個(gè)時(shí)候可以采用加法器樹(shù)的設(shè)計(jì)方式,將卷積運(yùn)算單元中的相加過(guò)程設(shè)計(jì)為樹(shù)形的并行相加模式,進(jìn)而提高運(yùn)算效率,可以把時(shí)鐘周期為N的工作縮小到log2N個(gè)時(shí)鐘周期。
通過(guò)實(shí)驗(yàn)對(duì)比,在不使用并行加速策略時(shí),單核的Arm 設(shè)備平均耗時(shí)為35.6 s,而本文使用上述的并行優(yōu)化設(shè)計(jì),在KV260 的ZYNQ 平臺(tái)中的平均計(jì)算耗時(shí)降低到0.046 s,且功耗并無(wú)明顯變化,證明該加速器在保證功耗基本不變的情況下,還能充分發(fā)揮FPGA 的并行計(jì)算優(yōu)勢(shì),提高計(jì)算速度。
表2 加速器優(yōu)化策略性能對(duì)比
該部分是神經(jīng)網(wǎng)絡(luò)最上層卷積,輸入為224×224×3 的圖像數(shù)據(jù)與該層的權(quán)重?cái)?shù)據(jù)。為了提升計(jì)算速度,我們對(duì)數(shù)據(jù)流進(jìn)行了控制,將輸入分為三個(gè)通道來(lái)處理輸入數(shù)據(jù),使用三條128位AXI總線進(jìn)行傳輸。在實(shí)際傳輸時(shí)數(shù)據(jù)為16 位的定點(diǎn)數(shù),這里將24 個(gè)16 位定點(diǎn)數(shù)打包,同時(shí)在AXI 總線上進(jìn)行并行傳輸。對(duì)于權(quán)重、偏置和輸出則分別使用一條64 位AXI 總線進(jìn)行傳輸。
為進(jìn)一步提升計(jì)算效率,對(duì)計(jì)算分為兩路的pingpong 緩存和計(jì)算,如圖10 所示。在ping?pong 操作中進(jìn)行后續(xù)的循環(huán)展開(kāi)計(jì)算卷積模塊,將輸入數(shù)據(jù)進(jìn)行如圖8的分塊卷積操作,對(duì)于權(quán)重來(lái)說(shuō),同樣在for循環(huán)中每次讀取出8個(gè)filter來(lái)進(jìn)行卷積操作,以達(dá)到數(shù)據(jù)并行計(jì)算的目的。
圖10 pingpong模塊偽代碼
經(jīng)過(guò)HLS 仿真測(cè)試和綜合之后,得到其資源使用報(bào)告,如圖11所示。
圖11 普通二維卷積IP核綜合報(bào)告
Depthwise 是逐通道卷積,是將特征圖的每個(gè)通道單獨(dú)使用卷積核來(lái)進(jìn)行卷積操作,獲得特征圖每個(gè)通道的空間特征,并使得到的特征圖和輸入的通道數(shù)保持一致。逐通道卷積的卷積計(jì)算采用PIPELINE 指令進(jìn)行流水優(yōu)化以及UNROLL 進(jìn)行循環(huán)展開(kāi),同時(shí)利用pingpong 模塊對(duì)緩存和計(jì)算進(jìn)行并行處理。在接口方面,將輸入設(shè)置為兩個(gè)不同通道來(lái)處理輸入數(shù)據(jù),使用兩條64 位AXI 總線進(jìn)行傳輸,同樣將8 個(gè)16 位定點(diǎn)數(shù)據(jù)打包到AXI 總線上并行傳輸,權(quán)重和偏置則采用一條32位AXI總線進(jìn)行傳輸。
由于每次不同層的逐通道卷積尺寸不同,我們將數(shù)據(jù)分塊來(lái)實(shí)現(xiàn)統(tǒng)一的單元化卷積計(jì)算,具體是將數(shù)據(jù)切分為若干個(gè)8×32 的小尺寸,且進(jìn)一步將32 劃分為4×8 的多通道數(shù)據(jù),使得不同尺寸的卷積轉(zhuǎn)換為多個(gè)固定尺寸的小的卷積,有利用逐通道卷積的加速核的統(tǒng)一化設(shè)計(jì)。對(duì)于不同步長(zhǎng)的層,可通過(guò)傳入的stride 值判斷輸出特征尺寸是否需要減半。分塊卷積的偽代碼如圖12 所示,W為卷積核的大小,B_r、B_c、B_ch 分別為分塊的尺寸以及通道大小,在B_ch處進(jìn)行PIPELINE 循環(huán)展開(kāi),使用B_ch 個(gè)并行的乘法器和深度為[log2B_ch]的加法器樹(shù),每時(shí)鐘將輸入緩存的ch 個(gè)通道的特征值與對(duì)應(yīng)的權(quán)重值進(jìn)行乘法計(jì)算,然后將計(jì)算的數(shù)據(jù)進(jìn)行累加,并使用加法器樹(shù)優(yōu)化計(jì)算,最后通過(guò)輸出緩存存儲(chǔ)結(jié)果。
圖12 分塊卷積實(shí)現(xiàn)偽代碼
在HLS 中進(jìn)行仿真和綜合后的報(bào)告如圖13所示。
圖13 逐通道卷積層IP核綜合報(bào)告
Pointwise 是逐點(diǎn)卷積,使用和輸入特征圖通道相同數(shù)量的1*1 的卷積核,對(duì)特征圖深度方面做了加權(quán)組合,相當(dāng)于獲得每個(gè)點(diǎn)的特征信息,大大減小了總體的計(jì)算量。
在具體的實(shí)現(xiàn)中,使用兩條64 位AXI 總線進(jìn)行傳輸,同樣將8 個(gè)16 位定點(diǎn)數(shù)據(jù)打包到AXI 總線上并行傳輸,權(quán)重和偏置則分別采用兩條64 位AXI 總線和用一條32 位AXI 總線進(jìn)行傳輸。計(jì)算部分由于該模塊存在許多1*1 的卷積,計(jì)算得到的通道數(shù)相對(duì)較多,同樣采用了數(shù)據(jù)分塊的思想,利用兩層pingpong 嵌套操作來(lái)讀取權(quán)重和特征數(shù)據(jù)并進(jìn)行卷積計(jì)算。
同樣經(jīng)過(guò)仿真以及HLS 綜合之后獲得資源使用情況的報(bào)告,如圖14所示。
圖14 逐點(diǎn)卷積層IP核綜合報(bào)告
由于已經(jīng)單獨(dú)實(shí)現(xiàn)了逐通道卷積和逐點(diǎn)卷積,所以這里殘差層是指最后的原始數(shù)據(jù)與經(jīng)過(guò)了殘差之后的輸出相加的操作,并通過(guò)流水展開(kāi)來(lái)進(jìn)行加速。
全連接模塊由全局平均池化層和全連接層組成,本文將其實(shí)現(xiàn)為一個(gè)IP 核,輸入大小為7×7×Channel,輸出為最后的分類結(jié)果。接口方面直接使用一條16 位AXI 總線進(jìn)行傳輸,具體的實(shí)現(xiàn)則是將卷積核的值當(dāng)做分?jǐn)?shù)來(lái)模擬求平均的計(jì)算,使用加法器樹(shù)對(duì)齊進(jìn)行并行加速,加載數(shù)據(jù)時(shí)同樣利用pingpong 模塊來(lái)進(jìn)行緩存和計(jì)算優(yōu)化。仿真和綜合之后得到報(bào)告,如圖15所示。
圖15 殘差層、全連接層IP核綜合報(bào)告
經(jīng)過(guò)上述的仿真和綜合之后,從Vivado HLS 2020.2 中導(dǎo)出IP 核的壓縮文件,在Vivado 2020.2 中導(dǎo)入IP 文件并在塊設(shè)計(jì)中進(jìn)行連線。對(duì)塊設(shè)計(jì)進(jìn)行仿真和綜合后得到.bit 和.hwh 文件,利用Python 語(yǔ)言調(diào)用PYNQ 軟件層的接口進(jìn)行主機(jī)端編程。
數(shù)據(jù)集采用公開(kāi)的DeepFashion 服裝數(shù)據(jù)集來(lái)進(jìn)行訓(xùn)練和測(cè)試,其中包括運(yùn)動(dòng)夾克、毛衣、連衣裙等46種類別,并使用2000張測(cè)試圖片進(jìn)行上板驗(yàn)證。分別從計(jì)算時(shí)間、識(shí)別準(zhǔn)確率、芯片功耗幾個(gè)方面來(lái)展示在KV260 的FPGA 上推理MobileNetv2 網(wǎng)絡(luò)的實(shí)驗(yàn)結(jié)果,并且將該結(jié)果分別與網(wǎng)絡(luò)在CPU 和GPU 計(jì)算平臺(tái)上的推理結(jié)果作為對(duì)比來(lái)分析基于FPGA方法的優(yōu)勢(shì)。
對(duì)于使用FPGA 加速器的方案,使用賽靈思的Kria KV260 作為硬件計(jì)算平臺(tái);對(duì)于直接使用CPU 的方案,使用i7-12th 作為硬件計(jì)算平臺(tái);而對(duì)于使用GPU 的方案,則使用RTX3060作為硬件計(jì)算平臺(tái)。
表3 計(jì)算速度對(duì)比
本文基于賽靈思提供的Kria KV260開(kāi)發(fā)板,使用高層次綜合工具通過(guò)C++語(yǔ)言進(jìn)行Mobile?Netv2 的加速核設(shè)計(jì),并在使用Python 在PYNQ平臺(tái)中對(duì)主機(jī)端進(jìn)行編程以及驗(yàn)證推理。實(shí)驗(yàn)表明,相比單核的Arm芯片,利用FPGA的并行計(jì)算設(shè)計(jì)以及HLS 相關(guān)指令對(duì)加速核進(jìn)行計(jì)算優(yōu)化效果明顯,且該種方法設(shè)計(jì)的卷積神經(jīng)網(wǎng)絡(luò)加速器在推理Top1 上并無(wú)明顯下降,在計(jì)算速度上相較于CPU 來(lái)說(shuō)提升了2 倍左右,雖然與GPU 相比還是有一定差距,但在功耗方面降低了10倍左右,有著較大的優(yōu)勢(shì)。