原文連接: http://www.zhiding.cn/techwalker/documents/J9UpWRDfVYHE5ToOGy30k4fU9v9ep3gPUOb3TSAsig算法
本文爲機器之心矽說專欄系列文章之一,對模型壓縮進行了深度解讀。網絡
1. 爲何要爲深度學習模型減肥架構
隨着深度學習的發展,神經網絡模型也愈來愈複雜,經常使用的模型中 VGG 系列網絡的計算量能夠達到 30-40 GOP(1GOP=109 運算)。這些神經網絡一般運行在 GPU 上,可是若是咱們要在移動/嵌入式端也實現深度學習,那麼這樣巨大的模型是絕對跑不動的。移動/嵌入式端的計算能力每每只有桌面級 GPU 的 1/100 到 1/1000,換句話說在 GPU 上一秒 40 幀的深度學習 CV 算法在移動/嵌入式端一秒只有 0.04-0.4 幀,這樣的性能會極大影響用戶體驗。性能
經常使用深度學習網絡運算量學習
在移動/嵌入式端跑深度學習模型,除了運行速度以外,能效比(energy efficiency)也是關鍵指標。能效比指的是一次運算所需消耗的能量,它決定了移動/嵌入式端運行深度學習算法時電池能用多久。能效比與深度學習模型息息相關,咱們下面將會看到深度學習模型的大小會決定運行算法時的片外內存訪問頻率,從而決定了能效比。測試
2. 怎樣的模型才能算「身材苗條」?優化
正如咱們減肥不只要看體重還要看體脂率同樣,爲深度學習模型「減肥」時不只要看模型計算量還要看模型大小。編碼
模型計算量是衡量深度學習是否適合在移動或嵌入式端計算的最重要指標,一般用 GOP 單位來表示。例如,流行的 ResNet-18 的計算量大約是 4 GOP,而 VGG-16 則爲大約 31 GOP。移動和嵌入式端的硬件計算能力有限,所以模型所需的計算量越大,則模型在移動端運行所須要的時間就越長。爲了能讓使用深度學習的應用順暢運行,模型運算量固然是越小越好。除此以外,深度學習每次運算都是須要花費能量的,模型運算量越大則完成一次 inference 須要的能量也就越大,換句話說就是越費電。在電池量有限的移動和嵌入式端,模型一次 inference 所花費的能量必須精打細算,所以深度學習模型計算量不能太大。spa
若是說計算量對模型來講是最簡單直接的「體重」的話,那麼模型大小就是略微有些複雜和微妙的「體脂率」。深度學習模型大小主要決定的是該模型作一次 inference 所須要的能量。那麼模型大小與 inference 所消耗的能量有什麼關係呢?首先,咱們知道,深度學習模型必須儲存在內存裏面,而內存其實還分爲片上內存和片外內存兩種。片上內存就是 SRAM cache,是處理器集成在芯片上用來快速存取重要數據的內存模塊。片上內存會佔據寶貴的芯片面積,所以處理器中集成的片上內存大小一般在 1-10 MB 這個數量級。片外內存則是主板上的 DDR 內存,這種內存能夠作到容量很大(>1 GB),可是其訪問速度較慢。內存
片上內存,離處理器核心電路很近,所以訪問消費的能量很小
片外內存,離處理器很遠,一次訪問須要消耗很大能量
更關鍵的是,訪問片外內存所須要的能量是巨大的。根據 Song Han 在論文中的估計,一次片外內存訪問消耗的能量是一次乘-加法運算的 200 倍,同時也是一次訪問片上內存所需能量的 128 倍。換句話說,一次片外內存訪問至關於作 200 次乘法運算!
固然,具體程序中運算和內存訪問消耗的能量取決於多少次運算須要一次內存存取。嚴格的分析方法是 roof-line model,不過咱們也能夠從 Google 公佈的數據中去估算深度學習模型中運算次數和內存訪問次數的比例。Google 在 TPU 的論文中公佈了這個數據,從中可見 LSTM 模型內存訪問頻率最高,平均 64 或 96 次計算就須要訪問一次內存去取權重(weight)數據;而 CNN 模型的內存訪問頻率相對最低,平均 2888 或 1750 次運算才訪問一次內存取權重。這也很好理解,由於 CNN 充分利用了局部特徵(local feature),其權重數據存在大量複用。再根據以前的計算和內存訪問能量數據,若是全部的權重數據都存儲在片外內存,那麼兩個 CNN 模型計算時運算和內存訪問消耗的能量比是 2:1 和 2.5:1,而在 LSTM0 和 LSTM1 模型計算時運算和內存訪問消耗的能量比是 1:10 和 1:7!也就是說在 LSTM 模型作 inference 的時候,內存訪問消耗的能量佔了絕大部份!
所以,咱們爲了減少能量消耗,必須減小片外內存訪問,或者說咱們須要儘量把模型的權重數據和每層的中間運算結果存儲在片上內存而非片外內存。這也是爲何 Google TPU 使用了高達 28MB 片上內存的緣由。然而,移動端和嵌入式系統使用的芯片不能成本過高,所以片上內存容量頗有限。這樣的話咱們就必須從深度學習模型大小方面想辦法,儘可能減少模型尺寸,讓模型儘量地能存儲在片上內存,或者至少一層網絡的權重數據能夠存在片上內存。
3. 爲模型減肥的幾種方法
2016 年可謂是深度學習模型減肥元年,那一年你們在被深度學習的潛力深深折服的同時開始認真考慮如何在移動硬件上跑深度學習,因而 MIT 的 Viviene Sze 發表了第一款深度學習加速芯片 Eyeriss,Bengio 發表了 Binarized Network,Rastegari 提出了 XOR-Net,Song Han 也發表了 Deep Compression,可謂是百花齊放。爲模型減肥的方法能夠分爲兩大類:第一類是大幅調整模型結構(包括網絡拓撲鏈接,運算等等),直接訓練出一個結構比較苗條的模型;第二類是在已有模型的基礎上小幅修改,一般不涉及從新訓練(模型壓縮)。
Bengio 的 Binarized Neural Network 可謂是第一類模型的先驅者,將神經元 activation 限制爲-1 或 1,從而極大地下降了運算量。Google 也於一個多月前發表的 MobileNet,使用了 depth-wise convolution 來下降運算量以及模型大小。Depthwise convolution 能大幅下降運算量,可是同時不一樣特徵之間的權重參數變成線性相關。理論上減少了自由度,可是因爲深度學習網絡自己就存在冗餘,所以實際測試中性能並無下降不少。MobileNet 的計算量僅爲 1GOP 上下,而模型大小隻有 4MB 多一些,但能在 ImageNet 上實現 90% 左右的 top-5 準確率。在這條路上努力的人也不少,前不久 Face++也發表了 ShuffleNet,做爲 MobileNet 的進一步進化形式也取得了更小尺寸的模型。將來咱們預期會有更多此類網絡誕生。
Google MobileNet 的幾種模型,模型運算量大幅下降的同時 top-5 準確率下降並很少。圖中 1MAC=2OP
第二種方法則是保持原有模型的大致架構,可是經過種種方法進行壓縮而不用從新訓練,即模型壓縮。一種思路就是在數據編碼上想辦法。你們都知道數據在計算機系統中以二進制形式表示,傳統的全精度 32-bit 浮點數能夠覆蓋很是大的數字範圍,可是也很佔內存,同時運算時硬件資源開銷也大。實際上在深度學習運算中可能用不上這麼高的精度,因此最簡單直接的方法就是下降精度,把原來 32-bit 浮點數計算換成 16-bit 浮點數甚至 8-bit 定點數。一方面,把數據的位長減少能夠大大減小模型所需的存儲空間(1KB 能夠存儲 256 個 32-bit 浮點數,但能夠存儲 1024 個 8-bit 定點數),另外一方面低精度的運算單元硬件實現更簡單,也能跑得更快。固然,隨着數據精度降低模型準確率也會隨之降低,因此隨之也產生了許多優化策略,好比說優化編碼(本來的定點數是線性編碼數字之間的間距相等,可是可使用非線性編碼在數字集中的地方使數字間的間距變小增長精度,而在數字較稀疏的地方使數字間距較大。非線性編碼的方法在數字通信重要已經有數十年的應用,8-bit 非線性編碼在合適的場合能夠達到接近 16-bit 線性編碼的精度)等等。業界的大部分人都已經開始使用下降精度的方案,Nvidia 帶頭推廣 16-bit 浮點數以及 8-bit 定點數計算,還推出了 Tensor RT 幫助優化精度。
除了編碼優化以外,另外一個方法是網絡修剪(network pruning)。你們知道在深度學習網絡中的神經元每每是有冗餘的,很多神經元即便拿掉對精度影響也不大。網絡修建就是這樣的技術,在原有模型的基礎上經過觀察神經元的活躍程度,把不活躍的神經元刪除,從而達到下降模型大小減少運算量的效果。
固然,網絡修剪和編碼優化能夠結合起來。Song Han 發表在 2016 年 ICLR 上的 Deep Compression 就同時採用了修剪以及編碼優化的方法,從而實現 35 倍的模型大小壓縮。
Deep Compression 使用的模型壓縮同時使用了網絡修剪和編碼優化
另外,訓練新模型和模型壓縮並不矛盾,徹底能夠作一個 MobileNet 的壓縮版本,從而進一步改善移動端運行 MobileNet 的速度和能效比。
總結
在移動/嵌入式端運行的深度學習網絡模型必須考慮運行速度以及能效比,所以模型的運算量和模型尺寸大小都是越小越好。咱們能夠訓練新的網絡拓撲以減少運算量,也可使用網絡壓縮的辦法改善運行性能,或者同時使用這兩種辦法。針對移動/嵌入式端的深度學習網絡是目前的熱門課題,隨着邊緣計算的逐漸興起預計會有更多精彩的研究出現,讓咱們拭目以待。