一、CBAM代碼解析
CBAM是一個基於注意力機制的深度學習模型改進方法,其全稱為「Convolutional Block Attention Module」(卷積塊注意力模塊)。CBAM在卷積神經網路(CNN)中引入了兩個注意力機制,分別是通道注意力和空間注意力。關於CBAM代碼的解析,我們可以看一下其代碼實現:
import torch.nn as nn
import torch.nn.functional as F
class ChannelAttention(nn.Module):
def __init__(self, in_planes, ratio=16):
super(ChannelAttention, self).__init__()
self.avg_pool = nn.AdaptiveAvgPool2d(1)
self.max_pool = nn.AdaptiveMaxPool2d(1)
self.fc1 = nn.Conv2d(in_planes, in_planes // ratio, 1, bias=False)
self.relu1 = nn.ReLU()
self.fc2 = nn.Conv2d(in_planes // ratio, in_planes, 1, bias=False)
self.sigmoid = nn.Sigmoid()
def forward(self, x):
avg_out = self.fc2(self.relu1(self.fc1(self.avg_pool(x))))
max_out = self.fc2(self.relu1(self.fc1(self.max_pool(x))))
out = avg_out + max_out
return self.sigmoid(out)
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.conv1 = nn.Conv2d(2, 1, kernel_size, padding=padding, bias=False)
self.sigmoid = nn.Sigmoid()
def forward(self, x):
avg_out = torch.mean(x, dim=1, keepdim=True)
max_out, _ = torch.max(x, dim=1, keepdim=True)
x = torch.cat([avg_out, max_out], dim=1)
x = self.conv1(x)
return self.sigmoid(x)
上述代碼中,ChannelAttention是用於通道注意力機制的類,SpatialAttention是用於空間注意力機制的類。在ChannelAttention類中,我們首先使用兩個自適應池化層avg_pool和max_pool來對輸入x進行平均值和最大值的計算。我們使用1×1的卷積層fc1和fc2對結果進行特徵提取和映射,並使用ReLU激活函數對映射後的結果進行非線性處理。最後,我們使用Sigmoid函數將特徵圖映射到0到1的區間中,從而生成通道注意力圖。
在對空間注意力機制進行處理時,我們使用一個卷積層對空間特徵進行處理,然後使用Sigmoid激活函數將特徵圖映射到0到1的範圍內。最終,我們將兩個注意力機制的輸出進行相乘,然後將結果與原始輸入進行加和操作。這個加和操作中的權重由兩個注意力機制的相乘結果確定。這樣就完成了CBAM在深度學習模型中的引入。
二、CBAM代碼實現
下面是一個使用CBAM的PyTorch代碼實現,該模型可以用於進行圖像分類:
import torch.nn as nn
from cbam import ChannelAttention, SpatialAttention
class CBAMBlock(nn.Module):
def __init__(self, in_channels, ratio=16, kernel_size=7):
super(CBAMBlock, self).__init__()
self.ca = ChannelAttention(in_channels, ratio)
self.sa = SpatialAttention(kernel_size)
def forward(self, x):
out = x * self.ca(x)
out = out * self.sa(out)
return out
class CBAMModel(nn.Module):
def __init__(self, num_classes=10):
super(CBAMModel, self).__init__()
self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=2, padding=1, bias=False)
self.bn1 = nn.BatchNorm2d(64)
self.cbam1 = CBAMBlock(64)
self.conv2 = nn.Conv2d(64, 128, kernel_size=3, stride=2, padding=1, bias=False)
self.bn2 = nn.BatchNorm2d(128)
self.cbam2 = CBAMBlock(128)
self.conv3 = nn.Conv2d(128, 256, kernel_size=3, stride=2, padding=1, bias=False)
self.bn3 = nn.BatchNorm2d(256)
self.cbam3 = CBAMBlock(256)
self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
self.fc = nn.Linear(256, num_classes)
def forward(self, x):
out = F.relu(self.bn1(self.conv1(x)))
out = self.cbam1(out)
out = F.relu(self.bn2(self.conv2(out)))
out = self.cbam2(out)
out = F.relu(self.bn3(self.conv3(out)))
out = self.cbam3(out)
out = self.avgpool(out)
out = out.view(out.size(0), -1)
out = self.fc(out)
return out
上述代碼中,我們可以看到CBAM的實現方式與傳統的卷積神經網路十分相似。我們首先使用三個卷積層和三個批量歸一化層來進行特徵提取和映射。然後,我們將每個卷積層的輸出連接到一個對應的CBAMBlock中進行注意力機制處理。最後,我們使用一個自適應池化層和全連接層對最終特徵提取結果進行分類。
三、CBAM代碼選取
我們選取幾個與CBAM代碼相關的示例,以幫助更好地理解CBAM的實現。首先,我們來看一下CBAM模塊中通道注意力機制的相關代碼:
class ChannelAttention(nn.Module):
def __init__(self, in_planes, ratio=16):
super(ChannelAttention, self).__init__()
self.avg_pool = nn.AdaptiveAvgPool2d(1)
self.max_pool = nn.AdaptiveMaxPool2d(1)
self.fc1 = nn.Conv2d(in_planes, in_planes // ratio, 1, bias=False)
self.relu1 = nn.ReLU()
self.fc2 = nn.Conv2d(in_planes // ratio, in_planes, 1, bias=False)
self.sigmoid = nn.Sigmoid()
def forward(self, x):
avg_out = self.fc2(self.relu1(self.fc1(self.avg_pool(x))))
max_out = self.fc2(self.relu1(self.fc1(self.max_pool(x))))
out = avg_out + max_out
return self.sigmoid(out)
上述代碼中,我們在通道注意力機制中使用一個自適應池化層avg_pool和max_pool來對輸入x進行平均值和最大值的計算。我們使用1×1的卷積層fc1和fc2對結果進行特徵提取和映射,並使用ReLU激活函數對映射後的結果進行非線性處理。最後,我們使用Sigmoid函數將特徵圖映射到0到1的區間中,從而生成通道注意力圖。
接著,我們來看一下CBAM模塊中空間注意力機制的相關代碼:
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.conv1 = nn.Conv2d(2, 1, kernel_size, padding=padding, bias=False)
self.sigmoid = nn.Sigmoid()
def forward(self, x):
avg_out = torch.mean(x, dim=1, keepdim=True)
max_out, _ = torch.max(x, dim=1, keepdim=True)
x = torch.cat([avg_out, max_out], dim=1)
x = self.conv1(x)
return self.sigmoid(x)
上述代碼中,我們使用一個卷積層對空間特徵進行處理,然後使用Sigmoid激活函數將特徵圖映射到0到1的範圍內。最終,我們將兩個注意力機制的輸出進行相乘,然後將結果與原始輸入進行加和操作。這個加和操作中的權重由兩個注意力機制的相乘結果確定。這樣就完成了CBAM在深度學習模型中的引入。
最後,我們來看一下使用CBAM模塊的PyTorch代碼示例:
class CBAMBlock(nn.Module):
def __init__(self, in_channels, ratio=16, kernel_size=7):
super(CBAMBlock, self).__init__()
self.ca = ChannelAttention(in_channels, ratio)
self.sa = SpatialAttention(kernel_size)
def forward(self, x):
out = x * self.ca(x)
out = out * self.sa(out)
return out
上述代碼中,我們可以看到CBAM的具體使用方式,即將CBAMBlock插入到卷積神經網路的特徵提取部分中,用於引入通道注意力和空間注意力機制。在CBAMBlock中,我們使用ChannelAttention和SpatialAttention分別進行通道注意力和空間注意力的計算,並將其相乘後再與原始輸入相加,生成輸出。
結語
本文詳細地闡述了CBAM在深度學習模型中的重要改進,分別對CBAM的代碼解析、代碼實現和代碼選取進行了詳細的介紹。相信通過對CBAM深入了解,可以對深度學習模型的構建和優化有更深刻的認識和理解。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/235690.html