綜述:輕量級(jí)CNN架構(gòu)設(shè)計(jì)(3)
· ShuffleNet系列
曠視出品的ShuffleNet系列有兩篇論文,且后一篇在打前一篇的臉,很有意思。
1.ShuffleNet V1是在MobileNet V1后MobileNet V2前提出的,說(shuō)實(shí)話結(jié)構(gòu)上和MobileNet V2還挺像,大家可以上下兩張圖片對(duì)比一下。兩者都想到了學(xué)習(xí)ResNet的殘差結(jié)構(gòu),區(qū)別在于ShuffleNet V1覺得block當(dāng)中的1×1標(biāo)準(zhǔn)卷積也非常耗時(shí),于是用1×1的分組卷積外加channel shuffle的操作給替換了,然后MobileNet V2會(huì)先升維讓深度可分離卷積得到充分的學(xué)習(xí)再降維回來(lái),ShuffleNet V1中stride為2的模塊也有自己的特色,雖然看著MobileNet V2的結(jié)構(gòu)更簡(jiǎn)潔一些,但ShuffleNet V1創(chuàng)新也是不少,尤其那個(gè)用channel shuffle增強(qiáng)不同組之間信息交互的操作。
ShuffleNet V1
2. ShuffleNet V2論文是一篇誠(chéng)意滿滿之作,作者通過(guò)分析ShuffleNet v1與MobileNet v2這兩個(gè)移動(dòng)端網(wǎng)絡(luò)在GPU/ARM兩種平臺(tái)下的時(shí)間消耗分布,看出Conv等計(jì)算密集型操作占了絕大多數(shù)時(shí)間,但其它像Elemwise和IO等內(nèi)存讀寫密集型操作也占了相當(dāng)比例的時(shí)間,因此像以往那樣僅以FLOPs來(lái)作為指導(dǎo)準(zhǔn)則來(lái)設(shè)計(jì)CNN網(wǎng)絡(luò)是不完備的,雖然它可以反映出占大比例時(shí)間的Conv操作,但不夠準(zhǔn)確。于是作者提出了高效網(wǎng)絡(luò)設(shè)計(jì)的四個(gè)指導(dǎo)原則:
1. 當(dāng)輸入和輸出的通道數(shù)相同時(shí),conv計(jì)算所需的MAC(memory access cost)最?。?/p>
2. 大量的分組卷積會(huì)增加MAC開銷;
3. 網(wǎng)絡(luò)結(jié)構(gòu)的碎片化會(huì)減少其可并行優(yōu)化的程度,GoogleNet系列和NASNet中很多分支進(jìn)行不同的卷積/pool計(jì)算非常碎片,對(duì)硬件運(yùn)行很不友好;
4. Element-wise操作不可忽視,對(duì)延時(shí)影響很大,包括ReLU,Addition,AddBias等,主要是因?yàn)檫@些操作計(jì)算與內(nèi)存訪問的占比太?。?/p>
基于此,作者提出了ShuffleNet V2的blocks,如下所示,與V1相比,去掉了分組卷積的操作,去掉了Add操作,換成了Concat,stride為2的block的旁路把平均池化換成了深度可分離卷積,為了繼續(xù)延續(xù)channel shuffle的操作,作者在block進(jìn)去的地方做了個(gè)split的操作,最后再concat+channel shuffle,這里是為了替換掉之前的Add,同時(shí)也可以減少計(jì)算量。
ShuffleNet V2
Shift: A Zero FLOP, Zero Parameter Alternative to Spatial Convolutions
這是一篇很有意思的論文,主要是提出了一種無(wú)參數(shù),無(wú)計(jì)算的移位算子來(lái)代替ResNet中計(jì)算量占比很高的3×3卷積,這種算子稱為shift kernel,如下圖所示,只需要根據(jù)kernel上的shift信息對(duì)feature map進(jìn)行位置上的上下左右偏移即可得到新的feature map,沒有計(jì)算,僅僅是訪存操作。詳細(xì)一點(diǎn)說(shuō)就是如下面Shift框里面的第一個(gè)卷積核,它只在黃色的區(qū)域?yàn)?,其他白色的區(qū)域?yàn)?,在做卷積計(jì)算的時(shí)候其實(shí)就相當(dāng)于把輸入feature map中間偏左邊的那個(gè)點(diǎn)的值平移到輸出feature map中間的地方,正如作者標(biāo)注的向右的箭頭所示。而且這個(gè)操作都是per-channel的,所以每個(gè)卷積核只有k×k種可能性,當(dāng)通道數(shù)大于k×k時(shí),就需要將所有通道分成iC/(k×k)組,剩下的channel設(shè)置為center,即中間為1,其余為0,然后怎么去選取每個(gè)卷積核的類型呢,論文在兩個(gè)shift kernel中間夾了一個(gè)1×1的標(biāo)準(zhǔn)卷積,要保證第二次shift操作之后數(shù)據(jù)與第一次輸入shift kernel之前順序一致,并且這個(gè)shift操作可以通過(guò)SGD的方式進(jìn)行端到端訓(xùn)練,再具體的細(xì)節(jié)論文其實(shí)也沒有闡述的很清楚,而且我目前也沒有看到作者公布源代碼,不過(guò)這篇論文看起來(lái)還是很有意思的,論文中還分析了depthwise計(jì)算不高效的原因在于計(jì)算/IO時(shí)間導(dǎo)致運(yùn)行更慢的問題,其實(shí)這個(gè)shift kernel的作用并沒有產(chǎn)生新的信息或者去進(jìn)行特征的學(xué)習(xí)(畢竟連參數(shù)都沒有),而是對(duì)feature map空域的信息做了個(gè)混洗,使得與他相接的1×1卷積可以學(xué)到更豐富的特征,在我看來(lái)有點(diǎn)類似于在網(wǎng)絡(luò)內(nèi)部做數(shù)據(jù)增強(qiáng)的感覺。
Shift
· GhostNet
GhostNet也是一篇很有意思且簡(jiǎn)潔的架構(gòu)設(shè)計(jì)的論文,作者在可視化一些訓(xùn)練好的神經(jīng)網(wǎng)絡(luò)中間feature map時(shí)發(fā)現(xiàn)它們通常會(huì)包含一些相似且冗余的特征圖,使得神經(jīng)網(wǎng)絡(luò)能得到更充分的學(xué)習(xí)。基于這個(gè)想法,作者通過(guò)設(shè)定一系列廉價(jià)的線性運(yùn)算操作來(lái)代替部分卷積計(jì)算,以此來(lái)產(chǎn)生更多的特征圖,僅僅這么一個(gè)簡(jiǎn)單的操作就可以減少模型的參數(shù)量和計(jì)算量,而且在幾個(gè)視覺公開數(shù)據(jù)集上取得了很不錯(cuò)的效果,甚至超越了MobileNet V3,感覺非常的大道至簡(jiǎn),這也是我比較喜歡的原因。
GhostNet
基于特定硬件的神經(jīng)架構(gòu)搜索
基于特定硬件的神經(jīng)架構(gòu)搜索(MIT HAN Lab論文總結(jié)
https://zhuanlan.zhihu.com/p/320290820)
設(shè)計(jì)方法總結(jié)
接下來(lái)我將結(jié)合自己看過(guò)的論文,還有這一年多的項(xiàng)目比賽經(jīng)歷談一談我所理解的圖像分類和目標(biāo)檢測(cè)相關(guān)輕量級(jí)模型設(shè)計(jì),本文思想還比較淺薄,主要是給自己的工作做個(gè)總結(jié),有不正確的地方希望大家能共同討論。
設(shè)計(jì)之前
通常我們都是基于已有的硬件架構(gòu)去進(jìn)行模型的部署,這個(gè)時(shí)候就需要確定這個(gè)架構(gòu)下能部署什么算子,可以通過(guò)已有的接口自己拓展哪些算子,并且哪些算子不是很高效。就拿我去年參加的某視覺加速比賽來(lái)說(shuō),當(dāng)時(shí)初出茅廬,不太懂硬件底層,頭鐵要在Xilinx ultra96 V1板子 + 我們組自研的硬件架構(gòu)上部署當(dāng)時(shí)最新,準(zhǔn)確率最高的EfficientNet,因?yàn)闇?zhǔn)確率確實(shí)高,老板就欽定必須使用這個(gè)模型,并且選擇了比較合適的EfficientNet-B4,輸入分辨率由384改成256。后來(lái)一頓開搞發(fā)現(xiàn)有很多swish操作,這個(gè)雖然之前還沒有經(jīng)驗(yàn),但是還好很快想到用查找表去實(shí)現(xiàn)了,并且還發(fā)現(xiàn)我們的架構(gòu)尚且不能實(shí)現(xiàn)全連接層(勿噴,之前都是在搞全卷積網(wǎng)絡(luò)),所以里面的SE block還有最后一層都無(wú)法用我們的架構(gòu)部署,然后博士師兄就想到了利用ultra96板子上的ARM+NEON加速技術(shù)去實(shí)現(xiàn)這一部分,每次PS和PL交互數(shù)據(jù),當(dāng)時(shí)只有一個(gè)月的開發(fā)時(shí)間,因?yàn)檫@個(gè)模型比較大且當(dāng)時(shí)我們開發(fā)模式的問題,連續(xù)熬夜差點(diǎn)沒把整個(gè)組人的命搭進(jìn)去,最后上板跑幀率也只有6幀(師兄最開始預(yù)估能達(dá)到80幀,所以大家一直不停的往下做hhhhh),在ImageNet驗(yàn)證集上純浮點(diǎn)準(zhǔn)確率是0.805,INT8準(zhǔn)確率是0.793,幀率低的原因有兩點(diǎn),一個(gè)是模型確實(shí)很大,另一個(gè)是因?yàn)镾E block在每一個(gè)stride為1的module中都出現(xiàn)了,整個(gè)模型PS和PL交互十分頻繁,而我們當(dāng)時(shí)間很緊剛剛完成一版就必須提交了,所以這塊也根本沒有優(yōu)化,導(dǎo)致了延時(shí)很高,并且當(dāng)時(shí)我們的架構(gòu)只跑了100M的頻率,更高頻率會(huì)有一些bug(貌似是板子的問題),所以幀率非常低,這個(gè)真的是血的教訓(xùn):一定要量力而行,仔細(xì)研究評(píng)價(jià)指標(biāo),在硬件友好程度和精度上做一個(gè)trade-off,一味片面地追求精度真的要命呀。
輕量級(jí)CNN架構(gòu)設(shè)計(jì)
總的思路: 選定合適結(jié)構(gòu) + 通道剪枝 + 量化
訓(xùn)練 :ImageNet pretrain model + Data Normalization(統(tǒng)計(jì)自己數(shù)據(jù)集的均值和方差) + Batch Normlization + 大batch size + 一堆數(shù)據(jù)增強(qiáng)tricks + 嘗試各種花里胡哨的loss function和optimizer
(再次說(shuō)明這部分只討論圖像分類和目標(biāo)檢測(cè)兩種任務(wù),目前的視覺加速比賽基本都是基于這兩個(gè)任務(wù)做的,按照計(jì)算資源和內(nèi)存從小到大排列,不用問,沒有劃分原則)
1.絕對(duì)貧窮人口
輸入分辨率要小,如128,160,192或256;
下采樣使用MaxPooling;
特征學(xué)習(xí)層使用Depthwise Separable Convolution,即一層3×3的Depthwise + 一層pointwise(1×1標(biāo)準(zhǔn)卷積)堆疊;
激活函數(shù)用ReLU;
另外這里推薦看看MCUNet,感覺非常呦西,MIT韓松團(tuán)隊(duì)yyds!
2. 相對(duì)貧窮人口
輸入分辨率依舊要小,記住分辨率對(duì)計(jì)算量的影響都是翻倍的;
下采樣可以使用MaxPooling或者stride為2的Depthwise Separable Convolution;
特征學(xué)習(xí)層使用Depthwise Separable Convolution,或者M(jìn)obileNet V2的倒置殘差結(jié)構(gòu),又或是ShuffleNet V2的unit,1×1的Group convolution能處理的比較好的話其實(shí)也推薦使用(主要是計(jì)算/訪存);
激活函數(shù)用ReLU或者ReLU6;
3. 低收入人口
輸入數(shù)據(jù)選用小分辨率,如果對(duì)精度要求高一些可以適當(dāng)增大;
下采樣可以使用MaxPooling或者stride為2的Depthwise Separable Convolution;
特征學(xué)習(xí)層可以使用MobileNet V2的倒置殘差結(jié)構(gòu),又或是ShuffleNet V2的unit,也可以使用通道數(shù)小一點(diǎn)的3×3標(biāo)準(zhǔn)卷積;
激活函數(shù)用ReLU,ReLU6或者leaky ReLU,看效果了;
4.一般收入人口
輸入數(shù)據(jù)可以稍微大一些,288,320,384啥的可以考慮上了;
下采樣使用stride為2的Depthwise Separable Convolution或者stride為2的3×3卷積;
特征學(xué)習(xí)層既可以使用上述的,也可以使用3×3標(biāo)準(zhǔn)卷積 + 1×1標(biāo)準(zhǔn)卷積的堆疊形式,SE block這種硬件支持的還不錯(cuò)的可以嘗試加上;
激活函數(shù)除了上述的可以試試H-sigmoid和H-swish,不過(guò)據(jù)我經(jīng)驗(yàn)效果基本和ReLU差不多;
5.高收入人口
輸入數(shù)據(jù)的分辨率可以往500-600靠攏了;
下采樣和上述一樣;
特征學(xué)習(xí)層可以上ResNet + SE block的配置,ResNet是真的牛逼,5×5的卷積啥的也可以整上,第一層直接上7×7的標(biāo)準(zhǔn)卷積也不是不可以,資源再多了可以增加通道數(shù)和深度 或者 上多核并行計(jì)算;
激活函數(shù)可以用H-swish;
番外
目標(biāo)檢測(cè)任務(wù)中感覺Tiny YOLO V3非常受歡迎,建議嘗試!計(jì)算量太大可以換更輕量的backbone或者改輸入分辨率,輕量級(jí)的backbone+FPN的結(jié)構(gòu)也很棒,且推薦使用商湯開源的mmdetection,訓(xùn)練調(diào)參當(dāng)場(chǎng)起飛。
另外之前閱讀MIT HAN lab基于特定硬件的神經(jīng)架構(gòu)搜索相關(guān)文章時(shí)發(fā)現(xiàn)他們?cè)O(shè)計(jì)模型常用的一個(gè)子結(jié)構(gòu):MobileNetV2的倒置殘差模塊 + SE block + H-swish,看他們?cè)诤芏嗨惴铀俦荣惿夏昧斯谲姡杏X百試不爽呀,且根據(jù)硬件資源進(jìn)行拓展的靈活度也很高,具體可以參見他們今年發(fā)表的OnceForAll論文中的模型,源代碼都在Github上能找到,MIT HAN lab真學(xué)術(shù)界良心,再喊一句MIT韓松團(tuán)隊(duì)yyds!
最后總結(jié)
過(guò)去的一年被導(dǎo)師安排著參加各種比賽,去年啥也不懂的時(shí)候還能拿幾個(gè)不錯(cuò)的獎(jiǎng),今年感覺學(xué)了很多懂了很多,使用的模型也都對(duì)硬件比較友好,量化后幾乎無(wú)損(一個(gè)點(diǎn)以內(nèi)),反倒連連受挫,心情非常沮喪,而且總被奇奇怪怪的模型打敗,總有一種自己學(xué)了一身正派功夫,最后反倒被野路子出招一擊即潰的感覺,然后論文也被拒了,沒心思改投,回想一下碰上疫情的這一年真的好失落,可能還是我太菜了吧。
馬上也要開始投入找實(shí)習(xí)(希望老板能放我)刷題找工作的階段了,最近也在培養(yǎng)下一屆,把工作慢慢移交給他們,一想到找工作,整個(gè)人的心態(tài)都不一樣了,無(wú)心科研,這篇文章就算是對(duì)我過(guò)去一年多的工作做個(gè)總結(jié)吧,同時(shí)也希望我們課題組能夠發(fā)展的越來(lái)越好,多多拿比賽大獎(jiǎng),多多發(fā)論文。
*博客內(nèi)容為網(wǎng)友個(gè)人發(fā)布,僅代表博主個(gè)人觀點(diǎn),如有侵權(quán)請(qǐng)聯(lián)系工作人員刪除。
pid控制器相關(guān)文章:pid控制器原理