修改YOLOV5的Backbone为shufflenetv2

引言

  • YOLOV5是一个速度和精度表现都非常优秀的目标检测算法,但我们在使用过程中有自己各种各样的需求,官方原本的代码可能不能满足我们需要,比如检测小目标,我们就需要使用对小目标检测效果好的Backbone,或者想要移植到嵌入设备上,我们就需要轻量化的Backbone。因此,在面对不同的任务需求的时候,我们需要采用不同的Backbone。下面就开始今天教程的正文。

  • YOLOV5官方仓库代码:

  • GitHub - ultralytics/yolov5: YOLOv5 🚀 in PyTorch > ONNX > CoreML > TFLite

修改backbone为 shufflenetv2

  • 我将YOLOv5修改Backbone的步骤分为以下四步:定义、注册、配置和使用

第一步、定义模块

在models/common.py中定义自己需要使用到的模块儿

首先,在common.py的顶部导入依赖包

    from torch import Tensor 
    from typing import Callable, Any, List

img

将ShuffleNetV2_InvertedResidual类和ShuffleNetV2_InvertedResidual类需要的channel_shuffle、conv_bn_relu_maxpool类都加入到common.py的底部

img

    def channel_shuffle(x: Tensor, groups: int) -> Tensor: 
        batchsize, num_channels, height, width = x.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 ShuffleNetV2_InvertedResidual(nn.Module): 
        def __init__( 
            self, 
            inp: int, 
            oup: int, 
            stride: int 
        ) -> None: 
            super(ShuffleNetV2_InvertedResidual, 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), 
                ) 
            else: 
                self.branch1 = nn.Sequential() 
     
            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: int, 
            o: int, 
            kernel_size: int, 
            stride: int = 1, 
            padding: int = 0, 
            bias: bool = False 
        ) -> nn.Conv2d: 
            return nn.Conv2d(i, o, kernel_size, stride, padding, bias=bias, groups=i) 
     
        def forward(self, x: Tensor) -> Tensor: 
            if self.stride == 1: 
                x1, x2 = x.chunk(2, dim=1) 
                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

第二步、注册模块

第一步,我们在models/common.py中定义了ShuffleNetV2_InvertedResidual类,但是YOLO算法并不知道我们定义了这个类,我们还需要YOLO的参数解析处对这个类名进行注册

在models/yolo.py的parse_model函数中注册加入InvertedResidual,这样在解析YAML文件的时候就知道配置文件中的字符串“InvertedResidual”对应的类了,在原版YOV5的基础上,一共需要另外注册ShuffleNetV2_InvertedResidual、conv_bn_relu_maxpool两个类

img

  if m in [Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv, 
                   BottleneckCSP, C3, C3TR, C3SPP, C3Ghost, CoordAtt,ShuffleNetV2_InvertedResidual,conv_bn_relu_maxpool]:

第三步、配置结构

