卷積神經網路結構演變(form Hubel and Wiesel to SENet)——學習總結,文末附參考論文
因為打算研究語義SLAM,所以就一直比較關注深度學習這塊,這篇文章算是自己的一個總結。結合自己以前了解的,以及上課老師講的和在深度學習大講堂的免費課程對網路結構做一個梳理。前面參考劉昕博士所介紹的關於深度學習模型的演化結構,基本上也就是自己當時所記錄的筆記,後面有一些參考資料來源於知乎CSDN等平台,文末附所有網路結構論文。
這幅圖應該是比較完善的,基本涵蓋了絕大部分的卷積神經網路。接下來,我就把自己當時的筆記整理一下,幫助自己更好的理解。我自己現在整理的網路包括:1989年LeCun first baby、LeNet、AlexNet、VGG、NIN 、GoogleNetV1~V4、Xception、, PReLU Net(MSRA-Net)、ResNet,、ResNet的增強版、ResNeXt、DenseNet、MobileNet V1~V2、ShuffleNet、SENet
一、早期的嘗試
1.貓的實驗
1962年(神經網路的發源時期),Hubel和Wiesel對貓做了個實驗,發現貓的視覺皮層對信息的處理是一種層級結構,也就是說它是一層一層提取信息的,最簡單的信息在最前面提取,然後不斷地對簡單信息提取,逐漸就得到了高層次的抽象信息,他們當時獲得的模型如圖所示:
即然有人提出來了,那麼什麼都喜歡用代碼來實現的計算機科學家們,當然不會放過了,於是在1980年的時候福島邦彥(Kunihiko Fukushima),把這個模型用代碼實現了,但是他雖然用的是卷積的方式,但是他的誤差是不是反向傳播,用的是自組織的一些方法去實現的。
看了下論文,論文中提到了輸出應該和非負模擬值成正比(這玩意是不是和relu激活函數很像啊。。。。。。·),還是老一輩人厲害!!!
沿著神經科學的腳步:Jones and Palmer 在1987年發現貓的V1區域對視覺信號的響應和數學裡面的gabor小波基非常相似,gabor小波基也曾經長時間用在圖像處理當中,朱松純當年也是在gabor小波基裡面找到了一組根據最小化最大熵原則的小波基,獲得了馬爾獎(這個是後話,後面我打算也寫一下關於我在計算機視覺課程裡面學習到的一些有趣的東西,關於底層視覺建模統計學派和稀疏學派)。
2.福島的嘗試
好了,現在回到計算機科學家上面了,後面Maximilian Riesenhuber 和Tomaso Poggio根據hubel和福島老爺爺的思路提出了基於層級的識別網路HMAX,從認知機制和計算實現方面給出了一些試驗結果,這裡面其實已經出現了max-pooling的操作了,並且在論文裡面作者認為這是關鍵的一步。(很多思路都是在很早就已經成型了)。
根據這個hubel的研究,其實我們就不難發現,分層去提取特徵這個是已經被研究了很久的一個方向,這種思路的其中一個解釋就是我們大腦識別其實也就分層的。
(我自己猜測可不可能有這樣一種思路:我們分析問題其實就是分層的,一層一層去分析,每一層分析都特別的簡單,就是一個化繁為簡的過程,把無數簡單疊加,就能解決一個複雜問題)。
3.1989年 LeCun First Baby
隨著時間的流逝,LeCun大佬出場(祖師爺,天生自帶光環)1989年,用了三個隱含層去學習一個郵政數字識別的網路。第一個隱層有12個通道,8*8的特徵響應圖(feature map),也就是有768個單元(8*8*12=768),每個特徵響應圖由5*5的卷積獲得,這裡lecun搞了個池化,但是沒有明確提出來,原文中叫做two-to-one undersampled,也沒有說到到底是求和還是平均還是取最大值,不過他這裡提到了這樣做的動機:對於高層感知可能更關注目標是否存在,而位置可能不那麼重要(這不就是capsule試圖去解決的嗎??)。然後這裡面他還用到了參數共享,第一層的參數是1068(768+25*12)。第二個隱層也是同樣操作,獲得的是12個通道4*4的結果,但是每個通道中的數據只來自上一層12個通道中的8個通道的數據(這8個怎麼選擇的,祖師爺沒給出來,老爺子是不是也是實驗出來的呢????),權值同樣共享,這樣第二個隱層的參數為2592(12*8*5*5+12*4*4),第三層就是全連接層是全連接層,一共30個單元,所以參數也好計算5790(12*4*4*30+30)。它池化層,局部感知,權值共享都有了,全連接層也有了,並且在論文中也詳細解釋了為什麼要引入這些東西,不過感覺當時LeCun應該是有保留的,還有東西沒說明白,比如這個池化,到底選的是什麼?為什麼只連接8個?怎麼選取這8個?
然後劉昕老師還在LeCun的論文裡面發現了4個彩蛋,第一個正切函數收斂更快,可以通過對函數求導來對比值域便可以發現,正切函數的值域是(0,1)而sigmoid函數的值域是(0,1/4] ,2.4對應的是根號6,但是分母不對,但是兩者出發點都一樣,都是keeping the range.
4.LeNet
接下來就是1998年大名鼎鼎的LeNet,在這裡LeCun發了一篇46頁的論文,第一次喊出了卷積網(Convolutional network)的口號,並且把結果同各種方法做了一個比較,基本唯一能抗衡的就是V-SVM poly9,結果祭出大殺器Boost,Boosted LeNet-4,以0.1%的優勢幹掉了SVM。
LeCun在這篇論文裡面非常詳細的介紹了自己的工作,看看網路結構:
C1,C3,C5都是用5*5的卷積核去提取信息,S2,S4採用的是相鄰像素之和。這裡面要講一下的就是S2與C3之間的連接,這裡有兩方面的考慮:1.局部的連接可以限制感知區域2.打斷網路中的對稱性(老爺子認為這個是更重要的·)。看著這個是不是和ShuffleNet非常相似???想一想1989年那篇文章,12個裡面只取8個來連接,兩者是不是有點類似。所以個人猜測,這篇文章是在89年那篇文章的基礎之上,老爺子通過了9年的沉澱,可能天天挑燈夜戰,把89年的理論做了一個完整的梳理,進而提出了卷積網路的概念!(備註:LeCun把這個不叫卷積神經網路,只認為這個是卷積網路)
這項工作一出來,的確在當時引起了不小的轟動,LeCun也準備大展拳腳,可惜啊,接下來出現了一些表現更好的手工設計的特徵比如:SIFT,HOG,LBP這些運算元再加上SVM,原理的清晰性,模型可解釋,數據需求小,計算需求小,很快蓋過了LeCun的工作,他也為此鬱悶了15年。
二、歷史轉折
5.AlexNet
這一次工作直接導致了神經網路的復興,在神經網路的歷史上,可以說具有跨時代的意義,這裡面也採用了許多技巧,比如dropout,relu激活函數,學習率衰減等,這些在優化方法裡面會介紹到一些。
這裡採用了多GPU分布計算,不過初衷好像是因為:他有兩塊GPU,沒有其他原因!整個網路有5個卷積層和3個全連接層。網上找了一張AlexNet的結構圖
第一層:輸入224*224*3,採用11*11的大卷積核,步長設定為4,輸出96個通道(提取96個特徵),經過激活函數,隨後會經過一個LRN層(Local Response Normalization),這個層被稱為響應規範化層,目的是為了進行一個橫向抑制,使得不同的卷積核所獲得的響應產生競爭。具體公式如下:
LRN這個現在很少使用了,因為效果不是很明顯,不過作為一個回顧,還是要簡單了解一下,說不定,你會根據這個獲得一種啟發。經過了LRN的輸出,經過一個池化就可以進入第二個卷積層了,這裡池化的核為3*3,步長為2。
簡單介紹一下關於尺寸變化的計算公式:
根據上一式可以計算經過11*11的卷積之後,尺寸變為:55*55(這裡採取進一操作),再經過一次pooling,獲得第二個卷積層的輸入尺寸:27*27
第二個卷積層:輸入為27*27*96,用256個卷積核去提取特徵,也就是提取了256個特徵,卷積核的大小為5*5(這裡面因為原文中是兩塊GPU,所以每塊GPU的輸入是48個通道,輸出是128個通道,從圖上看比較清晰),padding為2,隨後經過激活函數,經過一個LRN層,然後池化,池化的核同樣是3*3,步長為2,獲得的輸出為13*13*256。
第三第四第五的卷積層都沒有接響應規範化層,第三層輸入13*13*256,用384個大小為3*3的卷積核去提取特徵,尺寸沒有發生任何改變,獲得13*13*384.第四層也一樣,輸出為13*13*384。第五層用256個核去卷積,獲得13*13*256的特徵,隨後經過一個池化,池化的核為3*3,步長為2,獲得6*6*256的輸出,然後接到全連接層。
第一個全連接層4096,個輸入,第二個也是4096個輸入,第三個全連接層輸出為1000,因為分類是要分1000個。
三、網路加深
6.VGG Net
VGGnet是牛津大學計算機視覺組的一個研究工作,這個工作基本流程和AlexNet差不多,卷積-池化-卷積-池化…全連接,但是它的開創性的通過反覆堆疊小3*3的卷積層和2*2的池化層,加深了網路,並且獲得了一個很好的效果,同時使用兩個3*3的卷積核疊加能夠獲得一個5*5卷積的感知野,減小了參數並且還提升了非線性。
VGG通過將模塊分組來進行卷積,每一個模塊內的參數設置一樣,經過了卷積之後再pooling。同時在VGG-C裡面還引入了1*1的卷積,網上有的說是引入非線性,其實1*1的卷積相當於是一個將所有層的線性加權,因為卷積的時候,是把對所有層都進行卷積,然後再把對應位置上的值進行加和,得到激活值,所以本質就是一個線性加權的操作,這個在論文中也有提到。(這裡採用分為幾個模塊卷積,我試圖在論文中找到這種解釋,不過好像沒有發現,我個人猜測可能是為了模擬大腦分區的意味,不知道是不是??求大佬告知)
請注意這裡Feature Map的數目變化:64-128-256-512-512.,每次池化之後,變為原圖大小的1/4,也就是信息衰減為原來的1/4,但是由於增加了卷積通道,所以只相當於衰減了一半的信息,抽取太多信息不利於機器學習,所以這也算是一個小技巧吧!
7.PReLU Net(MSRA-Net)
這個網路其實是VGG的一個擴展,他比VGG的網路更加的深,但是我看了一下文章,感覺這篇文章其實更多的是探討一個新的激活函數和以及它權重的初始化。改善了relu函數在把在複數設置為了一個小值,然後根據Xavier初始化的動機,盡量是每個網路層的輸出方差相同,推導出了PRelu函數的初始化方法,在只考慮輸入層為n通道的時候應當滿足一個均值為0,方差為這是何凱明大神和孫劍大神共同發的文章。但是根據這篇文章的摘要中提到:這是第一次超越人類的識別率,因為2014年冠軍GoogleNet的top-5錯誤率為6.66%,而人類在5.1%左右,PReLUNet可以達到4.94%.由於這裡只看結構,所以從結構來看,它比VGG更加的深,採取的策略也是通過用小卷積核的形式。但是可以注意到,在第一層的時候,是用了一個7*7的卷積核,這一能夠減小深度,在論文中是這樣說的,他們注意到過深的網路會導致訓練精度的下降(這其實就是ResNet提出的初衷),所以這個7*7是權衡出來的結果。觀察下圖,這裡是不是也有同樣的規律?通道數增加,特徵的圖長和寬降低,保證信息一次不會受到太多損失。
四、 增加卷積模塊
8.network in network
這個工作的出發點是因為傳統的卷積網路是在一個固定的patch上麵線性加權,所以作者認為它對於特徵的提取能力不夠強,因此作者在卷積之後接了MLP,然後再輸出。
傳統的卷積,就是直接加權求和,然後在relu就得到了一個值。傳統的CNN求輸出只是把卷積核對所有輸入通道對應位置上的數字相加了,也就是說它是一個簡單的線性求和,這是不是和我們的CNN所想要的不一樣呢?於是goodFlow在13年做了一個工作,它引入了一個Maxout層,我個人的理解是類似於用來跨通道進行池化的,就是把幾個通道對應位置上最大輸出作為這幾個通道的一個輸出,而不再是簡單的線性求和。這項工作的數學依據在於:任意的凸函數都可以由分段線性函數以任意精度擬合,所以最大池化層是一個能夠擬合任意凸函數。
NIN的作者就想,你只能擬合任意凸函數,那還是不行,我要搞一個能夠擬合任意函數的層出來。徑向基神經網路和MLP可以逼近任意函數,但是MLP與BP演算法更相容,並且能夠加深網路,更加符合設計特徵重利用的思路,所以選擇MLP,這不就不Maxout更加牛逼了嗎?於是NIN的流程就很容易理解了:先卷積,卷積之後進行relu,之後再對這個結果連接一個MLP卷積層,以MLP卷積層的輸出經過relu之後作為下一層的輸入。這裡的MLP卷積層的實現是通過兩次1*1的卷積來實現的,224*224的圖像經過一個卷積核為11,步長為4的卷積之後大小變為了55*55,一共96個通道。用1*1*96去卷積一下獲得了55*55*96,relu激活一下,再用同樣大小的去卷積,也是獲得55*55*96的特徵輸出,在經過relu一下便是下一層的輸入。1*1的卷積核設計是一個非常巧妙的設計思路,對後來的GoogleNet, MoblieNet這些網路結構都產生了影響。這篇文章裡面還有一個創新點就是採用了平均池化作為最後一層的輸出,提升了它的泛化性能,這裡就不仔細去介紹了。最終NIN在減小了大量的參數前提下,比AlexNet的精度並沒有下降太多。
9. GoogleNet (Iception V1)
提升網路性能,一個有效的途徑就是增加網路層數,擴展網路寬度,但是沿著這條路去走就會發現,網路越複雜,參數越多,也就越容易出現過擬合,增加計算量。於是Google就提出了GoogleNet,其核心的思想就是:稀疏連接。這裡有兩個原因是他們認為稀疏性是有效的原因:1.生物神經連接是稀疏的2.稀疏的網路可以通過分析最後一層的激活性的相關統計來逐層構建一個最佳網路,這一點雖然數學上很難證明,但是Hebbian準則(連在一起的神經元一起激活)從側面有力支持了這一觀點。但是計算機對於非均勻稀疏的計算能力很差,想想LeCun最初的兩個卷積網路是不是都是稀疏的?但是由於後面數據量太多了,為了更好的優化並行設計,又不得不改回來了。那麼有沒有什麼辦法,既可以利用稀疏性,還能提高計算效率呢?根據文獻表明:將稀疏矩陣聚類成密集的子矩陣可以達到與稀疏矩陣同樣的效果,於是就他們最開始就提出如下模型:
現在主要目的是:找出如何讓已有的稠密組件接近與覆蓋卷積視覺網路中的最佳局部稀疏結構。現在需要找出最優的局部構造,並且重複幾次。根據相關文獻表明層與層連接的結構在最後一層進行相關性統計的時候,將高相關性的聚集到一起。這些聚類構成下一層的單元,且與上一層單元連接。我們假設來自較早層的每個單元對應於輸入圖像的一些區域,並且這些單元被分組成濾波器組,接近輸入層的低層中,相關單元集中在某些局部區域,最終得到在單個區域中的大量聚類,而1*1的卷積可以將這些聚類進行融合。三個不同大小的卷積核是用來去提取不同大小的聚類信息,隨著網路的加深,越到後面,抽取的特徵更為高級,信息關聯的跨度會越大。所以3*3,5*5的在後面會更多一些。這裡為了保證卷積後的尺寸一致,所以選了1*1,3*3,5*5的三個patch,同時增加一個pooling層提高效率。
但是這樣的計算效率實在太低了,於是為了提高計算效率,他們在3*3和5*5之前都引入了一個1*1的模塊,這個模塊主要是用來降維的,刪減一下通道,同時有不會失去過多信息,因為1*1的卷積核可以融合不同通道的特徵。比如原先輸入為100*100*64,經過5*5的卷積,輸出通道為128,參數的總數就為:5*5*64*128=204800,如果這裡先經過一個1*1*32的通道進行降維,那麼參數總量為:1*1*32*64+5*5*32*128=104448,這樣減小了幾乎一半的參數,如果通道數更多,那麼減小的參數會更多。所以最終得到了如下模型:
上圖是goognet論文中給出的圖,前面兩個softmax是為了避免梯度消失而加上去的,在訓練把這兩個loos加到一起來進行訓練,測試的時候,這兩塊會被去掉。
隨後google的大佬們覺得這個不太好,所以又進行了更為深入的研究,在V2當中提出了著名的BN演算法,加速了網路的收斂。這篇在優化方法我再詳細介紹吧。
10.Iception V3
在之前的基礎上,google又提出了V3,V3是想要尋找一種既可以提高網路深度,又能發揮計算性能的方式,在V3當中,google提出了一些設計技巧,這些技巧沒有太強的理論依據,大多來自於實驗:
1避免表達的瓶頸,也就是說一開始不要讓太多信息流失,逐漸縮小特徵圖尺寸的同時也要逐漸擴大輸出的通道數
2. 高維度能夠很更容易在網路的局部進行處理。在卷積網路結構中,增加非線性能夠使得更多的特徵解耦合。從而使的網路訓練速度更快。
3.可以在低維空間進行空間信息匯總,而無需擔心信息丟失,推測是因為如果採用空間聚合,則相鄰的位置的信息具有強相關性,即使進行了降維,也不會帶來太多的損失,並且維數的降低,也能夠加速網路學習。
4.網路深度和寬度的平衡。Google認為提升網路深度可以提高網路輸出質量,增加寬度(增加濾波器數量)可以在同等質量達到最佳水平。
更加GoogleNet V1的經驗在一個網路中,我們可以推測在低層特徵被激活之前,他們是高度相關的,所以這時候可以對特徵進行刪減,而不會對輸出造成太多損失。這裡他們進一步討論如何降低參數,因為卷積的本質其實就是對應點和權重相乘,乘法是能夠進行因式分解的,因此可以通過因式分解來降低參數量。(感覺有點牽強)根據感知野的變化規律,我們可以知道,用兩個3*3的卷積核串聯,相當於一個5*5的卷積核,而且參數更少。
這樣就完了?並沒有,Google大佬們還在進一步探討,既然5*5可以用兩個3*3來替換,那麼3*3能不能再拆分成更小的?當然是可以的,於是用1*3和3*1的卷積核,這就可以獲得3*3的感知野了。這裡他們也討論了為什麼不拆成2*2的兩個串聯,因為2個2*2的需要8個參數,而1*3和3*1隻需要6個參數,所以更加節省計算。
在V3之後還有V4,不過是結合ResNet網路的,可以先看一下ResNet。
11.Inception V4
V4引入了ResNet,把resnet作為一個子模塊嵌入到了原來的模型當中,在論文中他們放出了通過不同基礎組件所獲得的兩個版本。整個方案框架和各個子模塊如圖所示:
這篇文章的一個主要結論:Residual Net可以加速收斂,用Inception結構也可以達到相同的性能。縱觀Google Inception系列其實是在做因式分解。
五、集成路線
12.Resnet
隨著網路的加深,網路越來越難訓練,這裡面有兩個比較關鍵的問題:一個是梯度消失和梯度爆炸的問題,另一個就是退化問題(隨著網路加深,精度逐漸飽和,然後迅速退化)。梯度消失和梯度爆炸的問題已經可以通過BN這一類方法去優化,但是這個退化問題,它並不是由於過擬合造成的,而是由於難以優化所造成的。假設一個較淺的網路已經學到了一個參數,那麼我一個比他更深的網路,就算我什麼都不學,只是做一個恆等的映射,精度也應該和它持平才對,這也就說明了傳統的網路難以去學習恆等映射這個關係。在訓練的過程中,傳統的神經網路希望去學習一種理想映射,即x→H(x),但是現在這個映射不好學(至少恆等映射它是很難學的),作者就提出,我現在不學習這個映射,轉而學習輸入與輸出之間的插值這個映射,也就是x→F(x)=H(x)-x,只要我們通過不斷學習參數,獲得F(x),就能去逼近H(x)(這裡其實就是把原來需要學習的東西拆成了兩部分,我們只去學習其中的一部分,從理論上來看,應該是會比以前要好學一些)作者通過實驗證明了殘差函數一般會有較小的響應波動,表明恆等映射是一個合理的預處理。
這樣做其實還帶來了一個好處就是,梯度便於回傳,還記得GoogleNet為了能夠使梯度回傳,加了三個損失函數嗎?也就是要找近路幫助梯度回傳,在ResNet之前Schmidhuber大佬,也就是LSTM之父,曾經提出過Higway Network,原理和ResNet比較接近,它是引入了一種類似於LSTM的門機制,保留一定的原始輸入,這樣前面的一層就能夠獲得一定比例的不經過非線性變換的信息,直接傳輸到下一層。ResNet比這個還要乾脆一點,直接抄近道。
現在假定需要求的映射輸出為 ,輸入與輸出之間的殘差 ,在學的殘差 之後,便能獲得 ,這也就是殘差網路名字的來源。
如果淺層的學習已經和我們期望輸出完全一致的時候,可以直接令F為0,也就是恆等變換,如果有差異就通過F去修正它。假如優化目標函數是逼近一個恆等映射, 而不是0映射, 那麼學習找到對恆等映射的擾動會比重新學習一個映射函數要容易。往往我們不可能是恆等映射,因為後面的層總會學到一些特徵,但是它至少保證了,與淺層網路具有相同的擬合能力,而不會出現網路退化問題。
下圖是整個ResNet的網路模型結構:
如果輸入維度和輸出維度一致,我們可以直接相加,但是如果不一致怎麼辦呢?這裡作者提供了兩個思路:第一個把缺少的維度直接添加0,另一種就是通過1*1的卷積來令其輸出維度一致。但是為了減小參數,這裡作者提出了這裡先通過1*1的卷積模塊把輸入進行一個線性加權,然後降維成64通道,經過3*3的卷積之後,再通過1*1的卷積模塊還原為256通道。
ResNet效果為什麼這麼好,其實還可以從集成學習的觀點來看待。Serge Belongie等人在NIPS上面發了一篇文章討論過這個問題,他們發現ResNet其實並不深,本質上是一群淺層網路的集合。
一個擁有三個Block的ResNet(左邊)可以展開為右邊的形式。信息傳輸的路徑多了,所以準確度也就想用的要高一些,就算有些子網路學不好,還有其他網路嘛!
13.Identity Mappings in Deep Residual Networks(ResNet增強版)
這篇文章是ResNet的增強版,也是何凱明大佬的作品,它通過探究恆等映射來使網路變得更加容易訓練,其實就是研究如何把梯度更好的回傳回去。原來是將兩個先相加,再通過激活函數,這樣求導的時候,就會先經過一層激活函數,以relu激活函數為例,小於0的部分就沒有了梯度,現在我們為了要讓這部分更好的回傳回去,所以我們可以調整一下,直接把通過短路連接不經過激活函數,與經過卷積的直接相加,這樣就能夠保證梯度可以全部回傳到輸入。(參考:http://blog.csdn.net/shwan_ma/article/details/78163921)根據殘差模塊的設計,我們可以得到下式:
令 即可得到:
把這個遞推公式展開即可得到:
從這個公式,至少能夠獲得兩個比較有用的信息:
1) 任意的一層 都可以用淺層的 和它到層 的殘差表示
2)最後一層的輸出是原始輸入與所有層的殘差的總和(與boosting比較類似)。
現在為了保證來自原始的輸入和經過卷積之後的輸入在性質上是一致的,我們就需要對卷積的部分模塊進行一下調整。作者通過實驗嘗試了好幾種結構,具體如下,最後選擇了一種:
14.ResNeXt
ResNeXt也是何凱明大佬的一篇文章,這篇文章的中心思想就是將卷積通道分組,其實傳統的也就是只有一組。神經網路提高精度主要通過兩個辦法,一個是加深網路,一個就是加寬網路,但是這樣帶來了更多的超參數,因此作者提出了一種可以提高精度還能降低超參數的網路結構。這個結構其實和Inception有點類似(拆分-變換-合併)。
作者在文中提到了一個新名詞——基數(cardinality),用來表示一組變換的大小(the size of the set of transformations),其實就是將通道進行分組,具體操作如下圖所示:
上面三種是等價的,從圖b來看,和Inception是很像的,不同之處在於每一個block的拓撲結構都一樣,這樣就省去了很多超參數。這就是整個的核心思想,其實想一想AlexNet也有分組啊,不過當時只是分了兩組,現在分了32組。通過在空間維度對網路進行分解,減少了冗餘,原來每一層的每個通道與上一層所有通道都發生了關聯,但是現在只和組內的通道發生關聯,同時,這個也能夠集成多個單獨訓練的網路,提升準確率。
15.DenseNet
這篇文章是CVPR2017的BestPaper,整篇文章的思路就是把每一層都與其他所有層連接起來,思路很簡單,效果很棒!這篇文章當時好像投了三次,都沒中,結果投CVPR卻中了,還拿了一個BestPaper。我想絕大部分人看到這篇文章的時候都是:我擦,這也可以嗎?根據作者的解釋說他們之前提出過一個隨機深度網路來改善ResNet,也就是隨機丟掉一些層,發現可以顯著提升泛化性能。這個實驗啟發他們:神經網路其實並不一定要是一個遞進層級結構,也就是說網路中的某一層可以不僅僅依賴於緊鄰的上一層的特徵,而可以依賴於更前面層學習的特徵;還有就是ResNet網路存在冗餘。於是他們針對這兩點設計了DenseNet, 讓網路中的每一層都直接與其前面層相連,實現特徵的重複利用;同時把網路的每一層設計得特別「窄」,即只學習非常少的特徵圖(最極端情況就是每一層只學習一個特徵圖),達到降低冗餘性的目的.
這是整個DenseNet的網路結構,可以看到在每一個Block裡面,各層之間是相互連接的,每一層的輸入都包括了之前所有層的輸出,這些輸出通過concat連接在一起(ResNet是和),層內結構如下圖所示:
在每個Block之間,有一個過渡層,每個過渡層由BN層、1x1卷積層和2x2平均池化層組成,這個1*1的卷積主要是用來降維。這篇文章當中,作者提出了一個叫做增長速率的詞,其實也就是輸出的通道數。這裡把每經過一層的輸出通道數都進行固定,舉個例子:假定增長率為k,如果某一個block的輸入為w,那麼在l層的輸入就應該為w+k*(l-1)。這裡有一個解釋:每一層都可以和它所在的block中之前的所有特徵圖進行連接,使得網路具有了「集體知識」(collective knowledge)。可以將特徵圖看作是網路的全局狀態。每一層相當於是對當前狀態增加k(k為增長速率)個特徵圖。增長速率控制著每一層有多少信息對全局狀態有效。全局狀態一旦被寫定,就可以在網路中的任何地方被調用,而不用像傳統的網路結構那樣層與層之間的不斷重複。
作者在DenseBlock中還引入了一個1*1的卷積,也是用來降維,作者發現這種對densenet極為有效,因此作者將具有BN-ReLU-Conv(1x1)-BN-ReLU-Conv(3x3)的結構稱為DenseNet-B。如果同時具有過渡層的1*1卷積降維,在block內部也有1*1的卷積降維,那麼這個就稱為DenseNet-BC
16.Xception
這是CVPR2017年的一篇論文,它是針對Inception V3的一個改進,提出了深度可分離。但是這個實現過程卻和ResNeXt有點類似,其實就是把整個分到了極致,每一個組只有一個通道。根據Inception背後的理念,認為卷積其實是一個既要學習空間相關性又要學習通道相關性的問題,通過將這兩個相關性進行分離,能夠使學習過程更有效。首先通過1*1的卷積核來提取數據的跨通道相關性,然後再在各個輸出上面學習空間相關性。(部分參考:Xception演算法詳解 - CSDN博客)我們來看看如何從Inception一步步獲得Xception.
去掉平均池化,再把所有的卷積都變成3*3的卷積核:
現在有3個1*1的卷積核,1*1的卷積核能夠把通道相關性提取出來,簡化一下把這三個卷積核合併為一個卷積核:
由上圖作者產生了這樣一個想法,上面三組的通道之間是不能相互影響的,也就是上面的三組已經達到了通道分離的要求,那麼如果把上面的組分得足夠多,我每一個組都只用一個通道,這樣所有通道之間都不再相關了。
根據以上思路,作者結合ResNet設計了Xception的網路結構,但是作者這裡使用的深度可分離卷積操作,深度可分卷積和Inception的極端版本很像,不過深度可分卷積是先進行單通道卷積操作,再進行1*1的融合:
根據上述思路設計的網路結構如上,不過需要注意一下:
1.操作順序:深度可分卷積一般(例如在TensorFlow中)先進行通道的空間卷積,然後進行1×1卷積,而Inception首先進行1×1卷積,這一個沒有太大的影響。
2.上個操作後是否進行非線性操作:Inception中兩個操作後都使用ReLU進行非線性激活,而深度可分卷積不使用。作者通過實驗對比發現在depthwise separable convolution前後兩部分操作之間不加入激活函數,效果反而比加了激活函數要好,作者推測可能是因為只有單獨一個通道,對單通道加激活函數容易丟失特徵。
這篇文章思路就在於把原來的空間和通道之間的相關性進行了分離,幫助網路更好的學習。
17.SENet
這是2017年ImageNet挑戰賽的冠軍,也是最後一屆冠軍。根據作者的說法,很多工作都是在空間維度進行的操作,如Inception結構中嵌入了多尺度信息,聚合多種不同感受野上的特徵來獲得性能增益;在Inside-Outside網路中考慮了空間中的上下文信息;還有將Attention機制引入到空間維度上等等。但是對通道的關注還比較少,所以他們從特徵通道這個層面去著手來蓋上性能。(我覺得ResNeXt、shuffle Net,Xception這些其實都是在從特徵的通道層面著手去進行的,這可能會是一個趨勢吧)具體怎麼去做呢?希望顯式地建模特徵通道之間的相互依賴關係。其實就是希望讓機器自己去學習各個通道的權重,這個權重可以用來表示各個通道之間的重要程度。既然是權重那麼肯定就是一個實數,也就是說作者希望最後輸出的是一個n*1的向量,n是通道數,既然要用到權重,自然而然的就會想到LSTM裡面的門機制,用一個sigmoid函數就可以獲得每個通道的權重。那麼在sigmoid函數之前,就必須能夠用一個數來表示一個通道,這個數能夠表示這個通道也就是具有全局的感受野,所以先對每一個通道進行全局池化,獲得一個數,然後通過全連接網路的形式去對數據進行學習,這樣也就獲得了整個網路的架構,這個網路架構可以作為任何一個大的網路架構的一個子模塊嵌入,具體如下:
在這裡為什麼要用兩層全連接神經網路,一個先降到1/16,然後再升回來,作者解釋到:兩層具有更好的非線性,可以更好的擬合通道之間的複雜相關性,同時也能極大的減少參量和計算量。
六、輕量化網路
18.MoblieNet
MobileNet和Xception其實兩者的思想都是一樣的,都是用過將通道相關性和空間相關性進行分離,兩者的不同在於Xception主要在於提高精度,而MobileNet則主要側重壓縮模型。首先,我們來看一下,為什麼採用把通道和空間分離能夠減小參數個數:
傳統的卷積運算:假定卷積核大小為 ,輸入為M通道,大小為 ,使用N個卷積核(N個輸出)的運算量(有padding,stride=0)
卷積是在原圖像進行滑動,每個點都會被計算,所以一個卷積核只滑動一個通道是 有M個通道N個卷積核,所以再相乘。
現在先用 的卷積核去提取每一個通道的空間相關性,計算量為
再用先用1*1的卷積核去進行通道相關性提取,計算量為
整體的計算量:
兩者一除,則:
MobileNet的計算優勢相當明顯。
網路結構設計
傳統的3D卷積常見的使用方式如下圖左側所示,deep-wise卷積的使用方式如下圖右邊所示(這裡有個疑問?Xception作者說單通道卷積最好不引入激活函數,為什麼這裡還引入了???知乎上網友@xfanplus 給了我解答,我覺得還是有一定的道理:在Xception裡面depthwise之後的1*1是用來升維的,低維到高維的變換本來就是一個欠信息映射過程,如果再用relu丟失掉一部分信息,就更難了;而mobilenet的depthwise之後的1*1是用來降維的,高維到低維本來會壓縮信息,所以這裡用ReLu影響不大)(參考:xfanplus:如何評價mobilenet v2 ?)
作者又提出,我們可以根據需求對Mobile Net進行瘦身,給出了兩個超參數:
Width Multiplier:就是按比例減少通道數,Resolution Multiplier:按比例縮小特徵圖尺寸
19.Mobile Net V2
這是一個針對MobileNet的改進版,其實就是引入了shortcut,但是直接引入殘差會有點問題,所以就做了兩個改進:1.引入一個逆殘差模塊(Inverted Residual block),先升維獲取更多特徵,再降維,這是因為後面提取的其實是空間信息,要是壓縮太多了,對空間信息的損失也就比較大,所以這裡就先升維。2.去掉了通道數少的層輸出後的非線性激活函數,保留特徵的多樣性,這是因為減小通道數是為了降維使用的,本來降維就會損失一部分信息,再用ReLu函數的話就會損失更大的信息了。同時這裡考慮到會降維,所以就用ReLU6作為非線性變換,因為它在與低精度計算一起使用時具有很強的魯棒性(因為是針對移動端的,所以運算的時候是低精度的,mobileNetV1也是採用這個激活函數)。(參考:如何評價mobilenet v2 ?)
對於第二點,為什麼能夠降維?作者指出,根據流形具有低秩的特性,也就是它存在於一個低維的子空間裡面,所以我們可以對它進行降維。降維之後不用非線性激活是因為,如果使用非線性激活,會損失流形的一部分信息。
利用MxN的矩陣B將張量(2D,即N=2)變換到M維的空間中,通過ReLU後concat(y=ReLU(Bx)),再用此矩陣之逆恢復原來的張量。可以看到,當M較小時,恢復後的張量坍縮嚴重,M較大時則恢復較好。回到作者的思路上面來:根據作者這個思路,其實整個模塊就可以出來了:
1*1ConV->ReLu6->DepthWise->ReLu6->1*1ConV->Add
作者這裡提到了當stride為2的時候,尺寸不一樣,所以沒有shortcut,結構如下:
在這其中t是網路擴張的倍數,也就是第一個1*1卷積之後通道數為以前的t倍,c為輸出的通道數,n表示該模塊重複的次數,s是stride。表格裡面有一些錯誤,第一個在s的第5行,這裡如果為2的話,下一行就應該是14.另外,作者在論文中說有共計採用19個bottleneck,但是這裡只有17個。不知道是不是筆誤。
20.ShuffleNet
這篇論文的思想是還是延續稀疏設計的理念,作者通過分析Xception和ResNeXt,發現這兩種結構通過卷積核拆分雖然計算複雜度均較原始卷積運算有所下降,但是1*1的卷積卻佔了不少計算量。於是作者提出了一個通道混聯的思路來達到通過1*1獲取通道之間信息的效果,減小了計算量。首先作者還是延續了ResNeXt的思路,畢竟是何凱明的工作嘛,孫劍肯定還是比較看重的,採用了分組卷積的思路,同時為了打破組與組之間沒有通道信息交互的缺點,在分組卷積經過1*1之後充分融合了組內的通道特性之後,再把通道混聯,重新生成通道做3*3的depthwise,然後再把各組經過1*1變換為輸出通道。
作者就是通過不斷的堆疊Shuffle單元得到ShuffleNet,作者在文中給出了具體的演化過程:
圖a是一個帶有depthwise的bottleck單元,在圖a的基礎上,把1*1的卷積換成分組卷積,然後再引入一個shullfe操作,就得到了圖b,(注意這裡經過depthwise之後也沒有激活函數),在shortcut引入一個3*3的平均池化,同時為了獲得更多的通道,這裡採取了concat的操作。這是按作者論文中來說的,但是我覺得其實直接就可以從ResNeXt來推導可能會更好。當然ResNeXt也是來自於ResNet,所以也沒什麼問題。
整個網路結構圖如下:
我們來看看這個混聯操作具體怎麼實現(參考:http://blog.csdn.net/u011974639/article/details/79200559)這裡假設有g組,每一組n個通道,首先將g*n進行reshape為g*n的矩陣,然後再將這個矩陣展開,每隔n個相連。
附上所有論文
鏈接:https://pan.baidu.com/s/1p-CY483sdZuM88tTHByt8g 密碼:41ij
推薦閱讀:
TAG:深度學習DeepLearning | 人工智慧 | 卷積神經網路CNN |