【RT-DETR有效改进】交叉形窗口网络 | CSWinTransformer(附代码 + 修改教程)

news2024/9/25 1:13:51

前言

大家好,我是Snu77,这里是RT-DETR有效涨点专栏

本专栏的内容为根据ultralytics版本的RT-DETR进行改进,内容持续更新,每周更新文章数量3-10篇。

专栏以ResNet18、ResNet50为基础修改版本,同时修改内容也支持ResNet32、ResNet101和PPHGNet版本,其中ResNet为RT-DETR官方版本1:1移植过来的,参数量基本保持一致(误差很小很小),不同于ultralytics仓库版本的ResNet官方版本,同时ultralytics仓库的一些参数是和RT-DETR相冲的所以我也是会教大家调好一些参数和代码,真正意义上的跑ultralytics的和RT-DETR官方版本的无区别

👑欢迎大家订阅本专栏,一起学习RT-DETR👑  

 一、本文介绍

本文给大家带来的改进机制是CSWin Transformer其基于Transformer架构,创新性地引入了交叉形窗口自注意力机制,用于有效地并行处理图像的水平和垂直条带,形成交叉形窗口以提高计算效率。它还提出了局部增强位置编码(LePE),更好地处理局部位置信息,我将其替换RT-DETR的特征提取网络,用于提取更有用的特征。经过我的实验该主干网络确实能够涨点在大中小三种物体检测上,同时该主干网络也提供多种版本,大家可以在源代码中进行修改版本的使用。本文通过介绍其主要框架原理,然后教大家如何添加该网络结构到网络模型中。

推荐指数:⭐⭐⭐⭐

涨点效果:⭐⭐⭐⭐

 专栏链接:RT-DETR剑指论文专栏,持续复现各种顶会内容——论文收割机RT-DETR

目录

 一、本文介绍

二、CSWin Transformer原理

2.1 CSWin Transformer的基本原理

2.2 交叉形窗口自注意力

2.3 局部增强位置编码

2.4 下游任务友好

三、CSwinTransformer的核心代码

 四、手把手教你添加CSWin Transformer机制

4.1 修改一

4.2 修改二 

4.3 修改三 

4.4 修改四

4.5 修改五

4.6 修改六

4.7 修改七 

4.8 修改八

4.9 RT-DETR不能打印计算量问题的解决

4.10 可选修改

五、CSwinTransformer的yaml文件

5.1 yaml文件

5.2 运行文件

5.3 成功训练截图

六、全文总结


二、CSWin Transformer原理

论文地址:论文官方地址

代码地址:官方代码地址


2.1 CSWin Transformer的基本原理

CSWin Transformer基于Transformer架构,创新性地引入了交叉形窗口自注意力机制,用于有效地并行处理图像的水平和垂直条带,形成交叉形窗口以提高计算效率。它还提出了局部增强位置编码(LePE),更好地处理局部位置信息,支持任意输入分辨率,并对下游任务友好。这些创新使CSWin Transformer在视觉任务上,如图像分类和目标检测,显示出优于现有技术的性能。

CSWin Transformer 的基本原理可以总结如下:

1. 交叉形窗口自注意力:创新地采用了在水平和垂直方向上形成交叉形窗口的自注意力机制,提高了处理效率。
2. 局部增强位置编码(LePE):新颖的位置编码方案,更好地处理局部位置信息,支持任意大小的输入分辨率。
3. 下游任务友好:LePE使得CSWin Transformer尤其适用于各种后续视觉处理任务。


2.2 交叉形窗口自注意力

交叉形窗口自注意力是CSWin Transformer的核心特征之一,它通过将多头注意力分成两组来并行处理图像的水平和垂直条带。这种机制允许模型在交叉的区域内聚焦重要的特征,同时限制了全局自注意力的高计算成本。这样不仅保持了局部和全局信息的平衡,而且还提高了处理速度和效率。

下图展示了CSWin Transformer中不同自注意力机制的对比:

图解说明了CSWin Transformer如何通过在水平和垂直方向上拆分多头注意力,来并行处理形成交叉窗口结构。CSWin采用了一个创新的自注意力机制,通过将多头注意力拆分成两组来同时处理水平和垂直的条带,形成交叉形窗口。这种设计能够在计算成本和模型性能之间取得更好的平衡。图中展示了从全注意力到局部注意力的不同变体,以及CSWin特有的自注意力策略,这对于提高模型效率和精度都是至关重要的。


2.3 局部增强位置编码

