YOLOv5改进系列:升级版ResNet的新主干网络DenseNet

2024-03-31 08:20

本文主要是介绍YOLOv5改进系列:升级版ResNet的新主干网络DenseNet,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、论文理论

论文地址:Densely Connected Convolutional Networks

1.理论思想

DenseNet最大化前后层信息交流,通过建立前面所有层与后面层的密集连接,实现了特征在通道维度上的复用,不但减缓了梯度消失的现象,也使其可以在参数与计算量更少的情况下实现比ResNet更优的性能

2.创新点

操作过程:

  • 每一个Bottleneck输出的特征通道数是相同的,例如这里的K=32。同时可以看到,经过concat操作后的通道数是按K的增长量增加的,因此这个K也被称为GrowthRate。
  • 这里1×1卷积的作用是固定输出通道数,达到降维的作用,1×1卷积输出的通道数通常是GrowthRate的4倍。当几十个Bottleneck相连接时,concat后的通道数会增加到上千,如果不增加1×1的卷积来降维,后续3×3卷积所需的参数量会急剧增加。比如,输入通道数64,增长率K=32,经过15个Bottleneck,通道数输出为64+15*32=544,再经过第16个Bottleneck时,如果不使用1×1卷积,第16个Bottleneck层参数量是3*3*544*32=156672,如果使用1×1卷积,第16个Bottleneck层参数量是1*1*544*128+3*3*128*32=106496,可以看到参数量大大降低。
  • Dense Block采用了激活函数在前、卷积层在后的顺序,即BN-ReLU-Conv的顺序,这种方式也被称为pre-activation。通常的模型relu等激活函数处于卷积conv、批归一化batchnorm之后,即Conv-BN-ReLU,也被称为post-activation。作者证明,如果采用post-activation设计,性能会变差。想要更清晰的了解pre-activition,可以参考我的博客ResNet残差网络及变体详解中的Pre Activation ResNet。

二、代码部署

