推斷(Inference),就是深度學習把從訓練中學習到的能力應用到工作中去。
精心調整權值之后的神經網絡基本上就是個笨重、巨大的數據庫。為了充分利用訓練的結果,完成現實社會的任務,我們需要的是一個能夠保留學習到的能力,還能迅速應用到前所未見的數據上的,響應迅速的系統。這就是推斷,根據真實世界中的少量數據,迅速地提供正確的答案。 這可是計算機科學的全新領域。現在主要有兩種方法來優化龐大笨拙的神經網絡,以實現高速低延遲的應用。
第一個方法,是查找神經網絡中經過訓練后並沒有用到、也就是說尚未激活的部分。這些區域在應用中並不需要,所以可以被清洗掉。
第二個方法,則是把神經網絡中的多個層融合為一個單獨的計算步驟。
眾所周知,深度學習(deep learning)在訓練階段完成模型的建立和參數調優,在推斷階段完成具體的實現及應用。這就好比造車的過程與開車的過程一樣,造車過程需要不斷嘗試“新設計-試車-調優”,而設計一旦定型后,就需要大規模生產制造,最終賣給用戶使用。設計車型(訓練階段)時候可以借助各種工具和技術來加速研發與達到更高指標,但生產制造(推斷階段)時需要考慮成本、材料、市場等因素作出靈活適當的剪裁。深度學習在訓練階段常用GPU來加速訓練,在推斷階段可以用CPU、專用芯片(ASIC)、FPGA等實現。 GPU並行能力非常強大(內部包括上千核),但成本高昂、功耗大,不適合在無人機、航天、手機通信等特定場景中應用; CPU作為通用芯片的代表,理論上將在訓練、推斷階段均可使用,但運行速度教慢導致不適合做訓練、功耗太大不適合在功耗有強烈要求的場景中做推斷; ASIC通常是針對某個算法而設計的芯片,速度非常快,可以應用在推斷階段,但其設計周期長、成本高、缺乏靈活性不能適應深度學習算法快速更新的要求;FPGA是一種通用的芯片,在速度和功耗上位於CPU和ASIC之間,可以針對硬件編程所帶來的並行行和靈活性可以很好地適應深度學習的需求(算法更新+推斷階段的要求),但其開發設計難度較大,門檻高,需要掌握硬件電路調試的知識。另外,像goolge的TPU、寒武紀的NPU,有人認為是一種ASIC,也有人稱其為專用處理器(並列與CPU、DSP之外的新型處理器),他們是針對深度學習領域的算法(們)設計的一種計算芯片(顯然,這是在推斷階段),其內部設計了一套適合算法(們)計算的通用結構,任何新的算法只需映射(map)到特定到硬件結構上並按序執行即可,其好處是功耗、速度均得到了提升,不足是沒有配套的成熟的工具來支持其map過程。從應用者的角度來講,在推斷階段,CPU和FPGA是目前較好的選擇。從研究者的角度來講,尋找深度學習算法的高效通用實現方法,並設計硬件架構和軟件編譯工具是當務之急。當然,硬件架構可以設計成專用處理、也可以用FPGA現有資源搭建,相應的軟件編譯工具也會有巨大差異。
當前,深度學習在推斷階段的研究主要集中在以下幾個方面:降存儲、降計算、降功耗、提速度、 兼顧靈活性; 借助的手段是量化數據、重用數據、優化計算結構、優化訪存技術等。其目的是,依據現有的硬件資源,尋找一個簡化的、易於實現的近似模型代替原先訓練好的模型,來做具體實現和應用,要求近似的精度(測試准確率)盡可能地高,即壓縮模型。為了達到模型精度上的逼近,許多方法中對新模型進行重新訓練,而訓練過程中會加入新的約束來保障后期易於實現。比如,BNN權重量化成1bit數時,需要重新訓練權重。(原先訓練好的模型是在32bit的浮點數上得到的高精度模型。)從更加宏觀角度講,針對深度學習算法的具體實現問題,可以建立一個模型來求解,該計算模型要運行速度快、計算量盡可能地小、數據盡可能地重用、存儲需求量盡可能地小,還能適應各種不同深度學習算法等,假如設計出了該計算模型,軟硬件該如何分工與協同設計,硬件功能選擇專用處理器設計還是借助FPGA資源來設計或是其他硬件計算平台來設計,軟件功能該如何設計實現並與配硬件功能配合起來一起工作等。這就類似計算機采用圖靈計算模型、馮諾依曼體系架構實現一樣,用通用的計算模型和架構解決各種復雜的計算問題。顯然,要設計這樣的計算模型困難重重,但值得嘗試。 目前,采用這樣的思想典型代表有google TPU、寒武紀的NPU、深鑒科技的ESE、MIT的Eyeriss等。仔細分析他們的相似之處,可以發現:1)充分挖掘CNN卷積的內在並行能力,借助移位寄存器和片上buffer實現緩存和數據重用; 2)全部采用低精度的數據計算; 3)借鑒了CPU的設計理念,硬件分時復用+SIMD的處理辦法等。
1)數據量化。減少數據的位寬不僅有助於降低存儲,還可以降低計算量,甚至簡化計算。在GPU上訓練時常常采用32位的浮點數; 而推斷階段受到片上存儲和帶寬的限制,需要減少位寬換取更大的緩存來增加並行能力。 常用的量化精度有16bits,12bits,8bits,4bits,1bit, 有研究表明16bits與32bits在效果上非常接近(小於0.5%), 8bits的效果也在5%以內,因此,8bits非常受歡迎,許多廠商號稱支持8bits的深度學習應用。具體量化的方法,有簡單縮小位寬的,也有對數表示數據的,還有動態小數點將整數與小數分開的。不論那種都需要重新訓練才能確定權重數據。當然,32bits全精度的效果是參考標准。
1bit的研究也是一個熱點,盡管看起來1bit的表達能力遠遠弱於32bits,但針對特定算法的效果卻沒那么糟糕。從BNN到BCNN、再到XNOR、到現在各種變體,不斷嘗試各種方法拓展其通用性和提高預測精度。BNN類的算法非常適合在FPGA上實現,這是因為FPGA擁有大量的lut,可以精確地只針對位進行編程,而兩個1bit的數據乘法就是XNOR,權重可以實現存儲在lut中,然后給定輸入就可以立即得到結果,並不用大量的復雜操作,效率非常高。
2)簡化網絡結構。CNN相對全連接的神經網絡是稀疏的,但相對計算資源來講還是復雜的。目前壓縮模型的做法主要包括:剪枝(pruning)、權重共享(shared weights)。剪枝就是將模型中某些連接去掉,減少計算量和存儲量,去掉的標准有權重接近0的、相對其他權重較小的等。權重共享就是將卷積核中所有元素(權重)划成幾個類,同一個類中的元素都用“質心”來代替,這樣只需存儲幾個“質心”的值和每個元素歸屬哪個質心的索引即可,由於類別數都很少,索引所需的位寬用少量的幾位即可表示,從而起到壓縮模型的效果。也有人提出使用hash表來查找權重,也是一種嘗試而已。
3)數據重用。CNN圖像卷積過程中會有大量數據重復使用,考慮到片內存儲空間有限,不可能將其全部讀入再去處理; 而按照輸出特征圖形像素點挨個計算的需求來讀取數據,則數據從外存到內部緩存的帶寬瓶頸將會降低執行速度,而且每個數據重復讀取多次也是不可取的做法。顯然,數據重用必須在片上存儲空間、帶寬、計算資源三者之間尋找一個平衡點。MIT的Vivienne Sze等人仔細研究了可並行的三個維度:輸入圖像局部數據可在多個卷積核間重用; 卷積核可在輸入圖像不同區域重用; 卷積核在不同輸入特征間的重用(batch size>1),並在基礎上設計了一個CNN加速器(Eyeriss)。整張圖像(可以是三維的)的卷積可以化為矩陣的乘法運算,因此,理論上講只要矩陣乘法優化做得足夠好,也可以達到加速的效果。為了達到數據重用的目的,研究人員設計了諸多結構,比如采用移位寄存器鏈+MAC(乘累加)實現卷積,也有采用PE單元+ 加法tree並行實現卷積等。數據重用的方式也會影響到讀取外存數據和寫出輸出特征的方式。從宏觀上講,計算模型決定了數據重用的方式、硬件架構設計、訪存方式、軟件編譯的設計等。
4)計算結構。 現有幾乎每篇論文都會涉及計算架構,常用PE(process element)表示一個計算單元,具體功能不盡相同,但至少包括了卷積操作。除了PE之外,可能還會有局部buffer,有的還會有一級緩存負責從外部讀取數據再分發給二級緩存進行局部計算。當然,有些設計PE中包含了私有的buffer。 考慮到帶寬的影響,常常從外存讀取一塊數據進來,這時也會用到FIFO作為一級緩存。PE單元內部的設計千差萬別,有的借助移位寄存器鏈實現pipeline計算,也有先設計1-D的卷積單元、再組成2-D、3-D的卷積,還有搭建類似有ALU的結構。有些結構中甚至包括更大粒度的CU(Compute Unit)或PU(Process Unit)來執行更大粒度的並行。不論如何,整個設計中會包括若干PE、CU/PU以便並行加速計算。
5)存儲結構。移位寄存器實現數據搬運是最簡單有效的方式,可以實現pipeline,也無需尋址,控制器起來相對簡單。但是,在開始或數據重新加載時會出現若干周期無效數據,需要單獨剔除。而且,其比較適合一維順序情況。對於二維或三維的就需要同步,有些麻煩。FIFO也是一種常用的結構,可以設計成多維的,一個時鍾周期可以同時讓若干數據同時入隊或出隊。因此,FIFO可以滿足從片外緩存大塊數據的需要(緩存若干行輸入圖像數據,緩存若干行輸出特征圖像數據)。計算結構與存儲結構密切相關,正如人的左腿與右腿一般,缺一不可站立。
6)編譯工具。計算模型解決了如何做的問題,硬件架構(計算結構+存儲結構)決定了硬件功能,編譯工具需要完成深度學習算法向硬件架構的映射(map)的問題,讓其正確可靠地執行起來。編譯工具沒有一個統一標准,只能隨着硬件架構來設計。當前,caffe訓練好的模型結構存儲在prototxt文件中,權重數據存儲在數據庫中。鑒於prototxt格式獨立與具體編程語言,且有很好地解析工具,諸多學者、廠商最先使用它作為深度學習模型的輸入格式,再向硬件結果映射。這里存在軟硬件划分的問題,如果硬件做的足夠多,軟件編譯器就會相對簡單點,但也會缺乏一些靈活性; 反之,軟件工作量會變大。這里需要說明的一點是,這里的編譯跟c/c++/python編譯到CPU不是一回事,跟FPGA開發中的綜合布局布線也不是一回事——因為目標硬件結構不同,映射過程差異也非常大。盡管許多人在FPGA上采用C/C++/Verilog/VHDL設計了深度學習加速器,並借助vivado/quartus編譯生成了位流碼,但其本質只是將硬件架構在FPGA上實現了,即配置編程后的FPGA變成一個深度學習加速平台,該加速器運行哪個深度學習算法、怎么運行,需要從prototxt編譯而來的“指令”才能知道。(這里講的是通用加速平台而非真的某個具體算法編寫的verilog電路)。
總之,當前主流的深度學習算法在硬件上實現的主要集中在壓縮模型和設計計算模型兩個方面,前者着力尋找一個簡單有效易於實現的模型,后者重點在尋找一個基於現有硬件資源可以高效計算的方法,這二者的結合可以更加高效有效地解決推斷階段帶來的計算復雜和存儲爆炸等問題。