周 鑫,安 虹,遲孟賢,金 旭,韓文廷
(中國科學(xué)技術(shù)大學(xué) 計(jì)算機(jī)科學(xué)與技術(shù)學(xué)院,合肥 230021)
隨著人工智能的快速發(fā)展,現(xiàn)場可編程邏輯門陣列(FPGA, Field Programmable Gate Array,)憑借其強(qiáng)實(shí)時(shí)性和低功耗等優(yōu)勢獲得廣泛關(guān)注[1].利用 OpenCL 針對 FPGA 進(jìn)行編程的開發(fā)方式因其開發(fā)簡易的特點(diǎn)也獲得了重視[2,3].
為探究利用 OpenCL 實(shí)現(xiàn)的全連接神經(jīng)網(wǎng)絡(luò)前向過程的效率與優(yōu)化方法,本文利用 OpenCL 在 Intel Arria10 FPGA 上設(shè)計(jì)并實(shí)現(xiàn)了全連接神經(jīng)網(wǎng)絡(luò)前向過程,并針對系統(tǒng)的存儲瓶頸,通過分組劃分、數(shù)據(jù)復(fù)用、優(yōu)化激活函數(shù)、單指令多數(shù)據(jù)流、浮點(diǎn)數(shù)半精化等策略進(jìn)行了優(yōu)化,平衡了系統(tǒng)中的資源占用情況,擴(kuò)大了電路規(guī)模,提升了系統(tǒng)性能;優(yōu)化后的版本與基準(zhǔn)版本相比,得到了2.19x的加速.優(yōu)化后,系統(tǒng)的 RAM 占用率達(dá)到94%,DSP 占用率達(dá)到42%.
由于 FPGA 的強(qiáng)實(shí)時(shí)性非常適合神經(jīng)網(wǎng)絡(luò)的前向過程,很多開發(fā)者利用 OpenCL 針對卷積神經(jīng)網(wǎng)絡(luò)(Convolutional Neural Network)已經(jīng)做了較為詳盡的工作.Wang Dong 設(shè)計(jì)了流水線的卷積計(jì)算內(nèi)核,并將工作開源[5];Zhang Jia-liang 提出了衡量卷積性能的模型[6],探討了數(shù)據(jù)存儲方式對性能的影響,并設(shè)計(jì)了 cache 、利用復(fù)用寄存器等技術(shù)進(jìn)行了優(yōu)化[6];Naveen Suda 針對吞吐率,利用定點(diǎn)化技術(shù)進(jìn)行了優(yōu)化[7];Utku Aydonat 利用 Winograd 算法實(shí)現(xiàn)了卷積運(yùn)算,降低了訪存需求,系統(tǒng)瓶頸不再是存儲資源,而是計(jì)算資源[8].在卷積神經(jīng)網(wǎng)絡(luò)中,全連接層的計(jì)算量所占比重較小,因此,以上工作均直接復(fù)用卷積層的計(jì)算內(nèi)核處理全連接層,并未深入探究全連接層的特點(diǎn)與優(yōu)化方法[5-8].本文的工作針對全連接神經(jīng)網(wǎng)絡(luò)的特性,深入分析全連接網(wǎng)絡(luò)的特點(diǎn),提出了適用于全連接神經(jīng)網(wǎng)絡(luò)的系統(tǒng)設(shè)計(jì)方案,并針對基準(zhǔn)系統(tǒng)中的瓶頸進(jìn)行了一系列的優(yōu)化.
OpenCL 將計(jì)算分為主機(jī)(Host)端與設(shè)備(Device)端兩個(gè)部分[10],采用 offload 工作模式[9].設(shè)備運(yùn)行 kernel 代碼實(shí)現(xiàn)加速.Kernel 代碼的一次實(shí)例化稱為一個(gè)工作項(xiàng)(WI, Work Item),多個(gè)執(zhí)行同一任務(wù)的 WI 利用流水線實(shí)現(xiàn)并行執(zhí)行;多個(gè)存在數(shù)據(jù)同步或互斥的 WI 組織為一個(gè)工作組(WG, Work Group); 多個(gè)存在數(shù)據(jù)依賴關(guān)系的 WG 合并為一個(gè) N維工作空間(NDRange)[10].
每個(gè)工作項(xiàng)均擁有私有內(nèi)存;同一工作組中,所有的工作項(xiàng)共享本地內(nèi)存;一個(gè)工作空間內(nèi)所有工作項(xiàng)共享全局內(nèi)存.通常情況下,在 FPGA 中,私有內(nèi)存由片上寄存器實(shí)現(xiàn),因此訪問速度最快,但容量有限;本地內(nèi)存由 Block Memory 實(shí)現(xiàn);全局內(nèi)存由板載內(nèi)存實(shí)現(xiàn).
全連接神經(jīng)網(wǎng)絡(luò)的主要計(jì)算在全連接層和 Sigmoid 函數(shù)內(nèi).其中,全連接層的基本的數(shù)學(xué)計(jì)算公式為:
(1)
在全連接神經(jīng)網(wǎng)絡(luò)模型中,為了精確表示數(shù)據(jù)特征,每層的神經(jīng)元的規(guī)模非常龐大.因此,優(yōu)化思路應(yīng)該集中在數(shù)據(jù)存儲、減少計(jì)算量兩方面.
在全連接神經(jīng)網(wǎng)絡(luò)中,每層的計(jì)算量非常龐大.考慮將每層的神經(jīng)元拆分為固定大小的計(jì)算組.根據(jù)這一思路,設(shè)每層節(jié)點(diǎn)數(shù)為S,將S個(gè)節(jié)點(diǎn)劃分為K組,設(shè)C=?S/K」.將分組后的輸入數(shù)據(jù)標(biāo)記為Ci,i∈(1,…,K);同時(shí)將每層每個(gè)節(jié)點(diǎn)對應(yīng)的權(quán)值同樣劃分為K組,標(biāo)記為Wij,i∈(1,…,K),表示對應(yīng)節(jié)點(diǎn)的編號;j∈(1,…,K),表示權(quán)值組的編號.
下層神經(jīng)網(wǎng)絡(luò)的每一神經(jīng)元的輸入值由K組計(jì)算求得的部分和相加得出,其計(jì)算公式為:
(2)
由計(jì)算特性可知,各組之間無數(shù)據(jù)依賴關(guān)系.因此可以將相同編號的數(shù)據(jù)組與權(quán)重組的運(yùn)算映射到一個(gè) Work Item 上,實(shí)現(xiàn)粗粒度的組間并行計(jì)算.此時(shí)每個(gè) Work Item計(jì)算局部的乘加和,每個(gè)Work Item 的結(jié)果相加即為下層網(wǎng)絡(luò)中一個(gè)節(jié)點(diǎn)接受的值.

