李宏毅-Network Compression課程筆記


一、方法總結

  • Network Pruning
  • Knowledge Distillation
  • Parameter Quantization
  • Architecture Design
  • Dynamic Computation

二、Network Pruning

模型通常是過參數的,即很多參數或者neuron是冗余的(例如非常接近0),因此我們可以移除這些參數來對模型進行壓縮。

1. 重要性判斷

那么怎么判斷哪些參數是冗余或者不重要的呢?

  • 對權重(weight)而言,我們可以通過計算它的l1,l2值來判斷重要程度
  • 對neuron而言,我們可以給出一定的數據集,然后查看在計算這些數據集的過程中neuron參數為0的次數,如果次數過多,則說明該neuron對數據的預測結果並沒有起到什么作用,因此可以去除。

2. 為什么要pruning?

那我們不禁要問,既然最后要得到一個小的network,那為什么不直接在數據集上訓練小的模型,而是先訓練大模型?

  • 解釋一

一個比較普遍接受的解釋是因為模型越大,越容易在數據集上找到一個局部最優解,而小模型比較難訓練,有時甚至無法收斂。

  • 解釋二

2018年的一個發表在ICLR的大樂透假設(Lottery Ticket Hypothesis)觀察到下面的現象:

首先看最左邊的網絡,它表示大模型,我們隨機初始化它權重參數(紅色)。然后我們訓練這個大模型得到訓練后的模型以及權重參數(紫色)。最后我們對訓練好的大模型做pruning得到小模型。

下面就是見鬼的時刻,作者把小模型拿出來后隨機初始化參數(綠色,右上角),結果發現根本無法訓練。然后他又把最開始的大模型的隨機初始化的權重復制到小模型上(即把對應位置的權重參數復制過來,右下角),結果發現正常訓練!!!

作者對此的解釋是,就像我們買彩票,買的彩票越多,中獎的幾率才會越大。而最開始的大模型可以看成是由超級多的小模型組成的,也就是對大模型隨機初始化參數會得到各種各樣的初始化參數的小模型,有的小模型可能根本就無法訓練,但是有的就可以,所以上圖中右下角的小模型套用大模型對應位置的初始化參數,其實就是使用了“中獎”了的那個部分的參數。

BUT!!!后面有一篇文章Rethinking the value of network pruning做了實驗發現隨機初始化是可以正常訓練的,即他的結論和前面大大樂透假設有違背。。。emm,大佬之間大家我們還是做個吃瓜群眾吧。

3. 實際操作分析

前面提到模型pruning可以從weight和neuron兩個角度進行,下面就分別介紹實際可操作性:

  • weight pruning

image.png

如上圖示,每個節點的輸出和輸出節點數都會變得不規則,這樣一來有兩個方面的問題:

  • 使用Pytorch,Keras實現起來不方便
  • GPU是對矩陣運算做加速,現在都變得不規則,看起來似乎GPU面對這種情況也無能為力。2016年的一篇文章對AlexNet就做了這樣的實驗,實驗結果是模型參數去掉了將近90%,最后的准確率只降低了2%左右,說明weight pruning的確能夠在保證模型准確率的同時減少了模型大小,but!!!最后實驗發現模型計算的速度似乎並沒有提速,甚至對有的結構的修改使得速度降低了。

image.png

  • neuron pruning

如下面示意圖所示,刪減neuron之后網絡結構能夠保持一定的規則,實現起來方便,而且也能起到一定的加速作用

image.png

三、Knowledge Distillation

直接看下面的圖應該很好理解。整個知識蒸餾過程中會用到兩個模型:大模型(Teacher Net)和小模型(Student Net)。

具體方法是我們先用大模型在數據集上學習到收斂,並且這個大模型要學的還不錯,因為后面我們要用大模型當老師來教小模型學習嘛,如果大模型本身都沒學好還教個錘子,對吧?

