yolo系列的网络作为单阶段目标检测网络中的佼佼者,在目标检测方面发挥着很大的作用,而yolov5是其中较好的一代网络,yolov8是其中最新的一代网络。但是作为我们学习和使用来说,原始的yolov5或者yolov8网络并不一定就是最合适的,基于此,在yolov5的基础上,针对主干网络进行了替换,替换成EfficientNetv2网络,yolov8的替换方式也是类似的。主要步骤如下:
首先,我们需要在common.py文件中添加如下代码段:(建议添加在common.py文件的最后
class stem(nn.Module):
def __init__(self, c1, c2, kernel_size=3, stride=1, groups=1):
super(stem, self).__init__()
padding = (kernel_size-1) // 2
self.conv = nn.Conv2d(c1, c2, kernel_size, stride, padding=padding, groups=groups, bias=False)
self.bn = nn.BatchNorm2d(c2, eps=1e-3, momentum=0.1)
self.act = nn.SiLU(True)
def forward(self, x):
#print(x.shape)
x = self.conv(x)
x = self.bn(x)
x = self.act(x)
return x
def drop_path(x, drop_prob: float = 0., training: bool = False):
if drop_prob == 0. or not training:
return x
keep_prob = 1 - drop_prob
shape = (x.shape[0],) + (1,) * (x.ndim - 1)
random_tensor = keep_prob + torch.rand(shape, dtype=x.dtype, device=x.device)
random_tensor.floor_()
output = x.div(keep_prob) * random_tensor
return output
class DropPath(nn.Module):
def __init__(self, drop_prob=None):
super(DropPath, self).__init__()
self.drop_prob = drop_prob
def forward(self, x):
return drop_path(x, self.drop_prob, self.training)
class SqueezeExcite_efficientv2(nn.Module):
def __init__(self, c1, c2, se_ratio=0.25, act_layer=nn.ReLU):
super(SqueezeExcite_efficientv2, self).__init__()
self.gate_fn = nn.Sigmoid()
reduced_chs = int(c1 * se_ratio)
self.avg_pool = nn.AdaptiveAvgPool2d(1)
self.conv_reduce = nn.Conv2d(c1, reduced_chs, 1, bias=True)
self.act1 = act_layer(inplace=True)
self.conv_expand = nn.Conv2d(reduced_chs, c2, 1, bias=True)
def forward(self, x):
x_se = self.avg_pool(x)
x_se = self.conv_reduce(x_se)
x_se = self.act1(x_se)
x_se = self.conv_expand(x_se)
x_se = self.gate_fn(x_se)
x = x * (x_se.expand_as(x))
return x
class FusedMBConv(nn.Module):
def __init__(self, c1, c2, k=3, s=1, expansion=1, se_ration=0, dropout_rate=0.2, drop_connect_rate=0.2):
super().__init__()
self.has_shortcut = (s == 1 and c1 == c2)
self.has_expansion = expansion != 1
expanded_c = c1 * expansion
if self.has_expansion:
self.expansion_conv = stem(c1, expanded_c, kernel_size=k, stride=s)
self.project_conv = stem(expanded_c, c2, kernel_size=1, stride=1)
else:
self.project_conv = stem(c1, c2, kernel_size=k, stride=s)
self.drop_connect_rate = dropout_rate
if self.has_shortcut and drop_connect_rate > 0:
self.dropout = DropPath(drop_connect_rate)
def forward(self, x):
if self.has_expansion:
result = self.expansion_conv(x)
result = self.project_conv(result)
else:
result = self.project_conv(x)
if self.has_shortcut:
if self.drop_connect_rate > 0:
result = self.dropout(result)
result += x
return result
class MBConv(nn.Module):
def __init__(self, c1, c2, k=3, s=1, expansion=1, se_ration=0, dropout_rate=0.2, drop_connect_rate=0.2):
super(MBConv, self).__init__()
self.has_shortcut = (s == 1 and c1 == c2)
expanded_c = c1 * expansion
self.expansion_conv = stem(c1, expanded_c, kernel_size=1, stride=1)
self.dw_conv = stem(expanded_c, expanded_c, kernel_size=k, stride=s, groups=expanded_c)
self.se = SqueezeExcite_efficientv2(expanded_c, expanded_c, se_ration) if se_ration > 0 else nn.Identity()
self.project_conv = stem(expanded_c, c2, kernel_size=1, stride=1)
self.drop_connect_rate = drop_connect_rate
if self.has_shortcut and drop_connect_rate > 0:
self.dropout = DropPath(drop_connect_rate)
def forward(self, x):
result = self.expansion_conv(x)
result = self.dw_conv(result)
result = self.se(result)
result = self.project_conv(result)
if self.has_shortcut:
if self.drop_connect_rate > 0:
result = self.dropout(result)
result += x
return result
这部分代码需要全复制到common.py文件中。
接下来是要对上诉代码中的关键函数进行声明,在yolo.py文件中加入以下两个类名,具体的添加位置可以通过Ctrl+F的形式搜索关键词找到。添加的部分为图片中红框圈起来的几个。
最后就是在配置文件里面修改原始网络的主干网络了。最好的方式是复制一份原本的yolov5s.yaml文件,然后将其重新命名,将里面的代码全部换成以下部分:
# YOLOv5 🚀 by Ultralytics, GPL-3.0 license
# Parameters
nc: 80 # 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
backbone:
# [from, number, module, args]
[[-1, 1, stem, [24, 3, 2]], # 0-P1/2
[-1, 2, FusedMBConv, [24, 3, 1, 1, 0]], # 1-P2/4
[-1, 1, FusedMBConv, [48, 3, 2, 4, 0]],
[-1, 3, FusedMBConv, [48, 3, 1, 4, 0]], # 3-P3/8
[-1, 1, FusedMBConv, [64, 3, 2, 4, 0]],
[-1, 3, FusedMBConv, [64, 3, 1, 4, 0]], # 5-P4/16
[-1, 1, MBConv, [128, 3, 2, 4, 0.25]],
[-1, 5, MBConv, [128, 3, 1, 4, 0.25]], # 7-P5/32
[-1, 1, MBConv, [160, 3, 2, 6, 0.25]],
[-1, 8, MBConv, [160, 3, 1, 6, 0.25]], # 9
[-1, 1, MBConv, [256, 3, 2, 4, 0.25]], #10
[-1, 14, MBConv, [256, 3, 1, 4, 0.25]], #11
[-1, 1, SPPF, [1024, 5]], #12
]
# YOLOv5 v6.0 head
head:
[[-1, 1, Conv, [512, 1, 1]],
[-1, 1, nn.Upsample, [None, 2, 'nearest']],
[[-1, 9], 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, 7], 1, Concat, [1]], # cat backbone P3
[-1, 3, C3, [256, False]], # 17 (P3/8-small)
[-1, 1, Conv, [256, 3, 2]],
[[-1, 17], 1, Concat, [1]], # cat head P4
[-1, 3, C3, [512, False]], # 20 (P4/16-medium)
[-1, 1, Conv, [512, 3, 2]],
[[-1, 13], 1, Concat, [1]], # cat head P5
[-1, 3, C3, [1024, False]], # 23 (P5/32-large)
[[20, 23, 26], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
]
至此,所有的修改全部完成了,但是需要注意的一点是,在训练时,一定要将训练中的yolov5s.yaml配置文件替换成修改过后的配置文件。
学不了一点
版权归原作者 爱改网络的法式小面包 所有, 如有侵权,请联系我们删除。