論文信息
- 標題: EPSANet: An Efficient Pyramid Squeeze Attention Block on Convolutional Neural Network
- 論文鏈接: arXiv
- GitHub鏈接: https://github.com/murufeng/EPSANet
創新點
EPSANet提出了一種新穎的金字塔擠壓注意力(PSA)模塊,旨在解決傳統注意力機制在捕獲多尺度特征時的局限性。其主要創新點包括:
- 高效性: PSA模塊能夠在較低的計算成本下有效提取多尺度空間信息。
- 靈活性: 該模塊可以作為即插即用的組件,輕松集成到現有的卷積神經網絡(CNN)架構中。
- 多尺度特征表示: EPSANet通過自適應地重新校準跨維通道的注意權重,增強了特征表示能力。
方法
EPSANet的核心是PSA模塊,其實現過程如下:
- 多尺度特征提取: 通過Squeeze and Concat (SPC)模塊獲得通道維度上的多尺度特征圖。
- 注意力計算: 使用SEWeight模塊提取不同尺度特征圖的注意力,生成通道方向的注意力向量。
- 再校準: 通過Softmax對通道維度的注意向量進行再校準,得到多尺度信道的再校準權重。
- 特征融合: 在重新校準的權重和對應的特征圖上進行按元素乘積,輸出豐富的多尺度特征圖。
效果
EPSANet在多個計算機視覺任務中表現出色,包括圖像分類、目標檢測和實例分割。與傳統的通道注意力方法相比,EPSANet在性能上有顯著提升。例如:
- 在ImageNet數據集上,EPSANet的Top-1準確率比SENet-50提高了1.93%。
- 在MS-COCO數據集上,使用Mask-RCNN時,EPSANet在目標檢測和實例分割任務中分別提高了2.7和1.7的AP值。
實驗結果
實驗結果表明,EPSANet在多個標準數據集上均超越了當前最新的技術。具體表現為:
- 在COCO 2017數據集上,EPSANet的目標檢測率超越了ECANet,AP75指標提高了1.4%。
- 論文中進行了大量的定性和定量實驗,驗證了EPSANet在圖像分類、目標檢測和實例分割方面的先進性能。
總結
EPSANet通過引入金字塔擠壓注意力模塊,成功地提升了卷積神經網絡在多尺度特征提取方面的能力。其靈活的設計使得EPSANet能夠廣泛應用于各種計算機視覺任務,展現出良好的泛化性能和高效性。該研究為未來的深度學習模型設計提供了新的思路和方法。
代碼
import torch
import torch.nn as nnclass SEWeightModule(nn.Module):def __init__(self, channels, reduction=16):super(SEWeightModule, self).__init__()self.avg_pool = nn.AdaptiveAvgPool2d(1)self.fc1 = nn.Conv2d(channels, channels//reduction, kernel_size=1, padding=0)self.relu = nn.ReLU(inplace=True)self.fc2 = nn.Conv2d(channels//reduction, channels, kernel_size=1, padding=0)self.sigmoid = nn.Sigmoid()def forward(self, x):out = self.avg_pool(x)out = self.fc1(out)out = self.relu(out)out = self.fc2(out)weight = self.sigmoid(out)return weightdef conv(in_planes, out_planes, kernel_size=3, stride=1, padding=1, dilation=1, groups=1):"""standard convolution with padding"""return nn.Conv2d(in_planes, out_planes, kernel_size=kernel_size, stride=stride,padding=padding, dilation=dilation, groups=groups, bias=False)def conv1x1(in_planes, out_planes, stride=1):"""1x1 convolution"""return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False)class PSAModule(nn.Module):def __init__(self, inplans, planes, conv_kernels=[3, 5, 7, 9], stride=1, conv_groups=[1, 4, 8, 16]):super(PSAModule, self).__init__()self.conv_1 = conv(inplans, planes//4, kernel_size=conv_kernels[0], padding=conv_kernels[0]//2,stride=stride, groups=conv_groups[0])self.conv_2 = conv(inplans, planes//4, kernel_size=conv_kernels[1], padding=conv_kernels[1]//2,stride=stride, groups=conv_groups[1])self.conv_3 = conv(inplans, planes//4, kernel_size=conv_kernels[2], padding=conv_kernels[2]//2,stride=stride, groups=conv_groups[2])self.conv_4 = conv(inplans, planes//4, kernel_size=conv_kernels[3], padding=conv_kernels[3]//2,stride=stride, groups=conv_groups[3])self.se = SEWeightModule(planes // 4)self.split_channel = planes // 4self.softmax = nn.Softmax(dim=1)def forward(self, x):batch_size = x.shape[0]x1 = self.conv_1(x)x2 = self.conv_2(x)x3 = self.conv_3(x)x4 = self.conv_4(x)feats = torch.cat((x1, x2, x3, x4), dim=1)feats = feats.view(batch_size, 4, self.split_channel, feats.shape[2], feats.shape[3])x1_se = self.se(x1)x2_se = self.se(x2)x3_se = self.se(x3)x4_se = self.se(x4)x_se = torch.cat((x1_se, x2_se, x3_se, x4_se), dim=1)attention_vectors = x_se.view(batch_size, 4, self.split_channel, 1, 1)attention_vectors = self.softmax(attention_vectors)feats_weight = feats * attention_vectorsfor i in range(4):x_se_weight_fp = feats_weight[:, i, :, :]if i == 0:out = x_se_weight_fpelse:out = torch.cat((x_se_weight_fp, out), 1)return outif __name__ == "__main__":dim=512# 如果GPU可用,將模塊移動到 GPUdevice = torch.device("cuda" if torch.cuda.is_available() else "cpu")# 輸入張量 (batch_size, channels,height, width)x = torch.randn(1,dim,14,14).to(device)# 初始化 PSAModule 模塊block = PSAModule(dim,dim) # kernel_size為height或者widthprint(block)block = block.to(device)# 前向傳播output = block(x)print("輸入:", x.shape)print("輸出:", output.shape)
輸出結果: