CV 经典主干网络 (Backbone) 系列: CSP-Darknet53

2023-11-18

0. 引言

CSP-Darknet53无论是其作为CV Backbone,还是说它在别的数据集上取得极好的效果。与此同时,它与别的网络的适配能力极强。这些特点都在宣告:CSP-Darknet53的重要性。
关于原理部分的内容请查看这里CV 经典主干网络 (Backbone) 系列: CSPNet

1. 网络结构图

具体网络结构可以参考YOLO V3详解(一):网络结构介绍中使用的工具来进行操作。具体网址和对应的权重文件下载地址如下:
模型可视化工具:https://lutzroeder.github.io/netron/
cfg文件下载网址:https://github.com/WongKinYiu/CrossStagePartialNetworks

得到的部分网络结构图的如下所示。

1.1 输入部分

在这里插入图片描述

1.2 CSP部分结构

在这里插入图片描述

1.3 输出部分

在这里插入图片描述

2. 代码实现

2.1 代码整体实现

通过代码实现CSP-Darknet53。框架为PyTorch,代码整体框架实现如下所示:

class CsDarkNet53(nn.Module):
    def __init__(self, num_classes):
        super(CsDarkNet53, self).__init__()

        input_channels = 32

        # Network
        self.stage1 = Conv2dBatchLeaky(3, input_channels, 3, 1, activation='mish')
        self.stage2 = Stage2(input_channels)
        self.stage3 = Stage3(4*input_channels)
        self.stage4 = Stage(4*input_channels, 8)
        self.stage5 = Stage(8*input_channels, 8)
        self.stage6 = Stage(16*input_channels, 4)

        self.conv = Conv2dBatchLeaky(32*input_channels, 32*input_channels, 1, 1, activation='mish')
        self.avgpool = nn.AdaptiveAvgPool2d((1,1))
        self.fc = nn.Linear(1024, num_classes)

        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
            elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):
                nn.init.constant_(m.weight, 1)
                nn.init.constant_(m.bias, 0)

    def forward(self, x):
        stage1 = self.stage1(x)
        stage2 = self.stage2(stage1)
        stage3 = self.stage3(stage2)
        stage4 = self.stage4(stage3)
        stage5 = self.stage5(stage4)
        stage6 = self.stage6(stage5)

        conv = self.conv(stage6)
        x = self.avgpool(conv)
        x = x.view(-1, 1024)
        x = self.fc(x)

        return x

2.2 代码各个阶段实现

在代码中,对各个阶段的具体实现如下所示:

class Mish(nn.Module):
    def __init__(self):
        super(Mish, self).__init__()

    def forward(self, x):
        return x * torch.tanh(F.softplus(x))

class Conv2dBatchLeaky(nn.Module):
    """
    This convenience layer groups a 2D convolution, a batchnorm and a leaky ReLU.
    """
    def __init__(self, in_channels, out_channels, kernel_size, stride, activation='leaky', leaky_slope=0.1):
        super(Conv2dBatchLeaky, self).__init__()

        # Parameters
        self.in_channels = in_channels
        self.out_channels = out_channels
        self.kernel_size = kernel_size
        self.stride = stride
        if isinstance(kernel_size, (list, tuple)):
            self.padding = [int(k/2) for k in kernel_size]
        else:
            self.padding = int(kernel_size/2)
        self.leaky_slope = leaky_slope
        # self.mish = Mish()

        # Layer
        if activation == "leaky":
            self.layers = nn.Sequential(
                nn.Conv2d(self.in_channels, self.out_channels, self.kernel_size, self.stride, self.padding, bias=False),
                nn.BatchNorm2d(self.out_channels),
                nn.LeakyReLU(self.leaky_slope, inplace=True)
            )
        elif activation == "mish":
            self.layers = nn.Sequential(
                nn.Conv2d(self.in_channels, self.out_channels, self.kernel_size, self.stride, self.padding, bias=False),
                nn.BatchNorm2d(self.out_channels),
                Mish()
            )
        elif activation == "linear":
            self.layers = nn.Sequential(
                nn.Conv2d(self.in_channels, self.out_channels, self.kernel_size, self.stride, self.padding, bias=False)
            )

    def __repr__(self):
        s = '{name} ({in_channels}, {out_channels}, kernel_size={kernel_size}, stride={stride}, padding={padding}, negative_slope={leaky_slope})'
        return s.format(name=self.__class__.__name__, **self.__dict__)

    def forward(self, x):
        x = self.layers(x)
        return x

class SmallBlock(nn.Module):

    def __init__(self, nchannels):
        super().__init__()
        self.features = nn.Sequential(
            Conv2dBatchLeaky(nchannels, nchannels, 1, 1, activation='mish'),
            Conv2dBatchLeaky(nchannels, nchannels, 3, 1, activation='mish')
        )
        # conv_shortcut
        '''
        参考 https://github.com/bubbliiiing/yolov4-pytorch
        shortcut后不接任何conv
        '''
        # self.active_linear = Conv2dBatchLeaky(nchannels, nchannels, 1, 1, activation='linear')
        # self.conv_shortcut = Conv2dBatchLeaky(nchannels, nchannels, 1, 1, activation='mish')


    def forward(self, data):
        short_cut = data + self.features(data)
        # active_linear = self.conv_shortcut(short_cut)

        return short_cut

# Stage1  conv [256,256,3]->[256,256,32]

class Stage2(nn.Module):

    def __init__(self, nchannels):
        super().__init__()
        # stage2 32
        self.conv1 = Conv2dBatchLeaky(nchannels, 2*nchannels, 3, 2, activation='mish')
        self.split0 = Conv2dBatchLeaky(2*nchannels, 2*nchannels, 1, 1, activation='mish')
        self.split1 = Conv2dBatchLeaky(2*nchannels, 2*nchannels, 1, 1, activation='mish')

        self.conv2 = Conv2dBatchLeaky(2*nchannels, nchannels, 1, 1, activation='mish')
        self.conv3 = Conv2dBatchLeaky(nchannels, 2*nchannels, 3, 1, activation='mish')

        self.conv4 = Conv2dBatchLeaky(2*nchannels, 2*nchannels, 1, 1, activation='mish')


    def forward(self, data):
        conv1 = self.conv1(data)
        split0 = self.split0(conv1)
        split1 = self.split1(conv1)
        conv2 = self.conv2(split1)
        conv3 = self.conv3(conv2)

        shortcut = split1 + conv3
        conv4 = self.conv4(shortcut)

        route = torch.cat([split0, conv4], dim=1)
        return route

class Stage3(nn.Module):
    def __init__(self, nchannels):
        super().__init__()
        # stage3 128
        self.conv1 = Conv2dBatchLeaky(nchannels, int(nchannels/2), 1, 1, activation='mish')
        self.conv2 = Conv2dBatchLeaky(int(nchannels/2), nchannels, 3, 2, activation='mish')

        self.split0 = Conv2dBatchLeaky(nchannels, int(nchannels/2), 1, 1, activation='mish')
        self.split1 = Conv2dBatchLeaky(nchannels, int(nchannels/2), 1, 1, activation='mish')

        self.block1 = SmallBlock(int(nchannels/2))
        self.block2 = SmallBlock(int(nchannels/2))

        self.conv3 = Conv2dBatchLeaky(int(nchannels/2), int(nchannels/2), 1, 1, activation='mish')

    def forward(self, data):
        conv1 = self.conv1(data)
        conv2 = self.conv2(conv1)

        split0 = self.split0(conv2)
        split1 = self.split1(conv2)

        block1 = self.block1(split1)
        block2 = self.block2(block1)

        conv3 = self.conv3(block2)

        route = torch.cat([split0, conv3], dim=1)

        return route

