yolov5-7.0修改骨干网络Ghostnet\efficientnet_b0\MobileNetv3_small\ShuffleNetV2

修改骨干网络主要需要添加模块到models/common.py文件中,在models/yolo.py文件夹中进行注册,修改models下面的yaml文件中的网络结构。

一、添加Ghostnet网络,替换Backbone

(yolov5-7.0的models/hu/yolov5s-ghost已经包含整体替换):

class C3Ghost(C3):

    # C3 module with GhostBottleneck()

    def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):

        super().__init__(c1, c2, n, shortcut, g, e)

        c_ = int(c2 * e)  # hidden channels

        self.m = nn.Sequential(*(GhostBottleneck(c_, c_) for _ in range(n)))



class GhostConv(nn.Module):

    # Ghost Convolution https://github.com/huawei-noah/ghostnet

    def __init__(self, c1, c2, k=1, s=1, g=1, act=True):  # ch_in, ch_out, kernel, stride, groups

        super().__init__()

        c_ = c2 // 2  # hidden channels

        self.cv1 = Conv(c1, c_, k, s, None, g, act=act)

        self.cv2 = Conv(c_, c_, 5, 1, None, c_, act=act)



    def forward(self, x):

        y = self.cv1(x)

        return torch.cat((y, self.cv2(y)), 1)

class GhostBottleneck(nn.Module):

    # Ghost Bottleneck https://github.com/huawei-noah/ghostnet

    def __init__(self, c1, c2, k=3, s=1):  # ch_in, ch_out, kernel, stride

        super().__init__()

        c_ = c2 // 2

        self.conv = nn.Sequential(

            GhostConv(c1, c_, 1, 1),  # pw

            DWConv(c_, c_, k, s, act=False) if s == 2 else nn.Identity(),  # dw

            GhostConv(c_, c2, 1, 1, act=False))  # pw-linear

        self.shortcut = nn.Sequential(DWConv(c1, c1, k, s, act=False), Conv(c1, c2, 1, 1,

                                                                            act=False)) if s == 2 else nn.Identity()



    def forward(self, x):

        return self.conv(x) + self.shortcut(x)

修改步骤:

1. common.py与yolo.py文件已经包含ghost相关模块的配置和引用;

2.yolov5s_Ghost_backnone.yaml文件配置

# YOLOv5 ��� by Ultralytics, AGPL-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, Conv, [64, 6, 2, 2]],  # 0-P1/2

   [-1, 1, GhostConv, [128, 3, 2]],  # 1-P2/4

   [-1, 3, C3Ghost, [128]],

   [-1, 1, GhostConv, [256, 3, 2]],  # 3-P3/8

   [-1, 6, C3Ghost, [256]],

   [-1, 1, GhostConv, [512, 3, 2]],  # 5-P4/16

   [-1, 9, C3Ghost, [512]],

   [-1, 1, GhostConv, [1024, 3, 2]],  # 7-P5/32

   [-1, 3, C3Ghost, [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)

  ]

二、添加efficientnet_b0网络

修改步骤:

1. common.py

# ---------------------------- efficientnet_b0 start -------------------------------



class effb0(nn.Module):

    def __init__(self, *args) -> None:

        super().__init__()

        model = models.efficientnet_b0(pretrained=True)

        modules = list(model.children())

        modules = modules[0][args[1]:args[2]]

        self.model = nn.Sequential(*modules)

    def forward(self, x):

        return self.model(x)



# ---------------------------- efficientnet_b0 end ---------------------------------

2. yolo.py文件

parse_model函数中添加

 elif m is effb0:    
              
            c2 = args[0]

3. yolov5s_efficientnet_b0.yaml文件配置

# YOLOv5 ��� by Ultralytics, GPL-3.0 license



# Parameters

nc: 80  # number of classes

depth_multiple: 0.33  # model depth multiple

width_multiple: 0.25  # 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, effb0, [40,0,4]],  # 0

   [-1, 1, effb0, [112,4,6]],  # 1

   [-1, 1, effb0, [1280,6,9]],  # 2

   [-1, 1, SPPF, [1024, 5]],  # 3

  ]



# YOLOv5 v6.0 head

