劉華,陶冠男,楊文清
(廣東電網(wǎng)有限責(zé)任公司廣州供電局,廣州 510000)
近年來,人工智能技術(shù)飛速發(fā)展,越來越多的智能化產(chǎn)品開始在日常生活中嶄露頭角,尤其是以卷積神經(jīng)網(wǎng)絡(luò)(Convolutional Neural Network,CNN)[1]為基礎(chǔ)的深度學(xué)習(xí)技術(shù)。卷積神經(jīng)網(wǎng)絡(luò)以獨特的局部感知和權(quán)值共享結(jié)構(gòu)能夠更好地進行特征提取,其所帶來的實際應(yīng)用價值不斷地凸顯,在圖像分類[2]、目標(biāo)檢測[3]、語義分割[4]以及語音識別[5]等領(lǐng)域都有著十分重要的應(yīng)用。
GPU是專用的圖像處理單元,擁有大量的計算資源,隨著NVIDIA推出統(tǒng)一計算設(shè)備架構(gòu)(Compute Unified Device Architecture,CUDA),結(jié)合cuDNN[6]深度神經(jīng)網(wǎng)絡(luò)的GPU加速庫,GPU已經(jīng)成為主流的硬件計算平臺,但GPU功耗較高、體積較大,難以應(yīng)用到對體積與功耗要求較高的嵌入式移動與邊緣設(shè)備當(dāng)中。專用集成電路(Application Specific Integrated Circuit,ASIC)在嵌入式平臺的卷積神經(jīng)網(wǎng)絡(luò)硬件加速上具有絕對的優(yōu)勢,但ASIC需要較長的研發(fā)周期,一旦流片完成便不可進行更改,難以應(yīng)對復(fù)雜多變的算法結(jié)構(gòu),成本高、靈活性差。現(xiàn)場可編程門陣列(Field Programmable Gate Array,FPGA)是一種半定制、可重構(gòu)的專用集成電路,即彌補了ASIC靈活性差的不足又克服了GPU高功耗的缺點,使用FPGA作為卷積神經(jīng)網(wǎng)絡(luò)硬件加速平臺逐漸成為研究熱點[7]。
使用FPGA進行網(wǎng)絡(luò)相關(guān)模型的加速由來已久,早在1996年,Cloutier等[8]開始研究使用FPGA進行卷積神經(jīng)網(wǎng)絡(luò)的加速,其在FPGA上實現(xiàn)了手寫字母識別的相關(guān)設(shè)計,受制于當(dāng)時芯片的制造工藝,F(xiàn)PGA片上資源密度很低,其對卷積神經(jīng)網(wǎng)絡(luò)的并行性沒有充分展開設(shè)計。2015年,Zhang等[9]使用HLS的設(shè)計方法,針對CNN在FPGA上的部署,提出了基于Roofline的模型分析方法,通過對數(shù)據(jù)吞吐率以及系統(tǒng)存儲帶寬的量化分析,得到了模型部署的最小資源消耗與最佳性能方案,該方案消耗了較多的硬件資源,難以應(yīng)用在低成本的嵌入式場合。2016年,Qiu等[10]基于VGG網(wǎng)絡(luò),通過對卷積神經(jīng)網(wǎng)絡(luò)各層的計算資源消耗、內(nèi)存需求的分析,采用動態(tài)數(shù)據(jù)量化方法,實現(xiàn)了與浮點型數(shù)據(jù)十分接近的網(wǎng)絡(luò)分類精度。同年,Ghaffari等[11]提出一種通用卷積神經(jīng)網(wǎng)絡(luò)加速框架,該設(shè)計中對網(wǎng)絡(luò)中的每類網(wǎng)絡(luò)層設(shè)計專用的計算單元,并使用統(tǒng)一的邏輯控制單元進行調(diào)度,使用LeNet5對設(shè)計架構(gòu)進行測試。
并行化設(shè)計是卷積神經(jīng)網(wǎng)絡(luò)加速方法的核心方法之一,網(wǎng)絡(luò)并行化的設(shè)計主要是針對卷積層,通常根據(jù)卷積層的計算特征,使用循環(huán)分塊、循環(huán)展開等方法進行優(yōu)化。文獻[12]在特征圖的輸入與輸出層面進行并行化設(shè)計,以此提升卷積層的計算速度,然而并未充分利用卷積計算的內(nèi)在并行性。文獻[13]則提出了一種5層并行化結(jié)構(gòu),詳細分析了卷積神經(jīng)網(wǎng)絡(luò)的內(nèi)部并行性,設(shè)計了一種可配置的CNN并行計算單元,但并未給出硬件資源受限情況下的卷積復(fù)用設(shè)計。
基于以上分析,使用FPGA進行卷積神經(jīng)網(wǎng)絡(luò)硬件加速設(shè)計能夠在低功耗的同時滿足對高效性能與靈活性的要求,符合嵌入式應(yīng)用場景。本文使用設(shè)計一種卷積神經(jīng)網(wǎng)絡(luò)加速器,旨在為基于FPGA的卷積神經(jīng)網(wǎng)絡(luò)工程化實現(xiàn)提供一種設(shè)計方案,研究提出一種低功耗、可擴展、高性能的卷積神經(jīng)網(wǎng)絡(luò)并行化框架,從而實現(xiàn)面向嵌入式場景的卷積神經(jīng)網(wǎng)絡(luò)部署。
神經(jīng)網(wǎng)絡(luò)的基本組成單位是神經(jīng)元,研究人員通過對人腦結(jié)構(gòu)的模擬,對神經(jīng)元進行數(shù)學(xué)建模,構(gòu)成人工神經(jīng)網(wǎng)絡(luò)[14]。一個神經(jīng)元的組成結(jié)構(gòu)可用圖1表示。該神經(jīng)元接收上一級n個神經(jīng)元(x1,x2,...,xn)的輸出,并將其與對應(yīng)的權(quán)重w(w1,w2,...,wn)相乘,進而決定不同輸入信號的作用強度,通過求和單元將n個輸入信號與偏置b混合,最終通過一個激活函數(shù)f將該節(jié)點的運算結(jié)果輸出。
圖1 神經(jīng)元的組成結(jié)構(gòu)圖
則單個神經(jīng)元的計算可用式(1)表示:
偏置能夠使激活函數(shù)平移,進而增強網(wǎng)絡(luò)的魯棒性。激活函數(shù)的作用在于對神經(jīng)元的輸出進行非線性變換,使網(wǎng)絡(luò)模型具有良好的非線性模擬能力,并限定神經(jīng)元的輸出范圍,提高模型的表達能力。常見的激活函數(shù)有sigmoid、tanh以及relu等。
卷積層是卷積神經(jīng)網(wǎng)絡(luò)的主要組成部分,一個卷積層由多個特征面組成,每個特征面由多個神經(jīng)元組成,每個神經(jīng)元通過卷積核與上一層特征面的局部區(qū)域相連,卷積核是一個權(quán)值矩陣,卷積層通過卷積運算提取不同的特征。
如圖2所示,一個5×5的輸入特征圖與一個3×3的卷積核進行卷積計算,使用Xx,j表示輸入特征圖的第i行的第j個元素;使用wm,n表示卷積核第m行的第n個列權(quán)重,用wb示卷積核的偏置項;使用Yi,j表示輸出特征圖的第i行的第j個元素;用f(x)表示激活函數(shù)。則根據(jù)式(1)可得:
圖2 單輸入通道卷積計算示意圖
實際上卷積層通常是多輸入通道,圖3展示了多輸入通道卷積計算的過程,圖中M表示卷積核個數(shù),N表示輸入特征圖個數(shù),H和W分別表示特征圖尺寸,K表示卷積核尺寸。每組卷積核與對應(yīng)輸入通道的特征圖進行單通道的卷積計算,然后將各個通道的計算結(jié)果進行累加,再加上偏置wb就到了一個輸出特征圖上的結(jié)果輸出。
圖3 多輸入通道卷積計算示意圖
文獻[13]對卷積神經(jīng)網(wǎng)絡(luò)中的并行性做了詳細介紹,本文在此基礎(chǔ)上對并行性進行簡單分析。卷積神經(jīng)網(wǎng)絡(luò)的前向推理過程中具有不同維度的并行性,其中卷積的運算是網(wǎng)絡(luò)計算中的主要計算單元,因此對并行性的分析主要針對卷積計算單元。
1)卷積核間并行性
卷積核間并行是指每個卷積計算的卷積核是相互獨立的,所有的卷積核共享輸入特征圖,因此卷積核間的計算是不存在相互依賴的關(guān)系,我們可以通過圖4來描述這種卷積核間的并行性。
圖4 卷積核間并行性
可以發(fā)現(xiàn)M個卷積核的計算可以同時進行,彼此相互獨立,可以將此過程展開,使得M個卷積核同時進行計算,但要求系統(tǒng)加速器的設(shè)計有較高的數(shù)據(jù)吞吐量,對數(shù)據(jù)帶寬的要求極高。
2)特征圖間并行性
特征圖間的并行性是指對于N個輸入特征圖來說,每一組卷積核都有N卷積核與之對應(yīng)。當(dāng)進行卷積計算時,每個卷積核與對應(yīng)的輸入特征圖進行乘加計算。特征圖間并行性如圖5所示,實際計算時可將每個特征圖與對應(yīng)卷積核進行并行計算,然后將計算得到的結(jié)果相加即可得到輸出特征圖。
圖5 特征圖間并行性
特征圖間并行性對系統(tǒng)帶寬與吞吐率的要求相對較小,可通過一定的設(shè)計充分利用特征圖間的并行,但對于大多數(shù)的片上嵌入式系統(tǒng)來說,資源需求量還是稍高,實際使用時可以使用循環(huán)分塊等方法降低系統(tǒng)對帶寬的要求。
3)特征圖內(nèi)并行性
一個特征圖共享一個卷積核,因此可以將特征圖上的卷積滑窗同時進行運算。特征圖內(nèi)并行運算方式如圖6所示,在一個特征圖上的不同位置使用共享的卷積核進行并行運算,可減少循環(huán)的次數(shù)。
圖6 特征圖內(nèi)并行性
特征圖內(nèi)的并行性相對容易實現(xiàn),其對系統(tǒng)的帶寬與吞吐率要求不高,可以使用循環(huán)切片實現(xiàn)特征圖內(nèi)的并行性,但會消耗較多的片上存儲資源且數(shù)據(jù)復(fù)用度較低。
4)卷積核內(nèi)并行性
卷積核內(nèi)的并行性是整個卷積計算過程中最基本的計算單元。k*k的卷積核與特征圖上k*k的滑窗進行卷積計算,通常需要進行k*k次乘法運算與k*k-1次加法運算。以圖7中3*3的卷積核為例,整個計算過程需要進行9次乘法與8次加法運算,如果使用串行計算共需要循環(huán)9次,每一次循環(huán)需要進行一次乘法與加法運算;如果將卷積核與特征圖滑窗展開為圖7中的向量形式,可同時進行9次乘法運算,然后在進行1次加法運算即可完成整個計算,卷積核的并行性可通過循環(huán)展開的形式實現(xiàn)。
圖7 卷積核并行性
卷積層的計算占據(jù)整個網(wǎng)絡(luò)中的大量計算資源,因此對卷積層的加速能夠大幅提高網(wǎng)絡(luò)的前向推理時間。通過對卷積層并行性的分析可知,卷積層存在大量的并行性,針對標(biāo)準(zhǔn)卷積并行性的分析,我們提出一種標(biāo)準(zhǔn)卷積加速器設(shè)計思路,加速器的設(shè)計核心內(nèi)容是以減少數(shù)據(jù)的重復(fù)傳輸為目的,在此基礎(chǔ)上盡可能地將標(biāo)準(zhǔn)卷積計算的并行度與數(shù)據(jù)復(fù)用度最大化。
卷積計算中的并行性貫穿于整個卷積層的計算過程。通常情況下,由于硬件計算資源的限制,難以將計算過程中的所有循環(huán)都展開。因此,在實際設(shè)計過程中,采取循環(huán)分塊技術(shù)以降低加速器對硬件資源的消耗。所謂循環(huán)分塊技術(shù)是指對于一個較大的循環(huán)體可以將其拆分為幾個較小的循環(huán)體,以此實現(xiàn)對代碼的優(yōu)化,降低循環(huán)體對硬件資源的消耗。
如圖8所示,對于輸出通道來說,可將M個卷積核分割為M/p份,通過M/p次循環(huán)完成整個卷積核的并行計算,則此時卷積核的并行度為p,即一次進行p個卷積核的計算。同樣,如圖9所示,對于輸入通道來說,可以將N個輸入通道分為N/q份,通過N/q次循環(huán)完成整個輸出通道數(shù)據(jù)的遍歷,則此時特征圖間的并行性為q,即一次進行q個輸入特征圖的計算。每完成一次循環(huán),需要將本次循環(huán)的計算結(jié)果與之前所有的卷積計算結(jié)果相加,作為本次循環(huán)的最終輸出結(jié)果,當(dāng)進行最后一次循環(huán)時,將本次循環(huán)的最終計算結(jié)果與偏置相加,然后通過激活函數(shù)輸出,得到一個卷積核的最終輸出特征圖。
圖8 輸出通道遍歷循環(huán)分塊示意圖
圖9 輸入通道遍歷循環(huán)分塊示意圖
我們將輸出通道的p和輸入通道的q稱為循環(huán)分塊因子,可使用圖10中的代碼表示上述卷積計算過程。循環(huán)分塊因子的選擇對系統(tǒng)并行性的影響至關(guān)重要,如何確定循環(huán)分塊因子需要根據(jù)具體的網(wǎng)絡(luò)模型以及具體的硬件加速平臺,當(dāng)硬件加速平臺資源較多時,可以適當(dāng)?shù)脑龃笱h(huán)分塊因子,反之使用較小的循環(huán)分塊因子。此外,并不是分塊因子越大越好,當(dāng)系統(tǒng)的資源較為豐富時,循環(huán)分塊因子不再是限制系統(tǒng)性能的主要原因,此時系統(tǒng)的加速性能與系統(tǒng)數(shù)據(jù)傳輸帶寬有關(guān)。
圖10 輸入、輸出通道遍歷循環(huán)分塊代碼
循環(huán)展開是一種最直接的并行化加速方法,采用循環(huán)展開的方法能夠大幅地提高并行運算的速度,當(dāng)硬件加速平臺的資源充足時,可將計算過程沒有依賴關(guān)系的循環(huán)進行展開。對于整個卷積層的計算來說,僅對卷積計算過程中循環(huán)最內(nèi)層的計算單元進行展開難以達到理想的加速效果,因此需要根據(jù)實際的硬件資源對其他的循環(huán)進行展開。為了便于進行循環(huán)展開的設(shè)計,我們將卷積層計算的代碼調(diào)整為圖11中的形式。
圖11 改變循環(huán)次序的代碼
對調(diào)整后的代碼進行循環(huán)編號,從外層到內(nèi)層分別編號為1~8,此時循環(huán)1和循環(huán)2是對輸入、輸出通道的循環(huán)分塊,循環(huán)分塊的目的是為了減少加速器對硬件資源的要求,增大加速器的并行性,因此將循環(huán)分塊置于最外層。循環(huán)3和循環(huán)4是輸入對特征圖尺寸的遍歷,對于不同的卷積核其共用同一個輸入特征圖,因此對輸入特征圖的遍歷存在一定的數(shù)據(jù)復(fù)用度,可充分利用這一特點減少加速器對數(shù)據(jù)通信帶寬的要求,降低輸入數(shù)據(jù)的反復(fù)讀取。循環(huán)5和循環(huán)6是對輸入、輸出通道循環(huán)分塊因子的遍歷,為了能夠充分利用卷積計算的并行性,可在循環(huán)分塊因子的尺度進行循環(huán)展開設(shè)計,能夠大幅提高對硬件資源的利用率以及卷積層計算的速度,使用循環(huán)展開技術(shù)能夠有效地增加卷積運算的并行性,并行計算的大小由循環(huán)分塊因子決定。
片上存儲設(shè)計是卷積層加速器的核心設(shè)計內(nèi)容之一,加速器性能的好壞和片上存儲設(shè)計有直接聯(lián)系,F(xiàn)PGA的片上存儲資源十分有限,因此難以進行大規(guī)模的數(shù)據(jù)存儲。對于FPGA來說,塊隨機存取存儲器(Block Random Access Memory,BRAM)和觸發(fā)器(Flip Flop,FF)均可作為片上存儲器,通常使用FF構(gòu)成寄存器存儲需要進行反復(fù)讀取的數(shù)據(jù),F(xiàn)F的讀取速度大于BRAM,但能存儲的數(shù)據(jù)量遠小于BRAM。
卷積加速器片上存儲的設(shè)計主要包括權(quán)重偏置數(shù)據(jù)緩存、特征圖輸入緩存以及卷積計算結(jié)果輸出緩存三個層面,下面分別對其進行分析,并給出可行的設(shè)計方案。
1)權(quán)重偏置數(shù)據(jù)緩存
對于一個未進行剪枝、壓縮等優(yōu)化的j卷積神經(jīng)網(wǎng)絡(luò)模型來說,模型的參數(shù)量遠大于多數(shù)FPGA內(nèi)部的BRAM資源。因此,難以一次性將模型的全部參數(shù)部署到FPGA內(nèi)部,此時需要合理的設(shè)計片上存儲使加速器能夠具有較高的性能。對于一層卷積的計算,只需在卷積計算之前將本層的權(quán)重偏置數(shù)據(jù)傳輸?shù)紽PGA內(nèi)部的BRAM上,雖然會導(dǎo)致一定的數(shù)據(jù)傳輸與計算延時,但能夠大幅降低加速器對片上存儲資源的要求。
從循環(huán)展開的設(shè)計中可知,加速器一次計算需要完成p個卷積核對q個的輸入特征圖的遍歷。因此,對于片上存儲設(shè)計來說只需在卷積計算之前將p*q*k*k個權(quán)重參數(shù)傳輸?shù)紽PGA內(nèi)部的BRAM上即可,這樣能夠進一步降低對片上存儲資源的消耗,但會增加加速器的延時。
2)特征圖輸入緩存
卷積層的計算過程中通常難以將參與計算的輸入特征圖一次傳輸至加速器的片內(nèi)存儲。因此,需要設(shè)計輸入特征圖的緩存結(jié)構(gòu),使得加速器能夠滿足并行化計算。由卷積計算的原理可知,卷積的計算過程可描述為卷積核在特征圖上的滑動,不同的卷積核共享同一個輸入特征圖,可以將特征圖輸入緩存設(shè)計成行緩存的結(jié)構(gòu),需要緩存的行數(shù)與卷積核的尺寸k有關(guān)。
為了兼顧卷積計算的并行性、數(shù)據(jù)復(fù)用度以及FPGA的片上資源,采用圖12所示的行緩存結(jié)構(gòu),交替地將特征圖的數(shù)據(jù)傳輸至FPGA內(nèi)部。該緩存結(jié)構(gòu)可以實現(xiàn)特征圖間的并行性以及卷積核間的并行性。當(dāng)進行卷積計算時,q個不同的卷積核共享對應(yīng)的p個輸入特征圖行緩存,將p個輸入特征圖的卷積計算結(jié)果疊加即可得到一個卷積核的計算輸出。行緩存結(jié)構(gòu)相對復(fù)雜,但計算效率較高,能夠在有限的片上資源實現(xiàn)較大的并行性,此外引入多通道輸入特征圖的緩存能夠有效地降低臨時數(shù)據(jù)存儲。
圖12 特征圖行緩存結(jié)構(gòu)圖
當(dāng)進行卷積計算時,特征圖的數(shù)據(jù)通過AXI[15]總線串行的傳輸至FPGA內(nèi)部,如圖13所示。以4*4的輸入特征圖和3*3的卷積核為例進行行緩存內(nèi)部結(jié)構(gòu)的介紹(表示緩存器當(dāng)前位置),行緩存尺寸為3*4,一次緩存的最大尺寸為3行。
圖13 行緩存器內(nèi)部結(jié)構(gòu)圖
假設(shè)AXI總線每個時鐘周期傳輸一位輸入特征圖數(shù)據(jù),行緩存每個時鐘周期就能獲取一個數(shù)。每個時鐘周期下緩存器將當(dāng)前列的數(shù)據(jù)向上移動,然后將新的數(shù)據(jù)讀入緩存器的當(dāng)前位置。下一個時鐘周期到來時緩存器將當(dāng)前位置向右移動一個位置,然后將當(dāng)前列的數(shù)據(jù)向上移動,再將新的數(shù)據(jù)讀入緩存器的當(dāng)前位置,以此類推不斷重復(fù)這個過程,直到緩存器當(dāng)前位置移動到最后一列,在下個時鐘周期時再從第一列重復(fù)之前的過程。
3)特征圖輸出緩存
由卷積層的計算過程可知,一個完整的輸出特征圖與所有的輸入特征圖有關(guān)。因此,在引入循環(huán)分塊的加速器設(shè)計中,只有當(dāng)一組卷積核將所有的輸入通道遍歷完成后,才能得到對應(yīng)的輸出特征圖。無論是最終的輸出特征圖還是一組循環(huán)中的中間計算結(jié)果,都需要在完成q個卷積核對應(yīng)的p個輸入特征圖的卷積計算后,才將計算結(jié)果通過AXI總線傳輸至片外存儲。卷積層的計算中通常輸入特征圖的通道數(shù)小于輸出特征圖。因此,當(dāng)進行卷積計算時,AXI總線對輸入特征圖的數(shù)據(jù)讀取次數(shù)就小于對輸出特征圖的數(shù)據(jù)寫入次數(shù),這樣會造成讀取與寫入數(shù)據(jù)的不平衡,影響系統(tǒng)的數(shù)據(jù)吞吐率。為了提高加速器的整體數(shù)據(jù)吞吐量,我們在卷積的計算中引入FIFO的輸出緩存設(shè)計,通過FIFO緩存卷積計算結(jié)果。
假設(shè)卷積的計算有4個輸入通道和8個輸出通道,AXI總線一次能夠傳輸2個通道的數(shù)據(jù),因此對于輸入通道來說需要2個時鐘周期進行數(shù)據(jù)的讀取,對于輸出通道來說需要4個時鐘周期進行數(shù)據(jù)的輸出。
圖14是無FIFO的輸出緩存結(jié)構(gòu)圖,從圖中可知,由于沒有引入FIFO的結(jié)構(gòu),當(dāng)完成兩個輸入通道的數(shù)據(jù)讀取后,卷積開始產(chǎn)生計算結(jié)果的輸出,此時需要將部分計算結(jié)果傳輸至片外存儲。當(dāng)完成整個輸入通道的讀取后,卷積計算完成,而輸出通道的數(shù)據(jù)大于輸入通道,因此還需額外的時鐘周期將剩下的輸出通道數(shù)據(jù)傳輸至片外存儲,整個數(shù)據(jù)傳輸需要消耗5個時鐘周期。
圖14 無FIFO輸出緩存結(jié)構(gòu)圖
圖15是有FIFO的輸出緩存結(jié)構(gòu)圖,F(xiàn)IFO的深度為2,每進行一次輸入數(shù)據(jù)的讀取則進行兩次輸出數(shù)據(jù)的寫入,完成卷積計算時需要進行FIFO狀態(tài)的判斷,當(dāng)FIFO非滿狀態(tài)下進行FIFO的數(shù)據(jù)寫入,將當(dāng)前的計算結(jié)果緩存至FIFO中。同樣當(dāng)進行數(shù)據(jù)讀取時需要判斷FIFO是否為空,當(dāng)FIFO狀態(tài)非空時進行數(shù)據(jù)的讀取,將卷積計算結(jié)果輸出至片外存儲器。從圖中可知,由于引入FIFO的結(jié)構(gòu)設(shè)計,當(dāng)完成兩個輸入通道的數(shù)據(jù)讀取后,卷積開始產(chǎn)生計算結(jié)果的輸出,此時需要將本次的計算結(jié)果寫入到片內(nèi)的FIFO緩存中,在進行數(shù)據(jù)讀取的同時將上一次計算的結(jié)果從FIFO中讀取出來,通過AXI總線傳輸至片外存儲。
圖15 有FIFO輸出緩存結(jié)構(gòu)圖
兩種結(jié)構(gòu)對比可知,從單次計算的時鐘周期來說,沒有引入FIFO的結(jié)構(gòu)中完成一次完整的卷積計算所需要的時鐘周期是5,引入FIFO所需要的時鐘周期是4。從數(shù)據(jù)吞吐量來說,沒有引入FIFO的結(jié)構(gòu)中,12個時鐘周期內(nèi)完成了3次輸入數(shù)據(jù)的讀取與2次輸出數(shù)據(jù)的寫入,引入FIFO的設(shè)計中12個時鐘周期內(nèi)完成了4次輸入數(shù)據(jù)的讀取與2次輸出數(shù)據(jù)的寫入,一定程度上提高了數(shù)據(jù)的吞吐率。
為了保證卷積計算前后特征圖的尺寸不發(fā)生變化,通常在卷積計算時引入補“0”技術(shù)。此外,補“0”后的特征圖在進行卷積計算時,其邊緣的特征值也能多次參與卷積計算,從而達到減少特征圖邊緣信息丟失的作用。因此,補“0”對卷積計算十分重要。特征圖補“0”的方法有多種形式,本文僅以較為常用的邊緣均勻補“0”進行具體設(shè)計的介紹。
如圖16所示,輸入特征圖數(shù)據(jù)以數(shù)據(jù)流的形式傳輸至FPGA內(nèi)部,數(shù)據(jù)在進入FPGA的片上行緩存之前需要經(jīng)過片內(nèi)的Padding控制器,Padding控制器根據(jù)特征圖當(dāng)前傳輸?shù)臄?shù)據(jù)狀態(tài)決定是否進行補“0”。在進行特征圖數(shù)據(jù)傳輸之前,首先將特征圖原本的行數(shù)與列數(shù)傳輸至Padding控制器內(nèi)部,以此作為行、列控制器判斷補“0”個數(shù)與位置的依據(jù)。每次將AXI總線上的數(shù)據(jù)傳輸至行緩存內(nèi)部之前,Padding控制器中的行、列控制器會記錄當(dāng)前數(shù)據(jù)所處的位置,并根據(jù)當(dāng)前位置對行緩存數(shù)據(jù)流進行補“0”。具體的做法是:當(dāng)行控制器檢測到當(dāng)前行位于第一行或最后一行時,則在讀取特征圖數(shù)據(jù)之前將行緩存數(shù)據(jù)流中的所有列數(shù)據(jù)全部置為“0”。當(dāng)行控制器檢測到當(dāng)前行位于第一行與最后一行之間時,則在讀取特征圖數(shù)據(jù)之前將行緩存數(shù)據(jù)流中的第一列與最后一列數(shù)據(jù)全部置為“0”。當(dāng)列控制器檢測到當(dāng)前列為最后一列時則進行換行,以此對數(shù)據(jù)流中的數(shù)據(jù)進行分行處理。
圖16 Padding 控制器結(jié)構(gòu)圖
網(wǎng)絡(luò)中的卷積核通常有3*3與1*1兩種尺寸,為了降低硬件資源的消耗,提升資源利用率,我們設(shè)計了一種卷積復(fù)用的方法。如圖17,我們首先對1*1的卷積核進行擴充,使其轉(zhuǎn)換為3*3的卷積計算,然后將其送入3*3的卷積計算單元,即可完成卷積計算。擴充的方法是,將原始1*1卷積的權(quán)重放置3*3卷積核權(quán)重的第5位,3*3卷積核剩余8位權(quán)重均置0。根據(jù)圖17可知,擴充前后1*1卷積的計算結(jié)果相同,無需對3*3卷積計算單元做出更改,因此復(fù)用設(shè)計正確。卷積計算單元的復(fù)用沒有使用額外的硬件資源,極大地提高了硬件的利用率,但會造成1*1卷積計算效率的下降以及一定的無效數(shù)據(jù)傳輸,每傳輸一個權(quán)重需傳輸8個無效的數(shù)據(jù),此外還會增加一定的片外存儲空間用以存放擴充的“0”。總的來說,當(dāng)硬件資源較為緊張時,計算復(fù)用帶來的優(yōu)勢遠大于劣勢。
圖17 卷積復(fù)用轉(zhuǎn)換示意圖
設(shè)計優(yōu)化主要是使用高層次綜合(High-level Synthesis,HLS)[16]工具的Directive指令對卷積計算單元的延時進行優(yōu)化,優(yōu)化的目標(biāo)是以較小的資源消耗換取最大的計算效率,HLS工具會自動進行設(shè)計優(yōu)化,但需指定采用何種優(yōu)化方法 。我們的優(yōu)化對象主要有兩個:循環(huán)以及片上存儲結(jié)構(gòu)即數(shù)組。
1)循環(huán)優(yōu)化
卷積的計算中存在多層循環(huán),我們使用“PIPELINE”對循環(huán)進行優(yōu)化,多層循環(huán)嵌套的情況下,“PIPELINE”指令會對內(nèi)層循環(huán)進行展開,因此僅需在外層循環(huán)應(yīng)用“PIPLINE”即可。卷積計算單元一個時鐘周期能夠傳輸64位數(shù)據(jù)即4個輸入通道的數(shù)據(jù),則輸入通道最大循環(huán)次數(shù)為q/4,一次數(shù)據(jù)傳輸需完成p個卷積的計算。通常卷積層的最小輸入通道數(shù)為3,最大輸入通道數(shù)為可達1024,我們將卷積輸入通道的并行度設(shè)置為可變值,最大為q,并在此循環(huán)上使用“PIPLINE”進行優(yōu)化,由于循環(huán)次數(shù)q/4不固定,因此該循環(huán)并不被展開,該循環(huán)內(nèi)部即為卷積計算過程:行緩存、卷積滑窗、卷積計算、數(shù)據(jù)累加以及計算輸出,將該循環(huán)內(nèi)的循環(huán)均設(shè)為定值,則一次循環(huán)可完成p個輸出通道的計算,即輸出通道的并行度固定為p。
2)數(shù)組優(yōu)化
數(shù)組優(yōu)化的指令為“ARRAY_PARTITION”,通常是為了提升“PIPLINE”的性能。數(shù)組存儲在片上的BRAM中,BRAM的最大讀取端口數(shù)量為2,數(shù)據(jù)訪存速度較慢,為了提升吞吐量,通常將一個大的數(shù)組分割為幾個小的數(shù)組,這樣就能對數(shù)組進行并行訪存,提高數(shù)據(jù)吞吐量。HLS提供block、cyclic、complete三種數(shù)組分割方法,如圖18所示。對于block和cyclic指令,可使用factor指定將原始數(shù)組分割為多少個小數(shù)組,圖中factor等于2。對于complete指令,其直接對數(shù)組中的每個存儲單元進行完全分割,使其成為寄存器級接口,訪存速度最快。
圖18 數(shù)組分割示意圖
網(wǎng)絡(luò)模型中需要進行數(shù)組優(yōu)化的有權(quán)重、偏置、輸入行緩存、數(shù)據(jù)累加緩存以及輸出數(shù)據(jù)緩存,可分別使用Weight[p][q][k2]、Bias[p]、LineBuffer[q]、AccumulationBuffer[p]、OutputBuffer[p]表示。權(quán)重數(shù)組Weight[p][q][k2]是一個三維數(shù)組,通過以上分析可知對于權(quán)重數(shù)組的第一維參數(shù)p與第三維參數(shù)k2需使用complete對其進行優(yōu)化,而對于第二維參數(shù)q則將其分割為q/4個block。行緩存數(shù)組LineBuffer[q]一個時鐘周期只需進行4個輸入通道數(shù)據(jù)的寫入,因此將其拆分為4個block即可。對于Bias[p]、AccumulationBuffer[p]和Output-Buffer[p],由于輸出通道并行度p為固定值,因此需使用complete對其進行優(yōu)化。
我們以3*3的卷積計算為例,并其在外層加上一個不定循環(huán),使用“PIPLINE”與“ARRAY_PARTITION”對計算進行優(yōu)化。
優(yōu)化前后的資源消耗及計算延時如圖19所示。從圖中可以看出,使用“PIPLINE”與“ARRAY_PARTITION”能夠大幅提高計算單元的速度,但會消耗一定的硬件資源。
圖19 卷積運算優(yōu)化前后性能對比圖
實驗平臺使用Z-turn Board開發(fā)板,Z-turn Board是深圳市米爾科技有限公司推出的一款以Xilinx Zynq作為主處理器的嵌入式開發(fā)板,核心芯片為Zynq7020,板上配備兩片512MB的DDR3、一個16MB的SPI Flash、千兆以太網(wǎng)接口、USB接口等外部資源,這里我們不作出具體介紹。
我們使用Vivado軟件對卷積計算單元的IP進行綜合設(shè)計,生成比特流文件,然后在SDK環(huán)境下進行實驗測試。實驗平臺的資源配置如表1所示,實驗設(shè)計分為兩部分,首先是對不引入加速器僅使用Z-turn Board的PS端進行性能測試,然后是使用加速器的性能測試。測試所用的卷積層為YoloV3-tiny[17]網(wǎng)絡(luò)的第一層,輸入特征圖參數(shù)為416*416*3,輸出特征圖參數(shù)為416*416*16,使用16位定點數(shù)進行計算。我們將從資源消耗、計算延時、功耗、三個角度對實驗結(jié)果進行分析。
表1 實驗平臺資源配置表
實驗測試結(jié)果如表2所示。從表中可以看出,對于資源消耗,由于使用PS(ARM A9)端進行模型推理不涉及到PL(FPGA)端的資源消耗,因此資源消耗為0,使用FPGA進行計算加速,消耗量了一定的計算資源,其中主要消耗了大量的DSP48E與BRAM_18K。對于計算延時,使用并行加速的設(shè)計大幅提高了卷積的計算速度,相較于未并行化的方案加速比可達216.91,且功率僅增加0.569W。因此,本設(shè)計能夠在較小的資源消耗小取得較大的計算性能,能夠為面向嵌入式的卷積神經(jīng)網(wǎng)絡(luò)加速提供一定的設(shè)計參考。
表2 加速前后資源消耗對比
近些年來,人工智能技術(shù)快速發(fā)展,模型所需的算力不斷攀升。盡管服務(wù)器級CPU或GPU能夠提供強大的計算力,但其單位算力下的功耗,使其難以應(yīng)用在功耗敏感的嵌入式領(lǐng)域。FPGA能夠在保持低功耗的同時,提供強大的并行計算能力。本文通過對卷積神經(jīng)網(wǎng)絡(luò)計算特性的分析,使用循環(huán)分塊、循環(huán)展開等技術(shù),完成了一種具有通用性能的卷積神經(jīng)網(wǎng)絡(luò)加速器架構(gòu)設(shè)計。引入了輸入、輸出通道兩個維度的并行化因子,分別設(shè)計了可擴展的卷積硬件計算單元以及資源受限情況下的卷積復(fù)用結(jié)構(gòu)。此外,針對片上硬件結(jié)構(gòu),分別設(shè)計了權(quán)重偏置存儲結(jié)構(gòu)、特征圖行緩存結(jié)構(gòu)、多級輸出緩存結(jié)構(gòu),并使用數(shù)組分割進行設(shè)計優(yōu)化。