学习资源站

RT-DETR改进策略【卷积层】CVPR-2023部分卷积PConv轻量化卷积,降低内存占用_rtdetr轻量化改进-

RT-DETR改进策略【卷积层】| CVPR-2023 部分卷积 PConv 轻量化卷积,降低内存占用

一、本文介绍

本文记录的是 利用 部分卷积 Partial Conv 优化 RT-DETR 的目标检测方法研究 深度可分离卷积 可以减少FLOPs,但会导致更高的内存访问,引起延迟并减慢整体计算。 部分卷积利用逐点卷积处理通道冗余,减少模型计算量和内存访问量。



二、部分卷积原理介绍

Run, Don’t Walk: Chasing Higher FLOPS for Faster Neural Networks

2.1 出发点

  • 解决FLOPS问题 :在追求快速神经网络的过程中,许多工作致力于减少浮点运算(FLOPs),但研究者发现FLOPs的减少并不一定能带来延迟的同等降低,主要原因是每秒浮点运算次数(FLOPS)过低。通过对典型神经网络在Intel CPU上FLOPS的比较,发现很多现有神经网络FLOPS较低,其FLOPS普遍低于流行的ResNet50,导致“快速”神经网络实际上不够快,FLOPs的减少无法转化为延迟的准确降低。
  • 深度可分离卷积的内存访问问题 :深度可分离卷积(DWConv)是一种常用的减少FLOPs的方法,但它在实际应用中存在问题。当为了补偿精度下降而增加网络宽度(即DWConv的通道数c增加到c’)时,会导致更高的内存访问,从而引起不可忽视的延迟并减慢整体计算,特别是对于I/O受限的设备。

2.2 原理

  • 利用特征图冗余 :观察到特征图在不同通道之间存在高度相似性(冗余),通过 部分卷积(PConv) 来利用这种冗余。 PConv 不是对所有输入通道进行常规卷积,而是仅对一部分输入通道应用常规卷积进行空间特征提取,同时保持其余通道不变。
  • 减少计算冗余和内存访问 :通过这种方式,同时减少了计算冗余和内存访问。从计算量(FLOPs)来看,PConv的FLOPs仅为常规卷积的一部分(例如,当典型的部分比例 r = c p c = 1 4 r = \frac{c_{p}}{c}=\frac{1}{4} r = c c p = 4 1 时,PConv的FLOPs仅为常规Conv的 1 16 \frac{1}{16} 16 1 );从内存访问量来看,PConv的内存访问量也仅为常规卷积的一部分(同样在 r = 1 4 r=\frac{1}{4} r = 4 1 时,仅为常规Conv的 1 4 \frac{1}{4} 4 1 )。

2.3 结构

  • 基本结构 :对于输入 I ∈ R c × h × w I\in\mathbb{R}^{c×h×w} I R c × h × w ,PConv选取连续的 c p c_{p} c p 个通道(例如可以是第一个或最后一个连续的通道作为代表)应用常规卷积,输出的特征图维度与输入特征图维度相同(即输出 O ∈ R c × h × w O\in\mathbb{R}^{c×h×w} O R c × h × w )。
  • 与PWConv结合 :为了充分利用所有通道的信息,在 PConv 之后紧接着添加一个 逐点卷积(PWConv) 。它们在输入特征图上的有效感受野看起来像一个T形卷积,这种T形卷积更关注中心位置,与均匀处理一个区域的常规卷积不同。并且将T形卷积分解为 PConv PWConv 可以进一步利用滤波器间的冗余,节省FLOPs。

在这里插入图片描述

2.4 优势

  • 有效提取空间特征 :实验证明 PConv 在提取空间特征方面是有效的。通过构建由 PConv PWConv 组成的简单网络,并在从预训练ResNet50提取的特征图数据集上进行训练,结果表明PConv + PWConv能达到最低的测试损失,更好地近似常规卷积进行特征变换,说明仅从部分特征图中捕获空间特征是足够且高效的。
  • 适用于构建快速神经网络 PConv 为设计快速有效的神经网络提供了一种新的选择,具有很大潜力替代现有的DWConv等操作,并且基于PConv构建的FasterNet在各种设备上实现了快速运行,在分类、检测和分割任务上取得了良好的性能,验证了 PConv 的有效性。

论文: https://arxiv.org/pdf/2303.03667
源码: https://github.com/JierunChen/FasterNet

三、部分卷积的实现代码

