# YOLOv5 by Ultralytics, GPL-3.0 license
"每一行代表在某一层的anchor. 一行的三组数字分别代表三个anchor的宽和高基准,且小的anchor应
用在大特征图上,大的anchor应用在小特征图上。以输入图片大小640*640为例,最终提取三个特征图
大小分别为 80 X 80 , 40 X 40, 20X20,那么 :"
"""
在YOLOv5Q中网络结构采用yaml作为配置文件,之前我们也介绍过,YOLOV5配置了4种不同大小的 网络模型,分别是YOLOV5s.YOLOv5m、YOLOV51、YOLOV5x,这几个模型的结构基本-样,
不同的是depth multiple模型深度和width multiple模型宽度这两参数。就和我们买衣服的尺码大小排序一样,YOLOV5s
网络是YOLO5系列中深度最小,特征图的宽度最小的网络。其他的三种都是在此基础上不断加深,不断加宽。所以,这篇文竟我们就以yolov5s.yaml为例来介绍。
YAML,即“ YAML Ain'ta Markup Lanquage (YAML 不是一种标记语言)”的递归缩写。YAML真实意思是“Yet Another MarkupLanguage(仍是一种标记语言)”。
是专门用来写配置文件的语言,能很好的与当下的编程语言的一些任务相互协作,非常简洁和强大。
"""
# Parameters
nc: 80 # number of classes
depth_multiple: 0.33 # models1 depth multiple 模型层数因子 控制模型的深度 (BottleneckcSP个数)
width_multiple: 0.50 # layer channel multiple 模型通道数因子 控制conv通道channel个数(卷积核数量)
#小的Feature Map检测大的目标,小的Feature Map感受野大,所以相应的BBox也大
#9个anchor,其中p表示特征图的层级,P3/8该层特征图缩放为1/8,是第3层特征
anchors:
- [10,13, 16,30, 33,23] # P3/8 FM_size:80*80 FPN接主干网络下采样8倍后的anchor大小,检测小目标,10,13是一组尺寸,总共三组检测小目标[30,61,62,45,59,119]
- [30,61, 62,45, 59,119] # P4/16 FM_size:40*40 FPN接主于网络下采样16倍后的anchor大小,检测中目标,共三组[116,90,156,198,373,326]
- [116,90, 156,198, 373,326] # P5/32 FM_size:20*20 FPN接主干网络下采样32倍后的anchor大小,检测大目标,共三组
"
YOLOv5使用k-means聚类法来初始化了9个anchors,任意地选择了9个聚类和3个尺度,然后在各个尺度上均匀地划分聚类。在COCO数据集上, 这9个聚类是(10 x 13), (16 x 30), (33 x 23),
(30 x 61), (62 x 45), 59 x 119), (116 x 90), (156 x 198), (373 x 326)。这9个anchor分别在=个Detect层的feature map中使用,每个feature map的每个grid cell 都有三个anchor进行预测。
尺度越大的feature map分辨率越大,相对于原图的下采样越小,其感受野也就越小,那么设置的anchors自然越小,如110.13.16,30,33,23],因此对原始图像中的小物体预测较好;
尺度越小的freaure map分辨率越小,相对于原图的下采样越大,其感受野越大,设置的anchors自然也就越大,如116.90156.198,373.3261,因此对原始图像中的大物体预测较好。
"
# YOLOv5 v6.0 backbone
backbone:
# [from, number, module, args]
#from:表示当前模块的输入来自那一层的输出,-1表示将上一层的输出当做自己的输入(第0层的-1表示输入的图像)
#number:表示当前模块的重复次数,实际的重复次数还要由上面的参数depth multiple共同决定,决定网络模型的深度
#module:表示该层模块的名称,这些模块写在common.py中,进行模块化的搭建网络
#args:表示类的初始化参数,用于解析作为 moudle 的传入参数,会在网络搭建过程中根据不同层进行改变
#另外,注释中的#0-P112表示该层为第0层,输出后会变成原图的1/2
"
-------------------0------------
[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
原始输入图片: 640*640*3
第0层: Conv层 [-1,1,Conv,[64,6, 2, 2]]
。-1: 输入是图片
。1: 网络模块数量为1
。Conv: 该层的网络层名字是Conv
。[64,6,2,2]: Conv层的四个参数
64: channel=64
6: kernel size=6
2: padding=2
2: stride=2
输出图片: 320*320*64
-------------------1------------
[-1, 1, Conv, [128, 3, 2]], # 1-P2/4--》变为原图的4分之1
输入图片: 320*320*64
第1层: Conv层[-1,1,Conv,[128,3,2]]
。-1: 输入是上一层的输出
。1: 网络模块数量为1
。Conv: 该层的网络层名字是Conv
。[128,3,2]: Conv层的三个参数
128: channel=128
3: kernel size=3
2: stride=2
输出图片: 160*160*128
-------------------2------------
第2层: C3层[-1,3,C3,[128]]
。-1: 输入是上一层的输出
。3:网络模块数量为3
。C3:该层的网络层名字是C3·
。[128]: C3层的参数。
128: channel=128
。输出图片: 160*160*128
-------------------3------------
第3层: Conv层[-1,1,Conv, [256,3,2]]
。-1: 输入是上一层的输出
。1: 网络模块数量为1
。Conv: 该层的网络层名字是Conv
[256,3,2]: Conv层的三个参数
256: channel=256
3: kernel size=3
2: stride=2
图片变化: 80*80*256
-------------------4------------
第4层: C3层 [-1,6,C3,[256]]
。-1: 输入是上一层的输出
。6:网络模块数量为6
。C3:该层的网络层名字是C3
。[256]: C3层的参数256: channel=256
图片变化: 80*80*256
-------------------6------------
第6层: C3层[-1,9,C3,[512]]
。-1: 输入是上一层的输出。9: 网络模块数量为9
。C3:该层的网络层名字是C3。
。[512]: C3层的参数
512: channel=512
输出图片: 40*40*512
-------------------9------------
第9层: SPPF层[-1,1, SPPF,[1024, 5]]
。主要是对不同尺度特征图的融合
。-1: 输入是上一层的输出
。1:网络模块数量为1
。SPPF: 该层的网络层名字是SPPF
。[1024,5]: SPPF层的两个参数。1024: channel=10245: kernel size=5
。输出图片: 20*20*1024
"
"到第9层为止,backbone部分就结束了,这个部分会形成三个接口:
第4层的输出: 80*80*256
第6层的输出: 40*40*512
第9层的输出: 20*20*1024"
[[-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
"
YOLOv5中的Head包括Neck和Detect两部分。
Neck采用了FPN+PAN结构,Detect结构和YOLOV3中的Head一样。其中BottleNeckCSP带有False,说明没有使用残差结构,而是采用的backbone中的Conv。
上一个阶段输出大小: 20*20*1024
首先前两个阶段是向上concat
第10层: Conv层[-1,1, Conv,[512, 1, 1]]
。-1: 输入是上一层的输出
。1: 网络模块数量为1
。Conv: 该层的网络层名字是Conv
[512,1,1]: Conv层的三个参数
。512: channel=512
。1: kernel size=1
1: stride=1
输出图片: 20*20*512
第11层: Upsample层 [-1, 1, nn.Upsample,[None, 2,'nearest]]
。-1: 输入是上一层的输出
。1: 网络模块数量为1
。nn.Upsample: 该层的网络层名字是Upsample
[None,2,nearest]: Upsample层的三个参数
None: size=None (指定输出的尺寸大小)
2: scale factor=2 (指定输出的尺寸是输入尺寸的倍数)。
'nearest': mode='nearest' (默认: nearest)
输出图片: 通过该层之后特征图不改变通道数,特征图的长和宽会增加一倍40*40*512
第12层: Concat层[[-1,6],1,Concat,[1]]
。[-1,6]: 输入是上一层和第6层的输出
。1: 网络模块数量为1
。Concat: 该层的网络层名字是Concat
。[1]: Concat层的参数
[1]: 拼接的维度=1
输出图片: 通过该层之后特征图与第6层(p4阶段)的输出进行特征图的融合-40*40*1024 (即输出40x40x512contact40x40x512=40x40x1024)
第13层: C3层[-1,3, C3,[512, False]]
。-1: 输入是上一层的输出
。3:网络模块数量为1
。C3: 该层的网络层名字是C3
。[512,False]: C3层的两个参数
512: channel=512
False:没有残差模块
输出图片: 40*40*512
"
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) 其中最后一层的Detect由yolo.py文件中的Detect类来定义。
]
"
第24层: Detect层 [[17, 20, 23], 1, Detect, [nc, anchors]]
[17,20,23]: 表示把第17、20和23三层作为Detect模块的输入
1: 网络模块数量为1
Detect: 该层的网络层名字是Detect
[nc,anchors]: 初始化Detect模块的参数
。nc: 类别个数
。anchors: 超参数 anchors的值
输出图片: 20*20*1024
"
##Detect类负责yolov5的3个检测头层的构建, 实现上只有一个卷积层,卷积核为1x1, 输入是P3,
#P4, P5层。 Detect层位于下图中的红框处。
#这行的含义是,以17,20,23层作为输入,重复一次,参数是[nc, anchors],其中nc是类别数量,对于
#coco数据集来说, nc = 80,anchors是各层对应的anchors或者anchors的数量。