從DensNet到CliqueNet,解讀北大在卷積架構上的探索

思源發表於2018-05-23

卷積神經網路架構一直是計算機視覺領域的研究重點,很多分類、檢測和分割等任務都依賴於基本架構提供更好的效能。本文先概覽了經典的卷積網路架構及它們的優缺點,其次重點分析了 CVPR 去年的最佳論文 DenseNet 與今年北大等研究機構提出的 CliqueNet,這篇論文接收為 CVPR 2018 的 Orals/Spotlights。

近日,微軟亞洲研究院主辦了一場關於 CVPR 2018 中國論文分享會,機器之心在分享會中發現了一篇非常有意思的論文,它介紹了一種新型卷積網路架構,並且相比於 DenseNet 能抽取更加精煉的特徵。北大楊一博等研究者提出的這種 CliqueNet 不僅有前向的密集型連線,同時還有反向的密集型連線來精煉前面層級的資訊。根據楊一博向機器之心介紹的 CliqueNet 以及我們對卷積架構的瞭解,我們將與各位讀者縱覽卷積網路的演變。

卷積架構

很多讀者其實已經對各種卷積架構非常熟悉了,因此這一部分只簡要介紹具有代表性的卷積結構與方法。首先第一種當然是 Yann LeCun 在 1998 年提出的 LeNet-5,它奠定了整個卷積神經網路的基礎。正如 LeCun 在 LeNet-5 原論文中所說,卷積網路結合了三種關鍵性思想來確保模型對影象的平移、縮放和扭曲具有一定程度的不變性,這三種關鍵思想即區域性感受野、權重共享和空間/時間子取樣。其中區域性感受野表示卷積核只關注影象的區域性特徵,而權重共享表示一個卷積核在整張影象上都使用相同的權值,最後的子取樣即我們常用的池化操作,它可以精煉抽取的特徵。

從DensNet到CliqueNet,解讀北大在卷積架構上的探索

原論文:GradientBased Learning Applied to Document Recognition

上圖是 LeNet-5 架構,它疊加了兩個卷積層與池化層來抽取影象特徵,然後再將抽取的特徵傳入兩個全連線層以組合所有特徵並識別影象類別。雖然 LeNet-5 很早就提出來了,且架構和現在很多簡單的卷積網路非常相似,但當時可能限於計算資源和資料集等條件並沒有得到廣泛應用。

第一個得到廣泛關注與應用的卷積神經網路是 2012 年提出來的 AlexNet,它相比於 LeNet-5 最大的特點是使用更深的卷積網路和 GPU 進行並行運算。如下所示,AlexNet 有 5 個卷積層和 3 個最大池化層,它可分為上下兩個完全相同的分支,這兩個分支在第三個卷積層和全連線層上可以相互交換資訊。AlexNet卷積分為兩個分支主要是因為需要在兩塊老式 GTX580 GPU 上加速訓練,且單塊 GPU 無法為深度網路提供足夠的記憶體,因此研究者將網路分割為兩部分,並饋送到兩塊 GPU 中。

從DensNet到CliqueNet,解讀北大在卷積架構上的探索

原論文:ImageNet Classification with Deep Convolutional Neural Networks

AlexNet 還應用了非常多的方法來提升模型效能,包括第一次使用 ReLU 非線性啟用函式、第一次使用 Dropout 以及大量資料增強而實現網路的正則化。除此之外,AlexNet 還使用了帶動量隨機梯度下降、L2 權重衰減以及 CNN 的整合方法,這些方法現在都成為了卷積網路不可缺少的模組。

到了 2014 年,牛津大學提出了另一種深度卷積網路 VGG-Net,它相比於 AlexNet 有更小的卷積核和更深的層級。AlexNet 前面幾層用了 11*11 和 5*5 的卷積核以在影象上獲取更大的感受野,而 VGG 採用更小的卷積核與更深的網路提升引數效率。一般而言,疊加幾個小的卷積核可以獲得與大卷積核相同的感受野,而疊加小卷積核使用的引數明顯要少於一個大卷積核。此外,疊加小卷積核因為加深了卷積網路,能引入更強的非線性。

