Network slimming,一個比較好用的模型剪枝方法

由於深度學習模型大小以及計算資源的限制,導致將深度學習模型部署到如移動端的時候會受到一定的限制,爲了解決這個問題,就形成了一個新的領域:模型壓縮,即減少模型的參數以及計算量,並且依然保證模型的精度。常見的方法比如:量化、剪枝、蒸餾等,本文便是“剪枝”當中一篇非常經典的文章,也是比較有效果的一篇文章。本文方法其實比較簡單:首先,使用L1 regularization對BN層的scaling factor進行稀疏化訓練,然後將scaling factor較小的參數相連接的filter減掉,達到減少模型size的目標。最後再重新finetune剪枝後的網絡,以達到更好的效果。


論文名稱:Learning Efficient Convolutional Networks through Network Slimming

作者: Zhuang Liu & Jianguo Li 等

論文鏈接: https://arxiv.org/abs/1708.06519

github:https://github.com/liuzhuang13/slimming


模型壓縮加速方法介紹

  • Low-rank Decomposition

採用奇異值分解等方法對權重矩陣進行分解,以達到減少矩陣大小的作用,這種方法適用於全連接層,大概可以減少3倍的模型大小,但是對於卷積層,作用不大。

  • Weight Quantization

參數量化,比如將參數量化的int8,或者量化到-1,0,1,可以較大的提升模型的速度,但是這種方法往往較難保證精度,精度一般都會下降。

  • Weight Pruning / Sparsifying

參數剪枝與稀疏化,將不重要的較小的權重置爲0。這就需要矩陣較爲稀疏才能起作用。

  • Structured Pruning / Sparsifying

結構化剪枝就是不單單是對每個參數,而是對網絡結構進行剪枝,比如:channel,neurons,layers等

本文方法:Network Slimming

Advantage of Channel-level Sparsity

首先需要指出的是,稀疏化可以應用在各個level: weight-level, kernel-level, channel-level, layer-level. 其中weight-level的稀疏化程度最高,也可以達到最大的壓縮率,但是在weight-level進行加速,往往需要特殊的軟硬件加速器,來對稀疏的模型進行加速。

與其相反的layer-level,相對比較簡單,不需要特殊的硬件,但是對layer比較多的時候才具有一定的效果,比如50個layer以上,想想可以理解,把50個layer減到40個layer可能還能保留一定的精度。但是10個layer減少到5個layer,差別就比較大了。

相比之下,channel-level就是一種很好的平衡,即不需要特殊的硬件同時還保留了一定的複雜度。

但是channel-level依然具有一定得挑戰,由於channel-level的剪枝會影響到輸入和輸出,這就使得直接在預訓練模型上面將權重減掉是不行的,因爲一般不會存在輸入和輸出都接近0的情況。據統計,一般情況,也就減掉約10%是對精度影響不大的。

如何解決這個問題呢?

本文的方法是引入scale參數γ\gamma,將其作用於每一個channel,與輸出weight相乘,然後在訓練的時候,一起訓練這個γ\gamma參數,並對其增加 正則,使其稀疏化,稀疏化後,將γ\gamma參數較小的值減掉就可以了。

Loss公式表示就是如下:

L=x,yl(f(x,W),y)+λ(g(γ))L = \sum_{x,y}l(f(x,W),y)+\lambda\sum (g(\gamma))

爲了達到稀疏化的效果,這裏g()採用的是L1範數。

整個過程如下圖所示:

在這裏插入圖片描述

引入的scale參數放在哪裏呢?

我們知道BN層在深度網絡中起到了很大的作用,使得網絡可以快速的收斂,而且BN層往往是被插入到conv層的後面的,並且BN也是在channel-level進行計算的,基於此,我們可以直接利用BN層的γ\gamma來當做我們上面設計的參數,對channel進行篩選。

由於對γ\gamma參數加入了L1 正則化,所以訓練過後,該參數會較爲稀疏,所以在訓練後,可以根據閾值,對網絡進行裁剪,將γ\gamma小於閾值的對應channel減掉,就得到了新的網絡。但是這樣得到的網絡大小減少了,自然精度會稍有下降,所以我們需要再對其進行fine-tune操作,恢復期精度,整個流程可以迭代進行如下圖所示:

在這裏插入圖片描述

對BN層增加L1 正則化參數的方法也很簡單,如下代碼可以實現,就是在網絡反向傳播後,對BN層的參數加上其值的sign()就可以了,爲什麼可以這樣做呢?其實按照正常公式推理,需要將增加的BN的loss對參數求導,而由於loss是L1正則,也就是絕對值,所以求導後也就變成了1,-1, 0三個值,所以也就是如下代碼的解釋了。

def updateBN(model):
    for n, m in model.named_modules():
        if isinstance(m, nn.BatchNorm2d):
            m.weight.grad.data.add_(args.s*torch.sign(m.weight.data))  

實驗結果

show幾張圖吧

在這裏插入圖片描述

在這裏插入圖片描述

在這裏插入圖片描述

分析

如下圖是剪枝比例與精度的關係,可以發現,當減值比例超過40%的時候,精度下降非常明顯。但是經過finetune,基本還是可以恢復的,但是到70%以上,恢復的就比較難了。

在這裏插入圖片描述
對於正則化的效果,作者也進行了一定的分析,作者分別對正則化係數進行了分析,分別實驗了0,10e-4,10e-5的結果,結果如下圖所示,可見,隨着係數的增加,BN層的scale參數也越來越接近0,說明稀疏化的作用還是比較明顯的。

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章