我們以MNIST數據集為例,假設大模型訓練好了,現在對於一張數字為“1”的圖像,大模型的輸出結果是由0.7的概率是1,0.2的概率是7,0.1的概率是9,這是不是有一定的道理?相比如傳統的one-hot格式的label信息,這樣的label包含更多的信息,所以Student Net要做的事情就是對於這張數字為“1”的圖像,它的輸出結果也要盡量接近Teacher Net的預測結果。

image.png

當然,一個更騷氣的辦法就是讓多個老師出謀划策來教學生,即用Ensemble Net來進一步提升預測准確率,讓學生學習的知識更加准確。

image.png

那Student Net到底如何學習呢?首先回顧一下在多類別分類任務中,我們用到的是softmax來計算最終的概率,即

\[y_{i}=\frac{\exp \left(x_{i}\right)}{\sum_{j} \exp \left(x_{j}\right)} \]

但是這樣有一個缺點,因為使用了指數函數,如果在使用softmax之前的預測值是\(x1=100,x2=10,x3=1\),那么使用softmax之后三者對應的概率接近於\(y1=1,y2=0,y3=0\),那這和常規的label無異了,所以為了解決這個問題就引入了一個新的參數\(T\),稱之為Temperature,即有:

\[y_{i}=\frac{\exp \left(x_{i} / T\right)}{\sum_{j} \exp \left(x_{j} / T\right)} \]

此時,如果我們令\(T=100\),那么最后的預測概率是$y1=0.56,y2=0.23,y3=0.21。(不過李宏毅老師在視頻里提到說這個方法在實際使用時貌似用處不大hhhh,感覺這個方法可以回答知乎上的 什么東西看起來很厲害但是沒什么用? 哈哈哈哈哈哈哈哈哈哈或或)

四、Parameter Quantization

1. less bits

一個很直觀的方法就是使用更少bit來存儲數值,例如一般默認是32位,那我們可以用16或者8位來存數據。

2. weight clustering

如下圖所示,最左邊表示網絡中正常權重矩陣,之后我們對這個權重參數做聚類,比如最后得到了4個聚類,那么為了表示這4個聚類我們只需要2個bit,即用00,01,10,11來表示不同聚類。之后每個聚類的值就用均值來表示。這樣的一個缺點就是誤差可能會比較大。

image.png

3. Huffman Encoding

思路很簡單,以上面的圖為例,就是對於常出現的聚類用少一點的bit來表示,而那些很少出現的聚類就用多一點的bit來表示。

4. Binary Weights

Binary Weights是以一種更加極致的思路來對模型進行壓縮,即每個節點只有1或-1來表示。比較具有代表性的論文如下:

下面簡單介紹一下Binary Connect的思路,如下圖示,灰色節點表示使用binary weight的神經元,藍色節點可以是隨機初始化的參數,也可以是真實的權重參數。

第一步我們先計算出和藍色節點最接近的二元節點,並計算出其梯度方向(紅色剪頭)。

image.png

第二步,藍色節點的更新方向則是按照紅色箭頭方向更新,而不是按照他自身的梯度方向更新。如下圖示,梯度下降后,藍色節點到了一個新的位置。

image.png

最后在滿足一定條件后(例如訓練之最大epoch),藍色節點會停在一個灰色節點附近,那么我們就是用該灰色節點的權重。

image.png

五、Architecture Design

1. Low Rank Approximation(低秩近似)

下圖是低秩近似的簡單示意圖,左邊是一個普通的全連接層,可以看到權重矩陣大小為\(M\times N\),而低秩近似的原理就是在兩個全連接層之間再插入一層K。是不是很反直觀?插入一層后,參數還能變少?

沒錯,的確變少了,我們可以看看新插入一層后的參數數量為:\(N\times K+K\times M=K\times (M+N)\),因為\(K<M,K<N\),所以參數減少了。

image.png

