探祕計算機視覺中的注意力機制

本文做者:y****ngit

近年來,愈來愈多的工做專一於將注意力機制融入計算機視覺任務中。本文重點介紹注意力機制的基本原理和利用飛槳實現注意力機制的基本方法。

注意力機制大多數手段採用掩碼進行實現。掩碼每每指使用一層全新的注意力機制權重,將特徵數據中每一個部分的關鍵程度表示出來,並加以學習訓練。從通俗的意義上解釋,注意力機制的本質是利用相關特徵圖進行學習的權重,再將學習的權重施加在原特徵圖上進行加權求和,進而獲得加強的特徵。 通常來講,加權的過程能夠分爲soft attention和hard attention,前者保留全部權重份量進行加權求和,後者根據必定的策略選擇性保留權重,由於不可微的特性,通常採用強化學習的方法進行學習。 根據注意力域的不一樣,能夠將CV中的注意力機制分爲三類,分別爲:空間域(spatial domain),通道域(channel domain),混合域(mixed domain)。
  • 空間域:將圖片中的空間域信息作對應的空間變換,從而將關鍵的信息提取出來。對空間進行掩碼的生成和打分,表明做是Spatial Attention Module。
  • 通道域:相似於給每一個通道上的信號都增長一個權重,來表明該通道與關鍵信息的相關度,權重越大,表示相關度越高。對通道生成掩碼mask並進行打分,表明做是SENet、Channel Attention Module。
  • 混合域:空間域的注意力是忽略了通道域中的信息,將每一個通道中的圖片特徵同等處理,這種作法會將空間域變換方法侷限在原始圖片特徵提取階段,應用在神經網絡層其餘層的可解釋性不強。表明做是:BAM、CBAM。
本文以SENet和CBAM爲例,對CV中的注意力機制進行解讀。

SENetgithub

 

壓縮-激勵網絡(Squeeze-and-Excitation Networks, SENet),拿到了ImageNet2017分類比賽冠軍,其效果獲得了承認,其提出的壓縮-激勵模塊,思想簡單,易於實現,而且很容易加載到現有的網絡模型框架中。SENet主要是學習卷積過程當中通道之間的相關性,篩選出基於通道的注意力,雖然稍微增長了一點計算量,可是效果比較好。

