• YOLOv5全面解析教程①:网络结构逐行代码解析


    本教程涉及到的代码在 https://github.com/Oneflow-Inc/one-yolov5,教程也同样适用于 ultralytics/yolov5 因为 one-yolov5 仅仅是换了一个运行时后端而已,计算逻辑和代码相比于 ultralytics/yolov5 没有做任何改变,欢迎 star 。详细信息请看One-YOLOv5 发布,一个训得更快的YOLOv5

    YOLOv5 网络结构解析

    引言

    YOLOv5针对不同大小(n, s, m, l, x)的网络整体架构都是一样的,只不过会在每个子模块中采用不同的深度和宽度,

    分别应对yaml文件中的depth_multiple和width_multiple参数。

    还需要注意一点,官方除了n, s, m, l, x版本外还有n6, s6, m6, l6, x6,区别在于后者是针对更大分辨率的图片比如1280x1280,

    当然结构上也有些差异,前者只会下采样到32倍且采用3个预测特征层 , 而后者会下采样64倍,采用4个预测特征层。

    本章将以 yolov5s为例 ,从配置文件 models/yolov5s.yaml(https://github.com/Oneflow-Inc/one-yolov5/blob/main/models/yolov5s.yaml) 到 models/yolo.py(https://github.com/Oneflow-Inc/one-yolov5/blob/main/models/yolo.py) 源码进行解读。

    yolov5s.yaml文件内容:

    1. nc: 80  # number of classes 数据集中的类别数
    2. depth_multiple: 0.33  # model depth multiple  模型层数因子(用来调整网络的深度)
    3. width_multiple: 0.50  # layer channel multiple 模型通道数因子(用来调整网络的宽度)
    4. # 如何理解这个depth_multiple和width_multiple呢?它决定的是整个模型中的深度(层数)和宽度(通道数),具体怎么调整的结合后面的backbone代码解释。
    5. anchors: # 表示作用于当前特征图的Anchor大小为 xxx
    6. 9个anchor,其中P表示特征图的层级,P3/8该层特征图缩放为1/8,是第3层特征
    7.   - [10,1316,3033,23]  # P3/8, 表示[10,13],[16,30], [33,23]3个anchor
    8.   - [30,6162,4559,119]  # P4/16
    9.   - [116,90156,198373,326]  # P5/32
    10. # YOLOv5s v6.0 backbone
    11. backbone:
    12.   # [fromnumber, module, args]
    13.   [[-11, Conv, [64622]],  # 0-P1/2
    14.    [-11, Conv, [12832]],  # 1-P2/4
    15.    [-13, C3, [128]],
    16.    [-11, Conv, [25632]],  # 3-P3/8
    17.    [-16, C3, [256]],
    18.    [-11, Conv, [51232]],  # 5-P4/16
    19.    [-19, C3, [512]],
    20.    [-11, Conv, [102432]],  # 7-P5/32
    21.    [-13, C3, [1024]],
    22.    [-11, SPPF, [10245]],  # 9
    23.   ]
    24. # YOLOv5s v6.0 head
    25. head:
    26.   [[-11, Conv, [51211]],
    27.    [-11, nn.Upsample, [None, 2'nearest']],
    28.    [[-16], 1, Concat, [1]],  # cat backbone P4
    29.    [-13, C3, [512False]],  # 13
    30.    [-11, Conv, [25611]],
    31.    [-11, nn.Upsample, [None, 2'nearest']],
    32.    [[-14], 1, Concat, [1]],  # cat backbone P3
    33.    [-13, C3, [256False]],  # 17 (P3/8-small)
    34.    [-11, Conv, [25632]],
    35.    [[-114], 1, Concat, [1]],  # cat head P4
    36.    [-13, C3, [512False]],  # 20 (P4/16-medium)
    37.    [-11, Conv, [51232]],
    38.    [[-110], 1, Concat, [1]],  # cat head P5
    39.    [-13, C3, [1024False]],  # 23 (P5/32-large)
    40.    [[172023], 1, Detect, [nc, anchors]],  # Detect(P3, P4, P5)
    41.   ]

    anchors 解读

    yolov5 初始化了 9 个 anchors,分别在三个特征图 (feature map)中使用,每个 feature map 的每个 grid cell 都有三个 anchor 进行预测。 分配规则:

    • 尺度越大的 feature map 越靠前,相对原图的下采样率越小,感受野越小, 所以相对可以预测一些尺度比较小的物体(小目标),分配到的 anchors 越小。

    • 尺度越小的 feature map 越靠后,相对原图的下采样率越大,感受野越大, 所以可以预测一些尺度比较大的物体(大目标),所以分配到的 anchors 越大。

    • 即在小特征图(feature map)上检测大目标,中等大小的特征图上检测中等目标, 在大特征图上检测小目标。

    backbone & head解读

    [from, number, module, args] 参数

    四个参数的意义分别是:

    1. 第一个参数 from :从哪一层获得输入,-1表示从上一层获得,[-1, 6]表示从上层和第6层两层获得。

    2. 第二个参数 number:表示有几个相同的模块,如果为9则表示有9个相同的模块。

    3. 第三个参数 module:模块的名称,这些模块写在common.py中。

    4. 第四个参数 args:类的初始化参数,用于解析作为 moudle 的传入参数。

    下面以第一个模块Conv 为例介绍下common.py中的模块

    Conv 模块定义如下:

    1. class Conv(nn.Module):
    2.     # Standard convolution
    3.     def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True):  # ch_inch_out, kernel, stride, padding, groups
    4.         """
    5.         @Pargm c1: 输入通道数
    6.         @Pargm c2: 输出通道数
    7.         @Pargm k : 卷积核大小(kernel_size)
    8.         @Pargm s : 卷积步长 (stride)
    9.         @Pargm p : 特征图填充宽度 (padding)
    10.         @Pargm g : 控制分组,必须整除输入的通道数(保证输入的通道能被正确分组)
    11.         """
    12.         super().__init__()
    13.         # https://oneflow.readthedocs.io/en/master/generated/oneflow.nn.Conv2d.html?highlight=Conv
    14.         self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=False)
    15.         self.bn = nn.BatchNorm2d(c2)
    16.         self.act = nn.SiLU() if act is True else (act if isinstance(act, nn.Module) else nn.Identity())
    17.     def forward(self, x):
    18.         return self.act(self.bn(self.conv(x)))
    19.     def forward_fuse(self, x):
    20.         return self.act(self.conv(x))

    比如上面把width_multiple设置为了0.5,那么第一个 [64, 6, 2, 2] 就会被解析为 [3,64*0.5=32,6,2,2],其中第一个 3 为输入channel(因为输入),32 为输出channel。

    关于调整网络大小的详解说明

    在yolo.py(https://github.com/Oneflow-Inc/one-yolov5/blob/main/models/yolo.py)的256行 有对yaml 文件的nc,depth_multiple等参数读取,具体代码如下:

    anchors, nc, gd, gw = d['anchors'], d['nc'], d['depth_multiple'], d['width_multiple']
    

    "width_multiple"参数的作用前面介绍args参数中已经介绍过了,那么"depth_multiple"又是什么作用呢?

    在yolo.py(https://github.com/Oneflow-Inc/one-yolov5/blob/main/models/yolo.py)的257行有对参数的具体定义:

     n = n_ = max(round(n * gd), 1if n > 1 else n  # depth gain 暂且将这段代码当作公式(1)
    

    其中 gd 就是depth_multiple的值,n的值就是backbone中列表的第二个参数:

    根据公示(1)  很容易看出 gd 影响 n 的大小,从而影响网络的结构大小。

    后面各层之间的模块数量、卷积核大小和数量

  • 相关阅读:
    ros2 代码风格检查
    Skywalking Swck Agent注入实现分析
    2021 增强式学习RL 李宏毅
    debian12安装fail2ban
    物联网:用python调入机器学习分析物联网数据入侵检测模块
    云原生可观测套件:构建无处不在的可观测基础设施
    js 深入理解原型(prototype)及如何创建对象
    计算机组成原理百道必考大总结(上)
    STM32 SPI
    自动化测试selenium篇
  • 原文地址:https://blog.csdn.net/OneFlow_Official/article/details/128075629