Partial_conv3模块 及其改进的实现代码如下:

import numpy as np
import torch
import torch.nn as nn

class Partial_conv3(nn.Module):

    def __init__(self, dim, n_div=2, forward='split_cat'):
        super().__init__()
        self.dim_conv3 = dim // n_div
        self.dim_untouched = dim - self.dim_conv3
        self.partial_conv3 = nn.Conv2d(self.dim_conv3, self.dim_conv3, 3, 1, 1, bias=False)

        if forward == 'slicing':
            self.forward = self.forward_slicing
        elif forward == 'split_cat':
            self.forward = self.forward_split_cat
        else:
            raise NotImplementedError

    def forward_slicing(self, x):
        # only for inference
        x = x.clone()  # !!! Keep the original input intact for the residual connection later
        x[:, :self.dim_conv3, :, :] = self.partial_conv3(x[:, :self.dim_conv3, :, :])

        return x

    def forward_split_cat(self, x):
        # for training/inference
        x1, x2 = torch.split(x, [self.dim_conv3, self.dim_untouched], dim=1)
        x1 = self.partial_conv3(x1)
        x = torch.cat((x1, x2), 1)

        return x

def drop_path(x, drop_prob: float = 0., training: bool = False):
    """Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks).
    This is the same as the DropConnect impl I created for EfficientNet, etc networks, however,
    the original name is misleading as 'Drop Connect' is a different form of dropout in a separate paper...
    See discussion: https://github.com/tensorflow/tpu/issues/494#issuecomment-532968956 ... I've opted for
    changing the layer and argument names to 'drop path' rather than mix DropConnect as a layer name and use
    'survival rate' as the argument.
    """
    if drop_prob == 0. or not training:
        return x
    keep_prob = 1 - drop_prob
    shape = (x.shape[0],) + (1,) * (x.ndim - 1)  # work with diff dim tensors, not just 2D ConvNets
    random_tensor = keep_prob + torch.rand(shape, dtype=x.dtype, device=x.device)
    random_tensor.floor_()  # binarize
    output = x.div(keep_prob) * random_tensor
    return output

class DropPath(nn.Module):
    """Drop paths (Stochastic Depth) per sample  (when applied in main path of residual blocks).
    """
    
    def __init__(self, drop_prob=None):
        super(DropPath, self).__init__()
        self.drop_prob = drop_prob
    
    def forward(self, x):
        return drop_path(x, self.drop_prob, self.training)

class Faster_Block(nn.Module):
    def __init__(self,
                 inc,
                 dim,
                 n_div=4,
                 mlp_ratio=2,
                 drop_path=0.1,
                 layer_scale_init_value=0.0,
                 pconv_fw_type='split_cat'
                 ):
        super().__init__()
        self.dim = dim
        self.mlp_ratio = mlp_ratio
        self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()
        self.n_div = n_div

        mlp_hidden_dim = int(dim * mlp_ratio)

        mlp_layer = [
            Conv(dim, mlp_hidden_dim, 1),
            nn.Conv2d(mlp_hidden_dim, dim, 1, bias=False)
        ]

        self.mlp = nn.Sequential(*mlp_layer)

        self.spatial_mixing = Partial_conv3(
            dim,
            n_div,
            pconv_fw_type
        )
        
        self.adjust_channel = None
        if inc != dim:
            self.adjust_channel = Conv(inc, dim, 1)

        if layer_scale_init_value > 0:
            self.layer_scale = nn.Parameter(layer_scale_init_value * torch.ones((dim)), requires_grad=True)
            self.forward = self.forward_layer_scale
        else:
            self.forward = self.forward

    def forward(self, x):
        if self.adjust_channel is not None:
            x = self.adjust_channel(x)
        shortcut = x
        x = self.spatial_mixing(x)
        x = shortcut + self.drop_path(self.mlp(x))
        return x

    def forward_layer_scale(self, x):
        shortcut = x
        x = self.spatial_mixing(x)
        x = shortcut + self.drop_path(
            self.layer_scale.unsqueeze(-1).unsqueeze(-1) * self.mlp(x))
        return x

def autopad(k, p=None, d=1):  # kernel, padding, dilation
    """Pad to 'same' shape outputs."""
    if d > 1:
        k = d * (k - 1) + 1 if isinstance(k, int) else [d * (x - 1) + 1 for x in k]  # actual kernel-size
    if p is None:
        p = k // 2 if isinstance(k, int) else [x // 2 for x in k]  # auto-pad
    return p

