前言

最近在重构YOLOv5代码,本章主要介绍YOLOv5s的网络结构

1、YOLOv5s-6.0组成

我们熟知YOLOv5s由三部分组成,分别为backbone、neck、head

  1. backbone:主干网络,大多时候指的是提取特征的网络,其作用就是提取图片中的信息,供后面的网络使用。backbone主干网络可以直接加载官方已经训练好的模型参数,此外其后面,添加自己需要的网络,让自定义模型更加贴合实际使用。
  2. neck:放在backbone和head之间,进一步利用backbone提取的特征,提高模型的鲁棒性
  3. head:获取网络输出,head利用之前提取的特征,做出预测。

2、YOLOv5s网络介绍

2.1、参数解析

  1. nc:数据集中的类别数

  2. depth_multiple:模型层数因子(用来调整网络的深度)

    1. 为了控制层的重复的次数。它会和后面的backbone & head的number相乘后取整,代表该层的重复的数量
    2. 如:[[-1, 1, Conv, [64, 6, 2, 2]],当depth_multiple为1时候,则重复1*1个
depth_multiple 0.33 0.67 1.0 1.33
模块 [参数] yolov5s yolov5m yolov5l yolov5x
第1个C3 [-1, 3, C3, [128]] BottleNeck x 1 BottleNeck x 2 BottleNeck x 3 BottleNeck x 4
第2个C3 [-1, 6, C3, [256]] BottleNeck x 2 BottleNeck x 4 BottleNeck x 6 BottleNeck x 8
第3个C3 [-1, 9, C3, [512]] BottleNeck x 3 BottleNeck x 6 BottleNeck x 9 BottleNeck x 12
第4个C3 [-1, 3, C3, [1024]] BottleNeck x 1 BottleNeck x 2 BottleNeck x 3 BottleNeck x 4
第5个C3 [-1, 3, C3, [512, False]] BottleNeck x 1 BottleNeck x 2 BottleNeck x 3 BottleNeck x 4
第6个C3 [-1, 3, C3, [256, False]] BottleNeck x 1 BottleNeck x 2 BottleNeck x 3 BottleNeck x 4
第7个C3 [-1, 3, C3, [512, False]] BottleNeck x 1 BottleNeck x 2 BottleNeck x 3 BottleNeck x 4
第8个C3 [-1, 3, C3, [1024, False]] BottleNeck x 1 BottleNeck x 2 BottleNeck x 3 BottleNeck x 4
  1. width_multiple:模型通道数因子(用来调整网络的宽度)

    1. 为了控制输出特征图的通道数,它会和出特征图的通道数相乘,代表该层的输出通道数。
    2. 如:[[-1, 1, Conv, [64, 6, 2, 2]],当width_multiple为0.5时候,则输出通道为64*0.5=32通道
width_multiple 0.5 0.75 1.0 1.25
模块 [输出通道数/卷积核个数/步长/零填充] yolov5s yolov5m yolov5l yolov5x
第1个Conv [64, 6, 2, 2] 32 48 64 80
第2个Conv [128, 3, 2] 64 96 128 160
第3个Conv [256, 3, 2] 128 192 256 320
第4个Conv [512, 3, 2] 256 384 512 640
第5个Conv [1024, 3, 2] 512 768 1024 1280
第6个Conv [512, 1, 1] 256 384 512 640
第7个Conv [256, 1, 1] 128 192 256 320
第8个Conv [256, 3, 2] 128 192 256 320
第9个Conv [512, 3, 2] 256 384 512 640

  1. anchors:锚定框

    1. yolov5 初始化了 9 个 anchors,分别在三个特征图 (feature map)中使用,每个 feature map 的每个 grid cell (网络单元)都有三个 anchor 进行预测。分配规则:
      • 尺度越大的 feature map 越靠前,相对原图的下采样率越小,感受野越小,所以相对可以预测一些尺度比较小的物体(小目标),分配到的 anchors 越小。
      • 尺度越小的 feature map 越靠后,相对原图的下采样率越大,感受野越大,所以可以预测一些尺度比较大的物体(大目标),所以分配到的 anchors 越大。
      • 即在小特征图(feature map)上检测大目标,中等大小的特征图上检测中等目标,在大特征图上检测小目标。

5.如何计算参数

H₂=(H1-K+2P)/S+1

其中,H1代表输入宽度,K代表卷积核个数,P代表零填充,S代表步长。

  • Conv:卷积,一般来说宽高会降低一半(主要看参数)。
  • Upsample: 上采样,宽高升高一倍。
  • Concat:拼接,宽高一致情况下,维度相加。
  • 一般S步长为2时候,宽高都会缩小一半,因为除以2
  1. [from, number, module, args] 参数

    [from, number, module, args]

    1. 第一个参数 from :从哪一层获得输入,-1表示从上一层获得,[-1, 6]表示从上层和第6层两层获得。
    2. 第二个参数 number:表示有几个相同的模块,如果为9则表示有9个相同的模块。
    3. 第三个参数 module:模块的名称,这些模块写在common.py中。
    4. 第四个参数 args:类的初始化参数,用于解析作为 moudle 的传入参数。
      • args参数依次为:输出channel,卷积核大小kernel size,步长stride,p零填充大小,以字典的形式给出,具体取决于该层所使用的模块类型。即,这些参数在初始化时将模块的形参进行了更新。
[-1, 1, Conv, [64, 3, 2]]:
含义:定义一个卷积层。

-1:表示该层的输入来自上一层(即前一层的输出)。

 1:表示该层重复 1 次。

 Conv:表示这是一个卷积层。

[64, 3, 2]:卷积层的参数,分别表示输出通道数为 64,卷积核大小为 3×3,步幅为 2。

 # [from, number, module, args]
 # 输入640*640
 # [64, 6, 2, 2] c2=64,k=6,s=2,p=2 , s=2 宽高减半
 # [128, 3, 2] c2=128,k=3,s=2
  [[-1, 1, Conv, [64, 6, 2, 2]],  # 64*320*320
   [-1, 1, Conv, [128, 3, 2]],    # 128*160*160
   [-1, 3, C3, [128]],            # 128*160*160
   [-1, 1, Conv, [256, 3, 2]],    # 256*80*80
   [-1, 6, C3, [256]],            # 256*80*80
   [-1, 1, Conv, [512, 3, 2]],    # 512*40*40
   [-1, 9, C3, [512]],            # 512*40*40
   [-1, 1, Conv, [1024, 3, 2]],   # 1024*20*20
   [-1, 3, C3, [1024]],           # 1024*20*20
   [-1, 1, SPPF, [1024, 5]],      # 1024*20*20
  ]

针对Conv模块,我们可以在YOLO的目录下的module/common.py·中找到如下图所示的Conv的代码:

在这里插入图片描述
在模块初始化时,这些模块的参数的作用:

一般的数据都是从c2开始依次传输,即 [128, 3, 2] 代表 c2=128,k=3,s=2

  1. c1 :表示输入通道数,即输入特征图的深度或通道数。它决定了输入特征图的形状。
  2. c2 :表示输出通道数,即卷积层中卷积核的数量,也是输出特征图的深度或通道数。它决定了输出特征图的形状。
  3. k:表示卷积核的大小或尺寸。在这里,k 是一个整数,表示卷积核的高度和宽度相等。例如,k=3 表示使用一个 3x3 的卷积核。
  4. s:表示卷积的步幅(stride),即卷积核在输入特征图上滑动的步长。默认情况下,步幅为 1,表示卷积核每次滑动一个像素。如果设置 s=2,则卷积核每次滑动两个像素。
  5. p:表示卷积的填充(padding)。填充是在输入特征图周围添加额外的像素,以控制输出特征图的大小。p 可以是一个整数,表示在每个边缘添加相同数量的填充像素,也可以是一个元组 (p1, p2),其中 p1 表示在高度方向的填充数,p2 表示在宽度方向的填充数。默认情况下,没有填充。
  6. g:表示分组卷积(group convolution)中的分组数。默认为 1,表示标准的卷积操作。当 g 大于 1 时,卷积核被分成 g 个子组,每个子组进行独立的卷积操作。分组卷积可以降低计算量,减少参数数量。
  7. d:表示卷积操作的扩张(dilation)。扩张卷积是通过在卷积核元素之间添加间隔来增加感受野的。d 的默认值为 1,表示标准的卷积操作。当 d 大于 1 时,卷积核元素之间会有间隔。

2.2、YOLOv5s.yaml

nc: 80  # number of classes 数据集中的类别数,也就是你要检测的类别数
depth_multiple: 0.33  # model depth multiple  模型层数因子(用来调整网络的深度)
width_multiple: 0.50  # layer channel multiple 模型通道数因子(用来调整网络的宽度)
 
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/2
   [-1, 1, Conv, [128, 3, 2]],  # 1-P2/4,通过该层之后特征图的大小变成原图的1/4
   [-1, 3, C3, [128]],          # 2,通过该层之后特征图的大小不变
   [-1, 1, Conv, [256, 3, 2]],  # 3-P3/8,过该层之后特征图的大小变成原图的1/8
   [-1, 6, C3, [256]],			# 4,通过该层之后特征图的大小不变
   [-1, 1, Conv, [512, 3, 2]],  # 5-P4/16,,过该层之后特征图的大小变成原图的1/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']], #11 不改变通道数,特征图的长和宽会增加一倍
   [[-1, 6], 1, Concat, [1]],  # 12 cat backbone P4 与第6层的输出进行特征图的融合
   [-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,与第4层的输出进行特征图的融合。
   [-1, 3, C3, [256, False]],  # 17 (P3/8-small)
 
   [-1, 1, Conv, [256, 3, 2]],
   [[-1, 14], 1, Concat, [1]],  # cat head P4,与第14层的输出进行特征图的融合
   [-1, 3, C3, [512, False]],  # 20 (P4/16-medium)
 
   [-1, 1, Conv, [512, 3, 2]],
   [[-1, 10], 1, Concat, [1]],  # cat head P5,与第10层的输出进行特征图的融合
   [-1, 3, C3, [1024, False]],  # 23 (P5/32-large)
 
   [[17, 20, 23], 1, Detect, [nc, anchors]],  # Detect(P3, P4, P5)
  ]

2.3、YOLOv5s网络结构图

在这里插入图片描述

2.4、YOLOv5l.yaml

# YOLOv5 🚀 by Ultralytics, GPL-3.0 license

# Parameters
nc: 80  # number of classes
depth_multiple: 1.0  # model depth multiple
width_multiple: 1.0  # layer channel multiple
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

# YOLOv5 v6.0 backbone
backbone:
  # [from, number, module, args]
  # 输入 640*640
  [[-1, 1, Conv, [64, 6, 2, 2]],  # 0-P1/2    64*320*320
   [-1, 1, Conv, [128, 3, 2]],  # 1-P2/4      128*160*160 
   [-1, 3, C3, [128]],
   [-1, 1, Conv, [256, 3, 2]],  # 3-P3/8      256*80*80
   [-1, 6, C3, [256]],
   [-1, 1, Conv, [512, 3, 2]],  # 5-P4/16     512*40*40
   [-1, 9, C3, [512]],
   [-1, 1, Conv, [1024, 3, 2]],  # 7-P5/32    1024*20*20
   [-1, 3, C3, [1024]],
   [-1, 1, SPPF, [1024, 5]],  # 9             1024*20*20
  ]

# YOLOv5 v6.0 head
head:
  [[-1, 1, Conv, [512, 1, 1]], #              512*20*20   
   [-1, 1, nn.Upsample, [None, 2, 'nearest']],#   512*40*40
   [[-1, 6], 1, Concat, [1]],  # cat backbone P4  1024*40*40
   [-1, 3, C3, [512, False]],  # 13               512*40*40

   [-1, 1, Conv, [256, 1, 1]],#                   256*40*40
   [-1, 1, nn.Upsample, [None, 2, 'nearest']], #  256*80*80
   [[-1, 4], 1, Concat, [1]],  # cat backbone P3  512*80*80
   [-1, 3, C3, [256, False]],  # 17 (P3/8-small)  256*80*80

   [-1, 1, Conv, [256, 3, 2]], #                 256*40*40
   [[-1, 14], 1, Concat, [1]],  # cat head P4    512*40*40
   [-1, 3, C3, [512, False]],  # 20 (P4/16-medium) 512*40*40

   [-1, 1, Conv, [512, 3, 2]], #                  512*20*20
   [[-1, 10], 1, Concat, [1]],  # cat head P5     1024*20*20
   [-1, 3, C3, [1024, False]],  # 23 (P5/32-large)  1024*20*20

   [[17, 20, 23], 1, Detect, [nc, anchors]],  # Detect(P3, P4, P5)
  ]


2.5、YOLOv5l 网络结构图

在这里插入图片描述

3、附件

在yolov5中有l,n,m,s,x,5种配置文件,这5种配置文件只是depth_multiple和width_multiple两个参数不同,其它部分都相同的。

3.1、yolov5s.yaml 解析表

  1. yolov5s.yaml的width_multiple都为0.50
  2. 举例:[[-1, 1, Conv, [64, 6, 2, 2]],当width_multiple为0.5时候,则输出通道为64*0.5=32通道
层数 from moudule arguments input output
0 -1 Conv [3, 32, 6, 2, 2] [3, 640, 640] [32, 320, 320]
1 -1 Conv [32, 64, 3, 2] [32, 320, 320] [64, 160, 160]
2 -1 C3 [64, 64, 1] [64, 160, 160] [64, 160, 160]
3 -1 Conv [64, 128, 3, 2] [64, 160, 160] [128, 80, 80]
4 -1 C3 [128, 128, 2] [128, 80, 80] [128, 80, 80]
5 -1 Conv [128, 256, 3, 2] [128, 80, 80] [256, 40, 40]
6 -1 C3 [256, 256, 3] [256, 40, 40] [256, 40, 40]
7 -1 Conv [256, 512, 3, 2] [256, 40, 40] [512, 20, 20]
8 -1 C3 [512, 512, 1] [512, 20, 20] [512, 20, 20]
9 -1 SPPF [512, 512, 5] [512, 20, 20] [512, 20, 20]
10 -1 Conv [512, 256, 1, 1] [512, 20, 20] [256, 20, 20]
11 -1 Upsample [None, 2, ‘nearest’] [256, 20, 20] [256, 40, 40]
12 [-1, 6] Concat [1] [1, 256, 40, 40],[1, 256, 40, 40] [512, 40, 40]
13 -1 C3 [512, 256, 1, False] [512, 40, 40] [256, 40, 40]
14 -1 Conv [256, 128, 1, 1] [256, 40, 40] [128, 40, 40]
15 -1 Upsample [None, 2, ‘nearest’] [128, 40, 40] [128, 80, 80]
16 [-1, 4] Concat [1] [1, 128, 80, 80],[1, 128, 80, 80] [256, 80, 80]
17 -1 C3 [256, 128, 1, False] [256, 80, 80] [128, 80, 80]
18 -1 Conv [128, 128, 3, 2] [128, 80, 80] [128, 40, 40]
19 [-1, 14] Concat [1] [1, 128, 40, 40],[1, 128, 40, 40] [256, 40, 40]
20 -1 C3 [256, 256, 1, False] [256, 40, 40] [256, 40, 40]
21 -1 Conv [256, 256, 3, 2] [256, 40, 40] [256, 20, 20]
22 [-1, 10] Concat [1] [1, 256, 20, 20],[1, 256, 20, 20] [512, 20, 20]
23 -1 C3 [512, 512, 1, False] [512, 20, 20] [512, 20, 20]
24 [17, 20, 23] Detect [80, [[10, 13, 16, 30, 33, 23], [30, 61, 62, 45, 59, 119], [116, 90, 156, 198, 373, 326]], [128, 256, 512]] [1, 128, 80, 80],[1, 256, 40, 40],[1, 512, 20, 20] [1, 3, 80, 80, 85],[1, 3, 40, 40, 85],[1, 3, 20, 20, 85]

3.2、 yolov5l.yaml 解析表

注:yolov5l.yaml的depth_multiple和width_multiple都为1

层数 from moudule arguments input output
0 -1 Conv [3, 64, 6, 2, 2] [3, 640, 640] [64, 320, 320]
1 -1 Conv [64, 128, 3, 2] [64, 320, 320] [128, 160, 160]
2 -1 C3 [128,128, 1] [128, 160, 160] [128 160, 160]
3 -1 Conv [128,256, 3, 2] [128 160, 160] [256, 80, 80]
4 -1 C3 [256,256, 2] [256, 80, 80] [256, 80, 80]
5 -1 Conv [256,512, 3, 2] [256, 80, 80] [512, 40, 40]
6 -1 C3 [512, 512, 3] [512, 40, 40] [512, 40, 40]
7 -1 Conv [512, 1024, 3, 2] [512, 40, 40] [1024, 20, 20]
8 -1 C3 [1024, 1024, 1] [1024, 20, 20] [1024, 20, 20]
9 -1 SPPF [1024, 1024, 5] [1024, 20, 20] [1024, 20, 20]
10 -1 Conv [1024,512, 1, 1] [1024, 20, 20] [512, 20, 20]
11 -1 Upsample [None, 2, ‘nearest’] [512, 20, 20] [512, 40, 40]
12 [-1, 6] Concat [512+512] [1, 512, 40, 40],[1, 512, 40, 40] [1024, 40, 40]
13 -1 C3 [1024,512, 1, False] [1024, 40, 40] [512, 40, 40]
14 -1 Conv [512,256, 1, 1] [512, 40, 40] [256, 40, 40]
15 -1 Upsample [None, 2, ‘nearest’] [256, 40, 40] [256, 80, 80]
16 [-1, 4] Concat [256+256] [1, 256, 80, 80],[1, 256, 80, 80] [512, 80, 80]
17 -1 C3 [512, 256, 1, False] [512, 80, 80] [256, 80, 80]
18 -1 Conv [256, 256, 3, 2] [256, 80, 80] [256, 40, 40]
19 [-1, 14] Concat [256+256] [1, 256, 40, 40],[1, 256, 40, 40] [512, 40, 40]
20 -1 C3 [512, 512, 1, False] [512, 40, 40] [512, 40, 40]
21 -1 Conv [512, 512, 3, 2] [512, 40, 40] [512, 20, 20]
22 [-1, 10] Concat [512+512] [1, 512, 20, 20],[1, 512, 20, 20] [1024 20, 20]
23 -1 C3 [1024,1024, 1, False] [1024, 20, 20] [1024, 20, 20]
24 [17, 20, 23] Detect [80, [[10, 13, 16, 30, 33, 23], [30, 61, 62, 45, 59, 119], [116, 90, 156, 198, 373, 326]], [128, 256, 512]] [1, 256, 80, 80],[1, 512, 40, 40],[1, 1024, 20, 20] [1, 3, 80, 80, 85],[1, 3, 40, 40, 85],[1, 3, 20, 20, 85]

4、总结

其实看懂代码,结合画的网络结构图,就很容易理解YOLO的模型。后续,将会介绍如何利用YOLOv5进行训练。

参考文章

  1. YOLOv5 模型结构及代码详细讲解
  2. YOLOv5-网络结构
  3. YOLOv5 Focus C3 各模块详解及代码实现

5、目标检测系列文章

  1. 生活垃圾数据集(YOLO版)
  2. YOLOv5如何训练自己的数据集
  3. 双向控制舵机(树莓派版)
  4. 树莓派部署YOLOv5目标检测(详细篇)
  5. YOLO_Tracking 实践 (环境搭建 & 案例测试)
  6. 目标检测:数据集划分 & XML数据集转YOLO标签
  7. YOLOv5改进–轻量化YOLOv5s模型
  8. DeepSort行人车辆识别系统(实现目标检测+跟踪+统计)
  9. YOLOv5目标检测优化点(添加小目标头检测)
  10. YOLOv5参数大全(parse_opt篇)
  11. YOLOv5改进策略:Focaler-IoU损失函数改进
Logo

加入「COC·上海城市开发者社区」,成就更好的自己!

更多推荐