隨着深度學習的飛速發展,對處理器的性能要求也變得愈來愈高,隨之涌現出了不少針對神經網絡加速設計的AI芯片。卷積計算是神經網絡中最重要的一類計算,本文分析了高性能卷積計算中的數據複用,這是AI芯片設計中須要優化的重點之一,具體思路以下git
- 數據複用的動機
- 存儲-計算分離框架下,針對卷積計算的優化思路
- 針對卷積計算的硬件架構設計分析
- 已經面臨的挑戰和解決方向
- 神經網絡中數據複用的將來
深度學習的發展過程當中,較高的計算量是制約其應用的因素之一。卷積神經網絡中,主要計算爲三維的卷積計算(後簡稱爲卷積),現有的主流處理器難以高性能,高效能的完成卷積計算。相比通常的通用計算,卷積計算中存在的大量數據複用以及計算的規則性,在硬件的微架構(後簡稱爲架構)設計和計算優化上有很大的優化空間,由此誕生了衆多針對深度學習加速的AI芯片。卷積計算過程能夠表示以下github
for i = 1 : Ho for j = 1 : Wo for k = 1 : Co for l = 1 : Hf for m = 1 : Wf for n = 1 : Ci out[i,j,k] += In[i*s+l.j*s+m,n]*F[l,m,n];
其中各參數的含義以下表算法
數據維度 | 描述 |
---|---|
Ho/Wo | 輸出feature map的高和寬 |
Co | 輸出的channel數目 |
Hf/Wf | filter的高和寬 |
Ci | 輸入的channel數目 |
s | 卷積計算的stride |
據此可推算出輸入輸出數據的數據複用關係,以下表編程
Type | Mem Refs | Ops | Ops/Memory |
---|---|---|---|
Filter | \(H_f W_f C_i C_o\) | \(H_o W_o C_o H_f W_f C_i\) | \(H_oW_o\) |
Input | \(H_o W_o C_i s^2\) | \(H_o W_o C_o H_f W_f C_i\) | \(H_fW_fC_o/s^2\) |
Output | \(H_o W_o C_o\) | \(H_o W_o C_o H_f W_f C_i\) | \(H_f W_f C_i\) |
能夠看出,卷積計算過程當中對Filter,Input和Output的數據均有很高的數據複用;充分利用計算過程當中的數據複用是達到高性能和高效能的關鍵,這主要有如下幾個方面緣由緩存
根據Roofline模型很容易解釋第一點緣由。Roofline模型是一種面向吞吐量的性能評價模型,它指出在理想狀況下,處理器性能的理論上界。以下圖(Ref. CS217_Lec6)所示,在數據複用不高的狀況下,峯值性能受限於內存(Memory-bound)。網絡
訪問不一樣存儲的歸一化能耗比(Ref. 6)能夠解釋第二點緣由。充分利用數據複用,使得訪存多發生在RF等靠近ALU的存儲上,能夠極大下降功耗。架構
針對第三點,以AMD ZEN系列CPU爲例,Die的結構以下圖所示(Ref. https://en.wikichip.org/wiki/amd/microarchitectures/zen)。能夠看出FPU和ALU只佔CPU面積的很小一部分。大部分面積是控制邏輯的緩存。這意味着若是針對卷積計算這種規則的,具備時間和空間強相關性的,且沒有分支跳轉的計算設計專門的硬件,能夠拋開專用處理器中複雜的控制和緩存設計,減少芯片面積,提高性能,下降功耗。app
這些特性代表,卷積計算有很大的優化空間;專門針對卷積計算設計的芯片能極大的提升性能和效能 。框架
矩陣-矩陣乘法的應用已經很是普遍,不少線性代數庫充分結合了矩陣計算中的數據複用關係和處理器緩存的層次設計結構,對矩陣-矩陣乘法進行了充分的優化(GEMM,通用矩陣乘法)。\(C = AB + C\)的矩陣乘法能夠表示爲ide
for i = 1 : m for j = 1 : n for k = 1 : t C(i,j) = A(i,k)*B(k,j) + C(i,j)
這一形式和第1節中卷積的計算方式極其相似。實際上,針對三維的Tensor進行展開(即將卷積計算中的六層循環的內三層進行合併),很容易將卷積計算轉化爲矩陣乘法計算(im2col)。 其中一種展開方式以下圖 (Ref. CS217_Lec9)
下圖也給出了一個具體的例子(Ref. 在 Caffe 中如何計算卷積?,原始連接High Performance Convolutional Neural Networks for
Document Processing)
此時,卷積計算等價爲矩陣乘法計算;而卷積計算中的數據複用關係等價爲了矩陣計算中的數據複用關係。矩陣-矩陣乘的複雜度以下所示
Ex. | Mem Refs | Ops | Ops/Memory
-| - | - | -
Matrix-Matrix Mult | \(4n^2\) | \(2n^3\) | \(n/2\)
現有的處理器架構從存儲和計算之間的關係上來看都是相似的,處理器計算性能的上限能夠經過計算單元及其運行頻率肯定。爲了高性能的完成矩陣計算,即便得性能達到Roofline模型中峯值,須要對矩陣計算的三層循環進行優化。在進行分析以前,須要明確兩點固有的特性
若是矩陣存儲在內存中(DDR),直接按三層循環進行矩陣計算,那麼每一個週期須要訪問\(a,b,c\)三個數,此時性能會受限於DDR帶寬。將矩陣放在片上的Cache中是一個好的選擇,可是片上Cache的容量每每較小。解決這一個矛盾的方法是對大的矩陣進行分塊,此時矩陣計算能夠表示爲
for i = 1 : MR : m // step MR for j = 1 : NR : n // step NR for k = 1 : KC : c // step KC // block-dot product in cache // Csub_{NR*MR} += Asub_{MR*KC}*B_sub(KC*NR) // opt. mirco kernel for ir = 1:MR for jr = 1:NR for kr = 1: KC Csub(ir,jr) += Asub(ir,kr)*Bsub(kr,jr);
採用這一分塊方式,假設矩陣存儲在DDR,分塊後的矩陣存儲在片上Cache;完成\(MR\times NR\times NC\)次乘法計算只須要從DDR獲取\(MR\times NR + NR \times NC + MR\times NC\) 個數據,合理的分塊能下降對DDR的訪問。
針對具備不一樣存儲層次的處理器以及不一樣大小的矩陣計算而言,有不一樣的分塊方式以達到峯值性能。雖然這一方法針對矩陣計算進行了很好的優化,但對於卷積計算而言,依舊存在缺陷
因爲這些缺陷存在,若是沒有針對硬件架構進行特殊的設計,卷積即矩陣乘法的設計思路每每沒法達到峯值性能。
採用矩陣-矩陣乘法進行卷積計算忽略了卷積自己的特性。卷積計算其實是一類很特殊的計算,以一維的離散卷積爲例,函數\(f,g\)之間的卷積可表示爲
\[ (f*g)[n]=\sum_{m=-\infty}^{\infty}f[m]g[n-m] \]
以有限長脈衝響應(Finite impulse response,FIR)濾波器做爲離散卷積的一維特例,可表示爲
\[ y[n]=\sum_{i=0}^{N}b_i \cdot x[n-i] \]
一維的脈動陣列FIR濾波器的一種實現方式,其實現結構以下圖(Ref. Wikipedia),採用這種結構,每輸入一個\(x[n]\),就能計算獲得一個\(y[n]\)。這種特殊的數據複用是根據卷積計算的特殊性質獲得的。
在卷積神經網絡中,卷積層的計算通常也存在這種數據複用關係(除kernelsize <= stide狀況外)。若是能用好這一特性,再也不將卷積轉化爲矩陣乘法,直接計算卷積,能得到更高的性能。爲了達到這一目標,和分析矩陣乘法相似,對卷積的六層循環進行分析
for i = 1 : Ho for j = 1 : Wo for k = 1 : Co for l = 1 : Hf for m = 1 : Wf for n = 1 : Ci out[i,j,k] += In[i*s+l.j*s+m,n]*F[l,m,n];
相似GEMM,最內層循環會被並行化,爲了達到更好的性能,能夠對循環順序進行調整(Ref.9)
完成調整以後,對卷積計算進行分塊(Ref. 9)
爲了進一步提升訪存的效率,Input/Ouput/Filter在內存中的排布方式也須要進行相應的調整,可參見參考文獻9,此處再也不描述。
不管是將卷積轉化爲矩陣計算,或者直接計算卷積,都可以經過分塊的方式相對高效的完成卷積計算;因爲將卷積轉化爲矩陣計算有必定開銷,其性能可能會受到必定影響,但矩陣計算具備更高的靈活性。
顯然,實現一個硬的GEMM加速器能夠加速矩陣計算,進而加速卷積計算。針對GEMM的分塊矩陣(即內層循環)進行硬件加速是一種簡單,高效且相對靈活的選擇,其優點包括
相似設計包括Nvidia的Volta架構,其加速核心被稱爲Tensor Core;以及華爲的達芬奇架構(Davinci Core),其卷積的計算核心被稱爲CUBE Core。
其中,Nvidia的每一個Tensor Core是一個\(4\times4\times4\) 的MAC陣列。計算\(C = AB + C\) 時,矩陣\(A,B\) 中的元素廣播到4個不一樣的MAC上,同時每一個四個乘法的結構累加到一塊兒,以下圖所示(Ref.Volta Tensor Core GPU Achieves New AI Performance Milestones)
達芬奇中的CUBE Core是一個\(16\times16\times16\)的MAC陣列(以Davinci Max爲例),以下圖所示(hotchips31),具備更高的數據複用關係。
Nvidia Volta架構中,Tensor Core僅僅只是一個特殊的計算單元,其地位和FP計算單元一致。
爲了保證計算單元以外設計的統一性,送入計算單元的數據位寬徹底一致,和普通的FP32計算單元比,Tensor Core在算力上有很大的優點。由下表能夠看出,因爲數據複用和精度的下降,Tesnor Core的理論性能是FP32的8倍(同頻,其中兩倍受益於精度的下降)。
Ex. | DataWidth | Data Num | Ops |
---|---|---|---|
FP32 | 256 | 8 | 16 |
Tensor Core | 256 | 16 | 128 |
Davinci Core進行了更多的設計,配合完成高性能的卷積計算。MTE中的img2col代表其進行了3D Tensor到Matrix的轉換。(Ref. 華爲在hotchips詳細介紹了達芬奇架構)
前文提到「卷積即矩陣乘法的設計思路沒法達到峯值性能」,但有了硬件架構的聯合設計,這一結論再也不成立。譬如在Davinci Core中,在L0 Buffer進行Img2col能夠下降因爲im2col增長的訪存帶寬,合理設計的L0 BufferA/B/C也能應對卷積操做中大量的中間結果。
脈動陣列的典型表明是Google TPU,Google TPU中設計的脈動陣列也是針對矩陣乘法設計(雖然有的脈動陣列也可直接計算卷積,但TPU並無採用這一類設計)。以前的文章有對Google TPU進行細緻的分析(動手寫一個簡單版的谷歌TPU),並實現了一個小規模的基於VLIW+Vector Architecture的TPU(SimpleTPU,VLIW+向量體系結構),能夠做爲進一步參考。Google TPU的其計算核心爲一個\(256\times 256\)的二維脈動陣列,以下圖所示(Ref. 4)
另外一個相似的設計時Telsa(特斯拉)的Full self-driving(FSD) computer,其內部的Nerual Network Accelerator(NNA)也實現了一個大規模的矩陣乘法器(NNA也可能時直接採用廣播的形式,而非脈動形式進行輸入)。參考其專利中的說明,其具體實現和Google TPU略有差別。
根據描述,FSD NNA中的Wieght和Activation均經過DATA FORMATTER後送入到MATRIX PROCESSOR中。乘法的結果在MATRIX PROCESSOR中進行累加,計算出最終結果後依次向下移位輸出。FSD中有兩個NNA,其中MATRIX PROCESSOR的大小均爲\(96\times 96\),和TPU1相比,FSD的主要差別表如今
針對TPU和FSD這種在數據流中的差別,能夠分爲Weight Stationary,Output Stationary和No Local Reuse等(Ref. 6)。這種針對Dataflow的分類方法也涉及到數據複用,但主要針對Register File上的複用進行分析,和本文針對計算中存在的數據複用關係進行分析有所不一樣(一個典型的差異是Ref.6中歸類爲no local reuse的狀況在本文認爲是有數據複用的)。
Eyeriss是一種直接針對卷積計算優化的加速器,和其餘加速器不一樣,Eyeriss針對Convolution Reuse進行了優化。按Ref.6的分類標準,是一種Row Stationary。(Ref. 7)
因爲卷積神經網絡計算卷積時C方向的特殊性,Convolution Reuse僅在H和W方向存在。以kernelsiz=3,stride=1爲例,卷積計算中row方向的數據複用以下圖(Ref. 7)
此時ifmap中的元素3被利用了三次,只須要從存儲中訪問一次元素3,就能完成3次計算。當擴展爲二維時,有(Ref. 7)
即ifmap的row方向在不一樣PE之間進行復用;而實際上ifmap的col方向的數據會暫存在PE內的RF上,col方向的數據也在RF上進行復用。
Eyeriss利用了convolution resue,同時也能夠利用其餘resue的手段。譬如上圖中的filter在水平PE之間複用,psum在垂直的若干個PE之間複用。這意味這Eyeriss相比其餘結構作到了更多的數據複用,能夠進一步下降功耗。
一維卷積的計算複雜度爲\(O(n^2)\),因爲時域卷積等於頻域相乘,對於離散信號而言,能夠經過快速傅里葉變換(Fast Fourier Transform,FFT)及其逆變換將信號在時域和頻域之間變換。而FFT的計算複雜度爲\(O(nlogn)\),當\(n\)取值較大時,其計算複雜度會遠低於直接計算一維卷積。
相似的,能夠考慮在其餘域進行二維/三維卷積的計算;針對卷積神經網絡中的加速,有
但若想取得必定的加速比,這些方法對卷積核的大小和步長均有要求;這一類方法均難以適應卷積核日益小型化的發展趨勢。
當大多數AI芯片中的神經網絡加速器還在使用AlexNet/VGG/ResNet跑benchmark時,新的網絡層出不窮。一些爲了運行在嵌入式設備上而設計的輕量化網絡經過壓縮卷積中各個維度的計算來下降計算量,這很大程度影響了卷積計算中的數據複用關係。考慮在輕量化網絡中使用的Point Wise Conv和Depth Wise Conv,以及延時受限系統中Batch=1的全鏈接層,有下表
Type | Ops/Memory |
---|---|
Point-Wise Convolution Layer | Input: \(C_o/s^2\) Filter: \(H_oW_o\) Output:\(C_i\) |
Depth-Wise Convolution Layer | Input: \(H_fW_f/s^2\) Filter: \(H_oW_o\) Output:\(H_f W_f\) |
Batch=1 Fully Connect Layer | Input: \(C_o\) Filter: \(1\) Output:\(C_i\) |
而第三節中一些典型的基於數據複用的加速其設計中,若想達到最優性能,對數據複用的要求是
Architectures | Input1 | Input2 | Output |
---|---|---|---|
\(16\times16\times16\) Cube Core | 16 | 16 | 16 |
\(256\times256\) Systolic Array | 256 | 1350 | 256 |
Eyeriss V1(Theo. low bound) | 168 | 42 | 42 |
數據複用關係的失配會讓這些加速器在運行這些特定的Layer時出現嚴重的效率問題。譬如TPU V1在計算\(3\times3\) Depthwise Conv時效率不可能超過\(9/256=3.5\%\)。這樣低的效率使得這些設計良好的網絡帶來的數量級的計算量降低變得毫無心義。
從根源上看,Cube Core或者Systolic Array的優化目標都是Matrix-Matrix乘法,而Batch=1得FC和Depthwise Conv更貼近於Matrix-Vector乘法,這在本質上就是不一樣的。即便在軟件層面的優化上,這兩個運算也是分別進行優化的(GEMM和GEMV)。
而對於芯片設計而言,已經面臨的挑戰是如何設計一個在多變的複用關係下均能保證較高效率的神經網絡加速器。完成這一目標,至少有兩種不一樣的設計方向
上述的幾乎全部的討論和設計,都能歸結到下降數據帶寬上。一旦數據帶寬下降後,其靈活性就受到了很大的限制,這是沒法計算GEMV的緣由之一。若是須要加速器可以在各類狀況下有良好的表現,最直接的解決方案就是在設計上提供高的帶寬和靈活性。
Eyeriss V2就採用這種思路對Eyeriss V1進行改進,以高效支持MobileNet。爲了提供高帶寬,Eyeriss設計了層次化2D Mesh的Noc(Ref. 8)
設計中一個PE Cluster具備12個PE,12個PE之間互相鏈接;PE Cluster經過一個2D Mesh進行互聯。Global Buffer到PE之間具備豐富的連線,在不一樣計算模式下能夠以Multicast,broadcast和unicast進行數據傳輸,充分知足不一樣計算下的數據需求。
儘管Eyeriss V2中並無提到可重構,但其Noc在計算不一樣網絡時有不一樣的選通路徑,和可重構的思想一致。通常談到硬件可重構,通常會想到FPGA(Field-Programmable Gate Array,現場可編程大規模邏輯門陣列)。經過FPGA片上豐富的的互聯結構和查找表,FPGA理論上能夠用於實現各類形式的電路。
FPGA能夠創造出各類可能,但FPGA設計上有不少冗餘,在佈局佈線和加載上也會花費較多時間。究其本因,是由於FPGA採用了很底層的基本單元來構建整個電路。與FPGA這種細粒度可重構相對應的是粗粒度可重構網絡,粗細度可重構不像FPGA同樣能夠控制每個bit的選通,而是提供了一系列基本的計算單元和互聯結構。根據算法的需求,能夠採用不一樣的方式構建這些計算單元。譬如Plasticine中的PCU中,每一個FU由前向,反饋等多種路徑,能夠構建不一樣的計算單元。(Ref. 11)
多個PCU之間經過交換網絡和其餘PCU及PMU(Memory)相連,能夠配合完成不一樣的操做。這些都以增長片上各個單元之間的互聯性爲基礎。(Ref. 11)
採用可重構設計的還有清華大學微電子系設計的Thinker芯片,具體可參考A High Energy Efficient Reconfigurable Hybrid Neural Network Processor for Deep Learning Applications(Ref11)。這樣的具備靈活互聯結構的可重構加速器,能夠支持矩陣-矩陣乘法,矩陣-向量乘法以及更多的其餘計算,具備較強的靈活性。
另外一種思路是對某些運算作到極致的支持,其餘的運算經過CPU或者其餘的Core來計算;從華爲達芬奇架構,到Google TPU2/3的設計上,都有的體現,華爲的達芬奇架構可參見3.1節,Google V2/3的框圖以下
Google的框圖並無透露太多的細節,僅僅表面TPU中因爲MXU和scalar/vector units;華爲的達芬奇架構則指出了
雖然Vector Unit彷佛並不能計算FC Layer或者Depthwise Conv Layer,但這也表明了一種設計方向。當採用3D Matrix Unit進行矩陣計算時,隨着\(N\)取值的增長,數據輸入帶寬隨\(N^2\)增加,而MACs的數量隨\(N^3\)增加,這表面針對特定的計算進行優化結果可能會更優。固然,這樣的設計也有一些缺陷
固然,這種設計思想並不意味一個加速Core只能加速很受限的計算類型,依舊能夠對單個的加速Core進行兼容設計,本節的討論和4.1並不徹底衝突。譬如依舊有一些簡單方法可讓一個三維的MAC陣列(相似Cube Core)同時支持GEMM和GEMV操做,但依舊會有一些限制,因爲數據複用的不一樣,這兩類運算始終落在Roofline模型的不一樣位置。
但無論從哪一個角度去解決面臨的新的挑戰,暫時都沒有看到一個完美的解決方案。或許咱們並不須要一個真正完美的解決方案,能解決一部分問題,創造價值就已經足夠了。這裏引用Cloud TPU(TPU V2/3)的一些說明
Cloud TPU適合如下工做負載
- 由矩陣計算主導的模型
- 主循環內沒有自定義TensorFlow操做的模型
- 須要訓練數週或數月的模型
- 有效批量很是大的大型和極大型模型
Cloud TPU不適合如下工做負載
- 須要頻繁分支或逐項代數主導的現有代數程序
- 稀疏方式訪問內存的工做負載可能不適用於TPU
- 須要高精度算法的工做負載
顯然,Cloud TPU聚焦在大型和極大型模型的加速上,輕量化模型不在考慮範圍以內;Cloud TPU甚至明確指出了暫不支持Depthwise Convolution計算。但這些都不影響Cloud TPU的應用和創造價值。
而正由於沒有完美的設計,選擇和取捨會變得尤其重要。
雖然在AI芯片設計過程當中,都針對算法進行了深度的優化;同時算法也針對芯片實現進行了定點化和低比特量化等工做:這些看似是一個聯合優化的過程。可是歸根到底,既然是選擇爲AI應用設計芯片,在設計過程當中,算法永遠占主導地位。從長遠來看,還須要把握算法的發展趨勢。
站在硬件設計的角度來看,因爲在計算機誕生之初就有了高性能並行計算的需求,不少設計實際上以及出現了很長時間,譬如數據並行的向量體系結構,VLIW,脈動陣列,稀疏計算都有40年以上的歷史,2D Mesh互聯也至少有30年。從設計上看,新的東西並非不少,架構成功的關鍵在因而否順應了時代的潮流,包括算法/需求的發展和底層硬件技術的發展。
在發展過程當中算法和現有的硬件上的分歧每每是存在的,以本文討論的卷積計算的數據複用爲例,這和網絡稀疏化的發展方向相悖。若是以極度稀疏化爲目標,那麼網絡計算過程當中的數據複用會愈來愈低。
神經網絡中數據複用的將來如何,徹底取決於算法的發展。