CNN推理優化系列之一:Filters pruning
介紹
CNN模型簡化以減少引數數量及增加計算效率可分為兩種主要方法:一類是設計引數更少、所需計算更少的CNN結構像MobileNet/SqueezeNet/ShuffleNet等;另一類則是在常規CNN模型(如VGG/Resnet/Inception v3 etc.)
之上進行引數Quantization,Binarization,以及filters或weights pruning以來減少原生CNN模型所需的引數數目及計算量,從而加快其計算速度,減少模型體積。
Filters pruning屬於上面說的第二類方法。
Filters及相關feature maps pruning
下圖是filters pruning的本質方法。一目瞭然,就是將每一個Weight tensor中不重要的output filters set去掉,並去掉與其相關聯的下一層輸入filters。

Pruning_filters
上述filters pruning方法可歸納為以下四個步驟:
- 對每個Filter F i,j ,計算每個輸入filter set F j 的和(使用L 1 -Norm來計算filter之上weight的絕對值之和),即S j = Σ i (|F i,j |);
- 對上步計算出的S j 進行排序,S j 大小反映了相關filter的重要性;
- 去掉m個權重最小的filters,並同時去掉與其相關的feature maps及下一層的所有相關的輸入filters;
- 在本層(第i層)及下一層(i+1層)上分別新建兩個Kernel weight矩陣,用來存取餘下的filters(注意餘下filters的順序仍然與之前的相同)。
如何確定哪些filters需要被pruning
上面也大致說明了我們是通過計算每組輸入filter之上的L1-norm,然後來將那些具有較小L1-norm值的filters pruning掉。這麼做看似說得過去,畢竟小的引數對最終其輸出影響肯定愈小,所謂人微了自然言輕,
因此在選擇時,忽略掉小人物的聲音而重點聽取大人物的看法確實能對我們正確決策某件事情提供捷徑。
文章中,也有試著在算出所有的filters的L1-norm後pruning掉那些L1-norm值大的filters,或者隨機地裁filters,而不論其L1-norm值大小,不過最終結果卻表明還是如我們經驗所假定的那樣即裁L1-norm最小的
filters,最終所獲得的accuracy loss最小。

使用不同準則進行Filters_pruning所獲得的不同結果對比
每層的filters被pruning多少比較合適呢
顯然這裡無法逃避,我們肯定要有一個meta variable用來表明裁多少filters比較合適,而且最好是layer-wise的一個引數,畢竟每一層上面filters的L1-norm分佈不同,有些層是某些寡頭說了算,實行中央集權制管理,
而有些則是西方民主型,必須得每個filter都發光發熱、建言獻策決定下一層才行。
下圖可表明VGG-16在CIFAR10上訓練得到的模型不同層filters L1-norm分佈及其可被裁filters份量而不過分減少整個模型accuracy loss之間的關係。

VGG16上每層filters_L1-norm分佈及其與可被裁filters數量之間的關係
總結一下那就是不同的layer(模型的不同階段,輸入、輸出feature maps大小不同,網路位置不同)具有迥然不同的filters L1-norm分佈,需要特殊情況特殊處理。
有些Layers上的filters L1-norm分佈非常不均(貧富差距大,大佬說了算),這時我們prun掉那些L1-norm小的filters,對最終的model accuracy影響並不大,有些還反而會有所提升(汗),當然是在pruning後再進行re-training得到的。
而有些layers上的filters L1-norm分佈則非常平均(理想的大同社會嗎?或者是當下日本所謂的橄欖球式社會財富結構?),這時若prun掉其中任意一些filters,都會使得整體模型的accuracy受到影響,有些甚至是大受影響。。

Resnet網路上不同layers所具有的不同pruning敏感度分佈
Okay..
有了以上資訊後,我們的對策如下,(沒錯就是黨一直告訴我們的辦法,不同問題不同解決,實事求是。)
對那些分佈不均的layers狠勁兒裁,反正那些L1-norm小的沒啥用,不值得過多的資源耗在它們身上。
而對分佈均勻的layer則小心裁,甚至不裁。有些layer我們裁了可能對model accuracy loss會有顯著影響,但若影響尚能接受,而且裁後帶來的計算效率明顯提升,那麼我們也可狠心將其裁掉。而有些layer則是硬骨頭,我們稍動下它們,就翻臉無情地
將model accuracy給我們搞到最低,對這些狠角色,我們還是躲著點走好了,少動它們為妙。。
具體pruning時需考慮的策略
單個layer裁減時,我們要考慮是否應該考慮上一層被pruning layer對本layer的影響呢?其實有兩種選擇,要麼考慮,要麼就不考慮。
可由下圖來看得出,無非就是在計算第j個輸出filter set L1-norm S j 時是否考慮上個layer的pruning而已。

兩種計算Filters_pruning權重的策略
另外對於Residual block這種特殊結構,我們同樣要具體問題具體分析。
對於residual模組有多個conv layer的情況,第一個conv layer無所謂,可以正常pruning,而第二個的oc數目多少則需要保證跟identity mapping出來的數目一致,同時也要保證它們裁減相同的filters(不然殘差的表示就無法跟自已本家對得上了。。請
仔細考慮residual learning的含意。。)

Residual_block_pruning
Prun後如何Retrain
共有兩種方式:一種是將整個network的每一層layer都prun後再整體進行re-train;另外一種則是每prun一層layer或者一個stage的layers組合,就進行一輪retrain。
其優點缺點顯而易見,第一種比較省時省力,第二種更加精耕細作,但也麻煩不少。
一般如果一個模型中要裁的layers大多是那種對model accuracy loss不敏感的那麼可以使用第一種方法,不然若想裁得比較多(狠),而且想動那些對accuracy敏感的層,那麼就得使用第二種方法了。
實驗結果
下面為作者使用Resnet56/Resnet-110/VGG16(在CIFAR10上)以及Resnet-34(在Imagenet上)分別使用pruning及re-training後得到的結果。

多模型多資料集組合下pruning後再retrain所獲得的結果
參考文獻
- PRUNING FILTERS FOR EFFICIENT CONVNETS, Hao-Li, 2017