class Conv(nn.Module):
    """Standard convolution with args(ch_in, ch_out, kernel, stride, padding, groups, dilation, activation)."""
 
    default_act = nn.SiLU()  # default activation
 
    def __init__(self, c1, c2, k=1, s=1, p=None, g=1, d=1, act=True):
        """Initialize Conv layer with given arguments including activation."""
        super().__init__()
        self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p, d), groups=g, dilation=d, bias=False)
        self.bn = nn.BatchNorm2d(c2)
        self.act = self.default_act if act is True else act if isinstance(act, nn.Module) else nn.Identity()
 
    def forward(self, x):
        """Apply convolution, batch normalization and activation to input tensor."""
        return self.act(self.bn(self.conv(x)))
 
    def forward_fuse(self, x):
        """Perform transposed convolution of 2D data."""
        return self.act(self.conv(x))


四、创新模块

4.1 改进点⭐

模块改进方法 :直接加入 Partial_conv3 第五节讲解添加步骤 )。

Partial_conv3 模块加入如下:

在这里插入图片描述

4.2 改进点⭐

模块改进方法 :加入 Faster_Block 第五节讲解添加步骤 )。

FasterNet Block内部结构 :每个 FasterNet Block 由一个 部分卷积(PConv)层 两个逐点卷积(PWConv)层 组成。

  • PConv层 :只在部分输入通道上应用常规卷积来提取空间特征,其余通道保持不变。
  • PWConv层 :在PConv层之后,用于进一步处理特征信息,使特征信息能够在所有通道间流动,提高特征利用效率。

代码如下:

class Faster_Block(nn.Module):
    def __init__(self,
                 inc,
                 dim,
                 n_div=4,
                 mlp_ratio=2,
                 drop_path=0.1,
                 layer_scale_init_value=0.0,
                 pconv_fw_type='split_cat'
                 ):
        super().__init__()
        self.dim = dim
        self.mlp_ratio = mlp_ratio
        self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()
        self.n_div = n_div

        mlp_hidden_dim = int(dim * mlp_ratio)

        mlp_layer = [
            Conv(dim, mlp_hidden_dim, 1),
            nn.Conv2d(mlp_hidden_dim, dim, 1, bias=False)
        ]

        self.mlp = nn.Sequential(*mlp_layer)

        self.spatial_mixing = Partial_conv3(
            dim,
            n_div,
            pconv_fw_type
        )
        
        self.adjust_channel = None
        if inc != dim:
            self.adjust_channel = Conv(inc, dim, 1)

        if layer_scale_init_value > 0:
            self.layer_scale = nn.Parameter(layer_scale_init_value * torch.ones((dim)), requires_grad=True)
            self.forward = self.forward_layer_scale
        else:
            self.forward = self.forward

    def forward(self, x):
        if self.adjust_channel is not None:
            x = self.adjust_channel(x)
        shortcut = x
        x = self.spatial_mixing(x)
        x = shortcut + self.drop_path(self.mlp(x))
        return x

    def forward_layer_scale(self, x):
        shortcut = x
        x = self.spatial_mixing(x)
        x = shortcut + self.drop_path(
            self.layer_scale.unsqueeze(-1).unsqueeze(-1) * self.mlp(x))
        return x
 

在这里插入图片描述

注意❗:在 第五小节 中需要声明的模块名称为: Partial_conv3 Faster_Block


五、添加步骤

5.1 修改一

① 在 ultralytics/nn/ 目录下新建 AddModules 文件夹用于存放模块代码

② 在 AddModules 文件夹下新建 PConv.py ,将 第三节 中的代码粘贴到此处

在这里插入图片描述

5.2 修改二

AddModules 文件夹下新建 __init__.py (已有则不用新建),在文件内导入模块: from .PConv import *

在这里插入图片描述

5.3 修改三

ultralytics/nn/modules/tasks.py 文件中,需要在指定位置添加各模块类名称。

首先:导入模块

在这里插入图片描述

其次:在 parse_model函数 中注册 Faster_Block Partial_conv3 模块

在这里插入图片描述

在这里插入图片描述


六、yaml模型文件

6.1 模型改进版本1⭐

此处以 ultralytics/cfg/models/rt-detr/rtdetr-l.yaml 为例,在同目录下创建一个用于自己数据集训练的模型文件 rtdetr-l-PConv.yaml

rtdetr-l.yaml 中的内容复制到 rtdetr-l-PConv.yaml 文件下,修改 nc 数量等于自己数据中目标的数量。

📌 模型的修改方法是将 颈部网络 中的 RepC3模块 替换成 Partial_conv3模块

# 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: 1 # 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, HGStem, [32, 48]] # 0-P2/4
  - [-1, 6, HGBlock, [48, 128, 3]] # stage 1

  - [-1, 1, DWConv, [128, 3, 2, 1, False]] # 2-P3/8
  - [-1, 6, HGBlock, [96, 512, 3]] # stage 2

  - [-1, 1, DWConv, [512, 3, 2, 1, False]] # 4-P4/16
  - [-1, 6, HGBlock, [192, 1024, 5, True, False]] # cm, c2, k, light, shortcut
  - [-1, 6, HGBlock, [192, 1024, 5, True, True]]
  - [-1, 6, HGBlock, [192, 1024, 5, True, True]] # stage 3

  - [-1, 1, DWConv, [1024, 3, 2, 1, False]] # 8-P5/32
  - [-1, 6, HGBlock, [384, 2048, 5, True, False]] # stage 4

head:
  - [-1, 1, Conv, [256, 1, 1, None, 1, 1, False]] # 10 input_proj.2
  - [-1, 1, AIFI, [1024, 8]]
  - [-1, 1, Conv, [256, 1, 1]] # 12, Y5, lateral_convs.0

  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]
  - [7, 1, Conv, [256, 1, 1, None, 1, 1, False]] # 14 input_proj.1
  - [[-2, -1], 1, Concat, [1]]
  - [-1, 3,  Partial_conv3, [512]] # 16, fpn_blocks.0
  - [-1, 1, Conv, [256, 1, 1]] # 17, Y4, lateral_convs.1

  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]
  - [3, 1, Conv, [256, 1, 1, None, 1, 1, False]] # 19 input_proj.0
  - [[-2, -1], 1, Concat, [1]] # cat backbone P4
  - [-1, 3,  Partial_conv3, [512]] # X3 (21), fpn_blocks.1

  - [-1, 1, Conv, [256, 3, 2]] # 22, downsample_convs.0
  - [[-1, 17], 1, Concat, [1]] # cat Y4
  - [-1, 3, Partial_conv3, [512]] # F4 (24), pan_blocks.0

  - [-1, 1, Conv, [256, 3, 2]] # 25, downsample_convs.1
  - [[-1, 12], 1, Concat, [1]] # cat Y5
  - [-1, 3, Partial_conv3, [512]] # F5 (27), pan_blocks.1

  - [[21, 24, 27], 1, RTDETRDecoder, [nc]] # Detect(P3, P4, P5)

6.2 模型改进版本2⭐

此处以 ultralytics/cfg/models/rt-detr/rtdetr-l.yaml 为例,在同目录下创建一个用于自己数据集训练的模型文件 rtdetr-l-Faster.yaml

rtdetr-l.yaml 中的内容复制到 rtdetr-l-Faster.yaml 文件下,修改 nc 数量等于自己数据中目标的数量。

📌 模型的修改方法是将 骨干网络 中的 HGBlock模块 替换成 Faster_Block模块

# 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: 1 # 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, HGStem, [32, 48]] # 0-P2/4
  - [-1, 6, Faster_Block, [48]] # stage 1

  - [-1, 1, DWConv, [128, 3, 2, 1, False]] # 2-P3/8
  - [-1, 6, Faster_Block, [128]] # stage 2

  - [-1, 1, DWConv, [512, 3, 2, 1, False]] # 4-P4/16
  - [-1, 1, Faster_Block, [512]] # cm, c2, k, light, shortcut
  - [-1, 1, Faster_Block, [512]]
  - [-1, 1, Faster_Block, [512]] # stage 3

  - [-1, 1, DWConv, [1024, 3, 2, 1, False]] # 8-P5/32
  - [-1, 6, Faster_Block, [1024]] # stage 4