新建一个YAML文件,命名为yolov5s-shufflenetv2.yaml,具体配置如下

  # parameters 
  nc: 80  # number of classes 
  depth_multiple: 1.0  # model depth multiple 
  width_multiple: 0.5  # layer channel multiple 
   
  # anchors 
  anchors: 
    - [4,5,  8,10,  13,16]  # P3/8 
    - [23,29,  43,55,  73,105]  # P4/16 
    - [146,217,  231,300,  335,433]  # P5/32 
   
  # custom backbone 
  backbone: 
    # [from, number, module, args] 
    [[-1, 1, conv_bn_relu_maxpool, [3]],    # 0-P2/4 
     [-1, 1, ShuffleNetV2_InvertedResidual, [128, 2]], # 1-P3/8 
     [-1, 3, ShuffleNetV2_InvertedResidual, [128, 1]], # 2 
     [-1, 1, ShuffleNetV2_InvertedResidual, [256, 2]], # 3-P4/16 
     [-1, 7, ShuffleNetV2_InvertedResidual, [256, 1]], # 4 
     [-1, 1, ShuffleNetV2_InvertedResidual, [512, 2]], # 5-P5/32 
     [-1, 3, ShuffleNetV2_InvertedResidual, [512, 1]], # 6 
    ] 
   
  # YOLOv5 head 
  head: 
    [[-1, 1, Conv, [128, 1, 1]], 
     [-1, 1, nn.Upsample, [None, 2, 'nearest']], 
     [[-1, 4], 1, Concat, [1]],  # cat backbone P4 
     [-1, 1, C3, [128, 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, [128, False]],  # 17 (P4/16-medium) 
   
     [-1, 1, Conv, [128, 3, 2]], 
     [[-1, 7], 1, Concat, [1]],  # cat head P5 
     [-1, 1, C3, [128, False]],  # 20 (P5/32-large) 
   
     [[14, 17, 20], 1, Detect, [nc, anchors]],  # Detect(P3, P4, P5) 
    ]

第四步、使用

完成上述工作之后,我们就可以在train.py中使用刚才创建的那个配置文件了

  parser.add_argument('--cfg', type=str, default='yolov5s-shufflenetv2.yaml', help='model.yaml path')

img

之后网络就可以使用这个yolov5-shufflenetv2.yaml配置文件愉快的训练起来了

结语

  • 到这里,这个YOLOv5修改Backbone为shufflenetv2的教程已经结束了,相信大家如果手把手的严格按照我的这个教程在官方原版代码上面进行修改的话,一般情况下可以成功。
  • 不过这个教程上面只讲了如何进行修改,配置文件是直接给出的,并没有和大家讲解这个配置文件具体的修改方法,我们放在下一个教程中展开。
  • 6
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
### 回答1: rtmdet是一个目标检测框架,它支持使用多种检测算法,包括YOLOv5。如果你想在rtmdet中使用YOLOv5,你需要创建一个YOLOv5的配置文件。 YOLOv5的配置文件是一个YAML文件,包含了模型的超参数以及训练和验证所需的一些参数。下面是一个示例配置文件: ``` model: type: yolov5 backbone: type: cspdarknet53 anchors: - [10, 13, 16, 30, 33, 23] - [30, 61, 62, 45, 59, 119] - [116, 90, 156, 198, 373, 326] heads: - [yolo, anchor_mask=[0, 1, 2], anchor_size=[2, 3]] neck: type: pan bbox_head: type: yolo train_cfg: type: yolo test_cfg: type: yolo loss_type: mse pretrained: False train: dataset: type: coco data_root: /path/to/coco/dataset ann_file: /path/to/coco/annotations/train.json batch_size: 64 num_workers: 4 shuffle: True val: dataset: type: coco data_root: /path/to/coco/dataset ann_file: /path/to/coco/annotations/val.json batch_size: 64 num_workers: 4 shuffle: False ``` 在这个配置文件中,你可以设置模型的类型、backbone、anchors、heads、neck等参数。你还可以设置训练和测试所用的数据集以及训练和测试的参数,例如批大小、工作进程数量等。 希望这能帮到你!如果你还有其他问题,欢迎继续提问。 ### 回答2: 要将rtmdet转换为yolov5配置文件格式,需要进行以下步骤: 1. 理解rtmdet和yolov5的配置文件格式之间的区别。rtmdet是一个目标检测模型,而yolov5是另一种目标检测模型。两者的配置文件格式有一些差异,包括不同的参数和选项。 2. 打开rtmdet的配置文件,通常是以.yaml或.json为扩展名的文本文件。这个文件定义了rtmdet模型的结构、超参数和其他相关信息。 3. 根据yolov5的配置文件格式要求,创建一个新的配置文件。yolov5的配置文件通常是以.yaml为扩展名的文本文件。 4. 将rtmdet配置文件中的参数和选项转换为yolov5的格式,并将其写入新的yolov5配置文件中。这可能包括修改模型的输入和输出通道,调整网络结构和参数,以及更新训练和推理的超参数。 5. 验证新的yolov5配置文件,确保其结构和参数与yolov5模型的要求相符。可以参考yolov5的文档或示例配置文件来进行验证。 6. 将新的yolov5配置文件保存,并在训练或推理时使用该配置文件。 需要注意的是,rtmdet和yolov5是不同的目标检测模型,其配置文件格式有所差异。转换配置文件时,需要仔细阅读和理解两个模型的文档,以确保正确地将参数和选项转换为yolov5的格式。此外,还应该注意两个模型可能具有不同的默认值和配置要求,需要进行相应的调整和修改。 ### 回答3: 要将rtmdet(Real-Time Multi-object Detection)的配置文件格式改为YoloV5的格式,需要进行以下步骤: 1. 根据YoloV5的配置文件格式,先了解其结构和语法要求。 YoloV5的配置文件格式主要包括:模型的超参数设置、训练集和验证集的路径、类别标签等。 2. 打开rtmdet的配置文件,通常为一个文本文件,其中包含了当前模型的配置信息。该文件可能使用不同的格式,如JSON、XML等。 3. 将rtmdet配置文件的结构与YoloV5的配置文件进行对比。找出相似部分,并根据YoloV5的要求进行调整。 4. 针对不同部分进行具体修改: - 调整模型的超参数:包括网络结构、输入尺寸、训练时的学习率等。根据rtmdet的配置文件,将相应的参数调整为YoloV5所要求的格式。 - 修改训练集和验证集的路径:根据YoloV5的数据集路径格式,可以将rtmdet的路径进行相应调整。 - 更新类别标签:根据rtmdet所需要检测的物体类别,将其与YoloV5的类别标签进行对应。 5. 根据YoloV5的配置文件格式,对修改后的rtmdet配置文件进行格式验证。确保文件结构正确,参数符合YoloV5的要求。 6. 保存修改后的配置文件,并将其用于YoloV5模型的训练和推理过程。 需要注意的是,具体的配置文件格式要求可能因rtmdet和YoloV5版本的不同而有所变化,因此在进行文件格式改动时,要根据具体情况进行调整。同时,如果可能的话,建议参考rtmdet和YoloV5的官方文档,以获取更准确和详细的配置文件格式信息。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值