深度学习入门小菜鸟,希望像做笔记记录自己学的东西,也希望能帮助到同样入门的人,更希望大佬们帮忙纠错啦~侵权立删。
目录
一、背景知识 -- CSPNet
二、CSP结构分析
1、总括
2、CSP1_X结构(BottleneckCSP和C3均有分析)
3、CSP2_X结构(BottleneckCSP和C3均有分析)
三、源码分析(内含注释分析)
1、BottleneckCSP部分
2、C3部分
有关CSPNet的介绍分析可以康康博主之前的博客
深度学习之CSPNet分析_tt丫的博客-CSDN博客
YOLOv5s的CSP结构是将原输入分成两个分支,分别进行卷积操作使得通道数减半,然后一个分支进行Bottleneck * N操作,然后concat两个分支,使得BottlenneckCSP的输入与输出是一样的大小,这样是为了让模型学习到更多的特征。
YOLOv5中的CSP有两种设计,分别为CSP1_X结构和CSP2_X结构。
BottleneckCSP的网络结构图如下图所示:
【(1)其中CBL为Conv+BN+SiLu,代码解析等详见往期博客YOLOv5中的Focus层详解_tt丫的博客-CSDN博客中的代码分析部分。
(2)其中Resunit是x个残差组件,相关介绍详见往期博客详解YOLOv5中的Bottleneck_tt丫的博客-CSDN博客】
将输入分为两个分支,一个分支先通过CBL,再经过多个残差结构(Bottleneck * N),再进行一次卷积;另一个分支直接进行卷积;然后两个分支进行concat,再经过BN(正态分布),再来一次激活(之前的版本是Leaky,后期是SiLU),最后进行一个CBL。
C3的网络结构图如下图所示:
CSP1_X应用于backbone主干网络部分(backbone具体介绍以后再说哒),backbone是较深的网络,增加残差结构可以增加层与层之间反向传播的梯度值,避免因为加深而带来的梯度消失,从而可以提取到更细粒度的特征并且不用担心网络退化。
BottleneckCSP的网络结构图如图所示
C3的网络结构图如图所示
CSP2_X相对于CSP1_X来说,不一样的地方只有CSP2_X将Resunit换成了2 * X个CBL,主要应用在Neck网络 (网络没那么深)。
(同样的,之前的版本是Leaky,后期是SiLU)
每一部分对应网络结构中的哪一部分都有标注如下
(其中Bottleneck类的分析见博客详解YOLOv5中的Bottleneck_tt丫的博客-CSDN博客)
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
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
欢迎大家在评论区批评指正,谢谢大家~