yolov5源码--网络结构模块

该文详细解读了YOLOv5的网络配置文件,包括网络深度和通道参数的设置,以及如何通过Python代码进行模型构建和前向传播。文章重点讨论了Focus、BottleneckCSP等模块的功能,特征提取的过程,以及检测头的设计,强调了不同层次的特征图在检测不同大小目标中的作用。
摘要由CSDN通过智能技术生成

可视化

python models/export.py --weights ./weights/yolov5s.pt --img 640 --batch 1

在这里插入图片描述
使用onnx文件可视化
在这里插入图片描述

网络配置文件

在这里插入图片描述

depth_multiple: 0.33 # 模型网络深度参数(如果已经是1了就不做操作,只对非1的乘这个系数)
width_multiple: 0.50 # 模型channel参数
在这里插入图片描述
9就是堆叠BottleneckCSP的次数(网络深度)
512就是网络channel参数

在这里插入图片描述

  1. from 当前层的输入(-1表示由上一层的输出结果做为当前层的输入)
  2. number 当前层堆叠几次
  3. module 当前层的名字
  4. args 是channel数和卷积核的大小

网络结构解读

关于骨干网络前两个结构块,见我的这篇博文:
netron中的参数
在这里插入图片描述
实际上BottleneckCSP深度为1;channer为64
在这里插入图片描述
看onnx结构图中,只要把在这里插入图片描述
看成卷积+激活函数的组合操作,就很好的可以看懂onnx图了。

代码解读

在这里插入图片描述
首先读取网络结构配置文件yaml.
在这里插入图片描述
在这里插入图片描述

然后开始依据配置文件生成网络结构模型。
(使用函数parse_model来解析的)
在这里插入图片描述
parse_model解析网络架构的代码如下:
在这里插入图片描述
其输出参数如下:
在这里插入图片描述
(就是读取的yaml文件里面的内容)

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

将d中的数据读取出来:
gd是模型深度系数(堆叠次数)
gw是模型通道channer的系数
nc是类别个数
anchor是先验框的系数:在这里插入图片描述
na是anchor个数
no是:(类别数+5) × anchor个数

其中:

d['backbone'] + d['head']

的数据如下(就是从yaml的数据中一模一样读取过来的)

在这里插入图片描述
遍历backbone和head

for i, (f, n, m, args) in enumerate(d['backbone'] + d['head']):  # from, number, module, args

以第一次遍历为例:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
f、n、m、args、和在这里插入图片描述完全对应。
在这里插入图片描述

对应的Focus代码:
在这里插入图片描述
再回来,
对堆叠次数乘以系数gd,但最少也得1次
在这里插入图片描述
当前是Focus,在定义的模块里面。。
在这里插入图片描述
再继续:
在这里插入图片描述在这里插入图片描述
ch就是输入的channel在这里插入图片描述
f就是yaml文件里面写再第一位的那个-1
在这里插入图片描述
得到:

c1是输入channel,c2是输出channel

再将channel维度乘以系数

在这里插入图片描述
在这里插入图片描述
args的参数:输入channel,输出channel,卷积核大小
3,32,3
在这里插入图片描述
将Fcous模块添加进去:
在这里插入图片描述