但是低秩近似之所以叫低秩,是因為原來的矩陣的秩最大可能是\(min{(M,N)}\),而新增一層后可以看到矩陣\(U\)\(V\)的秩都是小於等於\(K\)的,我們知道\(rank(AB)≤min(rank(A),rank(B))\), 所以相乘之后的矩陣的秩一定還是小於等於\(K\)。那么這樣會帶來什么影響呢?那就是原先全連接層能表示更大的空間,而現在只能表示小一些的空間了。

2. Depthwise Separable Convolution

首先看一下標准卷積所需要的參數量。如下圖示,輸入數據由兩個6*\6的feature map組成,之后用4個大小為3*3的卷積核做卷積,最后的輸出特征圖大小為4*4*4。每個卷積核參數數量為2*3*3=18,所以總共用到的參數數量為4*18=72。

image.png

而Depthwise Separable卷積分成了兩步,如下圖示。

首先是輸入數據的每個通道只由一個二維的卷積核負責,即卷積核通道數固定為1,而不是像上面那樣,每個卷積核的通道數和輸入通道數保持一致。這樣最后得到的輸出特征圖的通道數等於輸入通道數。

因為第一步得到的輸出特征圖是用不同卷積核計算得到的,所以不同通道之間是獨立的,因此我們還需要對不同通道之間進行關聯。為了實現關聯,在第二步中使用了1*1大小的卷積核,通道數量等於輸入數據的通道數量。另外1*1卷積核的數量等於預期輸出特征圖的通道數,在這里等於4。最后我們可以得到和標准卷積一樣的效果,而且參數數量更少:3*3*2+(1*1*2)*4=26。

下面我們算一下標准卷積和Depthwise Separable卷積參數數量大小關系:假設輸入特征圖通道數為\(I\),輸出特征圖通道數為\(O\),卷積核大小為\(k\times k\)

標准卷積參數數量=\(k\times k\times I\times O\)
Depthwise Separable卷積參數數量=\(k\times k\times I+I\times O\)
因為通常輸出特征圖的通道數\(O\)會設置的比較大,所以可以看到Depthwise Separable卷積的參數量會明顯少於標准卷積。

image.png

這樣的卷積設計廣泛運用在各種小網絡上,如SqueezeNet,MobileNet,ShuffleNet,Xception

六、Dynamic Computation

該方法的主要思路是如果目前的資源充足(比如你的手機電量充足),那么算法就盡量做到最好,比如訓練更久,或者訓練更多模型等;反之,如果當前資源不夠(如電量只剩10%),那么就先算出一個過得去的結果。

那么如何實現呢?

1. 訓練更多的model

比如說我們提前訓練多種網絡,比如大網絡,中等網絡和小網絡,那么我們就可以根據資源情況來選擇不同的網絡。但是這樣的缺點是我們需要保存多個模型,這在移動設備上的可操作性不高。

2. 使用中間層輸出結果

這樣的思路其實也挺直觀的,就是比如說我們做分類任務,當資源有限時,我們可能只是基於前面幾層提取到的特征做分類預測,但是一般而言這樣得到的結果會打折扣,因為前面提取到的特征是比較細膩度的,可能只是一些紋理,而不是比較高層次抽象的特征。

左下角的圖表就展示了不同中間層的結果比較,可以看到越靠近輸入,預測結果越差。

右下角的圖則展示了在不同中間層插入分類器對於模型訓練的影響,可以看到越靠近輸入層插入分類器,對模型的影響越大。其實也很好理解,因為一般而言,前面的網絡結構負責提取淺層的特征,但是當我們在前面就插入分類器后,那么分類器為了得到較好的預測結果會強迫前面的網絡結構提取一些抽象的特征,進而擾亂了后面特征的提取。具體的分析可以閱讀這篇文章Multi-Scale Dense Networks for Resource Efficient Image Classification

image.png



MARSGGBO原創
如有意合作或學術討論歡迎私戳聯系~
微信:marsggbo
郵箱:marsggbo@foxmail.com



2019-12-21 22:45:38




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM