轉自:
http://blog.csdn.net/shenxiaolu1984/article/details/51444525
Iandola, Forrest N., et al. “SqueezeNet: AlexNet-level accuracy with 50x fewer parameters and< 1MB model size.” arXiv preprint arXiv:1602.07360 (2016).
本文考察了深度學習中除了精度之外的另一個重要因素:模型大小。有兩處值得學習的亮點:
- 給出了一個分類精度接近AlexNet1的網絡,模型縮小510倍
- 歸納了縮小模型尺寸時的設計思路
複習:卷積層的參數個數。
輸入通道ci。
以AlexNet第一個卷積層爲例,參數量達到:3*11*11*96 = 34848。
作者提供的源碼請戳這裏,各個主流框架均有實現。
基礎模塊
在當下許多深度學習的文章中都使用了模塊化的設計思想,遠者有AlexNet中反覆出現的conv+relu+pool模式;近者有用於人體姿態分析的Stacked Hourglass算法(參看這篇博客)
本文使用的基礎模塊稱爲fire:
包含三個卷積層(藍色),步長均爲1。分爲squeeze和expand兩部分,分別壓縮和擴展數據(灰色矩形)的通道數。
expand部分中,兩個不同核尺寸的結果通過串接層(黃色)合併輸出。
fire模塊有三個可調參數:
- s1: squeeze部分,1×1卷積層的通道數
- e1: expand部分,1×1卷積層的通道數
- e3: expand部分,3×3卷積層的通道數
輸入輸出尺寸相同。輸入通道數不限,輸出通道數爲e1+e3。
在本文提出的SqueezeNet結構中,e1=e3=4s1。
網絡結構
整個網絡包含10層。
第1層爲卷積層(藍色),縮小輸入圖像,提取96維特徵。
第2到9層爲fire模塊(紅色),每個模塊內部先減少通道數(squeeze)再增加通道數(expamd)。每兩個模塊之後,通道數會增加。
在1,4,8層之後加入降採樣的max pooling(綠色),縮小一半尺寸。
第10層又是卷積層(藍色),爲小圖的每個像素預測1000類分類得分。
最後用一個全圖average pooling(綠色)得到這張圖的1000類得分,使用softmax函數歸一化爲概率。
這是一個全卷積網絡,避免瞭如今越來越不受待見的全連接層。由於最後一層提供了全圖求平均操作,可以接受任意尺寸的輸入。當然,輸入還是需要歸一化到大致相當的尺寸,保持統一尺度。
全連接層的參數多,對性能提升幫助不大,現在往往被pooling代替。
這個網絡達到了和AlexNet相當的分類精度,但模型縮小了50倍:
architecture | model size | top-1 accuracy | top-5 accuracy |
---|---|---|---|
AlexNet | 240MB | 57.2% | 80.3% |
SqueezeNet | 4.8MB | 57.5% | 80.3% |
參數壓縮
在網絡結構確定的前提下,還可以進一步壓縮其中的參數。本文使用了第二作者的Deep Compression2方法,包含裁剪,量化,編碼三個手段。
AlexNet中卷積層的weight、bias以及全連層參數分佈如下所示。可以看出:全連層參數和卷積層weight佔絕大多數,卷積層的bias只佔極小部分。
參數壓縮針對卷積層的weight和全連層參數。每一層的參數單獨壓縮。
裁剪
由前圖可以看出,絕大部分參數集中在0附近。
裁剪操作的第一步,把網絡中所有絕對值小於門限的參數置0;非零參數再次訓練進行優化。
第二步,用下標方法表示剩餘的參數:記錄非零參數值和其在數組中的下標。
論文聲稱使用compressed sparse row方法進行壓縮,實際源碼中並沒有。
下標中相鄰元素差值不會超過數組長度。爲了進一步壓縮,把下標表示成差分形式。
例:稀疏矩陣
⎡⎣⎢⎢⎢0500080600300000⎤⎦⎥⎥⎥\begin{bmatrix} 0 & 0 & 0 & 0 \\ 5 & 8 & 0 & 0 \\ 0 & 0 & 3 & 0 \\A = [ 5 8 3 6 ], IA = [4 5 10 13]
差分形式:IA = [4 1 5 3]
差分形式的IA動態範圍大大縮小,可以用較少的比特數(4)進行編碼。
當差值超出當前比特數能表示的範圍後,在中間插入一個值爲0的“非零元素”。
量化(Quantization)
首先,用K均值把所有參數聚成2n個類。
之後,保持同一聚類內參數相等,對網絡進行調優。在梯度下降時,歸於同一類的節點的梯度相加,施加到該類的聚類中心上。
最後,使用n比特編碼的聚類中心替代原有參數。
Deep Compression論文:卷積層,n=8; fc層,n=4。SqueezeNet中全部爲卷積層,n=6。
問題:同類節點的梯度爲什麼相加?不是應該求平均嗎?
編碼(Huffman Encoding)
現在需要存儲的主要數據有二:編碼爲n位的非零數據取值;編碼爲4位的非零元素下標。
這兩者的分佈都不均勻,可以使用Huffman編碼進一步壓縮存儲。源碼中沒有實現。
模型存儲結構
壓縮後的二進制模型按層存儲,當前層有nz個非零元素,分爲如下4個部分:
name | type | size | note |
---|---|---|---|
codebook | float32 | 2^n | 碼書 |
bias | float32 | 輸出通道數 | 無壓縮 |
spm_stream | uint8 | nz−18/n+1 | 非零元素取值,n位編碼$ |
ind_stream | uint8 | nz−18/4+1 | 非零元素下標,4位編碼$ |
經過Deep Compression壓縮,模型進一步縮小了10倍,仍然保持原有精度。
architecture | model size | top-1 accuracy | top-5 accuracy |
---|---|---|---|
AlexNet | 240MB | 57.2% | 80.3% |
SqueezeNet | 4.8MB | 57.5% | 80.3% |
SqueezeNet+DeepCompression | 0.66MB | 57.5% | 80.3% |
設計思路
本文還花費較大篇幅介紹了設計網絡時的心得體會,頗具啓發性。
參數組合
每層fire模塊的三個參數如果單獨設計,需要嘗試的組合太多。需要使用超參數進行規劃:
- 首個fire模塊中包含base個3×3核;每隔freq個fire模塊,3×3模塊增加incre個。
- expand部分中,3×3核佔expand中核總數比例爲pct。
- squeeze中核數與expand中核數比例爲sr。
sr和pct增大可以提升準確率,但模型尺寸增大。本文取sr=0.125,pct=0.5。
大尺度結構
在通道數相同的層之間,添加旁路相加結構可以明顯提升準確性(源碼未實現)。
帶有卷積的旁路結構可以在任意層之間添加,準確性提升較小,模型增大。
壓縮:有的放矢
問:如何確定哪些層不重要?
答:逐個將每一層50%參數置零,查看模型性能。對性能影響不大的層,不重要。
問:不重要的怎麼辦?
答:Deep Compression中使用較少比特數表達。
問:重要的層呢?
答:增加expand部分中的輸出通道數,進一步提升準確率。
SDS訓練法
本文還有一個神奇的發現:使用裁剪之後的模型爲初始值,再次進行訓練調優所有參數,正確率能夠提升4.3%。
稀疏相當於一種正則化,有機會把解從局部極小中解放出來。這種方法稱爲DSD(dense->sparse->dense)。