head:

  [[-1, 1, Conv, [512, 1, 1]],

   [-1, 1, nn.Upsample, [None, 2, 'nearest']],

   [[-1, 1], 1, Concat, [1]],  # cat backbone P4

   [-1, 3, C3, [512, False]],  # 7



   [-1, 1, Conv, [256, 1, 1]],

   [-1, 1, nn.Upsample, [None, 2, 'nearest']],

   [[-1, 0], 1, Concat, [1]],  # cat backbone P3

   [-1, 3, C3, [256, False]],  # 11 (P3/8-small)



   [-1, 1, Conv, [256, 3, 2]],

   [[-1, 7], 1, Concat, [1]],  # cat head P4

   [-1, 3, C3, [512, False]],  # 14 (P4/16-medium)



   [-1, 1, Conv, [512, 3, 2]],

   [[-1, 3], 1, Concat, [1]],  # cat head P5

   [-1, 3, C3, [1024, False]],  # 17 (P5/32-large)



   [[11, 14, 17], 1, Detect, [nc, anchors]],  # Detect(P3, P4, P5)

  ]

三、添加MobileNetv3_small网络

修改步骤:

1. common.py

# ---------------------------- MobileBlock small start -------------------------------

# Mobilenetv3Small

class SeBlock(nn.Module):

    def __init__(self, in_channel, reduction=4):

        super().__init__()

        self.Squeeze = nn.AdaptiveAvgPool2d(1)



        self.Excitation = nn.Sequential()

        self.Excitation.add_module('FC1', nn.Conv2d(in_channel, in_channel // reduction, kernel_size=1))  # 1*1卷积与此效果相同

        self.Excitation.add_module('ReLU', nn.ReLU())

        self.Excitation.add_module('FC2', nn.Conv2d(in_channel // reduction, in_channel, kernel_size=1))

        self.Excitation.add_module('Sigmoid', nn.Sigmoid())



    def forward(self, x):

        y = self.Squeeze(x)

        ouput = self.Excitation(y)

        return x * (ouput.expand_as(x))





class Conv_BN_HSwish(nn.Module):

    """

    This equals to

    def conv_3x3_bn(inp, oup, stride):

        return nn.Sequential(

            nn.Conv2d(inp, oup, 3, stride, 1, bias=False),

            nn.BatchNorm2d(oup),

            h_swish()

        )

    """



    def __init__(self, c1, c2, stride):

        super(Conv_BN_HSwish, self).__init__()

        self.conv = nn.Conv2d(c1, c2, 3, stride, 1, bias=False)

        self.bn = nn.BatchNorm2d(c2)

        self.act = nn.Hardswish()



    def forward(self, x):

        return self.act(self.bn(self.conv(x)))





class MobileNetV3_InvertedResidual(nn.Module):

    def __init__(self, inp, oup, hidden_dim, kernel_size, stride, use_se, use_hs):

        super(MobileNetV3_InvertedResidual, self).__init__()

        assert stride in [1, 2]



        self.identity = stride == 1 and inp == oup



        if inp == hidden_dim:

            self.conv = nn.Sequential(

                # dw

                nn.Conv2d(hidden_dim, hidden_dim, kernel_size, stride, (kernel_size - 1) // 2, groups=hidden_dim,

                          bias=False),

                nn.BatchNorm2d(hidden_dim),

                nn.Hardswish() if use_hs else nn.ReLU(),

                # Squeeze-and-Excite

                SeBlock(hidden_dim) if use_se else nn.Sequential(),

                # pw-linear

                nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False),

                nn.BatchNorm2d(oup),

            )

        else:

            self.conv = nn.Sequential(

                # pw

                nn.Conv2d(inp, hidden_dim, 1, 1, 0, bias=False),

                nn.BatchNorm2d(hidden_dim),

                nn.Hardswish() if use_hs else nn.ReLU(),

                # dw

                nn.Conv2d(hidden_dim, hidden_dim, kernel_size, stride, (kernel_size - 1) // 2, groups=hidden_dim,

                          bias=False),

                nn.BatchNorm2d(hidden_dim),

                # Squeeze-and-Excite

                SeBlock(hidden_dim) if use_se else nn.Sequential(),

                nn.Hardswish() if use_hs else nn.ReLU(),

                # pw-linear

                nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False),

                nn.BatchNorm2d(oup),

            )



    def forward(self, x):

        y = self.conv(x)

        if self.identity:

            return x + y

        else:

            return y



# ---------------------------- MobileBlock end ---------------------------------

2. yolo.py文件

在parse_model函数中引入 Conv_BN_HSwish, MobileNetV3_InvertedResidual模块   

if m in {

                Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv,     #cyz

                BottleneckCSP, C3, C3TR, C3SPP, C3Ghost, nn.ConvTranspose2d, DWConvTranspose2d, C3x,

                Conv_BN_HSwish, MobileNetV3_InvertedResidual,conv_bn_relu_maxpool, Shuffle_Block}

 3.  yolov5s_MobileNetv3_small.yaml文件配置

# YOLOv5 ��� by Ultralytics, GPL-3.0 license



# Parameters

nc: 1  # number of classes

depth_multiple: 1.0  # model depth multiple

width_multiple: 1.0  # 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



   # Mobilenetv3-small backbone

   # MobileNetV3_InvertedResidual [out_ch, hid_ch, k_s, stride, SE, HardSwish]

backbone:

  # [from, number, module, args]

  [[-1, 1, Conv_BN_HSwish, [16, 2]],                              # 0-p1/2

   [-1, 1, MobileNetV3_InvertedResidual, [16,  16, 3, 2, 1, 0]],  # 1-p2/4

   [-1, 1, MobileNetV3_InvertedResidual, [24,  72, 3, 2, 0, 0]],  # 2-p3/8

   [-1, 1, MobileNetV3_InvertedResidual, [24,  88, 3, 1, 0, 0]],  # 3

   [-1, 1, MobileNetV3_InvertedResidual, [40,  96, 5, 2, 1, 1]],  # 4-p4/16

   [-1, 1, MobileNetV3_InvertedResidual, [40, 240, 5, 1, 1, 1]],  # 5

   [-1, 1, MobileNetV3_InvertedResidual, [40, 240, 5, 1, 1, 1]],  # 6

   [-1, 1, MobileNetV3_InvertedResidual, [48, 120, 5, 1, 1, 1]],  # 7

   [-1, 1, MobileNetV3_InvertedResidual, [48, 144, 5, 1, 1, 1]],  # 8

   [-1, 1, MobileNetV3_InvertedResidual, [96, 288, 5, 2, 1, 1]],  # 9-p5/32

   [-1, 1, MobileNetV3_InvertedResidual, [96, 576, 5, 1, 1, 1]],  # 10

   [-1, 1, MobileNetV3_InvertedResidual, [96, 576, 5, 1, 1, 1]],  # 11

  ]



# YOLOv5 v6.0 head

head:

  [[-1, 1, Conv, [96, 1, 1]],  # 12

   [-1, 1, nn.Upsample, [None, 2, 'nearest']],

   [[-1, 8], 1, Concat, [1]],  # cat backbone P4

   [-1, 3, C3, [144, False]],  # 15



   [-1, 1, Conv, [144, 1, 1]], # 16

   [-1, 1, nn.Upsample, [None, 2, 'nearest']],

   [[-1, 3], 1, Concat, [1]],  # cat backbone P3

   [-1, 3, C3, [168, False]],  # 19 (P3/8-small)



   [-1, 1, Conv, [168, 3, 2]],

   [[-1, 16], 1, Concat, [1]], # cat head P4

   [-1, 3, C3, [312, False]],  # 22 (P4/16-medium)



   [-1, 1, Conv, [312, 3, 2]],

   [[-1, 12], 1, Concat, [1]], # cat head P5

   [-1, 3, C3, [408, False]],  # 25 (P5/32-large)



   [[19, 22, 25], 1, Detect, [nc, anchors]],  # Detect(P3, P4, P5)

  ]

四、添加ShuffleNetV2网络

修改步骤:

1.common.py

# ---------------------------- ShuffleBlock start -------------------------------



# 通道重排,跨group信息交流

def channel_shuffle(x, groups):

    batchsize, num_channels, height, width = x.data.size()

    channels_per_group = num_channels // groups



    # reshape

    x = x.view(batchsize, groups,

               channels_per_group, height, width)



    x = torch.transpose(x, 1, 2).contiguous()



    # flatten

    x = x.view(batchsize, -1, height, width)



    return x





class conv_bn_relu_maxpool(nn.Module):

    def __init__(self, c1, c2):  # ch_in, ch_out

        super(conv_bn_relu_maxpool, self).__init__()

        self.conv = nn.Sequential(

            nn.Conv2d(c1, c2, kernel_size=3, stride=2, padding=1, bias=False),

            nn.BatchNorm2d(c2),

            nn.ReLU(inplace=True),

        )

        self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)



    def forward(self, x):

        return self.maxpool(self.conv(x))





class Shuffle_Block(nn.Module):

    def __init__(self, inp, oup, stride):

        super(Shuffle_Block, self).__init__()



        if not (1 <= stride <= 3):

            raise ValueError('illegal stride value')

        self.stride = stride



        branch_features = oup // 2

        assert (self.stride != 1) or (inp == branch_features << 1)



        if self.stride > 1:

            self.branch1 = nn.Sequential(

                self.depthwise_conv(inp, inp, kernel_size=3, stride=self.stride, padding=1),

                nn.BatchNorm2d(inp),

                nn.Conv2d(inp, branch_features, kernel_size=1, stride=1, padding=0, bias=False),

                nn.BatchNorm2d(branch_features),

                nn.ReLU(inplace=True),

            )



        self.branch2 = nn.Sequential(

            nn.Conv2d(inp if (self.stride > 1) else branch_features,

                      branch_features, kernel_size=1, stride=1, padding=0, bias=False),

            nn.BatchNorm2d(branch_features),

            nn.ReLU(inplace=True),

            self.depthwise_conv(branch_features, branch_features, kernel_size=3, stride=self.stride, padding=1),

            nn.BatchNorm2d(branch_features),

            nn.Conv2d(branch_features, branch_features, kernel_size=1, stride=1, padding=0, bias=False),

            nn.BatchNorm2d(branch_features),

            nn.ReLU(inplace=True),

        )



    @staticmethod

    def depthwise_conv(i, o, kernel_size, stride=1, padding=0, bias=False):

        return nn.Conv2d(i, o, kernel_size, stride, padding, bias=bias, groups=i)



    def forward(self, x):

        if self.stride == 1:

            x1, x2 = x.chunk(2, dim=1)  # 按照维度1进行split

            out = torch.cat((x1, self.branch2(x2)), dim=1)

        else:

            out = torch.cat((self.branch1(x), self.branch2(x)), dim=1)



        out = channel_shuffle(out, 2)



        return out





# ---------------------------- ShuffleBlock end --------------------------------

2. yolo.py文件

在parse_model函数中引入 conv_bn_relu_maxpool, Shuffle_Block模块:

 if m in {

                Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv,     #cyz

                BottleneckCSP, C3, C3TR, C3SPP, C3Ghost, nn.ConvTranspose2d, DWConvTranspose2d, C3x,

                Conv_BN_HSwish, MobileNetV3_InvertedResidual,conv_bn_relu_maxpool, Shuffle_Block}:

            c1, c2 = ch[f], args[0]



3. yolov5s_ShuffleNetV2.yaml文件配置

# YOLOv5 ��� by Ultralytics, GPL-3.0 license



# Parameters

nc: 20  # number of classes

depth_multiple: 1.0  # model depth multiple

width_multiple: 1.0  # 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]

  # Shuffle_Block: [out, stride]

  [[ -1, 1, conv_bn_relu_maxpool, [ 32 ] ], # 0-P2/4

   [ -1, 1, Shuffle_Block, [ 128, 2 ] ],  # 1-P3/8

   [ -1, 3, Shuffle_Block, [ 128, 1 ] ],  # 2

   [ -1, 1, Shuffle_Block, [ 256, 2 ] ],  # 3-P4/16

   [ -1, 7, Shuffle_Block, [ 256, 1 ] ],  # 4

   [ -1, 1, Shuffle_Block, [ 512, 2 ] ],  # 5-P5/32

   [ -1, 3, Shuffle_Block, [ 512, 1 ] ],  # 6

  ]



# YOLOv5 v6.0 head

head:

  [[-1, 1, Conv, [256, 1, 1]],

   [-1, 1, nn.Upsample, [None, 2, 'nearest']],

   [[-1, 4], 1, Concat, [1]],  # cat backbone P4

   [-1, 1, C3, [256, False]],  # 10



   [-1, 1, Conv, [128, 1, 1]],

   [-1, 1, nn.Upsample, [None, 2, 'nearest']],

   [[-1, 2], 1, Concat, [1]],  # cat backbone P3

   [-1, 1, C3, [128, False]],  # 14 (P3/8-small)



   [-1, 1, Conv, [128, 3, 2]],

   [[-1, 11], 1, Concat, [1]],  # cat head P4

   [-1, 1, C3, [256, False]],  # 17 (P4/16-medium)



   [-1, 1, Conv, [256, 3, 2]],

   [[-1, 7], 1, Concat, [1]],  # cat head P5

   [-1, 1, C3, [512, False]],  # 20 (P5/32-large)



   [[14, 17, 20], 1, Detect, [nc, anchors]],  # Detect(P3, P4, P5)

  ]

  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值