head:
  - [-1, 1, Conv, [256, 1, 1, None, 1, 1, False]] # 10 input_proj.2
  - [-1, 1, AIFI, [1024, 8]]
  - [-1, 1, Conv, [256, 1, 1]] # 12, Y5, lateral_convs.0

  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]
  - [7, 1, Conv, [256, 1, 1, None, 1, 1, False]] # 14 input_proj.1
  - [[-2, -1], 1, Concat, [1]]
  - [-1, 3, RepC3, [256]] # 16, fpn_blocks.0
  - [-1, 1, Conv, [256, 1, 1]] # 17, Y4, lateral_convs.1

  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]
  - [3, 1, Conv, [256, 1, 1, None, 1, 1, False]] # 19 input_proj.0
  - [[-2, -1], 1, Concat, [1]] # cat backbone P4
  - [-1, 3, RepC3, [256]] # X3 (21), fpn_blocks.1

  - [-1, 1, Conv, [256, 3, 2]] # 22, downsample_convs.0
  - [[-1, 17], 1, Concat, [1]] # cat Y4
  - [-1, 3, RepC3, [256]] # F4 (24), pan_blocks.0

  - [-1, 1, Conv, [256, 3, 2]] # 25, downsample_convs.1
  - [[-1, 12], 1, Concat, [1]] # cat Y5
  - [-1, 3, RepC3, [256]] # F5 (27), pan_blocks.1

  - [[21, 24, 27], 1, RTDETRDecoder, [nc]] # Detect(P3, P4, P5)


七、成功运行结果

打印网络模型可以看到 Partial_conv3 C2fCIB_PConv 已经加入到模型中,并可以进行训练了。

rtdetr-l-PConv

rtdetr-l-PConv summary: 564 layers, 25,320,751 parameters, 25,320,751 gradients, 66.9 GFLOPs

                   from  n    params  module                                       arguments                     
  0                  -1  1     25248  ultralytics.nn.modules.block.HGStem          [3, 32, 48]                   
  1                  -1  6    155072  ultralytics.nn.modules.block.HGBlock         [48, 48, 128, 3, 6]           
  2                  -1  1      1408  ultralytics.nn.modules.conv.DWConv           [128, 128, 3, 2, 1, False]    
  3                  -1  6    839296  ultralytics.nn.modules.block.HGBlock         [128, 96, 512, 3, 6]          
  4                  -1  1      5632  ultralytics.nn.modules.conv.DWConv           [512, 512, 3, 2, 1, False]    
  5                  -1  6   1695360  ultralytics.nn.modules.block.HGBlock         [512, 192, 1024, 5, 6, True, False]
  6                  -1  6   2055808  ultralytics.nn.modules.block.HGBlock         [1024, 192, 1024, 5, 6, True, True]
  7                  -1  6   2055808  ultralytics.nn.modules.block.HGBlock         [1024, 192, 1024, 5, 6, True, True]
  8                  -1  1     11264  ultralytics.nn.modules.conv.DWConv           [1024, 1024, 3, 2, 1, False]  
  9                  -1  6   6708480  ultralytics.nn.modules.block.HGBlock         [1024, 384, 2048, 5, 6, True, False]
 10                  -1  1    524800  ultralytics.nn.modules.conv.Conv             [2048, 256, 1, 1, None, 1, 1, False]
 11                  -1  1    789760  ultralytics.nn.modules.transformer.AIFI      [256, 1024, 8]                
 12                  -1  1     66048  ultralytics.nn.modules.conv.Conv             [256, 256, 1, 1]              
 13                  -1  1         0  torch.nn.modules.upsampling.Upsample         [None, 2, 'nearest']          
 14                   7  1    262656  ultralytics.nn.modules.conv.Conv             [1024, 256, 1, 1, None, 1, 1, False]
 15            [-2, -1]  1         0  ultralytics.nn.modules.conv.Concat           [1]                           
 16                  -1  3        27  ultralytics.nn.AddModules.PConv.Partial_conv3[512, 512]                    
 17                  -1  1    131584  ultralytics.nn.modules.conv.Conv             [512, 256, 1, 1]              
 18                  -1  1         0  torch.nn.modules.upsampling.Upsample         [None, 2, 'nearest']          
 19                   3  1    131584  ultralytics.nn.modules.conv.Conv             [512, 256, 1, 1, None, 1, 1, False]
 20            [-2, -1]  1         0  ultralytics.nn.modules.conv.Concat           [1]                           
 21                  -1  3        27  ultralytics.nn.AddModules.PConv.Partial_conv3[512, 512]                    
 22                  -1  1   1180160  ultralytics.nn.modules.conv.Conv             [512, 256, 3, 2]              
 23            [-1, 17]  1         0  ultralytics.nn.modules.conv.Concat           [1]                           
 24                  -1  3        27  ultralytics.nn.AddModules.PConv.Partial_conv3[512, 512]                    
 25                  -1  1   1180160  ultralytics.nn.modules.conv.Conv             [512, 256, 3, 2]              
 26            [-1, 12]  1         0  ultralytics.nn.modules.conv.Concat           [1]                           
 27                  -1  3        27  ultralytics.nn.AddModules.PConv.Partial_conv3[512, 512]                    
 28        [21, 24, 27]  1   7500515  ultralytics.nn.modules.head.RTDETRDecoder    [1, [512, 512, 512]]          