圖1 數(shù)據(jù)與權(quán)值復(fù)用Fig.1 Reuse of weights and input feature
4.2.1 數(shù)據(jù)復(fù)用設(shè)計(jì)
假設(shè)計(jì)算過程中,權(quán)值的路數(shù)為M,輸入數(shù)據(jù)路數(shù)為N,權(quán)值與數(shù)據(jù)之間的計(jì)算關(guān)系如圖1所示.
權(quán)值與輸入數(shù)據(jù)的復(fù)用,可以實(shí)現(xiàn)一次取數(shù),多次計(jì)算.因此,這一數(shù)據(jù)復(fù)用方式減少了數(shù)據(jù)的換出換入操作,降低了訪存延時(shí),提升了數(shù)據(jù)利用的效率,提高了全連接神經(jīng)網(wǎng)絡(luò)的并行處理能力.
4.2.2 存儲設(shè)計(jì)
實(shí)現(xiàn)輸入數(shù)據(jù)和權(quán)值的復(fù)用后,考慮結(jié)合多路輸入數(shù)據(jù)與多路權(quán)值的排布特征,設(shè)計(jì)權(quán)值與輸入數(shù)據(jù)的排布方式.
在初始狀態(tài)時(shí),同路數(shù)據(jù)按行優(yōu)先的順序存儲在內(nèi)存中連續(xù)的地址空間上,需多次訪存讀取多路數(shù)據(jù)與多路權(quán)值.因此,考慮采用列優(yōu)先交叉存儲的方式.順序存儲與交叉存儲在訪存時(shí)的區(qū)別如圖2所示.

