深度學習模型大小與模型推理速度的探討(1)
作者丨田子宸@知乎(已授權)
來源丨https://zhuanlan.zhihu.com/p/411522457
編輯丨極市平臺
導讀
本文對衡量深度學習模型大小的一些常用指標,如計算量、參數量、訪存量、內存占用等進行探討,分析這些指標對模型部署推理的影響,尤其是計算量與訪存量對模型推理速度的影響,并給出在不同硬件架構下設計網絡結構的一些建議。
0、前言
當年頭一次實習做算法的時候,主管給的第一個任務就是“把一個大的分割模型砍成一個小的”。當時并不理解模型“大”、“小”的真正含義,就簡單的選取計算量作為評價指標,瘋狂砍計算量(backbone 換 MobileNet/ShuffleNet、Conv 換成 DepthWise Conv、以及一些奇奇怪怪的融合結構等等),把模型計算量砍了將近 10 倍,結果一部署發現速度并沒有快多少,反而是把最初的 ResNet 簡單砍掉幾個 block 效果更好。
也是從那時起接觸了訪存量、流水線、RoofLine 模型等概念,對模型推理速度的問題產生了興趣,從此踏上了深度學習推理優化的不歸路(劃掉)。
如今做推理優化和 HPC 已經有一段時間了,還是偶爾能回想起當年不懂推理時設計的與硬件嚴重不匹配的模型。此外在工作中跟研究員溝通時,也會發現部分研究員對模型大小和模型推理速度的關系不太了解,設計出一些很難發揮硬件計算能力的模型結構。因此在這里對一些用于評價模型大小的指標——計算量、參數量、訪存量、內存占用等指標進行詳細探討,分析這些指標會對模型的部署推理產生何種影響,詳細討論計算量和訪存量對模型推理速度的影響,并給出不同硬件架構下設計高效網絡結構的一些建議。
本文不僅僅是為了給出網絡的設計建議,更是希望能夠有效傳達性能優化的基礎理論知識,以及性能分析的基本思路,幫助各位同學減少網絡設計與部署之間的 gap,更高效的完成網絡設計與部署工作。非常希望本文能夠對大家的工作有所幫助,也非常歡迎大家在評論區留言探討。
一、常用的模型大小評估指標
目前常用于評價模型大小的指標有:計算量、參數量、訪存量、內存占用等,這些指標從不同維度評價了模型的大小。本節僅作簡單介紹,熟悉的小伙伴可以跳過此節,直接看后面的分析與探討。
1. 計算量
計算量可以說是評價模型大小最常用的指標了,很多論文在跟 baseline 進行比較時,都會把計算量作為重要的比較依據。
計算量是模型所需的計算次數,反映了模型對硬件計算單元的需求。計算量一般用 OPs (Operations) ,即計算次數來表示。由于最常用的數據格式為 float32,因此也常常被寫作 FLOPs (Floating Point Operations),即浮點計算次數。(這里為了跟傳統習慣保持一致,下文就統一采用 FLOPs 啦)
模型的整體計算量等于模型中每個算子的計算量之和。而每個算子的計算量計算方法各不一致。例如對于 Eltwise Sum 來講,兩個大小均為 (N, C, H, W) 的 Tensor 相加,計算量就是 N x C x H x W;而對于卷積來說,計算量公式為(乘加各算一次):
PyTorch 有不少工具可以模型計算量,但需要注意的是這些工具有可能會遺漏一些算子的計算量,將其計算量算成 0,從而導致統計的計算量跟實際計算量有輕微的偏差,不過大多數情況下這些偏差影響不大。
2. 參數量
早期的論文也很喜歡用參數量來評價模型大小。
參數量是模型中的參數的總和,跟模型在磁盤中所需的空間大小直接相關。對于 CNN 來說參數主要由 Conv/FC 層的 Weight 構成,當然其他的一些算子也有參數,不過一般忽略不計了。
參數量往往是被算作訪存量的一部分,因此參數量不直接影響模型推理性能。但是參數量一方面會影響內存占用,另一方面也會影響程序初始化的時間。
參數量會直接影響軟件包的大小。當軟件包大小是很重要的指標時,參數量至關重要,例如手機 APP 場景,往往對 APK 包的大小有比較嚴格的限制;此外有些嵌入式設備的 Flash 空間很小,如果模型磁盤所需空間很大的話,可能會放不下,因此也會對參數量有所要求。
除了在設計模型時減少參數量外,還可以通過壓縮模型的方式降低軟件包大小。例如 Caffe 和 ONNX 采用的 Protobuf 就會對模型進行高效的編碼壓縮。不過壓縮模型會帶來解壓縮開銷,會一定程度增加程序初始化的時間。
3. 訪存量
訪存量往往是最容易忽視的評價指標,但其實是現在的計算架構中對性能影響極大的指標。
訪存量是指模型計算時所需訪問存儲單元的字節大小,反映了模型對存儲單元帶寬的需求。訪存量一般用 Bytes(或者 KB/MB/GB)來表示,即模型計算到底需要存/取多少 Bytes 的數據。
和計算量一樣,模型整體訪存量等于模型各個算子的訪存量之和。對于 Eltwise Sum 來講,兩個大小均為 (N, C, H, W) 的 Tensor 相加,訪存量是 (2 + 1) x N x C x H x W x sizeof(data_type),其中 2 代表讀兩個 Tensor,1 代表寫一個 Tensor;而對于卷積來說,訪存量公式為:
訪存量對模型的推理速度至關重要,設計模型時需要予以關注。
4. 內存占用
內存占用是指模型運行時,所占用的內存/顯存大小。一般有工程意義的是最大內存占用,當然有的場景下會使用平均內存占用。這里要注意的是,內存占用 ≠ 訪存量。
內存占用在論文里不常用,主要原因是其大小除了受模型本身影響外,還受軟件實現的影響。例如有的框架為了保證推理速度,會將模型中每一個 Tensor 所需的內存都提前分配好,因此內存占用為網絡所有 Tensor 大小的總和;但更多的框架會提供 lite 內存模式,即動態為 Tensor 分配內存,以最大程度節省內存占用(當然可能會犧牲一部分性能)。
和參數量一樣,內存占用不會直接影響推理速度,往往算作訪存量的一部分。但在同一平臺上有多個任務并發的環境下,如推理服務器、車載平臺、手機 APP,往往要求內存占用可控。可控一方面是指內存/顯存占用量,如果占用太多,其他任務就無法在平臺上運行;另一方面是指內存/顯存的占用量不會大幅波動,影響其他任務的可用性。
5. 小結
計算量、參數量、訪存量、內存占用從不同維度定義了模型的大小,應根據不同的場合選用合適的指標進行評價。
模型推理速度不單單受模型計算量的影響,也與訪存量和一些其他因素息息相關。下文將詳細討論影響模型推理速度的因素。
二、計算量越小,模型推理就越快嗎
答案是否定的。
實際上計算量和實際的推理速度之間沒有直接的因果關系。計算量僅能作為模型推理速度的一個參考依據。
模型在特定硬件上的推理速度,除了受計算量影響外,還會受訪存量、硬件特性、軟件實現、系統環境等諸多因素影響,呈現出復雜的特性。因此,在手頭有硬件且測試方便的情況下,實測是最準確的性能評估方式。
在設計網絡結構時,如果有實測的條件,建議在模型迭代早期對性能也進行測試。一些 NAS 的方法也會對搜索出來的網絡結構進行測速,或者干脆對硬件速度進行了建模,也作為初期搜索的重要參數。這種方法設計出來的網絡在后期部署時,會極大減少因性能問題迭代優化的時間和人力開銷。
這里我將討論影響模型在硬件上推理速度的一些因素,一方面希望可以幫助手動/自動設計網絡結構的同學更快的設計更高效的網絡結構,另一方面希望當模型部署時性能出現問題時能夠為大家提供分析原因的思路。
這一問題我將從如下 3 個點進行討論:
計算密度與 RoofLine 模型
計算密集型算子與訪存密集型算子
推理時間
1. 計算密度與 RoofLine 模型
計算密度是指一個程序在單位訪存量下所需的計算量,單位是 FLOPs/Byte。其計算公式很簡單,很多教材、資料里也稱之為計算訪存比,用于反映一個程序相對于訪存來說計算的密集程度:
RoofLine 模型是一個用于評估程序在硬件上能達到的性能上界的模型,可用下圖表示:
RoofLine 模型
用公式描述:
當程序的計算密度I較小時,程序訪存多而計算少,性能受內存帶寬限制,稱為訪存密集型程序,即圖中橙色區域。在此區域的程序性能上界=計算密度×內存帶寬,表現為圖中的斜線,其中斜率為內存帶寬的大小。計算密度越大,程序所能達到的速度上界越高,但使用的內存帶寬始終為最大值。
反之如果計算密度I較大,程序性能受硬件最大計算峰值(下文簡稱為算力)限制,稱為計算密集型程序,即圖中藍色區域。此時性能上界=硬件算力,表現為圖中的橫線。此時計算速度不受計算密度影響,但計算密度越大,所需內存帶寬就越少。
在兩條線的交點處,計算速度和內存帶寬同時到達最大值。
在不同設備上,同一個程序的性質可能發生變化
在不同設備上,同一個程序的性質可能發生變化。例如上圖中的程序2,在算力稍弱的設備2上屬于計算密集型程序,而在算力較強的設備1上就屬于訪存密集型程序了(感謝評論區指正)。如果想要充分發揮設備1的性能,應當適當加大程序的計算密度(比如到程序3的位置)。
2. 計算密集型算子與訪存密集型算子
網絡中的算子可以根據計算密度進行分類。一般來講,Conv、FC、Deconv 算子屬于計算密集型算子;ReLU、EltWise Add、Concat 等屬于訪存密集型算子。
同一個算子也會因參數的不同而導致計算密度變化,甚至改變性質,比如在其他參數不變的前提下,增大 Conv 的 group,或者減小 Conv 的 input channel 都會減小計算密度。
舉個栗子,對于不同參數的卷積,計算密度如下:
可以看到,不同參數下卷積算子的計算密度有很大的差異。第 4 個算子 Depthwise Conv 計算密度僅有 2.346,在當下的很多設備上都屬于訪存密集型算子。
算子的計算密度越大,約有可能提升硬件的計算效率,充分發揮硬件性能。我們以一個 Intel X86 服務器平臺為例(10980 XE)。該平臺 CPU 頻率為 4.5 GHz,我們以 16 核為例,其理論 FP32 算力為 4.608 TFLOPs/s,內存帶寬理論值為 96 GB/s。在此平臺上的 RoofLine 模型為:
Intel 10980 XE 16 核 RoofLine 模型,以及各個算子的計算密度與性能
該平臺“拐點”的計算密度為 48,計算較為密集的 OP1 和 OP2 處在計算密集區,能夠達到平臺的算力峰值;而 OP3 和 OP4 處在訪存密集區,受內存帶寬限制不能到達算力峰值,尤其是 OP4,由于計算訪存比過低,計算效率僅有可憐的 4.9%,計算效率并不高。
*博客內容為網友個人發布,僅代表博主個人觀點,如有侵權請聯系工作人員刪除。