当前位置:   article > 正文

yolov5改进之加入CBAM,SE,ECA,CA,SimAM,ShuffleAttention,Criss-CrossAttention,CrissCrossAttention多种注意力机制_yolov5 网络改进之增加se、cbam、ca、eca等注意力机制

yolov5 网络改进之增加se、cbam、ca、eca等注意力机制

本文所涉及到的yolov5网络为6.1版本(6.0-6.2均适用)

yolov5加入注意力机制模块的三个标准步骤(适用于本文中的任何注意力机制

1.common.py中加入注意力机制模块

2.yolo.py中增加对应的注意力机制关键字

3.yaml文件中添加相应模块

注:所有注意力机制的添加方法都是一致的,加入注意力机制是否有效的关键在于注意力机制添加的位置,本文提供两种常用常用方法。

注:需要下列所有注意力机制已经改好的代码版本及yaml文件(到手即用),请私聊我(免费)

目录

1.CBAM注意力机制

2.SE注意力机制

3.ECA注意力注意力机制

4.CA注意力注意力机制

5.SimAM注意力机制

6.ShuffleAttention注意力机制

7.CrissCrossAttention注意力机制


1.CBAM注意力机制

  1. class ChannelAttention(nn.Module):
  2. def __init__(self, in_planes, ratio=16):
  3. super(ChannelAttention, self).__init__()
  4. self.avg_pool = nn.AdaptiveAvgPool2d(1)
  5. self.max_pool = nn.AdaptiveMaxPool2d(1)
  6. self.f1 = nn.Conv2d(in_planes, in_planes // ratio, 1, bias=False)
  7. self.relu = nn.ReLU()
  8. self.f2 = nn.Conv2d(in_planes // ratio, in_planes, 1, bias=False)
  9. self.sigmoid = nn.Sigmoid()
  10. def forward(self, x):
  11. avg_out = self.f2(self.relu(self.f1(self.avg_pool(x))))
  12. max_out = self.f2(self.relu(self.f1(self.max_pool(x))))
  13. out = self.sigmoid(avg_out + max_out)
  14. return out
  15. class SpatialAttention(nn.Module):
  16. def __init__(self, kernel_size=7):
  17. super(SpatialAttention, self).__init__()
  18. assert kernel_size in (3, 7), 'kernel size must be 3 or 7'
  19. padding = 3 if kernel_size == 7 else 1
  20. self.conv = nn.Conv2d(2, 1, kernel_size, padding=padding, bias=False)
  21. self.sigmoid = nn.Sigmoid()
  22. def forward(self, x):
  23. avg_out = torch.mean(x, dim=1, keepdim=True)
  24. max_out, _ = torch.max(x, dim=1, keepdim=True)
  25. x = torch.cat([avg_out, max_out], dim=1)
  26. x = self.conv(x)
  27. return self.sigmoid(x)
  28. class CBAM(nn.Module):
  29. # CSP Bottleneck with 3 convolutions
  30. def __init__(self, c1, c2, ratio=16, kernel_size=7): # ch_in, ch_out, number, shortcut, groups, expansion
  31. super(CBAM, self).__init__()
  32. # c_ = int(c2 * e) # hidden channels
  33. # self.cv1 = Conv(c1, c_, 1, 1)
  34. # self.cv2 = Conv(c1, c_, 1, 1)
  35. # self.cv3 = Conv(2 * c_, c2, 1)
  36. # self.m = nn.Sequential(*[Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)])
  37. self.channel_attention = ChannelAttention(c1, ratio)
  38. self.spatial_attention = SpatialAttention(kernel_size)
  39. # self.m = nn.Sequential(*[CrossConv(c_, c_, 3, 1, g, 1.0, shortcut) for _ in range(n)])
  40. def forward(self, x):
  41. out = self.channel_attention(x) * x
  42. # print('outchannels:{}'.format(out.shape))
  43. out = self.spatial_attention(out) * out
  44. return out

以上代码需要添加在models文件夹下的common.py文件中,具体添加位置如果找不准可以选择common.py文件的最底端(最稳妥的做法,肯定不会错),或者C3模块后面(方便查找)。

第二步,需要更改models文件夹下的yolo.py文件。可以直接ctrl+F 然后查找parse_model关键字,定位到parse_model函数,你会发现有一段这样的代码

  1. if m in (Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv,
  2. BottleneckCSP, C3, C3TR, C3SPP, C3Ghost, nn.ConvTranspose2d, DWConvTranspose2d, C3x):
  3. c1, c2 = ch[f], args[0]
  4. if c2 != no: # if not output
  5. c2 = make_divisible(c2 * gw, 8)
  6. args = [c1, c2, *args[1:]]
  7. if m in [BottleneckCSP, C3, C3TR, C3Ghost, C3x]:
  8. args.insert(2, n) # number of repeats
  9. n = 1

我们仅需在第1行和第8行末尾添加CBAM即可,具体做法如下

  1. if m in (Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv,
  2. BottleneckCSP, C3, C3TR, C3SPP, C3Ghost, nn.ConvTranspose2d, DWConvTranspose2d, C3x, CBAM):
  3. c1, c2 = ch[f], args[0]
  4. if c2 != no: # if not output
  5. c2 = make_divisible(c2 * gw, 8)
  6. args = [c1, c2, *args[1:]]
  7. if m in [BottleneckCSP, C3, C3TR, C3Ghost, C3x, CBAM]:
  8. args.insert(2, n) # number of repeats
  9. n = 1

第三步,就是最为关键的改动yaml文件了,我们以yolov5s.yaml为例进行改进,这里仅截取关键部分,未截取部分则不做改动。

第一个版本是将CBAM放在backbone部分的最末端,这样可以使注意力机制看到整个backbone部分的特征图,将具有全局视野,类似于一个小transformer结构。

  1. # YOLOv5 v6.0 backbone
  2. backbone:
  3. # [from, number, module, args]
  4. [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
  5. [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
  6. [-1, 3, C3, [128]],
  7. [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
  8. [-1, 6, C3, [256]],
  9. [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
  10. [-1, 9, C3, [512]],
  11. [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
  12. [-1, 3, C3, [1024]],
  13. [-1, 1, SPPF, [1024, 5]], # 9
  14. [-1, 3, CBAM, [1024]], # 10
  15. ]
  16. # YOLOv5 v6.0 head
  17. head:
  18. [[-1, 1, Conv, [512, 1, 1]],
  19. [-1, 1, nn.Upsample, [None, 2, 'nearest']],
  20. [[-1, 6], 1, Concat, [1]], # cat backbone P4
  21. [-1, 3, C3, [512, False]], # 14
  22. [-1, 1, Conv, [256, 1, 1]],
  23. [-1, 1, nn.Upsample, [None, 2, 'nearest']],
  24. [[-1, 4], 1, Concat, [1]], # cat backbone P3
  25. [-1, 3, C3, [256, False]], # 18 (P3/8-small)
  26. [-1, 1, Conv, [256, 3, 2]],
  27. [[-1, 15], 1, Concat, [1]], # cat head P4
  28. [-1, 3, C3, [512, False]], # 21 (P4/16-medium)
  29. [-1, 1, Conv, [512, 3, 2]],
  30. [[-1, 11], 1, Concat, [1]], # cat head P5
  31. [-1, 3, C3, [1024, False]], # 24 (P5/32-large)
  32. [[18, 21, 24], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
  33. ]

第二个版本是将CBAM放在backbone部分每个C3模块的后面,这样可以使注意力机制看到局部的特征,每层进行一次注意力,可以分担学习压力。

  1. backbone:
  2. # [from, number, module, args]
  3. [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
  4. [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
  5. [-1, 3, C3, [128]],
  6. [-1, 3, CBAM, [128]], # 3
  7. [-1, 1, Conv, [256, 3, 2]], # 4-P3/8
  8. [-1, 6, C3, [256]],
  9. [-1, 3, CBAM, [256]],
  10. [-1, 1, Conv, [512, 3, 2]], # 7-P4/16
  11. [-1, 9, C3, [512]],
  12. [-1, 3, CBAM, [512]],
  13. [-1, 1, Conv, [1024, 3, 2]], # 10 -P5/32
  14. [-1, 3, C3, [1024]],
  15. [-1, 3, CBAM, [1024]],
  16. [-1, 1, SPPF, [1024, 5]], # 13
  17. ]
  18. # YOLOv5 v6.0 head
  19. head:
  20. [[-1, 1, Conv, [512, 1, 1]],
  21. [-1, 1, nn.Upsample, [None, 2, 'nearest']],
  22. [[-1, 9], 1, Concat, [1]], # cat backbone P4
  23. [-1, 3, C3, [512, False]], # 17
  24. [-1, 1, Conv, [256, 1, 1]],
  25. [-1, 1, nn.Upsample, [None, 2, 'nearest']],
  26. [[-1, 6], 1, Concat, [1]], # cat backbone P3
  27. [-1, 3, C3, [256, False]], # 21 (P3/8-small)
  28. [-1, 1, Conv, [256, 3, 2]],
  29. [[-1, 18], 1, Concat, [1]], # cat head P4
  30. [-1, 3, C3, [512, False]], # 24 (P4/16-medium)
  31. [-1, 1, Conv, [512, 3, 2]],
  32. [[-1, 14], 1, Concat, [1]], # cat head P5
  33. [-1, 3, C3, [1024, False]], # 27 (P5/32-large)
  34. [[21, 24, 27], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
  35. ]

2.SE注意力机制

同理,首先将下方代码添加在models文件夹下的common.py文件中,具体添加位置如果找不准可以选择common.py文件的最底端(最稳妥的做法,肯定不会错),或者C3模块后面(方便查找)。

  1. class SE(nn.Module):
  2. def __init__(self, c1, c2, r=16):
  3. super(SE, self).__init__()
  4. self.avgpool = nn.AdaptiveAvgPool2d(1)
  5. self.l1 = nn.Linear(c1, c1 // r, bias=False)
  6. self.relu = nn.ReLU(inplace=True)
  7. self.l2 = nn.Linear(c1 // r, c1, bias=False)
  8. self.sig = nn.Sigmoid()
  9. def forward(self, x):
  10. b, c, _, _ = x.size()
  11. y = self.avgpool(x).view(b, c)
  12. y = self.l1(y)
  13. y = self.relu(y)
  14. y = self.l2(y)
  15. y = self.sig(y)
  16. y = y.view(b, c, 1, 1)
  17. return x * y.expand_as(x)

第二步,需要更改models文件夹下的yolo.py文件。可以直接ctrl+F 然后查找parse_model关键字,定位到parse_model函数,你会发现有一段这样的代码

  1. if m in (Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv,
  2. BottleneckCSP, C3, C3TR, C3SPP, C3Ghost, nn.ConvTranspose2d, DWConvTranspose2d, C3x):
  3. c1, c2 = ch[f], args[0]
  4. if c2 != no: # if not output
  5. c2 = make_divisible(c2 * gw, 8)
  6. args = [c1, c2, *args[1:]]
  7. if m in [BottleneckCSP, C3, C3TR, C3Ghost, C3x]:
  8. args.insert(2, n) # number of repeats
  9. n = 1

我们仅需在第1行和第8行末尾添加SE即可,具体做法如下

  1. if m in (Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv,
  2. BottleneckCSP, C3, C3TR, C3SPP, C3Ghost, nn.ConvTranspose2d, DWConvTranspose2d, C3x, SE):
  3. c1, c2 = ch[f], args[0]
  4. if c2 != no: # if not output
  5. c2 = make_divisible(c2 * gw, 8)
  6. args = [c1, c2, *args[1:]]
  7. if m in [BottleneckCSP, C3, C3TR, C3Ghost, C3x, SE]:
  8. args.insert(2, n) # number of repeats
  9. n = 1

第三步,就是最为关键的改动yaml文件了,我们以yolov5s.yaml为例进行改进,这里仅截取关键部分,未截取部分则不做改动。

第一个版本是将SE放在backbone部分的最末端,这样可以使注意力机制看到整个backbone部分的特征图,将具有全局视野,类似于一个小transformer结构。

  1. # YOLOv5 v6.0 backbone
  2. backbone:
  3. # [from, number, module, args]
  4. [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
  5. [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
  6. [-1, 3, C3, [128]],
  7. [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
  8. [-1, 6, C3, [256]],
  9. [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
  10. [-1, 9, C3, [512]],
  11. [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
  12. [-1, 3, C3, [1024]],
  13. [-1, 1, SPPF, [1024, 5]], # 9
  14. [-1, 3, SE, [1024]], # 10
  15. ]
  16. # YOLOv5 v6.0 head
  17. head:
  18. [[-1, 1, Conv, [512, 1, 1]],
  19. [-1, 1, nn.Upsample, [None, 2, 'nearest']],
  20. [[-1, 6], 1, Concat, [1]], # cat backbone P4
  21. [-1, 3, C3, [512, False]], # 14
  22. [-1, 1, Conv, [256, 1, 1]],
  23. [-1, 1, nn.Upsample, [None, 2, 'nearest']],
  24. [[-1, 4], 1, Concat, [1]], # cat backbone P3
  25. [-1, 3, C3, [256, False]], # 18 (P3/8-small)
  26. [-1, 1, Conv, [256, 3, 2]],
  27. [[-1, 15], 1, Concat, [1]], # cat head P4
  28. [-1, 3, C3, [512, False]], # 21 (P4/16-medium)
  29. [-1, 1, Conv, [512, 3, 2]],
  30. [[-1, 11], 1, Concat, [1]], # cat head P5
  31. [-1, 3, C3, [1024, False]], # 24 (P5/32-large)
  32. [[18, 21, 24], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
  33. ]

第二个版本是将SE放在backbone部分每个C3模块的后面,这样可以使注意力机制看到局部的特征,每层进行一次注意力,可以分担学习压力。

  1. backbone:
  2. # [from, number, module, args]
  3. [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
  4. [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
  5. [-1, 3, C3, [128]],
  6. [-1, 3, SE, [128]], # 3
  7. [-1, 1, Conv, [256, 3, 2]], # 4-P3/8
  8. [-1, 6, C3, [256]],
  9. [-1, 3, SE, [256]],
  10. [-1, 1, Conv, [512, 3, 2]], # 7-P4/16
  11. [-1, 9, C3, [512]],
  12. [-1, 3, SE, [512]],
  13. [-1, 1, Conv, [1024, 3, 2]], # 10 -P5/32
  14. [-1, 3, C3, [1024]],
  15. [-1, 3, SE, [1024]],
  16. [-1, 1, SPPF, [1024, 5]], # 13
  17. ]
  18. # YOLOv5 v6.0 head
  19. head:
  20. [[-1, 1, Conv, [512, 1, 1]],
  21. [-1, 1, nn.Upsample, [None, 2, 'nearest']],
  22. [[-1, 9], 1, Concat, [1]], # cat backbone P4
  23. [-1, 3, C3, [512, False]], # 17
  24. [-1, 1, Conv, [256, 1, 1]],
  25. [-1, 1, nn.Upsample, [None, 2, 'nearest']],
  26. [[-1, 6], 1, Concat, [1]], # cat backbone P3
  27. [-1, 3, C3, [256, False]], # 21 (P3/8-small)
  28. [-1, 1, Conv, [256, 3, 2]],
  29. [[-1, 18], 1, Concat, [1]], # cat head P4
  30. [-1, 3, C3, [512, False]], # 24 (P4/16-medium)
  31. [-1, 1, Conv, [512, 3, 2]],
  32. [[-1, 14], 1, Concat, [1]], # cat head P5
  33. [-1, 3, C3, [1024, False]], # 27 (P5/32-large)
  34. [[21, 24, 27], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
  35. ]

3.ECA注意力注意力机制

同理,首先将下方代码添加在models文件夹下的common.py文件中,具体添加位置如果找不准可以选择common.py文件的最底端(最稳妥的做法,肯定不会错),或者C3模块后面(方便查找)。

  1. class h_sigmoid(nn.Module):
  2. def __init__(self, inplace=True):
  3. super(h_sigmoid, self).__init__()
  4. self.relu = nn.ReLU6(inplace=inplace)
  5. def forward(self, x):
  6. return self.relu(x + 3) / 6
  7. class h_swish(nn.Module):
  8. def __init__(self, inplace=True):
  9. super(h_swish, self).__init__()
  10. self.sigmoid = h_sigmoid(inplace=inplace)
  11. def forward(self, x):
  12. return x * self.sigmoid(x)
  13. class CA(nn.Module):
  14. def __init__(self, inp, oup, reduction=32):
  15. super(CA, self).__init__()
  16. self.pool_h = nn.AdaptiveAvgPool2d((None, 1))
  17. self.pool_w = nn.AdaptiveAvgPool2d((1, None))
  18. mip = max(8, inp // reduction)
  19. self.conv1 = nn.Conv2d(inp, mip, kernel_size=1, stride=1, padding=0)
  20. self.bn1 = nn.BatchNorm2d(mip)
  21. self.act = h_swish()
  22. self.conv_h = nn.Conv2d(mip, oup, kernel_size=1, stride=1, padding=0)
  23. self.conv_w = nn.Conv2d(mip, oup, kernel_size=1, stride=1, padding=0)
  24. def forward(self, x):
  25. identity = x
  26. n, c, h, w = x.size()
  27. x_h = self.pool_h(x)
  28. x_w = self.pool_w(x).permute(0, 1, 3, 2)
  29. y = torch.cat([x_h, x_w], dim=2)
  30. y = self.conv1(y)
  31. y = self.bn1(y)
  32. y = self.act(y)
  33. x_h, x_w = torch.split(y, [h, w], dim=2)
  34. x_w = x_w.permute(0, 1, 3, 2)
  35. a_h = self.conv_h(x_h).sigmoid()
  36. a_w = self.conv_w(x_w).sigmoid()
  37. out = identity * a_w * a_h
  38. return out

ECA注意力机制比较特殊,不需要改动models文件夹下的yolo.py文件,可直接使用。

第三步,就是最为关键的改动yaml文件了,我们以yolov5s.yaml为例进行改进,这里仅截取关键部分,未截取部分则不做改动。

第一个版本是将ECA放在backbone部分的最末端,这样可以使注意力机制看到整个backbone部分的特征图,将具有全局视野,类似于一个小transformer结构。

  1. # YOLOv5 v6.0 backbone
  2. backbone:
  3. # [from, number, module, args]
  4. [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
  5. [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
  6. [-1, 3, C3, [128]],
  7. [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
  8. [-1, 6, C3, [256]],
  9. [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
  10. [-1, 9, C3, [512]],
  11. [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
  12. [-1, 3, C3, [1024]],
  13. [-1, 1, SPPF, [1024, 5]], # 9
  14. [-1, 3, SE, [1024]], # 10
  15. ]
  16. # YOLOv5 v6.0 head
  17. head:
  18. [[-1, 1, Conv, [512, 1, 1]],
  19. [-1, 1, nn.Upsample, [None, 2, 'nearest']],
  20. [[-1, 6], 1, Concat, [1]], # cat backbone P4
  21. [-1, 3, C3, [512, False]], # 14
  22. [-1, 1, Conv, [256, 1, 1]],
  23. [-1, 1, nn.Upsample, [None, 2, 'nearest']],
  24. [[-1, 4], 1, Concat, [1]], # cat backbone P3
  25. [-1, 3, C3, [256, False]], # 18 (P3/8-small)
  26. [-1, 1, Conv, [256, 3, 2]],
  27. [[-1, 15], 1, Concat, [1]], # cat head P4
  28. [-1, 3, C3, [512, False]], # 21 (P4/16-medium)
  29. [-1, 1, Conv, [512, 3, 2]],
  30. [[-1, 11], 1, Concat, [1]], # cat head P5
  31. [-1, 3, C3, [1024, False]], # 24 (P5/32-large)
  32. [[18, 21, 24], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
  33. ]

第二个版本是将ECA放在backbone部分每个C3模块的后面,这样可以使注意力机制看到局部的特征,每层进行一次注意力,可以分担学习压力。

  1. backbone:
  2. # [from, number, module, args]
  3. [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
  4. [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
  5. [-1, 3, C3, [128]],
  6. [-1, 3, SE, [128]], # 3
  7. [-1, 1, Conv, [256, 3, 2]], # 4-P3/8
  8. [-1, 6, C3, [256]],
  9. [-1, 3, SE, [256]],
  10. [-1, 1, Conv, [512, 3, 2]], # 7-P4/16
  11. [-1, 9, C3, [512]],
  12. [-1, 3, SE, [512]],
  13. [-1, 1, Conv, [1024, 3, 2]], # 10 -P5/32
  14. [-1, 3, C3, [1024]],
  15. [-1, 3, SE, [1024]],
  16. [-1, 1, SPPF, [1024, 5]], # 13
  17. ]
  18. # YOLOv5 v6.0 head
  19. head:
  20. [[-1, 1, Conv, [512, 1, 1]],
  21. [-1, 1, nn.Upsample, [None, 2, 'nearest']],
  22. [[-1, 9], 1, Concat, [1]], # cat backbone P4
  23. [-1, 3, C3, [512, False]], # 17
  24. [-1, 1, Conv, [256, 1, 1]],
  25. [-1, 1, nn.Upsample, [None, 2, 'nearest']],
  26. [[-1, 6], 1, Concat, [1]], # cat backbone P3
  27. [-1, 3, C3, [256, False]], # 21 (P3/8-small)
  28. [-1, 1, Conv, [256, 3, 2]],
  29. [[-1, 18], 1, Concat, [1]], # cat head P4
  30. [-1, 3, C3, [512, False]], # 24 (P4/16-medium)
  31. [-1, 1, Conv, [512, 3, 2]],
  32. [[-1, 14], 1, Concat, [1]], # cat head P5
  33. [-1, 3, C3, [1024, False]], # 27 (P5/32-large)
  34. [[21, 24, 27], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
  35. ]

4.CA注意力注意力机制

同理,首先将下方代码添加在models文件夹下的common.py文件中,具体添加位置如果找不准可以选择common.py文件的最底端(最稳妥的做法,肯定不会错),或者C3模块后面(方便查找)。

  1. class ECA(nn.Module):
  2. """Constructs a ECA module.
  3. Args:
  4. channel: Number of channels of the input feature map
  5. k_size: Adaptive selection of kernel size
  6. """
  7. def __init__(self, channel, k_size=3):
  8. super(ECA, self).__init__()
  9. self.avg_pool = nn.AdaptiveAvgPool2d(1)
  10. self.conv = nn.Conv1d(1, 1, kernel_size=k_size, padding=(k_size - 1) // 2, bias=False)
  11. self.sigmoid = nn.Sigmoid()
  12. def forward(self, x):
  13. # feature descriptor on the global spatial information
  14. y = self.avg_pool(x)
  15. # Two different branches of ECA module
  16. y = self.conv(y.squeeze(-1).transpose(-1, -2)).transpose(-1, -2).unsqueeze(-1)
  17. # Multi-scale information fusion
  18. y = self.sigmoid(y)
  19. x= x*y.expand_as(x)
  20. return x * y.expand_as(x)

第二步,需要更改models文件夹下的yolo.py文件。可以直接ctrl+F 然后查找parse_model关键字,定位到parse_model函数,你会发现有一段这样的代码

  1. if m in (Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv,
  2. BottleneckCSP, C3, C3TR, C3SPP, C3Ghost, nn.ConvTranspose2d, DWConvTranspose2d, C3x):
  3. c1, c2 = ch[f], args[0]
  4. if c2 != no: # if not output
  5. c2 = make_divisible(c2 * gw, 8)
  6. args = [c1, c2, *args[1:]]
  7. if m in [BottleneckCSP, C3, C3TR, C3Ghost, C3x]:
  8. args.insert(2, n) # number of repeats
  9. n = 1

我们仅需在第1行和第8行末尾添加SE即可,具体做法如下

  1. if m in (Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv,
  2. BottleneckCSP, C3, C3TR, C3SPP, C3Ghost, nn.ConvTranspose2d, DWConvTranspose2d, C3x, SE):
  3. c1, c2 = ch[f], args[0]
  4. if c2 != no: # if not output
  5. c2 = make_divisible(c2 * gw, 8)
  6. args = [c1, c2, *args[1:]]
  7. if m in [BottleneckCSP, C3, C3TR, C3Ghost, C3x, SE]:
  8. args.insert(2, n) # number of repeats
  9. n = 1

第一个版本是将CA放在backbone部分的最末端,这样可以使注意力机制看到整个backbone部分的特征图,将具有全局视野,类似于一个小transformer结构。

  1. # YOLOv5 v6.0 backbone
  2. backbone:
  3. # [from, number, module, args]
  4. [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
  5. [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
  6. [-1, 3, C3, [128]],
  7. [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
  8. [-1, 6, C3, [256]],
  9. [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
  10. [-1, 9, C3, [512]],
  11. [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
  12. [-1, 3, C3, [1024]],
  13. [-1, 1, SPPF, [1024, 5]], # 9
  14. [-1, 3, CA, [1024]], # 10
  15. ]
  16. # YOLOv5 v6.0 head
  17. head:
  18. [[-1, 1, Conv, [512, 1, 1]],
  19. [-1, 1, nn.Upsample, [None, 2, 'nearest']],
  20. [[-1, 6], 1, Concat, [1]], # cat backbone P4
  21. [-1, 3, C3, [512, False]], # 14
  22. [-1, 1, Conv, [256, 1, 1]],
  23. [-1, 1, nn.Upsample, [None, 2, 'nearest']],
  24. [[-1, 4], 1, Concat, [1]], # cat backbone P3
  25. [-1, 3, C3, [256, False]], # 18 (P3/8-small)
  26. [-1, 1, Conv, [256, 3, 2]],
  27. [[-1, 15], 1, Concat, [1]], # cat head P4
  28. [-1, 3, C3, [512, False]], # 21 (P4/16-medium)
  29. [-1, 1, Conv, [512, 3, 2]],
  30. [[-1, 11], 1, Concat, [1]], # cat head P5
  31. [-1, 3, C3, [1024, False]], # 24 (P5/32-large)
  32. [[18, 21, 24], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
  33. ]

第二个版本是将CA放在backbone部分每个C3模块的后面,这样可以使注意力机制看到局部的特征,每层进行一次注意力,可以分担学习压力。

  1. # YOLOv5 v6.0 backbone
  2. backbone:
  3. # [from, number, module, args]
  4. [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
  5. [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
  6. [-1, 3, C3, [128]],
  7. [-1, 3, CA, [128]], # 3
  8. [-1, 1, Conv, [256, 3, 2]], # 4-P3/8
  9. [-1, 6, C3, [256]],
  10. [-1, 3, CA, [256]],
  11. [-1, 1, Conv, [512, 3, 2]], # 7-P4/16
  12. [-1, 9, C3, [512]],
  13. [-1, 3, CA, [512]],
  14. [-1, 1, Conv, [1024, 3, 2]], # 10 -P5/32
  15. [-1, 3, C3, [1024]],
  16. [-1, 3, CA, [1024]],
  17. [-1, 1, SPPF, [1024, 5]], # 13
  18. ]
  19. # YOLOv5 v6.0 head
  20. head:
  21. [[-1, 1, Conv, [512, 1, 1]],
  22. [-1, 1, nn.Upsample, [None, 2, 'nearest']],
  23. [[-1, 9], 1, Concat, [1]], # cat backbone P4
  24. [-1, 3, C3, [512, False]], # 17
  25. [-1, 1, Conv, [256, 1, 1]],
  26. [-1, 1, nn.Upsample, [None, 2, 'nearest']],
  27. [[-1, 6], 1, Concat, [1]], # cat backbone P3
  28. [-1, 3, C3, [256, False]], # 21 (P3/8-small)
  29. [-1, 1, Conv, [256, 3, 2]],
  30. [[-1, 18], 1, Concat, [1]], # cat head P4
  31. [-1, 3, C3, [512, False]], # 24 (P4/16-medium)
  32. [-1, 1, Conv, [512, 3, 2]],
  33. [[-1, 14], 1, Concat, [1]], # cat head P5
  34. [-1, 3, C3, [1024, False]], # 27 (P5/32-large)
  35. [[21, 24, 27], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
  36. ]

5.SimAM注意力机制

同理,首先将下方代码添加在models文件夹下的common.py文件中,具体添加位置如果找不准可以选择common.py文件的最底端(最稳妥的做法,肯定不会错),或者C3模块后面(方便查找)。

  1. class SimAM(torch.nn.Module):
  2. def __init__(self, channels = None,out_channels = None, e_lambda = 1e-4):
  3. super(SimAM, self).__init__()
  4. self.activaton = nn.Sigmoid()
  5. self.e_lambda = e_lambda
  6. def forward(self, x):
  7. b, c, h, w = x.size()
  8. n = w * h - 1
  9. x_minus_mu_square = (x - x.mean(dim=[2,3], keepdim=True)).pow(2)
  10. y = x_minus_mu_square / (4 * (x_minus_mu_square.sum(dim=[2,3], keepdim=True) / n + self.e_lambda)) + 0.5
  11. return x * self.activaton(y)

第二步,需要更改models文件夹下的yolo.py文件。可以直接ctrl+F 然后查找parse_model关键字,定位到parse_model函数,你会发现有一段这样的代码

  1. if m in (Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv,
  2. BottleneckCSP, C3, C3TR, C3SPP, C3Ghost, nn.ConvTranspose2d, DWConvTranspose2d, C3x):
  3. c1, c2 = ch[f], args[0]
  4. if c2 != no: # if not output
  5. c2 = make_divisible(c2 * gw, 8)
  6. args = [c1, c2, *args[1:]]
  7. if m in [BottleneckCSP, C3, C3TR, C3Ghost, C3x]:
  8. args.insert(2, n) # number of repeats
  9. n = 1

我们仅需在第1行和第8行末尾添加SimAM即可,具体做法如下

  1. if m in (Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv,
  2. BottleneckCSP, C3, C3TR, C3SPP, C3Ghost, nn.ConvTranspose2d, DWConvTranspose2d, C3x, SimAM):
  3. c1, c2 = ch[f], args[0]
  4. if c2 != no: # if not output
  5. c2 = make_divisible(c2 * gw, 8)
  6. args = [c1, c2, *args[1:]]
  7. if m in [BottleneckCSP, C3, C3TR, C3Ghost, C3x, SimAM]:
  8. args.insert(2, n) # number of repeats
  9. n = 1

第一个版本是将SimAM放在backbone部分的最末端,这样可以使注意力机制看到整个backbone部分的特征图,将具有全局视野,类似于一个小transformer结构。

  1. # YOLOv5 v6.0 backbone
  2. backbone:
  3. # [from, number, module, args]
  4. [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
  5. [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
  6. [-1, 3, C3, [128]],
  7. [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
  8. [-1, 6, C3, [256]],
  9. [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
  10. [-1, 9, C3, [512]],
  11. [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
  12. [-1, 3, C3, [1024]],
  13. [-1, 1, SPPF, [1024, 5]], # 9
  14. [-1, 3, SimAM, [1024]], # 10
  15. ]
  16. # YOLOv5 v6.0 head
  17. head:
  18. [[-1, 1, Conv, [512, 1, 1]],
  19. [-1, 1, nn.Upsample, [None, 2, 'nearest']],
  20. [[-1, 6], 1, Concat, [1]], # cat backbone P4
  21. [-1, 3, C3, [512, False]], # 14
  22. [-1, 1, Conv, [256, 1, 1]],
  23. [-1, 1, nn.Upsample, [None, 2, 'nearest']],
  24. [[-1, 4], 1, Concat, [1]], # cat backbone P3
  25. [-1, 3, C3, [256, False]], # 18 (P3/8-small)
  26. [-1, 1, Conv, [256, 3, 2]],
  27. [[-1, 15], 1, Concat, [1]], # cat head P4
  28. [-1, 3, C3, [512, False]], # 21 (P4/16-medium)
  29. [-1, 1, Conv, [512, 3, 2]],
  30. [[-1, 11], 1, Concat, [1]], # cat head P5
  31. [-1, 3, C3, [1024, False]], # 24 (P5/32-large)
  32. [[18, 21, 24], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
  33. ]

第二个版本是将SimAM放在backbone部分每个C3模块的后面,这样可以使注意力机制看到局部的特征,每层进行一次注意力,可以分担学习压力。

  1. # YOLOv5 v6.0 backbone
  2. backbone:
  3. # [from, number, module, args]
  4. [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
  5. [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
  6. [-1, 3, C3, [128]],
  7. [-1, 3, SimAM, [128]], # 3
  8. [-1, 1, Conv, [256, 3, 2]], # 4-P3/8
  9. [-1, 6, C3, [256]],
  10. [-1, 3, SimAM, [256]],
  11. [-1, 1, Conv, [512, 3, 2]], # 7-P4/16
  12. [-1, 9, C3, [512]],
  13. [-1, 3, SimAM, [512]],
  14. [-1, 1, Conv, [1024, 3, 2]], # 10 -P5/32
  15. [-1, 3, C3, [1024]],
  16. [-1, 3, SimAM, [1024]],
  17. [-1, 1, SPPF, [1024, 5]], # 13
  18. ]
  19. # YOLOv5 v6.0 head
  20. head:
  21. [[-1, 1, Conv, [512, 1, 1]],
  22. [-1, 1, nn.Upsample, [None, 2, 'nearest']],
  23. [[-1, 9], 1, Concat, [1]], # cat backbone P4
  24. [-1, 3, C3, [512, False]], # 17
  25. [-1, 1, Conv, [256, 1, 1]],
  26. [-1, 1, nn.Upsample, [None, 2, 'nearest']],
  27. [[-1, 6], 1, Concat, [1]], # cat backbone P3
  28. [-1, 3, C3, [256, False]], # 21 (P3/8-small)
  29. [-1, 1, Conv, [256, 3, 2]],
  30. [[-1, 18], 1, Concat, [1]], # cat head P4
  31. [-1, 3, C3, [512, False]], # 24 (P4/16-medium)
  32. [-1, 1, Conv, [512, 3, 2]],
  33. [[-1, 14], 1, Concat, [1]], # cat head P5
  34. [-1, 3, C3, [1024, False]], # 27 (P5/32-large)
  35. [[21, 24, 27], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
  36. ]

6.ShuffleAttention注意力机制

同理,首先将下方代码添加在models文件夹下的common.py文件中,具体添加位置如果找不准可以选择common.py文件的最底端(最稳妥的做法,肯定不会错),或者C3模块后面(方便查找)。

  1. class ShuffleAttention(nn.Module):
  2. def __init__(self, channel=512,reduction=16,G=8):
  3. super().__init__()
  4. self.G=G
  5. self.channel=channel
  6. self.avg_pool = nn.AdaptiveAvgPool2d(1)
  7. self.gn = nn.GroupNorm(channel // (2 * G), channel // (2 * G))
  8. self.cweight = torch.ones(1, channel // (2 * G), 1, 1)
  9. self.cbias = torch.ones(1, channel // (2 * G), 1, 1)
  10. self.sweight = torch.ones(1, channel // (2 * G), 1, 1)
  11. self.sbias = torch.ones(1, channel // (2 * G), 1, 1)
  12. self.sigmoid=nn.Sigmoid()
  13. @staticmethod
  14. def channel_shuffle(x, groups):
  15. b, c, h, w = x.shape
  16. x = x.reshape(b, groups, -1, h, w)
  17. x = x.permute(0, 2, 1, 3, 4)
  18. # flatten
  19. x = x.reshape(b, -1, h, w)
  20. return x
  21. def forward(self, x):
  22. b, c, h, w = x.size()
  23. #group into subfeatures
  24. x=x.view(b*self.G,-1,h,w) #bs*G,c//G,h,w
  25. #channel_split
  26. x_0,x_1=x.chunk(2,dim=1) #bs*G,c//(2*G),h,w
  27. #channel attention
  28. x_channel=self.avg_pool(x_0) #bs*G,c//(2*G),1,1
  29. x_channel=self.cweight*x_channel+self.cbias #bs*G,c//(2*G),1,1
  30. x_channel=x_0*self.sigmoid(x_channel)
  31. #spatial attention
  32. x_spatial=self.gn(x_1) #bs*G,c//(2*G),h,w
  33. x_spatial=self.sweight*x_spatial+self.sbias #bs*G,c//(2*G),h,w
  34. x_spatial=x_1*self.sigmoid(x_spatial) #bs*G,c//(2*G),h,w
  35. # concatenate along channel axis
  36. out=torch.cat([x_channel,x_spatial],dim=1) #bs*G,c//G,h,w
  37. out=out.contiguous().view(b,-1,h,w)
  38. # channel shuffle
  39. out = self.channel_shuffle(out, 2)
  40. return out

第二步,需要更改models文件夹下的yolo.py文件。可以直接ctrl+F 然后查找parse_model关键字,定位到parse_model函数,你会发现有一段这样的代码

  1. if m in (Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv,
  2. BottleneckCSP, C3, C3TR, C3SPP, C3Ghost, nn.ConvTranspose2d, DWConvTranspose2d, C3x):
  3. c1, c2 = ch[f], args[0]
  4. if c2 != no: # if not output
  5. c2 = make_divisible(c2 * gw, 8)
  6. args = [c1, c2, *args[1:]]
  7. if m in [BottleneckCSP, C3, C3TR, C3Ghost, C3x]:
  8. args.insert(2, n) # number of repeats
  9. n = 1

我们仅需在第1行和第8行末尾添加ShuffleAttention即可,具体做法如下

  1. if m in (Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv,
  2. BottleneckCSP, C3, C3TR, C3SPP, C3Ghost, nn.ConvTranspose2d, DWConvTranspose2d, C3x, ShuffleAttention):
  3. c1, c2 = ch[f], args[0]
  4. if c2 != no: # if not output
  5. c2 = make_divisible(c2 * gw, 8)
  6. args = [c1, c2, *args[1:]]
  7. if m in [BottleneckCSP, C3, C3TR, C3Ghost, C3x, ShuffleAttention]:
  8. args.insert(2, n) # number of repeats
  9. n = 1

第一个版本是将ShuffleAttention放在backbone部分的最末端,这样可以使注意力机制看到整个backbone部分的特征图,将具有全局视野,类似于一个小transformer结构。

  1. # YOLOv5 v6.0 backbone
  2. backbone:
  3. # [from, number, module, args]
  4. [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
  5. [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
  6. [-1, 3, C3, [128]],
  7. [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
  8. [-1, 6, C3, [256]],
  9. [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
  10. [-1, 9, C3, [512]],
  11. [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
  12. [-1, 3, C3, [1024]],
  13. [-1, 1, SPPF, [1024, 5]], # 9
  14. [-1, 3, ShuffleAttention, [1024]], # 10
  15. ]
  16. # YOLOv5 v6.0 head
  17. head:
  18. [[-1, 1, Conv, [512, 1, 1]],
  19. [-1, 1, nn.Upsample, [None, 2, 'nearest']],
  20. [[-1, 6], 1, Concat, [1]], # cat backbone P4
  21. [-1, 3, C3, [512, False]], # 14
  22. [-1, 1, Conv, [256, 1, 1]],
  23. [-1, 1, nn.Upsample, [None, 2, 'nearest']],
  24. [[-1, 4], 1, Concat, [1]], # cat backbone P3
  25. [-1, 3, C3, [256, False]], # 18 (P3/8-small)
  26. [-1, 1, Conv, [256, 3, 2]],
  27. [[-1, 15], 1, Concat, [1]], # cat head P4
  28. [-1, 3, C3, [512, False]], # 21 (P4/16-medium)
  29. [-1, 1, Conv, [512, 3, 2]],
  30. [[-1, 11], 1, Concat, [1]], # cat head P5
  31. [-1, 3, C3, [1024, False]], # 24 (P5/32-large)
  32. [[18, 21, 24], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
  33. ]

第二个版本是将ShuffleAttention放在backbone部分每个C3模块的后面,这样可以使注意力机制看到局部的特征,每层进行一次注意力,可以分担学习压力。

  1. # YOLOv5 v6.0 backbone
  2. backbone:
  3. # [from, number, module, args]
  4. [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
  5. [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
  6. [-1, 3, C3, [128]],
  7. [-1, 3, ShuffleAttention, [128]], # 3
  8. [-1, 1, Conv, [256, 3, 2]], # 4-P3/8
  9. [-1, 6, C3, [256]],
  10. [-1, 3, ShuffleAttention, [256]],
  11. [-1, 1, Conv, [512, 3, 2]], # 7-P4/16
  12. [-1, 9, C3, [512]],
  13. [-1, 3, ShuffleAttention, [512]],
  14. [-1, 1, Conv, [1024, 3, 2]], # 10 -P5/32
  15. [-1, 3, C3, [1024]],
  16. [-1, 3, ShuffleAttention, [1024]],
  17. [-1, 1, SPPF, [1024, 5]], # 13
  18. ]
  19. # YOLOv5 v6.0 head
  20. head:
  21. [[-1, 1, Conv, [512, 1, 1]],
  22. [-1, 1, nn.Upsample, [None, 2, 'nearest']],
  23. [[-1, 9], 1, Concat, [1]], # cat backbone P4
  24. [-1, 3, C3, [512, False]], # 17
  25. [-1, 1, Conv, [256, 1, 1]],
  26. [-1, 1, nn.Upsample, [None, 2, 'nearest']],
  27. [[-1, 6], 1, Concat, [1]], # cat backbone P3
  28. [-1, 3, C3, [256, False]], # 21 (P3/8-small)
  29. [-1, 1, Conv, [256, 3, 2]],
  30. [[-1, 18], 1, Concat, [1]], # cat head P4
  31. [-1, 3, C3, [512, False]], # 24 (P4/16-medium)
  32. [-1, 1, Conv, [512, 3, 2]],
  33. [[-1, 14], 1, Concat, [1]], # cat head P5
  34. [-1, 3, C3, [1024, False]], # 27 (P5/32-large)
  35. [[21, 24, 27], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
  36. ]

7.CrissCrossAttention注意力机制

同理,首先将下方代码添加在models文件夹下的common.py文件中,具体添加位置如果找不准可以选择common.py文件的最底端(最稳妥的做法,肯定不会错),或者C3模块后面(方便查找)。

  1. def INF(B,H,W):
  2. return -torch.diag(torch.tensor(float("inf")).repeat(H),0).unsqueeze(0).repeat(B*W,1,1).cuda()
  3. class CrissCrossAttention(nn.Module):
  4. """ Criss-Cross Attention Module"""
  5. def __init__(self, in_dim, out_channels, none):
  6. super(CrissCrossAttention,self).__init__()
  7. self.query_conv = nn.Conv2d(in_channels=in_dim, out_channels=in_dim//8, kernel_size=1)
  8. self.key_conv = nn.Conv2d(in_channels=in_dim, out_channels=in_dim//8, kernel_size=1)
  9. self.value_conv = nn.Conv2d(in_channels=in_dim, out_channels=in_dim, kernel_size=1)
  10. self.softmax = nn.Softmax(dim=3)
  11. self.INF = INF
  12. self.gamma = nn.Parameter(torch.zeros(1))
  13. def forward(self, x):
  14. m_batchsize, _, height, width = x.size()
  15. proj_query = self.query_conv(x)
  16. proj_query_H = proj_query.permute(0,3,1,2).contiguous().view(m_batchsize*width,-1,height).permute(0, 2, 1)
  17. proj_query_W = proj_query.permute(0,2,1,3).contiguous().view(m_batchsize*height,-1,width).permute(0, 2, 1)
  18. proj_key = self.key_conv(x)
  19. proj_key_H = proj_key.permute(0,3,1,2).contiguous().view(m_batchsize*width,-1,height)
  20. proj_key_W = proj_key.permute(0,2,1,3).contiguous().view(m_batchsize*height,-1,width)
  21. proj_value = self.value_conv(x)
  22. proj_value_H = proj_value.permute(0,3,1,2).contiguous().view(m_batchsize*width,-1,height)
  23. proj_value_W = proj_value.permute(0,2,1,3).contiguous().view(m_batchsize*height,-1,width)
  24. energy_H = (torch.bmm(proj_query_H, proj_key_H)+self.INF(m_batchsize, height, width)).view(m_batchsize,width,height,height).permute(0,2,1,3)
  25. energy_W = torch.bmm(proj_query_W, proj_key_W).view(m_batchsize,height,width,width)
  26. concate = self.softmax(torch.cat([energy_H, energy_W], 3))
  27. att_H = concate[:,:,:,0:height].permute(0,2,1,3).contiguous().view(m_batchsize*width,height,height)
  28. #print(concate)
  29. #print(att_H)
  30. att_W = concate[:,:,:,height:height+width].contiguous().view(m_batchsize*height,width,width)
  31. out_H = torch.bmm(proj_value_H, att_H.permute(0, 2, 1)).view(m_batchsize,width,-1,height).permute(0,2,3,1)
  32. out_W = torch.bmm(proj_value_W, att_W.permute(0, 2, 1)).view(m_batchsize,height,-1,width).permute(0,2,1,3)
  33. #print(out_H.size(),out_W.size())
  34. return self.gamma*(out_H + out_W) + x

第二步,需要更改models文件夹下的yolo.py文件。可以直接ctrl+F 然后查找parse_model关键字,定位到parse_model函数,你会发现有一段这样的代码

  1. if m in (Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv,
  2. BottleneckCSP, C3, C3TR, C3SPP, C3Ghost, nn.ConvTranspose2d, DWConvTranspose2d, C3x):
  3. c1, c2 = ch[f], args[0]
  4. if c2 != no: # if not output
  5. c2 = make_divisible(c2 * gw, 8)
  6. args = [c1, c2, *args[1:]]
  7. if m in [BottleneckCSP, C3, C3TR, C3Ghost, C3x]:
  8. args.insert(2, n) # number of repeats
  9. n = 1

我们仅需在第1行和第8行末尾添加CrissCrossAttention即可,具体做法如下

  1. if m in (Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv,
  2. BottleneckCSP, C3, C3new, C3new2, C3TR, C3SPP, C3Ghost, nn.ConvTranspose2d, DWConvTranspose2d, C3x, CrissCrossAttention):
  3. c1, c2 = ch[f], args[0]
  4. if c2 != no: # if not output
  5. c2 = make_divisible(c2 * gw, 8)
  6. args = [c1, c2, *args[1:]]
  7. if m in [BottleneckCSP, C3, C3new, C3new2, C3TR, C3Ghost, C3x, CrissCrossAttention]:
  8. args.insert(2, n) # number of repeats
  9. n = 1

第一个版本是将CrissCrossAttention放在backbone部分的最末端,这样可以使注意力机制看到整个backbone部分的特征图,将具有全局视野,类似于一个小transformer结构。

  1. # YOLOv5 v6.0 backbone
  2. backbone:
  3. # [from, number, module, args]
  4. [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
  5. [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
  6. [-1, 3, C3, [128]],
  7. [-1, 1, Conv, [256, 3, 2]], # 3-P3/8
  8. [-1, 6, C3, [256]],
  9. [-1, 1, Conv, [512, 3, 2]], # 5-P4/16
  10. [-1, 9, C3, [512]],
  11. [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
  12. [-1, 3, C3, [1024]],
  13. [-1, 1, SPPF, [1024, 5]], # 9
  14. [-1, 3, CrissCrossAttention, [1024]], # 10
  15. ]
  16. # YOLOv5 v6.0 head
  17. head:
  18. [[-1, 1, Conv, [512, 1, 1]],
  19. [-1, 1, nn.Upsample, [None, 2, 'nearest']],
  20. [[-1, 6], 1, Concat, [1]], # cat backbone P4
  21. [-1, 3, C3, [512, False]], # 14
  22. [-1, 1, Conv, [256, 1, 1]],
  23. [-1, 1, nn.Upsample, [None, 2, 'nearest']],
  24. [[-1, 4], 1, Concat, [1]], # cat backbone P3
  25. [-1, 3, C3, [256, False]], # 18 (P3/8-small)
  26. [-1, 1, Conv, [256, 3, 2]],
  27. [[-1, 15], 1, Concat, [1]], # cat head P4
  28. [-1, 3, C3, [512, False]], # 21 (P4/16-medium)
  29. [-1, 1, Conv, [512, 3, 2]],
  30. [[-1, 11], 1, Concat, [1]], # cat head P5
  31. [-1, 3, C3, [1024, False]], # 24 (P5/32-large)
  32. [[18, 21, 24], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
  33. ]

第二个版本是将CrissCrossAttention放在backbone部分每个C3模块的后面,这样可以使注意力机制看到局部的特征,每层进行一次注意力,可以分担学习压力。

  1. # YOLOv5 v6.0 backbone
  2. backbone:
  3. # [from, number, module, args]
  4. [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
  5. [-1, 1, Conv, [128, 3, 2]], # 1-P2/4
  6. [-1, 3, C3, [128]],
  7. [-1, 3, CrissCrossAttention, [128]], # 3
  8. [-1, 1, Conv, [256, 3, 2]], # 4-P3/8
  9. [-1, 6, C3, [256]],
  10. [-1, 3, CrissCrossAttention, [256]],
  11. [-1, 1, Conv, [512, 3, 2]], # 7-P4/16
  12. [-1, 9, C3, [512]],
  13. [-1, 3, CrissCrossAttention, [512]],
  14. [-1, 1, Conv, [1024, 3, 2]], # 10 -P5/32
  15. [-1, 3, C3, [1024]],
  16. [-1, 3, CrissCrossAttention, [1024]],
  17. [-1, 1, SPPF, [1024, 5]], # 13
  18. ]
  19. # YOLOv5 v6.0 head
  20. head:
  21. [[-1, 1, Conv, [512, 1, 1]],
  22. [-1, 1, nn.Upsample, [None, 2, 'nearest']],
  23. [[-1, 9], 1, Concat, [1]], # cat backbone P4
  24. [-1, 3, C3, [512, False]], # 17
  25. [-1, 1, Conv, [256, 1, 1]],
  26. [-1, 1, nn.Upsample, [None, 2, 'nearest']],
  27. [[-1, 6], 1, Concat, [1]], # cat backbone P3
  28. [-1, 3, C3, [256, False]], # 21 (P3/8-small)
  29. [-1, 1, Conv, [256, 3, 2]],
  30. [[-1, 18], 1, Concat, [1]], # cat head P4
  31. [-1, 3, C3, [512, False]], # 24 (P4/16-medium)
  32. [-1, 1, Conv, [512, 3, 2]],
  33. [[-1, 14], 1, Concat, [1]], # cat head P5
  34. [-1, 3, C3, [1024, False]], # 27 (P5/32-large)
  35. [[21, 24, 27], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
  36. ]

如需单独辅导改进(有偿) 可添加博主vx:Wansit99

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/289047
推荐阅读
相关标签
  

闽ICP备14008679号