1.代码

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.utils.checkpoint as cp
from torch.jit.annotations import Listfrom timm.models.layers import BatchNormAct2ddef autopad(k, p=None):  # kernel, padding# Pad to 'same'if p is None:p = k // 2 if isinstance(k, int) else [x // 2 for x in k]  # auto-padreturn pclass Conv(nn.Module):# Standard convolution iscyydef __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True):  # ch_in, ch_out, kernel, stride, padding, groupssuper().__init__()self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=False)self.bn = nn.BatchNorm2d(c2)self.act = nn.SiLU() if act is True else (act if isinstance(act, nn.Module) else nn.Identity())def forward(self, x):return self.act(self.bn(self.conv(x)))def forward_fuse(self, x):return self.act(self.conv(x))class DenseLayer(nn.Module):def __init__(self, int_numss, gr, bs, norm_layer=BatchNormAct2d,drop_rate=0., memory_efficient=False):super(DenseLayer, self).__init__()self.add_module('norm1', norm_layer(int_numss)),self.add_module('conv1', nn.Conv2d(int_numss, bs * gr, kernel_size=1, stride=1, bias=False)),self.add_module('norm2', norm_layer(bs * gr)),self.add_module('conv2', nn.Conv2d(bs * gr, gr, kernel_size=3, stride=1, padding=1, bias=False)),self.drop_rate = float(drop_rate)self.memory_efficient = memory_efficientdef bottleneck_fn(self, xs):concated_features = torch.cat(xs, 1)bottleneck_output = self.conv1(self.norm1(concated_features))  # noqa: T484return bottleneck_outputdef any_requires_grad(self, x):for tensor in x:if tensor.requires_grad:return Truereturn False@torch.jit.unused  # noqa: T484def call_checkpoint_bottleneck(self, x):def closure(*xs):return self.bottleneck_fn(xs)return cp.checkpoint(closure, *x)@torch.jit._overload_method  # mango noqa: F811def forward(self, x):pass@torch.jit._overload_method  # noqa: F811def forward(self, x):passdef forward(self, x):  # noqa: F811 iscyy/mangoif isinstance(x, torch.Tensor):prev_features = [x]else:prev_features = xif self.memory_efficient and self.any_requires_grad(prev_features):if torch.jit.is_scripting():raise Exception("Memory Efficient not supported in JIT")bottleneck_output = self.call_checkpoint_bottleneck(prev_features)else:bottleneck_output = self.bottleneck_fn(prev_features)new_features = self.conv2(self.norm2(bottleneck_output))if self.drop_rate > 0:new_features = F.dropout(new_features, p=self.drop_rate, training=self.training)return new_featuresclass DenseBlock(nn.ModuleDict):_version = 2def __init__(self, int_numss, gr, num_layers, bs=4, norm_layer=nn.ReLU,drop_rate=0., memory_efficient=False):super(DenseBlock, self).__init__()for i in range(num_layers):layer = DenseLayer(int_numss + i * gr,gr=gr,bs=bs,norm_layer=norm_layer,drop_rate=drop_rate,memory_efficient=memory_efficient,)self.add_module('denselayer%d' % (i + 1), layer)def forward(self, init_features):features = [init_features]for name, layer in self.items():new_features = layer(features)features.append(new_features)return torch.cat(features, 1)class DenseTrans(nn.Sequential):def __init__(self, int_numss, out_numss, kernel_size, norm_layer=nn.BatchNorm2d, aa_layer=None,  act=True):super(DenseTrans, self).__init__()self.conv = nn.Conv2d(int_numss, out_numss, kernel_size=kernel_size, stride=1)self.bn = nn.BatchNorm2d(out_numss)self.act = self.act = nn.SiLU() if act is True else (act if isinstance(act, nn.Module) else nn.Identity())def forward(self, x):return self.act(self.bn(self.conv(x)))def forward_fuse(self, x):return self.act(self.conv(x))class DenseB(nn.Module):def __init__(self, c1, c2, gr, num_layers=6):super().__init__()self.dense = DenseBlock(c1, gr, num_layers)self.con = DenseTrans(c1 + gr * num_layers, c2, 1 ,1)def forward(self, x):x = self.con(self.dense(x))return xclass DenseC(nn.Module):def __init__(self, c1, c2, gr, num_layers=6):super().__init__()self.dense = DenseBlock(c1, gr, num_layers)self.con = DenseTrans(c1 + gr * num_layers, c2, 1 ,1)self.dense2 = DenseBlock(c1, gr, num_layers)self.con2 = DenseTrans(c1 + gr * num_layers, c2, 1 ,1)def forward(self, x):x = self.con(self.dense(x))x = self.con2(self.dense2(x))return xclass DenseOne(nn.Module):def __init__(self, c1, c2, n=1, gr=32, e=0.5):super().__init__()c_ = int(c2 * e)self.cv1 = Conv(c1, c_, 1, 1)self.cv2 = Conv(c1, c_, 1, 1)self.cv3 = Conv(2 * c_, c2, 1)self.m = nn.Sequential(*(DenseB(c_, c_, gr=gr, num_layers=6) for _ in range(n)))def forward(self, x):return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), dim=1))class DenseOneC(nn.Module):def __init__(self, c1, c2, n=1, gr=32, e=0.5):super().__init__()c_ = int(c2 * e)self.cv1 = Conv(c1, c_, 1, 1)self.cv2 = Conv(c1, c_, 1, 1)self.cv3 = Conv(2 * c_, c2, 1)self.m = nn.Sequential(*(DenseC(c_, c_, gr=gr, num_layers=6) for _ in range(n)))def forward(self, x):return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), dim=1))

2.配置教程

(1)在models/cmmon.py中添加上述代码,将与初始代码中重复类删除

(2)在./models/yolo.py文件下里的parse_model函数,将类名加入进去

           for i, (f, n, m, args) in enumerate(d['backbone'] + d['head']):内部

        elif m in [DenseOne, DenseOneC]:c1, c2 = ch[f], args[0]if c2 != no:  # if not outputc2 = make_divisible(c2 * gw, 8)args = [c1, c2, *args[1:]]if m in [DenseOne, DenseOneC]:args.insert(2, n)  # number of repeatsn = 1

3.yaml文件

 YOLOv5 🚀 by Ultralytics, GPL-3.0 license# Parameters
