【CV中的Attention機制】并聯(lián)版的CBAM-BAM模塊

前言:之前介紹了CBAM模塊泼疑,可以方便的添加到自己的網(wǎng)絡模型中,代碼比較簡單容易理解讶隐。CBAM模塊的實現(xiàn)是通過先后施加通道注意力和空間注意力完成信息的提煉抖拦。今天介紹的這篇文章也是來自CBAM團隊,可以理解為空間注意力機制和通道注意力機制的并聯(lián)诫睬,但是具體實現(xiàn)與CBAM有較大差別煞茫,雖然代碼量相對而言比較大,實際表達的內(nèi)容并不復雜摄凡。

  • 作者:pprp
  • 編輯:BBuf

1. BAM

BAM全程是bottlenect attention module续徽,與CBAM很相似的起名,還是CBAM的團隊完成的作品亲澡。

CBAM被ECCV18接收钦扭,BAM被BMVC18接收。

CBAM可以看做是通道注意力機制和空間注意力機制的串聯(lián)(先通道后空間)床绪,BAM可以看做兩者的并聯(lián)客情。

image

這個模塊之所以叫bottlenect是因為這個模塊放在DownSample 也就是pooling layer之前,如下圖所示:

image

由于改論文與上一篇:CBAM模塊的理論部分極為相似癞己,下邊直接進行算法實現(xiàn)部分裹匙。

2. 通道部分的實現(xiàn)

class Flatten(nn.Module):
    def forward(self, x):
        return x.view(x.size(0), -1)
    
