DenseNet


發現yolo真是一個大雜燴,幾乎將所有的前沿技術都融合到一起了,CSP結構借鑒了DenseNet的想法,所以,開始啃DenseNet

摘自:https://www.leiphone.com/category/ai/0MNOwwfvWiAu43WO.html

補充:啃完之后發現不是CSP借鑒了DenseNet的想法,CSP只是一種思路,類似於FPN,可以與任何backbone進行融合,比如yolo中CSP其實是與Resunit融合在一起的…但啃都啃完了,基礎網絡總是要學的,何況DenseNet真的很了不起!

 DenseNet的基本結構

  DenseNet是一種具有密集連接的卷積神經網絡。在該網絡中,任何兩層之間都有直接的連接,也就是說,網絡每一層的輸入都是前面所有層輸出的並集,而該層所學習的特征圖也會被直接傳給其后面所有層作為輸入。下圖是DenseNet的一個示意圖。

 

  如果記第i層的變換函數為$H_i$(通常對於一組或兩組Batch-Normalization, ReLU和Convolution的操作),輸出為$x_i$,那么我們可以用一個非常簡單的式子描述DenseNet每一層的變換:

$x_i = H_i([x_0, x_1, ..., x_{i-1}])$

  可以看到,DenseNet的思想非常簡單,從理解到實現都不難(代碼已經開源,並且GitHub上有用各種框架寫的第三方實現)。可能很多人更關心的問題是為什么要提出DenseNet,它有什么用,為什么會有用以及怎么把它用好。

DenseNet是受什么啟發提出來的?

  DenseNet的想法很大程度上源於我們去年發表在ECCV上的一個叫做隨機深度網絡(Deep networks with stochastic depth)工作。當時我們提出了一種類似於Dropout的方法來改進ResNet。我們發現在訓練過程中的每一步都隨機的“扔掉”(drop)掉一些層,可以顯著的提高ResNet的泛化性能。這個方法的成功至少帶給我們兩點啟發:

  • 首先,它說明了神經網絡其實並以一定要是一個遞進層級結構,也就是說網絡中的某一層可以不僅僅依賴於緊鄰的上一層的特征,而可以依賴於更前面層學習的特征。想象一下在隨機深度網絡中,當第i層被扔掉之后,第i+1層就被直接練到了第i-1層;當第2到第i層都被扔掉之后,第i+1層就直接用到了第1層的特征。因此,隨機深度網絡其實可以看成一個具有隨機密集連接的DenseNet。
  • 其次,我們在訓練的過程中隨機扔掉很多層也不會破壞算法的收斂,說明了ResNet具有比較明顯的冗余性,網絡中的每一層都只提取了很少的特征(即所謂的殘差)。實際上,我們將訓練好的ResNet隨機的去掉幾層,對網絡的預測結果也不會產生太大的影響。既然每一層學習的特征這么少,能不能降低它的計算量來減小冗余呢?

 DenseNet的涉及正是基於以上兩點觀察。我們讓網絡中的每一層都直接與其前面層相連,實現特征的重復利用;同時把網絡的每一層實際得特別“窄”,即只學習非常少的特征圖(最極端情況就是每一層只學習一個特征圖),達到降低冗余性的目的。這兩點也是DenseNet與其他網絡最主要的不同。需要強調的是,第一點是第二點的前提,沒有密集鏈接,我們是不可能把網絡設計得太窄的,否則訓練會出現欠擬合(under-fitting)現象,即使ResNet也是如此。

