赞
踩
本教程涉及到的代码在 https://github.com/Oneflow-Inc/one-yolov5,教程也同样适用于 ultralytics/yolov5 因为 one-yolov5 仅仅是换了一个运行时后端而已,计算逻辑和代码相比于 ultralytics/yolov5 没有做任何改变,欢迎 star 。详细信息请看One-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
) 源码进行解读。
- nc: 80 # number of classes 数据集中的类别数
- depth_multiple: 0.33 # model depth multiple 模型层数因子(用来调整网络的深度)
- width_multiple: 0.50 # layer channel multiple 模型通道数因子(用来调整网络的宽度)
- # 如何理解这个depth_multiple和width_multiple呢?它决定的是整个模型中的深度(层数)和宽度(通道数),具体怎么调整的结合后面的backbone代码解释。
-
- anchors: # 表示作用于当前特征图的Anchor大小为 xxx
- # 9个anchor,其中P表示特征图的层级,P3/8该层特征图缩放为1/8,是第3层特征
- - [10,13, 16,30, 33,23] # P3/8, 表示[10,13],[16,30], [33,23]3个anchor
- - [30,61, 62,45, 59,119] # P4/16
- - [116,90, 156,198, 373,326] # P5/32
-
-
- # YOLOv5s 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
- ]
-
- # YOLOv5s 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 初始化了 9 个 anchors,分别在三个特征图 (feature map)中使用,每个 feature map 的每个 grid cell 都有三个 anchor 进行预测。 分配规则:
尺度越大的 feature map 越靠前,相对原图的下采样率越小,感受野越小, 所以相对可以预测一些尺度比较小的物体(小目标),分配到的 anchors 越小。
尺度越小的 feature map 越靠后,相对原图的下采样率越大,感受野越大, 所以可以预测一些尺度比较大的物体(大目标),所以分配到的 anchors 越大。
即在小特征图(feature map)上检测大目标,中等大小的特征图上检测中等目标, 在大特征图上检测小目标。
四个参数的意义分别是:
第一个参数 from :从哪一层获得输入,-1表示从上一层获得,[-1, 6]表示从上层和第6层两层获得。
第二个参数 number:表示有几个相同的模块,如果为9则表示有9个相同的模块。
第三个参数 module:模块的名称,这些模块写在common.py中。
第四个参数 args:类的初始化参数,用于解析作为 moudle 的传入参数。
下面以第一个模块Conv 为例介绍下common.py中的模块
Conv 模块定义如下:
- class Conv(nn.Module):
- # Standard convolution
- def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True): # ch_in, ch_out, kernel, stride, padding, groups
- """
- @Pargm c1: 输入通道数
- @Pargm c2: 输出通道数
- @Pargm k : 卷积核大小(kernel_size)
- @Pargm s : 卷积步长 (stride)
- @Pargm p : 特征图填充宽度 (padding)
- @Pargm g : 控制分组,必须整除输入的通道数(保证输入的通道能被正确分组)
- """
- super().__init__()
- # https://oneflow.readthedocs.io/en/master/generated/oneflow.nn.Conv2d.html?highlight=Conv
- self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=False)
- self.bn = nn.BatchNorm2d(c2)
- self.act = nn.SiLU() if act is True else (act if isinstance(act, nn.Module) else nn.Identity())
-
- def forward(self, x):
- return self.act(self.bn(self.conv(x)))
-
- def forward_fuse(self, x):
- 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), 1) if n > 1 else n # depth gain 暂且将这段代码当作公式(1)
其中 gd 就是depth_multiple的值,n的值就是backbone中列表的第二个参数:
根据公示(1) 很容易看出 gd 影响 n 的大小,从而影响网络的结构大小。
后面各层之间的模块数量、卷积核大小和数量
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。