從DensNet到CliqueNet,解讀北大在卷積架構上的探索

原論文:VERY DEEP CONVOLUTIONAL NETWORKS FOR LARGE-SCALE IMAGE RECOGNITION

VGG-Net 的泛化效能較好,常用於影象特徵的抽取目標檢測候選框生成等。VGG 最大的問題就在於引數數量,VGG-19 基本上是引數量最多的卷積網路架構。VGG-Net 的引數主要出現在後面兩個全連線層,每一層都有 4096 個神經元,可想而至這之間的引數會有多麼龐大。

同樣在 2014 年,谷歌提出了 GoogLeNet(或 Inception-v1)。該網路共有 22 層,且包含了非常高效的 Inception 模組,它沒有如同 VGG-Net 那樣大量使用全連線網路,因此引數量非常小。GoogLeNet 最大的特點就是使用了 Inception 模組,它的目的是設計一種具有優良區域性拓撲結構的網路,即對輸入影象並行地執行多個卷積運算或池化操作,並將所有輸出結果拼接為一個非常深的特徵圖。因為 1*1、3*3 或 5*5 等不同的卷積運算與池化操作可以獲得輸入影象的不同資訊,並行處理這些運算並結合所有結果將獲得更好的影象表徵。

從DensNet到CliqueNet,解讀北大在卷積架構上的探索

原論文:Going Deeper with Convolutions

一般 Inception 模組的引數雖然少,但很多並行的卷積運算需要很多計算量。直接拼接不同的卷積運算會產生巨量的運算,因此修正的 Inception 模組每一個卷積分支都會先執行一個 1*1 的卷積將通道數大大減少,這也相當於對輸入資料進行降維而簡化運算。此外,GoogLeNet 中間多出來的兩個分類網路主要是為了向前面的卷積與 Inception 模組提供額外的梯度進行訓練。因為隨著網路的加深,梯度無法高效地由後向前傳,網路引數也就得不到更新。這樣的分支則能減輕深度網路的梯度傳播問題,但這種修補並不優美,也不能解決更深網路的學習問題。

最後,何愷明等人於 2015 年提出來的深度殘差網路驟然將網路深度由十幾二十層提升到上百層。ResNet 最大的特點即解決了反向傳播過程中的梯度消失問題,因此它可以訓練非常深的網路而不用像 GoogLeNet 那樣在中間新增分類網路以提供額外的梯度。根據 ResNet 原論文,設計的出發點即更深的網路相對於較淺的網路不能產生更高的訓練誤差,因此研究者引入了殘差連線以實現這樣的能力。

從DensNet到CliqueNet,解讀北大在卷積架構上的探索

原論文:Deep Residual Learning for Image Recognition

如上黑色曲線,ResNet 引入了殘差連線。在每一個殘差模組上,殘差連線會將該模組的輸入與輸出直接相加。因此在反向傳播中,根據殘差連線傳遞的梯度就可以不經過殘差模組內部的多個卷積層,因而能為前一層保留足夠的梯度資訊。此外,每一個殘差模組還可以如同 Inception 模組那樣新增 1×1 卷積而形成瓶頸層。這樣的瓶頸結構對輸入先執行降維再進行卷積運算,運算完後對卷積結果升維以恢復與輸入相同的維度,這樣在低維特徵上進行計算能節省很多計算量。

DenseNet

ResNet 雖然非常高效,但如此深的網路並不是每一層都是有效的。最近一些研究表明 ResNet 中的很多層級實際上對整體的貢獻非常小,即使我們在訓練中隨機丟棄一些層級也不會有很大的影響。這種卷積層和特徵圖的冗餘將降低模型的引數效率,並加大計算力的需求。為此,Gao Huang 等研究者提出了 DenseNet,該論文獲得了 CVPR 2017 的最佳論文。