DenseNet有什么優點?

  • 省參數:在ImageNet分類數據集上達到同樣的准確率,DenseNet所需的參數量不到ResNet的一半。對於工業界耳炎,小模型可以顯著的節省帶寬,降低存儲開銷。
  • 省計算:達到與ResNet相當的精度,DenseNet所需的計算量也只有ResNet的一半左右。計算效率在深度學習實際應用中的需求非常強烈,從本次 CVPR 會上大家對模型壓縮以及 MobileNet 和 ShuffleNet 這些工作的關注就可以看得出來。最近我們也在搭建更高效的 DenseNet,初步結果表明 DenseNet 對於這類應用具有非常大的潛力,即使不用 Depth Separable Convolution 也能達到比現有方法更好的結果,預計在近期我們會公開相應的方法和模型。另外,我們還提出了一個可實現自適應推理的多尺度 DenseNet,用於提高深度學習模型的推理效率。這個方法的主要思想是用淺層的特征來預測相對「簡單」的圖片,而只用深層的特征來預測比較「難」的圖片。由於很多實際應用中,簡單的圖片占有較大的比例,而它們並不需要非常深的模型也能被正確預測,因此這種自適應推理方法可以有效的降低深度模型推理時的平均計算開銷,而不降低精度。感興趣的讀者請關注我們的 arXiv 論文 《Multi-Scale Dense Convolutional Networks for Efficient Prediction》(https://arxiv.org/abs/1703.09844),代碼參見 https://github.com/gaohuang/MSDNet
  • 抗過擬合:DenseNet具有非常好的抗過擬合性能,尤其適合於訓練數據相對匱乏的應用。這一點從論文中 DenseNet 在不做數據增強(data augmentation)的 CIFAR 數據集上的表現就能看出來。例如不對 CIFAR100 做數據增強,之前最好的結果是 28.20% 的錯誤率,而 DenseNet 可以將這一結果提升至 19.64%。對於 DenseNet 抗過擬合的原因有一個比較直觀的解釋:神經網絡每一層提取的特征都相當於對輸入數據的一個非線性變換,而隨着深度的增加,變換的復雜度也逐漸增加(更多非線性函數的復合)。相比於一般神經網絡的分類器直接依賴於網絡最后一層(復雜度最高)的特征,DenseNet 可以綜合利用淺層復雜度低的特征,因而更容易得到一個光滑的具有更好泛化性能的決策函數。實際上,DenseNet 的泛化性能優於其他網絡是可以從理論上證明的:去年的一篇幾乎與 DenseNet 同期發布在 arXiv 上的論文(AdaNet: Adaptive Structural Learning of Artificial Neural Networks)所證明的結論(見文中 Theorem 1)表明類似於 DenseNet 的網絡結構具有更小的泛化誤差界。

密集連接不會帶來冗余嗎?

  這是一個很多人都在問的問題,因為「密集連接」這個詞給人的第一感覺就是極大的增加了網絡的參數量和計算量。但實際上 DenseNet 比其他網絡效率更高,其關鍵就在於網絡每層計算量的減少以及特征的重復利用。DenseNet 的每一層只需學習很少的特征,使得參數量和計算量顯著減少。比如對於 ImageNet 上的模型,ResNet 在特征圖尺寸為 7x7 的階段,每個基本單元(包含三個卷積層)的參數量為 2048x512x1x1+512x512x3x3+512x2048x1x1=4.5M,而 DenseNet 每個基本單元(包含兩個卷積層,其輸入特征圖的數量一般小於 2000)的參數量約為 2000x4x32x1x1 + 4x32x32x3x3 = 0.26M,大幅低於 ResNet 每層的參數量。這就解釋了為什么一個 201 層的 DenseNet 參數量和計算量都只有一個 101 層 ResNet 的一半左右。

  還有一個自然而然的問題就是,這么多的密集連接,是不是全部都是必要的,有沒有可能去掉一些也不會影響網絡的性能?論文里面有一個熱力圖(heatmap),直觀上刻畫了各個連接的強度。從圖中可以觀察到網絡中比較靠后的層確實也會用到非常淺層的特征。

 

  我們還做過一些簡單的實驗,比如每一層都只連接到前面最近的 m 層(例如 m=4),或者奇(偶)數層只與前面的偶(奇)數層相連,但這樣簡化后的模型並沒有比一個相應大小的正常 DenseNet 好。當然這些都只是一些非常初步的嘗試,如果采用一些好的剪枝(prune)的方法,我覺得 DenseNet 中一部分連接是可以被去掉而不影響性能的。

DenseNet特別耗費顯存?

  不少人跟我們反映過 DenseNet 在訓練時對內存消耗非常厲害。這個問題其實是算法實現不優帶來的。當前的深度學習框架對 DenseNet 的密集連接沒有很好的支持,我們只能借助於反復的拼接(Concatenation)操作,將之前層的輸出與當前層的輸出拼接在一起,然后傳給下一層。對於大多數框架(如 Torch 和 TensorFlow),每次拼接操作都會開辟新的內存來保存拼接后的特征。這樣就導致一個 L 層的網絡,要消耗相當於 L(L+1)/2 層網絡的內存(第 l 層的輸出在內存里被存了 (L-l+1) 份)。

   解決這個問題的思路其實並不難,我們只需要預先分配一塊緩存,供網絡中所有的拼接層(Concatenation Layer)共享使用,這樣 DenseNet 對內存的消耗便從平方級別降到了線性級別。在梯度反傳過程中,我們再把相應卷積層的輸出復制到該緩存,就可以重構每一層的輸入特征,進而計算梯度。當然網絡中由於 Batch Normalization 層的存在,實現起來還有一些需要注意的細節。為此我們專門寫了一個技術報告(Memory-Efficient Implementation of DenseNets, https://arxiv.org/pdf/1707.06990.pdf)介紹如何提升 DenseNet 對內存的使用效率,同時還提供了 Torch, PyTorch, MxNet 以及 Caffe 的實現,代碼參見:

   新的實現極大地減小了 DenseNet 在訓練時對顯存的消耗,比如論文中 190 層的 DenseNet 原來幾乎占滿了 4 塊 12G 內存的 GPU,而優化過后的代碼僅需要 9G 的顯存,在單卡上就能訓練。

  另外就是網絡在推理(或測試)的時候對內存的消耗,這個是我們在實際產品中(尤其是在移動設備上)部署深度學習模型時最關心的問題。不同於訓練,一般神經網絡的推理過程不需要一直保留每一層的輸出,因此可以在每計算好一層的特征后便將前面層特征占用的內存釋放掉。而 DenseNet 則需要始終保存所有前面層的輸出。但考慮到 DenseNet 每一層產生的特征圖很少,所以在推理的時候占用內存不會多於其他網絡。

使用 DenseNet 有什么需要注意的細節?

  總的來說,訓練 DenseNet 跟訓練其他網絡沒有什么特殊的地方,對於訓練 ResNet 的代碼,只需要把模型替換成 DenseNet 就可以了。如果想對 DenseNet 的模型做一些改進,我們有一些建議供參考:

  1. 每層開始的瓶頸層(1x1 卷積)對於減少參數量和計算量非常有用。
  2. 像VGG 和 ResNet 那樣每做一次下采樣(down-sampling)之后都把層寬度(growth rate) 增加一倍,可以提高 DenseNet 的計算效率(FLOPS efficiency)。(這句不太理解,為什么每做一次下采樣之后把層寬度增加一倍可以提高FLOPS efficiency呢?寬度增加確實更符合GPU並行運算方式可以提高運算速度,但下采樣和增加寬度有什么聯系么?是這樣的組合為了不丟失信息並提高速度么?但個人理解,這里的增加寬度純屬增加寬度,不是像YOLOV5的FOCUS層那樣切片操作呀~~~想不明白,請各位指點。謝謝!)
  3. 與其他網絡一樣,DenseNet 的深度和寬度應該均衡的變化,當然 DenseNet 每層的寬度要遠小於其他模型。
  4. 每一層設計得較窄會降低 DenseNet 在 GPU 上的運算效率,但可能會提高在 CPU 上的運算效率。

DenseNet用於圖像語義分割和物體檢測等視覺任務效果如何?

  由於 DenseNet 不容易過擬合,在數據集不是很大的時候表現尤其突出。在一些圖像分割和物體檢測的任務上,基於 DenseNet 的模型往往可以省略在 ImageNet 上的預訓練,直接從隨機初始化的模型開始訓練,最終達到相同甚至更好的效果。由於在很多應用中實際數據跟預訓練的 ImageNet 自然圖像存在明顯的差別,這種不需要預訓練的方法在醫學圖像,衛星圖像等任務上都具有非常廣闊的應用前景。

  在圖像語義分割任務上,CVPR 2017 的一篇 workshop 文章 《The One Hundred Layers Tiramisu: Fully Convolutional DenseNets for Semantic Segmentation》 (https://arxiv.org/abs/1611.09326) 表明,基於 DenseNet 的全卷積網絡(FCN)模型在不需要預訓練的情況下甚至可以達到比其他預訓練方法更高的精度,並且比達到相同效果的其他方法的模型要小 10 倍。

  同樣,在物體檢測任務上,我們即將發表在 ICCV 2017 上的工作也表明,基於 DenseNet 的檢測方法可以在不需要 ImageNet 預訓練的情況下達到 state-of-the-art 的效果,並且模型參數相比較其他模型要少很多。這是目前為止第一個不用 ImageNet 預訓練的基於深度學習的物體檢測系統。文章會在 8 月初放到 arxiv,敬請關注。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM