当前位置:   article > 正文

YOLOv5全面解析教程①:网络结构逐行代码解析_[-1,1,conv,[64,6,2,2]]

[-1,1,conv,[64,6,2,2]]

本教程涉及到的代码在 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 的大小,从而影响网络的结构大小。

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/136547
推荐阅读
相关标签
  

闽ICP备14008679号