神經網路的推理速度是由什麼決定的?
深度學習使用了更深層的神經網路,擁有更多的參數,讓深度學習具備了優於傳統機器學習的學習表徵能力。與此同時,過多的參數與計算量也讓深度學習模型也很難在一般的機器上 real-time 執行。
從大約 2015 年開始,研究人員透過軟體、硬體、演算法等,透過不同的方式加速深度學習的推理時間;但是在探討加速方法之前,我們得先知道影響深度學習模型的推理時計算速度的關鍵因素有哪些。
這篇文章列舉了一些影響神經網路推理速度的指標,並且逐個介紹其如何影響神經網路的推理速度:
- FLOPs
- MACs
- Floating-Point Precision 浮點數精度
- Quantization 量化
- Inference SDK
- Process Unit 計算單元
FLOPs — 最直接的指標
FLOPs (Floating Point Operations),直譯就是浮點數的計算次數,是最直接用來評量深度學習速度的指標。一個簡單的概念是:如果一個演算法所需要的浮點數計算次數越多,那麼這個演算法所需要的時間越長。
值得注意的是,FLOPs 並不等於模型參數量。FLOPs 表示的是模型的計算成本,而模型參數量只能表示模型的大小與頻寬,不能直接反映模型的推理時間。
雖然說 FLOPs 只計算浮點數,但是通常神經網路的計算都是浮點數的,所以實際上我們在計算深度學習的 FLOPs 的時候並特別不會去確認數字的類型。對一個神經網路而言,總共的 FLOPs 就是所有子 OP (Operations) 的 FLOPs 加總。
舉例來說,Convolution OP 的 FLOPs 計算方式如下:
下圖的用動畫的例子來說明的話,上述公式可以展開成 (2 x 1 x 3 x 3–1) x 3 x 3 x 1 = 17 x 9 = 153,也就是 FLOPs=153。後面的 9 對應著動畫的 9 次卷積移動,而前面的 17 則是每格輸出數字需要的乘法與加法次數。
值得注意的是,無論原輸入與卷積核的數字是不是 0,在計算 FLOPs 的時候都需要納入計算。如果要將原輸入與卷積核的數字 0 剔除計算,則需要特殊的硬體支援。
MACs
MACs (Memory Access Costs) ,有時候也會寫成 Memory Access,指的是記憶體的存取次數。通常 MACs 是與 FLOPs 成正比的,但是在根據網路結構的不同,MACs 可能會在 FLOPs 不變的情況下增加,導致模型的推理時間變長。
在經典輕量化網路之一 SufficientNet V2 的論文中,作者對 MACs 做了一次詳盡的分析,發現一些常見的降低 FLOPs 的卷積設計,例如 Element-wise Convolution, Group Convolution,反而會使 MACs 增加。同時,在同樣的卷積設計下,輸入與輸出 Channels 相同時的 MACs 會最低,速度也會提升。
MACs 會導致運行速度增加的原因,是由於電腦的 IO 處理都是需要時間的。要進行一次的卷積計算,就勢必得把輸入與卷積核中的數字都從各自的記憶體中取出來,計算完後再寫到輸出的記憶體內。在一般的程式設計準則中,需要儘量減少 IO 操作例如 memory copy 也是基於一樣的道理,因為 IO 成本其實不低且通常難以察覺。
Floating Point Precision 浮點數精度
由於神經網路中的計算都是基於浮點數,因此使用精度越高的浮點數就可能造成越大的耗時。這篇文章列出了各種浮點數類型,並且用圖片的方式表示各種浮點數類型中每個 bit 的用途:
在深度學習中,最常用的是 Float32,也就是 32 bits 的浮點數類型。但為了提升計算速度,Float16 也使用的越來越頻繁,因為更小的浮點數各式不僅代表更小的計算成本,也代表更少的記憶體搬運。理論上,Float16 會比 Float32 減低一半的計算量、記憶體大小與 IO 頻寬。
在增加計算效率的同時,降低浮點精度也會導致神經網路的精度下降。因此NVIDIA 提出了論文《Mixed Precision Training》,可以在訓練的時候就考慮低浮點精度的情況,讓模型在浮點精度下降一半的情況下維持網路能力不變。目前主流的框架如 TensorFlow、PyTorch 都已經可以支援 Mixed Precision Training。
Quantization 量化
因為電腦的整數型別計算本來就比浮點數快,因此 2017 年 Google 提出了模型量化 Quantization,試著在網路推理階段用整數計算取代所有的浮點數計算。在量化計算之中,所有的數字都是整數,而這些整數都可以透過一組 scaling、bias 還原至對應的浮點數。
量化可以實作的計算壓縮率會比降低浮點精度來得高。目前主流的量化可以從 Float32 壓縮至 Int8,理論速度可以提昇至少 4 倍。當然,單純的量化會造成網路精度的損失,因此有 2 種量化方法可以儘量保持模型的精度:量化訓練、後量化。
量化訓練 Quantization Aware Training
量化訓練是在模型的訓練階段就把模型類型轉換為整數型。通常的量化訓練包含 3 個步驟:
- 使用一般的浮點數模型訓練。
- 統計浮點數輸出的值域邊界,把網路權重轉換為整數與一組 scaling、bias,並持續訓練權重、scaling、bias。
- 保存模型,紀錄學習的權重、scaling、bias。
目前 TensorFlow 對量化訓練的支援程度遠比 PyTorch 好,詳細範例可以參考 TensorFlow 的官方教學:
後量化 Post-Training Quantization
後量化是在模型訓練結束之後在轉換數字型別,後量化的原理是統計模型在實際計算中的實際值域上下界,推算量化的 scaling、bias,再把模型的權重轉換為整數類型。因此,為了後量化統計,需要額外輸入一個小的資料集給後量化使用。這個資料集可以來自於訓練集或驗證集,而且數量級可以在 1000 以內。
PyTorch 的後量化支援雖然比量化訓練好,但仍比不過 TensorFlow:
除了一般的整數量化外,目前最極端的量化是二制化網路—— Binary Neural Network,只用 0 跟1 來取代神經網路的所有權重。本篇文章不做過多介紹,有興趣的同學可以參考這篇文章:
Inference SDK
Inference SDK 是專門用來做模型推理的函式庫。與一般的深度學習框架不同,Inference SDK 剔除了模型的訓練、設計、Debug 等功能,並且用專門的數學函示庫對提升推理速度與記憶體頻寬做了最佳化。目前最有名的 Inference SDK 應屬 NVIDIA 的 TensorRT 與 Google 的 TFLite。
實務上,你應該針對不同的部屬場景使用不同的 SDK。如果你的模型要部署在雲端 server 處理大量的 data,那你應該使用 TensorRT;如果你是部署在手機端或是其他 IoT 設備,你應該使用 TFLite;如果你是部署在記憶體受限的 DSP、微處理器,可以使用 TFLiteMicro。
以下以 TensorRT 為例,來列舉一下 Inference SDK 能夠透過什麼方式來加速深度學習的模型推理。
- Reduce Mixed Precision:透過混合精度,將模型轉換為更低的浮點精度或是整數量化,在計算損失最小的情況下增加推理速度。
- Tayer/Tensor Fusion:融合相鄰的線型計算來減少推理時間,包含垂直融合與水平融合。比如前後 Conv/BN 層是可以完全融合成一個 Conv 表示的,屬於垂直融合;而多分支的 Conv 分支也可以融合為一個 Conv 層,屬於水平融合。Layer/Tensor Fusion 直接降低了模型的 FLOPs,達到加速作用。
- Kernel Auto-Tuning:相同的卷積運算在底層可能有不同的實作方式。SDK 會根據部署機器的不同,選擇最好的卷積計算實作。
- Dynamic Tensor Memory:透過動態的記憶體管理機制,降低記憶體的獲取、釋放、搬運次數,達成加速的效果。
- Multi-Stream Execution:利用平行計算降低運行時間。
- Time Fusion:針對 RNN 類的時序網路做的特殊加速。
Process Unit 計算單元
不同的計算單元會有不同的加速指令集與硬體實作,因此將模型部署在不同的計算單元上,推理的速度也會不一樣。除了深度學習最常用到的 GPU 之外,也有很多為了深度學習提出的專門晶片,例如 Google 推出的 TPU,以及各家晶片廠為移動設備設計的 NPU。另外,為了程式與模型的通用型,也有不少消費級的 APP 會把模型部署在 CPU。
GPU
GPU 本來是為了電腦繪圖設計的芯片,其特性是核心數非常多,因此可以利用來做大量的平行計算。早期只有 CUDA 的時代,GPU 就有被用來做科學計算的用途;在深度學習框架普世之後,GPU 在 AI 的地位也越來越穩固,是目前學術界最通用的部屬方式。
TPU
TPU,Tensor Process Unit,是 Google 為了深度學習專門推出的計算晶片,在產業界用的較多。通常是配備給雲端 Server,用來加速機器學習的訓練、推理。
NPU
NPU,Neural Process Unit,一般是指終端設備使用的深度學習專用晶片。不同廠家的 NPU,對浮點精度、量化類型、卷積類型的支援程度也不一樣。值得注意的是,很多廠商並不會用 NPU 這個名字,例如聯發科的 MT8175 中用的名字是 AI Accelerator。
CPU
CPU 是最通用的計算單元,因此將深度學習部署在 CPU 上也是最通用的部屬方式。值得注意的是,在相同的 CPU 計算主頻率下,不同的 CPU 架構以及指令集也會導致不同的推理時間,例如 RISC-V。
目前硬體加速也是深度學習的一個研究方向之一。例如今年 Facebook 提出了新的論文 ELMA,可以使用新的硬件架構,在維持模型浮點精度不變的情況下加速深度學習的推理時間,效果甚至可以超越 8 bits 量化。
結論
雖然我們在研讀深度學習論文時,大部分的網路架構只會列出參數量與FLOPs,作為網路 runtime 的速度指標。但是實際上神經網路的計算速度遠遠不是這兩個參數可以定義的。
在實際情況下,我們需要針對不同的部屬環境去設計不同的網路。例如對於部署在 server 端的模型,我們可以使用 Float32、中等 FLOPs 的模型設計,結合 TensorRT 的部屬方式;但是對於部署在 ARM 芯片的模型,我們可能需要 8-bits 量化、低 FLOPs、低 MACs 的模型設計,並且搭配 TFLite 達到最佳的加速效果。