目录
CBAM 论文链接:https://arxiv.org/pdf/1807.06521.pdf
1、修改common.py文件
在该文件的最后面添加下列代码:
#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)
# in_planes // ratio 这里会出现如下警告:
# UserWarning: __floordiv__ is deprecated(被舍弃了), and its behavior will change in a future version of pytorch.
# It currently rounds toward 0 (like the 'trunc' function NOT 'floor').
# This results in incorrect rounding for negative values.
# To keep the current behavior, use torch.div(a, b, rounding_mode='trunc'),
# or for actual floor division, use torch.div(a, b, rounding_mode='floor').
# kernel = torch.DoubleTensor([*(x[0].shape[2:])]) // torch.DoubleTensor(list((m.output_size,))).squeeze()
self.f1 = nn.Conv2d(in_planes, in_planes // ratio, 1, bias=False)
self.relu = nn.ReLU()
self.f2 = nn.Conv2d(in_planes // ratio, in_planes, 1, bias=False)
self.sigmoid = nn.Sigmoid()
def forward(self, x):
# 全局平均池化—>MLP两层卷积
avg_out = self.f2(self.relu(self.f1(self.avg_pool(x))))
# 全局最大池化—>MLP两层卷积
max_out = self.f2(self.relu(self.f1(self.max_pool(x))))
out = self.sigmoid(avg_out + max_out)
return 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.conv = nn.Conv2d(2, 1, kernel_size, padding=padding, bias=False)
self.sigmoid = nn.Sigmoid()
def forward(self, x):
# 基于channel的全局平均池化(channel=1)
avg_out = torch.mean(x, dim=1, keepdim=True)
# 基于channel的全局最大池化(channel=1)
max_out, _ = torch.max(x, dim=1, keepdim=True)
# channel拼接(channel=2)
x = torch.cat([avg_out, max_out], dim=1)
# channel=1
x = self.conv(x)
return self.sigmoid(x)
class CBAMBottleneck(nn.Module):
# ch_in, ch_out, shortcut, groups, expansion, ratio, kernel_size
def __init__(self, c1, c2, shortcut=True, g=1, e=0.5, ratio=16, kernel_size=7):
super(CBAMBottleneck, self).__init__()
c_ = int(c2 * e) # hidden channels
self.cv1 = Conv(c1, c_, 1, 1)
self.cv2 = Conv(c_, c2, 3, 1, g=g)
self.add = shortcut and c1 == c2
# 加入CBAM模块
self.channel_attention = ChannelAttention(c2, ratio)
self.spatial_attention = SpatialAttention(kernel_size)
def forward(self, x):
# 考虑加入CBAM模块的位置:bottleneck模块刚开始时、bottleneck模块中shortcut之前,这里选择在shortcut之前
x2 = self.cv2(self.cv1(x)) # x和x2的channel数相同
# 在bottleneck模块中shortcut之前加入CBAM模块
out = self.channel_attention(x2) * x2
# print('outchannels:{}'.format(out.shape))
out = self.spatial_attention(out) * out
return x + out if self.add else out
class C3CBAM(C3):
# C3 module with CBAMBottleneck()
def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):
super().__init__(c1, c2, n, shortcut, g, e) # 引入C3(父类)的属性
c_ = int(c2 * e) # hidden channels
self.m = nn.Sequential(*(CBAMBottleneck(c_, c_, shortcut) for _ in range(n)))
2、修改yolo.py 文件:
将下面的代码:
if m in {
Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv,
BottleneckCSP, C3, C3TR, C3SPP, C3Ghost, nn.ConvTranspose2d, DWConvTranspose2d, C3x}:
c1, c2 = ch[f], args[0]
在其后面添加:CBAMBottleneck,C3CBAM
if m in {
Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv,
BottleneckCSP, C3, C3TR, C3SPP, C3Ghost, nn.ConvTranspose2d, DWConvTranspose2d, C3x, CBAMBottleneck, C3CBAM}:
c1, c2 = ch[f], args[0]
3、创建yolov5-cbam.yaml 文件
在models文件夹下创建yolov5-cbam.yaml 文件,并写入以下代码:
这里是将backbone中的C3全部替换成了C3CBAM
# YOLOv5 🚀 by Ultralytics, GPL-3.0 license
# Parameters
nc: 20 # number of classes
depth_multiple: 0.33 # model depth multiple
width_multiple: 0.50 # layer channel multiple
anchors:
- [10,13, 16,30, 33,23] # P3/8
- [30,61, 62,45, 59,119] # P4/16
- [116,90, 156,198, 373,326] # P5/32
# YOLOv5 v6.0 backbone
# 第二种加入方法 全部替换 C3 模块
backbone:
# [from, number, module, args]
[[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
[-1, 1, Conv, [128, 3, 2]], # 1-P2/4
[-1, 3, C3CBAM, [128]],
[-1, 1, Conv, [256, 3, 2]], # 3-P3/8
[-1, 6, C3CBAM, [256]],
[-1, 1, Conv, [512, 3, 2]], # 5-P4/16
[-1, 9, C3CBAM, [512]],
[-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
[-1, 3, C3CBAM, [1024]],
[-1, 1, SPPF, [1024, 5]], # 9
]
# YOLOv5 v6.0 head
head:
[[-1, 1, Conv, [512, 1, 1]],
[-1, 1, nn.Upsample, [None, 2, 'nearest']],
[[-1, 6], 1, Concat, [1]], # cat backbone P4
[-1, 3, C3, [512, False]], # 13
[-1, 1, Conv, [256, 1, 1]],
[-1, 1, nn.Upsample, [None, 2, 'nearest']],
[[-1, 4], 1, Concat, [1]], # cat backbone P3
[-1, 3, C3, [256, False]], # 17 (P3/8-small)
[-1, 1, Conv, [256, 3, 2]],
[[-1, 14], 1, Concat, [1]], # cat head P4
[-1, 3, C3, [512, False]], # 20 (P4/16-medium)
[-1, 1, Conv, [512, 3, 2]],
[[-1, 10], 1, Concat, [1]], # cat head P5
[-1, 3, C3, [1024, False]], # 23 (P5/32-large)
[[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
]
4、修改yolo.py文件里面的cfg配置文件
parser.add_argument('--cfg', type=str, default='D:/pycharm/PythonProject/CBAM-EIOU-yolov5/models/yolov5-cbam.yaml', help='model.yaml')
5、修改train文件中的yaml文件
parser.add_argument('--cfg', type=str, default='D:/pycharm/PythonProject/CBAM-EIOU-yolov5/models/yolov5-cbam.yaml', help='model.yaml path')
6、运行train.py 文件
即添加成功!
推荐博主:YOLO V5(6.0)添加CBAM、SENet、CA注意力机制手把手教程_yolov5添加senet_weixin_55200566的博客-CSDN博客
每天学会一点点!加油!!!