【論文筆記】:Pyramid Feature Attention Network for Saliency detection

&Title

在這裏插入圖片描述

&Summary

在顯著性檢測算法中,如何提取到更有效的特徵是該任務的難點之一

爲了解決該問題,我們通過金字塔特徵注意網絡來注意高語義特徵和低維空間結構特徵
首先,使用上下文感知金字塔特徵提取(Context-aware PyramidFeatureExtraction,CPFE)模塊對高級多尺度信息捕捉豐富的語義信息。

其次,在CPFE模塊後加入通道注意模塊( channel-wise attention,CA)以及低級特徵中提取的空間注意模塊( spatial attention,SA),然後將CA和SA融合。

最後,我們提出邊緣保護損失,使網絡學習到更多的邊界定位的細節信息。

根據不同級別特徵的特徵,我們對高級特徵採用通道注意,對於低級特徵採用空間注意,以選擇有效特徵。另外,我們不對高級功能使用空間關注,因爲高級功能包含高度的抽象語義,因此無需過濾空間信息。同時,我們不對低級功能使用通道注意,因爲低級功能的不同通道之間幾乎沒有語義上的區別。

contributions:

  1. 我們提出了一種用於圖像顯着性檢測的金字塔特徵注意(PFA)網絡。 對於高級功能,我們採用了上下文感知金字塔特徵提取模塊和通道級注意模塊來捕獲豐富的上下文信息。 對於低級特徵,我們採用空間關注模塊過濾掉一些背景細節。
  2. 我們設計了一種新穎的邊緣保留損失,以指導網絡學習邊界定位方面的更多詳細信息。
  3. 所提出的模型在一些具有挑戰性的數據集上達到了最新水平。 實驗證明了該方法的有效性和優越性。

&Research Objective

提取到更有效的特徵。

&Problem Statement

如今算法多通過融合多尺度特徵來提取更有效的特徵,但並不是所有的特徵都是有效的,而且有些可能導致相反的效果。

  • 最有效的顯著性目標檢測算法都是基於FCN網絡,由多個卷積層和池化層堆疊來逐漸增加感受野大小以及獲得更高級的語義信息。但池化層減小了特徵映射的大小並惡化了顯著對象的邊界。
  • 一些研究者通過手動提取特徵將顯著性目標的邊界特徵進行保存。但這種方法難以有效地融合單獨提取的互補特徵,並且很耗時。
  • 研究者們又通過融合多尺度特徵來進行顯著性目標檢測。深層的特徵通常包含全局上下文感知信息,這些信息適合於正確定位顯著區域。 淺層的特徵包含空間結構細節,適合於定位邊界。這些方法的缺點是,融合不同尺度的特徵但是並未考慮到每一層不同的貢獻

&Method(s)

提出了一種新的顯着性檢測方法,該方法包含一個上下文感知金字塔特徵提取模塊和一個通道感知模塊:以捕獲上下文感知多尺度多接收場高級特徵;空間注意力:用於低級特徵圖的模塊以精煉顯着的對象細節;有效的邊緣保留損失,以指導網絡學習邊界定位中的更多詳細信息。 總體架構如下圖所示:
在這裏插入圖片描述

ef VGG16(img_input, dropout=False, with_CPFE=False, with_CA=False, with_SA=False, droup_rate=0.3):
    # Block 1  Conv 1-2
    x = Conv2D(64, (3, 3), activation='relu', padding='same', name='block1_conv1')(img_input)
    x = Conv2D(64, (3, 3), activation='relu', padding='same', name='block1_conv2')(x)
    C1 = x
    x = MaxPooling2D((2, 2), strides=(2, 2), name='block1_pool')(x)
    if dropout:
        x = Dropout(droup_rate)(x)
        
    # Block 2  Conv 2-2
    x = Conv2D(128, (3, 3), activation='relu', padding='same', name='block2_conv1')(x)
    x = Conv2D(128, (3, 3), activation='relu', padding='same', name='block2_conv2')(x)
    C2 = x
    x = MaxPooling2D((2, 2), strides=(2, 2), name='block2_pool')(x)
    if dropout:
        x = Dropout(droup_rate)(x)
        
    # Block 3  Conv 3-3
    x = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv1')(x)
    x = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv2')(x)
    x = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv3')(x)
    C3 = x
    x = MaxPooling2D((2, 2), strides=(2, 2), name='block3_pool')(x)
    if dropout:
        x = Dropout(droup_rate)(x)
        
    # Block 4   Conv 4-3
    x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv1')(x)
    x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv2')(x)
    x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv3')(x)
    C4 = x
    x = MaxPooling2D((2, 2), strides=(2, 2), name='block4_pool')(x)
    if dropout:
        x = Dropout(droup_rate)(x)
        
    # Block 5   Conv 5-3
    x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv1')(x)
    x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv2')(x)
    x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv3')(x)
    if dropout:
        x = Dropout(droup_rate)(x)
    C5 = x
    
	# 上面是backbone中五個conv的實現 下面就是 PFAN的核心的地方  對照着上面的圖就很好理解了
    C1 = Conv2D(64, (3, 3), padding='same', name='C1_conv')(C1)
    C1 = BN(C1, 'C1_BN')
    C2 = Conv2D(64, (3, 3), padding='same', name='C2_conv')(C2)
    C2 = BN(C2, 'C2_BN')
    # CPFE 實現
    if with_CPFE:
        C3_cfe = CFE(C3, 32, 'C3_cfe')
        C4_cfe = CFE(C4, 32, 'C4_cfe')
        C5_cfe = CFE(C5, 32, 'C5_cfe')
        # CFE的實現後面會提到
        C5_cfe = BilinearUpsampling(upsampling=(4, 4), name='C5_cfe_up4')(C5_cfe)
        C4_cfe = BilinearUpsampling(upsampling=(2, 2), name='C4_cfe_up2')(C4_cfe)
        C345 = Concatenate(name='C345_aspp_concat', axis=-1)([C3_cfe, C4_cfe, C5_cfe])
        # 通道注意力 用來注意高層特徵圖的,關注高級語義信息
        if with_CA:
            C345 = ChannelWiseAttention(C345, name='C345_ChannelWiseAttention_withcpfe')
    C345 = Conv2D(64, (1, 1), padding='same', name='C345_conv')(C345)
    C345 = BN(C345,'C345')
    C345 = BilinearUpsampling(upsampling=(4, 4), name='C345_up4')(C345)
	# 空間注意力,用在底層特徵圖上
    if with_SA:
        SA = SpatialAttention(C345, 'spatial_attention')
        C2 = BilinearUpsampling(upsampling=(2, 2), name='C2_up2')(C2)
        C12 = Concatenate(name='C12_concat', axis=-1)([C1, C2])
        C12 = Conv2D(64, (3, 3), padding='same', name='C12_conv')(C12)
        C12 = BN(C12, 'C12')
        C12 = Multiply(name='C12_atten_mutiply')([SA, C12])
        # 用的是乘,attention map用的高層特徵圖C345
    fea = Concatenate(name='fuse_concat',axis=-1)([C12, C345])
    sa = Conv2D(1, (3, 3), padding='same', name='sa')(fea)

    model = Model(inputs=img_input, outputs=sa, name="BaseModel")
    return model

CPFE
CPFE結構如下所示,輸入時VGG的三個高層特徵圖,然後對其分別進行三個具有不同擴張率的3×3卷積(豐富感受野)和一個1×1卷積,然後採樣到相同size的map特徵圖,最後cat連接作爲最終輸出。
在這裏插入圖片描述

爲了使最終提取的高級特徵包含比例尺和形狀不變性的特徵,我們採用具有不同擴張率的無窮卷積,將其設置爲3、5和7來捕獲多接收場上下文信息。 然後,通過跨通道級聯,將來自不同的多孔卷積層的特徵圖和1×1降維特徵進行組合。 此後,我們獲得了三個具有上下文感知信息的不同尺度特徵,我們將兩個較小的特徵上採樣爲最大的特徵。 最後,我們通過跨通道串聯將它們組合起來,作爲上下文感知金字塔特徵提取模塊的輸出。

代碼如下:

def CFE(input_tensor, filters, block_id):
    rate = [3, 5, 7]  ## 三種膨脹率
    cfe0 = Conv2D(filters, (1, 1), padding='same', use_bias=False, name=block_id + '_cfe0')(
        input_tensor)
    cfe1 = AtrousBlock(input_tensor, filters, rate[0], block_id + '_cfe1')
    cfe2 = AtrousBlock(input_tensor, filters, rate[1], block_id + '_cfe2')
    cfe3 = AtrousBlock(input_tensor, filters, rate[2], block_id + '_cfe3')
    cfe_concat = Concatenate(name=block_id + 'concatcfe', axis=-1)([cfe0, cfe1, cfe2, cfe3])
    cfe_concat = BN(cfe_concat, block_id)
    return cfe_concat

Channel-wise attention
在上下文感知金字塔特徵提取後,我們將通道方式注意(CA)模塊添加到加權的多尺度多接收場高級特徵中。 CA將對顯示對突出對象有高響應的通道分配更大的權重。

兩個連續的全連接(FC)層完全捕獲了通道相關性(請參見圖4)。 爲了限制模型的複雜性和輔助概括,我們通過在非線性周圍形成具有兩個FC層的瓶頸來編碼通道方式特徵向量。 然後,通過使用S形運算,對映射到[0,1]的編碼後的通道特徵向量採取歸一化處理措施。

在這裏插入圖片描述

