YOLOv5中的CSP结构
深度学习入门小菜鸟,希望像做笔记记录自己学的东西,也希望能帮助到同样入门的人,更希望大佬们帮忙纠错啦~侵权立删。
一、背景知识 -- CSPNet
有关CSPNet的介绍分析可以康康博主之前的博客
二、CSP结构分析
1、总括
YOLOv5s的CSP结构是将原输入分成两个分支,分别进行卷积操作使得通道数减半,然后一个分支进行Bottleneck * N操作,然后concat两个分支,使得BottlenneckCSP的输入与输出是一样的大小,这样是为了让模型学习到更多的特征。
YOLOv5中的CSP有两种设计,分别为CSP1_X结构和CSP2_X结构。
2、CSP1_X结构(BottleneckCSP和C3均有分析)
🌳BottleneckCSP的网络结构图如下图所示:
【(1)其中CBS为Conv+BN+SiLu,代码解析等详见往期博客YOLOv5中的Focus层详解_tt丫的博客-CSDN博客中的代码分析部分。
(2)其中Resunit是x个残差组件,相关介绍详见往期博客详解YOLOv5中的Bottleneck_tt丫的博客-CSDN博客】
(后面的图都是CBL(conv+BN+Leaky relu)改成CBS(conv+BN+SiLU)哈,之前没注意它的名称变化。)
将输入分为两个分支,一个分支先通过CBS,再经过多个残差结构(Bottleneck * N),再进行一次卷积;另一个分支直接进行卷积;然后两个分支进行concat,再经过BN(正态分布),再来一次激活(之前的版本是Leaky,后期是SiLU),最后进行一个CBS。
🌳C3的网络结构图如下图所示:
CSP1_X应用于backbone主干网络部分(backbone具体介绍以后再说哒),backbone是较深的网络,增加残差结构可以增加层与层之间反向传播的梯度值,避免因为加深而带来的梯度消失,从而可以提取到更细粒度的特征并且不用担心网络退化。
3、CSP2_X结构(BottleneckCSP和C3均有分析)
🌳BottleneckCSP的网络结构图如图所示
🌳C3的网络结构图如图所示
CSP2_X相对于CSP1_X来说,不一样的地方只有CSP2_X将Resunit换成了2 * X个CBS,主要应用在Neck网络 (网络没那么深)。
(同样的,之前的版本是Leaky,后期是SiLU)
三、源码分析(内含注释分析)
每一部分对应网络结构中的哪一部分都有标注如下
(其中Bottleneck类的分析见博客详解YOLOv5中的Bottleneck_tt丫的博客-CSDN博客)
1、BottleneckCSP部分
class BottleneckCSP(nn.Module):
#CSP结构
def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion
super().__init__()
c_ = int(c2 * e) # hidden channels
self.cv1 = Conv(c1, c_, 1, 1)#对应上面网络结构图的上面的分支的第一个CBL
self.cv2 = nn.Conv2d(c1, c_, 1, 1, bias=False)#对应上面网络结构图的下面的分支的conv
self.cv3 = nn.Conv2d(c_, c_, 1, 1, bias=False)#对应上面网络结构图的上面的分支的conv
self.cv4 = Conv(2 * c_, c2, 1, 1)#对应最后的CBL
self.bn = nn.BatchNorm2d(2 * c_) # applied to cat(cv2, cv3)
self.act = nn.SiLU()#对应Concat后的Leaky ReLU,这里看到后期的版本是改成了SiLU
self.m = nn.Sequential(*(Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)))
#nn.Sequential--序贯模型是函数式模型的简略版,为最简单的线性、从头到尾的结构顺序,不分叉,是多个网络层的线性堆叠。
#self.m对应X个Resunit or 2 * X个CBL(对应的切换是通过Bottleneck类中的True 或 False决定,True为X个Resunit,False为2 * X个CBL)
def forward(self, x):
y1 = self.cv3(self.m(self.cv1(x)))#对应上面网络结构图的上面的分支
y2 = self.cv2(x)#对应上面网络结构图的下面的分支
return self.cv4(self.act(self.bn(torch.cat((y1, y2), dim=1))))
#torch.cat对应Concat
#self.bn对应Concat后的BN
2、C3部分
class C3(nn.Module):
# CSP Bottleneck with 3 convolutions
def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion
super().__init__()
c_ = int(c2 * e) # hidden channels
self.cv1 = Conv(c1, c_, 1, 1)#对应上面网络结构图的上面的分支的第一个CBL
self.cv2 = Conv(c1, c_, 1, 1)#对应上面网络结构图的下面的分支的CBL
self.cv3 = Conv(2 * c_, c2, 1)#对应最后的CBL
self.m = nn.Sequential(*(Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)))
# self.m = nn.Sequential(*[CrossConv(c_, c_, 3, 1, g, 1.0, shortcut) for _ in range(n)])
#self.m对应X个Resunit or 2 * X个CBL(对应的切换是通过Bottleneck类中的True 或 False决定,True为X个Resunit,False为2 * X个CBL)
def forward(self, x):
return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), dim=1))
#torch.cat对应Concat
欢迎大家在评论区批评指正,谢谢大家~
相关文章
- 容器编排工具鉴赏- docker-compose 、Kubernetes、OpenShift、Docker Swarm
- Docker 搭建 Nexus3 私服 | 基本操作
- 微服务Docker打包
- 微服务网关Gateway实践总结
- Docker仓库管理镜像 -- 公共仓库【Docker Hub】和私人仓库【Registry】和【harbor】
- Spring框架中使用了哪些设计模式及应用场景
- 2022-8-30 servlet
- Get请求使用请求体传递参数会报400异常的问题
- 线程池中的一个 BUG,注意了!!
- 2022-8-29 javaweb 第一天 servlet/tomcat
- 如何使用(扫描)二维码进行登录
- Mac系统下Datagrip打不开、点击没反应?
- Java synchronized锁升级过程验证
- AOP面向切面编程简单介绍与应用
- Java---Stream入门
- 聊聊动态线程池的9个场景
- 历时2月,动态线程池 DynamicTp 发布里程碑版本 V1.0.8
- Docker也疯狂,微服务一键打包部署
- 面试手撕并发算法题
- 异步线程里的日志不好追踪?小支一招,轻松搞定!