首页 > 其他分享 >CSPNet跨阶段局部网络方法

CSPNet跨阶段局部网络方法

时间:2023-11-29 15:46:57浏览次数:51  
标签:BasicConv nn 局部 网络 残差 channels CSPNet self out

CSPNet跨阶段局部网络方法

目录

论文地址:https://arxiv.org/pdf/1911.11929.pdf

背景和问题

  • 随着卷积神经网络结构变得更深更宽,扩展神经网络的体系结构通常会带来更多的计算
  • 轻量级网络,MobileNetv1/v2/v3ShuffleNetv1/v2 采用了深度可分离卷积 技术与工业芯片设计不兼容

网络优化中的「重复梯度信息」。CSPNet 通过整合网络阶段开始和结束的特征图来注重梯度的可变性

CSPNet不仅仅是一个网络,更是一个处理思想,可以和ResNet、ResNext、DenseNet、EfficientNet等网络结合,使得上诉网络可以部署在 cpu 和移动 gpu 上,而不会牺牲性能。

主要解决问题

  1. 增强 CNN 的学习能力,能够在轻量化的同时保持准确性。
  2. 降低计算瓶颈和 DenseNet 的梯度信息重复。
  3. 降低内存成本。

网络结构

img

通过将基础层的特征图划分为两个部分 \(x = [x_0^,,x_0^{,,}]\) 其中一个直接连接到网络的最后面,一个通过dense block进行传递。

CSPDenseNet 的一个阶段是由局部密集块和局部过渡层组成a partial dense block and a partial transition layer

主要保留了 DenseNet 重用特征特性,但同时通过截断梯度流防止了过多的重复梯度信息。

采用的是一种分层的特殊融合的策略,并应用于局部过渡层(partial transition layer)。

设计局部密集块(partial dense block)的目的

  • 增加梯度路径: 通过分块归并策略,可以使梯度路径的数量增加一倍。由于采用了跨阶段策略,可以减轻使用显式特征图 copy 进行拼接所带来的弊端
  • 每一层的平衡计算: 通常,DenseNet 基层的通道数远大于生长速率。由于在局部稠密块中,参与密集层操作的基础层通道仅占原始数据的一半
  • 减少内存流量: 假设 DenseNet 中一个密集块的基本特征图大小为 \(w × h × c\),增长率为 \(d\) ,共有 \(m\) 个密集块。则该密集块的 CIO为 \((c × m)+(m^2+m)/2\) ,而局部密集块(partial dense block)的 CIO为 \([(c × m)+(m^2+m)]/2\)

特征融合策略

img

Transition layer,是一个 1x1 的卷积层,过渡层。上图中 transition layer 的位置决定了梯度的结构方式,并且各有优势:

  • (a) 图 为原始的DenseNet的特征融合

  • (c) 图 Fusion First 方式,先将两个部分进行 concatenate,然后再进行输入到 Transion layer 中,采用这种做法会是的大量特梯度信息被重用,有利于网络学习;

  • (d) 图 Fusion Last 的方式,先将部分特征输入 Transition layer,然后再进行concatenate,这样梯度信息将被截断,损失了部分的梯度重用,但是由于 Transition 的输入维度比(c)图少,大大减少了计算复杂度。

  • (b) 图中的结构是论文 CSPNet 所采用的,其结合了 (c)、(d) 的特点,提升了学习能力的同时也提高了一些计算复杂度。

CSPnet代码结构

import math
from collections import OrderedDict

import torch
import torch.nn as nn
import torch.nn.functional as F

