王湘新,時 洋,文 梅
(1.武警湖南省消防總隊信息中心,湖南 長沙 410205;2.國防科技大學計算機學院,湖南 長沙 410073)
關于卷積神經網絡CNN(Convolution Neural Network)的相關研究在過去幾十年中取得了很多的成果,CNN作為一種強有力的方法在圖像分類[1]、語音識別[2]以及目標檢測[3]等相關領域中所取得的結果明顯優(yōu)于傳統方法。在圖像分類領域,CNN方法甚至已經具有了擊敗人類的能力。微軟在ImageNet的數據集上使用CNN將分類錯誤率降至3.57%[4],而人類自己眼睛分類的錯誤率大約是5.1%。CNN應用的不斷普及也使得研究人員開始嘗試在移動設備上對其進行使用。
從較高的層次來看,CNN的工作過程分為兩個階段。首先是利用大量數據讓網絡進行學習的訓練階段,接下來的前向階段則是利用網絡來進行推斷工作。
對于移動設備上的CNN應用來說,往往只需要前向階段。CNN在移動設備上得到普及的最大制約因素就是巨大的計算量。以圖像分類的前向過程為例,在常見的手機移動設備上,一張圖像的分類結果就需要數秒的時間,這些時間主要被用來進行CNN中的卷積計算。如何處理好復雜的卷積計算是CNN在移動設備上取得實際應用的關鍵。
Figure 1 Convert the convolution to matrix multiplication圖1 矩陣乘法計算卷積
本文提出了一種新的方法來處理CNN的卷積過程,以實現更好的性能。我們的基礎是MXNet[5]所提供的在手機CPU上的CNN基礎實現[6]。我們注意到,手機上的圖形處理單元GPU(Graphics Processing Unit)相對于CPU來說,計算性能更為強大。因此,本文利用OpenCL(Open Computing Language)[7]將卷積計算轉化為并行度更高的矩陣乘法運算,并將其轉移到GPU端來進行。之后,本文又采用了諸如優(yōu)化任務分配、利用片上存儲、向量化和循環(huán)展開等操作來進行優(yōu)化,最終,卷積過程取得了16.39倍的加速比,前向分類過程取得了2.1的加速比。
雖然各種各樣的CNN具有不同的網絡結構,但是它們都是由卷積層、池化層等網絡層連接組成。在這些網絡層中,CNN絕大部分的計算量都集中在卷積層。卷積層通過將卷積核在圖像數據上滑動計算,來提取圖像中的高維特征。在CNN的具體實現中,對于卷積計算有兩種主流實現方法:一是按照卷積定義來進行計算。這種方法的優(yōu)點是原理簡潔,缺點則是計算訪存混亂,容易觸發(fā)內存速度瓶頸。另一種方式則是將計算過程轉化為矩陣相乘來實現,優(yōu)點是訪存更加規(guī)整,可以利用已有的數學運算庫,缺點則是增加內存消耗。
在本文的卷積加速實現中,考慮到移動GPU的功能特點,我們采用的是第二種矩陣乘的方法,可以更加充分地利用GPU的并行計算性能,同時有更多的優(yōu)化空間。具體的轉化過程在Kumar的論文[8]中有詳細的介紹,示例過程如圖1所示。原理就是將圖像數據以及卷積核數據進行復制重排,構造兩個大矩陣,通過這兩個大矩陣的相乘來得到卷積計算的最終結果。
圖形處理單元(GPU)[9]首先應用在計算機圖形應用程序比如游戲之中,后來,人們又利用它的多核架構來進行通用并行計算。不同于人們在桌面GPU上長達幾十年的嘗試與研究,在移動GPU這一領域,直到最近幾年才有人開始嘗試開發(fā)。得益于類似OpenCL這樣的編程框架的興起,我們才可以方便地使用移動GPU進行通用編程。
OpenCL是一個開放的、無版權的跨平臺并行編程標準,它提供了一個標準接口來給程序員進行編程。由制造計算設備的硬件廠商來實現這個接口并將其具體實現封裝在設備之中。在OpenCL中,主機處理器(通常是CPU)管理OpenCL的運行環(huán)境上下文以及計算設備,程序員需要進行選擇來將計算密集的任務編程成為一個kernel文件,然后選擇一個計算設備來執(zhí)行這個任務。在一個計算設備中,可以劃分為許多的工作組,而每個工作組又可以劃分為許多的計算單元。每個計算單元都會獨立地執(zhí)行編寫的kernel程序。
一個典型的移動GPU是由數個計算單元組成的,在每個單元內有數個算術邏輯單元ALU(Arithmetic Logic Unit)。這里我們以高通公司生產的Adreno 330 GPU[10]為例:這款移動GPU具有4個計算單元和總計128個ALU,在每個計算單元中有16線程可以并行。與桌面GPU不同,移動GPU的存儲器與CPU芯片共享相同的內存,但是每個計算單元具有不能由其他計算單元使用的本地存儲器。之前很少有人研究如何利用移動GPU來加速應用。龔若皓[11]在移動GPU平臺上進行了關于加速靜態(tài)、動態(tài)圖像解碼算法的嘗試,取得了4倍的加速比;曾寶國[12]借助移動GPU給離散傅里葉變換的高效實現提供了一種新的思路,可以大大提高信號處理的實時性。對于移動GPU利用的探索,還是一個很新的研究課題,具有一定的研究意義。
在MXNet框架中,卷積計算是通過矩陣乘法來實現的。其中,矩陣A表示輸入圖像數據,矩陣B是卷積內核,矩陣C存儲計算的結果。這里設A具有M行和K列,B具有K行和N列,C具有M行和N列。在卷積計算過程中,三個矩陣均使用列主序來進行存儲。在矩陣乘法的實現方式上,MXNet選擇的是OpenBLAS[13]數學運算庫中的SGEMM函數。
本文目標是在移動設備上利用GPU的并行計算能力來對卷積層進行加速實現。為此,本文首先利用OpenCL編程框架在移動GPU上實現了矩陣乘法的多重循環(huán)樸素算法。這里設定局部大小為{1,1}和全局大小為{M,N},在此條件下,我們有M*N個工作線程,每個工作組包含一個線程,每個線程計算C的一個元素,這是我們的基本內核。接下來,本文將討論一些優(yōu)化手段來提升程序性能。
在討論具體的優(yōu)化策略之前,我們需要對矩陣的數據存儲結構進行調整。首先,由于GPU的結構決定了它在處理ALU運算時速度快,處理條件分支時卻相當緩慢,我們將歸一化矩陣規(guī)模,以減少由于矩陣尺寸所引起的條件分支數量。在這里,我們用零填充矩陣使之行列數都是32的倍數。
第二,我們需要恢復矩陣A為行主序存儲而不是列主序存儲。在矩陣乘法計算中,計算C中的一個元素,需要A的一整行和B的一整列。如3.1節(jié)所述,初始矩陣被存儲在列主序中。換句話說,在B的某一列中的元素可以被連續(xù)地訪問,但A某一行中的元素則不能。所以,這種調整有助于提升矩陣乘法中對內存的訪問連續(xù)性。接下來,我們重點介紹兩種加速GPU上卷積實現的方法。
3.2.1 優(yōu)化任務劃分并使用局部存儲
在本文所使用的Adreno 330 GPU中有4個計算單元,而且每一個計算單元中都有32個ALU,并支持16個線程同時運行。因此,前文中的樸素內核對于GPU的計算能力利用并不充分。當某一工作組被裝載到GPU某個計算單元時,這個工作組中僅有一個線程運行,并且這個線程只負責計算C中的一個元素。這種計算模式下的線程劃分會造成線程數目以及空閑ALU單元過多的問題。為了提升GPU的利用率,本文采取分塊矩陣乘的方法來優(yōu)化線程任務劃分。
該方法的示意圖如圖2所示,為了計算矩陣C的一個子塊,需要矩陣A相應的行和矩陣B相應的列?,F在,如果我們利用分塊(記為Asub和Bsub以及Csub)來劃分A和B,我們可以通過反復計算Asub與Bsub的乘積進行累加來得到Csub的值。
Figure 2 Principe of block matrix multiplication圖2 矩陣乘分塊算法原理
經過對于矩陣分塊規(guī)模的測試,本文最終選擇局部大小為{1,32}以及全局大小為{M/32,N}。這意味著現在每32個線程將組成一個工作組,總計擁有M*N/1024工作組。工作組中的每個線程將計算包含32個元素的一列。矩陣子塊中的每一列數據將由工作組中的一個線程負責計算。通過矩陣分塊,本文可以解決之前內核所造成的線程數量過多的問題。
在目前卷積計算的加速實現中,每當需要矩陣A、B的數據時,都會從全局內存中進行讀取。頻繁的全局內存訪問會造成程序執(zhí)行緩慢。值得注意的是,在移動GPU中,每個計算單元具有一塊獨立的存儲空間,稱為本地存儲器,本地存儲器中的數據訪問速度高于全局存儲器,并且在本地存儲器中的數據可以在此工作組中的線程之間實現共享。因此,本文將利用本地存儲器來優(yōu)化程序的訪存速度。
在Adreno 330 GPU中本地存儲器塊的大小為8 192 KB,即可容納2 048個單精度浮點數。所以本文將分塊矩陣實現中A和B的兩個32 *32子塊(Asub與Bsub)迭代加載到本地存儲器,線程從本地的存儲器讀取數據,而不是從全局存儲器來讀取計算的數據。通過這種訪存優(yōu)化,在本地存儲器中的每個元素將被用于工作組中的32個線程。也就是說,本文成功地將程序全局內存訪問量減少到只有原來的1/32。
3.2.2 循環(huán)展開與向量化
在這一小節(jié)里,將討論兩種可以加速程序循環(huán)體執(zhí)行的方法:循環(huán)展開以及向量化。
循環(huán)展開是一種循環(huán)變換技術,可以加快整個循環(huán)執(zhí)行的速度,其代價則是代碼二進制文件的大小增加。由于GPU對于條件分支的執(zhí)行很慢,而循環(huán)展開則會減少甚至消除分支的數量,所以循環(huán)展開技術在GPU上將帶來性能上的提升。而另一方面,更大的循環(huán)體會給編譯器提供更多優(yōu)化的機會。值得一提的是,并不是越大的循環(huán)體就會取得越好的性能,這里面還有一個高速緩存交換的因素也要考慮。在本文中,經過對性能以及代碼文件大小的綜合考量,我們選擇以8為距離進行循環(huán)展開。
現在在我們的內核中,所操作的數據類型為4個字節(jié)的單浮點類型。本文提出對于循環(huán)執(zhí)行進行向量化操作,增加對訪存部件寬度的利用率。在Adreno 330的硬件層次不支持向量運算(如向量乘或向量加),但他們確實有專為全局和本地存儲器特殊設計的更寬的讀取和存儲指令。這將使我們得到更快的速度,因為更寬的數據類型減少了加載/存儲指令的數目。OpenCL還支持簡單的向量數據類型,這使得我們也不必將矩陣轉換成向量類型就可以享受到向量化帶來的收益。
經過對于float4、float8以及float16三種向量寬度的測試,本文選擇了表現最好的float4向量來進行向量化。圖3顯示了我們如何利用這些優(yōu)化來從存儲器加載數據。
本文中所涉及的實驗在小米note[14]上完成。這款手機使用的是高通801處理器,在這個處理器上集成了一顆Adreno 330的GPU,其單精度32位浮點計算峰值為84.6 GFlops/s,訪存速度為2.84 GB/s。
本文首先使用AlexNet[1]來測試卷積實現中矩陣乘法使用不同內核的執(zhí)行時間,以檢驗本文GPU實現以及優(yōu)化手段的加速效果。結果展示如圖4所示。從實驗結果可以看到,利用GPU比使用CPU獲得了明顯的加速效果。對于移動GPU,帶寬是非常緊缺的資源,所以優(yōu)化策略應著眼于內存訪問。我們使用本地存儲器后速度提升了3倍;使用向量加載/存儲指令將性能提升了1.25倍;而循環(huán)展開又將性能提升了1.16倍。對于最終的卷積內核,程序訪存速度為2.24 GB/s,達到了GPU訪存峰值的79.9%,對GPU進行了比較充分的利用。圖5是手機上運行我們應用程序的一個屏幕截圖,可以看到圖像經過CNN網絡被正確分類(文本框中是分類的結果)。
Figure 4 Comparison of the speed of matrix multiplication圖4 矩陣乘法速度比較
Figure 5 Screen capture of the App圖5 程序運行截圖
盡管使用移動GPU來進行卷積計算會帶來額外的開銷,比如說數據的重新組織以及傳輸等,但是對于整體前向過程的測試結果顯示,在整體時間上,本文的實現也取得了很好的加速效果。在此本文選取了不同的三種CNN網絡來測試GPU實現在整體前向過程上的加速效果以及加速穩(wěn)定性:AlexNet、Inception-Full Net以及Inception-Sub Net。AlexNet是首個在圖像分類領域擊敗傳統方法的CNN網絡;Inception Net是由Szegedy[15]提出的一個比AlexNet更加復雜精確的網絡,計算量也更大;這個網絡有一個簡化的、應用更加廣泛的版本為Inception-sub。前向整體時間的測試結果顯示在表1中。
Table 1 Forward time of different networks
可以看到,對于不同結構的CNN網絡,本文的卷積實現都能取得大約2.1倍的前向過程加速比,因此程序對于不同的網絡結構具有穩(wěn)定性。
針對CNN網絡中卷積計算負載較大的問題,本文在移動GPU上采取矩陣乘方法對卷積算法進行了實現。同時,通過探索利用優(yōu)化任務劃分、局部存儲單元、向量化以及循環(huán)展開等技術來加速程序的執(zhí)行速度。優(yōu)化之后,矩陣乘法的執(zhí)行速度由CPU版本的0.44 Gflops提升了16.39倍,達到了7.21 Gflops;同時實驗結果還表明,本文的優(yōu)化實現可以將整體前向的時間減少到只有原來的一半。
一個可以繼續(xù)研究的問題依然是關于處理時間的。今后的工作重點將是利用CPU和GPU協同工作,以得到更快的速度。
[1] Krizhevsky A,Sutskever I,Hinton G E.Imagenet classification with deep convolutional neural networks[C]∥Proc of International Conference on Advances in Neural Information Processing Systems, 2012: 1097-1105.
[2] Abdel-Hamid O, Mohamed A,Jiang H,et al.Applying convolutional neural networks concepts to hybrid NN-HMM model for speech recognition[C]∥Proc of 2012 IEEE International Conference on Acoustics,Speech and Signal Processing (ICASSP),2012: 4277-4280.
[3] Chen Y N,Han C C,Wang C T,et al.The application of a convolution neural network on face and license plate detection[C]∥Proc of the 18th International Conference on Pattern Recognition,2006:552-555.
[4] He K,Zhang X,Ren S,et al.Deep residual learning for image recognition[C]∥Proc of 2016 IEEE Conference on Computer Vision and Pattern Recognition, 2016:1.
[5] Chen T,Li M,Li Y,et al.MXNet: A flexible and efficient machine learning library for heterogeneous distributed systems[J].arXiv preprint arXiv:1512.01274,2015.
[6] Leliana/WhatsThis[EB/OL].[2015-11-11].https:∥github.com/Leliana/WhatsThis.
[7] Munshi A. The openCL specification[EB/OL].[2016-03-10]. http:∥www.khronos.org/opencl.
[8] Chellapilla K,Puri S,Simard P.High performance convolutional neural networks for document processing[C]∥Proc of the 10th International Workshop on Frontiers in Handwriting Recognition,2006:1.
[9] Owens J D,Houston M,Luebke D,et al.GPU computing[J].Proceedings of the IEEE,2008,96(5): 879-899.
[10] Qualcomm Inc. Qualcomm Adreno GPU[EB/OL].[2013-01-11].https:∥www.qualcomm.com/news/onq/2013/01/11/inside-snapdragon-800-series-processors-new-adreno-330-gpu.
[11] Gong Ruo-hao.Image codec parallel optimization based on embedded mobile GPU[D].Chengdu:Southwest Jiaotong University,2015.(in Chinese)
[12] Zeng Bao-guo,Yang Bin,et al,Parallelization of DFT based on embedded mobile GPU[J].Microcontrolles & Embedded Systems,2016:16(1):12-15.(in Chinese)
[13] Zhang Xian-yi,Wang Qian,Saar W.OpenBLAS library[EB/OL].[2015-12-09].https:∥www.openblas.net.
[14] XiaoMi. XiaoMi note[EB/OL].[2015-01-15].https:∥www.mi.com/minote.
[15] Szegedy C,Liu W,Jia Y,et al.Going deeper with convolutions[J].arXiv preprint arXiv:1409.4842,2014.
附中文參考文獻:
[11] 龔若皓. 基于嵌入式移動 GPU 的圖像編解碼并行優(yōu)化[D].成都:西南交通大學,2015.
[12] 曾寶國,楊斌.基于嵌入式移動 GPU 的離散傅里葉變換并行優(yōu)化[J].單片機與嵌入式系統應用,2016,16(1): 12-15.