def SpatialAttention(inputs,name):
    k = 9
    H, W, C = map(int,inputs.get_shape()[1:])
    attention1 = Conv2D(C / 2, (1, k), padding='same', name=name+'_1_conv1')(inputs)
    attention1 = BN(attention1,'attention1_1')
    attention1 = Conv2D(1, (k, 1), padding='same', name=name + '_1_conv2')(attention1)
    attention1 = BN(attention1, 'attention1_2')
    attention2 = Conv2D(C / 2, (k, 1), padding='same', name=name + '_2_conv1')(inputs)
    attention2 = BN(attention2, 'attention2_1')
    attention2 = Conv2D(1, (1, k), padding='same', name=name + '_2_conv2')(attention2)
    attention2 = BN(attention2, 'attention2_2')
    attention = Add(name=name+'_add')([attention1,attention2])
    attention = Activation('sigmoid')(attention)
    attention = Repeat(repeat_list=[1, 1, 1, C])(attention)
    return attention

def ChannelWiseAttention(inputs,name):
    H, W, C = map(int, inputs.get_shape()[1:])
    attention = GlobalAveragePooling2D(name=name+'_GlobalAveragePooling2D')(inputs)
    attention = Dense(C / 4, activation='relu')(attention)
    attention = Dense(C, activation='sigmoid',activity_regularizer=l1_reg)(attention)
    # Dense是全連接層
    attention = Reshape((1, 1, C),name=name+'_reshape')(attention)
    attention = Repeat(repeat_list=[1, H, W, 1],name=name+'_repeat')(attention)
    attention = Multiply(name=name + '_multiply')([attention, inputs])
    return attention
#這兩個返回的attention不一樣,SA返回的是attention weight。CA返回的是attention後的特徵圖

Spacial attention Natural
自然圖像通常包含大量的前景和複雜背景細節。我們通過在底層特徵圖應用SA模塊,用來注意前景區域。圖4 SA模塊中,Y means context-aware high-level feature after CA in this paper。即CA之後的高級特徵圖。就是用的上層語義來注意底層特徵中需要關注的特徵。上層語義包含的背景信息較少。
PS:這種利用上層語義來做attention map,使用sigmoid來歸一化的操作,我也做過,但實驗效果基本上沒有。

從圖1可以看出,來自低層特徵的顯着性圖包含許多細節,很容易帶來不良結果。 在顯着性檢測中,我們希望獲得顯着物體與背景之間的詳細邊界,而沒有其他會分散人類注意力的紋理。 因此,我們不是在均等地考慮所有空間位置,而是將空間注意力更多地集中在前景區域上,這有助於生成用於顯着性預測的有效特徵。
在這裏插入圖片描述

Loss function
使用拉普拉斯算子來獲取地面實況和網絡輸出的顯着性圖的邊界,然後使用交叉熵損失來監督顯着對象邊界的生成。
在這裏插入圖片描述
拉普拉斯算子是n維歐幾里德空間中的二階微分算子,定義爲梯度的散度(∆f)。 由於二階導數可用於檢測邊緣,因此我們使用Laplace運算符來獲取顯着的對象邊界。 二維的拉普拉斯算子由公式8給出,其中x和y是xy平面的標準笛卡爾座標。最後,我們使用交叉熵損失來監督顯着物體邊界公式10的生成。
在這裏插入圖片描述
總損失:
在這裏插入圖片描述

def EdgeHoldLoss(y_true, y_pred):
    y_pred2 = tf.sigmoid(y_pred)
    y_true_edge = tfLaplace(y_true)
    # tfLaplace 爲拉普拉斯算子,具體代碼看github
    y_pred_edge = tfLaplace(y_pred2)
    # 獲取邊界
    y_pred_edge = logit(y_pred_edge)
    edge_loss = K.mean(tf.nn.sigmoid_cross_entropy_with_logits(labels=y_true_edge,logits=y_pred_edge), axis=-1)
    saliency_pos = 1.12
    saliency_loss = K.mean(tf.nn.weighted_cross_entropy_with_logits(y_true,y_pred,saliency_pos), axis=-1)
    return 0.7*saliency_loss+0.3*edge_loss # 總loss,論文設置 α 爲 0.7

&Evaluation

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

&Thinks

  • 注意力加損失函數的改進,不算是特別好的idea了,這個loss的設計可能是本文的比較大的亮點吧,有空研究研究。
  • 文中使用的空間注意力,之前有做過類似的實驗,也是用兩層的融合來做attention map,用sigmoid來歸一化處理,然後mul。效果基本沒提升。之前分析是:利用上層語義 map 來做注意力(mul), 使得剃度回傳的時候變小,從而使得上層與 下層的聯繫沒有直接使用加法來得更緊密,sigmoid 會進一步縮小梯度。但是本文這樣操作跟我差不多啊,就是我沒有用BN而已,有空重新做一下實驗。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章