圖2 順序存儲與交叉存儲Fig.2 Sequential and interleaving storage
采用列優(yōu)先的交叉存儲模式可以大大減少訪存次數(shù).在同一 Work Group 中的Work Item 并行計(jì)算完畢后統(tǒng)一刷新,重新從內(nèi)存中讀取數(shù)據(jù).這一策略可以減少訪存次數(shù),提高數(shù)據(jù)命中率,較好地發(fā)揮數(shù)據(jù)局部性優(yōu)勢.
劃分計(jì)算組的策略將每一個(gè)計(jì)算組映射為一個(gè) Work Item,Work Item 并行執(zhí)行,實(shí)現(xiàn)計(jì)算組計(jì)算的并行.計(jì)算組內(nèi)部則可以利用 SIMD 技術(shù)實(shí)現(xiàn)組內(nèi)并行,提升數(shù)據(jù)處理速率.但 SIMD 的路數(shù)并非越多越好,因?yàn)?Work Item 的并行與 SIMD 并行都會占用大量的硬件資源,若多數(shù)據(jù)的路數(shù)超過了物理帶寬的限制,反而對計(jì)算速度產(chǎn)生負(fù)面影響,應(yīng)根據(jù)情況選擇合適的 SIMD 路數(shù).
Sigmoid 函數(shù)的公式為:
(3)
計(jì)算主要在e-x上.Sigmoid 函數(shù)具有對稱性:函數(shù)關(guān)于 (0,0.5) 對稱,因此可以只關(guān)注自變量在正數(shù)區(qū)間的計(jì)算,自變量為負(fù)數(shù)時(shí),其函數(shù)值可以由自變量絕對值的 Sigmoid 函數(shù)得到[12],如公式(4)所示.
(4)
同時(shí),Sigmoid 函數(shù)具有飽和性.在x>12 后,函數(shù)處于飽和狀態(tài),函數(shù)值無限趨近于1,因此在x>12 后函數(shù)值近似為1[12].
實(shí)現(xiàn)Sigmoid函數(shù)的方法一般情況下有四種:利用泰勒級數(shù)計(jì)算、查表法、坐標(biāo)旋轉(zhuǎn)數(shù)字計(jì)算機(jī)法,以及分段函數(shù)逼近法[13].為尋找最優(yōu)方法,通過實(shí)現(xiàn)泰勒級數(shù)法、查表法、分段函數(shù)逼近法分別進(jìn)行實(shí)驗(yàn).
4.4.1 泰勒級數(shù)法
利用泰勒展開式計(jì)算e-x,實(shí)現(xiàn)Sigmoid 函數(shù).泰勒展開式為:
(5)
使用泰勒公式時(shí),展開的級數(shù)對精度影響很大.在保證小數(shù)點(diǎn)后三位的精度時(shí),至少需要進(jìn)行5階的泰勒級數(shù)展開來計(jì)算,浪費(fèi)了計(jì)算資源,因此性能并非最優(yōu)[14].
4.4.2 查表法
查表法利用采樣的原理,將x對應(yīng)的Sigmoid函數(shù)值儲存在存儲器中[13],同時(shí),利用對稱性和飽和性減少存儲規(guī)模.
但由于全連接神經(jīng)網(wǎng)絡(luò)對精度要求較高,采樣點(diǎn)和其對應(yīng)的Sigmoid函數(shù)值數(shù)目較多,因此需要較大的空間儲存查找表,如設(shè)計(jì)采樣間隔為10-3,為保證采樣精度的準(zhǔn)確性,使用16bit作為采樣精度,需消耗192Kbit 的存儲空間.
4.4.3 分段函數(shù)逼近法
由于Sigmoid 函數(shù)中e-x的計(jì)算比較復(fù)雜,因此考慮將Sigmoid 函數(shù)分段,每段使用簡化的函數(shù)進(jìn)行模擬計(jì)算,在計(jì)算Sigmoid 函數(shù)值時(shí)根據(jù)變量所在的區(qū)間,使用不同的簡化函數(shù)計(jì)算公式進(jìn)行模擬,得到Sigmoid的函數(shù)結(jié)果[15].同時(shí)利用Sigmoid函數(shù)的對稱性和飽和性減少計(jì)算量.
根據(jù)Sigmoid 函數(shù)特征,以函數(shù)值的變化間隔對函數(shù)分段.為減少模擬函數(shù)銜接處的誤差,將擬合誤差較大的部分放入下一區(qū)間,同時(shí)適當(dāng)縮小每個(gè)區(qū)間的跨度.經(jīng)過實(shí)驗(yàn)得到9個(gè)分段函數(shù),每段函數(shù)R2均為1,分段模擬函數(shù)的基本形式為:f(x)=ax3+bx2+cx+d分段區(qū)間內(nèi),模擬函數(shù)參數(shù)、結(jié)果與 Sigmoid 函數(shù)的最大誤差如表1所示.

