自己做电视视频网站吗,如何控制一个网站软件开发,厦门网站开发公司,最新企业网站系统秋招面试专栏推荐 #xff1a;深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 #x1f4a1;#x1f4a1;#x1f4a1;本专栏所有程序均经过测试#xff0c;可成功执行#x1f4a1;#x1f4a1;#x1f4a1; 专栏目录 #xff1a;《YOLOv8改进有效…秋招面试专栏推荐 深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 本专栏所有程序均经过测试可成功执行 专栏目录 《YOLOv8改进有效涨点》专栏介绍 专栏目录 | 目前已有40篇内容内含各种Head检测头、损失函数Loss、Backbone、Neck、NMS等创新点改进——点击即可跳转 许多现代目标检测器通过使用“观察和思考两次”的机制展现了卓越的性能。我们在目标检测的主干设计中探讨了这种机制。在宏观层面上提出了递归特征金字塔Recursive Feature Pyramid它将额外的反馈连接从特征金字塔网络整合到底向上的主干层中。在微观层面上提出了可切换空洞卷积Switchable Atrous Convolution它用不同的空洞率对特征进行卷积并使用切换函数收集结果。将它们结合起来就得到了DetectoRS它显著提高了目标检测的性能。 文章在介绍主要的原理后将手把手教学如何进行模块的代码添加和修改并将修改后的完整代码放在文章的最后方便大家一键运行小白也可轻松上手实践。以帮助您更好地学习深度学习目标检测YOLO系列的挑战。
目录
1. 原理
2. 将PConv添加到YOLOv8代码
2.1 PConv代码实现
2.2 更改init.py文件
2.3 新增yaml文件
2.4 注册模块
2.5 执行程序
3. 完整代码分享
4. GFLOPs
5. 进阶
6. 总结 1. 原理 论文地址DetectoRS: Detecting Objects with Recursive Feature Pyramid and Switchable Atrous Convolutio——点击即可跳转官方代码官方代码仓库——点击即可跳转 可切换空洞卷积 (SAC) 是一种复杂的卷积技术用于增强深度学习模型的性能特别是在对象检测和分割等任务中。以下是根据提供的文档对其主要原理的细分
空洞卷积
空洞卷积也称为扩张卷积用于增加过滤器的视野而不会增加参数数量或计算量。这是通过在连续的过滤器值之间引入零来实现的。插入这些零的速率称为空洞速率 ( r )。对于大小为 的过滤器有效内核大小变为 ( k (k-1)(r-1) )。这允许网络捕获多尺度信息这对于检测不同大小的物体特别有用。
可切换空洞卷积 (SAC)
SAC 以空洞卷积为基础引入了一种在卷积操作期间动态切换不同空洞率的机制。其核心思想是允许卷积层根据输入特征自适应地选择适当的空洞率。这种适应性有助于模型更好地处理同一图像中不同尺度的对象。
SAC 的组件
SAC 由三个主要组件组成主 SAC 组件和两个附加在 SAC 组件之前和之后的全局上下文模块。 主 SAC 组件这是实际发生可切换空洞卷积的核心部分。它涉及两个具有不同空洞率的卷积操作的加权组合。
SAC 的数学公式如下 其中 ( x ) 是输入。 和 是卷积运算的权重。 ( r ) 是空洞率。 是一个开关函数实现为一个平均池化层具有 5x5 内核后跟一个 1x1 卷积层确定两个卷积运算之间的平衡。 全局上下文模块这些模块在 SAC 操作前后为特征添加了图像级上下文增强了模型理解图像全局结构的能力。
SAC的优势 多尺度检测通过动态切换不同的空洞率SAC 使模型能够更好地检测各种尺寸的物体。 参数效率SAC 在不增加额外参数的情况下增加了感受野同时保持了计算效率。 适应性切换功能允许卷积层根据输入进行适应使模型更加灵活能够处理不同的图像和物体尺度。
实现示例 SAConv结构 骨干网络例如 ResNet中的每个 3x3 卷积层都转换为 SAC然后执行具有不同空洞率的卷积的加权组合。
综上所述可切换空洞卷积结合了空洞卷积和动态适应性的优点增强了深度学习模型提高了其处理不同物体尺度图像的能力同时保持参数和计算方面的效率。
2. 将PConv添加到YOLOv8代码
2.1 PConv代码实现 关键步骤一将下面代码粘贴到在/ultralytics/ultralytics/nn/modules/conv.py中并在该文件的__all__中添加“SAConv” class ConvAWS2d(nn.Conv2d):def __init__(self,in_channels,out_channels,kernel_size,stride1,padding0,dilation1,groups1,biasTrue):super().__init__(in_channels,out_channels,kernel_size,stridestride,paddingpadding,dilationdilation,groupsgroups,biasbias)self.register_buffer(weight_gamma, torch.ones(self.out_channels, 1, 1, 1))self.register_buffer(weight_beta, torch.zeros(self.out_channels, 1, 1, 1))def _get_weight(self, weight):weight_mean weight.mean(dim1, keepdimTrue).mean(dim2,keepdimTrue).mean(dim3, keepdimTrue)weight weight - weight_meanstd torch.sqrt(weight.view(weight.size(0), -1).var(dim1) 1e-5).view(-1, 1, 1, 1)weight weight / stdweight self.weight_gamma * weight self.weight_betareturn weightdef forward(self, x):weight self._get_weight(self.weight)return super()._conv_forward(x, weight, None)def _load_from_state_dict(self, state_dict, prefix, local_metadata, strict,missing_keys, unexpected_keys, error_msgs):self.weight_gamma.data.fill_(-1)super()._load_from_state_dict(state_dict, prefix, local_metadata, strict,missing_keys, unexpected_keys, error_msgs)if self.weight_gamma.data.mean() 0:returnweight self.weight.dataweight_mean weight.data.mean(dim1, keepdimTrue).mean(dim2,keepdimTrue).mean(dim3, keepdimTrue)self.weight_beta.data.copy_(weight_mean)std torch.sqrt(weight.view(weight.size(0), -1).var(dim1) 1e-5).view(-1, 1, 1, 1)self.weight_gamma.data.copy_(std)class SAConv2d(ConvAWS2d):def __init__(self,in_channels,out_channels,kernel_size,s1,pNone,g1,d1,actTrue,biasTrue):super().__init__(in_channels,out_channels,kernel_size,strides,paddingautopad(kernel_size, p),dilationd,groupsg,biasbias)self.switch torch.nn.Conv2d(self.in_channels,1,kernel_size1,strides,biasTrue)self.switch.weight.data.fill_(0)self.switch.bias.data.fill_(1)self.weight_diff torch.nn.Parameter(torch.Tensor(self.weight.size()))self.weight_diff.data.zero_()self.pre_context torch.nn.Conv2d(self.in_channels,self.in_channels,kernel_size1,biasTrue)self.pre_context.weight.data.fill_(0)self.pre_context.bias.data.fill_(0)self.post_context torch.nn.Conv2d(self.out_channels,self.out_channels,kernel_size1,biasTrue)self.post_context.weight.data.fill_(0)self.post_context.bias.data.fill_(0)self.bn nn.BatchNorm2d(out_channels)self.act nn.SiLU() if act is True else (act if isinstance(act, nn.Module) else nn.Identity())def forward(self, x):# pre-contextavg_x torch.nn.functional.adaptive_avg_pool2d(x, output_size1)avg_x self.pre_context(avg_x)avg_x avg_x.expand_as(x)x x avg_x# switchavg_x torch.nn.functional.pad(x, pad(2, 2, 2, 2), modereflect)avg_x torch.nn.functional.avg_pool2d(avg_x, kernel_size5, stride1, padding0)switch self.switch(avg_x)# sacweight self._get_weight(self.weight)out_s super()._conv_forward(x, weight, None)ori_p self.paddingori_d self.dilationself.padding tuple(3 * p for p in self.padding)self.dilation tuple(3 * d for d in self.dilation)weight weight self.weight_diffout_l super()._conv_forward(x, weight, None)out switch * out_s (1 - switch) * out_lself.padding ori_pself.dilation ori_d# post-contextavg_x torch.nn.functional.adaptive_avg_pool2d(out, output_size1)avg_x self.post_context(avg_x)avg_x avg_x.expand_as(out)out out avg_xreturn self.act(self.bn(out))可切换空洞卷积 (SAconv) 通过动态调整卷积层中的空洞率来增强图像处理从而实现更有效的多尺度特征提取。 SAconv 处理图像的主要工作流程概述
SAconv 的主要工作流程 输入图像 该过程从输入到神经网络的输入图像开始。 初始卷积层 图像首先经过几个标准卷积层提取边缘、纹理和基本形状等低级特征。这些层通常具有固定的内核大小和步长值。 可切换空洞卷积 (SAC) 模块 核心组件 SAC 模块取代了网络主干中的传统卷积层例如 ResNet。以下是 SAC 操作的详细分解 特征提取 输入特征 ( x ) 首先通过两个不同的卷积操作进行处理权重分别为 ( w ) 和 其中 表示对权重的调整。这些卷积具有不同的空洞率使它们能够捕获多个尺度的特征。 切换函数 切换函数 S(x) 确定两个卷积之间的平衡。它通常实现为具有 5x5 内核的平均池化层后跟 1x1 卷积层。切换函数的输出是一组权重用于平衡两个卷积的贡献。 加权组合 SAC 的最终输出是两个卷积的加权组合 这里 表示标准卷积表示速率为 ( r ) 的空洞卷积。 全局上下文模块 在 SAC 模块之前和之后使用全局上下文模块来合并图像级上下文。这些模块通常涉及全局平均池化和全连接层等操作以捕获图像的整体结构。这有助于细化特征并为后续层提供更好的上下文。 中间层: SAC 模块和全局上下文模块的输出被馈送到网络的进一步层其中可能包括额外的卷积、规范化和激活函数。这些层继续细化和处理 SAC 模块提取的特征。 输出层: 最后处理后的特征到达输出层生成所需的结果。这可能是分类标签、分割掩码或用于对象检测的边界框具体取决于网络设计用于的任务。
工作流程说明
在提供的文档中图 4 显示了集成到 ResNet 架构中的 SAC 模块的示例。在此图中ResNet 主干中的每个 3x3 卷积层都被 SAC 模块替换。此修改允许网络根据输入特征动态调整其感受野从而提高需要多尺度特征检测的任务的性能。 2.2 更改init.py文件 关键步骤二修改modules文件夹下的__init__.py文件先导入函数 然后在下面的__all__中声明函数 2.3 新增yaml文件 关键步骤三在 \ultralytics\ultralytics\cfg\models\v8下新建文件 yolov8_SAConv.yaml并将下面代码复制进去 # Ultralytics YOLO , AGPL-3.0 license
# YOLOv8 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect# Parameters
nc: 80 # number of classes
scales: # model compound scaling constants, i.e. modelyolov8n.yaml will call yolov8.yaml with scale n# [depth, width, max_channels]n: [ 0.33, 0.25, 1024 ] # YOLOv8n summary: 225 layers, 3157200 parameters, 3157184 gradients, 8.9 GFLOPs# YOLOv8.0n backbone
backbone:# [from, repeats, module, args]- [ -1, 1, SAConv2d, [ 64, 3, 2 ] ] # 0-P1/2- [ -1, 1, SAConv2d, [ 128, 3, 2 ] ] # 1-P2/4- [ -1, 3, C2f, [ 128, True ] ]- [ -1, 1, SAConv2d, [ 256, 3, 2 ] ] # 3-P3/8- [ -1, 6, C2f, [ 256, True ] ]- [ -1, 1, SAConv2d, [ 512, 3, 2 ] ] # 5-P4/16- [ -1, 6, C2f, [ 512, True ] ]- [ -1, 1, SAConv2d, [ 1024, 3, 2 ] ] # 7-P5/32- [ -1, 3, C2f, [ 1024, True ] ]- [ -1, 1, SPPF, [ 1024, 5 ] ] # 9# YOLOv8.0n head
head:- [ -1, 1, nn.Upsample, [ None, 2, nearest ] ]- [ [ -1, 6 ], 1, Concat, [ 1 ] ] # cat backbone P4- [ -1, 3, C2f, [ 512 ] ] # 12- [ -1, 1, nn.Upsample, [ None, 2, nearest ] ]- [ [ -1, 4 ], 1, Concat, [ 1 ] ] # cat backbone P3- [ -1, 3, C2f, [ 256 ] ] # 15 (P3/8-small)- [ -1, 1, SAConv2d, [ 256, 3, 2 ] ]- [ [ -1, 12 ], 1, Concat, [ 1 ] ] # cat head P4- [ -1, 3, C2f, [ 512 ] ] # 18 (P4/16-medium)- [ -1, 1, SAConv2d, [ 512, 3, 2 ] ]- [ [ -1, 9 ], 1, Concat, [ 1 ] ] # cat head P5- [ -1, 3, C2f, [ 1024 ] ] # 21 (P5/32-large)- [ [ 15, 18, 21 ], 1, Detect, [ nc ] ] # Detect(P3, P4, P5)温馨提示因为本文只是对yolov8基础上添加模块如果要对yolov8n/l/m/x进行添加则只需要指定对应的depth_multiple 和 width_multiple。 # YOLOv8n
depth_multiple: 0.33 # model depth multiple
width_multiple: 0.25 # layer channel multiple
max_channels: 1024 # max_channels# YOLOv8s
depth_multiple: 0.33 # model depth multiple
width_multiple: 0.50 # layer channel multiple
max_channels: 1024 # max_channels# YOLOv8l
depth_multiple: 1.0 # model depth multiple
width_multiple: 1.0 # layer channel multiple
max_channels: 512 # max_channels# YOLOv8m
depth_multiple: 0.67 # model depth multiple
width_multiple: 0.75 # layer channel multiple
max_channels: 768 # max_channels# YOLOv8x
depth_multiple: 1.33 # model depth multiple
width_multiple: 1.25 # layer channel multiple
max_channels: 512 # max_channels
2.4 注册模块 关键步骤四在parse_model函数中进行注册添加SAConv, 2.5 执行程序
在train.py中将model的参数路径设置为yolov8_SAConv.yaml的路径
建议大家写绝对路径确保一定能找到
from ultralytics import YOLO# Load a model
# model YOLO(yolov8n.yaml) # build a new model from YAML
# model YOLO(yolov8n.pt) # load a pretrained model (recommended for training)model YOLO(r/projects/ultralytics/ultralytics/cfg/models/v8/yolov8_PConv.yaml) # build from YAML and transfer weights# Train the model
model.train(batch16)
运行程序如果出现下面的内容则说明添加成功 3. 完整代码分享
https://pan.baidu.com/s/1z2KWa9guFsyHTETM9gXdPA?pwdkbu5 提取码: kbu5
4. GFLOPs
关于GFLOPs的计算方式可以查看百面算法工程师 | 卷积基础知识——Convolution
未改进的YOLOv8nGFLOPs 改进后的GFLOPs 5. 进阶
可以与其他的注意力机制或者损失函数等结合进一步提升检测效果
6. 总结
可切换空洞卷积 (SAConv) 可动态调整卷积层中的空洞率通过基于输入特征平衡其贡献的切换函数组合不同的空洞卷积使网络能够更有效地捕获多尺度特征。这种适应性增强了网络检测不同大小物体的能力并提高了物体检测和分割等任务的性能而无需添加额外的参数。