謝豪 曹健,? 李普 趙雄波 張興,?
1.北京大學(xué)軟件與微電子學(xué)院, 北京 102600; 2.北京航天自動(dòng)控制研究所, 北京 100854;? 通信作者, E-mail: caojian@ss.pku.edu.cn (曹健), zhx@pku.edu.cn (張興)
計(jì)算機(jī)視覺(jué)是一種使用計(jì)算機(jī)代替人類視覺(jué)系統(tǒng)對(duì)圖像進(jìn)行處理的方法, 卷積神經(jīng)網(wǎng)絡(luò)(convolution neural network, CNN)是計(jì)算機(jī)視覺(jué)的一種常用方法。隨著神經(jīng)網(wǎng)絡(luò)算法的不斷優(yōu)化以及計(jì)算機(jī)系統(tǒng)性能的不斷提高, 計(jì)算機(jī)視覺(jué)對(duì)日常生活的影響日益擴(kuò)大, 如自動(dòng)駕駛路況識(shí)別以及 CT 圖像識(shí)別等[1–2]。一些需要在端側(cè)部署神經(jīng)網(wǎng)絡(luò)模型的場(chǎng)景中, 神經(jīng)網(wǎng)絡(luò)模型計(jì)算量過(guò)大, 端側(cè)設(shè)備算力不足,功耗受限成為具有挑戰(zhàn)性的問(wèn)題。
常用的目標(biāo)檢測(cè)神經(jīng)網(wǎng)絡(luò)算法包括 SSD (single shot detector)、YOLO (you only look once)和 R-CNN(region-CNN)[3–5]。SSD 算法檢測(cè)速度較快, 對(duì)尺寸不同的目標(biāo)均有較好的檢測(cè)效果。FPGA (field programmable gate array)內(nèi)部具有大量的并行計(jì)算資源, 并且比 GPU 功耗低, 適用于在端側(cè)實(shí)現(xiàn)卷積神經(jīng)網(wǎng)絡(luò)算法的加速。
FPGA 加速神經(jīng)網(wǎng)絡(luò)算法時(shí), FPGA 內(nèi)部的計(jì)算資源的總數(shù)是固定的, 應(yīng)盡可能將計(jì)算資源利用起來(lái), 使大部分計(jì)算資源處于工作狀態(tài)。Zhang 等[6]采用卷積分塊, 對(duì)計(jì)算資源進(jìn)行復(fù)用, 采用roofline模型分析來(lái)提高計(jì)算并行度, 降低系統(tǒng)對(duì)數(shù)據(jù)傳輸帶寬的需求。Ma 等[7–8]采用循環(huán)展開(kāi)的方式實(shí)現(xiàn)PE (processing element)單元, 對(duì)數(shù)據(jù)傳輸和卷積計(jì)算建模, 進(jìn)行設(shè)計(jì)空間探索, 對(duì)不同的模型采用不同的加速器結(jié)構(gòu), 提高了PE單元的利用率。Gong等[9]利用FPGA的動(dòng)態(tài)可重配置技術(shù), 對(duì)同一模型的不同卷積層, 也采用不同的加速器結(jié)構(gòu), 進(jìn)一步提高 FPGA 內(nèi)部資源的利用率。Nguyen 等[10]采用細(xì)粒度的層間流水方法, 針對(duì)不同卷積層的特點(diǎn)細(xì)化資源的使用。
現(xiàn)有的用于目標(biāo)檢測(cè)的 FPGA 加速器設(shè)計(jì)存在一些不足, 比如只有當(dāng)輸入圖片的 batch 較大時(shí)才能獲得比較好的加速性能, 不適合用于嵌入式系統(tǒng)。針對(duì) SSD 算法設(shè)計(jì)的加速器沒(méi)有實(shí)現(xiàn)空洞卷積(dilated convolution)[11]的算法加速, 而空洞卷積在卷積神經(jīng)網(wǎng)絡(luò)中的應(yīng)用越來(lái)越廣泛。
本文針對(duì) SSD 網(wǎng)絡(luò)設(shè)計(jì)一種加速器, 其優(yōu)點(diǎn)主要體現(xiàn)在以下幾方面: 1) 通過(guò)卷積循環(huán)內(nèi)展開(kāi)的方式, 設(shè)計(jì)了一種 PE 處理單元, 可以靈活地配置計(jì)算并行度, 可用于常規(guī)卷積和空洞卷積的加速; 2) 針對(duì) AXI 總線設(shè)計(jì)了一種數(shù)據(jù)傳輸方式, 在不帶來(lái)額外硬件資源開(kāi)銷的情況下對(duì)數(shù)據(jù)進(jìn)行重排序, 提高AXI 總線帶寬利用率。
卷積是 SSD 算法中用于提取特征的一種基本算子, 通過(guò)卷積核在特征圖滑動(dòng), 與特征圖相乘和相加來(lái)完成。對(duì)輸入特征圖(input featuremap, IF)、權(quán)重(weights, WT)以及偏置(bias,B)進(jìn)行卷積的過(guò)程如下:
其中, OF 為輸出特征圖,C為輸入特征圖寬度,R為高度,N為通道數(shù),W為輸出特征圖寬度,H為高度,M為通道數(shù),Kw×Kh為權(quán)重的尺寸,Kw為寬度,Kh為高度,S為卷積步長(zhǎng)。
除上述的標(biāo)準(zhǔn)卷積外, SSD 還使用空洞卷積。圖1 是空洞卷積和標(biāo)準(zhǔn)卷積的對(duì)比示意圖??斩淳矸e的計(jì)算過(guò)程如式(2)所示:
其中,l為空洞率,l=1時(shí)空洞卷積與標(biāo)準(zhǔn)卷積一致,其他變量與標(biāo)準(zhǔn)卷積相同。
池化用于降采樣, 可以提高模型感受野。常用的池化方法包括最大池化和平均池化。SSD中采用的2×2最大池化計(jì)算過(guò)程如下:
計(jì)算結(jié)果需要經(jīng)過(guò)批歸一化[12]使得數(shù)據(jù)分布均勻, 批歸一化過(guò)程如下:
其中,μm表示均值,σm表示方差,?是為防止σm為0引入的一個(gè)小值。每個(gè)通道的輸出特征圖都有各自的μm和σm, 這些參數(shù)都是在訓(xùn)練過(guò)程中確定的。在推理過(guò)程中可以將BN融合進(jìn)卷積中, 在設(shè)計(jì)硬件加速器時(shí), 不需要考慮批歸一化的硬件實(shí)現(xiàn)。
激活函數(shù)使用ReLU, 計(jì)算方法如下:
訓(xùn)練得到的權(quán)重參數(shù)一般為浮點(diǎn)類型, 在FPGA中使用浮點(diǎn)數(shù)進(jìn)行乘加計(jì)算時(shí)消耗資源較多, 計(jì)算的延時(shí)較多。使用定點(diǎn)數(shù)計(jì)算可以實(shí)現(xiàn)更大的計(jì)算吞吐量[13]。Ma 等[14]對(duì) SSD 進(jìn)行 8 bit 定點(diǎn)化, 精度損失為 0.36%。在 FPGA 中實(shí)現(xiàn)神經(jīng)網(wǎng)絡(luò)算法時(shí),將參數(shù)進(jìn)行定點(diǎn)化, 用一個(gè)Q位的有符號(hào)定點(diǎn)數(shù) Fixq來(lái)表示小數(shù):
其中, fl 為規(guī)定的小數(shù)部分長(zhǎng)度。
每層的輸入特征圖、權(quán)重和輸出特征圖分別對(duì)應(yīng)一個(gè) fl, 分別用 flin, flw和 flout表示。fl 的值是通過(guò)數(shù)據(jù)的分布來(lái)統(tǒng)計(jì), 應(yīng)選取適當(dāng)?shù)?fl 值, 保證大部分的數(shù)據(jù)都能用定點(diǎn)數(shù) Fixq來(lái)表示。輸入特征圖和權(quán)重相乘后需要進(jìn)行移位, 使得計(jì)算結(jié)果的 fl 為flout, 移位的位數(shù)為
如圖1 所示, 整個(gè)加速器系統(tǒng)是基于 Xilinx 的Zynq 系列的 FPGA 構(gòu)建, 這一系列的 FPGA 由 PS和 PL 兩部分構(gòu)成。PS 由 ARM 核和外設(shè)構(gòu)成, PL是可編程硬件部分, 由查找表(look up table, LUT)、BRAM (block RAM)、數(shù)字信號(hào)處理器(digital sig-nal processor, DSP)等邏輯資源構(gòu)成。PS 端負(fù)責(zé)調(diào)用 PL 端加速器, 實(shí)現(xiàn)對(duì)整個(gè)加速流程的控制以及檢測(cè)結(jié)果顯示。PL 端使用 Vivado HLS 語(yǔ)言設(shè)計(jì)前向推理加速器和后處理加速器, AXI (advanced extensible interface)總線為 PS 和 PL 的通信接口。
圖1 硬件加速器整體結(jié)構(gòu)Fig.1 Overall architecture of hardware accelerator
圖1 右側(cè)是前向推理加速器的整體結(jié)構(gòu)框圖。加速器由寄存器、全局控制單元、DMA (direct memory access)、片上緩存、卷積計(jì)算單元和池化計(jì)算單元構(gòu)成。ARM 通過(guò) AXI-Lite 總線寫(xiě)配置寄存器啟動(dòng)一層卷積/池化的計(jì)算, 全局控制器根據(jù)寄存器的參數(shù)啟動(dòng)各個(gè)子模塊, 這些參數(shù)包括特征圖尺寸、輸入通道數(shù)、輸出通道數(shù)、卷積核大小和卷積核步長(zhǎng)等。全局控制器啟動(dòng) DMA 進(jìn)行數(shù)據(jù)讀取,所需數(shù)據(jù)完成讀取后啟動(dòng)卷積模塊, 卷積計(jì)算完成后再次啟動(dòng) DMA, 將輸出特征圖寫(xiě)入 DDR (double data rate)內(nèi)存中。
由于 FPGA 內(nèi)部 BRAM 大小有限, 無(wú)法存儲(chǔ)所有的權(quán)重和特征圖, 為了保證加速器能夠適用于不同尺度的輸入特征圖和不同的 FPGA 型號(hào), 本文采用卷積分塊的策略對(duì)卷積和池化進(jìn)行計(jì)算。為了盡可能減少數(shù)據(jù)傳輸?shù)臅r(shí)間, 在片上分別對(duì)輸入特征圖、權(quán)重和輸出部分使用雙緩存進(jìn)行存儲(chǔ), 這樣可以將數(shù)據(jù)傳輸?shù)臅r(shí)間隱藏在卷積計(jì)算時(shí)間中, 使得計(jì)算單元的利用率可以趨近于 100%。使用雙緩存進(jìn)行卷積計(jì)算的偽代碼如圖2 所示。
圖2 卷積分塊以及雙緩存計(jì)算Fig.2 Convolution blocking and double cache calculation
圖2 代碼表示一次計(jì)算(Tw,Th,Tm)的輸出特征圖。calculate 函數(shù)表示讀取輸入特征圖和權(quán)重進(jìn)行一次卷積計(jì)算, 將計(jì)算結(jié)果寫(xiě)入 Output_buffer 中,memcpy 函數(shù)用于將 Output_buffer 中的數(shù)據(jù)搬運(yùn)到 DDR 內(nèi)存中, 在硬件中通過(guò) DMA 實(shí)現(xiàn)。由于采用雙緩存 Ouptut_buffer0 和 Ouptut_buffer1, 所以在硬件中 calculate 和 memcpy 可以并行實(shí)現(xiàn)。
圖3中的循環(huán)表示通過(guò)(Tc,Tr,Tn)分塊完成輸入特征圖和權(quán)重的卷積計(jì)算, 計(jì)算過(guò)程也使用雙緩存方式將數(shù)據(jù)傳輸和計(jì)算并行起來(lái)。Tr與Th以及Tc與Tw的關(guān)系為
圖3 分塊內(nèi)部卷積計(jì)算Fig.3 Block internal convolution calculation
片上緩存的組織方式如下: 每個(gè)輸入緩存是一個(gè)位寬為T(mén)n×bw(bw 為單個(gè)數(shù)據(jù)的位寬), 深度為T(mén)r×Tc的 RAM,Tn個(gè)通道方向的數(shù)據(jù)合并為一個(gè)數(shù)據(jù),深度方向上對(duì)應(yīng)(C,R)平面上的數(shù)據(jù)。以這種方式存儲(chǔ)的特征圖數(shù)據(jù)可以靈活地支持各種分塊方式,比如 2048 深度 RAM 既可以支持(Tc,Tr)為(40,40)的分塊存儲(chǔ), 也可以支持(6, 300)的分塊存儲(chǔ)。每個(gè)權(quán)重緩存是由Tm個(gè)位寬為T(mén)n×bw的RAM構(gòu)成,每個(gè)RAM的深度為模型所有卷積層中最大的Kw×Kh。與輸入緩存類似, 每個(gè)輸出緩存是一個(gè)位寬為T(mén)m×bw, 深度為T(mén)w×Th的 RAM。
圖4為本文設(shè)計(jì)的卷積模塊結(jié)構(gòu)圖。在每個(gè)分塊的內(nèi)部, 通過(guò)循環(huán)展開(kāi)的方式對(duì)卷積并行計(jì)算。在輸入特征圖通道方向和輸出特征圖通道方向循環(huán)展開(kāi)(圖3中最內(nèi)層的兩層循環(huán))。在輸入通道方向上的展開(kāi)次數(shù)為Pn(Pn≤Tn), 即一次計(jì)算Pn個(gè)通道方向上的輸入特征圖和權(quán)重的乘累加(multiplication and accumulation, MAC)。硬件由Pn個(gè)乘法器和 ceil(log2(Pn))級(jí)加法器樹(shù)構(gòu)成, 用流水線的方式進(jìn)行工作, 因此在一個(gè)時(shí)鐘周期內(nèi)可以完成Pn個(gè)輸入特征圖和權(quán)重的 MAC 計(jì)算。上述計(jì)算由一個(gè) PE 單元實(shí)現(xiàn), 共有Pm(本文中Pm=Tm)個(gè) PE 單元, 可以并行計(jì)算Pm個(gè)輸出通道的數(shù)據(jù)。在 FPGA 中乘法由 DSP實(shí)現(xiàn), 共需要Pm×Pn個(gè)乘法器。流水線開(kāi)始工作后,每個(gè)時(shí)鐘周期可以完成 2×Pm×Pn次 MAC 操作, 峰值計(jì)算性能為2×Pm×Pn×fGOPS (GIGA operations per second),f為頻率。
圖4 卷積模塊Fig.4 Convolution module
每個(gè)分塊的計(jì)算數(shù)據(jù)流如下: 每個(gè)PE單元從各自對(duì)應(yīng)的權(quán)重緩存中獲取Pn個(gè)權(quán)重?cái)?shù)據(jù), 在之后的每個(gè)時(shí)鐘周期, 權(quán)重寄存器中的內(nèi)容保持不變,輸入特征圖的數(shù)據(jù)從緩存中更新Pn個(gè)數(shù)據(jù)到輸入寄存器中, 與權(quán)重進(jìn)行MAC計(jì)算, 直到計(jì)算完一個(gè)分塊的輸出部分。然后將權(quán)重寄存器的數(shù)據(jù)更新為同一個(gè)卷積核的下一個(gè)權(quán)重, 重復(fù)該過(guò)程, 直到Kw×Kh×Tm×Tn個(gè)權(quán)重都與輸入特征圖進(jìn)行 MAC 計(jì)算后, 結(jié)束此分塊的計(jì)算, 切換為下一個(gè)分塊。在加法樹(shù)的最后一級(jí), 通過(guò)右移單元間計(jì)算結(jié)果移位進(jìn)行數(shù)據(jù)的量化。得到輸出數(shù)據(jù)后, ReLU激活單元根據(jù)計(jì)算結(jié)果的符號(hào)位對(duì)輸出結(jié)果進(jìn)行選擇。
基于上述數(shù)據(jù)流, 本文設(shè)計(jì)了可以兼容空洞卷積的計(jì)算方法。圖3 中, 計(jì)算常規(guī)卷積時(shí), 讀取的輸入特征圖為Input_buffer[ic][S*th+kh][S*tw+kw],空洞卷積讀取的輸入特征圖為 Input_buffer[ic][S*th+l*kh][S*tw+l*kw]。kh和kw為卷積核中每個(gè)元素對(duì)應(yīng)的地址偏移, 在權(quán)重寄存器數(shù)據(jù)更新時(shí), 該地址偏移也被更新。實(shí)現(xiàn)空洞卷積時(shí), 只需要在片上輸入緩存中讀數(shù)據(jù)時(shí)加上空洞卷積帶來(lái)的地址偏移即可。
本文將卷積層和池化層進(jìn)行融合, 在卷積單元計(jì)算出一個(gè)輸出特征圖分塊后, 如果卷積層的后一層是池化層而不是卷積層, 則將數(shù)據(jù)送入池化單元進(jìn)行最大池化計(jì)算, 否則將數(shù)據(jù)寫(xiě)回DDR內(nèi)存。與卷積的循環(huán)展開(kāi)類似, 池化單元也采用循環(huán)展開(kāi)的方法對(duì)最大池化算法進(jìn)行加速。池化單元的循環(huán)展開(kāi)次數(shù)為T(mén)m, 每一個(gè) PE 的結(jié)構(gòu)如圖5 所示。最大池化的過(guò)程是用比較器找出池化核中的最大數(shù)。以池化2×2為例, 在第一個(gè)時(shí)鐘周期, 從緩存中讀取一個(gè)數(shù)據(jù)與最小值(8bit對(duì)應(yīng)–128)做比較, 將比較結(jié)果寫(xiě)入寄存器中, 之后將每個(gè)時(shí)鐘周期寄存器中的數(shù)據(jù)與從緩存讀取的數(shù)據(jù)做比較, 當(dāng)2×2的數(shù)據(jù)做完比較后, 將寄存器中的數(shù)據(jù)寫(xiě)回輸出緩存中。
圖5 池化模塊Fig.5 Pooling module
本文訪問(wèn)DDR 的方式為通過(guò)AXI總線實(shí)現(xiàn)。AXI 的傳輸效率主要與位寬和突發(fā)傳輸有關(guān), AXI的傳輸帶寬與突發(fā)傳輸長(zhǎng)度(burst length)以及總線位寬都正相關(guān)[15]。本文提出一種數(shù)據(jù)傳輸方式, 可以充分利用 AXI 總線提供的帶寬, 同時(shí)不會(huì)帶來(lái)額外的資源和時(shí)間開(kāi)銷。
本文提出的傳輸方式如圖6所示。對(duì)于輸入特征圖, 在通道方向?qū)n×bw bit 的數(shù)據(jù)合并, 向上取整至2n, 不足的部分補(bǔ)零。例如, 當(dāng)Tn=7, bw=8 且Tn
圖6 數(shù)據(jù)傳輸方式示意圖Fig.6 Schematic diagram of data transmission pattern
利 用 Oxford Hand 數(shù) 據(jù) 集[16]對(duì) SSD 進(jìn) 行 訓(xùn) 練 ,得到 mAP (mean average precision)為 0.7820。對(duì)訓(xùn)練好的 SSD 模型進(jìn)行 8 bit 和 16 bit 的量化。將硬件加速器進(jìn)行部署測(cè)試, 構(gòu)建目標(biāo)檢測(cè)系統(tǒng), 部署平臺(tái) 為 Xilinx 的 ZCU102 開(kāi) 發(fā) 板 , FPGA 型號(hào) 為 Zynq UltraScale+XCZU9EG-2FFVB1156, PS 端軟件在Xilinx提供的pynq環(huán)境下用python語(yǔ)言編寫(xiě)。對(duì)于前向推理加速器, 參數(shù)為Pn=Tn=16,Pm=Tm=64,Tw=76,Th=38, 片上輸入特征圖緩存的深度為4096, 權(quán)重緩存深度為 9, 輸出特征圖緩存深度為 4096。
表1是加速器在不同位寬配置下的加速性能對(duì)比。當(dāng)其他配置都相同時(shí), bw=8 比 bw=16 的利用率下降一半, 與 bw=16 相比, LUT 下降 42%。16 bit 加速器的計(jì)算性能為 338.41 GOPS, 8 bit 加速器的計(jì)算性能為534.72 GOPS, 位寬降低帶來(lái)的性能提升為58%。由于 8 bit 加速器對(duì)資源的消耗減少, 可以針對(duì)時(shí)序做出更好的優(yōu)化, 實(shí)現(xiàn)的頻率更高。因此,在其他配置相同的情況下, 加速器的位寬越小, 對(duì)資源的消耗和對(duì)數(shù)據(jù)傳輸?shù)膸捫枨笤叫? 實(shí)現(xiàn)的最大計(jì)算性能越強(qiáng)。
表1 不同位寬下加速器的資源消耗及性能對(duì)比Table 1 Comparison of resource usage and performance of accelerator with different bitwidth
圖7 展示加速器為 8 bit 位寬時(shí)每一層的推理時(shí)間以及計(jì)算性能。由于從 CONV2_1 到 FC7 這幾層的輸入輸出通道數(shù)較多, 在進(jìn)行卷積計(jì)算時(shí)能充分利用DSP資源, 所以這幾層的計(jì)算性能較高, 都大于 440 GOPS。另外, 這幾層的大部分時(shí)間都用于卷積計(jì)算, 數(shù)據(jù)傳輸時(shí)間能夠很好地隱藏在卷積計(jì)算時(shí)間中, 并且大部分的計(jì)算時(shí)間都集中在 CONV1_2到FC6之間, 因此實(shí)現(xiàn)了較高的整體計(jì)算性能。
圖7 SSD分層測(cè)試Fig.7 Performance of each layer in SSD
從 CONV9_1 到 CONV11_2 的計(jì)算性能較低。這幾層的計(jì)算量較小, 卷積計(jì)算時(shí)間占比很小, 大部分的時(shí)間都用于 PS 與 PL 端的數(shù)據(jù)交互, 主要是PS通過(guò)AXI-Lite總線配置加速寄存器。對(duì)于FC7和 CONV8_1 這兩層中卷積核尺寸為 1×1 的卷積層,計(jì)算性能略低于卷積核尺寸為 3×3 的卷積層, 因?yàn)?×1 的卷積計(jì)算量較小, MAC 計(jì)算的時(shí)間少, 但需要讀寫(xiě)的特征圖數(shù)據(jù)量較大, 大部分時(shí)間用于數(shù)據(jù)傳輸。
表2 是本文設(shè)計(jì)的卷積加速器與其他目標(biāo)檢測(cè)加速器在性能和功耗方面的差異。曾成龍等[17]設(shè)計(jì)的加速器也采用卷積分塊的方式進(jìn)行計(jì)算, 但同一個(gè)分塊的數(shù)據(jù)在讀寫(xiě)時(shí)地址不連續(xù), 需要跳躍式讀數(shù)據(jù)。Ma 等[14]設(shè)計(jì)的加速 SSD 模型實(shí)現(xiàn)了 2178 GOPS 的計(jì)算性能, 每個(gè) DSP 實(shí)現(xiàn)的計(jì)算性能為0.499 GOPS, 本文為 0.506 GOPS。Zhang 等[18]在ZCU102 開(kāi)發(fā)板實(shí)現(xiàn)對(duì) YOLOv2 的加速, 但是, 由于DSP資源利用率不夠, 導(dǎo)致整體計(jì)算性能不高。由于使用的模型和部署平臺(tái)不一致, 本文的設(shè)計(jì)在推理時(shí)間方面不如其他的 SSD 目標(biāo)檢測(cè)加速器, 但本文的能耗比為20.96 GOPS/W, 僅次于Ma等[14]的21.78 GOPS/W, 實(shí)現(xiàn)了較高的能耗比, 加速器架構(gòu)效率高。
表2 與其他的FPGA工作比較Table 2 Comparison with other FPGA designs
針對(duì) SSD 目標(biāo)檢測(cè)算法, 本文基于 FPGA 設(shè)計(jì)一種硬件加速器, 通過(guò)循環(huán)展開(kāi)的方式實(shí)現(xiàn)可重配置的計(jì)算單元, 利用乘法器和加法樹(shù)構(gòu)建了卷積模塊, 可實(shí)現(xiàn)常規(guī)卷積和空洞卷積。本文設(shè)計(jì)可重配置的數(shù)據(jù)通路, 用于提高訪問(wèn) DDR 內(nèi)存的帶寬。將該硬件加速器部署至Xilinx ZCU 102 開(kāi)發(fā)板進(jìn)行驗(yàn)證, 結(jié)果表明, 加速器整體實(shí)現(xiàn) 534.72 GOPS 的計(jì)算性能。在后續(xù)工作中可進(jìn)行優(yōu)化, 對(duì)加速器進(jìn)行性能建模, 實(shí)現(xiàn)更加合理的資源分配。