DenseNet 的目標是提升網路層級間資訊流與梯度流的效率,並提高引數效率。它也如同 ResNet 那樣連線前層特徵圖與後層特徵圖,但 DenseNet 並不會像 ResNet 那樣對兩個特徵圖求和,而是直接將特徵圖按深度相互拼接在一起。DenseNet 最大的特點即每一層的輸出都會作為後面所有層的輸入,這樣最後一層將拼接前面所有層級的輸出特徵圖。這種結構確保了每一層能從損失函式直接訪問到梯度,因此可以訓練非常深的網路。

從DensNet到CliqueNet,解讀北大在卷積架構上的探索

原論文:Densely Connected Convolutional Networks

如上所示為 Dense Block 的結構,特徵圖 X_2 在輸入 X_0 與 X_1 的條件下執行卷積運算得出,同時 X_2 會作為計算 X_3 和 X_4 的輸入。一般對於 L 層的 DenseNet,第 l 層有 l 個輸入特徵圖和 L-l 個輸出特徵圖,因此它一共擁有 L(L+1)/2 個連線。這種密集連線型的網路也就形象地稱為 DenseNet 了。

此外,Gao Huang 等研究者在原論文表示 DenseNet 所需要的引數更少,因為它相對於傳統卷積網路不需要重新學習冗餘的特徵圖。具體來說,DenseNet 的每一層都有非常淺的特徵圖或非常少的卷積核,例如 12、24、32 等,因此能節省很多網路引數

又因為每一層輸出的特徵圖都比較淺,所以每一層都能將前面所有層級的特徵圖拼接為一個較深的特徵圖而作為輸入,這樣每一層也就複用了前面的特徵圖。特徵圖的複用能產生更緊湊的模型,且拼接由不同層產生的特徵圖能提升輸入的方差和效率。

形式化來說,若給定一張影象 x_0 饋送到 L 層的 DenseNet 中,且 H_l() 表示第 l 層包含卷積池化、BN 和啟用函式等的非線性變換,那麼第 l 層的輸出可以表示為 X_l。對於 DenseNet 的密集型連線,第 l 層的輸出特徵圖可以表示為:

從DensNet到CliqueNet,解讀北大在卷積架構上的探索

其中 [x_0, x_1, . . . , x_{−1}] 表示從 0 到 l-1 層產生的特徵圖,為了簡化計算,它們會按深度拼接為單個張量。在原論文的實現中,H_l() 為包含了三個模組的複合函式,即先執行批量歸一化和 ReLU 啟用函式,再執行 1 個 3×3 的卷積

上述方程若想將特徵圖按深度拼接,那麼所有特徵圖的尺寸就需要相等。一般常用的方法是控制卷積核的移動步幅或新增池化運算,DenseNet 將網路分為不同的 Dense Block,並在 Dense Block 之間調整特徵圖的大小。

從DensNet到CliqueNet,解讀北大在卷積架構上的探索

如上所示,密集連線塊之間的轉換層會通過卷積改變特徵圖深度,通過池化層改變特徵圖尺寸。在原論文的實現中,轉換層先後使用了批量歸一化、1×1 的逐點卷積和 2×2 的平均池化

此外,若 Dense Block 中的 H_l 輸出 k 張特徵圖,那麼第 l 層的輸入特徵圖就有 k_0 + k × (l - 1) 張,其中 k_0 為輸入影象的通道數。由於輸入特徵圖的深度或張數取決於 k,DenseNet 每一個卷積都有比較淺的特徵圖,即 k 值很小。在 ImageNet 中,DenseNet 的 k 值設為了 32。

不過儘管 k 值比較小,但在後面層級的卷積運算中,輸入的特徵圖深度還是非常深的。因此與 ResNet 的殘差模組和 GoogLeNet 的 Inception 模組一樣,DenseNet 同樣在 3×3 卷積運算前加入了 1×1 逐點卷積作為瓶頸層來減少輸入特徵圖的深度。因此我們可以將 H_l 由原版的 BN-ReLU-Conv(3×3) 修正為:BN-ReLU-Conv(1× 1)-BN-ReLU-Conv(3×3)。除了加入瓶頸層,DenseBlock 間的轉換層也可以通過 1×1 卷積減低特徵圖的維度。