#---------------------------------------------------#
#   卷积块 -> 卷积 + 标准化 + 激活函数
#   Conv2d + BatchNormalization + Mish
#---------------------------------------------------#
class BasicConv(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size, stride=1):
        super(BasicConv, self).__init__()

        self.conv = nn.Conv2d(in_channels, out_channels, kernel_size, stride, kernel_size//2, bias=False)
        self.bn = nn.BatchNorm2d(out_channels)
        self.activation = nn.Mish()    #  MISH激活函数

    def forward(self, x):
        x = self.conv(x)
        x = self.bn(x)
        x = self.activation(x)
        return x

#---------------------------------------------------#
#   CSPdarknet的结构块的组成部分
#   内部堆叠的残差块
#---------------------------------------------------#
class Resblock(nn.Module):
    def __init__(self, channels, hidden_channels=None):
        super(Resblock, self).__init__()

        if hidden_channels is None:
            hidden_channels = channels

        self.block = nn.Sequential(
            BasicConv(channels, hidden_channels, 1),
            BasicConv(hidden_channels, channels, 3)
        )

    def forward(self, x):
        return x + self.block(x)

#--------------------------------------------------------------------#
#   CSPdarknet的结构块
#   首先利用ZeroPadding2D和一个步长为2x2的卷积块进行高和宽的压缩
#   然后建立一个大的残差边shortconv、这个大残差边绕过了很多的残差结构
#   主干部分会对num_blocks进行循环,循环内部是残差结构。
#   对于整个CSPdarknet的结构块,就是一个大残差块+内部多个小残差块
#--------------------------------------------------------------------#
class Resblock_body(nn.Module):
    def __init__(self, in_channels, out_channels, num_blocks, first):
        super(Resblock_body, self).__init__()
        #----------------------------------------------------------------#
        #   利用一个步长为2x2的卷积块进行高和宽的压缩
        #----------------------------------------------------------------#
        self.downsample_conv = BasicConv(in_channels, out_channels, 3, stride=2)

        if first:
            #--------------------------------------------------------------------------#
            #   然后建立一个大的残差边self.split_conv0、这个大残差边绕过了很多的残差结构
            #--------------------------------------------------------------------------#
            self.split_conv0 = BasicConv(out_channels, out_channels, 1)

            #----------------------------------------------------------------#
            #   主干部分会对num_blocks进行循环,循环内部是残差结构。
            #----------------------------------------------------------------#
            self.split_conv1 = BasicConv(out_channels, out_channels, 1)
            self.blocks_conv = nn.Sequential(
                Resblock(channels=out_channels, hidden_channels=out_channels//2),
                BasicConv(out_channels, out_channels, 1)
            )

            self.concat_conv = BasicConv(out_channels*2, out_channels, 1)
        else:
            #--------------------------------------------------------------------------#
            #   然后建立一个大的残差边self.split_conv0、这个大残差边绕过了很多的残差结构
            #--------------------------------------------------------------------------#
            self.split_conv0 = BasicConv(out_channels, out_channels//2, 1)

            #----------------------------------------------------------------#
            #   主干部分会对num_blocks进行循环,循环内部是残差结构。
            #----------------------------------------------------------------#
            self.split_conv1 = BasicConv(out_channels, out_channels//2, 1)
            self.blocks_conv = nn.Sequential(
                *[Resblock(out_channels//2) for _ in range(num_blocks)],
                BasicConv(out_channels//2, out_channels//2, 1)
            )

            self.concat_conv = BasicConv(out_channels, out_channels, 1)

    def forward(self, x):
        x = self.downsample_conv(x)

        x0 = self.split_conv0(x)

        x1 = self.split_conv1(x)
        x1 = self.blocks_conv(x1)

        #------------------------------------#
        #   将大残差边再堆叠回来
        #------------------------------------#
        x = torch.cat([x1, x0], dim=1)
        #------------------------------------#
        #   最后对通道数进行整合
        #------------------------------------#
        x = self.concat_conv(x)

        return x

#---------------------------------------------------#
#   CSPdarknet53 的主体部分
#   输入为一张416x416x3的图片
#   输出为三个有效特征层
#---------------------------------------------------#
class CSPDarkNet(nn.Module):
    def __init__(self, layers):
        super(CSPDarkNet, self).__init__()
        self.inplanes = 32
        # 416,416,3 -> 416,416,32
        self.conv1 = BasicConv(3, self.inplanes, kernel_size=3, stride=1)
        self.feature_channels = [64, 128, 256, 512, 1024]

        self.stages = nn.ModuleList([
            # 416,416,32 -> 208,208,64
            Resblock_body(self.inplanes, self.feature_channels[0], layers[0], first=True),
            # 208,208,64 -> 104,104,128
            Resblock_body(self.feature_channels[0], self.feature_channels[1], layers[1], first=False),
            # 104,104,128 -> 52,52,256
            Resblock_body(self.feature_channels[1], self.feature_channels[2], layers[2], first=False),
            # 52,52,256 -> 26,26,512
            Resblock_body(self.feature_channels[2], self.feature_channels[3], layers[3], first=False),
            # 26,26,512 -> 13,13,1024
            Resblock_body(self.feature_channels[3], self.feature_channels[4], layers[4], first=False)
        ])

        self.num_features = 1
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
                m.weight.data.normal_(0, math.sqrt(2. / n))
            elif isinstance(m, nn.BatchNorm2d):
                m.weight.data.fill_(1)
                m.bias.data.zero_()


    def forward(self, x):
        x = self.conv1(x)

        x = self.stages[0](x)
        x = self.stages[1](x)
        out3 = self.stages[2](x)
        out4 = self.stages[3](out3)
        out5 = self.stages[4](out4)

        return out3,out4,out5

def darknet53():
    model = CSPDarkNet([1, 2, 8, 8, 4])
    input_data= torch.randn(1,3,416,416)
    out3,out4,out5=model(input_data)
    print(out3.shape)
    print(out4.shape)
    print(out5.shape)

darknet53()

参考资料

https://zhuanlan.zhihu.com/p/562927364?utm_id=0

http://pointborn.com/article/2022/2/14/1815.html

https://zhuanlan.zhihu.com/p/263555330

https://zhuanlan.zhihu.com/p/509160824

https://blog.csdn.net/qq_45603919/article/details/117265617 代码

标签:BasicConv,nn,局部,网络,残差,channels,CSPNet,self,out
From: https://www.cnblogs.com/tian777/p/17864996.html

相关文章

  • 网络管理
    目录网络管理1.网络配置1.1网卡命名规则1.2网络管理器2.使用nmcli管理网络2.1查看设备信息2.2查看设备详细信息2.3添加和激活连接2.4管理连接2.5修改网络配置文件2.6重新加载连接2.7重启网络服务3.使用nmtui和nm-connection-editor3.1使用nmtui3.2使用nm-conn......
  • 网络参考模型
    先上图,我们慢慢讲,如下:TCP/IP标准模型OSI参考模型TCP/IP对等模型协议应用层 应用层应用层 Telnet23FTP20/21TFTP69SNMP表示层HTTP80SMTPDNSDHCP会话层 主机到主机层传输层传输层TCPUDP......
  • Linux ubuntu网络配置(学习笔记)
    1.网卡名称修改#修改配置文件为下面形式root@ubuntu1804:~#vi/etc/default/grubGRUB_CMDLINE_LINUX="net.ifnames=0"#或者sed修改root@ubuntu1804:~#sed-i.bak'/^GRUB_CMDLINE_LINUX=/s#"$#net.ifnames=0"#'/etc/default/grubroot@maple-u18:~#grub-mkconfig......
  • 运营商网络性能测试-Y.1564
    前言在网络部署之后和业务开展之前,运营商迫切希望了解当前网络的性能状态,以便为商业规划和业务推广提供必要的基础数据支持。因此,高可靠性和高精确度的性能测试方法对于运营商评判网络性能的优劣,显得尤为重要,而RFC2544等传统测试标准已不足于鉴定当今的服务等级协议(SLA)。SLA是服......
  • 低时延精品网 - 打造专属智能网络服务的新标杆
    跟着全球信息化的快速开展,企业和机构对通讯网络的需求也在不断晋级。他们不仅要求网络连接稳定牢靠,还对时延、安全性、服务质量等方面提出了更高的要求。为了满意这些需求,各大服务商纷繁推出了一系列立异型网络服务产品,其中就包含低时延精品网。低时延精品网是一种专属智能网络服......
  • 断开网络麒麟总是自动打开浏览器
    访问的网址:http://capnet.elementary.io就是检测你有没有网络的解决办法sed-i'42d'/etc/NetworkManager/dispatcher.d/90-open_captive_portal就是删掉了下面这行内容:......
  • 使用Golang构建高性能网络爬虫
    前段时间和以前公司的老同事聚会,喝酒中无意聊到目前他们公司在做的一个爬虫项目,因为效率低下,整个人每天忙的不可开交。借着这次聚会,正好询问我一些解决方案。于是,我给了他们我的一些思路。所谓的高性能网络爬虫就是一种能够快速、高效地从互联网上抓取大量网页数据的程序。网络爬虫......
  • 神经网络入门篇之深层神经网络:详解前向传播和反向传播(Forward and backward propagati
    深层神经网络(DeepL-layerneuralnetwork)复习下前面的内容:1.逻辑回归,结构如下图左边。一个隐藏层的神经网络,结构下图右边:注意,神经网络的层数是这么定义的:从左到右,由0开始定义,比如上边右图,\({x}_{1}\)、\({x}_{2}\)、\({x}_{3}\),这层是第0层,这层左边的隐藏层是第1层,由此类推......
  • 多开工具对网络游戏安全性的评估与加固
    多开工具对网络游戏安全性的评估与加固随着网络游戏的普及和发展,一些玩家为了方便或者获得不正当利益,开始使用多开工具同时登录多个游戏账号。然而,多开工具的使用可能会对网络游戏的安全性造成一定的威胁,因此有必要对其进行评估并采取相应的加固措施。首先,对于多开工具的评估需要......
  • 深度解析工业网络交换机与工业自动化的紧密关系
    随着工业化程度的不断提高,工业控制系统的自动化程度也在不断增强,工业网络交换机作为数据通信和网络连接的重要设备,在工业自动化中扮演着关键的角色。工业网络交换机将不同的工业控制设备连接起来,实现数据的高效传输和实时互联,为工业自动化系统提供了可靠的网络基础。本文将围绕工业......