苗瑞霞,張雪蘭,譚星浩,方華啟
(1.西安郵電大學(xué) 電子工程學(xué)院,陜西 西安 710121;2.芯來智融科技有限公司,湖北 武漢 430074)
由于不斷提高的嵌入式設(shè)備性能的需求和ARM指令集不能向后兼容的特性導(dǎo)致了在ARM平臺(tái)上的人工智能算法不能很好地移植和維護(hù)。文獻(xiàn)[1]和文獻(xiàn)[2]分別闡述了從數(shù)據(jù)量化的方式和進(jìn)行數(shù)據(jù)量化時(shí),采用非線性量化的方式來分析此方法對(duì)嵌入式神經(jīng)網(wǎng)絡(luò)加速的可執(zhí)行性。此結(jié)論為文章中提出采用8位定點(diǎn)數(shù)卷積模型來代替ARM CMSIS-NN模型中提出的16位定點(diǎn)數(shù)卷積模型這一操作奠定了理論基礎(chǔ)。同時(shí),從現(xiàn)有的神經(jīng)網(wǎng)絡(luò)加速優(yōu)化的方向來看,本文主要采用了模型參數(shù)低精度量化的思想[5-8]進(jìn)行設(shè)計(jì),完善了當(dāng)前ARM中不支持8位數(shù)據(jù)處理的神經(jīng)網(wǎng)絡(luò)平臺(tái)的短板。并為RISC-V平臺(tái)的神經(jīng)網(wǎng)絡(luò)模型發(fā)展做出補(bǔ)充。
嵌入式設(shè)備的芯片處理能力和內(nèi)存資源都是有限且珍貴的,這一限制使得卷積這一復(fù)雜且運(yùn)算量巨大的算法在嵌入式平臺(tái)的部署成為難點(diǎn)。并且在嵌入式平臺(tái)部署神經(jīng)網(wǎng)絡(luò)的情景時(shí),需要解決性能和內(nèi)存資源緊缺的問題[9-11]。同時(shí),由于目前RISC-V沒有自身專用的神經(jīng)網(wǎng)絡(luò)函數(shù)處理庫(kù)和專用的嵌入式設(shè)備。針對(duì)以上闡述問題,本文主要采用了從軟硬件協(xié)同的角度,提出了一種面向RISC-V處理器的卷積神經(jīng)網(wǎng)絡(luò)系統(tǒng)的實(shí)現(xiàn)方法,將模型參數(shù)量化與RISC-V硬件平臺(tái)結(jié)合的方式來更大程度上優(yōu)化神經(jīng)網(wǎng)絡(luò)在嵌入式平臺(tái)上的部署。首先提出采用針對(duì)嵌入式平臺(tái)的低精度定點(diǎn)量化的方法,在保持精度的同時(shí)減小了數(shù)據(jù)位寬,進(jìn)而減小了神經(jīng)網(wǎng)絡(luò)模型在嵌入式設(shè)備上部署的內(nèi)存限制,采用RISC-V指令架構(gòu)[12-14]來完成卷積神經(jīng)網(wǎng)絡(luò)模型的底層實(shí)現(xiàn)以縮短運(yùn)算的執(zhí)行時(shí)間,提升整體的性能。本設(shè)計(jì)完善了神經(jīng)網(wǎng)絡(luò)中數(shù)據(jù)低精度的處理,減輕了內(nèi)存資源對(duì)神經(jīng)網(wǎng)絡(luò)在嵌入式設(shè)備上部署的限制,同時(shí)又將神經(jīng)網(wǎng)絡(luò)和RISC-V相結(jié)合,不必承受遭受困擾ARM許久的兼容性問題的干擾,可以用在更廣泛的高性能嵌入式設(shè)備中。
(1)寄存器操作的R類型指令
(2)用于短立即數(shù)和訪存load操作的I型指令
(3)用于訪存store操作的S型指令
(4)用于條件跳轉(zhuǎn)操作的B類型指令
(5)用于長(zhǎng)立即數(shù)的U型指令和用于無條件跳轉(zhuǎn)的J型
(1)指令只有6種格式,所有指令都是32位位寬,b便于指令解碼。例如ARM-32、x86-32中包含許多不同格式的指令,增加解碼的成本。
(2)RISC-V指令架構(gòu)含有3個(gè)寄存器操作數(shù),與x86-32不同的是,后者讓源操作數(shù)和目的操作數(shù)共享一個(gè)字段。這就需要多使用一條move(搬運(yùn))指令,來保存目的寄存器的值,增加了代碼量。
(3)所有指令,總是在同一位置的讀寫寄存器的標(biāo)識(shí)符可以大大簡(jiǎn)化解碼操作,增加了指令的執(zhí)行效率。
(4)這些格式的立即數(shù)字段總是符號(hào)擴(kuò)展,符號(hào)位總是在指令中最高位。這一特征表明可能成為關(guān)鍵路徑的立即數(shù)符號(hào)擴(kuò)展,可以在指令解碼之前進(jìn)行,對(duì)于RISC-V的模塊化指令特點(diǎn)具體見表1。
CMSIS-NN其實(shí)是作為基于ARM的Cortex處理器微控制器的硬件抽象層,其本質(zhì)是一個(gè)擁有眾多神經(jīng)網(wǎng)絡(luò)功能函數(shù)接口的模型庫(kù)。該庫(kù)是高效神經(jīng)網(wǎng)絡(luò)的內(nèi)核集合。使用者可以通過各種易于使用的標(biāo)準(zhǔn)化軟件界面更快地編寫軟件而不用去了解這些功能函數(shù)的實(shí)現(xiàn)方法以及實(shí)現(xiàn)流程,只需要按照需求去調(diào)用相應(yīng)的功能函數(shù)即可。
表1 RISC-V的模塊化指令集
同時(shí)其一致的API(應(yīng)用程序編程接口)提高了軟件的可移植性和可重用性。通用軟件庫(kù)和接口提供一致的軟件框架。同時(shí),作為獨(dú)立于編譯器的一層,它允許使用者選擇大部分主流的編譯器。
內(nèi)核代碼主要由兩部分組成:NN-Functions和NN-Support[15,16]函數(shù),應(yīng)用程序代碼可以使用這些函數(shù)來實(shí)現(xiàn)機(jī)器學(xué)習(xí)的功能。NNSuppor庫(kù)包括實(shí)用功能,如數(shù)據(jù)轉(zhuǎn)換和激活函數(shù)表,服務(wù)于NN庫(kù)的函數(shù)。應(yīng)用程序代碼也可以使用這些實(shí)用功能來構(gòu)造更復(fù)雜的NN模塊。ARM CMSIS-NN神經(jīng)網(wǎng)絡(luò)內(nèi)核架構(gòu)如圖1所示。
圖1 ARM CMSIS-NN神經(jīng)網(wǎng)絡(luò)內(nèi)核架構(gòu)
該卷積神經(jīng)網(wǎng)絡(luò)利用了輸入由圖像組成的方式約束了體系結(jié)構(gòu)。與常規(guī)神經(jīng)網(wǎng)絡(luò)不同的是,ARM CMSIS-NN的圖層具有3個(gè)維度排列的神經(jīng)元:寬度、高度、深度。例如CIFAR-10[17,18]中的輸入圖像是經(jīng)過激活的輸入量,并且大小為32*32*3(寬度、高度、深度)的尺寸。一個(gè)層中的神經(jīng)元將只連接到它之前的一個(gè)小區(qū)域,而不是以完全連接的方式連接所有神經(jīng)元。此外,CIFAR-10的最終輸出層具有尺寸1×1×10,因?yàn)榈紺onvNet體系結(jié)構(gòu)結(jié)束時(shí),我們將整個(gè)圖像縮減為類分?jǐn)?shù)的單個(gè)矢量,并沿深度維度排列,如圖2所示。
在CIFAR-10輸入圖像的大小僅為32*32*3(32寬、32高、3色通道),因此常規(guī)神經(jīng)網(wǎng)絡(luò)第一個(gè)隱藏層中的單個(gè)完全連接神經(jīng)元將具有32*32*3=3072權(quán)重。此時(shí)權(quán)重?cái)?shù)量還在可管理范圍內(nèi),但很明顯,此完全連接的結(jié)構(gòu)不會(huì)擴(kuò)展到更大的圖像。例如輸入更大的圖像200*200*3將導(dǎo)致具有200*200*3=120 000個(gè)權(quán)重的神經(jīng)元。顯然,這樣會(huì)造成浪費(fèi)和大量的參數(shù)將迅速過度擬合,而這樣的輸入僅僅是一張尺寸較大圖片的輸入帶來影響。如Alexnet[19]神經(jīng)網(wǎng)絡(luò)中的計(jì)算量達(dá)到上億級(jí),但是乘法運(yùn)算就至少需要7億次以上。卷積層的計(jì)算公式如式(1)
(1)
式中:w是權(quán)重矩陣,b為偏置,f是激活函數(shù),x是每一層的輸入,Y是每一層的輸出。從公式可以看出輸入與權(quán)重的乘積隨著卷積層數(shù)的增加都是呈指數(shù)型增長(zhǎng)的,數(shù)據(jù)量的增大對(duì)嵌入式設(shè)備的綜合要求就越高,由此可見嵌入式神經(jīng)網(wǎng)絡(luò)平臺(tái)受到自身資源因素限制。其最常見的3層神經(jīng)網(wǎng)絡(luò)如圖2所示。
P標(biāo)準(zhǔn)擴(kuò)展:封裝的單指令多數(shù)據(jù)(Packed-SIMD)指令。P擴(kuò)展細(xì)分了現(xiàn)有的寄存器架構(gòu),提供更小數(shù)據(jù)類型上的并行計(jì)算。P指令集擴(kuò)展增加了RISC-V CPU IP產(chǎn)品的DSP算法處理能力,其支持8、16、32位數(shù)據(jù)操作。通過添加RISC-V P指令集擴(kuò)展,RISC-V CPU現(xiàn)在可以以更低的功耗和更高的性能運(yùn)行這些各種DSP應(yīng)用程序。同時(shí),P指令集封裝的SIMD指令(單指令多數(shù)據(jù)指令)代表了一種合理復(fù)用現(xiàn)有寬數(shù)據(jù)通路的設(shè)計(jì),這樣更加有利于組合指令完成復(fù)雜的運(yùn)算,有了更多實(shí)現(xiàn)方式,以便于移植和維護(hù)。
SIMD,即Single Instruction, Multiple Data,一條指令操作多個(gè)數(shù)據(jù)。是CPU基本指令集的擴(kuò)展。主要用于提供fine grain parallelism,即瑣碎數(shù)據(jù)的并行操作,同時(shí)更多用于圖像處理,圖像的數(shù)據(jù)常用的數(shù)據(jù)類型是RGB565、RGBA8888、YUV422等格式,這些格式的數(shù)據(jù)特點(diǎn)是一個(gè)像素點(diǎn)的一個(gè)分量總是用小于等于8 bit的數(shù)據(jù)表示。如果使用傳統(tǒng)的處理器做計(jì)算,雖然處理器的寄存器是32位或是64位的,處理這些數(shù)據(jù)卻只能用于它們的低8位,這樣對(duì)于內(nèi)存的使用效率略低。如果把64位寄存器拆成8個(gè)8位寄存器就能同時(shí)完成8個(gè)操作,計(jì)算效率提升了8倍。
首先是協(xié)處理器的接口,課題中使用的蜂鳥E200處理器核的接口是借鑒的Rocket Core的協(xié)處理器接口,為了和其區(qū)分開來,名為EAI(extension accelerator interface)。其32位的EAI指令格式如圖3所示。
圖3 EAI 指令編碼格式
課題采用支持協(xié)處理器訪問存儲(chǔ)器資源的RISC-V處理器核是因?yàn)槠淇梢詳U(kuò)大處理器處理的指令范圍。在LSU(load store unit)中有特定的協(xié)處理器接口資源,這就使得基于EAI接口的協(xié)處理器可以訪問主處理器能訪問的存儲(chǔ)資源。
其實(shí)現(xiàn)的原理是在LUS中有預(yù)留的接口資源。另外在主處理器中有控制信號(hào),即為了防止主處理器中的存儲(chǔ)訪問指令和協(xié)處理器中存儲(chǔ)訪問指令造成競(jìng)爭(zhēng),主處理器有專用的控制信號(hào)阻止后續(xù)的指令繼續(xù)訪問存取器,以此來規(guī)避競(jìng)爭(zhēng)。另外協(xié)處理采用的是基于ICB總線的Valid和Ready握手機(jī)制。所以,只要初期的LSU單元能夠接受多個(gè)存取器訪問指令,那么協(xié)處理就可以發(fā)送多個(gè)存儲(chǔ)器訪問指令。這樣也可以加快在數(shù)據(jù)處理中執(zhí)行效率。同時(shí),主處理器也能在協(xié)處理器沒有訪問操作的時(shí)候拉低其獨(dú)占信號(hào),使得主處理器中的后續(xù)指令得以執(zhí)行,協(xié)處理器控制模塊控制框架如圖4所示。
圖4 示例協(xié)處理器控制模塊框架
能效分析如下:以3*3的平面卷積來看,啟動(dòng)指令需要一個(gè)周期,協(xié)處理器從數(shù)據(jù)緩存中讀取到一個(gè)矩陣元素,那么采用流水線的方式去連續(xù)讀取,第一行的所有矩陣元素相加之和就需要4個(gè)周期,從第二行開始后,在本行的基礎(chǔ)之上,還要增加上一行的部分累加和,所以需要7個(gè)周期,每一個(gè)列累加直接從緩存中拿出計(jì)算結(jié)果即可在一個(gè)周期內(nèi)計(jì)算完成,那么完成一個(gè)3*3的矩陣運(yùn)算就需要22個(gè)時(shí)鐘周期,這是純C++實(shí)現(xiàn)的矩陣乘加性能的3~5倍。
在嵌入式平臺(tái)方面,有限的計(jì)算和內(nèi)存能力使得在它們上部署NN推理模型必須進(jìn)行軟件算法優(yōu)化,如圖5所示,本文采用純軟件模擬和協(xié)處理器輔助實(shí)現(xiàn)采用8位定點(diǎn)量化網(wǎng)絡(luò)模型。為了保證對(duì)比實(shí)驗(yàn)結(jié)果的準(zhǔn)確性,采用Convolve->Relu->MaxPool->Convolve->Relu->MaxPool->Relu->MaxPool->FullConnected->Softmax的流程,其中分開了卷積部分以區(qū)分優(yōu)化前后的卷積。
圖5 實(shí)現(xiàn)流程
在軟件層次,對(duì)ARM CMSIS-NN算法模型中替換了RISC-V的P標(biāo)準(zhǔn)拓展指令,具有單指令多數(shù)據(jù)的特性的DSP專用指令集,在SIMD(單指令多數(shù)據(jù))指令中可以最多同時(shí)處理8個(gè)8位的數(shù)據(jù),并且不需在ARM的模型中將8位數(shù)據(jù)符號(hào)拓展成16位,經(jīng)對(duì)比,在內(nèi)存的使用效率上和數(shù)據(jù)的處理效率上分別提高了2倍和8倍,同時(shí)DSP不僅支持浮點(diǎn)也支持定點(diǎn)數(shù)據(jù)運(yùn)算,所以為了保證數(shù)據(jù)的正確性,還在軟件層次增加了飽和計(jì)算、舍入和移位的功能函數(shù)。
協(xié)處理器層次,因?yàn)樵赑標(biāo)準(zhǔn)的拓展DSP指令的大量使用下,會(huì)需要更多的乘加寄存器,并且為了保證定點(diǎn)計(jì)算的數(shù)據(jù)正確性,也增加了硬件方面的定點(diǎn)飽和,舍入和移位的實(shí)現(xiàn)和更多寄存器的實(shí)現(xiàn),最后為P標(biāo)準(zhǔn)的DSP指令做了適配和兼容,以及后期的簡(jiǎn)易驗(yàn)證是否能夠正確執(zhí)行。
CMSIS-NN庫(kù)函數(shù)大多數(shù)使用16位MAC(乘加)指令,文中采用8位數(shù)據(jù)類型指令操作來實(shí)現(xiàn)16位數(shù)據(jù)類型指令的算法模型。CMSIS提供了相應(yīng)函數(shù)arm_q7_to_q15()執(zhí)行數(shù)據(jù)轉(zhuǎn)換。數(shù)據(jù)轉(zhuǎn)換分為兩個(gè)步驟:第一步將8位數(shù)據(jù)符號(hào)擴(kuò)展到16位,它使用符號(hào)擴(kuò)展指令(__SXTB16)進(jìn)行數(shù)據(jù)轉(zhuǎn)換;第二步重新排列數(shù)據(jù),使輸出遵循與輸入相同的順序,如圖6所示。
圖6 CMSIS-NN中q7_t轉(zhuǎn)換至q15_t
在對(duì)數(shù)據(jù)進(jìn)行優(yōu)化之前采用的是16位數(shù)據(jù)運(yùn)算,關(guān)鍵代碼如下所示:
while (blkCnt > 0u)
in = arm_nn_read_q7x4_ia(&pIn);
in1 = __SXTB16(__ROR(in, 8));
in2 = __SXTB16(in);
#ifndef ARM_MATH_BIG_ENDIAN
out2 = __PKHTB(in1, in2, 16);
out1 = __PKHBT(in2, in1, 16);
#else
out1 = __PKHTB(in1, in2, 16);
out2 = __PKHBT(in2, in1, 16);
#endif
write_q15x2_ia(&pDst, out1);
write_q15x2_ia(&pDst, out2);
blkCnt- -;
上述代碼中,首先是循環(huán)展開處理的第一部分。每次計(jì)算4個(gè)輸出,旋轉(zhuǎn)8位數(shù)據(jù)并將兩個(gè)q7_t值符號(hào)擴(kuò)展到q15_t值,再將剩余的兩個(gè)q7_t值符號(hào)擴(kuò)展到q15_t值。在獲得拓展成16位數(shù)據(jù)之后再通過__PKHTB和__PKHBT指令將in1參數(shù)的位低16位與in2參數(shù)的高16位左移16之后的結(jié)果組合在一起成一個(gè)32位操作數(shù)。以此來實(shí)現(xiàn)在一個(gè)操作數(shù)中具有2個(gè)真實(shí)有效的由8位拓展而來的16位數(shù)據(jù),之后在使用相應(yīng)16位的mul指令進(jìn)行運(yùn)算。設(shè)計(jì)中的優(yōu)化省略了數(shù)據(jù)拓展這一操作。關(guān)鍵代碼如下所示:
while (blkCnt > 0u) {
in = read_q7x4_ia((q7_t **)&pIn);
write_q7x4_ia(&pDst, in);
blkCnt- -;
}
優(yōu)化后的卷積數(shù)據(jù)處理過程是直接將8位輸入分開讀取至8位位寬的內(nèi)存指針中,在取出相應(yīng)的存儲(chǔ)單元地址寫入數(shù)據(jù)即可。省略數(shù)據(jù)拓展操作后即不需要__PKHTB()和__SXTB16()指令操作,提升了存儲(chǔ)單位的使用效率且提高了單位時(shí)間內(nèi)的數(shù)據(jù)操作數(shù)量,降低了運(yùn)算時(shí)間。
卷積的矩陣乘法優(yōu)化,優(yōu)化前矩陣乘法函數(shù)關(guān)鍵代碼:
While (colCnt)
q31_t inA11, inA12, inA21, inA22;
q31_t inB1 = arm_nn_read_q15x2_ia (& pB);
q31_t inB2 = arm_nn_read_q15x2_ia (& pB2);
pA = read_and_pad (pA, &inA11, &inA12);
pA2 = read_and_pad (pA2, & inA21, & inA22);
sum = __SMLAD (inA11, inB1, sum);
sum2 = __SMLAD (inA11, inB2, sum2);
sum3 = __SMLAD (inA21, inB1, sum3);
sum4 = __SMLAD (inA21, inB2, sum4);
inB1 = arm_nn_read_q15x2_ia (& pB);
inB2 = arm_nn_read_q15x2_ia (& pB2);
sum = __SMLAD (inA12, inB1, sum);
sum2 = __SMLAD (inA12, inB2, sum2);
sum3 = __SMLAD (inA22, inB1, sum3);
sum4 = __SMLAD (inA22, inB2, sum4);
可以看出在arm-cmsis中對(duì)于矩陣的運(yùn)算每次都是需要先將存儲(chǔ)中的數(shù)據(jù)地址通過指針傳遞給運(yùn)算指令,然后重復(fù)上面圖6的步驟,對(duì)低精度的數(shù)據(jù)進(jìn)行零拓展,然后在進(jìn)行數(shù)據(jù)重新排序,對(duì)于處理器來講這樣的操作就會(huì)每次都造成額外的存儲(chǔ)訪問,在大量數(shù)據(jù)的存儲(chǔ)訪問操作環(huán)境中,這對(duì)卷積運(yùn)算的處理效率有著很大的影響,甚至對(duì)于處理器的冒險(xiǎn)協(xié)調(diào)模塊是個(gè)極大的挑戰(zhàn)。因此為了解決以上潛在問題,以及加速在卷積模塊中對(duì)于卷積運(yùn)算所需要的數(shù)據(jù)處理,化簡(jiǎn)后關(guān)鍵代碼如下所示,矩陣乘法核如圖7所示:
while (colCnt){
q31_t inB1 = *__SIMD32 (pB)++;
q31_t inB2 = *__SIMD32 (pB2)++;
q31_t inA1 = *__SIMD32 (pA)++;
q31_t inA2 = *__SIMD32 (pA2)++;
sum = __SMAQA (inA1, inB1, sum);
sum2 = __SMAQA (inA1, inB2, sum2);
sum3 = __SMAQA (inA2, inB1, sum3);
sum4 = __SMAQA (inA2, inB2, sum4);
colCnt- -;}
圖7 q7_t操作數(shù)輸出2×2矩陣乘法核
從上述代碼中可以看出,相較于之前的操作我們簡(jiǎn)化了處理操作,通過將低精度的8 bit數(shù)據(jù)的地址直接通過指針的形式傳遞給RISCV-P拓展的SIMD運(yùn)算指令,然后進(jìn)行乘加運(yùn)算。將其和圖6所示的計(jì)算過程相比,顯而易見的是單位操作數(shù)據(jù)量翻了一倍,同時(shí)節(jié)省了大量的存儲(chǔ)訪問指令,減輕了對(duì)片上存儲(chǔ)的壓力,降低了運(yùn)算的復(fù)雜度,同時(shí)增加了算法的效率并增加了計(jì)算的吞吐量。圖7用圖形化的方式對(duì)矩陣乘法內(nèi)核內(nèi)循環(huán)的執(zhí)行進(jìn)行展示,在填充計(jì)算兩個(gè)空間相鄰輸出像素所需的兩個(gè)im2col緩沖區(qū)后,矩陣乘法內(nèi)循環(huán)如圖7所示。在循環(huán)的每一次迭代中,從兩個(gè)im2col[20]緩沖器中的每一個(gè)(圖中的指針pBuffer1和pBuffer2)和從兩個(gè)權(quán)重庫(kù)(指針pWeight1和pWeight2)加載到寄存器中,所需的負(fù)載操作總數(shù)為4個(gè)。這樣,就有足夠的元素來在4個(gè)不同的累加器上設(shè)置4個(gè)_SMAQA指令操作數(shù)。因此,在矩陣乘法內(nèi)核內(nèi)循環(huán)的一次運(yùn)行中,我們可以計(jì)算4個(gè)__SMAQA指令,它們對(duì)應(yīng)于8位的MAC操作,而代價(jià)是4個(gè)負(fù)載指令,極大簡(jiǎn)化了矩陣乘法函數(shù)。
同時(shí),為了最大程度上的優(yōu)化卷積運(yùn)算因大量的數(shù)據(jù)而對(duì)存儲(chǔ)造成的壓力,課題中實(shí)現(xiàn)了im2col模塊,事實(shí)上,在卷積層中是通過計(jì)算濾波器權(quán)重與輸入要素圖中的一個(gè)小的接受區(qū)域之間的點(diǎn)積來提取新的特征圖。但是基于CPU實(shí)現(xiàn)的卷積分解為輸入重新排序和擴(kuò)展(即im2col,圖像轉(zhuǎn)列)和矩陣乘法運(yùn)算。im2col其實(shí)是將類似圖像的輸入轉(zhuǎn)換為代表每個(gè)卷積過濾器所需數(shù)據(jù)的列。但是要實(shí)現(xiàn)im2col的最大困難之一是內(nèi)存占用量的增加,這就與意圖減少內(nèi)存占用的初心違背,因?yàn)檩斎雸D像在im2col輸出矩陣中部分?jǐn)?shù)據(jù)是重復(fù)的。為了緩解內(nèi)存占用問題,并且保留im2col的性能優(yōu)勢(shì),為卷積實(shí)現(xiàn)了部分im2col內(nèi)核。內(nèi)核只會(huì)擴(kuò)展有限數(shù)量的列,對(duì)于點(diǎn)積后矩陣的數(shù)據(jù)加以特征值的提取,因此足以獲取矩陣乘法內(nèi)核,最大程度地減低內(nèi)存占用,以及獲取輸入圖像的完整特征值。在此基礎(chǔ)上最大提升了存儲(chǔ)訪問的性能,同時(shí)保持了內(nèi)存的最小開銷。im2col過程如圖8所示。
圖8 3×3內(nèi)核的2D圖像上的im2col示例
另外發(fā)現(xiàn)隨著輸入的圖像格式的變化,對(duì)于卷積運(yùn)算的效率也是有一定的影響。當(dāng)輸入的數(shù)據(jù)批量是1,那么im2col其實(shí)就是平面卷積,在神經(jīng)網(wǎng)絡(luò)中最常見的數(shù)據(jù)輸入格式有兩種,Channel-Width-Height(CHW),即首先是通道。Height-Width Channel(HWC),即最后一個(gè)通道。因此,在蜂鳥E200開發(fā)板上分別執(zhí)行了HWC和CHW格式的數(shù)據(jù)來比較兩者im2col執(zhí)行時(shí)間,結(jié)果顯示HWC格式具有更好的im2col性能。因此在后面的性能測(cè)試中,采用的也是基于HWC格式的數(shù)據(jù)輸入例如圖9所示的數(shù)據(jù)布局實(shí)驗(yàn)結(jié)果。
圖9 CHW和HWC數(shù)據(jù)布局的實(shí)驗(yàn)結(jié)果
SPIKE,RISC-V ISA模擬器,內(nèi)部實(shí)現(xiàn)了多個(gè)RISC-V harts的功能模型。為了便于對(duì)項(xiàng)目維護(hù)并且進(jìn)行后續(xù)的版本控制以及查看API何時(shí)擴(kuò)展或呈現(xiàn)不兼容,SPIKE遵守版本控制方案,當(dāng)進(jìn)行向后不兼容的API更改時(shí),將主要版本號(hào)遞增;添加新API時(shí),次要版本號(hào)遞增;當(dāng)以向后兼容的方式修復(fù)Bug時(shí),修補(bǔ)程序版本號(hào)將遞增。同時(shí)SPIKE的主要公共API是RISC-VISA。目前C++與SPIKE內(nèi)部接口的一個(gè)接口不被視為公共API,并且將在不增加主要版本號(hào)的情況下對(duì)此接口進(jìn)行向后不兼容的更改。
本設(shè)計(jì)中所采用的開源ARM CMSIS-NN模型,使用軟件語(yǔ)言C++將模塊功能以代碼來實(shí)現(xiàn)。功能仿真測(cè)試通過開源的RISC-V拓展指令集自測(cè)試用例,測(cè)試處理器是否符合指令集架構(gòu)的功能級(jí)仿真器SPIKE。該測(cè)試程序是由RISC-V架構(gòu)開發(fā)者為了檢測(cè)處理器是否符合指令集架構(gòu)中的定義而編寫的測(cè)試程序,但是由于本設(shè)計(jì)中對(duì)硬件方面的優(yōu)化做出的改動(dòng)為使用了RISC-V架構(gòu)協(xié)處理器,并且自行設(shè)計(jì)拓展了RISC-V的DSP專用指令。原生SPIKE仿真器不支持DSP的拓展指令,因此在做仿真測(cè)試前需要在SPIKE功能仿真器上適配DSP功能。
為了量化卷積運(yùn)算協(xié)處理器的加速效果,在此對(duì)軟件實(shí)現(xiàn)的卷積運(yùn)算和協(xié)處理器提供一定量相同的隨機(jī)輸入數(shù)據(jù),并且在SPIKE的仿真器上模擬設(shè)置和在蜂鳥E203 FPGA開發(fā)板上相同的16 MHZ的運(yùn)行頻率來保證相同的輸入環(huán)境和相同的運(yùn)行頻率,然后對(duì)比兩者分別所需要的時(shí)間。
實(shí)驗(yàn)選取一個(gè)卷積神經(jīng)網(wǎng)絡(luò)(CNN)示例的演示,卷積、ReLU激活、池化和完全連接的功能。實(shí)驗(yàn)中使用的CNN基于BVLC Caffe的CIFAR-10示例。神經(jīng)網(wǎng)絡(luò)由3個(gè)卷積層組成,散布有ReLU激活層和最大池化層,最后是一個(gè)完全連接地層。網(wǎng)絡(luò)的輸入是32×32像素的顏色圖片,將被分為10個(gè)輸出類別之一。設(shè)置32.3 KB的存儲(chǔ)權(quán)重,以及40 KB的激活權(quán)重,同時(shí)在實(shí)驗(yàn)開始前需要調(diào)試好軟件環(huán)境。
實(shí)驗(yàn)準(zhǔn)備需要安裝工具Ubuntu Linux 18.04 LTS,以及使用sudo apt-get install make zip命令解壓縮python2.7 pythonpip,還有相應(yīng)環(huán)境設(shè)置,如設(shè)置項(xiàng)目路徑等。同時(shí)還需要使用兩條硬件線將GPIO與BTN連接,硬件連線如圖10所示。
圖10 硬件連線
實(shí)驗(yàn)測(cè)試參數(shù)設(shè)定結(jié)果見表2。
表2 卷積網(wǎng)絡(luò)輸入各參量
實(shí)驗(yàn)條件控制:輸入數(shù)據(jù)為隨機(jī),并且對(duì)比確認(rèn)純軟件實(shí)現(xiàn)算法和協(xié)處理器實(shí)現(xiàn)算法的輸入相同,輸出結(jié)果對(duì)比結(jié)果完全相同,在此實(shí)驗(yàn)環(huán)境下得出的兩種前景下的消耗時(shí)間見表3。
表3 測(cè)試結(jié)果數(shù)據(jù)對(duì)比
經(jīng)軟件模擬RISC-V處理器,利用RISC-V處理器中可用的數(shù)字信號(hào)處理(DSP)擴(kuò)展和集群的并行性,分別在開啟DSP拓展模式和未開啟DSP拓展模式下通過測(cè)試所得數(shù)據(jù),如表4所示在q7_t數(shù)據(jù)類型上優(yōu)化后的卷積神經(jīng)網(wǎng)絡(luò)算法加速比為11.968 101 93,此數(shù)據(jù)在蜂鳥E203上采用8 M大小RAM測(cè)得。
表4 采用hbird-e-sdk使用riscv-cifar10測(cè)試所得數(shù)據(jù)
本文針對(duì)當(dāng)前嵌入式神經(jīng)網(wǎng)絡(luò)平臺(tái)逐漸提高的性能要求和部署神經(jīng)網(wǎng)絡(luò)模型時(shí)受到寄存器資源限制這一現(xiàn)狀,設(shè)計(jì)了一款面向RISC-V的神經(jīng)網(wǎng)絡(luò)嵌入式平臺(tái)模型,且采用8位點(diǎn)量化數(shù)據(jù)對(duì)ARM CMSIS-NN定開源的卷積神經(jīng)網(wǎng)絡(luò)模型進(jìn)行優(yōu)化。分析了采用8位定點(diǎn)量化數(shù)據(jù)的必要性、將神經(jīng)網(wǎng)絡(luò)部署在嵌入式設(shè)備上的必要性、ARM CMSIS-NN模型中的有待優(yōu)化之處。實(shí)驗(yàn)結(jié)果表明,RISC-V的拓展指令集在測(cè)試平臺(tái)可以驗(yàn)證通過。優(yōu)化后的神經(jīng)網(wǎng)絡(luò)卷積模型在蜂鳥E203開發(fā)板上實(shí)現(xiàn)邏輯功能,并完成了SPIKE仿真分析和示例測(cè)試。由測(cè)試結(jié)果可知,性能加Cortex-M3提升了11.968倍。目前該模型已經(jīng)用于蜂鳥E203嵌入式設(shè)備,下一步將面向特定的模型進(jìn)行優(yōu)化,對(duì)嵌入式神經(jīng)網(wǎng)絡(luò)的全連接層、池化層進(jìn)一步研究。