YOLOv5中的CSP结构

深度学习入门小菜鸟,希望像做笔记记录自己学的东西,也希望能帮助到同样入门的人,更希望大佬们帮忙纠错啦~侵权立删。

一、背景知识 — CSPNet

有关CSPNet的介绍分析可以康康博主之前的博客

深度学习之CSPNet分析_tt丫的博客-CSDN博客

二、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)哈,之前没注意它的名称变化。)

YOLOv5中的CSP结构

将输入分为两个分支,一个分支先通过CBS,再经过多个残差结构(Bottleneck * N),再进行一次卷积;另一个分支直接进行卷积;然后两个分支进行concat,再经过BN(正态分布),再来一次激活(之前的版本是Leaky,后期是SiLU),最后进行一个CBS。

🌳C3的网络结构图如下图所示:

YOLOv5中的CSP结构

CSP1_X应用于backbone主干网络部分(backbone具体介绍以后再说哒),backbone是较深的网络,增加残差结构可以增加层与层之间反向传播的梯度值,避免因为加深而带来的梯度消失,从而可以提取到更细粒度的特征并且不用担心网络退化。

3、CSP2_X结构(BottleneckCSP和C3均有分析)

🌳BottleneckCSP的网络结构图如图所示

YOLOv5中的CSP结构

🌳C3的网络结构图如图所示

YOLOv5中的CSP结构

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

欢迎大家在评论区批评指正,谢谢大家~

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
xiaoxingxing的头像xiaoxingxing管理团队
上一篇 2023年2月23日
下一篇 2023年2月23日

相关推荐