# Stage4 Stage5 Stage6
class Stage(nn.Module):
    def __init__(self, nchannels, nblocks):
        super().__init__()
        # stage4 : 128
        # stage5 : 256
        # stage6 : 512
        self.conv1 = Conv2dBatchLeaky(nchannels, nchannels, 1, 1, activation='mish')
        self.conv2 = Conv2dBatchLeaky(nchannels, 2*nchannels, 3, 2, activation='mish')
        self.split0 = Conv2dBatchLeaky(2*nchannels, nchannels, 1, 1, activation='mish')
        self.split1 = Conv2dBatchLeaky(2*nchannels, nchannels, 1, 1, activation='mish')
        blocks = []
        for i in range(nblocks):
            blocks.append(SmallBlock(nchannels))
        self.blocks = nn.Sequential(*blocks)
        self.conv4 = Conv2dBatchLeaky(nchannels, nchannels, 1, 1, activation='mish')

    def forward(self,data):
        conv1 = self.conv1(data)
        conv2 = self.conv2(conv1)

        split0 = self.split0(conv2)
        split1 = self.split1(conv2)
        blocks = self.blocks(split1)
        conv4 = self.conv4(blocks)
        route = torch.cat([split0, conv4], dim=1)

        return route

3. 代码测试

下面使用一个小例子来对代码进行测试。

if __name__ == "__main__":
    use_cuda = torch.cuda.is_available()
    if use_cuda:
        device = torch.device("cuda")
        cudnn.benchmark = True
    else:
        device = torch.device("cpu")

    darknet = CsDarkNet53(num_classes=10)
    darknet = darknet.cuda()
    with torch.no_grad():
        darknet.eval()
        data = torch.rand(1, 3, 256, 256)
        data = data.cuda()
        try:
            #print(darknet)
            summary(darknet,(3,256,256))
            print(darknet(data))
        except Exception as e:
            print(e)

代码的输出如下所示:

Total params: 26,627,434
Trainable params: 26,627,434
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.75
Forward/backward pass size (MB): 553.51
Params size (MB): 101.58
Estimated Total Size (MB): 655.83
----------------------------------------------------------------
tensor([[ 0.1690,  0.0798,  0.1836,  0.2414,  0.3855,  0.2437, -0.1422, -0.1855,
          0.1758, -0.2452]], device='cuda:0')

注意:输出中存在框架结构内容,这里没有将其写在博客中

4. 结论

CSP-Darknet53的代码结构结合着对应的代码实现一起看,可以有效帮助大家理解关于原理部分的内容。希望可以帮助到大家!!!
另外,关于代码中存在的一些小的部分可能会在后面进行介绍。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CV 经典主干网络 (Backbone) 系列: CSP-Darknet53 的相关文章