表1 分段模擬函數(shù)表Table 1 Table of section analogue function
此時(shí),計(jì)算Sigmoid 函數(shù)時(shí),利用自變量所在區(qū)間對應(yīng)的參數(shù)使用三階多項(xiàng)式函數(shù)模擬即可[16].將參數(shù)存儲在 片上寄存器構(gòu)成的 Cache 中,可以提高參數(shù)的訪問速度.
利用9段模擬函數(shù)逼近時(shí),誤差波動范圍較大,少數(shù)情況下誤差可達(dá)10-3的數(shù)量級,如表1所示.由于全連接神經(jīng)網(wǎng)絡(luò)中每層神經(jīng)元的數(shù)目十分龐大,因此,無法有效避免誤差較大的數(shù)據(jù)出現(xiàn);同時(shí),由于全連接的結(jié)構(gòu),即使誤差較小,經(jīng)過全連接過程也會累積為較大的誤差,對結(jié)果的精確性產(chǎn)生一定的影響.
因此,這一激活函數(shù)的模擬方法可以考慮使用在非全連接的神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)中,降低計(jì)算的復(fù)雜度并保證精度,如卷積神經(jīng)網(wǎng)絡(luò).
4.4.4 差分查表法
為了解決查表法對存儲資源的浪費(fèi)問題,嘗試使用函數(shù)值分段與查表兩種策略結(jié)合的方式實(shí)現(xiàn) Sigmoid 函數(shù)設(shè)計(jì),在保證精度的同時(shí)實(shí)現(xiàn)高效的 Sigmoid 計(jì)算.
如前所述,在設(shè)計(jì) Sigmoid 的查找表時(shí),可以利用函數(shù)的對稱性和飽和性;儲存對應(yīng)表值時(shí),采用0.5作為基準(zhǔn)值,表中儲存函數(shù)值相對于基準(zhǔn)值的偏移量,可以減少用于表示函數(shù)值的數(shù)據(jù)的位數(shù).
按照這一思路,設(shè)計(jì)差分查找表.
首先,在Sigmoid 函數(shù)自變量為[0,12]的區(qū)間內(nèi),按Δy的間隔對函數(shù)采樣,得到共計(jì)0.5/(Δy)個(gè)采樣點(diǎn),作為構(gòu)建查找表的基礎(chǔ).再將采樣點(diǎn)分段標(biāo)記,設(shè)第i段的第k個(gè)采樣點(diǎn)對應(yīng)的函數(shù)值與段首采樣點(diǎn)基準(zhǔn)值Basei的差值為Δi.k,則存儲時(shí)只需儲存各段段首基準(zhǔn)采樣點(diǎn)的函數(shù)值Basei和差值Δi.k.由于在節(jié)約存儲空間的同時(shí)可以實(shí)現(xiàn)高效查找.如圖3所示.