以下表格是 DenseNet 在 ImageNet 資料集上所採用的架構,其中每個卷積層的卷積核數 k=32,「conv」層對應於原版 H_l 或新增了瓶頸層的 H_l。

從DensNet到CliqueNet,解讀北大在卷積架構上的探索

在實踐中,很多研究者都表示 DenseNet 的引數雖然少,但視訊記憶體佔用非常恐怖。這主要是因為大量的特徵圖拼接操作和 BN 運算結果都會佔用新的視訊記憶體,不過現在已經有研究者修改程式碼而降低視訊記憶體佔用。此外,DenseNet 的計算量也非常大,很難做到實時語義分割等任務。

CliqueNet

DenseNet 通過複用不同層級的特徵圖,減少了不同層間的相互依賴性,且最終的預測會利用所有層的資訊而提升模型魯棒性。但是 Yunpeng Chen 等研究者在論文 Dual Path Networks 中表示隨著網路深度的增加,DenseNet 中的密集型連線路徑會線性地增加,因此引數會急劇地增加。這就導致了在不特定優化實現程式碼的情況下需要消耗大量的 GPU 視訊記憶體。而在北大楊一博等研究者提出來的 CliqueNet 中,每個 Clique Block 只有固定通道數的特徵圖會饋送到下一個 Clique Block,這樣就大大增加了引數效率。

CliqueNet 最大的特點是其不僅有前傳的部分,同時還能根據後面層級的輸出對前面層級的特徵圖做優化。這種網路架構受到了迴圈結構與注意力機制的啟發,即卷積輸出的特徵圖可重複使用,經過精煉的特徵圖將注意更重要的資訊。在同一個 Clique 模組內,任意兩層間都有前向和反向連線,這也就提升了深度網路中的資訊流。

  • 論文:Convolutional Neural Networks with Alternately Updated Clique

  • 論文地址:https://arxiv.org/abs/1802.10419

  • 實現地址:https://github.com/iboing/CliqueNet

CliqueNet 的每一個模組可分為多個階段,但更高的階段需要更大的計算成本,因此該論文只討論兩個階段。第一個階段如同 DenseNet 那樣傳播,這可以視為初始化過程。而第二個階段如下圖所示每一個卷積運算的輸入不僅包括前面所有層的輸出特徵圖,同樣還包括後面層級的輸出特徵圖。第二階段中的迴圈反饋結構會利用更高階視覺資訊精煉前面層級的卷積核,因而能實現空間注意力的效果。

從DensNet到CliqueNet,解讀北大在卷積架構上的探索

如上所示在第一階段中,若輸入 0、1、2 號特徵圖的拼接張量卷積運算可得出特徵圖 3。在第二階段中,特徵圖 1 會根據第一階段輸出的 2、3、4 號拼接特徵圖計算得出,我們可將其稱為已更新特徵圖 1。第二階段的特徵圖 3 在輸入第一階段的輸出特徵圖 4 和已更新特徵圖 1、2 的情況下得出。

由此可以看出,每一步更新時,都利用最後得到的幾個特徵圖去精煉相對最早得到的特徵圖。因為最後得到的特徵圖相對包含更高階的視覺資訊,所以該方法用交替的方式,實現了對各個層級特徵圖的精煉。

Clique Block 中的第一階段比較好理解,與上文 Dense Block 的前向傳播相同。可能讀者對第二階段的傳播過程仍然有些難以理解,不過原論文中給出了一個很好的表示式來描述第 2 階段。對於第二階段中的第 i 層和第 k 個迴圈,交替更新的表示式為:

從DensNet到CliqueNet,解讀北大在卷積架構上的探索