上圖展現了一個壓縮-激勵模塊的實現過程,經過對卷積獲得的特徵圖進行處理,獲得一個和通道數同樣的一維向量做爲每一個通道的評價分數,而後將該分數分別施加到對應的通道上,獲得其結果,至關於在原有的基礎上只添加了一個模塊。其詳細過程可分爲三個階段:壓縮、激勵、特徵重標定。 設輸入特徵圖爲。在壓縮階段,對的特徵圖進行全局平均池化: 獲得1 ×1 ×C大小的特徵圖,該特徵圖可理解爲具備全局感覺野。在激勵階段,首先使用W1和z進行一個全鏈接操做,W1的維度是C / r × C。r爲一個放縮參數,目的爲減小通道個數從而下降計算量。W1z的結果爲1 × 1 × C / r,隨後加一個ReLU層,而後和W2通過一個全鏈接層,W2維度爲C × C / r,所以輸出維度爲1 ×1 ×C。最後再通過Sigmoid函數,獲得S,即: 在特徵重標定階段,使用激勵階段獲得的結果做爲通道注意力權重,乘到輸入特徵上。 壓縮-激勵模塊通常放在一個卷積模塊以後,做爲一個信息改善的手段,在前人的實驗中已證實了其有效性。SE模塊能夠嵌入到幾乎全部的網絡結構中,經過在經典backbone的block中嵌入SE模塊,咱們能夠獲得各式各樣的SENet,諸如SE-BN-Inception、SE-ResNet 、SE-ReNeXt、SE-Inception-ResNet-v2等等。 上圖爲原論文所列的一些在ImageNet分類上的網絡的結果對比,其中的SENet使用的是SE-ResNeXt-152(64x4d),即在ResNeXt-152上嵌入SE模塊,並作了一些相應的修改和優化。該網絡取得了當時single-crop上最好的性能。 最近的一些研究並不僅僅把Squeeze-and-Excitation侷限在圖片分類上,也會嘗試將其應用在一些不一樣任務的中間特徵圖上,以提高不一樣通道特徵的信息利用。 一個Squeeze-and-Excitation函數的飛槳實現 (https://github.com/c8241998/CV_attention/blob/master/SEnet/senet-paddle.py): def _squeeze_excitation(self, input, num_channels, name=None):
    mixed_precision_enabled = mixed_precision_global_state() is not None
    pool = fluid.layers.pool2d(
        input=input,
        pool_size=0,
        pool_type='avg',
        global_pooling=True,
        use_cudnn=mixed_precision_enabled)
    stdv = 1.0 / math.sqrt(pool.shape[1] * 1.0)
    squeeze = fluid.layers.fc(
        input=pool,
        size=int(num_channels / self.reduction_ratio),
        act='relu',
        param_attr=fluid.param_attr.ParamAttr(
            initializer=fluid.initializer.Uniform(-stdv, stdv),
            name=name + '_sqz_weights'),
        bias_attr=ParamAttr(name=name + '_sqz_offset'))
    stdv = 1.0 / math.sqrt(squeeze.shape[1] * 1.0)
    excitation = fluid.layers.fc(
        input=squeeze,
        size=num_channels,
        act='sigmoid',
        param_attr=fluid.param_attr.ParamAttr(
            initializer=fluid.initializer.Uniform(-stdv, stdv),
            name=name + '_exc_weights'),
        bias_attr=ParamAttr(name=name + '_exc_offset'))
    scale = fluid.layers.elementwise_mul(x=input, y=excitation, axis=0)
  CBAM是一個簡單但有效的注意力模塊。對於一箇中間特徵圖,能夠沿着空間和通道兩個維度依次推斷出注意力權重,而後與原特徵圖相乘來對特徵進行自適應調整。做者將整個過程分爲兩個獨立的模塊:通道注意力模塊和空間注意力模塊。這樣不只能夠節約參數和計算量,還保證了其能夠做爲即插即用的模塊集成到現有的網絡架構中去。 圖2展現的是一個通道注意力模塊。給定H×W×C 的特徵 F,做者分別採用了兩種池化方式對中間特徵進行不一樣的處理:即分別對空間進行全局平均池化和最大池化獲得兩個 1×1×C 的通道特徵。隨後將它們送入一個共享的兩層神經網絡,第一層神經元個數爲 C/r,激活函數爲 Relu,第二層神經元個數爲 C。再將獲得的兩個特徵相加後通過一個 Sigmoid 激活函數獲得權重係數 Mc。最後拿權重係數和原特徵相乘便可獲得新特徵。 return scale 圖3展現的是一個空間注意力模塊。給定H×W×C 的特徵 F,做者前後採用兩種池化方式對中間特徵進行不一樣處理,即前後對通道進行平均池化和最大池化,獲得兩個 H×W×1 的通道特徵。將兩層特徵拼接在一塊兒,通過一個7×7 的卷積層,激活函數爲 Sigmoid,獲得權重係數 Ms。最後,拿權重將數和特徵 F 相乘便可獲得新特徵。 圖4即爲一個完整的CBAM模塊,將兩種注意力模塊順序組合便可。 上表展現的是原論文的實驗數據,在ImageNet分類實驗中,將 CBAM 集成到全部的 ResNet 系列網絡中去,均可以下降最終的分類錯誤率。CBAM 是一個輕量級的通用模塊,與SENet相似,它被認爲一樣能夠集成到任何 CNN 經典backbone中,而且能夠與backbone一塊兒進行端到端的訓練。在原論文中的不一樣的分類和檢測數據集上,集成CBAM後的模型的表現都有了一致的提高,體現了其普遍的可適用性。 一個CBAM模塊的飛槳實現。 (https://github.com/c8241998/CV_attention/blob/master/CBAM/cbam-paddle.py): class CBAM_Module(fluid.dygraph.Layer):  
    def __init__(self, channels, reduction):  
        super(CBAM_Module, self).__init__()  
        self.avg_pool = AdaptiveAvgPool2d(pool_size=1, pool_type="avg")  
        self.max_pool = AdaptiveAvgPool2d(pool_size=1, pool_type="max")  
        self.fc1 = fluid.dygraph.Conv2D(num_channels=channels, num_filters=channels // reduction, filter_size=1, padding=0)  
        self.relu = ReLU()  
        self.fc2 = fluid.dygraph.Conv2D(num_channels=channels // reduction, num_filters=channels, filter_size=1, padding=0)  

        self.sigmoid_channel = Sigmoid()  
        self.conv_after_concat = fluid.dygraph.Conv2D(num_channels=2, num_filters=1, filter_size=7, stride=1, padding=3)  
        self.sigmoid_spatial = Sigmoid()  

    def forward(self, x):  
        # Channel Attention Module  
        module_input = x  
        avg = self.relu(self.fc1(self.avg_pool(x)))  
        avg = self.fc2(avg)  
        mx = self.relu(self.fc1(self.max_pool(x)))  
        mx = self.fc2(mx)  
        x = avg + mx  
        x = self.sigmoid_channel(x)  

        # Spatial Attention Module  
        x = module_input * x  
        module_input = x  
        avg = fluid.layers.mean(x)  
        mx = fluid.layers.argmax(x, axis=1)  
        print(avg.shape, mx.shape)  
        x = fluid.layers.concat([avg, mx], axis=1)  
        x = self.conv_after_concat(x)  
        x = self.sigmoid_spatial(x)  
        x = module_input * x  

        return x  

總結網絡

 

注意力機制是一個很寬泛的概念,隨着針對它的研究愈來愈多,其操做方式也愈來愈多樣。但它們都有一個共同的核心思想:對特徵中更感興趣的層面施加更大的注意力權重,而這個過程與人類觀察物體的方式很是類似,期待在該領域有更多高質量的工做出現。

原文連接地址:https://developer.baidu.com/topic/show/291085架構

相關文章
相關標籤/搜索