一文看懂深度學習模型壓縮和加速
作者:知乎-揚易(@xieyangyi) 簡楓 千瞳
一
前言
近年來深度學習模型在計算機視覺、自然語言處理、搜索推薦廣告等各種領(lǐng)域,不斷刷新傳統(tǒng)模型性能,并得到了廣泛應用。隨著移動端設備計算能力的不斷提升,移動端AI落地也成為了可能。相比于服務端,移動端模型的優(yōu)勢有:
減輕服務端計算壓力,并利用云端一體化實現(xiàn)負載均衡。特別是在雙11等大促場景,服務端需要部署很多高性能機器,才能應對用戶流量洪峰。平時用戶訪問又沒那么集中,存在巨大的流量不均衡問題。直接將模型部署到移動端,并在置信度較高情況下直接返回結(jié)果,而不需要請求服務端,可以大大節(jié)省服務端計算資源。同時在大促期間降低置信度閾值,平時又調(diào)高,可以充分實現(xiàn)云端一體負載均衡。 實時性好,響應速度快。在feed流推薦和物體實時檢測等場景,需要根據(jù)用戶數(shù)據(jù)的變化,進行實時計算推理。如果是采用服務端方案,則響應速度得不到保障,且易造成請求過于密集的問題。利用端計算能力,則可以實現(xiàn)實時計算。 穩(wěn)定性高,可靠性好。在斷網(wǎng)或者弱網(wǎng)情況下,請求服務端會出現(xiàn)失敗。而采用端計算,則不會出現(xiàn)這種情況。在無人車和自動駕駛等可靠性要求很高的場景下,這一點尤為關(guān)鍵,可以保證在隧道、山區(qū)等場景下仍能穩(wěn)定運行。 安全性高,用戶隱私保護好。由于直接在端上做推理,不需要將用戶數(shù)據(jù)傳輸?shù)椒斩?,免去了網(wǎng)絡通信中用戶隱私泄露風險,也規(guī)避了服務端隱私泄露問題
算法層壓縮加速。這個維度主要在算法應用層,也是大多數(shù)算法工程師的工作范疇。主要包括結(jié)構(gòu)優(yōu)化(如矩陣分解、分組卷積、小卷積核等)、量化與定點化、模型剪枝、模型蒸餾等。 框架層加速。這個維度主要在算法框架層,比如tf-lite、NCNN、MNN等。主要包括編譯優(yōu)化、緩存優(yōu)化、稀疏存儲和計算、NEON指令應用、算子優(yōu)化等 硬件層加速。這個維度主要在AI硬件芯片層,目前有GPU、FPGA、ASIC等多種方案,各種TPU、NPU就是ASIC這種方案,通過專門為深度學習進行芯片定制,大大加速模型運行速度。
二
算法層壓縮加速

分解前:矩陣參數(shù)量為?(M * N) 分解后:參數(shù)量為?(M*K + K*N) 壓縮量:(M * N) / (M*K + K*N), 由于M遠大于N,故可近似為 N / k,當N=2014,k=128時,可以壓縮8倍
分組前:參數(shù)量?(M*N*dk*dk) 分組后:參數(shù)量?(M*dk*dk + M*N*1*1) 壓縮量:(M*dk*dk + M*N*1*1) / (M*N*dk*dk),近似為 1/(dk*dk)。dk的常見值為3,也就是3*3卷積,故可縮小約9倍

使用兩個串聯(lián)小卷積核來代替一個大卷積核。InceptionV2中創(chuàng)造性的提出了兩個3x3的卷積核代替一個5x5的卷積核。在效果相同的情況下,參數(shù)量僅為原先的 3x3x2 / 5x5 = 18/25 使用兩個并聯(lián)的非對稱卷積核來代替一個正常卷積核。InceptionV3中將一個7x7的卷積拆分成了一個1x7和一個7x1, 卷積效果相同的情況下,大大減少了參數(shù)量,同時還提高了卷積的多樣性。
2.1.5 其他
全局平均池化代替全連接層。這個才是大殺器!AlexNet和VGGNet中,全連接層幾乎占據(jù)了90%的參數(shù)量。inceptionV1創(chuàng)造性的使用全局平均池化來代替最后的全連接層,使得其在網(wǎng)絡結(jié)構(gòu)更深的情況下(22層,AlexNet僅8層),參數(shù)量只有500萬,僅為AlexNet的1/12 1x1卷積核的使用。1x1的卷積核可以說是性價比最高的卷積了,沒有之一。它在參數(shù)量為1的情況下,同樣能夠提供線性變換,relu激活,輸入輸出channel變換等功能。VGGNet創(chuàng)造性的提出了1x1的卷積核 使用小卷積核來代替大卷積核。VGGNet全部使用3x3的小卷積核,來代替AlexNet中11x11和5x5等大卷積核。小卷積核雖然參數(shù)量較少,但也會帶來特征面積捕獲過小的問題。inception net認為越往后的卷積層,應該捕獲更多更高階的抽象特征。因此它在靠后的卷積層中使用的5x5等大面積的卷積核的比率較高,而在前面幾層卷積中,更多使用的是1x1和3x3的卷積核。

