精华内容
下载资源
问答
  • yolov5主干网络
    千次阅读
    2022-07-04 09:10:33

    ​前 言:作为当前先进的深度学习目标检测算法YOLOv5,已经集合了大量的trick,但是还是有提高和改进的空间,针对具体应用场景下的检测难点,可以不同的改进方法。此后的系列文章,将重点对YOLOv5的如何改进进行详细的介绍,目的是为了给那些搞科研的同学需要创新点或者搞工程项目的朋友需要达到更好的效果提供自己的微薄帮助和参考。

    解决问题:YOLOv5主干特征提取网络采用C3结构,带来较大的参数量,检测速度较慢,应用受限,在某些真实的应用场景如移动或者嵌入式设备,如此大而复杂的模型时难以被应用的。首先是模型过于庞大,面临着内存不足的问题,其次这些场景要求低延迟,或者说响应速度要快,想象一下自动驾驶汽车的行人检测系统如果速度很慢会发生什么可怕的事情。所以,研究小而高效的CNN模型在这些场景至关重要,至少目前是这样,尽管未来硬件也会越来越快。本文尝试将主干特征提取网络替换为更轻量的MobileNet网络,以实现网络模型的轻量化,平衡速度和精度。

    原理:

    论文地址:https://arxiv.org/abs/1905.02244.pdf

    代 码:https://github.com/LeBron-Jian/DeepLearningNote

    MobileNet V3 相关技术如下:

    • 1,用 MnasNet 搜索网络结构

    • 2,用 V1 的深度可分离

    • 3,用 V2 的倒置残差线性瓶颈结构

    • 4,引入 SE模块

    • 5,新的激活函数 h-swish(x)

    • 6,网络搜索中利用两个策略:资源受限的 NAS 和 NetAdapt

    • 7,修改 V2 最后部分减小计算

    方 法:

    第一步修改common.py,增加MobileNetV3模块。部分代码如下。

    class StemBlock(nn.Module):
        def __init__(self, c1, c2, k=3, s=2, p=None, g=1, act=True):
            super(StemBlock, self).__init__()
            self.stem_1 = Conv(c1, c2, k, s, p, g, act)
            self.stem_2a = Conv(c2, c2 // 2, 1, 1, 0)
            self.stem_2b = Conv(c2 // 2, c2, 3, 2, 1)
            self.stem_2p = nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True)
            self.stem_3 = Conv(c2 * 2, c2, 1, 1, 0)
    
        def forward(self, x):
            stem_1_out = self.stem_1(x)
            stem_2a_out = self.stem_2a(stem_1_out)
            stem_2b_out = self.stem_2b(stem_2a_out)
            stem_2p_out = self.stem_2p(stem_1_out)
            out = self.stem_3(torch.cat((stem_2b_out, stem_2p_out), 1))
            return out
    
    
    
    class h_swish(nn.Module):
        def __init__(self, inplace=True):
            super(h_swish, self).__init__()
            self.sigmoid = h_sigmoid(inplace=inplace)
    
        def forward(self, x):
            y = self.sigmoid(x)
            return x * y
    
    
    class SELayer(nn.Module):
        def __init__(self, channel, reduction=4):
            super(SELayer, self).__init__()
            self.avg_pool = nn.AdaptiveAvgPool2d(1)
            self.fc = nn.Sequential(
                nn.Linear(channel, channel // reduction),
                nn.ReLU(inplace=True),
                nn.Linear(channel // reduction, channel),
                h_sigmoid()
            )
    
        def forward(self, x):
            b, c, _, _ = x.size()
            y = self.avg_pool(x)
            y = y.view(b, c)
            y = self.fc(y).view(b, c, 1, 1)
            return x * y
    
    
    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 = h_swish()
    
        def forward(self, x):
            return self.act(self.bn(self.conv(x)))
    
        def fuseforward(self, x):
            return self.act(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),
                    h_swish() if use_hs else nn.ReLU(inplace=True),
                    # Squeeze-and-Excite
                    SELayer(hidden_dim) if use_se else nn.Sequential(),
                    # Eca_layer(hidden_dim) if use_se else nn.Sequential(),#1.13.2022
                    # 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),
                    h_swish() if use_hs else nn.ReLU(inplace=True),
                    # 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
                    SELayer(hidden_dim) if use_se else nn.Sequential(),
                    # Eca_layer(hidden_dim) if use_se else nn.Sequential(),  # 1.13.2022
                    h_swish() if use_hs else nn.ReLU(inplace=True),
                    # 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

    第二步:将yolo.py中注册模块。

    if m in [Conv,MobileNetV3_InvertedResidual,ShuffleNetV2_InvertedResidual, ]:

    第三步:修改yaml文件

    backbone:
      # MobileNetV3-large
      # [from, number, module, args]
      [[-1, 1, conv_bn_hswish, [16, 2]],                   # 0-p1/2
       [-1, 1, MobileNetV3_InvertedResidual, [ 16,  16, 3, 1, 0, 0]],  # 1-p1/2
       [-1, 1, MobileNetV3_InvertedResidual, [ 24,  64, 3, 2, 0, 0]],  # 2-p2/4
       [-1, 1, MobileNetV3_InvertedResidual, [ 24,  72, 3, 1, 0, 0]],  # 3-p2/4
       [-1, 1, MobileNetV3_InvertedResidual, [ 40,  72, 5, 2, 1, 0]],  # 4-p3/8
       [-1, 1, MobileNetV3_InvertedResidual, [ 40, 120, 5, 1, 1, 0]],  # 5-p3/8
       [-1, 1, MobileNetV3_InvertedResidual, [ 40, 120, 5, 1, 1, 0]],  # 6-p3/8
       [-1, 1, MobileNetV3_InvertedResidual, [ 80, 240, 3, 2, 0, 1]],  # 7-p4/16
       [-1, 1, MobileNetV3_InvertedResidual, [ 80, 200, 3, 1, 0, 1]],  # 8-p4/16
       [-1, 1, MobileNetV3_InvertedResidual, [ 80, 184, 3, 1, 0, 1]],  # 9-p4/16
       [-1, 1, MobileNetV3_InvertedResidual, [ 80, 184, 3, 1, 0, 1]],  # 10-p4/16
       [-1, 1, MobileNetV3_InvertedResidual, [112, 480, 3, 1, 1, 1]],  # 11-p4/16
       [-1, 1, MobileNetV3_InvertedResidual, [112, 672, 3, 1, 1, 1]],  # 12-p4/16
       [-1, 1, MobileNetV3_InvertedResidual, [160, 672, 5, 1, 1, 1]],  # 13-p4/16
       [-1, 1, MobileNetV3_InvertedResidual, [160, 960, 5, 2, 1, 1]],  # 14-p5/32   原672改为原算法960
       [-1, 1, MobileNetV3_InvertedResidual, [160, 960, 5, 1, 1, 1]],  # 15-p5/32
      ]

    结 果:本人在多个数据集上做了大量实验,针对不同的数据集效果不同,map值有所下降,但是权值模型大小降低,参数量下降。

    预告一下:下一篇内容将继续分享网络轻量化方法的分享。有兴趣的朋友可以关注一下我,有问题可以留言或者私聊我哦

    PS:干网络的替换不仅仅是适用改进YOLOv5,也可以改进其他的YOLO网络以及目标检测网络,比如YOLOv4、v3等。

    最后,希望能互粉一下,做个朋友,一起学习交流。

    更多相关内容
  • # 复现TPH-YOLOv5 # 支持的backbone为Ghostnet、Shufflenetv2、Mobilenetv3Small、EagleEye、EfficientNetLite-0、PP-LCNet-1x、SwinTrans-YOLOv5
  • 也许会有像我这样的人,所以我将yolov5模型拆分为{主干,脖子,头部},以方便各种模块的操作并支持更多的主干。基本上,我只更改了模型,而没有更改架构,培训和测试yolov5。 因此,如果原始代码被更新,则更新该...
  • [深度学习]如何替换YoloV5主干网络:Flexible-Yolov5

    千次阅读 多人点赞 2022-03-05 20:18:16
    Flexible-Yolov5:可自定义主干网络YoloV5工程实践 本文目录: 概述 理论学习 准备自己的数据集 修改、调整自定义的主干网络 部署训练 一、概述 YoloV5主干网络是优秀的,但是许多时候默认的DarkNet并不能满足...

    Flexible-Yolov5:可自定义主干网络的YoloV5工程实践

    本文目录:

    1. 概述
    2. 理论学习与环境配置
    3. 准备自己的数据集
    4. 修改或调整自定义的主干网络
    5. 部署训练

    一、概述

    YoloV5的主干网络是优秀的,但是许多时候默认的DarkNet并不能满足我们的需求,包括科研、立项时需要更多的创新性。而Yolo框架出色的集成了许多目标检测相关的功能与输出,很容易让人联想到在Yolo框架下替换掉DarkNet来测试自己的网络性能水平。
    本文是一篇经验帖,主要描述如何使用Github的开源项目flexible-yolov5以下简称FY5)来达到我们替换YoloV5的主干网络的目的,虽然YoloV5官方也可以修改主干网络,但由于集成度较高,对替换操作有较大的阻力,因此选用该项目进行替换。授人以鱼不如授人以渔,在本文中我尽量以分析的视角来描述如何掌握整个FY5项目。

    说两句题外话: Yolo只不过是目标检测的入门框架,可轻松上手,请不要在未持有深度学习设备、拥有相关导师的情况下因为Yolo轻易选择入行深度学习的计算机视觉领域,在目前该领域内卷爆炸的时代浪费自己的青春。

    二、理论学习与环境配置

    在进行实际操作前,我们先阅读Yolo中主干网络结构,主干网络是将图片的输入进行特征提取的神经网络,一般情况下我们也只需要对主干网络进行修改,即下图中从张量大小为608* 608* 3的输入图片到最右侧变成3个蓝色的张量的过程,在主干网络将图片变换为3幅特征图后,主干网络的任务就完成了,最后生成的3幅特征图共同组成了“三层特征金字塔结构”。
    图1:YoloV5s的网络结构图
    因此,我们的主干网络只要能够将输入的图片转化为3个蓝色的向量,交给目标检测任务的其他部分(实际上也可以对这部分进行修改,以提高检测速度或精度,但本文不再陈述),就可以了。
    接下来我们从Github下载FY5的代码(GitHub链接),其目录结构如下图所示。
    图2
    各个目录结构的作用:

    • configs:存储数据集与主干网络的Yaml文件(配置文件)
    • od:存储模型的结构文件(基于Pytorch框架的py脚本)与数据集的一些处理操作
    • projects:项目部署相关的一些py脚本,笔者没有使用过
    • scripts:训练模型、模型检测的一些py脚本
    • utils:可视化等相关工具
      配置环境:直接使用Pip工具利用目录下的requiements.txt配置即可,值得一提的是,使用requirements.txt部署环境时请尽量使用Linux系统,Windows系统的某些Python依赖缺失,需要编译安装比较麻烦。

    三、准备自己的数据集

    数据集的准备工作网络上的教程已经很多了,这里只简单说明一下FY5要求的数据集格式。实际上FY5与Yolov5官方的数据集要求相同,都是Txt格式的Bbox标签、Yaml格式的数据集配置文件要求(该部分可查阅网络相关资料),可以直接将Yolov5项目上配置的数据集迁移过来,准备数据集的主要思路是:下载数据集->找到标签配置文件(一般是Json文件)->转换标签内容为Bbox的txt格式标签->创建并配置相关Yaml文件->在FY5项目的Script目录的train.py中如下图所示配置Yaml文件(下文会再次介绍)。
    在这里插入图片描述

    四、修改或调整自定义的主干网络

    接下来的网络配置是最为关键的一步(毕竟这么多的准备也只是为了这一步),先介绍思路:

    1. 设计、调整模型的yaml文件
    2. 准备py格式的网络文件(可以是自己设计的,也可以是从复现、从网络上找的)
    3. 将网络文件进行修改,使得网络头、尾与Yolov5的结构相匹配
    4. 设计、调整超参数的yaml文件

    根据前文学习的Yolov5的结构知识,现在我们以Resnet为例,阅读源码的结构与思路。

    1.模型的yaml文件

    Yaml文件是模型的配置文件,简单来说:框架在运行时根据Yaml文件(与Yolov5官方的yaml文件类似)来生成相应的模型Class,是一个类似于Json的解析文件,只是为了在调整网络结构的时候方便开发者而已,ResNet的yaml文件可以在“\configs”目录中找到,下面是默认的yaml文件以及相关注释:

    backbone: #主干网络的部分,我们也只需要对这部分进行调整
      type: resnet #网络类型为resnet,在构建模型的时候会解析出来,即"od/models/backbone/__init__.py"中解析
      #下面的都是模型的相关参数
      version: 18  # 18, 34, 50, 101, 152 #这里的version实际上是Resnet的深度,
      #我们自定义的网络如果需要大量调整的话可以修改相关代码让这个参数起作用,如果只是简单运行一下则不需要,下面的同上
      dcn: False #是否启用参数共享机制
      cbam: False #是否启用cbam注意力机制
    head: #head结构是网络头,起到分类器的作用
      nc: 1 #num_class的缩写,取决于你的目标检测任务所需要的分类的类别
      stride: [8.0, 16.0, 32.0] #网络头的步长,一般不用做修改
      anchors: #Yolov5是自适应的锚定框,这个参数一般也不用修改
        - [10,13, 16,30, 33,23]  # P3/8
        - [30,61, 62,45, 59,119]  # P4/16
        - [116,90, 156,198, 373,326]  # P5/32    
    

    yaml文件需要在后续的train.py中调用。

    2.模型的py文件

    还是以resnet为例,我们从"od/models/backbone/resnet.py"中构造resnet的函数看起:

    
    def resnet(pretrained=False, **kwargs):
        version = str(kwargs.pop('version')) #解析模型的版本
        if version == '18': #判断网络版本
            return resnet18(pretrained, **kwargs) #pretrained是是否启用预训练权重进行迁移学习的布尔代数
        if version == '34':
            return resnet34(pretrained, **kwargs)
        if version == '50':
            return resnet50(pretrained, **kwargs)
        if version == '101':
            return resnet101(pretrained, **kwargs)
        if version == '152':
            return resnet152(pretrained, **kwargs)
    

    不难看出,构造不同的resnet实际上也只有两个关键的区别:

    • 不同的构造函数
    • 不同的kwargs

    以resnet18为例,我们继续进入分析:

    def resnet18(pretrained=False, **kwargs):
        """Constructs a ResNet-18 model.
        Args:
            pretrained (bool): If True, returns a model pre-trained on ImageNet
        """
        model = Resnet(BasicBlock, [2, 2, 2, 2], **kwargs) #构造resnet
        if pretrained: #调用预训练权重
            model.load_state_dict(model_zoo.load_url(model_urls['resnet18'], model_dir='.'), strict=False)
        return model
    

    终于要对模型的结构动刀子了,如果有相关经验的朋友肯定已经发现了flexible-yolov5使用的resnet几乎就是官方的resnet,甚至目前为止都没有出现任何区别,接下来的地方就是前文理论学习中讲到的“三层特征金字塔结构”所需要修改的地方了。
    接下来我们定位到resnet的构造函数部分,对构造函数进行分析。

    
    class Resnet(nn.Module):#注意:无关代码略有删减!
    
        def __init__(self, block, layers, cbam=False, dcn=False):
            super(Resnet, self).__init__()
            self.inplanes = 64 #输入的通道数
            self.dcn = dcn #是否启用dcn,该项由yaml文件中的同名项解析而来
            self.cbam = cbam#是否启用cbam,该项由yaml文件中的同名项解析而来
            self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, bias=False) #resnet的proj结构
            self.bn1 = nn.BatchNorm2d(64) #防止过拟合的BN
            self.relu = nn.ReLU(inplace=True) #relu激活函数
            self.out_channels = [] #输出通道数(此项是我们要替换的网络也需要具备的),后面的三层特征金字塔结构会用到
            self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)#最大池化层
            self.layer1 = self._make_layer(block, 64, layers[0])#通过make.layer函数构造一层网络(这里的层其实我更愿意看做一个stage)
            self.layer2 = self._make_layer(block, 128, layers[1], stride=2, cbam=self.cbam, dcn=dcn)
            self.layer3 = self._make_layer(block, 256, layers[2], stride=2, cbam=self.cbam, dcn=dcn)
            self.layer4 = self._make_layer(block, 512, layers[3], stride=2, cbam=self.cbam, dcn=dcn) #第四层网络选择是否启用cbam
           
                            
            self.out_shape = {'C3_size': self.out_channels[0] * 2,
                              'C4_size': self.out_channels[1] * 2,
                              'C5_size': self.out_channels[2] * 2} #需要通过make_layer函数中设定的通道数来计算
    
            print("backbone output channel: C3 {}, C4 {}, C5 {}".format(self.out_channels[0] * 2, self.out_channels[1] * 2,
                                                                        self.out_channels[2] * 2))
    
    
        def _make_layer(self, block, planes, blocks, stride=1, cbam=False, dcn=None): #make layer函数是构建网络层的函数
            downsample = None #下采样,不用管
            if stride != 1 or self.inplanes != planes * block.expansion:
                downsample = nn.Sequential(
                    nn.Conv2d(self.inplanes, planes * block.expansion,
                              kernel_size=1, stride=stride, bias=False),
                    nn.BatchNorm2d(planes * block.expansion),
                ) #是构建下采样层,我们要替换的网络里不一定需要
    
            layers = [block(self.inplanes, planes, stride, downsample, cbam=cbam, dcn=dcn)] #构建网络层,这个想必都不用我说了
            self.inplanes = planes * block.expansion 
            self.out_channels.append(self.inplanes) #将输入通道数添加到前面的out_channels列表里,这一步很重要!我们替换的网络也要有这样一个列表,也要将通道数添加到该列表里,后面的forward方法会用到!
            for i in range(1, blocks):
                layers.append(block(self.inplanes, planes, cbam=cbam, dcn=dcn)) #将每层网络以此添加到layers数组
    
            return nn.Sequential(*layers)
            
        def forward(self, inputs):#forward方法是最关键的一步了,如果您这一步明白了,那么结合特征金字塔的理论图,就全部都明白了
            x = self.conv1(inputs)
            x = self.bn1(x)
            x = self.relu(x)
            x = self.maxpool(x)
    
            x1 = self.layer1(x) #获得从第一个网络层的输出
            x2 = self.layer2(x1)  # 80,80 #保存第二个网络层的输出
            x3 = self.layer3(x2)  # 40,40 #保存第三个网络层的输出
            x4 = self.layer4(x3)  # 20,20 ##保存第四个网络层的输出
            return x2, x3, x4 #注意:此处是将三个网络层的输出一起返回!!!
    
    

    看到了forward方法的return,您一定就明白了resnet中实现特征金字塔的方式,那就是将不同的网络层的输出分别保存下来,再分别返回,依照这样的方式,我们自己要替换的网络也可以轻而易举地完成到特征金字塔模型的转换。
    那么您一定会好奇,返回了3个平行的张量去了哪里呢?随后我们继续阅读"od/models/model.py"的Model类,定位到forward方法,立刻就真相大白了。

    
        def forward(self, x):
            out = self.backbone(x) #这里的backbone就是我们前面陈述的resnet,相应的out就是前面的3个平行输出,关于该类的定义以及部件请详见Model类的构造函数
            out = self.fpn(out) #可与理论学习的Yolov5图结合理解
            out = self.pan(out) #可与理论学习的Yolov5图结合理解
            y = self.detection(list(out))
            return y
    

    Model类是FY5项目中的模型类,用于完成整个目标检测任务,即提取特征+分类+检测,我们都知道Yolov5是使用滑动窗口进行目标检测的,我们的主干网络将特征提取出来,直接丢给fpn进行后续处理就可以了,完全不许要再进行任何操作。我们的主干网络实际上在代码中只对应backbone部分,也只完成特征提取的操作。只要我们已经有了模型的py文件,将其略作修改,将模型输出按照特征金字塔的结构返回给Fpn,我们就不需要在进行其他操作即可借助Yolov5的框架完成目标检测任务了。

    在添加模型的py文件后,我们还需要在"od/models/backbone/init.py"中添加网络引用,如下面的代码与注释所解释的一样。

    # -*- coding: utf-8 -*-
    from .resnet import resnet #与resnet一样,我们需要在od/models/backbone/目录下添加我们的py模型文件
    from .testnet import testnet #是左侧的格式
    __all__ = ['build_backbone'] #这个不用修改
    
    support_backbone = ['resnet', 'shufflenetv2', 'mobilenetv3', 'YOLOv5', 'efficientnet', 'hrnet', 'swin', 'vgg',
                        'repvgg' ,'testnet'] #在这个字典里添加我们的网络名称
    
    
    def build_backbone(backbone_name, **kwargs):#下面的函数不用修改,该函数会自动根据yaml文件生成kwargs(传递构造网络参数的字典)
        assert backbone_name in support_backbone, f'all support backbone is {support_backbone}'
        backbone = eval(backbone_name)(**kwargs)
        return backbone
    

    综上所述,我们重新一下修改BackBone的几个要点:

    • 设定模型的Yaml文件
    • 添加模型的py脚本文件(要点在于forward方法需要调整,以满足三层特征金字塔结构),这一步需要对网络计算的张量大小有较好的理解
    • 将模型信息添加到__init.py__文件中
    • 使用train.py时调用模型的Yaml文件即可进行训练

    此外,训练的超参数与官方的Yolov5使用方法基本相同,直接在"configs/hyp.scratch.yaml"中修改,在train.py中调用即可

    # Hyperparameters for COCO training from scratch
    # python train.py --batch 40 --cfg yolov5m.yaml --weights '' --data coco.yaml --img 640 --epochs 300
    # See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials
    
    
    lr0: 0.001  # initial learning rate (SGD=1E-2, Adam=1E-3)
    lrf: 0.2  # final OneCycleLR learning rate (lr0 * lrf)
    momentum: 0.957  # SGD momentum/Adam beta1
    weight_decay: 0.0005  # optimizer weight decay 5e-4
    warmup_epochs: 3.0  # warmup epochs (fractions ok)
    warmup_momentum: 0.8  # warmup initial momentum
    warmup_bias_lr: 0.1  # warmup initial bias lr
    box: 0.05  # box loss gain
    cls: 0.5  # cls loss gain
    cls_pw: 1.0  # cls BCELoss positive_weight
    obj: 1.0  # obj loss gain (scale with pixels)
    obj_pw: 1.0  # obj BCELoss positive_weight
    iou_t: 0.20  # IoU training threshold
    anchor_t: 4.0  # anchor-multiple threshold
    # anchors: 3  # anchors per output layer (0 to ignore)
    fl_gamma: 0.0  # focal loss gamma (efficientDet default gamma=1.5)
    hsv_h: 0.015  # image HSV-Hue augmentation (fraction)
    hsv_s: 0.7  # image HSV-Saturation augmentation (fraction)
    hsv_v: 0.4  # image HSV-Value augmentation (fraction)
    degrees: 0.0  # image rotation (+/- deg)
    translate: 0.1  # image translation (+/- fraction)
    scale: 0.5  # image scale (+/- gain)
    shear: 0.0  # image shear (+/- deg)
    perspective: 0.0  # image perspective (+/- fraction), range 0-0.001
    flipud: 0.0  # image flip up-down (probability)
    fliplr: 0.5  # image flip left-right (probability)
    mosaic: 1.0  # image mosaic (probability)
    mixup: 0.0  # image mixup (probability)
    

    五、部署训练

    模型的训练使用"scripts/train.py"脚本即可。FY5的训练模型方法同Yolov5官方一样,都支持命令行,但是我个人习惯使用运行代码的方式。
    我们定位到train.py的main部分,如下所示:

    
    if __name__ == '__main__':
        parser = argparse.ArgumentParser()
        parser.add_argument('--weights', type=str, default='', help='initial weights path') #是否有权重继续训练,这个应当是Yolov5训练出来的权重
        parser.add_argument('--cfg', type=str,
                            default='',
                            help='model.yaml path') #模型的yaml文件
        parser.add_argument('--data', type=str, default='',
                            help='data.yaml path')#数据集的Yaml文件
        parser.add_argument('--hyp', type=str, default='',
                            help='hyperparameters path')#超参数的Yaml文件
        parser.add_argument('--epochs', type=int, default=250)#训练Epoch的Yaml文件
        parser.add_argument('--batch-size', type=int, default=16, help='total batch size for all GPUs') #batch_size
        parser.add_argument('--img-size', nargs='+', type=int, default=[800, 800], help='[train, test] image sizes') #对数据集进行预处理后的图像大小
        parser.add_argument('--rect', action='store_true', help='rectangular training')
        parser.add_argument('--resume', nargs='?', const=True, default=False, help='resume most recent training')
        parser.add_argument('--nosave', action='store_true', help='only save final checkpoint')
        parser.add_argument('--notest', action='store_true', help='only test final epoch')
        parser.add_argument('--noautoanchor', action='store_true', help='disable autoanchor check')
        parser.add_argument('--evolve', action='store_true', help='evolve hyperparameters')
        parser.add_argument('--bucket', type=str, default='', help='gsutil bucket')
        parser.add_argument('--cache-images', action='store_true', help='cache images for faster training')
        parser.add_argument('--image-weights', action='store_true', help='use weighted image selection for training')
        parser.add_argument('--device', default='2', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') #设定训练的GPU设备
        parser.add_argument('--multi-scale', action='store_true', help='vary img-size +/- 50%%')
        parser.add_argument('--single-cls', action='store_true', help='train multi-class data as single-class')
        parser.add_argument('--adam', default=True, action='store_true', help='use torch.optim.Adam() optimizer')
        parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode')
        parser.add_argument('--local_rank', type=int, default=-1, help='DDP parameter, do not modify')
        parser.add_argument('--log-imgs', type=int, default=16, help='number of images for W&B logging, max 100')
        parser.add_argument('--log-artifacts', action='store_true', help='log artifacts, i.e. final trained model')
        parser.add_argument('--workers', type=int, default=4, help='maximum number of dataloader workers')
        parser.add_argument('--project', default='runs/train', help='save to project/name')
        parser.add_argument('--name', default='exp', help='save to project/name')
        parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment')
        parser.add_argument('--quad', action='store_true', help='quad dataloader')
        parser.add_argument('--linear-lr', action='store_true', help='linear LR')
        opt = parser.parse_args()
    #注:以下代码略,不需要修改
    

    设定好了以上参数后,我们就可以开始训练了!控制台的输出、模型的保存方式等都与YoloV5官方一致。训练完成后,在"scripts/runs/train"中,如下图所示我们能够得到一批pt格式的模型权重与部分训练可视化结果:
    在这里插入图片描述
    打开weights文件夹,就是我们训练得到的权重文件(last是最后一轮,best是表现最好的一轮):
    在这里插入图片描述
    到此,我们的训练就大功告成了!
    训练完成后,我们可以使用"scripts/detector.py"来调用模型进行检测,我们定位到该py文件的main处:

    
    if __name__ == '__main__':
        pt_path = 'last.pt'#pt文件的路径
        #mes_file = 'names.txt' #检测类别的txt文件,单独存放,用于模型检测完成后加上在矩形框加上文字说明,官方代码不包含此模块
        model = Detector(pt_path, mes_file, 800, xcycwh=False) #通过Pt文件搭建的模型,其中变量以官方代码为准
        imgs_root = 'scripts/detect_1'#待检测的图片文件夹
        save_dir = '/scripts/detect_out' #保存检测成功的图片文件夹
        #注:以下代码略,无需修改
    

    imgs_root目录直接放图片即可:
    在这里插入图片描述
    以上的准备工作完成后,我们直接运行detector.py进行检测,检测结果输出在代码中的save_dir中:
    在这里插入图片描述
    在这里插入图片描述

    至此,FY5的使用介绍完成!

    感谢Flexible-yolov5的开发者yl305237731

    展开全文
  • YOLOV4:You Only Look Once目标检测模型-修改mobilenet系列主干网络-在pytorch当中的实现 2021年2月8日更新: 加入letterbox_image的选项,关闭letterbox_image后网络的map一般可以得到提升。 目录 性能情况 训练...
  • ​前 言:作为当前先进的深度学习目标...解决问题:YOLOv5主干特征提取网络采用C3结构,带来较大的参数量,检测速度较慢,应用受限,在某些真实的应用场景如移动或者嵌入式设备,如此大而复杂的模型时难以被应用的。...

     ​前 言:作为当前先进的深度学习目标检测算法YOLOv5,已经集合了大量的trick,但是还是有提高和改进的空间,针对具体应用场景下的检测难点,可以不同的改进方法。此后的系列文章,将重点对YOLOv5的如何改进进行详细的介绍,目的是为了给那些搞科研的同学需要创新点或者搞工程项目的朋友需要达到更好的效果提供自己的微薄帮助和参考。

    解决问题:YOLOv5主干特征提取网络采用C3结构,带来较大的参数量,检测速度较慢,应用受限,在某些真实的应用场景如移动或者嵌入式设备,如此大而复杂的模型时难以被应用的。首先是模型过于庞大,面临着内存不足的问题,其次这些场景要求低延迟,或者说响应速度要快,想象一下自动驾驶汽车的行人检测系统如果速度很慢会发生什么可怕的事情。所以,研究小而高效的CNN模型在这些场景至关重要,至少目前是这样,尽管未来硬件也会越来越快。本文尝试将主干特征提取网络替换为更轻量的EfficientNetV2网络,以实现网络模型的轻量化,平衡速度和精度。

    以下为历史发布博客篇。

    YOLOv5改进之十一:主干网络C3替换为轻量化网络MobileNetV3_人工智能算法工程师0301的博客-CSDN博客
    YOLOv5改进之十二:主干网络C3替换为轻量化网络ShuffleNetV2_人工智能算法工程师0301的博客-CSDN博客

    原理:

    论文地址:https://arxiv.org/abs/2104.0029

       谷歌的MingxingTan与Quov V.Le对EfficientNet的一次升级,旨在保持参数量高效利用的同时尽可能提升训练速度。在EfficientNet的基础上,引入了Fused-MBConv到搜索空间中;同时为渐进式学习引入了自适应正则强度调整机制。两种改进的组合得到了本文的EfficientNetV2,它在多个基准数据集上取得了SOTA性能,且训练速度更快。比如EfficientNetV2取得了87.3%的top1精度且训练速度快5-11倍。

     

    方 法:

    第一步修改common.py,增加MobileNetV3模块。

    class stem(nn.Module):
        def __init__(self, c1, c2, kernel_size=3, stride=1, groups=1):
            super().__init__()
    
            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(inplace=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_()  # binarize
    
        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().__init__()
            self.gate_fn = nn.Sigmoid()
            reduced_chs = int(c1 * se_ratio)
            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__()
    
            assert s in [1, 2]
    
            self.has_shortcut = (s == 1 and c1 == c2)
            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 = drop_connect_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().__init__()
    
            assert s in [1, 2]
    
            self.has_shortcut = (s == 1 and c1 == c2)
            # print(c1, c2, k, s, expansion)
    
            expanded_c = c1 * expansion
    
    
            self.dw_conv = stem(expanded_c, expanded_c, kernel_size=k, stride=s, groups=expanded_c)
    
            self.se = SqueezeExcite_efficientv2(c1, 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):
    
            # print(x.shape)
            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
    class SPPF(nn.Module):
        # Spatial Pyramid Pooling - Fast (SPPF) layer for YOLOv5 by Glenn Jocher
        def __init__(self, c1, c2, k=5, e=0.5, ratio=1.0):  # equivalent to SPP(k=(5, 9, 13))
            super().__init__()
            # c_ = c1 // 2  # hidden channels
            c_ = int(c1 * e)
            c2 = int(c2 * ratio)
            c2 = make_divisible(c2, 8)
            self.cv1 = Conv(c1, c_, 1, 1)
            self.cv2 = Conv(c_ * 4, c2, 1, 1)
            self.m = nn.MaxPool2d(kernel_size=k, stride=1, padding=k // 2)
    
        def forward(self, x):
            x = self.cv1(x)
            with warnings.catch_warnings():
                warnings.simplefilter('ignore')  # suppress torch 1.9.0 max_pool2d() warning
                y1 = self.m(x)
                y2 = self.m(y1)
                return self.cv2(torch.cat([x, y1, y2, self.m(y2)], 1))

    第二步:将yolo.py中注册模块。

    if m in [Conv,MobileNetV3_InvertedResidual,ShuffleNetV2_InvertedResidual, ]:

    第三步:修改yaml文件

    backbone:
      [[-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]], # 2
       [-1, 3, FusedMBConv, [48, 3, 1, 4, 0]], # 3
       [-1, 1, FusedMBConv, [64, 3, 2, 4, 0]], # 4
       [-1, 3, FusedMBConv, [64, 3, 1, 4, 0]], # 5
       [-1, 1, MBConv, [128, 3, 2, 4, 0.25]], # 6
       [-1, 5, MBConv, [128, 3, 1, 4, 0.25]], # 7
       [-1, 1, MBConv, [160, 3, 2, 6, 0.25]], # 8
       [-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
    #   [-1, 1, SPP, [1024, [5, 9, 13]]],
      ]
    # YOLOv5 v6.0 head

    结 果:本人在多个数据集上做了大量实验,针对不同的数据集效果不同,map值有所下降,但是权值模型大小降低,参数量下降。

    预告一下:下一篇内容将继续分享网络轻量化方法ghost的分享。有兴趣的朋友可以关注一下我,有问题可以留言或者私聊我哦

    PS:主干网络的替换不仅仅是适用改进YOLOv5,也可以改进其他的YOLO网络以及目标检测网络,比如YOLOv4、v3等。

    最后,希望能互粉一下,做个朋友,一起学习交流。

    展开全文
  • ​前 言:作为当前先进的深度学习...解决问题:YOLOv5主干特征提取网络采用C3结构,带来较大的参数量,检测速度较慢,应用受限,在某些真实的应用场景如移动或者嵌入式设备,如此大而复杂的模型时难以被应用的。.......

     ​前 言:作为当前先进的深度学习目标检测算法YOLOv5,已经集合了大量的trick,但是还是有提高和改进的空间,针对具体应用场景下的检测难点,可以不同的改进方法。此后的系列文章,将重点对YOLOv5的如何改进进行详细的介绍,目的是为了给那些搞科研的同学需要创新点或者搞工程项目的朋友需要达到更好的效果提供自己的微薄帮助和参考。

    需要更多程序资料以及答疑欢迎大家关注——微信公众号:人工智能AI算法工程师 

    解决问题:YOLOv5主干特征提取网络采用C3结构,带来较大的参数量,检测速度较慢,应用受限,在某些真实的应用场景如移动或者嵌入式设备,如此大而复杂的模型时难以被应用的。首先是模型过于庞大,面临着内存不足的问题,其次这些场景要求低延迟,或者说响应速度要快,想象一下自动驾驶汽车的行人检测系统如果速度很慢会发生什么可怕的事情。所以,研究小而高效的CNN模型在这些场景至关重要,至少目前是这样,尽管未来硬件也会越来越快。本文尝试将主干特征提取网络替换为更轻量的ShuffleNetV2网络,以实现网络模型的轻量化,平衡速度和精度。

    YOLOv5改进之十一:主干网络C3替换为轻量化网络MobileNetV3_人工智能算法工程师0301的博客-CSDN博客https://blog.csdn.net/m0_70388905/article/details/125593267?spm=1001.2014.3001.5502

    原理:

    文章链接 https://arxiv.org/abs/1807.11164

    近来,深度CNN网络如ResNet和DenseNet,已经极大地提高了图像分类的准确度。但是除了准确度外,计算复杂度也是CNN网络要考虑的重要指标,过复杂的网络可能速度很慢,一些特定场景如无人车领域需要低延迟。另外移动端设备也需要既准确又快的小模型。为了满足这些需求,一些轻量级的CNN网络如MobileNet和ShuffleNet被提出,它们在速度和准确度之间做了很好地平衡。今天我们要讲的是ShuffleNetv2,它是旷视最近提出的ShuffleNet升级版本,并被ECCV2018收录。在同等复杂度下,ShuffleNetv2比ShuffleNet和MobileNetv2更准确。下图为整体结构图。

    方 法:

    第一步修改common.py,增加ShuffleNetV2模块。

    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()
    
    
    
        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
    
            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,
                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

    第二步:将yolo.py中注册模块ShuffleNetV2。

    if m in [Conv,MobileNetV3_InvertedResidual,ShuffleNetV2_InvertedResidual ]:

    第三步:修改yaml文件

    backbone:
      # [from, number, module, args]
      [[-1, 1, Focus, [64, 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
      ]
    

    结 果:本人在多个数据集上做了大量实验,针对不同的数据集效果不同,map值有所下降,但是权值模型大小降低,参数量下降。

    预告一下:下一篇内容将继续分享网络轻量化方法EfficientNetv2的分享。有兴趣的朋友可以关注一下我,有问题可以留言或者私聊我哦

    PS:主干网络的替换不仅仅是适用改进YOLOv5,也可以改进其他的YOLO网络以及目标检测网络,比如YOLOv4、v3等。

    需要更多程序资料以及答疑欢迎大家关注——微信公众号:人工智能AI算法工程师 

    最后,希望能互粉一下,做个朋友,一起学习交流。

    展开全文
  • YOLOv5网络详解

    千次阅读 2022-04-21 20:06:05
    前言 YOLOv5项目的作者是Glenn Jocher并不是原Darknet项目的作者Joseph Redmon,并且这个项目至今都没有发表过正式的论文。 官方源码仓库:https://github.com/ultralytics/yolov5
  • yolov5网络结构学习

    万次阅读 多人点赞 2021-04-19 14:21:13
    1. yolov5 网络架构 上图是yolov5s的网络结构,它是yolov5系列中深度最小、特征图宽度最小的网络。后面的m、l、x都是在此基础上不断加深、加宽的。 网络主要分为输入端、Backbone、Neck、Prediction四个部分。 它和...
  • YOLOv5主干特征提取网络采用C3结构,带来较大的参数量,检测速度较慢,应用受限,在某些真实的应用场景如移动或者嵌入式设备,如此大而复杂的模型时难以被应用的。作为当前先进的深度学习目标检测算法YOLOv5,已经...
  • 支持的backbone为Ghostnet、Shufflenetv2、Mobilenetv3Small、EagleEye、EfficientNetLite-0、PP-LCNet-1x、SwinTrans-YOLOv5 Requirements pip install -r requirements.txt Multi-Backbone Substitution...
  • YOLOV3:只看一次目标检测模型在Pytorch当中的实现-替换高效网络主干网络2021年2月8日更新:加入letterbox_image的选项,关闭letterbox_image后网络的地图得到大幅度提升。目录性能情况训练数据集权值文件名称测试...
  • YOLOV5YOLOV5网络配置文件解读

    千次阅读 2022-01-29 10:20:44
    注意注意此时的YOLOV5版本为6.0 配置文件路径:yolov5/models/yolov5l.yaml # YOLOv5 ???? by Ultralytics, GPL-3.0 license # Parameters nc: 80 # number of classes depth_multiple: 1.0 # model depth multiple ...
  • YOLOv5网络结构+代码+应用详解|CSDN创作打卡

    万次阅读 多人点赞 2022-01-22 21:08:49
    不好意思)的提醒 v5.0版本 目前更新到v6.0版本 (这里比较大的改动是:用CBS代替 Focus 层,主要是为了方便模型导出 ) YOLOv5网络结构分为3个部分,Backbone(主干部分),Neck和Head。 Backbone作用:特征提取 ...
  • YOLOV4:You Only Look Once目标检测模型-修改mobilenet系列主干网络-在Keras当中的实现 2021年2月8日更新: 加入letterbox_image的选项,关闭letterbox_image后网络的map一般可以得到提升。 目录 性能情况 训练数据...
  • 既然这样,今天本人就本着幽默、清晰、轻松的风格带大家深入了解一下YOLOv5那倾倒众生的网络结构,和它较之其他算法的改进之处。还是一句话,希望我的不经意之谈能够帮助到各位,如果感兴趣可以收藏一下,有任何问题...
  • YOLOv5系列(3)——YOLOv5修改网络结构

    万次阅读 多人点赞 2021-03-07 18:33:44
    文章目录一、设置网络结构为mobilenet-V2二、添加注意力模块 一、设置网络结构为mobilenet-V2 首先,需要在models/common.py里,实现MobileNetv2的 bottleneck 和 Pwconv。 1、Mobilenetv2的bottleneck: ...
  • “#yolov5_transformer”
  • 深度解析YoloV3的主干网络和Loss

    万次阅读 2021-05-26 11:54:08
    YoloV3作为物体检测模型中比较常用的模型之一,是广大算法工程师入门物体检测必学的算法之一,所以弄清楚Yolov3的主干网络和Loss很有必要。本文根据网络收集和自己的理解写的,如果有不对的地方,欢迎大家指正。代码...
  • ​前 言:作为当前先进的深度学习...解决问题:YOLOv5主干特征提取网络采用C3结构,带来较大的参数量,检测速度较慢,应用受限,在某些真实的应用场景如移动或者嵌入式设备,如此大而复杂的模型时难以被应用的。......
  • 待实现
  • YOLOv5网络代码解析

    千次阅读 2022-02-05 17:26:51
    pytorch-YOLOv5网络代码解析,针对code进行了较为详细的解释,欢迎提问
  • 1, 1, C3, [512, False]], # 20 (P5/32-large) [[14, 17, 20], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) ] 更详细的网络结构复现请看ShuffleNet v2网络结构复现(Pytorch版) 本人更多Yolov5(v6.1)实战内容...
  • YOLOV4:You Only Look Once目标检测模型-修改mobilenet系列主干网络-在Keras当中的实现 2021年2月8日更新: 加入letterbox_image的选项,关闭letterbox_image后网络的map一般可以得到提升。 目录 性能情况 训练数据...
  • YoloV5目标检测系统【详解】

    千次阅读 2022-05-14 11:31:42
    我之前学过yoloV1到yoloV3,但对于图像检测这些明显还不够,所以把yoloV5提上日程,以下是我学习yoloV5的笔记,主要参考此链接。 文章目录
  • YOLOV5更换轻量级的backbone:mobilenetV2

    千次阅读 2022-07-06 16:36:23
    如何更换YOLOV5的backbone
  • ​前 言:作为当前先进的深度学习目标...解决问题:YOLOv5主干特征提取网络采用C3结构,带来较大的参数量,检测速度较慢,应用受限,在某些真实的应用场景如移动或者嵌入式设备,如此大而复杂的模型时难以被应用的。...
  • 在我的本科毕业论文中,我使用了Yolov5,并尝试...可以对Yolov5进行一定程度的定制化修改,例如更轻量级的Yolov5-MobileNetv3 或者比Yolov5s更好的(存疑,没有跑过大数据集,可自己实验)Yolov5-EfficientNet。......
  • 目录 一、软件安装 1、VS2019 2、Anaconda 3、Pycharm 4、CUDAv10.2 二、依赖库安装 三、swin transformer中需要本地编译的依赖库 1、mmcv 2、mmdet 3、apex 四、swin transformer训练参数修改 五、YOLOv5训练参数...
  • 新增支持更换yolov5的backbone主干网络为Efficientnetv2, shufflenetv2, 具体网络模型实现可在model-->common.py中查看。 后续,将会添加更多更轻量,更优秀的主干网络,比如swintranst等,其他剪枝方法,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,021
精华内容 808
关键字:

yolov5主干网络