局部增强位置编码(LePE)是CSWin Transformer中的一种新型位置编码机制。它改善了现有编码方案处理局部位置信息的能力。与传统位置编码不同,LePE专门设计来增强模型对于图像局部区域的感知能力,支持任意大小的输入分辨率。这使得CSWin Transformer在处理各种尺寸的输入图像时更为灵活和有效,特别适合各种视觉任务中的下游应用。 

这张图展示了CSWin Transformer的整体架构和其中一个CSWin Transformer块的细节

图中展示了交叉形窗口自注意力局部增强位置编码这两种机制是如何集成在CSWin Transformer的不同阶段中,以及在单个Transformer块中的具体实现。这些设计共同支持了模型在进行视觉任务处理时的高效性和有效性。模型分为四个阶段,每个阶段由多个CSWin Transformer块组成,每个块包含了交叉形窗口自注意力和局部增强位置编码。随着阶段的推进,特征图的维度逐渐增大,通道数也相应增加,这允许网络逐渐捕获更复杂的特征。右侧详细描绘了一个CSWin Transformer块的内部结构,展示了MLP(多层感知机)、LN(层归一化)以及核心的交叉形窗口自注意力机制。 

下面这张图对比了不同的位置编码机制,如APE、CPE、RPE以及CSWin Transformer中采用的LePE。图中展示了LePE是如何直接作用于自注意力机制中的V(值)部分,并且作为一个并行模块存在的。LePE的引入使得位置信息能够更有效地融入到自注意力计算中,与其他位置编码机制相比,它提供了对局部位置信息的更强处理能力。 

LePE的设计允许位置信息更直接地融入到自注意力计算中,与传统的位置编码方法相比,LePE为模型提供了更精细的局部位置感知能力。这在处理视觉任务时是极其有益的,因为它帮助模型更好地理解图像中各个部分的相对位置关系。


2.4 下游任务友好

下游任务友好性是指模型或技术易于被应用于特定任务的后续步骤或进一步的处理中。对于CSWin Transformer,其局部增强位置编码(LePE)的设计支持任意分辨率的输入,使得模型能够更容易地适应不同的视觉任务,如图像分类、目标检测和语义分割。这种灵活性意味着CSWin Transformer可以直接应用于各种不同分辨率的数据集,而无需进行复杂的重新调整或额外的预处理步骤,从而降低了对下游任务的应用难度。


三、CSwinTransformer的核心代码

代码使用方式看章节四

# ------------------------------------------
# CSWin Transformer
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# written By Xiaoyi Dong
# ------------------------------------------
import torch
import torch.nn as nn
from timm.data import IMAGENET_DEFAULT_MEAN, IMAGENET_DEFAULT_STD
from timm.models.layers import DropPath, trunc_normal_
from timm.models.registry import register_model
from einops.layers.torch import Rearrange
import torch.utils.checkpoint as checkpoint
import numpy as np



def _cfg(url='', **kwargs):
    return {
        'url': url,
        'num_classes': 1000, 'input_size': (3, 640, 640), 'pool_size': None,
        'crop_pct': .9, 'interpolation': 'bicubic',
        'mean': IMAGENET_DEFAULT_MEAN, 'std': IMAGENET_DEFAULT_STD,
        'first_conv': 'patch_embed.proj', 'classifier': 'head',
        **kwargs
    }


default_cfgs = {
    'cswin_224': _cfg(),
    'cswin_384': _cfg(
        crop_pct=1.0
    ),

}


class Mlp(nn.Module):
    def __init__(self, in_features, hidden_features=None, out_features=None, act_layer=nn.GELU, drop=0.):
        super().__init__()
        out_features = out_features or in_features
        hidden_features = hidden_features or in_features
        self.fc1 = nn.Linear(in_features, hidden_features)
        self.act = act_layer()
        self.fc2 = nn.Linear(hidden_features, out_features)
        self.drop = nn.Dropout(drop)

    def forward(self, x):
        x = self.fc1(x)
        x = self.act(x)
        x = self.drop(x)
        x = self.fc2(x)
        x = self.drop(x)
        return x