class ChannelGate(nn.Module):
    def __init__(self, gate_channel, reduction_ratio=16, num_layers=1):
        super(ChannelGate, self).__init__()
        self.gate_c = nn.Sequential()
        self.gate_c.add_module('flatten', Flatten())

        gate_channels = [gate_channel]  # eg 64
        gate_channels += [gate_channel // reduction_ratio] * num_layers  # eg 4
        gate_channels += [gate_channel]  # 64
        # gate_channels: [64, 4, 4]

        for i in range(len(gate_channels) - 2):
            self.gate_c.add_module(
                'gate_c_fc_%d' % i,
                nn.Linear(gate_channels[i], gate_channels[i + 1]))
            self.gate_c.add_module('gate_c_bn_%d' % (i + 1),
                                   nn.BatchNorm1d(gate_channels[i + 1]))
            self.gate_c.add_module('gate_c_relu_%d' % (i + 1), nn.ReLU())

        self.gate_c.add_module('gate_c_fc_final',
                               nn.Linear(gate_channels[-2], gate_channels[-1]))

    def forward(self, x):
        avg_pool = F.avg_pool2d(x, x.size(2), stride=x.size(2))
        return self.gate_c(avg_pool).unsqueeze(2).unsqueeze(3).expand_as(x)

看上去代碼要比CBAM中的ChannelAttention模塊要多很多,貼上ChannelAttention代碼方便對比:

class ChannelAttention(nn.Module):
    def __init__(self, in_planes, rotio=16):
        super(ChannelAttention, self).__init__()
        self.avg_pool = nn.AdaptiveAvgPool2d(1)
        self.max_pool = nn.AdaptiveMaxPool2d(1)

        self.sharedMLP = nn.Sequential(
            nn.Conv2d(in_planes, in_planes // ratio, 1, bias=False), nn.ReLU(),
            nn.Conv2d(in_planes // rotio, in_planes, 1, bias=False))
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        avgout = self.sharedMLP(self.avg_pool(x))
        maxout = self.sharedMLP(self.max_pool(x))
        return self.sigmoid(avgout + maxout)

首先講ChannelGate的處理流程:

  • 使用avg_pool2d測試

    >>> import torch.nn.functional as F
    >>> import torch
    >>> x = torch.ones((12, 8, 64, 64))
    >>> x.shape
    torch.Size([12, 8, 64, 64])
    >>> F.avg_pool2d(x,x.size(2), stride=x.size(2)).shape
    torch.Size([12, 8, 1, 1])
    >>>
    

    其效果與AdaptiveAvgPool2d(1)是一樣的末秃。

  • 然后經(jīng)過gate_c模塊概页,里邊先經(jīng)過Flatten將其變?yōu)閇batch size, channel]形狀的tensor, 然后后邊一大部分都是Linear模塊,進行線性變換练慕。(ps:雖然代碼看上去多惰匙,但是功能很簡單)這個部分與SE模塊有一點相似,但是可以添加多個Linear層铃将,蘊含的信息要更豐富一點项鬼。

  • 最終按照輸入tensor x的形狀進行擴展,得到關于通道的注意力劲阎。

然后講一下與CBAM中的channel attention的區(qū)別:

  • CBAM中使用的是先用adaptiveAvgPooling绘盟,然后進行卷積實現(xiàn)的通道處理;BAM使用的也是adaptiveAvgPooling, 然后進行多個Linear線性變換,得到channel attention龄毡。其實關于用1\times1卷積和Linear層實現(xiàn)吠卷,在feature map尺寸為1\times?1的時候,兩者從數(shù)學原理上講沦零,沒有區(qū)別祭隔。具體可以參考知乎上的問題:1*1的卷積核和全連接層有什么異同?
  • CBAM中激活函數(shù)使用sigmoid路操, BAM中的通道部分使用了ReLU疾渴,還添加了BN層。

3. 空間注意力機制

class SpatialGate(nn.Module):
    def __init__(self,
                 gate_channel,
                 reduction_ratio=16,
                 dilation_conv_num=2,
                 dilation_val=4):
        super(SpatialGate, self).__init__()
        self.gate_s = nn.Sequential()

        self.gate_s.add_module(
            'gate_s_conv_reduce0',
            nn.Conv2d(gate_channel,
                      gate_channel // reduction_ratio,
                      kernel_size=1))
        self.gate_s.add_module('gate_s_bn_reduce0',
                               nn.BatchNorm2d(gate_channel // reduction_ratio))
        self.gate_s.add_module('gate_s_relu_reduce0', nn.ReLU())

        # 進行多個空洞卷積屯仗,豐富感受野
        for i in range(dilation_conv_num):
            self.gate_s.add_module(
                'gate_s_conv_di_%d' % i,
                nn.Conv2d(gate_channel // reduction_ratio,
                          gate_channel // reduction_ratio,
                          kernel_size=3,
                          padding=dilation_val,
                          dilation=dilation_val))
            self.gate_s.add_module(
                'gate_s_bn_di_%d' % i,
                nn.BatchNorm2d(gate_channel // reduction_ratio))
            self.gate_s.add_module('gate_s_relu_di_%d' % i, nn.ReLU())

        self.gate_s.add_module(
            'gate_s_conv_final',
            nn.Conv2d(gate_channel // reduction_ratio, 1, kernel_size=1))

    def forward(self, x):
        return self.gate_s(x).expand_as(x)

這里可以看出搞坝,代碼量相比CBAM中的spatial attention要大很多,依然進行對比:

class SpatialAttention(nn.Module):
    def __init__(self, kernel_size=7):
        super(SpatialAttention, self).__init__()
        assert kernel_size in (3,7), "kernel size must be 3 or 7"
        padding = 3 if kernel_size == 7 else 1

        self.conv = nn.Conv2d(2,1,kernel_size, padding=padding, bias=False)
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        avgout = torch.mean(x, dim=1, keepdim=True)
        maxout, _ = torch.max(x, dim=1, keepdim=True)
        x = torch.cat([avgout, maxout], dim=1)
        x = self.conv(x)
        return self.sigmoid(x)

這個部分空間注意力處理就各有特色了魁袜,先說一下BAM中的流程:

  • 先經(jīng)過一個conv+bn+relu模塊瞄沙,通道縮進,信息進行壓縮慌核。
  • 然后經(jīng)過了多個dilated conv+bn+relu模塊,空洞率設置為4(默認)申尼。
  • 最后經(jīng)過一個卷積垮卓,將通道壓縮到1。
  • 最終將其擴展為tensor x的形狀师幕。

區(qū)別在于:

  • CBAM中通過通道間的max,avg處理成通道數(shù)為2的feature, 然后通過卷積+Sigmoid得到最終的map
  • BAM中則全部通過卷積或者空洞卷積完成信息處理粟按,計算量更大一點, 但是融合了多感受野,信息更加豐富霹粥。

4. BAM融合

class BAM(nn.Module):
    def __init__(self, gate_channel):
        super(BAM, self).__init__()
        self.channel_att = ChannelGate(gate_channel)
        self.spatial_att = SpatialGate(gate_channel)

    def forward(self, x):
        att = 1 + F.sigmoid(self.channel_att(x) * self.spatial_att(x))
        return att * x

最終融合很簡單灭将,需要注意的就是兩者是相乘的,并且使用了sigmoid進行歸一化后控。


論文鏈接:https://arxiv.org/pdf/1807.06514

核心代碼:https://github.com/pprp/SimpleCVReproduction/tree/master/attention/BAM

后記:感覺BAM跟CBAM相比有一點點復雜庙曙,沒有CBAM的那種簡潔美。這兩篇都是坐著在同一時期進行發(fā)表的浩淘,所以并沒有互相的一個詳細的對照捌朴,但是大概看了一下,感覺CBAM效果好于BAM张抄。

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末砂蔽,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子署惯,更是在濱河造成了極大的恐慌左驾,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異诡右,居然都是意外死亡安岂,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門稻爬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來嗜闻,“玉大人,你說我怎么就攤上這事桅锄×瘀ǎ” “怎么了?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵友瘤,是天一觀的道長翠肘。 經(jīng)常有香客問我,道長辫秧,這世上最難降的妖魔是什么束倍? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮盟戏,結果婚禮上绪妹,老公的妹妹穿的比我還像新娘。我一直安慰自己柿究,他們只是感情好邮旷,可當我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蝇摸,像睡著了一般婶肩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上貌夕,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天律歼,我揣著相機與錄音,去河邊找鬼啡专。 笑死险毁,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的们童。 我是一名探鬼主播辱揭,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼病附!你這毒婦竟也來了问窃?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤完沪,失蹤者是張志新(化名)和其女友劉穎域庇,沒想到半個月后嵌戈,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡听皿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年熟呛,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片尉姨。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡庵朝,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出又厉,到底是詐尸還是另有隱情九府,我是刑警寧澤,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布覆致,位于F島的核電站侄旬,受9級特大地震影響,放射性物質發(fā)生泄漏煌妈。R本人自食惡果不足惜儡羔,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望璧诵。 院中可真熱鬧汰蜘,春花似錦、人聲如沸之宿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽澈缺。三九已至,卻和暖如春炕婶,著一層夾襖步出監(jiān)牢的瞬間姐赡,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工柠掂, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留项滑,地道東北人。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓涯贞,卻偏偏與公主長得像枪狂,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子宋渔,可洞房花燭夜當晚...
    茶點故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內(nèi)容