圖3 差分設(shè)計(jì)Fig.3 Difference design
在儲存Basei和Δi.k時(shí),可以在不損失精度的前提下降低Basei和Δi.k占用的存儲空間,壓縮表的規(guī)模.例如使用16bit儲存Basei的值,使用8bit 儲存Δi.k的值,可以將查找表的規(guī)模縮小為原始表的四分之一.
由于系統(tǒng)設(shè)計(jì)的主要瓶頸在于 RAM 的占用率與 DSP 的使用率非常不平衡,因此,需考慮降低 RAM 的占用率,提升 DSP 的使用率,來擴(kuò)大電路規(guī)模和計(jì)算規(guī)模[17].利用半精化可以節(jié)省一半的存儲空間,同時(shí)也可以保證一定的精度.輸入數(shù)據(jù)和權(quán)重半精化的設(shè)計(jì)使存儲的占用減少了一半,可以擴(kuò)大電路規(guī)模和計(jì)算規(guī)模來進(jìn)行優(yōu)化,以提高吞吐率.
為衡量利用 OpenCL 實(shí)現(xiàn)和優(yōu)化的全連接神經(jīng)網(wǎng)絡(luò)的性能,針對實(shí)際生產(chǎn)中使用的全連接神經(jīng)網(wǎng)絡(luò)模型設(shè)計(jì)實(shí)驗(yàn),進(jìn)行驗(yàn)證.這一網(wǎng)絡(luò)由7層全連接層組成,其中每個(gè)單層網(wǎng)絡(luò)均擁有2048個(gè)神經(jīng)元,采用 Sigmoid 作為激活函數(shù).
由于數(shù)據(jù)組的個(gè)數(shù)與硬件資源消耗強(qiáng)相關(guān),因此數(shù)據(jù)組的規(guī)模選擇尤為重要.若數(shù)據(jù)組內(nèi)數(shù)據(jù)規(guī)模偏大,則Work Item 的并行粒度較大,計(jì)算時(shí)間較長,同時(shí)對 RAM 的消耗較大;若數(shù)據(jù)組內(nèi)數(shù)據(jù)規(guī)模偏小,則不利于組內(nèi)進(jìn)一步細(xì)粒度的優(yōu)化.Intel OpenCL SDK 提供了優(yōu)化分析報(bào)告幫助使用者查看系統(tǒng)資源的占用情況,如表2所示.由于系統(tǒng)中稀缺的資源為計(jì)算資源 DSP 與內(nèi)存資源 RAM,全連接網(wǎng)絡(luò)中很容易出現(xiàn) DSP 與 RAM 消耗不平衡的情況,因此需要采用合適的取值進(jìn)行計(jì)算組的劃分.

表2 資源占用報(bào)告Table 2 Report of resource usage
表2是初始組內(nèi)數(shù)據(jù)規(guī)模為32,即 C=32 時(shí),系統(tǒng)資源占用比例.C 為32時(shí),存儲與計(jì)算資源的占用較為平衡,同時(shí)系統(tǒng)內(nèi)仍有足夠的資源支持下一步的優(yōu)化.
實(shí)現(xiàn)輸入數(shù)據(jù)與權(quán)重的多路復(fù)用可以有效地提高數(shù)據(jù)命中率,如圖4所示.

