我很長一段時間一直都在作自動駕駛的物體檢測性能調優,因此想總結整理一些小網絡和檢測框架的經驗。git
文章會分紅三個部分:github
第一部分將參照知乎@YaqiLYU 對小網絡(經典網絡)的分析而且結合的本身的理解。算法
第二部分詳細介紹目前state-of-art的主流檢測框架。網絡
第三部分介紹了目標檢測的問題及解決方案,目標檢測在其餘領域的拓展應用 架構
---------------------------------------------------------------------------------------------------------------------------框架
第一部分 經典小網絡性能分析ide
---------------------------------------------------------------------------------------------函數
對於早期經典模型SqueezeNet, MobileNet(V1), 和CVPR 2018最新模型ShuffleNet, IGCV2, MobileNetV2, 探究短小精悍的祕密,學習設計理念和技術。性能
問題:學習
經過一張ncnn框架的高端ARM高通820和低端ARM海思3519硬件實測速度對比。ImageNet上的top-1準確率 vs 理論計算量 vs 模型大小的對比提出
1 MobileNetV2到底優化了什麼,能作到比MobileNetV1既好又快?
2 爲何理論計算很高的SqueezeNet反而很是快?爲何ShuffleNet要比架構技術接近的MobileNetV1和MobileNetV2快那麼多?
背景介紹:
首先介紹CNN中不一樣層的參數數量和理論計算量,簡單起見小寫表明下標,卷積核Kh*Kw,輸入通道數Cin,輸出通道數Cout,輸出特徵圖的分辨率爲寬H高W。
參數數量:用params表示,關係到模型大小,單位一般爲M,一般參數用float32表示,因此模型大小是參數數量的4倍。
理論計算量:用FLOPs或者M-Adds表示,這裏用FLOPs寫起來簡單,關係到算法速度,大模型的單位一般爲G,小模型通道爲M。注意兩點:
CONV標準卷積層:
FC全鏈接層,卷積核k=1:
CONV和FC是經典CNN架構(如VGGNet和ResNet)中最重要的組件,CONV通常位於前面,做用相似特徵提取,FC位於後面,做用相似分類決策。咱們還須要兩個卷積的變種。
首先在比較流行的高效卷積核(GCONV和DWCONV)上作個對比
GCONV分組(Group)卷積層,輸入按通道數劃分爲g組,每小組獨立分別卷積,結果聯結到一塊兒做爲輸出,如圖中上面部分,Output channels做爲GCONV的輸入,分了3組分別CONV3x3,組內有信息流通,但不一樣分組之間沒有信息流通。
(Xception版本)DWCONV深度分離(DepthWise)卷積層,是GCONV的極端狀況,分組數量等於輸入通道數量,即每一個通道做爲一個小組分別進行卷積,結果聯結做爲輸出,Cin = Cout = g,沒有bias項,如圖中上面部分,Output channels做爲DWCONV的輸入,劃分了輸入通道數量相等的分組,通道之間徹底沒有信息流通。
綜合對比:
Block分析:設計CNN目前都採用堆block的方式,後面對每一個模型只集中分析其block的設計。堆Block簡化了網絡設計問題:只要設計好block結構,對於典型224x224輸入,設計CNN只須要考慮112x1十二、56x5六、28x2八、14x1四、7x7 這5個分辨率階段(stage)的block數量和通道數量就能夠了。
CNN加深度通常都選擇14x14這個分辨率階段,多堆幾個block,這一層的參數數量和計算量佔比最大,因此咱們選這一層做爲特例分析每種block的參數數量和計算量,量化說明選擇14x14x該層通道數的輸入和輸出狀況。
傳統網絡分析:
NIN(net in network)
最先的的小網絡要從Network in Network提及,NiN是Shuicheng Yan組ICLR 2014的論文,提出在CONV3x3中插入CONV1x1層,和Global Average Pooling (GAP)層,雖然論文並無強調這兩個組件對減少CNN體積的做用,但它們確實成爲CNN壓縮加速的核心:
GoogLeNet
就大量使用層和GAP,與同時期性能相近的VGG-19相比,22層GoogLeNet模型參數少20倍以上,速度快10倍以上。GoogLeNet是最先的高效小網絡,Inception系列沿襲這一架構理念,在均衡網絡深度和模型大小方面都比較優秀。
(提問:截止2018.5.27,VGGNet論文的引用量是11499,GoogLeNet的應用量是7440次,同一時期的兩個經典結構,看起來明顯更好的GoogLeNet影響力爲什麼反而不如VGGNet?早期檢測、跟蹤和分割等方向的經典方法,如SSD, C-COT, FCN,骨架網絡BackBone默認都是VGGNet,爲何都沒有選更小更快的GoogLeNet?)
(模型的推理速度也就是計算量其實不只僅和參數量有關,計算次數,還和MAC內存帶寬的交互,以及GPU的底層支持的友好程度都相關,再其次更深的網絡在imagenet上的訓練效果會更好一些)
Resnet:
除了conv1*1 和GAP,ResNet還採用了另外一項經常使用技術:
綜合以上技術,即便152層的ResNet,也比VGGNet小7倍,快12倍以上。目標檢測的YOLO系列中,YOLOv2中提出的DarkNet-19採用了CONV1x1和GAP設計,YOLOv3的DarkNet-53加入了CONV/s2設計,兩個CNN都是以上壓縮加速技術的實例。
SqueezeNet
論文很是的標題黨:同等精度比AlexNet小50倍,<0.5M的模型大小。SqueezeNet的核心設計理念是模型能夠不快但必定要小,分析三個設計策略:
此外,保證conv10的通道數是1000,這樣GAP後直接是1000個輸出,這樣鏈接到輸出的最後一個FC層也省了,僅0.5M參數就完成了收尾部分,簡直喪心病狂,但這種作法很是低效,僅conv10這一層的計算量就有100M。
SqueezeNet共8個Fire Module,2個CONV和4個POOL,沒有BN,最終模型4.8M,在ImageNet上top-1 acc 57.5%, top-5 acc 80.3%,性能是AlexNet水平,通過DeepCompression進一步壓縮後模型大小能夠達到逆天的0.47M,但DeepCompression方法也是僅關心壓縮不關心加速的。最後實驗還測試了shotcut,證實相似ResNet那樣最簡單的shotcut最好,top-1和top-5分別提高2.9%和2.2%,性能提高明顯且不會增長參數數量,幾乎不會影響計算量 (ResNet賽高)
論文描述的模型是SqueezeNet v1.0,後來代碼又更新了SqueezeNet v1.1,模型大小和性能不變的狀況下快了2.4倍:
主要修改了第一層的卷積核大小和通道數,把下采樣提早了,即拋棄了策略3。
SqueezeNet的計算量在MobileNet論文中是1700M,在ShuffleNet論文中是833,根據最新論文結果,SqueezeNet v1.0的理論計算量是837M,SqueezeNet v1.1的理論計算量是352M,ncnn-benchmark中所用測試模型就是SqueezeNet v1.1,因此在benchmark中SqueezeNet確實應該比MobileNet和AlexNet快。
stage的通道數量:【128 256 384-512 0】
stage的block數量:【2 2 4 0】
Block分析:加shotcut的一個典型SqueezeNet block,即論文中的Fire module
第一個CONV1x1將輸入通道數壓縮(squeeze)到1/8送給CONV3x3,上下兩路CONV擴展(expand)四倍後聯結,還原輸入通道數量。block中CONV1x1和CONV3x3的參數數量之比是1:3,計算量之比也是1:3。
SqueezeNet中雖然大量使用CONV1x1,但CONV3x3佔比依然在75%以上,inferece framework中CONV3x3的優化對速度影響更大。
在part2 中會介紹做者最新的SqueezeDet
MobileNet
MobileNet是第一個面向移動端的小網絡,設計兼顧模型小和速度快,提出了Depthwise Separable Convolution深度分離卷積,由DWCONV3x3 + CONV1x1組成,DWCONV3x3將CONV3x3的計算量下降到恐怖程度,後面的CONV1x1幫助信息在通道之間流通。這種結構很是高效,代替CONV後性能微小降低換取速度數倍提高。
MobileNet參數數量4.2M,計算量569M,top-1 70.6%,性能是GoogLeNet和VGG16水平,比最龐大的VGG16模型小32倍,計算量低27倍,比設計高效的GoogLeNet模型更小,計算量低2.5倍。
第一層是CONV,以後堆疊DWCONV3x3 + CONV1x1, 每層都加BN沒有shotcut,DWCONV/S2方式下采樣,GAP後連FC到1000個分類輸出,僅這個1024-1000的FC層就有1M參數。
論文提供了兩個用戶定製參數:
減小網絡的層數也能夠減小模型大小和計算量,即CNN變淺,實驗給出同等參數和計算量,變淺比邊瘦性能要差不少,強烈建議不要減深度!
(提問:不少論文都證實,同等參數和計算量,深度模型比寬度模型更好,深度也是一種正則方式?)
論文統計了不一樣類型層的計算量和參數數量,僅一個CONV一個FC,計算量能夠忽略,前面也提到FC層參數佔比較大,重點關注,大量使用的DWCONV33計算量僅3%,參數數量僅1%,其貌不揚的CONV1x1居然是罪魁禍首,CONV1x1計算量佔95%,參數數量佔75%,因此MobileNet速度快不快,與inferece framework中CONV1x1的優化程度密切相關(實際上是由於depthwise的3*3卷積只計算一次,而pointwise層會瘋狂的計算Cout次和sequeezenet 不一樣,seq雖然1*1卷積核不少,但本質仍是因爲3*3與1*1的佔比所致使)。
Block分析:MobileNet雖然沒有明確指出,Depthwise Separable Convolution也能夠看作block
DWCONV3x3以極低代價卷積產生特徵,CONV1x1輔助通道信息流通,二者完美配合。block中CONV1x1和DWCONV3x3的計算量、參數數量比例是C:9,以瘋狂加深度層14x14x512爲例,兩者比例是512:9=56.89,依然很震驚有木有,SqueezeNet中核心壓縮加速手段CONV1x1,在MobileNet中反倒成了開銷大戶。
進一步優化MobileNet,下降CONV1x1的佔比是關鍵,在mobilenetV2中針對於conv1*1的佔比進行了優化。
MobileNet的結構是相似VGGNet的直筒形式,目前ResNet已經取代了VGGNet,咱們是否是按照ResNet中比較高效的bottleneck block構建更先進的DWCONV-bottleneck block呢?固然很簡單,按照ResNet論文,CONV3x3換成DWCONV3x3就完成了。
ResNet代替VGGNet的歷史告訴咱們,這樣作必定比MobileNet更好,要試一試嗎?彆着急,仔細看參數數量和計算量都增長了數倍(約8倍),block中CONV1x1和DWCONV3x3的計算量、參數數量比例是8C:9,仍是以深度層14x14x512爲例,兩者比例高達8*512:9=455.11,再次震驚,這樣作性能是上去了,但模型大小和速度都嚴重降低了,對於移動端這是咱們最不肯看到的結果。
ShuffleNet
繼MobileNet掛出來以後三個月,曠世科技掛出了ShuffleNet:解決了DWCONV-bottleneck block中CONV1x1佔比高、計算量大的問題;可是並無開源代碼。
相似DWCONV-bottleneck block中DWCONV3x3代替CONV3x3,其中的CONV1x1是標準卷積,這部分是否也能經過分組卷積或深度分離卷積來加速壓縮呢?ShuffleNet第一步就是把block中的CONV1x1變成了分組卷積GCONV1x1下降計算量和參數數量,按照分組數量(g=2,3,4,8)加速g倍。但這帶來一個很嚴重的問題,通道之間信息不能流通:DWCONV3x3沒有通道間信息流通,而GCONV1x1信息只在分組內部流通,會嚴重影響性能。ShuffleNet給出解決方案,就是題目中'Shuffle'表明的Channel Shuffle操做,交錯重排,混疊通道以輔助(強制)信息流通。
從理論計算量的公式能夠看出,feature map的分辨率對計算量影響很是大,因此通常CNN結構都有輸入圖像快速降維模塊,經常使用CONV3x3s2+CONV3x3s2階梯降維,或CONV7x7s2 + MaxPools2,實現輸入圖像快速降維4倍。在ShuffleNet中採用了很是很是激進的CONV3x3s2 + MaxPools2結構,雖然這樣參數更少速度更快,但CONV3x3的感覺野不足以支撐4倍降維,會形成信息丟失(猜想這多是ShuffleNet難以復現的緣由之一)。
ShuffleNet發現深度分離卷積雖然參數數量和計算量都很低,但與其餘密集操做相比計算/內存訪問比不好,在實際硬件上較難優化,因此採用了大量GCONV1x1加少許DWCONV3x3的設計方式,後面MobileNetV2中會看到大相徑庭的處理方式。
分組數量g越大,對應壓縮加速比率越大,論文增長通道數量以保持不一樣g設置的計算量接近,公平對比性能;用戶定製參數僅通道乘子s,壓縮加速 倍。經常使用兩個版本是ShuffleNetx1g8和ShuffleNetx2g3:
(提問:還有哪些相似SE的「黑科技」,能在基本保持理論計算量不變的狀況下能大幅提高性能,表面上看起來很是「便宜」,但實際上大幅下降了部署速度)
ncnn-benchmark中ShuffleNet是x1g8版本,理論計算量140,固然比理論計算量352M的SqueezeNet v1.1和理論計算量569M的MobileNet更快。
爲保持公平比較,接下來分析x2g3版本:
每一個stage的通道數量:【0 480 960 1920】
每一個stage的block數量:【0 4 8 4】
Block分析:shuffle block即論文中的ShuffleNet Unit,非stride=2版本
block中CONV1x1和DWCONV3x3的計算量、參數數量比例是8/3C:9,以深度層14x14x960 (c=240)爲例,兩者比例8/3*240:9=71.11,比DWCONV-bottleneck block中的455.11,GCONV1x1依然是主力但佔比已經下降不少不少了。與MobileNet相比,DWCONV3x3的通道數少了不少(猜想是難以復現的緣由之二),但GCONV1x1通道數多了不少,因此上面4C-C-C4的通道數表示不必定客觀。
其餘須要注意的:ShuffleNet Unit中,僅第一個GCONV1x1後面加了Channel Shuffle,DWCONV3x3後面沒有ReLU,stride=2版本用聯結輸入AVGPools2的方式實現通道翻倍。
(HELP:有能完美復現CVPR版本ShuffleNet論文結果的同窗,歡迎慷慨分享你的模型和訓練方式,功德無量!)
看到這個不少同窗第一時間都會想:這個和Channel Shuffle好像啊,並且是今年4月才掛出來。。其核心部分的交錯分組卷積Interleaved Group Convolutions發表在ICCV 2017,因此是ShuffleNet同時期的工做(或更早)。交錯分組卷積IGC,把CONV1x1變成分組卷積,而後加上交錯重排操做Permutation,做用相似Channel Shuffle。
IGCV2在MobileNet的基礎上改進,兩個GCONV1x1中間加Permutation,分組數量g=8,每層的通道數量都翻倍,這樣參數數量和計算量都基本保持不變(更胖)。IGCV2和MobileNet對比,1.0版本的參數、計算量和性能都很是類似,但0.5和0.25版本IGCV2優點很是明顯。
每一個stage的通道數量:【256 512 1024 2048】
每一個stage的block數量:【2 2 6 2】
Block分析:IGCV2 block,相似MobileNet沒有加shotcut
block中CONV1x1和DWCONV3x3的計算量、參數數量比例是1/4C:9,以深度層14x14x1024爲例,兩者比例1/4*1024:9=28.44,比MobileNet block中的56.89的佔比下降。網絡設計方面,IGCV2只在MobileNet的基礎上改進,驗證了IGC的可行性,沒有太大的結構變更。
下降DWCONV-bottleneck block中CONV1x1的佔比,除了ShuffleNet和IGCV2用GCONV+shuffle/permutation方法,還有其餘好辦法嗎?MobileNet採用了兩種新技術來解決這個問題,按照論文來講:
沒有分組卷積,那MobileNetV2到底優化了什麼?觀察網絡發現,bottleneck的輸出通道數很是小[24 32 64-96 160-320],這在之前的結構中容量是遠遠不夠的。再來看經expand layer擴展之後的DWCONV3x3層,baseline版本通道數是[144 192 384-576 960-1920],比較接近ShuffleNetx2的配置,略高於V1,從這個角度來看,MobileNetV2設計上是保持DWCONV3x3層通道數基本不變或輕微增長,將bottleneck的輸入和輸出通道數直接減少t倍,擴展因子其實更像是壓縮因子,將CONV1x1層的參數數量和計算量直接減少t倍,輕微增長DWCONV3x3的通道數以保證的網絡容量。ShuffleNet中標準卷積更多、深度分離卷積更少的優化思路徹底相反,MobileNetV2中標準卷積更少、深度分離卷積更多(相對的,計算量佔比CONV1x1依然絕對優點)。
(舒適提示:因爲論文arXiv初版有幾處筆誤,致使以前github上覆現的模型結構都或多或少有錯誤,請仔細對照tensorflow官方代碼和模型結構。好比:
發現第一個t=1的bottleneck結構其實是dwconv3x3-conv1x1,沒有前面expansion layer的conv1x1,對照代碼驗證確實如此)
結構方面,每一個bottleneck裏面兩個ReLU6,方便量化;輸入圖像以s2方式逐階平滑降維;用戶定製依然是寬度乘子和分辨率乘子,同MobileNetV1;通道數量分佈前期少後期多,在14x14和7x7階段通道數量額外增長了一次,分別上升50%和100%。
ncnn-benchmark中MobileNetV2是caffe復現的baseline,但因爲標準卷積比深度分離卷積優化更好,且CONV3x3比CONV1x1優化更好,致使部分ARM上MobileNetV2與MobileNet速度接近,但性能差距仍是存在的,期待進一步優化後能接近SqueezeNetv1.1速度。
每一個stage的通道數量:【24 32 64-96 160-320】*6
每一個stage的block數量:【2 3 7 4】
Block分析:MobileNetV2 block,相似MobileNet沒有加shotcut
block中CONV1x1和DWCONV3x3的計算量、參數數量比例是C:27,以深度層14x14x64(C=384)或14x14x96(C=576)爲例,兩者比例爲14.22或21.33 ,這個佔比是目前最低的,因此MobileNetV2是目前能看到的最好的小網絡結構。
MobileNetV2中直接壓縮CONV1x1的方法與前面GCONV+Shuffle/Permutation的方法可否結合優化呢?IGCV3在MobileNetV2的基礎上改進,block中兩個GCONV1x1後面都加了Permutation,分組數量g=2,通道數量保持不變,但深度大幅增長,多了15個block(更高)。
1.0和1.4版本IGCV3都比一樣條件復現的MobileNetV2分別高了接近0.9%和0.8%,但若是與論文中MobileNetV2結果相比,優點就不明顯了。消融實驗代表,同等參數,加深度版本的性能比加寬度版本更好(同等質量,高比胖要好。。恍然大悟),block中僅在DWCONV3x3後面加ReLU更好。
每一個stage的通道數量:【24 32 64-96 160-320】
每一個stage的block數量:【4 6 14 7】
block分析略,g=2的block很是類似,主要變化是增長了深度。
DWCONV這種壓縮加速「大殺器」在某些移動設備上很難優化,並不老是像理論上那麼高效,SqueezeNext延續SqueezeNet模型小的優良傳統,但此次更加註重硬件部署速度,採用兩級sqeeze+分解CONV3x3的方式壓縮加速,兩級CONV1x1壓縮輸入通道數,相似Inception-v3將CONV3x3分解爲CONV3x1和CONV1x3,加了ResNet類型的shotcut(避開了DenseNet類型鏈接,會增長通道數和須要費時耗能的聯結激活)。最後經過硬件模擬找到瓶頸,優化調整網絡結構。
硬件模擬的結果頗有參考價值:降維模塊中CONV7x7的計算量佔比很是高,即便改爲了5x5後總計算量仍然比14x14這一深度層14個block的總計算量還高;分組卷積能夠進一步減小模型參數,但會損失性能;一樣21個block,不一樣分佈[6 6 8 1], [4 8 8 1], [2 10 8 1], [2 4 14 1]計算量和參數數量很是接近,實驗結果代表[2 4 14 1]這種在14x14深度層加block的方式性能最好、更快更節能,符合之前全部模型的設計趨勢(加深度層名副其實,我不是亂叫的)。
(提問:DWCONV已證實確實是很差優化,但非對稱卷積CONV1x3和CONV3x1就很好優化嗎?)
每一個stage的通道數量:【32 64 128 256】
每一個stage的block數量:【2 4 14 1】
Block分析:
block中CONV1x1和CONV3x1+CONV1x3的計算量、參數數量比例是1:1。整體上,通道數較少,體積小是優點,但性能水平不高,且部署速度還須要良好優化的CONV3x1和CONV1x3支撐。
未完待續--