參考目錄:
文章來自微信公眾號【機器學習煉丹術】。我是煉丹兄,如果有疑問或者想要和煉丹兄交流的可以加微信:cyx645016617.
efficientNet的論文原文連結: https://arxiv.org/pdf/1905.11946.pdf
模型擴充套件Model scaling一直以來都是提高卷積神經網路效果的重要方法。
比如說,ResNet可以增加層數從ResNet18擴充套件到ResNet200。這次,我們要介紹的是最新的網路結構——EfficientNet,就是一種標準化的模型擴充套件結果,通過下面的圖,我們可以i只管的體會到EfficientNet b0-b7在ImageNet上的效果:對於ImageNet歷史上的各種網路而言,可以說EfficientNet在效果上實現了碾壓
1 EfficientNet
1.1 概述
一般我們在擴充套件網路的時候,一般通過調成輸入影像的大小、網路的深度和寬度(卷積通道數,也就是channel數)。在EfficientNet之前,沒有研究工作只是針對這三個維度中的某一個維度進行調整,因為沒錢啊!!有限的計算能力,很少有研究對這三個維度進行綜合調整的。
EfficientNet的設想就是能否設計一個標準化的卷積網路擴充套件方法,既可以實現較高的準確率,又可以充分的節省算力資源。因而問題可以描述成,如何平衡解析度、深度和寬度這三個維度,來實現拘拿及網路在效率和準確率上的優化
EfficientNet給出的解決方案是提出了這個模型複合縮放方法 (compound scaling methed)
圖a是一個基線網路,也就是我們所說的baseline,圖b,c,d三個網路分別對該基線網路的寬度、深度、和輸入解析度進行了擴充套件,而最右邊的e圖,就是EfficientNet的主要思想,綜合寬度、深度和解析度對網路進行符合擴充套件。
1.2 把擴充套件問題用數學來描述
首先,我們把整個卷積網路稱為N,他的第i個卷積層可以看作下面的函式對映:
Yi是輸出張量,Xi是輸入張量,假設這個Xi的維度是<Hi,Wi,Ci>(這裡省略了Batch的維度),那麼這個整個卷積網路N,是由k個卷積層組成的,因此可以表示為:
通常情況,一個神經網路會有多個相同的卷積層存在,因此,我們稱多個結構相同的卷積層為一個stage。舉個例子:ResNet可以分為5個stage,每一個stage中的卷積層結構相同(除了第一層為降取樣層),前四個stage都是baseblock,第五個stage是fc層。不太理解的可以看這個:【從零學習PyTorch】 如何殘差網路resnet作為pre-model +程式碼講解+殘差網路resnet是個啥
總之,我們以stage為單位,將上面的卷積網路N改成為:
其中,下表1...s表示stage的訊號,Fi表示對第i層的卷積運算,Li的意思是Fi在第i個stage中有Li個一樣結構的卷積層。<Hi, Wi, Ci>表示第i層輸入的shape。
為了減小搜尋空間,作者先固定了網路的基本結構,而只改變上面公式中的三個縮放維度。還記得之前我們提高的解析度,寬度,深度嗎?
- Li就是深度,Li越大重複的卷積層越多,網路越深;
- Ci就是channel數目,也就是網路的寬度
- Hi和Wi就是圖片的解析度
就算如此,這也有三個引數要調整,搜尋空間也是非常的大,因此EfficientNet的設想是一個卷積網路所有的卷積層必須通過相同的比例常數進行統一擴充套件,這句話的意思是,三個引數乘上常熟倍率。所以個一個模型的擴充套件問題,就用數學語言描述為:
其中,d、w和r分別表示網路深度、寬度和解析度的倍率。這個算式表現為在給定計算記憶體和效率的約束下,如何優化引數d、w和r來實現最好的模型準確率。
1.3 實驗內容
上面問題的難點在於,三個倍率之間是由內在聯絡的,比如更高解析度的圖片就需要更深的網路來增大感受野的捕捉特徵。因此作者做了兩個實驗(實際應該是做了很多的實驗)來說明:
(1) 第一個實驗,對三個維度固定了兩個,只方法其中一個,得到的結果如下:
從左到右分別是隻放大了網路寬度(width,w為放大倍率)、網路深度(depth,d為放大倍率)和影像解析度(resolution, r為放大倍率)。我們可以看到,單個維度的放大最高精度只有80左右,本次實驗,作者得出一個管帶你:三個維度中任一維度的放大都可以帶來精度的提升,但是隨著倍率的越來越大,提升越來越小。
(2)於是作者做了第二個實驗,嘗試在不同的d,r組合下變動w,得到下圖:
從實驗結果來看,最高精度相比之前已經有所提升,突破了80大關。而且組合不同,效果不同。作者又得到了一個觀點:得到了更高的精度以及效率的關鍵是平衡網路的寬度,網路深度,網路解析度三個維度的縮放倍率
1.4 compound scaling method
這時候作者提出了這個方法
EfficientNet的規範化複合調參方法使用了一個複合係數\(\phi\),來對三個引數進行符合調整:
其中的\(\alpha, \beta, \gamma\)都是常數,可以通過網格搜尋獲得。複合係數通過人工調節。考慮到如果網路深度翻番那麼對應的計算量翻番,網路寬度和影像解析度翻番對應的計算量會翻4番,卷積操作的計算量與\(d,w^2 ,r^2\)成正比,。在這個約束下,網路的計算量大約是之前的\(2^\phi\)倍
以上就是EfficientNet的複合擴充套件的方式,但是這僅僅是一種模型擴充套件方式,我們還沒有講到EfficientNet到底是一個什麼樣的網路。
1.5 EfficientNet的基線模型
EfficientNet使用了MobileNet V2中的MBCConv作為模型的主幹網路,同時也是用了SENet中的squeeze and excitation方法對網路結構進行了優化。 MBCConv是mobileNet中的基本結構,關於什麼是MBCconv在百度上很少有解釋,通過閱讀論文和Google這裡有一個比較好的解釋:
The MBConv block is nothing fancy but an Inverted Residual Block (used in MobileNetV2) with a Squeeze and Excite block injected sometimes.
MBCconv就是一個MobileNet的倒殘差模組,但是這個模組中還封裝了Squeeze and Excite的方法。
總之呢,綜合了MBConv和squeeze and excitation方法的EfficientNet-B0的網路結構如下表所示:
對於EfficientNet-B0這樣的一個基線網路,如何使用複合擴充套件發對該網路進行擴充套件呢?這裡主要是分兩步走:還記得這個規劃問題嗎?
(1)第一步,先將複合係數\(\phi\)固定為1,先假設有兩倍以上的計算資源可以用,然後對\(\alpha, \beta, \gamma\)進行網路搜尋。對於EfficientNet-B0網路,在約束條件為
時,\(\alpha, \beta, \gamma\)分別取1.2,1.1和1.15時效果最佳。第二步是固定\(\alpha, \beta, \gamma\),通過複合調整公式對基線網路進行擴充套件,得到B1到B7網路。於是就有了開頭的這一張圖片,EfficientNet在ImageNet上的效果碾壓,而且模型規模比此前的GPipe小了8.4倍。
普通人來訓練和擴充套件EfficientNet實在過於昂貴,所以對於我們來說,最好的方法就是遷移學習,下面我們來看如何用PyTorch來做遷移學習。
2 PyTorch實現
之前也提到了,在torchvision中並沒有加入efficientNet所以這裡我們使用某一位大佬貢獻的API。有一個這樣的檔案Efficient_PyTorch
,裡面存放了b0到b8的預訓練模型儲存檔案,我們將會呼叫這個API。因為這裡我們沒有直接使用pip
進行安裝,所以需要將這個庫函式設定成系統路徑。Pycharm中很多朋友會踩著個坑,不知道如何設定成系統路徑:
點選Sources Root之後,就可以直接import了。
整個程式碼非常少,因為都寫成API介面了嘛:
from efficientnet_pytorch import EfficientNet
model = EfficientNet.from_name('efficientnet-b0')
print(model)
列印的模型可以看,我加了詳細的註解(快誇我):
整個b0的結構和論文中的結構相同:
從上圖中可以知道,總共有16個MBConv模組;在第16個時候的輸出通道為320個通道;
從執行結果來看,結構相同。總之這就是EfficientNet的結構,原理和呼叫方式。