学习资源站

RT-DETR改进策略【模型轻量化】PP-LCNet:轻量级的CPU卷积神经网络_ppstructrt-detr-

RT-DETR改进策略【模型轻量化】| PP-LCNet:轻量级的CPU卷积神经网络

一、本文介绍

本文记录的是利用 PP-LCNet 中的 DepSepConv模块 优化 RT-DETR 。本文利用 DepSepConv模块 改善模型结构, 使模型在几乎不增加延迟的情况下提升网络准确度。

模型 参数量 计算量 推理速度
rtdetr-l 32.8M 108.0GFLOPs 11.6ms
Improved 30.2M 86.5GFLOPs 10.7ms


二、PP-LCNet介绍

PP-LCNet :一个轻量级的CPU卷积神经网络

2.1 PP-LCNet结构设计

2.1.1 特点

论文中总结了一系列在不增加推理时间的情况下提高精度的方法,并结合这些方法实现了精度和速度的更好平衡。基于此提出了设计轻量级CNN的一些通用规则。

2.1.2 模块原理

  • 基本块 :使用 MobileNetV1 中提到的 DepthSepConv 作为基本块,该模块不会增加模型的推理速度和额外的操作,且已被英特尔CPU加速库深度优化,推理速度可超越其他轻量级块。

  • 激活函数 :将 BaseNet 中的激活函数从 ReLU 替换为 H-Swish ,大大提高了性能,同时推理时间几乎不变。

  • SE模块 SE模块 有助于对网络通道进行加权以获得更好的特征,但在英特尔CPU上会增加推理时间。通过实验发现,将SE模块添加到网络尾部附近的块中,可以发挥更好的作用,实现更好的精度 - 速度平衡。

  • 卷积核大小 :实验发现,在网络尾部用5×5卷积核替换3×3卷积核,可以在低延迟和高准确性的情况下达到替换几乎所有层的效果,因此只在尾部进行此替换操作。

  • 1×1卷积层 :在 GAP 后的网络输出维度较小,直接添加最终分类层会丢失特征的组合。为了给网络更强的拟合能力,在最终 GAP层 后添加了一个1280维大小的1×1卷积(相当于FC层),可以在几乎不增加推理时间的情况下让模型存储更多信息。

在这里插入图片描述

论文: https://arxiv.org/pdf/2109.15099.pdf
源码: https://github.com/PaddlePaddle/PaddleClas

三、PP-LC模块的实现代码

PP-LC模块 的实现代码如下:

import torch.nn as nn

class SELayer(nn.Module):
    def __init__(self, in_channel, reduction=16):
        super(SELayer, self).__init__()
        assert reduction >= 16
        self.avg_pool = nn.AdaptiveAvgPool2d(1)
        self.fc = nn.Sequential(
            nn.Linear(in_channel, in_channel // reduction, bias=False),
            nn.ReLU(inplace=True),
            nn.Linear(in_channel // reduction, in_channel, bias=False),
            nn.Sigmoid()
        )

    def forward(self, x):
        b, c, _, _ = x.size()
        y = self.avg_pool(x).view(b, c)
        y = self.fc(y).view(b, c, 1, 1)
        return x * y.expand_as(x)
class DepSepConv(nn.Module):
    def __init__(self, inp, oup, kernel_size, stride, use_se):
        super(DepSepConv, self).__init__()
        assert stride in [1, 2]
        padding = (kernel_size - 1) // 2
        if use_se:
            self.conv = nn.Sequential(
                # dw
                nn.Conv2d(inp, inp, kernel_size, stride, padding, groups=inp, bias=False),
                nn.BatchNorm2d(inp),
                nn.Hardswish(),
                
                # SE
                SELayer(inp, inp),
                # pw-linear
                nn.Conv2d(inp, oup, 1, 1, 0, bias=False),
                nn.BatchNorm2d(oup),
                nn.Hardswish(),
                
            )
        else:
            self.conv = nn.Sequential(
                # dw
                nn.Conv2d(inp, inp, kernel_size, stride, padding, groups=inp, bias=False),
                nn.BatchNorm2d(inp),
                nn.Hardswish(),
                # pw-linear
                nn.Conv2d(inp, oup, 1, 1, 0, bias=False),
                nn.BatchNorm2d(oup),
                nn.Hardswish()
            )
    def forward(self, x):
        return self.conv(x)

DepSepConv模块 参数详解

参数 解释
inp 输入通道数
oup 输出通道数
kernel_size 卷积核大小
stride 步长
use_se 是否使用SE注意力

四、模块声明

4.1 改进点⭐

将上方代码按照 5.1小节 的说明加载到文件中

📌 模型的修改方法是将 骨干网络 中的所有 HGBlock模块 替换成 DepSepConv模块 ,使 RT-DETR 在不增加延迟的情况下促进网络学习更强的特征表示、提高轻量级模型精度,并且 DepSepConv模块 中的 SE模块 有助于对网络通道进行加权以获得更好的特征表示。

在这里插入图片描述

注意❗:需要声明的模块名称为: DepSepConv


五、添加步骤

5.1 修改一

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

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

在这里插入图片描述

5.2 修改二

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

在这里插入图片描述

5.3 修改三

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

首先:导入模块

在这里插入图片描述

其次:在 parse_model函数 中注册 DepSepConv

在这里插入图片描述

在这里插入图片描述


六、yaml模型文件

6.1 模型改进版本

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

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

📌 模型的修改方法是将 骨干网络 中添加 DepSepConv模块

# 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, DepSepConv, [48, 3, 1, True]] # stage 1

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

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

  - [-1, 1, DWConv, [1024, 3, 2, 1, False]] # 8-P5/32
  - [-1, 6, DepSepConv, [1024, 3, 1, True]] # 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)


七、成功运行结果

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

**rtdetr-l-PPLCNet **:

rtdetr-PPLCNet summary: 950 layers, 30,177,507 parameters, 30,177,507 gradients, 86.5 GFLOPs

                   from  n    params  module                                       arguments                     
  0                  -1  1     25248  ultralytics.nn.modules.block.HGStem          [3, 32, 48]                   
  1                  -1  6     18144  ultralytics.nn.AddModules.PPLCNet.DepSepConv [48, 48, 3, 1, True]          
  2                  -1  1      3712  ultralytics.nn.modules.conv.DWConv           [48, 128, 3, 2, 1, False]     
  3                  -1  6    109824  ultralytics.nn.AddModules.PPLCNet.DepSepConv [128, 128, 3, 1, True]        
  4                  -1  1      5632  ultralytics.nn.modules.conv.DWConv           [128, 512, 3, 2, 1, False]    
  5                  -1  6   1618944  ultralytics.nn.AddModules.PPLCNet.DepSepConv [512, 512, 3, 1, True]        
  6                  -1  6   1618944  ultralytics.nn.AddModules.PPLCNet.DepSepConv [512, 512, 3, 1, True]        
  7                  -1  6   1618944  ultralytics.nn.AddModules.PPLCNet.DepSepConv [512, 512, 3, 1, True]        
  8                  -1  1     11264  ultralytics.nn.modules.conv.DWConv           [512, 1024, 3, 2, 1, False]   
  9                  -1  6   6383616  ultralytics.nn.AddModules.PPLCNet.DepSepConv [1024, 1024, 3, 1, True]      
 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-PPLCNet summary: 950 layers, 30,177,507 parameters, 30,177,507 gradients, 86.5 GFLOPs