神經網路架構搜索(NAS)中的milestones
- 2019 年 12 月 10 日
- 筆記
作者:風車車
https://zhuanlan.zhihu.com/p/94252445
本文已由作者授權,未經允許,不得二次轉載
神經網路架構搜索(NAS)今年也是火的不行,本文簡單梳理一下個人覺得比較有代表意義的工作,如果有錯誤或者遺漏歡迎大家指出hhhh
另外推薦一篇survey(雖然到處都在說這個,但我還是要推薦一下)
Neural Architecture Search: A Survey
大致按照時間線來,內容分為這麼幾塊:大力出奇蹟,平民化,落地
1,大力出奇蹟
--------------------------------
被人們所熟知的第一篇NAS工作應該是Google的這篇NEURAL ARCHITECTURE SEARCH WITH REINFORCEMENT LEARNING[ICLR'17],充分展現了Google的實力和財力(劃掉)。思路也是簡單明了,以前每一層的filter數量大小等等都需要人為來定,那就可以做成一個優化問題列幾個選項讓它自己選個最好的,這樣的選擇組合起來就成了編碼某個網路結構的token。為了讓其更加靈活支援變長token,使用RNN來作為這裡的controller,然後用policy gradient來最大化controller取樣網路的期望reward,也就是validation accuracy

思路很直接,效果也不錯,然鵝Google用了800塊gpu跑了快一個月(還只是在cifar10)...直接勸退
後來這幫大佬可能覺得跑個cifar10太naive了,應該整個ImageNet,但是像之前這麼搞直接在ImageNet上搜肯定是跑不動的,別說800張卡,8000張都搞不定。
於是Google又出了一篇Learning Transferable Architectures for Scalable Image Recognition[CVPR'18]。那我不搜整個結構,搜個cell然後堆起來就行了,反正VGG/Inception/ResNet也是這麼乾的,於是沿用了之前的思路,繼續用RNN和policy gradient在新的搜索空間中尋找最佳的結構,在cifar上搜cell然後堆起來用到ImageNet上。搜索目標只包括兩種cell,一種是normal cell,另一種reduction cell用於downsample,每個cell裡面包括一些block,新的搜索空間包括選擇這些block使用什麼op,用什麼作為輸入等。之後很多工作都沿用了NASNet Search Space這個套路。

最後整體結構和搜到的cell長這個樣子,也就是NASNet

performance也很不錯,cifar10最好的一次跑到了2.19%的error rate,在同樣參數下ImageNet也都超過了手工設計的網路

這次的速度比上次快多了,500塊gpu只跑了4天就跑完了(再次勸退)
之後大佬們可能覺得現在的token都定長了,或許RNN+policy gradient的優化方式可以換成一些其他的演算法(也可能是覺得強化學習調參太tm蛋疼了),於是Google又出來一篇Regularized Evolution for Image Classifier Architecture Search[AAAI'19],搜索空間沿用上面的NASNet Search Space,只是將優化演算法換成了regularized evolution(具體演算法還是看paper吧...寫出來感覺內容太多了(其實就是懶)),搜到的結構叫做AmoebaNet。實驗表明確實evolution更加好使,收斂快,效果好,調參還沒那麼蛋疼。

右邊兩個是不同數據集上的
AmoebaNet這種方法用450塊gpu跑了7天,依舊勸退。。
後來Google自己也覺得之前的方法太花時間了,於是又搞了個Progressive Neural Architecture Search[ECCV'18],主要目標就是做加速。將搜索空間減小並且用預測函數來預測網路精度,最後時間縮短到大概225個gpu-day,相比AmoebaNet少了十幾倍,然而對於普通玩家還是在勸退。。。
2,平民化
--------------------------------
像上面這種大力出奇蹟的玩法平民玩家基本玩不起,但是計算量的問題擺在這裡,自然就有一些解決方案來加速這個過程。
比較有代表性的就是weight sharing加速validation的Efficient Neural Architecture Search via Parameter Sharing[ICML'18](咦,還是Google的Quoc V. Le他們),大概思路就是將NAS的取樣過程變成在一個DAG裡面取樣子圖的過程,取樣到的子圖裡面的操作(卷積等)是參數共享的。與之前的方法主要差別就在於ENAS中子圖的參數從DAG繼承而來而不是重新初始化,不需要train-from-scratch即可以驗證子圖的精度,極大的加速了NAS的過程。

從DAG中取樣子圖,這裡1是輸入節點,3/6是輸出節點
為了評估取樣到的子圖在數據集上的表現,DAG的參數(weight等)是需要優化的,除此之外為了找到最好的子圖,取樣器(這裡使用的RNN)也是需要優化的。ENAS採用的是交替優化DAG中的參數和取樣器中的參數。DAG參數的優化是通過取樣一個子圖,然後forward-backward計算對應操作的梯度,再將梯度應用到DAG上對應的操作通過梯度下降更新參數。取樣器RNN的更新採用了之前policy gradient的優化方式。

ENAS搜索整個CNN,RNN取樣每個節點的操作以及輸入的前置節點
ENAS提出了兩種模式(這裡只介紹CNN),一種是搜整個網路結構,一種是搜個cell然後按照之前的方式堆起來,在搜索cell的時候只需要一張卡跑半天就能跑完。不過最近ICLR'20的投稿中對於weight sharing有很多不同的聲音,有興趣的可以去openreview看一看。
還有一個很快就能跑完的NAS工作是用可微分的方式進行搜索的DARTS: Differentiable Architecture Search[ICLR'19],在今年被各種魔改(我猜很可能是因為開源了pytorch的程式碼,然後程式碼寫得很漂亮改起來也比較容易)。DARTS和ENAS很像,也是從DAG中找子圖,並且同樣採用了weight sharing,主要的區別在於搜索空間和搜索演算法上。搜索空間比較類似NASNet search space,搜索演算法則是採用了可微分的方式。
DARTS也是搜cell然後按照一定的模式堆起來,在搜索演算法上與之前的方法最大的區別在於DARTS選擇某個操作的時候並不是像之前按照RNN的輸出概率進行取樣,而是把所有操作都按照權重(不是直接加權,先將權重softmax歸一化)加起來,那這樣權重就在計算圖裡面了,在計算驗證集loss之後就可以backward計算權重的梯度,直接通過梯度下降來優化權重。搜索的過程也就是優化權重的過程,最後保留權重最大的操作就是最後搜到的結構。

DARTS裡面的一個cell,不同顏色的邊表示不同的操作,顏色深淺表示不同的權重,最後留下權重最大的
權重的優化和DAG裡面weight的優化類似於ENAS,也是交替進行的(在訓練集上優化weight,在驗證集優化權重),不過DARTS是整個DAG進行forward-backward(這樣的缺點在於記憶體開銷會比較大)而不是像ENAS一樣先取樣子圖。

DARTS的搜索演算法,很漂亮的工作
DARTS搜索一次只需要一張1080ti跑一天即可,對於平民玩家完全沒壓力hhhhh
上面這兩項工作讓很多只有幾張顯示卡的平民玩家也能玩得起NAS。
3,落地
--------------------------------
上面所介紹的NAS工作很少有人工設計網路的影子,基本都是重新設計了新的搜索空間。從實驗結果上來NAS搜到的網路確實能取得很好的效果,但並不一定適合實際部署(比如DARTS能在很小的參數量下達到很高的精度,但是實際forward其實很慢)。既然之前已經有了很多優秀的人工設計的網路結構,NAS可以通過引入這些先驗知識來加速或者取得更好的實際部署性能。
先舉個最直觀的例子,EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks[ICML'19]簡單粗暴,既然MobileNet在同樣精度下速度快,那我把它拿來搞大一點,同樣的速度下精度會不會高一點?答案是肯定的
問題在於怎麼放大這個網路,單獨加深/加寬/加大解析度效果一般般,EfficientNet搜索了寬度/深度/解析度之間的相對縮放因子,將他們按照一定的比例放大,事實證明這種方式(我覺得這應該也算是NAS)雖然簡單但是有效。


EfficientNet(縮放之後的MobileNetV2)性能很殘暴並且縮放的組合方式很重要
還有一個魔改MobileNetV2的工作出自MIT Song Han組,ProxylessNAS: Direct Neural Architecture Search on Target Task and Hardware[ICLR'19],這篇工作的point不在於魔改MobileNetV2(kernel size,expansion ratio等),而是在於proxyless的理念。想要某個數據集在某硬體上的結果就直接在對應的數據集和硬體上進行搜索,而不是像之前的工作先在cifar10搜然後transfer到ImageNet等大數據集上,並且在目標函數上加入硬體latency的損失項作為多目標NAS,直接面向部署的硬體。

另一個系列的工作也是出自Google,MnasNet: Platform-Aware Neural Architecture Search for Mobile[CVPR'19]用來魔改MobileNetV2裡面的layer數/卷積操作/加attention等等,然後用之前同樣的RNN+policy gradient的方式來優化

除此之外,NetAdapt: Platform-Aware Neural Network Adaptation for Mobile Applications[ECCV'18]針對特定硬體對已有的網路做壓縮,相當於對網路在硬體上做一個結構上的fine-tune。

Google後來結合了上面這兩項工作,推出了Searching for MobileNetV3[ICCV'19],把MnasNet魔改的MobileNetV2再用NetAdapt做微調,然後加了一些工程技巧,得到了最後的MobileNetV3。

性能很強悍,超過了ProxylessNAS和MnasNet
最後再介紹一個同樣是Song Han組最近的工作,Once for All: Train One Network and Specialize it for Efficient Deployment[Arxiv],直接train一個大網路,需要哪種網路直接去裡面取就可以,將訓練過程和搜索的過程解耦開來,相當於只需要train一次。

比較神奇的地方在於訓完了之後不需要fine-tune就能取得很好的結果,應該是跟下面這種progressive shrinking的訓練方式相關。如果再fine-tune精度會更高,openreview上的版本甚至比MobileNetV3高出4個點。

progressive shrinking
感覺是一個很好的思路,大部分NAS的主要時間到都花在驗證/比較網路精度上,那麼把這個時間都花在訓練一個大網路上,然後再選所需要的小網路或許是一種更高效/性能更好的方式。Once for All使用的一些技巧也比較多,推薦大家看一下原paper
最後再說一個Rethinking the Value of Network Pruning[ICLR'19]裡面的結論,對於結構化的剪枝,Training---Pruning---Fine-tuning的pipeline得到的精度並不如將目標網路train-from-scratch的精度高,也就是說剪枝的目標網路的結構設計其實最為重要,這也就是NAS正在做的事情。不過在train-from-scratch代價比較大的時候,pruning和fine-tuning的策略也很重要,爭取在計算量盡量少的情況下維持原有精度。
終於寫完啦,以後再看到有意思的paper也會繼續更新~

