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