泉州建站模板搭建,响应式网站的费用,短视频seo营销系统,网站空间稳定性前言
大家好#xff0c;我是Snu77#xff0c;这里是RT-DETR有效涨点专栏。
本专栏的内容为根据ultralytics版本的RT-DETR进行改进#xff0c;内容持续更新#xff0c;每周更新文章数量3-10篇。
专栏以ResNet18、ResNet50为基础修改版本#xff0c;同时修改内容也支持Re…前言
大家好我是Snu77这里是RT-DETR有效涨点专栏。
本专栏的内容为根据ultralytics版本的RT-DETR进行改进内容持续更新每周更新文章数量3-10篇。
专栏以ResNet18、ResNet50为基础修改版本同时修改内容也支持ResNet32、ResNet101和PPHGNet版本其中ResNet为RT-DETR官方版本11移植过来的参数量基本保持一致(误差很小很小)不同于ultralytics仓库版本的ResNet官方版本同时ultralytics仓库的一些参数是和RT-DETR相冲的所以我也是会教大家调好一些参数和代码真正意义上的跑ultralytics的和RT-DETR官方版本的无区别
一、本文介绍
本文给大家带来的改进内容是LSKNetLarge Kernel Selection, LK Selection其是一种专为遥感目标检测设计的网络架构其核心思想是动态调整其大的空间感受野以更好地捕捉遥感场景中不同对象的范围上下文。实验部分我在一个包含三十多个类别的数据集上进行实验其中包含大目标检测和小目标检测mAP的平均涨点幅度在0.04-0.1之间(也有极个别的情况没有涨点)同时官方的版本只提供了一个大版本我在其基础上提供一个轻量化版本给大家选择本文会先给大家对比试验的结果供大家参考该网络的mAP提高大概在2个点参数量也有一定程度上的下降可以起到轻量化的作用。 专栏链接RT-DETR剑指论文专栏持续复现各种顶会内容——论文收割机RT-DETR 目录
一、本文介绍
二、LSKNet原理
2.1 LSKNet的基本原理
2.2 大型核选择LK Selection子块
2.3 前馈网络FFN子块
三、LSKNet核心代码 四、手把手教你添加LSKNet机制
4.1 修改一
4.2 修改二
4.3 修改三
4.4 修改四
4.5 修改五
4.6 修改六
4.7 修改七
4.8 修改八
4.9 RT-DETR不能打印计算量问题的解决
4.10 可选修改
五、LSKNet的yaml文件
5.1 yaml文件
5.2 运行文件
5.3 成功训练截图
六、全文总结 二、LSKNet原理 论文地址 官方论文地址
代码地址 官方代码地址 2.1 LSKNet的基本原理
LSKNetLarge Selective Kernel Network是一种专为遥感目标检测设计的网络架构其核心优势在于能够动态调整其大的空间感受野以更好地捕捉遥感场景中不同对象的范围上下文。这是第一次在遥感目标检测领域探索大型和选择性核机制。
LSKNet大型选择性核网络的基本原理包括以下关键组成部分
1. 大型核选择LK Selection子块这个子块能够动态地调整网络的感受野以便根据需要捕获不同尺度的上下文信息。这使得网络能够根据遥感图像中对象的不同尺寸和复杂性调整其处理能力。
2. 前馈网络FFN子块该子块用于通道混合和特征精炼。它由一个完全连接的层、一个深度卷积、一个GELU激活函数以及第二个完全连接的层组成。这些组件一起工作提高了特征的质量并为分类和检测提供了必要的信息。
这两个子块共同构成LSKNet块能够提供大范围的上下文信息同时保持对细节的敏感度这对于遥感目标检测尤其重要。
下面我将为大家展示四种不同的选择性机制模块的架构比较 对于LSK模块
1. 有一个分解步骤似乎是用来处理大尺寸的卷积核Large K。 2. 接着是一个空间选择*步骤可能用于选择或优化空间信息的特定部分。
这与其他三种模型的架构相比较显示了LSK模块在处理空间信息方面可能有其独特的方法。具体来说LSK模块似乎强调了在大尺寸卷积核上进行操作这可能有助于捕获遥感图像中较大范围的上下文信息这对于检测图像中的对象特别有用。空间选择步骤可能进一步增强了模型对于输入空间特征的选择能力从而使其能够更加有效地聚焦于图像的重要部分。 2.2 大型核选择LK Selection子块
LSKNet的大型核选择Large Kernel Selection, LK Selection子块是其架构的核心组成部分之一。这个子块的功能是根据需要动态调整网络的感受野大小。通过这种方式LSKNet能够根据遥感图像中不同对象的大小和上下文范围调整处理这些对象所需的空间信息范围。
大型核选择子块与前馈网络Feed-forward Network, FFN子块一起工作。FFN子块用于通道混合和特征细化它包括一个序列这个序列由一个全连接层、一个深度卷积、一个GELU激活函数以及第二个全连接层组成。这种设计允许LSKNet块进行特征深度融合和增强进一步提升了遥感目标检测的性能。
下面我将通过LSKLarge Selective Kernel模块的概念性插图展示LSKNet如何通过大型核选择子块和空间选择机制来处理遥感数据从而使网络能够适应不同对象的长范围上下文需求。 1. Large Kernel Decomposition原始输入经过大核分解使用两种不同的大型卷积核Large K进行处理以捕获不同尺度的空间信息。
2. Channel Concatenation两个不同的卷积输出和通过通道拼接组合在一起这样可以在后续步骤中同时利用不同的空间特征。
3. Mixed Pooling拼接后的特征图经过平均池化和最大池化的组合操作然后与自注意力SA机制一起使用以进一步强化特征图的关键区域。
4. Convolution and Spatial Selection通过卷积操作和自注意力SA生成新的特征图然后通过空间选择机制进一步增强对目标区域的关注。
5. Element Product and Sigmoid使用Sigmoid函数生成一个掩码然后将这个掩码与特征图进行元素乘积操作得到最终的输出特征图。这一步骤用于加权特征图中更重要的区域以增强网络对遥感图像中特定对象的检测能力。
整个LSK模块的设计强调了对遥感图像中不同空间尺度和上下文信息的有效捕获这对于在复杂背景下准确检测小型或密集排布的目标至关重要。通过上述步骤的复合操作LSK模块能够提升遥感目标检测的性能。 2.3 前馈网络FFN子块
LSKNet的前馈网络Feed-forward Network, FFN子块用于通道混合和特征精炼。该子块包含以下组成部分
1. 全连接层用于特征变换提供网络额外的学习能力。2. 深度卷积depth-wise convolution用于在通道间独立地应用空间滤波减少参数量的同时保持效果。3. GELU激活函数一种高斯误差线性单元用于引入非线性提高模型的表达能力。4. 第二个全连接层进一步变换和精炼特征。
这个FFN子块紧随LK Selection子块之后作用是在保持特征空间信息的同时增强网络在特征通道上的表示能力。通过这种设计FFN子块有效地对输入特征进行了深度加工提升了最终特征的质量从而有助于提高整个网络在遥感目标检测任务中的性能。 三、LSKNet核心代码
将此代码复制粘贴到ultralytics/nn/modules目录下新建一个py文件我这里起名字为LSKNet.py然后把代码复制粘贴进去即可使用教程看章节四。
import torch
import torch.nn as nn
from torch.nn.modules.utils import _pair as to_2tuple
from timm.models.layers import DropPath, to_2tuple
from functools import partial
import warningsclass Mlp(nn.Module):def __init__(self, in_features, hidden_featuresNone, out_featuresNone, act_layernn.GELU, drop0.):super().__init__()out_features out_features or in_featureshidden_features hidden_features or in_featuresself.fc1 nn.Conv2d(in_features, hidden_features, 1)self.dwconv DWConv(hidden_features)self.act act_layer()self.fc2 nn.Conv2d(hidden_features, out_features, 1)self.drop nn.Dropout(drop)def forward(self, x):x self.fc1(x)x self.dwconv(x)x self.act(x)x self.drop(x)x self.fc2(x)x self.drop(x)return xclass LSKblock(nn.Module):def __init__(self, dim):super().__init__()self.conv0 nn.Conv2d(dim, dim, 5, padding2, groupsdim)self.conv_spatial nn.Conv2d(dim, dim, 7, stride1, padding9, groupsdim, dilation3)self.conv1 nn.Conv2d(dim, dim // 2, 1)self.conv2 nn.Conv2d(dim, dim // 2, 1)self.conv_squeeze nn.Conv2d(2, 2, 7, padding3)self.conv nn.Conv2d(dim // 2, dim, 1)def forward(self, x):attn1 self.conv0(x)attn2 self.conv_spatial(attn1)attn1 self.conv1(attn1)attn2 self.conv2(attn2)attn torch.cat([attn1, attn2], dim1)avg_attn torch.mean(attn, dim1, keepdimTrue)max_attn, _ torch.max(attn, dim1, keepdimTrue)agg torch.cat([avg_attn, max_attn], dim1)sig self.conv_squeeze(agg).sigmoid()attn attn1 * sig[:, 0, :, :].unsqueeze(1) attn2 * sig[:, 1, :, :].unsqueeze(1)attn self.conv(attn)return x * attnclass Attention(nn.Module):def __init__(self, d_model):super().__init__()self.proj_1 nn.Conv2d(d_model, d_model, 1)self.activation nn.GELU()self.spatial_gating_unit LSKblock(d_model)self.proj_2 nn.Conv2d(d_model, d_model, 1)def forward(self, x):shorcut x.clone()x self.proj_1(x)x self.activation(x)x self.spatial_gating_unit(x)x self.proj_2(x)x x shorcutreturn xclass Block(nn.Module):def __init__(self, dim, mlp_ratio4., drop0., drop_path0., act_layernn.GELU, norm_cfgNone):super().__init__()if norm_cfg:self.norm1 nn.BatchNorm2d(norm_cfg, dim)self.norm2 nn.BatchNorm2d(norm_cfg, dim)else:self.norm1 nn.BatchNorm2d(dim)self.norm2 nn.BatchNorm2d(dim)self.attn Attention(dim)self.drop_path DropPath(drop_path) if drop_path 0. else nn.Identity()mlp_hidden_dim int(dim * mlp_ratio)self.mlp Mlp(in_featuresdim, hidden_featuresmlp_hidden_dim, act_layeract_layer, dropdrop)layer_scale_init_value 1e-2self.layer_scale_1 nn.Parameter(layer_scale_init_value * torch.ones((dim)), requires_gradTrue)self.layer_scale_2 nn.Parameter(layer_scale_init_value * torch.ones((dim)), requires_gradTrue)def forward(self, x):x x self.drop_path(self.layer_scale_1.unsqueeze(-1).unsqueeze(-1) * self.attn(self.norm1(x)))x x self.drop_path(self.layer_scale_2.unsqueeze(-1).unsqueeze(-1) * self.mlp(self.norm2(x)))return xclass OverlapPatchEmbed(nn.Module): Image to Patch Embeddingdef __init__(self, img_size224, patch_size7, stride4, in_chans3, embed_dim768, norm_cfgNone):super().__init__()patch_size to_2tuple(patch_size)self.proj nn.Conv2d(in_chans, embed_dim, kernel_sizepatch_size, stridestride,padding(patch_size[0] // 2, patch_size[1] // 2))if norm_cfg:self.norm nn.BatchNorm2d(norm_cfg, embed_dim)else:self.norm nn.BatchNorm2d(embed_dim)def forward(self, x):x self.proj(x)_, _, H, W x.shapex self.norm(x)return x, H, Wclass LSKNet(nn.Module):def __init__(self, img_size224, in_chans3, dimNone, embed_dims[64, 128, 256, 512],mlp_ratios[8, 8, 4, 4], drop_rate0., drop_path_rate0., norm_layerpartial(nn.LayerNorm, eps1e-6),depths[3, 4, 6, 3], num_stages4,pretrainedNone,init_cfgNone,norm_cfgNone):super().__init__()assert not (init_cfg and pretrained), \init_cfg and pretrained cannot be set at the same timeif isinstance(pretrained, str):warnings.warn(DeprecationWarning: pretrained is deprecated, please use init_cfg instead)self.init_cfg dict(typePretrained, checkpointpretrained)elif pretrained is not None:raise TypeError(pretrained must be a str or None)self.depths depthsself.num_stages num_stagesdpr [x.item() for x in torch.linspace(0, drop_path_rate, sum(depths))] # stochastic depth decay rulecur 0for i in range(num_stages):patch_embed OverlapPatchEmbed(img_sizeimg_size if i 0 else img_size // (2 ** (i 1)),patch_size7 if i 0 else 3,stride4 if i 0 else 2,in_chansin_chans if i 0 else embed_dims[i - 1],embed_dimembed_dims[i], norm_cfgnorm_cfg)block nn.ModuleList([Block(dimembed_dims[i], mlp_ratiomlp_ratios[i], dropdrop_rate, drop_pathdpr[cur j], norm_cfgnorm_cfg)for j in range(depths[i])])norm norm_layer(embed_dims[i])cur depths[i]setattr(self, fpatch_embed{i 1}, patch_embed)setattr(self, fblock{i 1}, block)setattr(self, fnorm{i 1}, norm)self.width_list [i.size(1) for i in self.forward(torch.randn(1, 3, 640, 640))]def freeze_patch_emb(self):self.patch_embed1.requires_grad Falsetorch.jit.ignoredef no_weight_decay(self):return {pos_embed1, pos_embed2, pos_embed3, pos_embed4, cls_token} # has pos_embed may be betterdef get_classifier(self):return self.headdef reset_classifier(self, num_classes, global_pool):self.num_classes num_classesself.head nn.Linear(self.embed_dim, num_classes) if num_classes 0 else nn.Identity()def forward_features(self, x):B x.shape[0]outs []for i in range(self.num_stages):patch_embed getattr(self, fpatch_embed{i 1})block getattr(self, fblock{i 1})norm getattr(self, fnorm{i 1})x, H, W patch_embed(x)for blk in block:x blk(x)x x.flatten(2).transpose(1, 2)x norm(x)x x.reshape(B, H, W, -1).permute(0, 3, 1, 2).contiguous()outs.append(x)return outsdef forward(self, x):x self.forward_features(x)# x self.head(x)return xclass DWConv(nn.Module):def __init__(self, dim768):super(DWConv, self).__init__()self.dwconv nn.Conv2d(dim, dim, 3, 1, 1, biasTrue, groupsdim)def forward(self, x):x self.dwconv(x)return xdef _conv_filter(state_dict, patch_size16): convert patch embedding weight from manual patchify linear proj to convout_dict {}for k, v in state_dict.items():if patch_embed.proj.weight in k:v v.reshape((v.shape[0], 3, patch_size, patch_size))out_dict[k] vreturn out_dictdef LSKNET_Tiny():model LSKNet(depths [2, 2, 2, 2])return modelif __name__ __main__:model LSKNet()inputs torch.randn((1, 3, 640, 640))for i in model(inputs):print(i.size()) 四、手把手教你添加LSKNet机制
下面教大家如何修改该网络结构主干网络结构的修改步骤比较复杂我也会将task.py文件上传到CSDN的文件中大家如果自己修改不正确可以尝试用我的task.py文件替换你的然后只需要修改其中的第1、2、3、5步即可。
⭐修改过程中大家一定要仔细⭐ 4.1 修改一
首先我门中到如下“ultralytics/nn”的目录我们在这个目录下在创建一个新的目录名字为Addmodules此文件之后就用于存放我们的所有改进机制之后我们在创建的目录内创建一个新的py文件复制粘贴进去 可以根据文章改进机制来起这里大家根据自己的习惯命名即可。 4.2 修改二
第二步我们在我们创建的目录内创建一个新的py文件名字为__init__.py只需要创建一个即可然后在其内部导入我们本文的改进机制即可其余代码均为未发大家没有不用理会。 4.3 修改三
第三步我门中到如下文件ultralytics/nn/tasks.py然后在开头导入我们的所有改进机制如果你用了我多个改进机制这一步只需要修改一次即可。 4.4 修改四
添加如下两行代码
4.5 修改五
找到七百多行大概把具体看图片按照图片来修改就行添加红框内的部分注意没有()只是函数名此处我的文件里已经添加很多了后期都会发出来大家没有的不用理会即可。 elif m in {自行添加对应的模型即可下面都是一样的}:m m(*args)c2 m.width_list # 返回通道列表backbone True 4.6 修改六
用下面的代码替换红框内的内容。
if isinstance(c2, list):m_ mm_.backbone True
else:m_ nn.Sequential(*(m(*args) for _ in range(n))) if n 1 else m(*args) # modulet str(m)[8:-2].replace(__main__., ) # module type
m.np sum(x.numel() for x in m_.parameters()) # number params
m_.i, m_.f, m_.type i 4 if backbone else i, f, t # attach index, from index, type
if verbose:LOGGER.info(f{i:3}{str(f):20}{n_:3}{m.np:10.0f} {t:45}{str(args):30}) # print
save.extend(x % (i 4 if backbone else i) for x in ([f] if isinstance(f, int) else f) if x ! -1) # append to savelist
layers.append(m_)
if i 0:ch []
if isinstance(c2, list):ch.extend(c2)if len(c2) ! 5:ch.insert(0, 0)
else:ch.append(c2) 4.7 修改七
修改七这里非常要注意不是文件开头YOLOv8的那predict是400行的RTDETR的predict初始模型如下用我给的代码替换即可
代码如下- def predict(self, x, profileFalse, visualizeFalse, batchNone, augmentFalse, embedNone):Perform a forward pass through the model.Args:x (torch.Tensor): The input tensor.profile (bool, optional): If True, profile the computation time for each layer. Defaults to False.visualize (bool, optional): If True, save feature maps for visualization. Defaults to False.batch (dict, optional): Ground truth data for evaluation. Defaults to None.augment (bool, optional): If True, perform data augmentation during inference. Defaults to False.embed (list, optional): A list of feature vectors/embeddings to return.Returns:(torch.Tensor): Models output tensor.y, dt, embeddings [], [], [] # outputsfor m in self.model[:-1]: # except the head partif m.f ! -1: # if not from previous layerx y[m.f] if isinstance(m.f, int) else [x if j -1 else y[j] for j in m.f] # from earlier layersif profile:self._profile_one_layer(m, x, dt)if hasattr(m, backbone):x m(x)if len(x) ! 5: # 0 - 5x.insert(0, None)for index, i in enumerate(x):if index in self.save:y.append(i)else:y.append(None)x x[-1] # 最后一个输出传给下一层else:x m(x) # runy.append(x if m.i in self.save else None) # save outputif visualize:feature_visualization(x, m.type, m.i, save_dirvisualize)if embed and m.i in embed:embeddings.append(nn.functional.adaptive_avg_pool2d(x, (1, 1)).squeeze(-1).squeeze(-1)) # flattenif m.i max(embed):return torch.unbind(torch.cat(embeddings, 1), dim0)head self.model[-1]x head([y[j] for j in head.f], batch) # head inferencereturn x 4.8 修改八
我们将下面的s用640替换即可这一步也是部分的主干可以不修改但有的不修改就会报错所以我们还是修改一下。 4.9 RT-DETR不能打印计算量问题的解决
计算的GFLOPs计算异常不打印所以需要额外修改一处 我们找到如下文件ultralytics/utils/torch_utils.py文件内有如下的代码按照如下的图片进行修改大家看好函数就行其中红框的640可能和你的不一样 然后用我给的代码替换掉整个代码即可。 def get_flops(model, imgsz640):Return a YOLO models FLOPs.try:model de_parallel(model)p next(model.parameters())# stride max(int(model.stride.max()), 32) if hasattr(model, stride) else 32 # max stridestride 640im torch.empty((1, 3, stride, stride), devicep.device) # input image in BCHW formatflops thop.profile(deepcopy(model), inputs[im], verboseFalse)[0] / 1E9 * 2 if thop else 0 # stride GFLOPsimgsz imgsz if isinstance(imgsz, list) else [imgsz, imgsz] # expand if int/floatreturn flops * imgsz[0] / stride * imgsz[1] / stride # 640x640 GFLOPsexcept Exception:return 04.10 可选修改
有些读者的数据集部分图片比较特殊在验证的时候会导致形状不匹配的报错如果大家在验证的时候报错形状不匹配的错误可以固定验证集的图片尺寸方法如下 -
找到下面这个文件ultralytics/models/yolo/detect/train.py然后其中有一个类是DetectionTrainer class中的build_dataset函数中的一个参数rectmode val改为rectFalse 五、LSKNet的yaml文件
5.1 yaml文件
大家复制下面的yaml文件然后通过我给大家的运行代码运行即可RT-DETR的调参部分需要后面的文章给大家讲现在目前免费给大家看这一部分不开放。
# Ultralytics YOLO , AGPL-3.0 license
# RT-DETR-l object detection model with P3-P5 outputs. For details see https://docs.ultralytics.com/models/rtdetr# Parameters
nc: 80 # number of classes
scales: # model compound scaling constants, i.e. modelyolov8n-cls.yaml will call yolov8-cls.yaml with scale n# [depth, width, max_channels]l: [1.00, 1.00, 1024]backbone:# [from, repeats, module, args]- [-1, 1, LSKNET_Tiny, []] # 4head:- [-1, 1, Conv, [256, 1, 1, None, 1, 1, False]] # 5 input_proj.2- [-1, 1, AIFI, [1024, 8]] # 6- [-1, 1, Conv, [256, 1, 1]] # 7, Y5, lateral_convs.0- [-1, 1, nn.Upsample, [None, 2, nearest]] # 8- [3, 1, Conv, [256, 1, 1, None, 1, 1, False]] # 9 input_proj.1- [[-2, -1], 1, Concat, [1]] # 10- [-1, 3, RepC3, [256, 0.5]] # 11, fpn_blocks.0- [-1, 1, Conv, [256, 1, 1]] # 12, Y4, lateral_convs.1- [-1, 1, nn.Upsample, [None, 2, nearest]] # 13- [2, 1, Conv, [256, 1, 1, None, 1, 1, False]] # 14 input_proj.0- [[-2, -1], 1, Concat, [1]] # 15 cat backbone P4- [-1, 3, RepC3, [256, 0.5]] # X3 (16), fpn_blocks.1- [-1, 1, Conv, [256, 3, 2]] # 17, downsample_convs.0- [[-1, 12], 1, Concat, [1]] # 18 cat Y4- [-1, 3, RepC3, [256, 0.5]] # F4 (19), pan_blocks.0- [-1, 1, Conv, [256, 3, 2]] # 20, downsample_convs.1- [[-1, 7], 1, Concat, [1]] # 21 cat Y5- [-1, 3, RepC3, [256, 0.5]] # F5 (22), pan_blocks.1- [[16, 19, 22], 1, RTDETRDecoder, [nc, 256, 300, 4, 8, 3]] # Detect(P3, P4, P5)5.2 运行文件
大家可以创建一个train.py文件将下面的代码粘贴进去然后替换你的文件运行即可开始训练。
import warnings
from ultralytics import RTDETR
warnings.filterwarnings(ignore)if __name__ __main__:model RTDETR(替换你想要运行的yaml文件)# model.load() # 可以加载你的版本预训练权重model.train(datar替换你的数据集地址即可,cacheFalse,imgsz640,epochs72,batch4,workers0,device0,projectruns/RT-DETR-train,nameexp,# ampTrue) 5.3 成功训练截图
下面是成功运行的截图确保我的改进机制是可用的已经完成了有1个epochs的训练图片太大截不全第2个epochs了。 六、全文总结
从今天开始正式开始更新RT-DETR剑指论文专栏本专栏的内容会迅速铺开在短期呢大量更新价格也会乘阶梯性上涨所以想要和我一起学习RT-DETR改进可以在前期直接关注本文专栏旨在打造全网最好的RT-DETR专栏为想要发论文的家进行服务。 专栏链接RT-DETR剑指论文专栏持续复现各种顶会内容——论文收割机RT-DETR