【CV中的Attention機制】ECCV 2018 Convolutional Block Attention Module
- 2020 年 2 月 12 日
- 筆記
前言
這是【CV中的Attention機制】系列的第三篇文章。目前cv領域借鑒了nlp領域的attention機制以後生產出了很多有用的基於attention機制的論文,attention機制也是在2019年論文中非常火。這篇cbam雖然是在2018年提出的,但是其影響力比較深遠,在很多領域都用到了該模組,所以一起來看一下這個模組有什麼獨到之處,並學著實現它。
1. 什麼是注意力機制?
注意力機制(Attention Mechanism)是機器學習中的一種數據處理方法,廣泛應用在自然語言處理、影像識別及語音識別等各種不同類型的機器學習任務中。
通俗來講:注意力機制就是希望網路能夠自動學出來圖片或者文字序列中的需要注意的地方。比如人眼在看一幅畫的時候,不會將注意力平等地分配給畫中的所有像素,而是將更多注意力分配給人們關注的地方。
從實現的角度來講:注意力機制通過神經網路的操作生成一個掩碼mask, mask上的值一個打分,評價當前需要關注的點的評分。
注意力機制可以分為:
- 通道注意力機制:對通道生成掩碼mask,進行打分,代表是senet, Channel Attention Module
- 空間注意力機制:對空間進行掩碼的生成,進行打分,代表是Spatial Attention Module
- 混合域注意力機制:同時對通道注意力和空間注意力進行評價打分,代表的有BAM, CBAM
2. 怎麼實現CBAM?(pytorch為例)
CBAM全稱是Convolutional Block Attention Module, 是在ECCV2018上發表的注意力機制代表作之一,論文地址見附錄。本人在打比賽的時候遇見過有人使用過該模組取得了第一名的好成績,證明了其有效性。
在該論文中,作者研究了網路架構中的注意力,注意力不僅要告訴我們重點關注哪裡,還要提高關注點的表示。目標是通過使用注意機制來增加表現力,關注重要特徵並抑制不必要的特徵。為了強調空間和通道這兩個維度上的有意義特徵,作者依次應用通道和空間注意模組,來分別在通道和空間維度上學習關注什麼、在哪裡關注。此外,通過了解要強調或抑制的資訊也有助於網路內的資訊流動。
主要網路架構也很簡單,一個是通道注意力模組,另一個是空間注意力模組,CBAM就是先後集成了通道注意力模組和空間注意力模組。
2.1 通道注意力機制

通道注意力機制按照上圖進行實現:
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)
2.2 空間注意力機制

空間注意力機制按照上圖進行實現:
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)
2.3 Convolutional bottleneck attention module

class BasicBlock(nn.Module): expansion = 1 def __init__(self, inplanes, planes, stride=1, downsample=None): super(BasicBlock, self).__init__() self.conv1 = conv3x3(inplanes, planes, stride) self.bn1 = nn.BatchNorm2d(planes) self.relu = nn.ReLU(inplace=True) self.conv2 = conv3x3(planes, planes) self.bn2 = nn.BatchNorm2d(planes) self.ca = ChannelAttention(planes) self.sa = SpatialAttention() self.downsample = downsample self.stride = stride def forward(self, x): residual = x out = self.conv1(x) out = self.bn1(out) out = self.relu(out) out = self.conv2(out) out = self.bn2(out) out = self.ca(out) * out # 廣播機制 out = self.sa(out) * out # 廣播機制 if self.downsample is not None: residual = self.downsample(x) out += residual out = self.relu(out) return out
為何要先使用通道注意力機制然後再使用空間注意力機制?使用順序使用這兩個模組還是並行的使用兩個模組?其實是作者已經做過了相關實驗,並且證明了先試用通道然後再使用空間注意力機制這樣的組合效果比較好,這也是CBAM的通用組合模式。
3. 在什麼情況下可以使用?
提出CBAM的作者主要對分類網路和目標檢測網路進行了實驗,證明了CBAM模組確實是有效的。
以ResNet為例,論文中提供了改造的示意圖,如下圖所示:

也就是在ResNet中的每個block之間添加了CBAM模組,訓練數據來自benchmark ImageNet-1K。檢測使用的是Faster R-CNN, Backbone選擇的ResNet34,ResNet50, WideResNet18, ResNeXt50等,還跟SE等進行了對比。
消融實驗:消融實驗一般是控制變數,最能看出模型變好起作用的部分在那裡。分為三個部分:
- 如何更有效地計算channel attention?

可以看出來,使用avgpool和maxpool可以更好的降低錯誤率,大概有1-2%的提升,這個組合就是dual pooling,能提供更加精細的資訊,有利於提升模型的表現。
- 如何更有效地計算spatial attention?

這裡的空間注意力機制參數也是有avg, max組成,另外還有一個卷積的參數kernel_size(k), 通過以上實驗,可以看出,當前使用通道的平均和通道的最大化,並且設置kernel size=7是最好的。
- 如何組織這兩個部分?

可以看出,這裡與SENet中的SE模組也進行了比較,這裡使用CBAM也是超出了SE的表現。除此以外,還進行了順序和並行的測試,發現,先channel attention然後spatial attention效果最好,所以也是最終的CBAM模組的組成。
在MSCOCO數據及使用了ResNet50,ResNet101為backbone, Faster RCNN為檢測器的模型進行目標檢測,如下圖所示:

在VOC2007數據集中採用了StairNet進行了測試,如下圖所示:

貌似沒有找到目標檢測部分的程式碼,CBAM的作用在於對資訊進行精細化分配和處理,所以猜測是在backbone的分類器之前添加的CBAM模組,歡迎有研究的小夥伴賜教。
附錄
- 論文原文:http://openaccess.thecvf.com/content_ECCV_2018/papers/Sanghyun_Woo_Convolutional_Block_Attention_ECCV_2018_paper.pdf