0
本文作者: 奕欣 | 2017-08-02 10:05 | 專題:CVPR 2017 |
雷鋒網(wǎng) AI 科技評論按:CVPR 2017上,康奈爾大學(xué)博士后黃高博士(Gao Huang)、清華大學(xué)本科生劉壯(Zhuang Liu)、Facebook 人工智能研究院研究科學(xué)家 Laurens van der Maaten 及康奈爾大學(xué)計算機(jī)系教授 Kilian Q. Weinberger 所作論文《Densely Connected Convolutional Networks》當(dāng)選 CVPR 2017 最佳論文,與蘋果的首篇公開論文《Learning From Simulated and Unsupervised Images through Adversarial Training》共獲這一殊榮。
在大會期間,雷鋒網(wǎng) AI 科技評論第一時間與獲獎?wù)撐淖髡唿S高博士及劉壯取得聯(lián)系,以下為兩位作者對 DenseNet 的詳細(xì)介紹及常見疑問解答,雷鋒網(wǎng) AI 科技評論做了不改動原意的編輯和整理。
DenseNet 是一種具有密集連接的卷積神經(jīng)網(wǎng)絡(luò)。在該網(wǎng)絡(luò)中,任何兩層之間都有直接的連接,也就是說,網(wǎng)絡(luò)每一層的輸入都是前面所有層輸出的并集,而該層所學(xué)習(xí)的特征圖也會被直接傳給其后面所有層作為輸入。下圖是 DenseNet 的一個示意圖。
如果記第 l 層的變換函數(shù)為 H_l(通常對應(yīng)于一組或兩組 Batch-Normalization,ReLU 和 Convolution 的操作),輸出為 x_l,那么我們可以用一個非常簡單的式子描述 DenseNet 每一層的變換:
x_l = H_l([x_0, x_1, …, x_{l-1}])
可以看到,DenseNet 的思想非常簡單,從理解到實現(xiàn)都不難(代碼已經(jīng)開源,并且 GitHub 上有用各種框架寫的第三方實現(xiàn))??赡芎芏嗳烁P(guān)心的問題是為什么要提出 DenseNet,它有什么用,為什么會有用以及怎么把它用好。
DenseNet 的想法很大程度上源于我們?nèi)ツ臧l(fā)表在 ECCV 上的一個叫做隨機(jī)深度網(wǎng)絡(luò)(Deep networks with stochastic depth)工作。當(dāng)時我們提出了一種類似于 Dropout 的方法來改進(jìn)ResNet。我們發(fā)現(xiàn)在訓(xùn)練過程中的每一步都隨機(jī)地「扔掉」(drop)一些層,可以顯著的提高 ResNet 的泛化性能。這個方法的成功至少帶給我們兩點啟發(fā):
首先,它說明了神經(jīng)網(wǎng)絡(luò)其實并不一定要是一個遞進(jìn)層級結(jié)構(gòu),也就是說網(wǎng)絡(luò)中的某一層可以不僅僅依賴于緊鄰的上一層的特征,而可以依賴于更前面層學(xué)習(xí)的特征。想像一下在隨機(jī)深度網(wǎng)絡(luò)中,當(dāng)?shù)?l 層被扔掉之后,第 l+1 層就被直接連到了第 l-1 層;當(dāng)?shù)?2 到了第 l 層都被扔掉之后,第 l+1 層就直接用到了第 1 層的特征。因此,隨機(jī)深度網(wǎng)絡(luò)其實可以看成一個具有隨機(jī)密集連接的 DenseNet。
其次,我們在訓(xùn)練的過程中隨機(jī)扔掉很多層也不會破壞算法的收斂,說明了 ResNet 具有比較明顯的冗余性,網(wǎng)絡(luò)中的每一層都只提取了很少的特征(即所謂的殘差)。實際上,我們將訓(xùn)練好的 ResNet 隨機(jī)的去掉幾層,對網(wǎng)絡(luò)的預(yù)測結(jié)果也不會產(chǎn)生太大的影響。既然每一層學(xué)習(xí)的特征這么少,能不能降低它的計算量來減小冗余呢?
DenseNet 的設(shè)計正是基于以上兩點觀察。我們讓網(wǎng)絡(luò)中的每一層都直接與其前面層相連,實現(xiàn)特征的重復(fù)利用;同時把網(wǎng)絡(luò)的每一層設(shè)計得特別「窄」,即只學(xué)習(xí)非常少的特征圖(最極端情況就是每一層只學(xué)習(xí)一個特征圖),達(dá)到降低冗余性的目的。這兩點也是 DenseNet 與其他網(wǎng)絡(luò)最主要的不同。需要強(qiáng)調(diào)的是,第一點是第二點的前提,沒有密集連接,我們是不可能把網(wǎng)絡(luò)設(shè)計得太窄的,否則訓(xùn)練會出現(xiàn)欠擬合(under-fitting)現(xiàn)象,即使 ResNet 也是如此。
省參數(shù)。在 ImageNet 分類數(shù)據(jù)集上達(dá)到同樣的準(zhǔn)確率,DenseNet 所需的參數(shù)量不到 ResNet 的一半。對于工業(yè)界而言,小模型可以顯著地節(jié)省帶寬,降低存儲開銷。
省計算。達(dá)到與 ResNet 相當(dāng)?shù)木?,DenseNet 所需的計算量也只有 ResNet 的一半左右。計算效率在深度學(xué)習(xí)實際應(yīng)用中的需求非常強(qiáng)烈,從本次 CVPR 會上大家對模型壓縮以及 MobileNet 和 ShuffleNet 這些工作的關(guān)注就可以看得出來。最近我們也在搭建更高效的 DenseNet,初步結(jié)果表明 DenseNet 對于這類應(yīng)用具有非常大的潛力,即使不用 Depth Separable Convolution 也能達(dá)到比現(xiàn)有方法更好的結(jié)果,預(yù)計在近期我們會公開相應(yīng)的方法和模型。
另外,我們還提出了一個可實現(xiàn)自適應(yīng)推理的多尺度 DenseNet,用于提高深度學(xué)習(xí)模型的推理效率。這個方法的主要思想是用淺層的特征來預(yù)測相對「簡單」的圖片,而只用深層的特征來預(yù)測比較「難」的圖片。由于很多實際應(yīng)用中,簡單的圖片占有較大的比例,而它們并不需要非常深的模型也能被正確預(yù)測,因此這種自適應(yīng)推理方法可以有效的降低深度模型推理時的平均計算開銷,而不降低精度。感興趣的讀者請關(guān)注我們的 arXiv 論文 《Multi-Scale Dense Convolutional Networks for Efficient Prediction》(https://arxiv.org/abs/1703.09844),代碼參見 https://github.com/gaohuang/MSDNet。
抗過擬合。DenseNet 具有非常好的抗過擬合性能,尤其適合于訓(xùn)練數(shù)據(jù)相對匱乏的應(yīng)用。這一點從論文中 DenseNet 在不做數(shù)據(jù)增強(qiáng)(data augmentation)的 CIFAR 數(shù)據(jù)集上的表現(xiàn)就能看出來。例如不對 CIFAR100 做數(shù)據(jù)增強(qiáng),之前最好的結(jié)果是 28.20% 的錯誤率,而 DenseNet 可以將這一結(jié)果提升至 19.64%。對于 DenseNet 抗過擬合的原因有一個比較直觀的解釋:神經(jīng)網(wǎng)絡(luò)每一層提取的特征都相當(dāng)于對輸入數(shù)據(jù)的一個非線性變換,而隨著深度的增加,變換的復(fù)雜度也逐漸增加(更多非線性函數(shù)的復(fù)合)。相比于一般神經(jīng)網(wǎng)絡(luò)的分類器直接依賴于網(wǎng)絡(luò)最后一層(復(fù)雜度最高)的特征,DenseNet 可以綜合利用淺層復(fù)雜度低的特征,因而更容易得到一個光滑的具有更好泛化性能的決策函數(shù)。實際上,DenseNet 的泛化性能優(yōu)于其他網(wǎng)絡(luò)是可以從理論上證明的:去年的一篇幾乎與 DenseNet 同期發(fā)布在 arXiv 上的論文(AdaNet: Adaptive Structural Learning of Artificial Neural Networks)所證明的結(jié)論(見文中 Theorem 1)表明類似于 DenseNet 的網(wǎng)絡(luò)結(jié)構(gòu)具有更小的泛化誤差界。
這是一個很多人都在問的問題,因為「密集連接」這個詞給人的第一感覺就是極大的增加了網(wǎng)絡(luò)的參數(shù)量和計算量。但實際上 DenseNet 比其他網(wǎng)絡(luò)效率更高,其關(guān)鍵就在于網(wǎng)絡(luò)每層計算量的減少以及特征的重復(fù)利用。DenseNet 的每一層只需學(xué)習(xí)很少的特征,使得參數(shù)量和計算量顯著減少。比如對于 ImageNet 上的模型,ResNet 在特征圖尺寸為 7x7 的階段,每個基本單元(包含三個卷積層)的參數(shù)量為 2048x512x1x1+512x512x3x3+512x2048x1x1=4.5M,而 DenseNet 每個基本單元(包含兩個卷積層,其輸入特征圖的數(shù)量一般小于 2000)的參數(shù)量約為 2000x4x32x1x1 + 4x32x32x3x3 = 0.26M,大幅低于 ResNet 每層的參數(shù)量。這就解釋了為什么一個 201 層的 DenseNet 參數(shù)量和計算量都只有一個 101 層 ResNet 的一半左右。
還有一個自然而然的問題就是,這么多的密集連接,是不是全部都是必要的,有沒有可能去掉一些也不會影響網(wǎng)絡(luò)的性能?論文里面有一個熱力圖(heatmap),直觀上刻畫了各個連接的強(qiáng)度。從圖中可以觀察到網(wǎng)絡(luò)中比較靠后的層確實也會用到非常淺層的特征。
via arXiv
我們還做過一些簡單的實驗,比如每一層都只連接到前面最近的 m 層(例如 m=4),或者奇(偶)數(shù)層只與前面的偶(奇)數(shù)層相連,但這樣簡化后的模型并沒有比一個相應(yīng)大小的正常 DenseNet 好。當(dāng)然這些都只是一些非常初步的嘗試,如果采用一些好的剪枝(prune)的方法,我覺得 DenseNet 中一部分連接是可以被去掉而不影響性能的。
不少人跟我們反映過 DenseNet 在訓(xùn)練時對內(nèi)存消耗非常厲害。這個問題其實是算法實現(xiàn)不優(yōu)帶來的。當(dāng)前的深度學(xué)習(xí)框架對 DenseNet 的密集連接沒有很好的支持,我們只能借助于反復(fù)的拼接(Concatenation)操作,將之前層的輸出與當(dāng)前層的輸出拼接在一起,然后傳給下一層。對于大多數(shù)框架(如 Torch 和 TensorFlow),每次拼接操作都會開辟新的內(nèi)存來保存拼接后的特征。這樣就導(dǎo)致一個 L 層的網(wǎng)絡(luò),要消耗相當(dāng)于 L(L+1)/2 層網(wǎng)絡(luò)的內(nèi)存(第 l 層的輸出在內(nèi)存里被存了 (L-l+1) 份)。
解決這個問題的思路其實并不難,我們只需要預(yù)先分配一塊緩存,供網(wǎng)絡(luò)中所有的拼接層(Concatenation Layer)共享使用,這樣 DenseNet 對內(nèi)存的消耗便從平方級別降到了線性級別。在梯度反傳過程中,我們再把相應(yīng)卷積層的輸出復(fù)制到該緩存,就可以重構(gòu)每一層的輸入特征,進(jìn)而計算梯度。當(dāng)然網(wǎng)絡(luò)中由于 Batch Normalization 層的存在,實現(xiàn)起來還有一些需要注意的細(xì)節(jié)。為此我們專門寫了一個技術(shù)報告(Memory-Efficient Implementation of DenseNets, https://arxiv.org/pdf/1707.06990.pdf)介紹如何提升 DenseNet 對內(nèi)存的使用效率,同時還提供了 Torch, PyTorch, MxNet 以及 Caffe 的實現(xiàn),代碼參見:
Torch implementation: https://github.com/liuzhuang13/DenseNet/tree/master/models
PyTorch implementation: https://github.com/gpleiss/efficient_densenet_pytorch
MxNet implementation: https://github.com/taineleau/efficient_densenet_mxnet
Caffe implementation: https://github.com/Tongcheng/DN_CaffeScript
新的實現(xiàn)極大地減小了 DenseNet 在訓(xùn)練時對顯存的消耗,比如論文中 190 層的 DenseNet 原來幾乎占滿了 4 塊 12G 內(nèi)存的 GPU,而優(yōu)化過后的代碼僅需要 9G 的顯存,在單卡上就能訓(xùn)練。
另外就是網(wǎng)絡(luò)在推理(或測試)的時候?qū)?nèi)存的消耗,這個是我們在實際產(chǎn)品中(尤其是在移動設(shè)備上)部署深度學(xué)習(xí)模型時最關(guān)心的問題。不同于訓(xùn)練,一般神經(jīng)網(wǎng)絡(luò)的推理過程不需要一直保留每一層的輸出,因此可以在每計算好一層的特征后便將前面層特征占用的內(nèi)存釋放掉。而 DenseNet 則需要始終保存所有前面層的輸出。但考慮到 DenseNet 每一層產(chǎn)生的特征圖很少,所以在推理的時候占用內(nèi)存不會多于其他網(wǎng)絡(luò)。
總的來說,訓(xùn)練 DenseNet 跟訓(xùn)練其他網(wǎng)絡(luò)沒有什么特殊的地方,對于訓(xùn)練 ResNet 的代碼,只需要把模型替換成 DenseNet 就可以了。如果想對 DenseNet 的模型做一些改進(jìn),我們有一些建議供參考:
每層開始的瓶頸層(1x1 卷積)對于減少參數(shù)量和計算量非常有用。
像 VGG 和 ResNet 那樣每做一次下采樣(down-sampling)之后都把層寬度(growth rate) 增加一倍,可以提高 DenseNet 的計算效率(FLOPS efficiency)。
與其他網(wǎng)絡(luò)一樣,DenseNet 的深度和寬度應(yīng)該均衡的變化,當(dāng)然 DenseNet 每層的寬度要遠(yuǎn)小于其他模型。
每一層設(shè)計得較窄會降低 DenseNet 在 GPU 上的運(yùn)算效率,但可能會提高在 CPU 上的運(yùn)算效率。
由于 DenseNet 不容易過擬合,在數(shù)據(jù)集不是很大的時候表現(xiàn)尤其突出。在一些圖像分割和物體檢測的任務(wù)上,基于 DenseNet 的模型往往可以省略在 ImageNet 上的預(yù)訓(xùn)練,直接從隨機(jī)初始化的模型開始訓(xùn)練,最終達(dá)到相同甚至更好的效果。由于在很多應(yīng)用中實際數(shù)據(jù)跟預(yù)訓(xùn)練的 ImageNet 自然圖像存在明顯的差別,這種不需要預(yù)訓(xùn)練的方法在醫(yī)學(xué)圖像,衛(wèi)星圖像等任務(wù)上都具有非常廣闊的應(yīng)用前景。
在圖像語義分割任務(wù)上,CVPR 2017 的一篇 workshop 文章 《The One Hundred Layers Tiramisu: Fully Convolutional DenseNets for Semantic Segmentation》 (https://arxiv.org/abs/1611.09326) 表明,基于 DenseNet 的全卷積網(wǎng)絡(luò)(FCN)模型在不需要預(yù)訓(xùn)練的情況下甚至可以達(dá)到比其他預(yù)訓(xùn)練方法更高的精度,并且比達(dá)到相同效果的其他方法的模型要小 10 倍。
同樣,在物體檢測任務(wù)上,我們即將發(fā)表在 ICCV 2017 上的工作也表明,基于 DenseNet 的檢測方法可以在不需要 ImageNet 預(yù)訓(xùn)練的情況下達(dá)到 state-of-the-art 的效果,并且模型參數(shù)相比較其他模型要少很多。這是目前為止第一個不用 ImageNet 預(yù)訓(xùn)練的基于深度學(xué)習(xí)的物體檢測系統(tǒng)。文章會在 8 月初放到 arxiv,敬請關(guān)注。
頭圖 via cognifyx,正文圖片由作者提供
雷峰網(wǎng)特約稿件,未經(jīng)授權(quán)禁止轉(zhuǎn)載。詳情見轉(zhuǎn)載須知。
本專題其他文章