馬佳利,朱智強,戴樂育,郭松輝,向建安
(1.信息工程大學 密碼工程學院,河南 鄭州 450001;2.95010部隊,廣東 汕頭 515000)
計算資源是卷積神經網絡(convolutional neural networks,CNN)[1-3]得到發展和應用的基礎。但是,隨著研究的不斷深入,CNN在其分類精度不斷提升的同時還引進了一些問題,網絡的拓撲結構日趨復雜,算法的運算量和參數量也有所增加,這些規模較大的模型正變得難以處理[4]。與此同時,半導體器件的發展卻逐漸變慢,傳統的CPU運算能力的提升速度跟不上神經網絡參數膨脹的速度。為了更好地應用CNN,需要性能更佳的加速器件。
使用GPU進行CNN的運算是目前廣泛采用的一種加速方法。GPU當中存在大量并行計算資源,將CNN中的各部分運算適配到這些計算核中并行處理,可以實現運算加速。但是,GPU作為一種通用處理器,并不是為卷積神經網絡專門設計的,因此沒有考慮到當前CNN運算過程中的一些特性,例如低精度運算和稀疏性[5],這將導致運算加速的不充分。
為進一步提高CNN的運算速度,更好的方法是定制專用加速器。這種方法基本思想是讓器件“適應”CNN,因此需要根據CNN各部分的運算特點,設計專門的電路,以完成網絡各部分的運算與控制。考慮到卷積運算通常占CNN運算總量的90%以上[6],有效的卷積加速方案顯著影響硬件CNN加速器的性能,需要重點研究卷積運算的加速。本文通過分析卷積運算的特點和運算中數據傳輸的過程,設計了多數據流并行卷積運算加速引擎,與已有方案相比,實現了運算速度的提升和邏輯資源的減少。
CNN的結構主要包括卷積層、池化層和全連接層。其中卷積層是CNN中特有的運算層,是網絡具有良好分類效果的基礎,還是網絡運算中耗時最多的部分。卷積層的運算包括卷積運算和激活函數運算。卷積運算涉及多層嵌套循環,運算復雜且耗時多,是卷積層最重要的環節;激活函數當前大多使用ReLU函數,實現較為簡單。因此對CNN加速器研究的重點是卷積運算的加速,需要對卷積運算進行研究分析。
卷積運算的計算方式和偽代碼表示如圖1所示,卷積核在輸入特征圖上從左向右、從上到下按照設定的步長S進行滑動,每次滑動完成一次Nkx×Nky乘累加運算,得到的結果作為輸出特征圖的一個像素值。可以看到,卷積運算中存在大量并行運算,如何利用并行性是實現運算加速的重點。由于當前主流的CNN中存在大量步長為一的3×3卷積運算,本文針對S=1,Nkx=3,Nky=3的卷積運算進行加速。

圖1 卷積運算計算方式及偽代碼表示
目前,卷積運算的硬件加速方法存在兩種思路,一種是運算轉換,一種是流水線卷積。
運算轉換的目的是將卷積運算轉換為適合硬件實現的或算法復雜度較低的其它運算。最常見的運算轉換方法是將卷積運算轉換為矩陣乘法[7],矩陣乘法的硬件實現方式簡單,有利于簡化電路設計。除此之外,一些研究團隊從降低算法復雜度的角度出發,提出了快速傅里葉變換[8]和Winograd轉換[9]的方法,在特定的卷積核尺寸情況下,這兩種轉換可以減少計算量。但是,運算轉換的方法需要設計專門的轉換電路,消耗了更多的邏輯資源,而且在運算過程中還需要消耗一定時間進行轉換。
根據卷積運算特有的運算模式,一些研究學者提出了流水線并行加速方法[10]。這種方法通過在電路中設計一組移位寄存器,構造了卷積運算的滑動窗口。寄存器中的值每更新一次相當于滑動窗口向右移動一次,取滑動窗口的數據與卷積核數據進行乘累加運算,得到卷積運算的結果。流水線并行加速方法如圖2所示。

圖2 流水線并行加速方法
流水線并行加速方法充分考慮了卷積運算特點,設計了卷積運算專用電路,每個時鐘周期完成9次乘法運算,運算效率高;此外,這種方法數據路由方式簡單,只需將輸入特征圖的值逐行依次輸入到移位寄存器中即可,簡化了控制電路的設計;與運算轉換方法相比,這種方法不需要設計相應的轉換電路,也不存在進行數據格式轉換的時間。但是,這種方法仍存在一些不足,主要包括3個方面:
(1)電路設計中需要大量寄存器用于構造滑動窗口,但其中大部分寄存器沒有參與運算;
(2)為了充滿流水線,電路運行過程中需要進行較長時間的數據輸入,期間無法進行運算;
(3)這種方法只對固定尺寸的輸入特征圖有加速效果,當尺寸大小發生改變時,輸出異常。
針對上述流水線并行加速方法中存在的問題,本文提出了一種多數據流并行卷積運算方法,并設計了相應的加速引擎。在FPGA中進行設計驗證,通過對比實驗得出,多數據流并行卷積運算加速引擎采用多數據流并行輸入的方法有效減少了設計所需的寄存器數量,提高了卷積運算的速度,得到了良好的應用效果。
流水線并行加速方法的設計中需要大量寄存器,用來存儲已經輸入但還沒有參與運算的像素值,導致大量寄存器資源的浪費以及充滿流水線帶來的時延。為了解決這種方法帶來的問題,本文提出了一種多數據流并行卷積運算方法,將輸入特征圖的3行數據同時輸入,輸入數據即為參與運算的數據,減少了用于存儲尚未參與運算的像素值所需寄存器的數量,同時加快了從數據輸入到開始運算的過程。這種方法的運算如圖3所示。

圖3 多數據流卷積運算
多數據流并行卷積運算方法中數據流一共包括3條,分別來自輸入特征圖前3行,按照由左至右、由上至下的順序依次輸入。輸入的像素值將會存儲在3組長度為3的移位寄存器中,構成卷積運算中的滑動窗口。當移位寄存器被充滿后開始進行運算,取滑動窗口數據與卷積核數據進行乘累加運算,得到卷積運算的一個輸出。
多數據流并行卷積運算方法中輸入數據即為直接參與運算的數據,不需要額外的寄存器存儲等待運算的數據,因此可以顯著減少設計中所需寄存器數量。數據流開始輸入到運算開始只需要充滿長度為3的移位寄存器,卷積運算從數據輸入到運算結束所需的時間有所減少。此外,多數據流并行卷積運算方法相比流水線并行加速的方法更具靈活性,對于輸入特征圖的尺寸沒有限制,對于任意3×3卷積運算均可以實現加速,因此在CNN中不同卷積層可以實現復用,有益于提高CNN加速器的整體性能。
基于上述方法,本節設計了多數據流并行卷積運算加速引擎。加速引擎共包括3部分,數據流輸入電路、運算電路和輸出控制電路。考慮卷積神經網絡精度需要以及邏輯資源的限制,像素值位寬選取為16位,權重值位寬選取為8位。加速引擎整體框架如圖4所示。

圖4 加速引擎整體框架
2.2.1 數據流輸入電路設計
數據流輸入電路的功能是將輸入特征圖的像素值傳輸到運算單元中。像素值數據存儲在RAM中,由于RAM只有一個輸出端口,不能實現輸入特征圖3行像素值同時輸出。本文在輸入電路部分設計了一個數據引導控制器,并通過sel[1∶0]信號對電路進行控制,實現了多個數據流同時輸出的功能。數據流輸入部分的電路設計如圖5所示。

圖5 數據流輸入電路
數據流輸入電路的輸入信號為基地址信息address[9∶0]和控制信號sel[1∶0],它們經過一個地址譯碼電路得到RAM的實際讀地址,用于輸出不同行的像素值。實際上,sel[1∶0]信號為00時輸出的是第一行的數據,此時讀地址即為基地址;sel[1∶0]信號為01時輸出第二行的數據,讀地址為基地址加上存儲一整行像素值所需要的地址空間;sel[1∶0]信號為10時輸出第三行的數據,讀地址為基地址加上存儲兩行像素值所需要的地址空間;sel[1∶0]信號為11時,RAM不輸出,讀使能信號rd置為零。
數據引導控制器的作用是將RAM輸出的不同行數據傳輸到正確的位置,它同樣受到sel[1∶0]信號的控制,將數據路由到3個不同的FIFO中。具體說來,sel[1∶0]信號取00、01和10時,分別對應于輸出到FIFO1、FIFO2、FIFO3;sel[1∶0]信號取11時,數據引導控制器不輸出。數據引導控制器4種狀態交替出現,設定讀位寬為64位(4個像素值的位寬),則RAM根據地址每次讀取連續4個像素值,就可以實現各個FIFO平均每個周期寫入一個像素值。
3個FIFO分別接收來自數據引導控制器3行像素值,由于3行數據需要同時輸出,因此要判斷3個FIFO均為非空才能開始輸出,FIFO的讀信號由empty信號控制,如圖6所示。FIFO的讀寫位寬設置為16位,與像素值位寬相等。在電路運行過程中,FIFO中最多可能存儲7個像素值,即FIFO1在其開始接受數據后第5個時鐘周期,為了保證FIFO不溢出,FIFO的深度設置為8。FIFO開始接收數據之后,其中至少存在一個像素值,empty信號一直為0,FIFO不斷輸出數據,在電路運行過程中不存在等待時間。

圖6 FIFO輸出控制電路
2.2.2 運算電路與輸出控制電路設計
運算電路接收來自數據流輸入電路的3行像素值,并將其存儲在3組移位寄存器中,當這些寄存器都充滿數據,開始進行運算。取移位寄存器的數據與已經讀取的卷積核數據進行乘累加運算,得到卷積運算輸出。運算電路的整體結構如圖7所示。

圖7 卷積運算電路
值得注意的是,卷積窗口在移動到輸入特征圖行尾時會產生跨行輸入,如圖8所示,其中陰影部分表示卷積窗口的位置。跨行期間得到的運算結果需要忽略。

圖8 卷積窗口跨行
本文在運算電路部分設計了一個輸出控制電路,用于屏蔽卷積窗口跨行時產生的輸出,當卷積窗口跨行時控制運算單元的輸出結果不寫到RAM中,輸出屏蔽模塊電路如圖9所示。

圖9 輸出屏蔽電路
輸出屏蔽電路由計數器和比較器組成,當運算單元開始輸出時計數器開始計數,之后每輸出一個結果計數器值加一,當計數器值為輸入特征圖的行素數減二時,卷積窗口發生跨行,此時屏蔽運算單元的輸出結果;當計數器值為輸入特征圖的行素數時,卷積窗口跨行結束,不再屏蔽輸出,同時計數器值清零,重新開始計數。
為了驗證設計的性能,實驗使用FPGA實現多數據流并行卷積運算加速引擎,以Altera公司的Stratix IV系列EP4SGX70DF29C3 FPGA芯片作為主要硬件環境,在Qua-rtus II下完成設計的仿真和分析,以此來驗證本設計的正確性與高效性。
為驗證所設計的加速引擎功能正確,利用ModelSim軟件進行功能仿真,設置一組便于觀測的數據,如圖10所示。

圖10 輸入特征圖數據(左)和卷積核數據(右)
對于這一組數據,仿真波形如圖11所示。其中A1、A2、A3分別代表數據流輸入電路生成的3行像素值,與輸入特征圖前3行的輸入一致;add_temp5 代表經過乘累加運算得到的結果,包括滑動窗口跨行時產生結果;result代表卷積運算的結果,屏蔽了跨行時的輸出結果。通過仿真波形圖,可以得到本文設計的卷積運算加速引擎運行正確。

圖11 仿真波形
為了更好地描述多數據流并行卷積運算加速引擎的性能,本文與已有方案設計[10]進行了對比實驗,通過控制變量的方法,得到本設計在相同類型卷積運算中的資源使用情況以及運算速度。實驗中使用的輸入特征圖尺寸為32×32。
在資源使用方面,在Quartus II開發平臺上完成加速引擎的設計,得到資源消耗情況見表1。

表1 資源使用情況
由表1可以看出多數據流并行卷積運算加速引擎的設計所消耗邏輯資源數較少,因此在此FPGA中最多可以使用5個加速引擎同時對卷積運算進行加速,提高運算的并行度。與文獻[10]中的設計相比,該設計所需寄存器數量減少了30.6%,查找表數減少了10.3%,達到了節約了邏輯資源的效果。
在運算速度方面,實驗中設置了與文獻[10]中設計相同的時鐘頻率(50 MHz),得到完成相同的運算(卷積運算+激活函數+池化運算)所需時間。由于本文僅對卷積運算設計了加速引擎,為達到控制變量的效果,完成全部運算的時間等于本設計中完成卷積運算的時間加上設計文獻[10]中完成激活函數以及池化運算所需時間。得到不同加速方案完成同一運算所需時間,見表2。

表2 電路運行速度
由表2可以看出,與CPU或GPU解決方案相比,設計專用加速器的方法能夠顯著提高CNN的運算速度。與流水線并行加速方案相比,本設計由于縮短數據流輸入所需時間,整體運算速度提高了7.37%。
CNN的運算過程中卷積運算耗時最長,為提高CNN的運行效率,需要對卷積運算進行加速。本文分析卷積運算的運算模式和數據路由方式,提出了一種多數據流卷積運算方法,并基于這種方法設計了加速引擎。在FPGA上完成了該加速引擎的設計,通過功能仿真驗證該設計的正確性,仿真波形圖表明運算輸出正確。與已有設計進行了對比實驗,對于相同形式的卷積運算,該設計需要的寄存器資源減少了30.6%,對于相同的運算量,速度提高了7.37%,該加速引擎的設計能夠有效地加速卷積運算。