rtdetr-l-PConv summary: 564 layers, 25,320,751 parameters, 25,320,751 gradients, 66.9 GFLOPs

rtdetr-l-Faster

**rtdetr-l-Faster summary: 597 layers, 51,648,483 parameters, 51,648,483 gradients, 107.0 GFLOPs **

                   from  n    params  module                                       arguments                     
  0                  -1  1     25248  ultralytics.nn.modules.block.HGStem          [3, 32, 48]                   
  1                  -1  6     64224  ultralytics.nn.AddModules.PConv.Faster_Block [48, 48]                      
  2                  -1  1      3712  ultralytics.nn.modules.conv.DWConv           [48, 128, 3, 2, 1, False]     
  3                  -1  6    451584  ultralytics.nn.AddModules.PConv.Faster_Block [128, 128]                    
  4                  -1  1      5632  ultralytics.nn.modules.conv.DWConv           [128, 512, 3, 2, 1, False]    
  5                  -1  1   1198080  ultralytics.nn.AddModules.PConv.Faster_Block [512, 512]                    
  6                  -1  1   1198080  ultralytics.nn.AddModules.PConv.Faster_Block [512, 512]                    
  7                  -1  1   1198080  ultralytics.nn.AddModules.PConv.Faster_Block [512, 512]                    
  8                  -1  1     11264  ultralytics.nn.modules.conv.DWConv           [512, 1024, 3, 2, 1, False]   
  9                  -1  6  28729344  ultralytics.nn.AddModules.PConv.Faster_Block [1024, 1024]                  
 10                  -1  1    262656  ultralytics.nn.modules.conv.Conv             [1024, 256, 1, 1, None, 1, 1, False]
 11                  -1  1    789760  ultralytics.nn.modules.transformer.AIFI      [256, 1024, 8]                
 12                  -1  1     66048  ultralytics.nn.modules.conv.Conv             [256, 256, 1, 1]              
 13                  -1  1         0  torch.nn.modules.upsampling.Upsample         [None, 2, 'nearest']          
 14                   7  1    131584  ultralytics.nn.modules.conv.Conv             [512, 256, 1, 1, None, 1, 1, False]
 15            [-2, -1]  1         0  ultralytics.nn.modules.conv.Concat           [1]                           
 16                  -1  3   2232320  ultralytics.nn.modules.block.RepC3           [512, 256, 3]                 
 17                  -1  1     66048  ultralytics.nn.modules.conv.Conv             [256, 256, 1, 1]              
 18                  -1  1         0  torch.nn.modules.upsampling.Upsample         [None, 2, 'nearest']          
 19                   3  1     33280  ultralytics.nn.modules.conv.Conv             [128, 256, 1, 1, None, 1, 1, False]
 20            [-2, -1]  1         0  ultralytics.nn.modules.conv.Concat           [1]                           
 21                  -1  3   2232320  ultralytics.nn.modules.block.RepC3           [512, 256, 3]                 
 22                  -1  1    590336  ultralytics.nn.modules.conv.Conv             [256, 256, 3, 2]              
 23            [-1, 17]  1         0  ultralytics.nn.modules.conv.Concat           [1]                           
 24                  -1  3   2232320  ultralytics.nn.modules.block.RepC3           [512, 256, 3]                 
 25                  -1  1    590336  ultralytics.nn.modules.conv.Conv             [256, 256, 3, 2]              
 26            [-1, 12]  1         0  ultralytics.nn.modules.conv.Concat           [1]                           
 27                  -1  3   2232320  ultralytics.nn.modules.block.RepC3           [512, 256, 3]                 
 28        [21, 24, 27]  1   7303907  ultralytics.nn.modules.head.RTDETRDecoder    [1, [256, 256, 256]]          
rtdetr-l-Faster summary: 597 layers, 51,648,483 parameters, 51,648,483 gradients, 107.0 GFLOPs