其中 k >= 2,上面 Clique Block 的展開圖 k=2。W * X 表示卷積核在輸入特徵圖上做卷積運算,g 為非線性啟用函式。若 k=2,那麼第 i 層更新後的特徵圖 從DensNet到CliqueNet,解讀北大在卷積架構上的探索,可通過拼接前面層級(l<i)已更新的特徵圖 從DensNet到CliqueNet,解讀北大在卷積架構上的探索 和後面層級(m>i)前一個迴圈的特徵圖 從DensNet到CliqueNet,解讀北大在卷積架構上的探索得出。在這個式子中,加號和累加都表示按特徵圖深度的拼接運算。


如上所示有兩套卷積核,即階段 2 中的前向卷積運算與反向卷積運算。每一套卷積引數在不同階段中是共享的。

對於有五個卷積層的 Clique Block,傳播方式如下表所示。其中 W_ij 表示 X_i 到 X_j 的引數,它在不同階段可以重複利用和更新,「{}」表示拼接操作。

從DensNet到CliqueNet,解讀北大在卷積架構上的探索

如上所示,第一階段的輸出特徵圖都是拼接前面層級的特徵圖 X^1 和輸入資料 X_0 ,並做對應的卷積運算而得出。第二階段的輸出特徵圖會拼接前面層級更新過的特徵圖 X^2 與第一階段的特徵圖 X^1 而得出。

除了特徵圖的複用與精煉外,CliqueNet 還採用了一種多尺度的特徵策略來避免引數的快速增長。具體如下所示我們將每一個 Block 的輸入特徵圖與輸出特徵圖拼接在一起,並做全域性池化以得到一個向量。將所有 Block 的全域性池化結果拼接在一起就能執行最後的預測。由於損失函式是根據所有 Block 結果計算得出,那麼各個 Block 就能直接訪問梯度資訊。

從DensNet到CliqueNet,解讀北大在卷積架構上的探索


此外,由於每一個 Block 只有第二階段的輸出會作為下一個 Block 的輸入,因此 Block 的特徵圖維度也不會超線性的增加,從而具有引數量和計算量上的優勢。

如下所示為 CliqueNet 的關鍵程式碼,build_model 函式會先構建 3 個 Clique Block,並將它們全域性池化的結果傳入列表中。最終的特徵即使用 tf.concat() 函式將所有池化結果拼接在一起,且在進行一個線性變換後可傳入 Softmax 函式獲得類別的預測概率。

import tensorflow as tf
from utils import *

block_num=3

def build_model(input_images, k, T, label_num, is_train, keep_prob, if_a, if_b, if_c):

    current=first_transit(input_images, channels=64, strides=1, with_biase=False)
    current_list=[]

    ## build blocks    
    for i in range(block_num):
        block_feature, transit_feature = loop_block_I_II(current, if_b, channels_per_layer=k, layer_num=T/3, is_train=is_train, keep_prob=keep_prob, block_name='b'+str(i))
        if if_c==True:
            block_feature=compress(block_feature, is_train=is_train, keep_prob=keep_prob, name='com'+str(i))
        current_list.append(global_pool(block_feature, is_train))
        if i==block_num-1:
            break
        current=transition(transit_feature, if_a, is_train=is_train, keep_prob=keep_prob, name='tran'+str(i))


    ## final feature
    final_feature=current_list[0]
    for block_id in range(len(current_list)-1):
        final_feature=tf.concat((final_feature, current_list[block_id+1]),
                                axis=3)
    feature_length=final_feature.get_shape().as_list()[-1]
    print 'final feature length:',feature_length

    feature_flatten=tf.reshape(final_feature, [-1, feature_length])
    ##   final_fc
    Wfc=tf.get_variable(name='FC_W', shape=[feature_length, label_num], initializer=tf.contrib.layers.xavier_initializer())
    bfc=tf.get_variable(name='FC_b', initializer=tf.constant(0.0, shape=[label_num]))

    logits=tf.matmul(feature_flatten, Wfc)+bfc
    prob=tf.nn.softmax(logits)

    return logits, prob

以上的 CliqueNet 就是北京大學和上海交通大學在 CVPR 2018 對卷積網路架構的探索,也許還有更多更高效的結構,但這需要研究社群長期的努力。

相關文章