Focus(
  (conv): Conv(
    (conv): Conv2d(12, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    (bn): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (act): Hardswish()
  )
)

将Fcous添加并计算参数
在这里插入图片描述
和控制台打印数据有关的参数:

m_.i, m_.f, m_.type, m_.np = i, f, t, np  # attach index, 'from' index, type, number params
logger.info('%3s%18s%3s%10.0f  %-40s%-30s' % (i, f, n, np, t, args))  # print

在这里插入图片描述
将当前层添加到layer里面
在这里插入图片描述
由开始第二层的遍历。。。。。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
其中2是步长,如果是1特征图大小不变,是2的话,特征图减半:在这里插入图片描述
。。。。。。
最后的结果:
在这里插入图片描述
初始化先验框和参数权重
在这里插入图片描述

前向传播

特征提取网络

定位到forward_once函数:
在这里插入图片描述
其中self.model就是之前定义的网络结构
在这里插入图片描述
对self.model进学校遍历:
在这里插入图片描述

第一个m是:

Focus(
  (conv): Conv(
    (conv): Conv2d(12, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    (bn): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (act): Hardswish()
  )
)

图像经过Focus的处理…
在这里插入图片描述
跳转到Focus:
在这里插入图片描述

  1. 先分块,再拼接,最后卷积
  2. 间隔来完成分块
  3. channel由3变为12(3x4)
  4. 为了加速
    在这里插入图片描述

x(b,c,w,h) -> y(b,4c,w/2,h/2)

其卷积为:
在这里插入图片描述

Conv(
  (conv): Conv2d(12, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
  (bn): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (act): Hardswish()
)

再回来。。。
到了第二个模块的遍历。。
在这里插入图片描述

Conv(
  (conv): Conv2d(32, 64, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
  (bn): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (act): Hardswish()
)

在这里插入图片描述
到三个模块的遍历
在这里插入图片描述

BottleneckCSP(
  (cv1): Conv(
    (conv): Conv2d(64, 32, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (bn): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (act): Hardswish()
  )
  (cv2): Conv2d(64, 32, kernel_size=(1, 1), stride=(1, 1), bias=False)
  (cv3): Conv2d(32, 32, kernel_size=(1, 1), stride=(1, 1), bias=False)
  (cv4): Conv(
    (conv): Conv2d(64, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)
    (bn): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (act): Hardswish()
  )
  (bn): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (act): LeakyReLU(negative_slope=0.1, inplace=True)
  (m): Sequential(
    (0): Bottleneck(
      (cv1): Conv(
        (conv): Conv2d(32, 32, kernel_size=(1, 1), stride=(1, 1), bias=False)
        (bn): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (act): Hardswish()
      )
      (cv2): Conv(
        (conv): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
        (bn): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
        (act): Hardswish()
      )
    )
  )
)

跳转到BottleneckCSP函数
在这里插入图片描述
在这里插入图片描述

y1是主分支的路径
y2是捷径分支的路径
最后return self.cv4(self.act(self.bn(torch.cat((y1, y2), dim=1))))就是concat拼接合并后的操作

在这里插入图片描述

在这里插入图片描述

  1. 结合了resnet模块
  2. 提升map
  3. 叠加个数=配置文件中的个数x深度系数

然后,到spp结构了:
在这里插入图片描述
1024为输出特征图channel
5,9,13为不同kernel核的池化
在这里插入图片描述
4. 第四个分支直接短路,然后拼接
5. 先卷积(cv1),再三池化一短路,最后卷积(cv2)
6. 第一个cv1卷积为了降维(之后拼接就升回来了)
7.

在这里插入图片描述

ModuleList(
  (0): MaxPool2d(kernel_size=5, stride=1, padding=2, dilation=1, ceil_mode=False)
  (1): MaxPool2d(kernel_size=9, stride=1, padding=4, dilation=1, ceil_mode=False)
  (2): MaxPool2d(kernel_size=13, stride=1, padding=6, dilation=1, ceil_mode=False)
)

不同的操作,最后得到的图中图大小是一样的,以便完成拼接操作
输出特征图计算公司如下:
在这里插入图片描述
例如(300-5+2x2)/1 +1 =300
(300-9+2x4)/1 +1 = 300特征图不会变化。。
在这里插入图片描述
channel输入是256,输出是256x4=1024,卷积再降维到512…、、

带上卷积操作:
在这里插入图片描述
在这里插入图片描述

整体的结构为:
(卷积后的那一些乘除加是hardswish激活函数的计算过程)
在这里插入图片描述

特征融合网络

在这里插入图片描述
在这里插入图片描述

深层网络的特征图感受野大-检测大目标
浅层网络的特征图感受野小-检测小目标

第一个模块中的卷积模块如下:
(i=11的那一层卷积操作)(第11层)
在这里插入图片描述
在这里插入图片描述

上采用模块(第12层)
在这里插入图片描述
特征拼接模块(第13层)
在这里插入图片描述
在这里插入图片描述
看到,yaml文件中的:
[[-1, 6], 1, Concat, [1]], # cat backbone P4
6,表示和第六层的拼接,其特征层维度一样。

torch.Size([1, 256, 8, 8])concat torch.Size([1, 256, 8, 8])

在这里插入图片描述
在这里插入图片描述


开始第二个卷积模块:
在这里插入图片描述
这里的拼接是和第四层进行concat的
在这里插入图片描述
在这里插入图片描述
上采样输出的结果就是16层的特征图
和第四层的拼接就是17层的输出维度

层数: 4 特征图大小: torch.Size([1, 128, 16, 16])
层数: 16 特征图大小: torch.Size([1, 128, 16, 16])
特征图拼接后:
层数: 17 特征图大小: torch.Size([1, 256, 16, 16])

在这里插入图片描述


开始第三个卷积模块
在这里插入图片描述
在这里插入图片描述
其concat是拼接第14个层结构。
在这里插入图片描述
在这里插入图片描述


第四个卷积块的concat
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
拼接前是22层输出的大小
拼接后是23层输出的大小
在这里插入图片描述

检测头

在这里插入图片描述

在这里插入图片描述

na是anchor的个数
nc是类别个数
5=4+1(位置预测+置信度)
具体的大图见pdf.

在这里插入图片描述
在这里插入图片描述

Detect(
  (m): ModuleList(
    (0): Conv2d(128, 21, kernel_size=(1, 1), stride=(1, 1))
    (1): Conv2d(256, 21, kernel_size=(1, 1), stride=(1, 1))
    (2): Conv2d(512, 21, kernel_size=(1, 1), stride=(1, 1))
  )
)

将17层、20层、23层的进行检测头操作(1x1卷积)。

输出的通道数channel: 21 = 3x(2+5)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值