nc: 2  # number of classes
depth_multiple: 0.33  # model depth multiple
width_multiple: 0.5  # layer channel multiple
anchors:- [10,13, 16,30, 33,23]  # P3/8- [30,61, 62,45, 59,119]  # P4/16- [116,90, 156,198, 373,326]  # P5/32# YOLOv5 v6.0 backbone  by mango
backbone:# [from, number, module, args][[-1, 1, Conv, [64, 6, 2, 2]],  # 0-P1/2[-1, 1, Conv, [128, 3, 2]],  # 1-P2/4[-1, 3, C3, [128]],[-1, 1, Conv, [256, 3, 2]],  # 3-P3/8[-1, 6, C3, [256]],[-1, 1, Conv, [512, 3, 2]],  # 5-P4/16[-1, 9, C3, [512]],[-1, 1, Conv, [1024, 3, 2]],  # 7-P5/32[-1, 3, DenseOne, [1024, 32]],[-1, 1, SPPF, [1024, 5]],  # 9]# YOLOv5 v6.0 head by mango
head:[[-1, 1, Conv, [512, 1, 1]],[-1, 1, nn.Upsample, [None, 2, 'nearest']],[[-1, 6], 1, Concat, [1]],  # cat backbone P4[-1, 3, C3, [512, False]],  # 13[-1, 1, Conv, [256, 1, 1]],[-1, 1, nn.Upsample, [None, 2, 'nearest']],[[-1, 4], 1, Concat, [1]],  # cat backbone P3[-1, 3, C3, [256, False]],  # 17 (P3/8-small)[-1, 1, Conv, [256, 3, 2]],[[-1, 14], 1, Concat, [1]],  # cat head P4[-1, 3, C3, [512, False]],  # 20 (P4/16-medium)[-1, 1, Conv, [512, 3, 2]],[[-1, 10], 1, Concat, [1]],  # cat head P5[-1, 3, DenseOne, [1024]],  # 23 (P5/32-large)[[17, 20, 23], 1, Detect, [nc, anchors]],  # Detect(P3, P4, P5)]

三、总结

本文主要工作包括DenseNet介绍及改进代码策略,该模块为即插即用模块,部署位置可根据实际针对任务需求,自行调整

本专栏持续更新中,订阅本栏,关注更新~

这篇关于YOLOv5改进系列:升级版ResNet的新主干网络DenseNet的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/863870

相关文章

SSID究竟是什么? WiFi网络名称及工作方式解析

《SSID究竟是什么?WiFi网络名称及工作方式解析》SID可以看作是无线网络的名称,类似于有线网络中的网络名称或者路由器的名称,在无线网络中,设备通过SSID来识别和连接到特定的无线网络... 当提到 Wi-Fi 网络时,就避不开「SSID」这个术语。简单来说,SSID 就是 Wi-Fi 网络的名称。比如

Java实现任务管理器性能网络监控数据的方法详解

《Java实现任务管理器性能网络监控数据的方法详解》在现代操作系统中,任务管理器是一个非常重要的工具,用于监控和管理计算机的运行状态,包括CPU使用率、内存占用等,对于开发者和系统管理员来说,了解这些... 目录引言一、背景知识二、准备工作1. Maven依赖2. Gradle依赖三、代码实现四、代码详解五

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

【生成模型系列(初级)】嵌入(Embedding)方程——自然语言处理的数学灵魂【通俗理解】

【通俗理解】嵌入(Embedding)方程——自然语言处理的数学灵魂 关键词提炼 #嵌入方程 #自然语言处理 #词向量 #机器学习 #神经网络 #向量空间模型 #Siri #Google翻译 #AlexNet 第一节:嵌入方程的类比与核心概念【尽可能通俗】 嵌入方程可以被看作是自然语言处理中的“翻译机”,它将文本中的单词或短语转换成计算机能够理解的数学形式,即向量。 正如翻译机将一种语言

ASIO网络调试助手之一:简介

多年前,写过几篇《Boost.Asio C++网络编程》的学习文章,一直没机会实践。最近项目中用到了Asio,于是抽空写了个网络调试助手。 开发环境: Win10 Qt5.12.6 + Asio(standalone) + spdlog 支持协议: UDP + TCP Client + TCP Server 独立的Asio(http://www.think-async.com)只包含了头文件,不依

poj 3181 网络流,建图。

题意: 农夫约翰为他的牛准备了F种食物和D种饮料。 每头牛都有各自喜欢的食物和饮料,而每种食物和饮料都只能分配给一头牛。 问最多能有多少头牛可以同时得到喜欢的食物和饮料。 解析: 由于要同时得到喜欢的食物和饮料,所以网络流建图的时候要把牛拆点了。 如下建图: s -> 食物 -> 牛1 -> 牛2 -> 饮料 -> t 所以分配一下点: s  =  0, 牛1= 1~

poj 3068 有流量限制的最小费用网络流

题意: m条有向边连接了n个仓库,每条边都有一定费用。 将两种危险品从0运到n-1,除了起点和终点外,危险品不能放在一起,也不能走相同的路径。 求最小的费用是多少。 解析: 抽象出一个源点s一个汇点t,源点与0相连,费用为0,容量为2。 汇点与n - 1相连,费用为0,容量为2。 每条边之间也相连,费用为每条边的费用,容量为1。 建图完毕之后,求一条流量为2的最小费用流就行了

poj 2112 网络流+二分

题意: k台挤奶机,c头牛,每台挤奶机可以挤m头牛。 现在给出每只牛到挤奶机的距离矩阵,求最小化牛的最大路程。 解析: 最大值最小化,最小值最大化,用二分来做。 先求出两点之间的最短距离。 然后二分匹配牛到挤奶机的最大路程,匹配中的判断是在这个最大路程下,是否牛的数量达到c只。 如何求牛的数量呢,用网络流来做。 从源点到牛引一条容量为1的边,然后挤奶机到汇点引一条容量为m的边