圖4 數(shù)據(jù)復(fù)用率Fig.4 Reusing rate of data
根據(jù)訪存帶寬與計(jì)算帶寬的限制,系統(tǒng)的采用16路輸入數(shù)據(jù)和16路權(quán)值,即M=16,N=16.此時(shí)數(shù)據(jù)復(fù)用率由6.5%提升至99.7%.
為保證數(shù)據(jù)精度,以函數(shù)值的變化設(shè)計(jì)采樣區(qū)間.將y∈(0.5,1)的采樣區(qū)間劃分為5段,每段函數(shù)值的變化范圍為0.1.段內(nèi)按Δy=10-4的間隔對函數(shù)采樣,得到5×103個(gè)采樣點(diǎn),使用16bit 儲存表內(nèi)數(shù)據(jù)時(shí),查找表的尺寸為160kbit.利用壓縮策略,使用16bit儲存第i段的段首采樣基準(zhǔn)值Basei,8bit 儲存偏移量Δi.k,其中6bit表示尾數(shù),2bit表示指數(shù),則查找表可以壓縮為81kbit,節(jié)約了約一半的存儲空間.
半精策略,是將32 bit 的單精度浮點(diǎn)數(shù)轉(zhuǎn)換為16 bit 的半精浮點(diǎn)數(shù).這一策略以損失少許數(shù)字精度為代價(jià),有效地降低了系統(tǒng)中的存儲開銷.采用半精策略后,RAM 占用率降低為初始值的一半,因此,可以將電路規(guī)模擴(kuò)大為基準(zhǔn)系統(tǒng)的兩倍.
實(shí)現(xiàn)電路擴(kuò)增后,系統(tǒng)的資源占用情況如表3所示.
通過表3可以看出,半精策略可以有效地降低存儲開銷,擴(kuò)大電路規(guī)模.

表3 系統(tǒng)資源占用情況Table 3 Report of resource usage
將優(yōu)化后的工作與基準(zhǔn)工作進(jìn)行對比,如圖5所示.

圖5 優(yōu)化前后的對比Fig.5 Comparison between baseline and present version
經(jīng)過一系列的優(yōu)化后,系統(tǒng)中的DSP使用率由21%升至42%,利用率提升了一倍;RAM 的占用,由65% 提升至 94%;單組數(shù)據(jù)的平均運(yùn)行時(shí)間由81ms降低至37ms,得到了2.19倍的加速,如圖5所示.此時(shí)限制系統(tǒng)進(jìn)一步優(yōu)化的瓶頸為 RAM 的容量.
本工作利用 Intel OpenCL SDK 在 FPGA 上設(shè)計(jì)并實(shí)現(xiàn)了全連接神經(jīng)網(wǎng)絡(luò),同時(shí)針對 FPGA 的特點(diǎn)進(jìn)行了進(jìn)一步的優(yōu)化.針對計(jì)算部分,在單路數(shù)據(jù)的基礎(chǔ)上,實(shí)現(xiàn)了多數(shù)據(jù)的多路復(fù)用,討論了在多種復(fù)用方式下分組策略的優(yōu)化手段;針對激活函數(shù),在傳統(tǒng)解決方案的基礎(chǔ)上,提出和實(shí)現(xiàn)了差分查表設(shè)計(jì)方案,在保證精度的同時(shí)節(jié)省了內(nèi)存資源;針對 RAM 消耗過多的瓶頸,采用半精技術(shù)釋放了有限的存儲資源,有效地?cái)U(kuò)大了電路規(guī)模和計(jì)算規(guī)模.優(yōu)化后,系統(tǒng)的 DSP 使用率上升了一倍,達(dá)到了 42%;系統(tǒng)主頻達(dá)到了380MHz,并得到了2.19倍的加速.
利用 OpenCL SDK 實(shí)現(xiàn)的全連接神經(jīng)網(wǎng)絡(luò)充分挖掘了 FPGA 高能效比、低響應(yīng)時(shí)延的優(yōu)點(diǎn),雖然在性能上有一定的損失,無法精確調(diào)配系統(tǒng)中的資源,但這一開發(fā)方式降低了 FPGA 的開發(fā)難度、縮短了開發(fā)周期、對軟件開發(fā)者更加友好,性價(jià)比較高.