精华内容
下载资源
问答
  • yolov5网络结构详解
    千次阅读
    2022-03-17 03:46:16

    yolov5 的网络结构

    yolov5 的网络结构的配置文件在models文件夹下,有yolov5n.yaml, yolov5s.yaml, yolov5m.yaml等等。几个网络结构其实都一样,通过depth_multiple和width_multiple参数来控制网络结构的深度和宽度。

    主要理解 head和backbone部分,根据需求对模型做修改时主要也是改动backbone部分。

    
    # YOLOv5 v6.0 backbone
    backbone:
      # [from, number, module, args]
      [[-1, 1, Conv, [64, 6, 2, 2]],  # 0-P1/2
       [-1, 1, Conv, [128, 3, 2]],  # 1-P2/4
       [-1, 3, C3, [128]],
       [-1, 1, Conv, [256, 3, 2]],  # 3-P3/8
       [-1, 6, C3, [256]],
       [-1, 1, Conv, [512, 3, 2]],  # 5-P4/16
       [-1, 9, C3, [512]],
       [-1, 1, Conv, [1024, 3, 2]],  # 7-P5/32
       [-1, 3, C3, [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)
      ]
    
    

    最新版本的yolov5 v6.0的backbone已经不用Focus了,直接使用卷积核为6,stride为2的卷积层。

    from:输入来自那一层,-1代表前面一层,1代表第1层,3代表第3层,[-1, 6]则表示来自上一层和第6层的输入维度相加(concat)

    number:模块的数量,最终数量需要乘width,然后四舍五入取整,如果小于1,取1。

    module:子模块名称

    args:模块参数,有 out_channel,kernel_size,stride,padding,bias等

    自定义网络结构

    自定义网络结构需要三步:

    1. 在model文件夹下创建新的模块,比如mobilenetv3.py,编写你要加的结构,再在yolo.py中导入
    2. 更改yaml配置文件,将backbone或者head中需要改的层换成自己的
    3. 更改yolo.py 中的parse_model解析函数

    第一步,编写mobilenetv3.py

    # MobileNetV3
    
    import torch.nn as nn
    
    
    class h_sigmoid(nn.Module):
        def __init__(self, inplace=True):
            super(h_sigmoid, self).__init__()
            self.relu = nn.ReLU6(inplace=inplace)
    
        def forward(self, x):
            return self.relu(x + 3) / 6
    
    
    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(),
                    # 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(),
                    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中加上:

    from models.mobilenetv3 import *
    

    第二步,新建mobilenetv3small.yaml,将yolov5中的backbone的卷积模块全部替换成MobileNetV3_InvertedResidual

    # parameters
    nc: 80  # number of classes
    depth_multiple: 1.0
    width_multiple: 1.0
    # anchors
    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
    
    # custom backbone
    backbone:
      # MobileNetV3-small
      # [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-p3/8
       [-1, 1, MobileNetV3_InvertedResidual, [40,  96, 5, 2, 1, 1]],  # 4-p4/16
       [-1, 1, MobileNetV3_InvertedResidual, [40, 240, 5, 1, 1, 1]],  # 5-p4/16
       [-1, 1, MobileNetV3_InvertedResidual, [40, 240, 5, 1, 1, 1]],  # 6-p4/16
       [-1, 1, MobileNetV3_InvertedResidual, [48, 120, 5, 1, 1, 1]],  # 7-p4/16
       [-1, 1, MobileNetV3_InvertedResidual, [48, 144, 5, 1, 1, 1]],  # 8-p4/16
       [-1, 1, MobileNetV3_InvertedResidual, [96, 288, 5, 2, 1, 1]],  # 9-p5/32
       [-1, 1, MobileNetV3_InvertedResidual, [96, 576, 5, 1, 1, 1]],  # 10-p5/32
       [-1, 1, MobileNetV3_InvertedResidual, [96, 576, 5, 1, 1, 1]],  # 11-p5/32
      ]
    
    head:
      [[-1, 1, Conv, [256, 1, 1]],
       [-1, 1, nn.Upsample, [None, 2, 'nearest']],
       [[-1, 8], 1, Concat, [1]],  # cat backbone P4
       [-1, 1, C3, [256, False]],  # 15
    
       [-1, 1, Conv, [128, 1, 1]],
       [-1, 1, nn.Upsample, [None, 2, 'nearest']],
       [[-1, 3], 1, Concat, [1]],  # cat backbone P3
       [-1, 1, C3, [128, False]],  # 19 (P3/8-small)
    
       [-1, 1, Conv, [128, 3, 2]],
       [[-1, 16], 1, Concat, [1]],  # cat head P4
       [-1, 1, C3, [256, False]],  # 22 (P4/16-medium)
    
       [-1, 1, Conv, [256, 3, 2]],
       [[-1, 12], 1, Concat, [1]],  # cat head P5
       [-1, 1, C3, [512, False]],  # 25 (P5/32-large)
    
       [[19, 22, 25], 1, Detect, [nc, anchors]],  # Detect(P3, P4, P5)
      ]
    

    第三步,更改解析模块,models/yolo.py中的parse_model函数

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

    开始训练

    python train.py --data coco.yaml --img 640 --batch 64  --cfg mobilenetv3small.yaml --weights ''
    

    模型参数

                     from  n    params  module                                  arguments
      0                -1  1       464  models.mobilenetv3.conv_bn_hswish       [3, 16, 2]
      1                -1  1       612  models.mobilenetv3.MobileNetV3_InvertedResidual[16, 16, 16, 3, 2, 1, 0]
      2                -1  1      3864  models.mobilenetv3.MobileNetV3_InvertedResidual[16, 24, 72, 3, 2, 0, 0]
      3                -1  1      5416  models.mobilenetv3.MobileNetV3_InvertedResidual[24, 24, 88, 3, 1, 0, 0]
      4                -1  1     13736  models.mobilenetv3.MobileNetV3_InvertedResidual[24, 40, 96, 5, 2, 1, 1]
      5                -1  1     55340  models.mobilenetv3.MobileNetV3_InvertedResidual[40, 40, 240, 5, 1, 1, 1]
      6                -1  1     55340  models.mobilenetv3.MobileNetV3_InvertedResidual[40, 40, 240, 5, 1, 1, 1]
      7                -1  1     21486  models.mobilenetv3.MobileNetV3_InvertedResidual[40, 48, 120, 5, 1, 1, 1]
      8                -1  1     28644  models.mobilenetv3.MobileNetV3_InvertedResidual[48, 48, 144, 5, 1, 1, 1]
      9                -1  1     91848  models.mobilenetv3.MobileNetV3_InvertedResidual[48, 96, 288, 5, 2, 1, 1]
     10                -1  1    294096  models.mobilenetv3.MobileNetV3_InvertedResidual[96, 96, 576, 5, 1, 1, 1]
     11                -1  1    294096  models.mobilenetv3.MobileNetV3_InvertedResidual[96, 96, 576, 5, 1, 1, 1]
     12                -1  1     25088  models.common.Conv                      [96, 256, 1, 1]
     13                -1  1         0  torch.nn.modules.upsampling.Upsample    [None, 2, 'nearest']
     14           [-1, 8]  1         0  models.common.Concat                    [1]
     15                -1  1    308736  models.common.C3                        [304, 256, 1, False]
     16                -1  1     33024  models.common.Conv                      [256, 128, 1, 1]
     17                -1  1         0  torch.nn.modules.upsampling.Upsample    [None, 2, 'nearest']
     18           [-1, 3]  1         0  models.common.Concat                    [1]
     19                -1  1     77568  models.common.C3                        [152, 128, 1, False]
     20                -1  1    147712  models.common.Conv                      [128, 128, 3, 2]
     21          [-1, 16]  1         0  models.common.Concat                    [1]
     22                -1  1    296448  models.common.C3                        [256, 256, 1, False]
     23                -1  1    590336  models.common.Conv                      [256, 256, 3, 2]
     24          [-1, 12]  1         0  models.common.Concat                    [1]
     25                -1  1   1182720  models.common.C3                        [512, 512, 1, False]
     26      [19, 22, 25]  1     18879  models.yolo.Detect                      [2, [[10, 13, 16, 30, 33, 23], [30, 61, 62, 45, 59, 119], [116, 90, 156, 198, 373, 326]], [128, 256, 512]]
    Model Summary: 340 layers, 3545453 parameters, 3545453 gradients, 6.3 GFLOPs
    

    yaml 文件中的这些参数[16, 16, 3, 2, 1, 0]]也是自定义的

       [-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-p3/8
       [-1, 1, MobileNetV3_InvertedResidual, [40,  96, 5, 2, 1, 1]],  # 4-p4/16
       [-1, 1, MobileNetV3_InvertedResidual, [40, 240, 5, 1, 1, 1]],  # 5-p4/16
       [-1, 1, MobileNetV3_InvertedResidual, [40, 240, 5, 1, 1, 1]],  # 6-p4/16
       [-1, 1, MobileNetV3_InvertedResidual, [48, 120, 5, 1, 1, 1]],  # 7-p4/16
       [-1, 1, MobileNetV3_InvertedResidual, [48, 144, 5, 1, 1, 1]],  # 8-p4/16
       [-1, 1, MobileNetV3_InvertedResidual, [96, 288, 5, 2, 1, 1]],  # 9-p5/32
       [-1, 1, MobileNetV3_InvertedResidual, [96, 576, 5, 1, 1, 1]],  # 10-p5/32
       [-1, 1, MobileNetV3_InvertedResidual, [96, 576, 5, 1, 1, 1]],  # 11-p5/32
    

    在mobilenetv3.py中都有定义,除了inp(input_channel)以外,其他一一对应

    class MobileNetV3_InvertedResidual(nn.Module):
        def __init__(self, inp, oup, hidden_dim, kernel_size, stride, use_se, use_hs):
    

    以[16, 16, 3, 2, 1, 0]]为例:

    oup=16,
    hidden_dim=16,
    kernel_size=3,
    stride=2,
    use_se=1,表示是否使用SELayer
    use_hs=0,表示使用h_swish还是ReLU
    use_se表示是否使用SELayer

    参考

    1. 目标检测 YOLOv5 自定义网络结构
    更多相关内容
  • yolov5网络结构

    yolov5

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    可以看出,相比于之前v5.x,最新版的v6.x网络结构更加精简(以提高速度和推理性能),主要有以下更新:

    <1>.Conv(k=6, s=2, p=2) 替换Focus
    <2>.SPPF代替SPP,并且将SPPF放在主干最后一层
    <3>.主干中的C3层重复次数从9次减小到6次
    <4>.主干中最后一个C3层引入shortcut

    1. CBL模块

    网络中的标准卷积层,有2D卷积+BN层+激活函数(SiLU)组成,在之后的Bottleneck、C3、SPPF等结构中都会被调用。

    import torch
    import torch.nn as nn
    
    展开全文
  • YOLOv5网络详解

    万次阅读 多人点赞 2022-03-19 14:23:17
    在前面我们已经介绍过了YOLOv1~v4的网络结构,今天接着上次的YOLOv4再来聊聊YOLOv5,如果还不了解YOLOv4的可以参考之前的博文。YOLOv5项目的作者是Glenn Jocher并不是原Darknet项目的作者Joseph Redmon。并且这个...

    官方源码仓库:https://github.com/ultralytics/yolov5
    文章下载地址:没有

    视频讲解:https://www.bilibili.com/video/BV1T3411p7zR



    0 前言

    在前面我们已经介绍过了YOLOv1~v4的网络的结构,今天接着上次的YOLOv4再来聊聊YOLOv5,如果还不了解YOLOv4的可以参考之前的博文。YOLOv5项目的作者是Glenn Jocher并不是原Darknet项目的作者Joseph Redmon。并且这个项目至今都没有发表过正式的论文。之前翻阅该项目的issue时,发现有很多人问过这个问题,有兴趣的可以翻翻这个issue #1333。作者当时也有说准备在2021年的12月1号之前发表,并承诺如果到时候没有发表就吃掉自己的帽子。
    在这里插入图片描述

    (⊙o⊙)…,emmm,但这都2022年了,也不知道他的帽子是啥味儿。过了他承诺的发表期限后,很多人还去该issue下表示"关怀",问啥时候吃帽子,下面这位大哥给我整笑了。

    在这里插入图片描述
    本来Glenn Jocher是准备要发表论文的,但至于为啥没发成作者并没有给出原因。我个人的猜测是自从YOLOv4发表后,有很多人想发这方面的文章,然后在YOLOv4上进行改动,改动过程中肯定有人把YOLOv5仓库里的一些技术拿去用了(YOLOv4论文4月出的,YOLOv5仓库5月就有了)。大家改完后发了一堆文章,那么YOLOv5的技术就被零零散散的发表到各个文章中去了。Glenn Jocher一看,这也太卷了吧,你们都把我技术写了,那我还写个锤子,直接撂挑子不干了。

    当然以上都是我个人yy哈,回归正题,YOLOv5仓库是在2020-05-18创建的,到今天已经迭代了很多个大版本了,现在(2022-3-19)已经迭代到v6.1了。所以本篇博文讲的内容是针对v6.1的,大家阅读的时候注意看下版本号,不同的版本内容会略有不同。前几天我在YOLOv5项目中向作者提了一个issue #6998,主要是根据当前的源码做了一个简单的总结,然后想让作者帮忙看看总结的内容是否有误,根据作者的反馈应该是没啥问题的,所以今天就来谈谈我个人的见解。下表是当前(v6.1)官网贴出的关于不同大小模型以及输入尺度对应的mAP、推理速度、参数数量以及理论计算量FLOPs

    Modelsize
    (pixels)
    mAPval
    0.5:0.95
    mAPval
    0.5
    Speed
    CPU b1
    (ms)
    Speed
    V100 b1
    (ms)
    Speed
    V100 b32
    (ms)
    params
    (M)
    FLOPs
    @640 (B)
    YOLOv5n64028.045.7456.30.61.94.5
    YOLOv5s64037.456.8986.40.97.216.5
    YOLOv5m64045.464.12248.21.721.249.0
    YOLOv5l64049.067.343010.12.746.5109.1
    YOLOv5x64050.768.976612.14.886.7205.7
    YOLOv5n6128036.054.41538.12.13.24.6
    YOLOv5s6128044.863.73858.23.612.616.8
    YOLOv5m6128051.369.388711.16.835.750.0
    YOLOv5l6128053.771.3178415.810.576.8111.4
    YOLOv5x6
    + TTA
    1280
    1536
    55.0
    55.8
    72.7
    72.7
    3136
    -
    26.2
    -
    19.4
    -
    140.7
    -
    209.8
    -

    1 网络结构

    关于YOLOv5的网络结构其实网上相关的讲解已经有很多了。网络结构主要由以下几部分组成:

    • Backbone: New CSP-Darknet53
    • Neck: SPPF, New CSP-PAN
    • Head: YOLOv3 Head

    下面是我根据yolov5l.yaml绘制的网络整体结构,YOLOv5针对不同大小(n, s, m, l, x)的网络整体架构都是一样的,只不过会在每个子模块中采用不同的深度和宽度,分别应对yaml文件中的depth_multiplewidth_multiple参数。还需要注意一点,官方除了n, s, m, l, x版本外还有n6, s6, m6, l6, x6,区别在于后者是针对更大分辨率的图片比如1280x1280,当然结构上也有些差异,后者会下采样64倍,采用4个预测特征层,而前者只会下采样到32倍且采用3个预测特征层。本博文只讨论前者。下面这幅图(yolov5l)有点大,大家可以下载下来仔细看一下。

    在这里插入图片描述

    通过和上篇博文讲的YOLOv4对比,其实YOLOv5在Backbone部分没太大变化。但是YOLOv5在v6.0版本后相比之前版本有一个很小的改动,把网络的第一层(原来是Focus模块)换成了一个6x6大小的卷积层。两者在理论上其实等价的,但是对于现有的一些GPU设备(以及相应的优化算法)使用6x6大小的卷积层比使用Focus模块更加高效。详情可以参考这个issue #4825。下图是原来的Focus模块(和之前Swin Transformer中的Patch Merging类似),将每个2x2的相邻像素划分为一个patch,然后将每个patch中相同位置(同一颜色)像素给拼在一起就得到了4个feature map,然后在接上一个3x3大小的卷积层。这和直接使用一个6x6大小的卷积层等效。

    在这里插入图片描述

    Neck部分的变化还是相对较大的,首先是将SPP换成成了SPPFGlenn Jocher自己设计的),这个改动我个人觉得还是很有意思的,两者的作用是一样的,但后者效率更高。SPP结构如下图所示,是将输入并行通过多个不同大小的MaxPool,然后做进一步融合,能在一定程度上解决目标多尺度问题。

    在这里插入图片描述
    SPPF结构是将输入串行通过多个5x5大小的MaxPool层,这里需要注意的是串行两个5x5大小的MaxPool层是和一个9x9大小的MaxPool层计算结果是一样的,串行三个5x5大小的MaxPool层是和一个13x13大小的MaxPool层计算结果是一样的。

    在这里插入图片描述

    下面做个简单的小实验,对比下SPPSPPF的计算结果以及速度,代码如下(注意这里将SPPF中最开始和结尾处的1x1卷积层给去掉了,只对比含有MaxPool的部分):

    import time
    import torch
    import torch.nn as nn
    
    
    class SPP(nn.Module):
        def __init__(self):
            super().__init__()
            self.maxpool1 = nn.MaxPool2d(5, 1, padding=2)
            self.maxpool2 = nn.MaxPool2d(9, 1, padding=4)
            self.maxpool3 = nn.MaxPool2d(13, 1, padding=6)
    
        def forward(self, x):
            o1 = self.maxpool1(x)
            o2 = self.maxpool2(x)
            o3 = self.maxpool3(x)
            return torch.cat([x, o1, o2, o3], dim=1)
    
    
    class SPPF(nn.Module):
        def __init__(self):
            super().__init__()
            self.maxpool = nn.MaxPool2d(5, 1, padding=2)
    
        def forward(self, x):
            o1 = self.maxpool(x)
            o2 = self.maxpool(o1)
            o3 = self.maxpool(o2)
            return torch.cat([x, o1, o2, o3], dim=1)
    
    
    def main():
        input_tensor = torch.rand(8, 32, 16, 16)
        spp = SPP()
        sppf = SPPF()
        output1 = spp(input_tensor)
        output2 = sppf(input_tensor)
    
        print(torch.equal(output1, output2))
    
        t_start = time.time()
        for _ in range(100):
            spp(input_tensor)
        print(f"spp time: {time.time() - t_start}")
    
        t_start = time.time()
        for _ in range(100):
            sppf(input_tensor)
        print(f"sppf time: {time.time() - t_start}")
    
    
    if __name__ == '__main__':
        main()
    

    终端输出:

    True
    spp time: 0.5373051166534424
    sppf time: 0.20780706405639648
    

    通过对比可以发现,两者的计算结果是一模一样的,但SPPFSPP计算速度快了不止两倍,快乐翻倍。

    Neck部分另外一个不同点就是New CSP-PAN了,在YOLOv4中,NeckPAN结构是没有引入CSP结构的,但在YOLOv5中作者在PAN结构中加入了CSP。详情见上面的网络结构图,每个C3模块里都含有CSP结构。在Head部分,YOLOv3, v4, v5都是一样的,这里就不讲了。


    2 数据增强

    在YOLOv5代码里,关于数据增强策略还是挺多的,这里简单罗列部分方法:

    • Mosaic,将四张图片拼成一张图片,讲过很多次了
      在这里插入图片描述

    • Copy paste,将部分目标随机的粘贴到图片中,前提是数据要有segments数据才行,即每个目标的实例分割信息。下面是Copy paste原论文中的示意图。
      在这里插入图片描述

    • Random affine(Rotation, Scale, Translation and Shear),随机进行仿射变换,但根据配置文件里的超参数发现只使用了ScaleTranslation即缩放和平移。
      在这里插入图片描述

    • MixUp,就是将两张图片按照一定的透明度融合在一起,具体有没有用不太清楚,毕竟没有论文,也没有消融实验。代码中只有较大的模型才使用到了MixUp,而且每次只有10%的概率会使用到。
      在这里插入图片描述

    • Albumentations,主要是做些滤波、直方图均衡化以及改变图片质量等等,我看代码里写的只有安装了albumentations包才会启用,但在项目的requirements.txt文件中albumentations包是被注释掉了的,所以默认不启用。

    • Augment HSV(Hue, Saturation, Value),随机调整色度,饱和度以及明度。
      在这里插入图片描述

    • Random horizontal flip,随机水平翻转
      在这里插入图片描述


    3 训练策略

    在YOLOv5源码中使用到了很多训练的策略,这里简单总结几个我注意到的点,还有些没注意到的请大家自己看下源码:

    • Multi-scale training(0.5~1.5x),多尺度训练,假设设置输入图片的大小为 640 × 640 640 \times 640 640×640,训练时采用尺寸是在 0.5 × 640 ∼ 1.5 × 640 0.5 \times 640 \sim 1.5 \times 640 0.5×6401.5×640之间随机取值,注意取值时取得都是32的整数倍(因为网络会最大下采样32倍)。
    • AutoAnchor(For training custom data),训练自己数据集时可以根据自己数据集里的目标进行重新聚类生成Anchors模板。
    • Warmup and Cosine LR scheduler,训练前先进行Warmup热身,然后在采用Cosine学习率下降策略。
    • EMA(Exponential Moving Average),可以理解为给训练的参数加了一个动量,让它更新过程更加平滑。
    • Mixed precision,混合精度训练,能够减少显存的占用并且加快训练速度,前提是GPU硬件支持。
    • Evolve hyper-parameters,超参数优化,没有炼丹经验的人勿碰,保持默认就好。

    4 其他

    4.1 损失计算

    YOLOv5的损失主要由三个部分组成:

    • Classes loss,分类损失,采用的是BCE loss,注意只计算正样本的分类损失。
    • Objectness lossobj损失,采用的依然是BCE loss,注意这里的obj指的是网络预测的目标边界框与GT Box的CIoU。这里计算的是所有样本的obj损失。
    • Location loss,定位损失,采用的是CIoU loss,注意只计算正样本的定位损失。

    L o s s = λ 1 L c l s + λ 2 L o b j + λ 3 L l o c Loss=\lambda_1 L_{cls} + \lambda_2 L_{obj} + \lambda_3 L_{loc} Loss=λ1Lcls+λ2Lobj+λ3Lloc
    其中, λ 1 , λ 2 , λ 3 \lambda_1, \lambda_2, \lambda_3 λ1,λ2,λ3为平衡系数。

    4.2 平衡不同尺度的损失

    这里是指针对三个预测特征层(P3, P4, P5)上的obj损失采用不同的权重。在源码中,针对预测小目标的预测特征层(P3)采用的权重是4.0,针对预测中等目标的预测特征层(P4)采用的权重是1.0,针对预测大目标的预测特征层(P5)采用的权重是0.4,作者说这是针对COCO数据集设置的超参数。
    L o b j = 4.0 ⋅ L o b j s m a l l + 1.0 ⋅ L o b j m e d i u m + 0.4 ⋅ L o b j l a r g e L_{obj} = 4.0 \cdot L_{obj}^{small} + 1.0 \cdot L_{obj}^{medium} + 0.4 \cdot L_{obj}^{large} Lobj=4.0Lobjsmall+1.0Lobjmedium+0.4Lobjlarge

    4.3 消除Grid敏感度

    在上篇文章YOLOv4中有提到过,主要是调整预测目标中心点相对Grid网格的左上角偏移量。下图是YOLOv2,v3的计算公式。

    在这里插入图片描述

    其中:

    • t x t_x tx是网络预测的目标中心 x x x坐标偏移量(相对于网格的左上角)
    • t y t_y ty是网络预测的目标中心 y y y坐标偏移量(相对于网格的左上角)
    • c x c_x cx是对应网格左上角的 x x x坐标
    • c y c_y cy是对应网格左上角的 y y y坐标
    • σ \sigma σSigmoid激活函数,将预测的偏移量限制在0到1之间,即预测的中心点不会超出对应的Grid Cell区域

    关于预测目标中心点相对Grid网格左上角 ( c x , c y ) (c_x, c_y) (cx,cy)偏移量为 σ ( t x ) , σ ( t y ) \sigma(t_x), \sigma(t_y) σ(tx),σ(ty)。YOLOv4的作者认为这样做不太合理,比如当真实目标中心点非常靠近网格的左上角点( σ ( t x ) \sigma(t_x) σ(tx) σ ( t y ) \sigma(t_y) σ(ty)应该趋近与0)或者右下角点( σ ( t x ) \sigma(t_x) σ(tx) σ ( t y ) \sigma(t_y) σ(ty)应该趋近与1)时,网络的预测值需要负无穷或者正无穷时才能取到,而这种很极端的值网络一般无法达到。为了解决这个问题,作者对偏移量进行了缩放从原来的 ( 0 , 1 ) (0, 1) (0,1)缩放到 ( − 0.5 , 1.5 ) (-0.5, 1.5) (0.5,1.5)这样网络预测的偏移量就能很方便达到0或1,故最终预测的目标中心点 b x , b y b_x, b_y bx,by的计算公式为:
    b x = ( 2 ⋅ σ ( t x ) − 0.5 ) + c x b y = ( 2 ⋅ σ ( t y ) − 0.5 ) + c y b_x = (2 \cdot \sigma(t_x) - 0.5) + c_x \\ b_y = (2 \cdot \sigma(t_y) - 0.5) + c_y bx=(2σ(tx)0.5)+cxby=(2σ(ty)0.5)+cy
    下图是我绘制的 y = σ ( x ) y = \sigma(x) y=σ(x)对应before曲线和 y = 2 ⋅ σ ( x ) − 0.5 y = 2 \cdot \sigma(x) - 0.5 y=2σ(x)0.5对应after曲线,很明显通过引入缩放系数scale以后, y y y x x x更敏感了,且偏移的范围由原来的 ( 0 , 1 ) (0, 1) (0,1)调整到了 ( − 0.5 , 1.5 ) (-0.5, 1.5) (0.5,1.5)
    在这里插入图片描述
    在YOLOv5中除了调整预测Anchor相对Grid网格左上角 ( c x , c y ) (c_x, c_y) (cx,cy)偏移量以外,还调整了预测目标高宽的计算公式,之前是:
    b w = p w ⋅ e t w b h = p h ⋅ e t h b_w = p_w \cdot e^{t_w} \\ b_h = p_h \cdot e^{t_h} bw=pwetwbh=pheth
    在YOLOv5调整为:
    b w = p w ⋅ ( 2 ⋅ σ ( t w ) ) 2 b h = p h ⋅ ( 2 ⋅ σ ( t h ) ) 2 b_w = p_w \cdot (2 \cdot \sigma(t_w))^2 \\ b_h = p_h \cdot (2 \cdot \sigma(t_h))^2 bw=pw(2σ(tw))2bh=ph(2σ(th))2
    作者Glenn Jocher的原话如下,也可以参考issue #471

    The original yolo/darknet box equations have a serious flaw. Width and Height are completely unbounded as they are simply out=exp(in), which is dangerous, as it can lead to runaway gradients, instabilities, NaN losses and ultimately a complete loss of training.

    作者的大致意思是,原来的计算公式并没有对预测目标宽高做限制,这样可能出现梯度爆炸,训练不稳定等问题。下图是修改前 y = e x y = e^x y=ex和修改后 y = ( 2 ⋅ σ ( x ) ) 2 y = (2 \cdot \sigma(x))^2 y=(2σ(x))2(相对Anchor宽高的倍率因子)的变化曲线, 很明显调整后倍率因子被限制在 ( 0 , 4 ) (0, 4) (0,4)之间。
    在这里插入图片描述

    4.4 匹配正样本(Build Targets)

    之前在YOLOv4介绍中有讲过该部分内容,其实YOLOv5也差不多。主要的区别在于GT BoxAnchor Templates模板的匹配方式。在YOLOv4中是直接将每个GT Box与对应的Anchor Templates模板计算IoU,只要IoU大于设定的阈值就算匹配成功。但在YOLOv5中,作者先去计算每个GT Box与对应的Anchor Templates模板的高宽比例,即:
    r w = w g t / w a t r h = h g t / h a t r_w = w_{gt} / w_{at} \\ r_h = h_{gt} / h_{at} \\ rw=wgt/watrh=hgt/hat
    然后统计这些比例和它们倒数之间的最大值,这里可以理解成计算GT BoxAnchor Templates分别在宽度以及高度方向的最大差异(当相等的时候比例为1,差异最小):
    r w m a x = m a x ( r w , 1 / r w ) r h m a x = m a x ( r h , 1 / r h ) r_w^{max} = max(r_w, 1 / r_w) \\ r_h^{max} = max(r_h, 1 / r_h) rwmax=max(rw,1/rw)rhmax=max(rh,1/rh)
    接着统计 r w m a x r_w^{max} rwmax r h m a x r_h^{max} rhmax之间的最大值,即宽度和高度方向差异最大的值:
    r m a x = m a x ( r w m a x , r h m a x ) r^{max} = max(r_w^{max}, r_h^{max}) rmax=max(rwmax,rhmax)
    如果GT Box和对应的Anchor Template r m a x r^{max} rmax小于阈值anchor_t(在源码中默认设置为4.0),即GT Box和对应的Anchor Template的高、宽比例相差不算太大,则将GT Box分配给该Anchor Template模板。为了方便大家理解,可以看下我画的图。假设对某个GT Box而言,其实只要GT Box满足在某个Anchor Template宽和高的 × 0.25 \times 0.25 ×0.25倍和 × 4.0 \times 4.0 ×4.0倍之间就算匹配成功。

    在这里插入图片描述
    剩下的步骤和YOLOv4中一致:

    • GT投影到对应预测特征层上,根据GT的中心点定位到对应Cell,注意图中有三个对应的Cell。因为网络预测中心点的偏移范围已经调整到了 ( − 0.5 , 1.5 ) (-0.5, 1.5) (0.5,1.5),所以按理说只要Grid Cell左上角点距离GT中心点在 ( − 0.5 , 1.5 ) (−0.5,1.5) (0.5,1.5)范围内它们对应的Anchor都能回归到GT的位置处。这样会让正样本的数量得到大量的扩充。
    • 则这三个Cell对应的AT2AT3都为正样本。

    在这里插入图片描述
    还需要注意的是,YOLOv5源码中扩展Cell时只会往上、下、左、右四个方向扩展,不会往左上、右上、左下、右下方向扩展。下面又给出了一些根据 G T x c e n t e r , G T y c e n t e r GT_x^{center}, GT_y^{center} GTxcenter,GTycenter的位置扩展的一些Cell案例,其中%1表示取余并保留小数部分。

    在这里插入图片描述
    到此,YOLOv5相关的内容基本上都分析完了。当然由于个人原因,肯定还有一些细节被我忽略掉了,也建议大家自己看看源码,收获肯定会更多。

    展开全文
  • YOLOv5网络结构+代码+应用详解|CSDN创作打卡

    万次阅读 多人点赞 2022-01-22 21:08:49
    (感谢@qq_44622851博友的提醒) (v5.0是SPP,v6.0是SPPF) 有关SPP/SPPF的分析可以康康博主之前写的博客 YOLOv5中的SPP/SPPF结构详解_tt丫的博客-CSDN博客_spp yolov5 四、Neck Neck说白了就是FPN+PAN结构的设计。...

    深度学习入门小菜鸟,希望像做笔记记录自己学的东西,也希望能帮助到同样入门的人,更希望大佬们帮忙纠错啦~侵权立删。

    这一篇文章属于是对YOLOv5系列的一个整理汇总。

    目录

    一、输入端分析

    二、整体网络结构图以及总括介绍

    三、Backbone

    四、Neck

     五、Head

    六、代码实现网络具体构建

    七、利用YOLOv5训练自己的数据集


    一、输入端分析

    YOLOv5输入端(一)—— Mosaic数据增强|CSDN创作打卡_tt丫的博客-CSDN博客

    YOLOv5输入端(二)|CSDN创作打卡_tt丫的博客-CSDN博客(自适应锚框计算+自适应图片缩放)


    二、整体网络结构图以及总括介绍

    网络结构图如下图所示:

    (其中CBL的标注都是有关输出的)

    在这里感谢博友352(兄弟你前面那个符号是啥我这边显示不出来,不好意思)的提醒

    v5.0版本

    目前更新到v6.0版本

    (这里比较大的改动是:用CBS代替 Focus 层,主要是为了方便模型导出 )

    YOLOv5网络结构分为3个部分,Backbone(主干部分),Neck和Head。

    Backbone作用:特征提取

    Neck作用:对特征进行一波混合与组合,并且把这些特征传递给预测层

    Head作用:进行最终的预测输出


    三、Backbone

    Backbone主要由Focus,CBS,BottleneckCSP(/C3)以及SPP等组成。

    🌳Focus作用:进行一个下采样,并且减少计算量加快网络速度。(v5.0)

    🌳CBS作用:(就是我们常说的卷积啦,虽然这里的卷积不是直接意义上的nn.Conv2d。)获取特征。

    有关Focus和CBS的分析可以康康博主之前写的博客

    YOLOv5中的Focus层详解_tt丫的博客-CSDN博客

    🌳BottleneckCSP(/C3)作用:残差结构,学习更多的特征。

    有关BottleneckCSP(/C3)的分析可以康康博主之前写的博客

    YOLOv5中的CSP结构_tt丫的博客-CSDN博客

    🌳SPP/SPPF作用:空间金字塔池化,将前面得到的任意大小的特征图转换成固定大小的特征向量。实现局部特征和全局特征的featherMap级别的融合。(感谢@qq_44622851博友的提醒)

    (v5.0是SPP,v6.0是SPPF)

    有关SPP/SPPF的分析可以康康博主之前写的博客

    YOLOv5中的SPP/SPPF结构详解_tt丫的博客-CSDN博客_spp yolov5


    四、Neck

    Neck说白了就是FPN+PAN结构的设计。

    关于FPN和PAN可以看博主之前写的文章

    深度学习中的FPN详解_tt丫的博客-CSDN博客

    深度学习之PAN详解_tt丫的博客-CSDN博客

    (这里v5.0和v6.0的区别请对照上图,懒得改了嘻嘻)


     五、Head

    我理解的Head就是输出端。如果单从网络结构上来说的话,他就是对Neck出来的3个输出分别进行卷积操作。然而Head的主要部分在于它的输出推理及处理。具体的可以看博主之前的文章,里面有关于损失函数,NMS以及源码的解析。

    YOLOv5的输出端详解_tt丫的博客-CSDN博客


    六、代码实现网络具体构建

    详见YOLOv5的模型构建源码详解|CSDN创作打卡_tt丫的博客-CSDN博客


    七、利用YOLOv5训练自己的数据集

    YOLOv5训练自己的数据集详解_tt丫的博客-CSDN博客


    欢迎大家在评论区批评指正,谢谢大家~

    展开全文
  • YOLOv5网络结构学习

    万次阅读 多人点赞 2021-05-07 16:29:20
    最近在学习yolov5的代码(因为项目需要),其实陆陆续续接触...我们就先从yolov5网络结构开始讲起吧~ 一、Focus层 Focus层的代码如下: class Focus(nn.Module): # Focus wh information into c-space def __ini
  • YOLOv5保姆级解读
  • YOLOv5s网络结构详解

    万次阅读 多人点赞 2020-08-15 13:08:29
    YOLOv5网络分析,并自行搭建
  • YOLOV5网络结构搭建

    千次阅读 2022-07-06 13:59:43
    二、残差块Bottleneck 三、C3模块 四、SPPF模块 ...五、主干网络 ...主干网络中的C3模块输入和...Pytorch 搭建自己的YoloV5目标检测平台(Bubbliiiing 源码详解 训练 预测)-Yolo Head介绍_哔哩哔哩_bilibiliYOLOv5
  • 文章目录1 总体介绍2 YOLOv3主干网络3 FPN特征融合4 利用Yolo Head获得预测结果5 不同尺度的先验框anchor box5.1 理论介绍5.2 代码读取6 YOLOv3整体网络结构代码理解7 感谢链接 1 总体介绍 YOLOv3网络主要包括两部分...
  • yolov5网络结构学习

    万次阅读 多人点赞 2021-04-19 14:21:13
    上图是yolov5s的网络结构,它是yolov5系列中深度最小、特征图宽度最小的网络。后面的m、l、x都是在此基础上不断加深、加宽的。 网络主要分为输入端、Backbone、Neck、Prediction四个部分。 它和yolov3主要不同的地方...
  • Yolov5m可视化网络结构

    万次阅读 多人点赞 2020-07-29 11:04:48
    Yolov5共有四种网络结构,每种网络深度和宽度上都不相同。 (1) Yolov5s可视化网络结构图:点击查看 (2) Yolov5m可视化网络结构图:点击查看 (3) Yolov5l可视化网络结构图:点击查看 (4) Yolov5x可视化网络结构图:...
  • 深度学习-YOLOv4网络结构详解

    千次阅读 2020-04-26 14:43:36
    论文提出YOLOv4,从图1的结果来看,相对于YOLOv3在准确率上提升了近10个点,然而速度并几乎没有下降. 论文主要贡献如下: 1.提出速度更快、精度更好的检测模型,仅需要单张1080Ti或2080Ti即可完成训练。 3.验证了...
  • 以下内容以 v5.0 为准,网络结构选用 yolov5s。 为了方便画图和理解网络结构,选用可视化工具:Netron 网页版进行可视化, 然后使用PPT作图。 在Releases · ultralytics/yolov5 · GitHub找到 v5.0中的Assets 中...
  • Yolov5中,网络模型的配置放在yaml文件中,而yolov5s放置在文件中其中一层网络的参数是用列表实现的,比如四个参数的含义分别是-1输入来自上一层,如果是正数i则代表第i层1使用一个网络模块Conv该层的网络层名字是...
  • YOLOv5模型网络结构简单理解及详解anchor设置

    万次阅读 多人点赞 2020-11-09 16:19:52
    YOLOv5模型网络结构理解及anchor设置写在前面Yolov5网络结构anchor(锚框)计算与设置详解 写在前面 作者最近在做一些目标检测的竞赛,参加了火箭军智箭火眼人工智能挑战赛,科目一排名28,科目二排名23,提升不上去...
  • 深入浅出 Yolo 系列之 Yolov7 基础网络结构详解

    万次阅读 多人点赞 2022-07-20 00:23:08
    从 2015 年的 ** YOLOV1,2016 年 YOLOV2,2018...对于 YOLO 的基础知识以及 YOLOV1 到 YOLOV5 可以去看大白的 YOLO 系列,本文主要对 YOLOV7 的网络结构进行一个梳理,便于大家直观的感受。 1. YOLOV7 整体结构 ...
  • yolov5模型框架详解

    万次阅读 2021-03-03 13:56:26
    yolov5yolov4很像 Mosaic数据增强 1、每次读取四张图片。 2、分别对四张图片进行翻转、缩放、色域变化等,并且按照四个方向位置摆好。 3、进行图片的组合和框的组合 对于小目标的检测效果还是很不错的 自适应...
  • Yolov5s网络结构

    千次阅读 2022-04-25 22:39:07
    (5): Conv( (conv): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False) (bn): BatchNorm2d(256, eps=0.001, momentum=0.03, affine=True, track_running_stats=True) (act): SiLU()...
  • YOLOv4网络详解

    千次阅读 2022-04-20 16:49:06
    1.YOLOV4的网络改进部分 1、主干特征提取网络:DarkNet53 => CSPDarkNet53、使用Mish激活函数 2、特征金字塔:SPP结构,PAN结构 优化策略: 1.Eliminate grid sensitivity 2.Mosaic data augmentation 3. IoU ...
  • Yolov4网络详解

    2022-07-21 09:43:15
    Yolov4是在2020年CVPR上发表的,从作者的名字可以知道Yolov4并不是原Yolo系列的作者。
  • YOLOv5 6.0 结构

    2022-05-27 09:13:49
    贡献一张6.0版本的结构图,想要用的拿去
  • 上节分析了 v5.0 的 yolov5s 模型架构,本节顺便把 v6.0的图也画下。官方代码中贴心的给提供了 onnx 文件,如下图: 但是,当我打开 onnx 的时候,我麻了... 所以,还是需要自己生成下 onnx 文件。 打开...
  • 理解yolov6网络结构

    千次阅读 2022-07-11 19:27:38
    先上一张yolov6的网络架构图片来源于网络 yolov6使用了repVGG作为backbone 如果不了解repVGG的可以看原文 这里简单过一下,repVGG其核心思想是:通过结构重参数化思想,让训练网络的多路结构转换为推理网络的单路...
  • YOLOv5-v6.0-网络架构详解,包含架构图

空空如也

空空如也

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

yolov5网络结构详解

友情链接: 分类器识别.zip