class LePEAttention(nn.Module):
    def __init__(self, dim, resolution, idx, split_size=7, dim_out=None, num_heads=8, attn_drop=0., proj_drop=0.,
                 qk_scale=None):
        super().__init__()
        self.dim = dim
        self.dim_out = dim_out or dim
        self.resolution = resolution
        self.split_size = split_size
        self.num_heads = num_heads
        head_dim = dim // num_heads
        # NOTE scale factor was wrong in my original version, can set manually to be compat with prev weights
        self.scale = qk_scale or head_dim ** -0.5
        if idx == -1:
            H_sp, W_sp = self.resolution, self.resolution
        elif idx == 0:
            H_sp, W_sp = self.resolution, self.split_size
        elif idx == 1:
            W_sp, H_sp = self.resolution, self.split_size
        else:
            print("ERROR MODE", idx)
            exit(0)
        self.H_sp = H_sp
        self.W_sp = W_sp
        stride = 1
        self.get_v = nn.Conv2d(dim, dim, kernel_size=3, stride=1, padding=1, groups=dim)

        self.attn_drop = nn.Dropout(attn_drop)

    def im2cswin(self, x):
        B, N, C = x.shape
        H = W = int(np.sqrt(N))
        x = x.transpose(-2, -1).contiguous().view(B, C, H, W)
        x = img2windows(x, self.H_sp, self.W_sp)
        x = x.reshape(-1, self.H_sp * self.W_sp, self.num_heads, C // self.num_heads).permute(0, 2, 1, 3).contiguous()
        return x

    def get_lepe(self, x, func):
        B, N, C = x.shape
        H = W = int(np.sqrt(N))
        x = x.transpose(-2, -1).contiguous().view(B, C, H, W)

        H_sp, W_sp = self.H_sp, self.W_sp
        x = x.view(B, C, H // H_sp, H_sp, W // W_sp, W_sp)
        x = x.permute(0, 2, 4, 1, 3, 5).contiguous().reshape(-1, C, H_sp, W_sp)  ### B', C, H', W'

        lepe = func(x)  ### B', C, H', W'
        lepe = lepe.reshape(-1, self.num_heads, C // self.num_heads, H_sp * W_sp).permute(0, 1, 3, 2).contiguous()

        x = x.reshape(-1, self.num_heads, C // self.num_heads, self.H_sp * self.W_sp).permute(0, 1, 3, 2).contiguous()
        return x, lepe

    def forward(self, qkv):
        """
        x: B L C
        """
        q, k, v = qkv[0], qkv[1], qkv[2]

        ### Img2Window
        H = W = self.resolution
        B, L, C = q.shape
        assert L == H * W, "flatten img_tokens has wrong size"

        q = self.im2cswin(q)
        k = self.im2cswin(k)
        v, lepe = self.get_lepe(v, self.get_v)

        q = q * self.scale
        attn = (q @ k.transpose(-2, -1))  # B head N C @ B head C N --> B head N N
        attn = nn.functional.softmax(attn, dim=-1, dtype=attn.dtype)
        attn = self.attn_drop(attn)

        x = (attn @ v) + lepe
        x = x.transpose(1, 2).reshape(-1, self.H_sp * self.W_sp, C)  # B head N N @ B head N C

        ### Window2Img
        x = windows2img(x, self.H_sp, self.W_sp, H, W).view(B, -1, C)  # B H' W' C

        return x


class CSWinBlock(nn.Module):

    def __init__(self, dim, reso, num_heads,
                 split_size=7, mlp_ratio=4., qkv_bias=False, qk_scale=None,
                 drop=0., attn_drop=0., drop_path=0.,
                 act_layer=nn.GELU, norm_layer=nn.LayerNorm,
                 last_stage=False):
        super().__init__()
        self.dim = dim
        self.num_heads = num_heads
        self.patches_resolution = reso
        self.split_size = split_size
        self.mlp_ratio = mlp_ratio
        self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)
        self.norm1 = norm_layer(dim)

        if self.patches_resolution == split_size:
            last_stage = True
        if last_stage:
            self.branch_num = 1
        else:
            self.branch_num = 2
        self.proj = nn.Linear(dim, dim)
        self.proj_drop = nn.Dropout(drop)

        if last_stage:
            self.attns = nn.ModuleList([
                LePEAttention(
                    dim, resolution=self.patches_resolution, idx=-1,
                    split_size=split_size, num_heads=num_heads, dim_out=dim,
                    qk_scale=qk_scale, attn_drop=attn_drop, proj_drop=drop)
                for i in range(self.branch_num)])
        else:
            self.attns = nn.ModuleList([
                LePEAttention(
                    dim // 2, resolution=self.patches_resolution, idx=i,
                    split_size=split_size, num_heads=num_heads // 2, dim_out=dim // 2,
                    qk_scale=qk_scale, attn_drop=attn_drop, proj_drop=drop)
                for i in range(self.branch_num)])

        mlp_hidden_dim = int(dim * mlp_ratio)

        self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()
        self.mlp = Mlp(in_features=dim, hidden_features=mlp_hidden_dim, out_features=dim, act_layer=act_layer,
                       drop=drop)
        self.norm2 = norm_layer(dim)

    def forward(self, x):
        """
        x: B, H*W, C
        """

        H = W = self.patches_resolution
        B, L, C = x.shape
        assert L == H * W, "flatten img_tokens has wrong size"
        img = self.norm1(x)
        qkv = self.qkv(img).reshape(B, -1, 3, C).permute(2, 0, 1, 3)

        if self.branch_num == 2:
            x1 = self.attns[0](qkv[:, :, :, :C // 2])
            x2 = self.attns[1](qkv[:, :, :, C // 2:])
            attened_x = torch.cat([x1, x2], dim=2)
        else:
            attened_x = self.attns[0](qkv)
        attened_x = self.proj(attened_x)
        x = x + self.drop_path(attened_x)
        x = x + self.drop_path(self.mlp(self.norm2(x)))

        return x


def img2windows(img, H_sp, W_sp):
    """
    img: B C H W
    """
    B, C, H, W = img.shape
    img_reshape = img.view(B, C, H // H_sp, H_sp, W // W_sp, W_sp)
    img_perm = img_reshape.permute(0, 2, 4, 3, 5, 1).contiguous().reshape(-1, H_sp * W_sp, C)
    return img_perm


def windows2img(img_splits_hw, H_sp, W_sp, H, W):
    """
    img_splits_hw: B' H W C
    """
    B = int(img_splits_hw.shape[0] / (H * W / H_sp / W_sp))

    img = img_splits_hw.view(B, H // H_sp, W // W_sp, H_sp, W_sp, -1)
    img = img.permute(0, 1, 3, 2, 4, 5).contiguous().view(B, H, W, -1)
    return img


class Merge_Block(nn.Module):
    def __init__(self, dim, dim_out, norm_layer=nn.LayerNorm):
        super().__init__()
        self.conv = nn.Conv2d(dim, dim_out, 3, 2, 1)
        self.norm = norm_layer(dim_out)

    def forward(self, x):
        B, new_HW, C = x.shape
        H = W = int(np.sqrt(new_HW))
        x = x.transpose(-2, -1).contiguous().view(B, C, H, W)
        x = self.conv(x)
        B, C = x.shape[:2]
        x = x.view(B, C, -1).transpose(-2, -1).contiguous()
        x = self.norm(x)

        return x


class CSWinTransformer(nn.Module):
    """ Vision Transformer with support for patch or hybrid CNN input stage
    """

    def __init__(self, img_size=640, patch_size=16, in_chans=3, num_classes=1000, embed_dim=96, depth=[2, 2, 6, 2],
                 split_size=[3, 5, 7],
                 num_heads=12, mlp_ratio=4., qkv_bias=True, qk_scale=None, drop_rate=0., attn_drop_rate=0.,
                 drop_path_rate=0., hybrid_backbone=None, norm_layer=nn.LayerNorm, use_chk=False):
        super().__init__()
        self.use_chk = use_chk
        self.num_classes = num_classes
        self.num_features = self.embed_dim = embed_dim  # num_features for consistency with other models
        heads = num_heads

        self.stage1_conv_embed = nn.Sequential(
            nn.Conv2d(in_chans, embed_dim, 7, 4, 2),
            Rearrange('b c h w -> b (h w) c', h=img_size // 4, w=img_size // 4),
            nn.LayerNorm(embed_dim)
        )

        curr_dim = embed_dim
        dpr = [x.item() for x in torch.linspace(0, drop_path_rate, np.sum(depth))]  # stochastic depth decay rule
        self.stage1 = nn.ModuleList([
            CSWinBlock(
                dim=curr_dim, num_heads=heads[0], reso=img_size // 4, mlp_ratio=mlp_ratio,
                qkv_bias=qkv_bias, qk_scale=qk_scale, split_size=split_size[0],
                drop=drop_rate, attn_drop=attn_drop_rate,
                drop_path=dpr[i], norm_layer=norm_layer)
            for i in range(depth[0])])

        self.merge1 = Merge_Block(curr_dim, curr_dim * 2)
        curr_dim = curr_dim * 2
        self.stage2 = nn.ModuleList(
            [CSWinBlock(
                dim=curr_dim, num_heads=heads[1], reso=img_size // 8, mlp_ratio=mlp_ratio,
                qkv_bias=qkv_bias, qk_scale=qk_scale, split_size=split_size[1],
                drop=drop_rate, attn_drop=attn_drop_rate,
                drop_path=dpr[np.sum(depth[:1]) + i], norm_layer=norm_layer)
                for i in range(depth[1])])

        self.merge2 = Merge_Block(curr_dim, curr_dim * 2)
        curr_dim = curr_dim * 2
        temp_stage3 = []
        temp_stage3.extend(
            [CSWinBlock(
                dim=curr_dim, num_heads=heads[2], reso=img_size // 16, mlp_ratio=mlp_ratio,
                qkv_bias=qkv_bias, qk_scale=qk_scale, split_size=split_size[2],
                drop=drop_rate, attn_drop=attn_drop_rate,
                drop_path=dpr[np.sum(depth[:2]) + i], norm_layer=norm_layer)
                for i in range(depth[2])])

        self.stage3 = nn.ModuleList(temp_stage3)

        self.merge3 = Merge_Block(curr_dim, curr_dim * 2)
        curr_dim = curr_dim * 2
        self.stage4 = nn.ModuleList(
            [CSWinBlock(
                dim=curr_dim, num_heads=heads[3], reso=img_size // 32, mlp_ratio=mlp_ratio,
                qkv_bias=qkv_bias, qk_scale=qk_scale, split_size=split_size[-1],
                drop=drop_rate, attn_drop=attn_drop_rate,
                drop_path=dpr[np.sum(depth[:-1]) + i], norm_layer=norm_layer, last_stage=True)
                for i in range(depth[-1])])

        self.norm = norm_layer(curr_dim)
        # Classifier head
        self.head = nn.Linear(curr_dim, num_classes) if num_classes > 0 else nn.Identity()

        trunc_normal_(self.head.weight, std=0.02)
        self.apply(self._init_weights)
        self.width_list = [i.size(1) for i in self.forward(torch.randn(1, 3, 640, 640))]
    def _init_weights(self, m):
        if isinstance(m, nn.Linear):
            trunc_normal_(m.weight, std=.02)
            if isinstance(m, nn.Linear) and m.bias is not None:
                nn.init.constant_(m.bias, 0)
        elif isinstance(m, (nn.LayerNorm, nn.BatchNorm2d)):
            nn.init.constant_(m.bias, 0)
            nn.init.constant_(m.weight, 1.0)

    @torch.jit.ignore
    def no_weight_decay(self):
        return {'pos_embed', 'cls_token'}

    def get_classifier(self):
        return self.head

    def reset_classifier(self, num_classes, global_pool=''):
        if self.num_classes != num_classes:
            print('reset head to', num_classes)
            self.num_classes = num_classes
            self.head = nn.Linear(self.out_dim, num_classes) if num_classes > 0 else nn.Identity()
            self.head = self.head.cuda()
            trunc_normal_(self.head.weight, std=.02)
            if self.head.bias is not None:
                nn.init.constant_(self.head.bias, 0)

    def forward(self, x):
        B = x.shape[0]
        x = self.stage1_conv_embed(x)
        unique_tensors = {}
        for blk in self.stage1:
            if self.use_chk:
                x = checkpoint.checkpoint(blk, x)
            else:
                x = blk(x)
                y = x.reshape((x.size(0), x.size(2), int(x.size(1) ** 0.5), int(x.size(1) ** 0.5)))
                width, height = y.shape[2], y.shape[3]
                unique_tensors[(width, height)] = y
        for pre, blocks in zip([self.merge1, self.merge2, self.merge3],
                               [self.stage2, self.stage3, self.stage4]):
            x = pre(x)
            for blk in blocks:
                if self.use_chk:
                    x = checkpoint.checkpoint(blk, x)
                    y = x.reshape((x.size(0), x.size(2), int(x.size(1) ** 0.5), int(x.size(1) ** 0.5)))
                    width, height = y.shape[2], y.shape[3]
                    unique_tensors[(width, height)] = y
                else:
                    x = blk(x)
                    y = x.reshape((x.size(0), x.size(2), int(x.size(1) ** 0.5), int(x.size(1) ** 0.5)))
                    width, height = y.shape[2], y.shape[3]
                    unique_tensors[(width, height)] = y
        result_list = list(unique_tensors.values())[-4:]
        return result_list

def _conv_filter(state_dict, patch_size=16):
    """ convert patch embedding weight from manual patchify + linear proj to conv"""
    out_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] = v
    return out_dict


### 224 models

@register_model
def CSWin_64_12211_tiny_224(pretrained=False, **kwargs):
    model = CSWinTransformer(patch_size=4, embed_dim=64, depth=[1, 2, 21, 1],
                             split_size=[1, 2, 8, 8], num_heads=[2, 4, 8, 16], mlp_ratio=4., **kwargs)
    model.default_cfg = default_cfgs['cswin_224']
    return model


@register_model
def CSWin_64_24322_small_224(pretrained=False, **kwargs):
    model = CSWinTransformer(patch_size=4, embed_dim=64, depth=[2, 4, 32, 2],
                             split_size=[1, 2, 8, 8], num_heads=[2, 4, 8, 16], mlp_ratio=4., **kwargs)
    model.default_cfg = default_cfgs['cswin_224']
    return model


@register_model
def CSWin_96_24322_base_224(pretrained=False, **kwargs):
    model = CSWinTransformer(patch_size=4, embed_dim=96, depth=[2, 4, 32, 2],
                             split_size=[1, 2, 8, 8], num_heads=[4, 8, 16, 32], mlp_ratio=4., **kwargs)
    model.default_cfg = default_cfgs['cswin_224']
    return model


@register_model
def CSWin_144_24322_large_224(pretrained=False, **kwargs):
    model = CSWinTransformer(patch_size=4, embed_dim=144, depth=[2, 4, 32, 2],
                             split_size=[1, 2, 8, 8], num_heads=[6, 12, 24, 24], mlp_ratio=4., **kwargs)
    model.default_cfg = default_cfgs['cswin_224']
    return model



if __name__ == "__main__":

    # Generating Sample image
    image_size = (1, 3, 640, 640)
    image = torch.rand(*image_size)

    # Model
    model = CSWin_64_24322_small_224()

    out = model(image)
    print(len(out))


 四、手把手教你添加CSWin Transformer机制

下面教大家如何修改该网络结构,主干网络结构的修改步骤比较复杂,我也会将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_ = m
    m_.backbone = True
else:
    m_ = nn.Sequential(*(m(*args) for _ in range(n))) if n > 1 else m(*args)  # module
    t = 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, profile=False, visualize=False, batch=None, augment=False, embed=None):
        """
        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): Model's output tensor.
        """
        y, dt, embeddings = [], [], []  # outputs
        for m in self.model[:-1]:  # except the head part
            if m.f != -1:  # if not from previous layer
                x = y[m.f] if isinstance(m.f, int) else [x if j == -1 else y[j] for j in m.f]  # from earlier layers
            if profile:
                self._profile_one_layer(m, x, dt)
            if hasattr(m, 'backbone'):
                x = m(x)
                if len(x) != 5:  # 0 - 5
                    x.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)  # run
                y.append(x if m.i in self.save else None)  # save output
            if visualize:
                feature_visualization(x, m.type, m.i, save_dir=visualize)
            if embed and m.i in embed:
                embeddings.append(nn.functional.adaptive_avg_pool2d(x, (1, 1)).squeeze(-1).squeeze(-1))  # flatten
                if m.i == max(embed):
                    return torch.unbind(torch.cat(embeddings, 1), dim=0)
        head = self.model[-1]
        x = head([y[j] for j in head.f], batch)  # head inference
        return x

4.8 修改八

我们将下面的s用640替换即可,这一步也是部分的主干可以不修改,但有的不修改就会报错,所以我们还是修改一下。


4.9 RT-DETR不能打印计算量问题的解决

计算的GFLOPs计算异常不打印,所以需要额外修改一处, 我们找到如下文件'ultralytics/utils/torch_utils.py'文件内有如下的代码按照如下的图片进行修改,大家看好函数就行,其中红框的640可能和你的不一样, 然后用我给的代码替换掉整个代码即可。

def get_flops(model, imgsz=640):
    """Return a YOLO model's FLOPs."""
    try:
        model = de_parallel(model)
        p = next(model.parameters())
        # stride = max(int(model.stride.max()), 32) if hasattr(model, 'stride') else 32  # max stride
        stride = 640
        im = torch.empty((1, 3, stride, stride), device=p.device)  # input image in BCHW format
        flops = thop.profile(deepcopy(model), inputs=[im], verbose=False)[0] / 1E9 * 2 if thop else 0  # stride GFLOPs
        imgsz = imgsz if isinstance(imgsz, list) else [imgsz, imgsz]  # expand if int/float
        return flops * imgsz[0] / stride * imgsz[1] / stride  # 640x640 GFLOPs
    except Exception:
        return 0


4.10 可选修改

有些读者的数据集部分图片比较特殊,在验证的时候会导致形状不匹配的报错,如果大家在验证的时候报错形状不匹配的错误可以固定验证集的图片尺寸,方法如下 ->

找到下面这个文件ultralytics/models/yolo/detect/train.py然后其中有一个类是DetectionTrainer class中的build_dataset函数中的一个参数rect=mode == 'val'改为rect=False


五、CSwinTransformer的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. 'model=yolov8n-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, CSWin_64_12211_tiny_224, []]  # 4

head:
  - [-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(data=r'替换你的数据集地址即可',
                cache=False,
                imgsz=640,
                epochs=72,
                batch=4,
                workers=0,
                device='0',
                project='runs/RT-DETR-train',
                name='exp',
                # amp=True
                )


5.3 成功训练截图

下面是成功运行的截图(确保我的改进机制是可用的),已经完成了有1个epochs的训练,图片太大截不全第2个epochs了。 


六、全文总结

从今天开始正式开始更新RT-DETR剑指论文专栏,本专栏的内容会迅速铺开,在短期呢大量更新,价格也会乘阶梯性上涨,所以想要和我一起学习RT-DETR改进,可以在前期直接关注,本文专栏旨在打造全网最好的RT-DETR专栏为想要发论文的家进行服务。

 专栏链接:RT-DETR剑指论文专栏,持续复现各种顶会内容——论文收割机RT-DETR

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1408789.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【GitHub项目推荐--一款美观的开源社区系统】【转载】

推荐一款开源社区系统&#xff0c;该系统基于主流的 Java Web 技术栈&#xff0c;如果你是一名 Java 新手掌握了基本 JavaEE 框架知识&#xff0c;可以拿本项目作为练手项目。 开源社区系统功能还算完善包含发布帖子、发布评论、私信、系统通知、点赞、关注、搜索、用户设置、…

ToDesk/向日葵的MAC远程鼠标控制不了?如何解决

不知道各位使用Mac电脑的小伙伴们&#xff0c;在日常进行跨设备远控操作时是否曾遇到过远程鼠标控制不了的问题&#xff1f;其实这是因为有项系统权限没有开设导致的&#xff0c;本篇文章木木小编就给大家逐步教学一下针对该问题如何解决才有效&#xff01; 当通过ToDesk远程连…

vue中图片不显示问题 - vue中静态资源加载

文章目录 vue中图片不显示问题静态资源URL 转换规则webpack 静态资源处理 图片不显示问题问题描述解决办法1&#xff1a;使用require引入require is not defined 解决办法2&#xff1a;使用import引入解决办法3&#xff1a;将图片放进公共文件夹static或public vue中图片不显示…

当世界加速离你而去

当世界加速离你而去 会不会这个标题显的太悲观&#xff0c;也可能是耳机里正在放着To Be Frank的原因。 对于阳历跨年我是没有太多的感觉&#xff0c;而且跨年夜忙着约会&#xff0c;所以2023年的跨年文章今天才出来。 一年的时间一晃就过了。2022年12月9日时候彻底结束了风控…

基于EfficientNet(B0-B7)全系列不同参数量级模型开发构建中草药图像识别分析系统,实验量化对比不同模型性能

EfficientNet系列的模型在我们前面开发识别类项目或者是检测类项目都是比较少去使用的&#xff0c;一方面是技术本身迭代发展的速度是比较快的&#xff0c;可能新的东西还没学习更新的东西就出来了&#xff0c;另一方面是EfficientNet本身实际业务使用度并不高&#xff0c;可能…

maptalks 右键删除多边形 电子围栏

<!-- 地图组件 --> <template><div :id"id" class"container"></div> </template><script> import _ from "lodash"; import "maptalks/dist/maptalks.css"; import * as maptalks from "ma…

RDMA vs InfiniBand 网卡接口如何区分?

(该架构图来源于参考文献) 高性能计算网络&#xff0c;RoCE vs. InfiniBand该怎么选&#xff1f; 新 RoCEv2 标准可实现 RDMA 路由在第三层以太网网络中的传输。RoCEv2 规范将用以太网链路层上的 IP 报头和 UDP 报头替代 InfiniBand 网络层。这样&#xff0c;就可以在基于 IP…

虹科分享丨AR与AI融合加速,医疗护理更便捷!

来源&#xff1a;虹科数字化与AR 虹科分享丨AR与AI融合加速&#xff0c;医疗护理更便捷&#xff01; 原文链接&#xff1a;https://mp.weixin.qq.com/s/Fi0wNfk_TDXRo_1-6cSRNQ 欢迎关注虹科&#xff0c;为您提供最新资讯&#xff01; #AR眼镜 #医疗护理 根据Reports and Da…

【动态规划】【map】【C++算法】1289. 下降路径最小和 II

作者推荐 视频算法专题 本文涉及知识点 动态规划汇总 map LeetCode1289. 下降路径最小和 II 给你一个 n x n 整数矩阵 grid &#xff0c;请你返回 非零偏移下降路径 数字和的最小值。 非零偏移下降路径 定义为&#xff1a;从 grid 数组中的每一行选择一个数字&#xff0c;…

云计算项目五:部署数据库服务mysql |部署共享存储服务NFS | 配置网站服务

部署数据库服务mysql |部署共享存储服务NFS | 配置网站服务 案例1:配置逻辑卷步骤一:创建LV步骤二:格式化案例2:配置数据库服务器步骤一:安装软件MySQL服务软件(2台数据库服务器都要安装)步骤二:挂载lv设备步骤三:启动服务步骤四:管理员登录案例3:配置主从同步步骤一…

【自然语言处理】【深度学习】文本向量化、one-hot、word embedding编码

因为文本不能够直接被模型计算&#xff0c;所以需要将其转化为向量 把文本转化为向量有两种方式&#xff1a; 转化为one-hot编码转化为word embedding 一、one-hot 编码 在one-hot编码中&#xff0c;每一个token使用一个长度为N的向量表示&#xff0c;N表示词典的数量。 即&…

谷歌地球引擎Google Earth Engine针对不同地表类型分别自动生成随机采样点的方法

本文介绍在谷歌地球引擎&#xff08;Google Earth Engine&#xff0c;GEE&#xff09;中&#xff0c;按照给定的地表分类数据&#xff0c;对每一种不同的地物类型&#xff0c;分别加以全球范围内随机抽样点自动批量选取的方法。 本文是谷歌地球引擎&#xff08;Google Earth En…

05.Elasticsearch应用(五)

Elasticsearch应用&#xff08;五&#xff09; 1.目标 咱们这一章主要学习Mapping&#xff08;映射&#xff09; 2.介绍 Mapping是对索引库中文档的约束&#xff0c;类似于数据表结构&#xff0c;作用如下&#xff1a; 定义索引中的字段的名称定义字段的数据类型&#xff…

0124-2-算法题解析与总结(四)

5.5 如何去除有序数组的重复元素 本文对应的力扣题目&#xff1a; 26.删除排序数组中的重复项 83.删除排序链表中的重复元素 26.删除排序数组中的重复项&#xff1a; int removeDuplicates(int[] nums) {int n nums.length;if (n 0) return 0;int slow 0, fast 1;while…

Spring基于AbstractRoutingDataSource实现MySQL多数据源

目录 多数据源实现 yml配置文件 配置类 业务代码 案例演示 多数据源实现 yml配置文件 spring:datasource:type: com.alibaba.druid.pool.DruidDataSourcedatasource1:url: jdbc:mysql://127.0.0.1:3306/datasource1?serverTimezoneUTC&useUnicodetrue&characte…

第二百八十六回

文章目录 概念介绍实现方法示例代码 我们在上一章回中介绍了如何拦截路由相关的内容&#xff0c;本章回中将介绍页面转场动画.闲话休提&#xff0c;让我们一起Talk Flutter吧。 概念介绍 我们在上一章回中介绍了路由拦截相关的内容&#xff0c;本章回中将使用路由拦截实现转场…

《动手学深度学习(PyTorch版)》笔记3

注&#xff1a;书中对代码的讲解并不详细&#xff0c;本文对很多细节做了详细注释。另外&#xff0c;本书源代码是在Jupyter Notebook上运行的&#xff0c;较为分散&#xff0c;本文将代码集中起来&#xff0c;并加以完善&#xff0c;全部用vscode测试通过。 Chapter3 Linear …

长城资产信息技术岗24届校招面试面经

本文介绍2024届秋招中&#xff0c;中国长城资产管理股份有限公司的信息技术岗岗位一面的面试基本情况、提问问题等。 10月投递了中国长城资产管理股份有限公司的信息技术岗岗位&#xff0c;所在部门为长城新盛信托有限责任公司。目前完成了一面&#xff0c;在这里记录一下一面经…

Puppeteer结合Jest对网页进行测试

之前我们使用Puppeteer进行网页爬虫&#xff08;以及自动化操作&#xff09;&#xff0c;这篇文章主要验证一下Puppeteer测试的可实现性。 项目设置 让我们从设置一个基本的React应用程序开始。 我们将安装其他依赖项,如Puppeteer和Faker。 为了这篇文章的目的,我创建了一个…

ASP.NET Core WebAPI从HTTPS调整为HTTP启动

使用VS2022创建WebAPI项目时&#xff0c;默认勾选“配置HTTPS(H)”&#xff0c;这样启动WebAPI时以https方式启动。   如果要从HTTPS调整为HTTP启动&#xff0c;需要修改项目中以下几处&#xff0c;首先是Program.cs中删除app.UseHttpsRedirection()语句&#xff0c;删除后…