將大小相近的參數(shù)聚在一起,分為一類。 每一類計算參數(shù)的平均值,作為它們量化后對應的值。 每一類參數(shù)存儲時,只存儲它們的聚類索引。索引和真實值(也就是類內(nèi)平均值)保存在另外一張表中 推理時,利用索引和映射表,恢復為真實值。

訓練一個performance較好的大模型。 評估模型中參數(shù)的重要性。常用的評估方法是,越接近0的參數(shù)越不重要。當然還有其他一些評估方法,這一塊也是目前剪枝研究的熱點。 將不重要的參數(shù)去掉,或者說是設置為0。之后可以通過稀疏矩陣進行存儲。比如只存儲非零元素的index和value。 訓練集上微調(diào),從而使得由于去掉了部分參數(shù)導致的performance下降能夠盡量調(diào)整回來。 驗證模型大小和performance是否達到了預期,如果沒有,則繼續(xù)迭代進行。




2.3.3 神經(jīng)元剪枝







老師和學生可以是不同的網(wǎng)絡結(jié)構(gòu),比如BERT蒸餾到BiLSTM網(wǎng)絡。但一般相似網(wǎng)絡結(jié)構(gòu),蒸餾效果會更好。 總體loss為 soft_label_loss + hard_label_loss。soft_label_loss可以用KL散度或MSE擬合 soft label為teacher模型的要擬合的對象??梢允悄P皖A測輸出,也可以是embeddings, 或者hidden layer和attention分布。
Teacher 12層,student 6層,每兩層去掉一層。比如student第二層對應teacher第三層 Loss= 5.0 * Lce+2.0 * Lmlm+1.0 * Lcos
Lce:?soft_label 的KL散度 Lmlm:?mask LM hard_label 的交叉熵 Lcos:hidden state 的余弦相似度






三
框架層加速
基于基本的C++編譯器優(yōu)化。 打開編譯器的優(yōu)化選項,選擇O2等加速選項。 小函數(shù)內(nèi)聯(lián),概率大分支優(yōu)先,避免除法,查表空間換時間,函數(shù)參數(shù)不超過4個等。 利用C,而不是C++,C++有不少冗余的東西。 緩存優(yōu)化 小塊內(nèi)存反復使用,提升cache命中率,盡量減少內(nèi)存申請。比如上一層計算完后,接著用作下一層計算。 連續(xù)訪問,內(nèi)存連續(xù)訪問有利于一次同時取數(shù),相近位置cache命中概率更高。比如縱向訪問數(shù)組時,可以考慮轉(zhuǎn)置后變?yōu)闄M向訪問。 對齊訪問,比如224*224的尺寸,補齊為256*224,從而提高緩存命中率。 緩存預取,CPU計算的時候,preload后面的數(shù)據(jù)到cache中。 多線程 為循環(huán)分配線程。 動態(tài)調(diào)度,某個子循環(huán)過慢的時候,調(diào)度一部分循環(huán)到其他線程中。 稀疏化 稀疏索引和存儲方案,采用eigen的sparseMatrix方案。 內(nèi)存復用和提前申請 掃描整個網(wǎng)絡,計算每層網(wǎng)絡內(nèi)存復用的情況下,最低的內(nèi)存消耗。推理剛開始的時候就提前申請好。避免推理過程中反復申請和釋放內(nèi)存,避免推理過程中因為內(nèi)存不足而失敗,復用提升內(nèi)存訪問效率和cache命中率。 ARM NEON指令的使用,和ARM的深度融合。NEON可以單指令多取值(SIMD),感興趣可針對學習,這一塊水也很深。 手工匯編,畢竟機器編譯出來的代碼還是有不少冗余的。可以針對運行頻次特別高的代碼進行手工匯編優(yōu)化。當然如果你匯編功底驚天地泣鬼神的強,也可以全方位手工匯編。 算子支持:比如支持GPU加速,支持定點化等。有時候需要重新開發(fā)端側(cè)的算子。
四
硬件層加速


五
總結(jié)
end
評論
圖片
表情