随机推荐

  • 西门子PLC S7-1200程序实例 西门子1200与安川机器人TCP/IP通讯,包含机器人GSD文件

    西门子PLC S7 1200程序实例 博图版本V15 仅供电气编程者学习借鉴 1 西门子1200与安川机器人TCP IP通讯 包含机器人GSD文件 2 西门子1200控制6轴伺服电机 四台台脉冲控制台达B2伺服 两台PN通讯控制西门子V90
  • Python 新手入门学习教程、第三方库以及开发工具整合(持续更新)

    目录 一 学习教程 1 python 系统学习教程 python 菜鸟教程 真的挺全面 接口讲解比较全面且有例子参考 通俗易懂 入门必备 2 python api接口文档 官方 python api接口标准库 所有的api接口解释非常详细
  • 算法学习之二分查找

    个人主页 勇敢的小牛儿 推荐专栏 C语言知识点 座右铭 敢于尝试才有机会 今日鸡汤 Is the true wisdom fortitude ambition Napoleon 真正的才智是刚毅的志向 拿破仑 目录 一 二分查找法介绍 二
  • JAVA单元测试框架-13-TestNG中的Listener监听

    使用TestNG中的Listener完成监听测试 通过实现ITestListener里面的方法完成测试过程监听 public class TestListenner implements ITestListener Override pub
  • 浮点数转化为字符串存进数组模块分享(自动保留到小数点后一位)

    目录 一 使用说明 二 模块代码 三 代码讲解 四 作者的话 一 使用说明 1 数据格式 浮点数可以为整数部分不超过3位的所有浮点数 数组格式只能设置为下面这一种 unsigned char fnums 5 0 a 0 用于存放正负 1表示
  • 面向对象编程是什么意思呢?汇总

    https blog csdn net qq 32381815 article details 79119996 面向对象思想 谈谈你对面向对象的理解 https blog csdn net qsbbl article details 71
  • Altium Designer20快捷键整理合集

    花了点时间整理了一下平常经常用到的一些AD20的快捷键操作 自用可取 经过验证均可用 原理图 PCB通用快捷键 保存 CTRL S 打开 CTRL O 关闭 CTRL F4 打印 CTRL P 退出 ALT F4 项目打包 C P 文档切换
  • UnrealEngine4初始设置及个人使用崩溃记录

    日志 1 第一次记录 2020 2 05 版本 4 24 2 UnrealEngine的初始设置 1 在Epic中下载UnrealEngine4之后 1 1 首先 启动 选项 1 2 接着 勾选 输入调试用符号 应用 以后出现新的崩溃问题
  • vue3中如何循环本地图片

  • eNSP实验:DHCP&&安全区域&&安全策略&&静态路由

    解题思路 1 先给各个接口以及server1服务器配置好地址 2 连接Cloud云 利用物理 web 防火墙 方便操作 只用命令行的情况下可以不用这个方法 3 利用DHCP给各个方向接口的PC自动分配好地址 4 利用静态路由的方法 将两个防
  • VimFoundation

    模式 vim 分为两种模式 1 命令模式 2 编辑模式 命令模式 i 进入编辑模式 w 保存 q 退出 强制 syntax on 打开语法高亮 set number 显示行号 cc 剪切当前行 pp 粘贴到当前行 u 撤销3武器3 yy 复
  • 开源大模型资料总结

    基本只关注开源大模型资料 非开源就不关注了 意义也不大 基座大模型 LLaMA 7 13 33 65B 1 4T token LLaMA及其子孙模型概述 知乎 GLM 6 130B ChatGLM基座 GLM General Languag
  • C++基础知识 - stack容器

    stack容器 stack是堆栈容器 是一种 先进后出 的容器 stack是基于deque容器而实现的容器 include lt stack gt stack对象的默认构造 stack采用模板类实现 stack对象的默认构造形式 stack
  • 金三银四必备,全面总结 Kotlin 面试知识点

    作者 彭旭锐 前言 在 Android 面试中很重视基础知识的考察 其中语言基础主要包括 Java Kotlin C C 三种编程语言 在小彭面试的经验中 发现很多同学的 Kotlin 语言能力只是停留在一些非常入门的语法使用上 在这篇文章
  • 如何让ChatGPT写情书(三步走)

    近年来 人工智能技术的迅猛发展给我们生活带来了许多便利和惊喜 而动人的情书文学也逐渐成为ChatGPT技术的应用领域之一 ChatGPT模型是一种递归神经网络 可以在大量数据的基础上为用户生成语言内容 使用GPT来写情书 相比以前的纯手工撰
  • python详细安装教程(配置环境变量)

    python安装教程 配置环境变量 人生苦短 我用python 直接在官网下载安装包 msi文件进行安装 https www python org downloads windows 下载python 注意 浏览器左下角下载 点击后 会自动
  • conda和pip 安装python依赖包区别和使用技巧

    引言 Conda 作为一种跨平台的包和虚拟环境管理器 使用的时候功能与pip类似 安装python依赖包的时候经常将两种方法混合使用 但一直没有进行具体区分其差别 重新安装python依赖包的时候出现各种不兼容的bug 经历一天烦躁的安装
  • 你不知道的 script 标签的 defer 与 async 属性

    我持续组织了近一年的源码共读活动 感兴趣的可以 点此扫码加我微信 ruochuan12 参与 每周大家一起学习200行左右的源码 共同进步 同时极力推荐订阅我写的 学习源码整体架构系列 包含20余篇源码文章 历史面试系列 另外 目前建有江西
  • 4G路由器设置

    总共分四步如下图所示 1 用网线连接电脑 2 给路由器上电 3 设置电脑网络 如图打开电脑网络和共享数据中心选中本地连接双击 弹出如下图所示弹框选择图中ipv4双击 根据下面图片配置ip地址 4 浏览器上输入地址访问路由器进行配置 第一步
  • CV 经典主干网络 (Backbone) 系列: CSP-Darknet53

    CSP Darknet53 0 引言 1 网络结构图 1 1 输入部分 1 2 CSP部分结构 1 3 输出部分 2 代码实现 2 1 代码整体实现 2 2 代码各个阶段实现 3 代码测试 4 结论 0 引言 CSP Darknet53无论