Bootstrap

YOLOv5改进 | 卷积模块 | 无卷积步长用于低分辨率图像和小物体的新 CNN 模块SPD-Conv

 秋招面试专栏推荐 :深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转


💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡


专栏目录: 《YOLOv5入门 + 改进涨点》专栏介绍 & 专栏目录 |目前已有50+篇内容,内含各种Head检测头、损失函数Loss、Backbone、Neck、NMS等创新点改进


卷积神经网络(CNNs)在许多计算机视觉任务中取得了巨大成功,图像分类和目标检测。然而,在处理更复杂的任务时,如图像分辨率低或目标小的情况下,它们的性能会迅速下降。这一问题的根源在于现有CNN架构中一个有缺陷但常见的设计,即使用步进卷积和/或池化层,这导致了细粒度信息的丢失和次优特征表示的学习。为此,研究人员提出了一个新的CNN构建模块,称为SPD-Conv,以取代每个步进卷积层和每个池化层(从而完全消除它们)。SPD-Conv由一个空间到深度(SPD)层和一个非步进卷积(Conv)层组成,并且可以被应用于大多数甚至所有的CNN架构中。文章在介绍主要的原理后,将手把手教学如何进行模块的代码添加和修改,并将修改后的完整代码放在文章的最后,方便大家一键运行,小白也可轻松上手实践。以帮助您更好地学习深度学习目标检测YOLO系列的挑战。

专栏地址YOLOv5改进+入门——持续更新各种有效涨点方法——点击即可跳转  订阅专栏学习不迷路 

目录

1.原理

2. 将SPD-Conv代码添加到YOLOv5中

2.1 SPD-Conv代码实现

2.2 新增yaml文件

2.3 注册模块

2.4 执行程序

3. 完整代码分享

4. GFLOPs

5. 进阶

6. 总结 


1.原理

论文地址: No More Strided Convolutions or Pooling: A New CNN Building Block for Low-Resolution Images and Small Objects——点击即可跳转

官方代码: 官方代码仓库——点击即可跳转

SPD-Conv(空间到深度卷积)是卷积神经网络(CNN)的一个新的构建块,旨在解决由于传统使用步幅卷积和池化层而导致的低分辨率图像和小物体检测的性能下降问题。下面详细解释其主要原理:

SPD-Conv 的关键原理

传统 CNN 的问题:

  • 传统 CNN 通常使用步幅卷积和池化层来对特征图进行下采样。虽然这减少了特征图的空间维度,但也会导致细粒度信息的大量丢失。

  • 这种信息丢失在涉及低分辨率图像或小物体的任务中尤其有害,因为在这些任务中,保持细节对于准确的分类和检测至关重要。

SPD-Conv 设计:

  • 空间到深度 (SPD) 转换:

  • SPD 层通过增加通道维度来减少特征图的空间维度,但保留所有信息。此转换可确保在下采样期间不会丢失任何信息。

  • 对于大小为 S \times S \times C1 的特征图 (X),SPD 通过将 (X) 切成较小的网格并沿通道维度重新排列这些网格来创建子特征图。例如,在下采样因子为 2 的情况下,S \times S \times C1 特征图将转换为 \frac{S}{2} \times \frac{S}{2} \times 4C1 特征图。

  • 非步进卷积:

  • 在 SPD 层之后,应用非步进卷积层(步进 = 1),将增加的通道数量减少到可管理的大小,同时保持空间分辨率。这确保保留了判别性特征,而不会出现步进卷积会引入的不对称采样或信息丢失。

在 CNN 架构中的应用:

  • SPD-Conv 取代了 CNN 架构中所有步进卷积和池化层。

  • 只需进行少量修改,即可应用于大多数现有的 CNN 架构,使其成为各种计算机视觉任务的通用统一解决方案。

实证评估:

  • SPD-Conv 已通过将其集成到  ResNet(用于图像分类)等流行模型中进行测试。

  • 结果显示准确度和性能显著提高,尤其是在涉及低分辨率图像和小物体的任务上。例如,ResNet-SPD 变体在这些具有挑战性的场景中表现优于传统变体。

SPD-Conv 的优势

  • 无信息丢失:通过将空间细节转换为通道维度,SPD-Conv 避免了传统步幅卷积和池化层中发生的信息丢失。

  • 性能提升:对于低分辨率图像和小物体检测特别有效,可在具有挑战性的条件下实现更好的准确性和鲁棒性。

  • 多功能性:可以集成到各种 CNN 架构中,使其成为计算机视觉深度学习模型的广泛适用的改进。

总结

SPD-Conv 用空间到深度变换和非步幅卷积的组合取代了 CNN 中的步幅卷积和池化层。这种创新方法保留了细粒度信息,增强了特征表示,并显著提高了涉及低分辨率图像和小物体的任务的性能。

2. 将SPD-Conv代码添加到YOLOv5中

2.1 SPD-Conv代码实现

关键步骤一: 将下面代码添加到 yolov5/models/common.py中

class SPDConv(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__()
        c1 = c1 * 4
        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):
        x = torch.cat([x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]], 1)
        """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."""
        x = torch.cat([x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]], 1)
        return self.act(self.conv(x))

 并将该文件中的第一个函数autopad修改为


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

SPD-Conv,即空间到深度卷积,是一种新的构建块,旨在通过解决步进卷积和池化层的局限性来改进卷积神经网络 (CNN) 中的图像处理,尤其是在处理低分辨率图像和小物体时。以下是其主要原理及其处理图像方式的概述:

SPD-Conv 的主要原理:

消除步进卷积和池化

  • 传统 CNN 使用步进卷积和池化层对特征图进行下采样,这可能导致细粒度信息的丢失。在处理低分辨率图像或检测小物体时,这种损失是有害的。

空间到深度 (SPD) 层

  • SPD 层通过对特征图进行下采样而不丢失信息来取代步进卷积。它将空间维度转换为通道维度,从而保留所有信息。

  • 对于大小为 S \times S \times C_1 的特征图 ( X ),SPD 将其划分为多个子图。例如,如果比例因子为 2,则将图划分为四个子图。然后沿通道维度连接这些子图,以减小空间维度,同时将通道数增加比例因子平方的倍数。

非步进卷积:

  • 在 SPD 变换之后,应用非步进卷积层。该层处理由 SPD 生成的高维特征图以提取特征并使用可学习参数降低通道维数。

使用 SPD-Conv 的图像处理流程:

输入特征图:

  • 从大小为 S \times S \times C_1 的中间特征图 ( X ) 开始。

空间到深度转换

  • 通过将 ( X ) 划分为子图来应用 SPD 转换。对于比例因子 2,创建四个子图 f{0,0}, f{1,0}, f{0,1}, f{1,1},每个子图的大小为 \left(\frac{S}{2}, \frac{S}{2}, C_1\right)

  • 沿通道维度连接这些子图,得到一个新的特征图 ( X' ),其大小为 \left(\frac{S}{2}, \frac{S}{2}, 4C_1\right)

非步进卷积

  • 将 (X') 传递到非步进卷积层以提取特征并将通道数减少到可管理的大小。

特征提取

  • 处理后的特征图用于 CNN 的后续层,用于对象检测和图像分类等任务。

SPD-Conv 的优势:

信息保留:

  • 与步进卷积和池化不同,SPD-Conv 通过将空间信息转换为通道维度来保留原始特征图中的所有信息。

在小物体和低分辨率图像上的性能提升

  • 通过避免丢失细粒度细节,SPD-Conv 增强了模型检测小物体和有效处理低分辨率图像的能力。

通用和统一方法

  • SPD-Conv 可以集成到各种 CNN 架构中,统一替换步进卷积和池化层。

应用和结果:

  • 物体检测

  • 本文使用流行的物体检测模型 YOLOv5 评估 SPD-Conv,创建了一个名为 YOLOv5-SPD 的变体。此变体在平均精度 (AP) 方面显示出显着的改进,尤其是对于小物体和低分辨率图像。

  • 图像分类

  • 本文还将 SPD-Conv 应用于 ResNet 架构 (ResNet18-SPD 和 ResNet50-SPD),在 Tiny ImageNet 和 CIFAR-10 等数据集的分类任务中展示了增强的性能。

SPD-Conv 的创新方法为传统 CNN 设计的局限性提供了强大的解决方案,使其成为基于深度学习的计算机视觉任务的宝贵补充。

2.2 新增yaml文件

关键步骤二在下/yolov5-6.1/models下新建文件 yolov5_SPDConv.yaml并将下面代码复制进去

# YOLOv5 🚀 by Ultralytics, GPL-3.0 license

# Parameters
nc: 80  # number of classes
depth_multiple: 1.0  # model depth multiple
width_multiple: 1.0  # layer channel multiple
anchors:
  - [10,13, 16,30, 33,23]  # P3/8
  - [30,61, 62,45, 59,119]  # P4/16
  - [116,90, 156,198, 373,326]  # P5/32

# YOLOv5 v6.0 backbone
backbone:
  # [from, number, module, args]
  [[-1, 1, Conv, [64, 6, 2, 2]],  # 0-P1/2
   [-1, 1, SPDConv, [128]],  # 1-P2/4
   [-1, 3, C3, [128]],
   [-1, 1, SPDConv, [256]],  # 3-P3/8
   [-1, 6, C3, [256]],
   [-1, 1, SPDConv, [512]],  # 5-P4/16
   [-1, 9, C3, [512]],
   [-1, 1, SPDConv, [1024]],  # 7-P5/32
   [-1, 3, C3, [1024]],
   [-1, 1, SPPF, [1024, 5]],  # 9
  ]

# YOLOv5 v6.0 head
head:
  [[-1, 1, Conv, [512, 1, 1]],
   [-1, 1, nn.Upsample, [None, 2, 'nearest']],
   [[-1, 6], 1, Concat, [1]],  # cat backbone P4
   [-1, 3, C3, [512, False]],  # 13

   [-1, 1, Conv, [256, 1, 1]],
   [-1, 1, nn.Upsample, [None, 2, 'nearest']],
   [[-1, 4], 1, Concat, [1]],  # cat backbone P3
   [-1, 3, C3, [256, False]],  # 17 (P3/8-small)

   [-1, 1, SPDConv, [256]],
   [[-1, 14], 1, Concat, [1]],  # cat head P4
   [-1, 3, C3, [512, False]],  # 20 (P4/16-medium)

   [-1, 1, SPDConv, [512]],
   [[-1, 10], 1, Concat, [1]],  # cat head P5
   [-1, 3, C3, [1024, False]],  # 23 (P5/32-large)

   [[17, 20, 23], 1, Detect, [nc, anchors]],  # Detect(P3, P4, P5)
  ]

温馨提示:本文只是对yolov5基础上添加模块,如果要对yolov5n/l/m/x进行添加则只需要指定对应的depth_multiple 和 width_multiple。


# YOLOv5n
depth_multiple: 0.33  # model depth multiple
width_multiple: 0.25  # layer channel multiple
 
# YOLOv5s
depth_multiple: 0.33  # model depth multiple
width_multiple: 0.50  # layer channel multiple
 
# YOLOv5l 
depth_multiple: 1.0  # model depth multiple
width_multiple: 1.0  # layer channel multiple
 
# YOLOv5m
depth_multiple: 0.67  # model depth multiple
width_multiple: 0.75  # layer channel multiple
 
# YOLOv5x
depth_multiple: 1.33  # model depth multiple
width_multiple: 1.25  # layer channel multiple

2.3 注册模块

关键步骤三在yolo.py的parse_model函数中注册 添加“SPDConv",

2.4 执行程序

在train.py中,将cfg的参数路径设置为yolov5_SPDConv.yaml的路径

建议大家写绝对路径,确保一定能找到

🚀运行程序,如果出现下面的内容则说明添加成功🚀 

           from  n    params  module                                  arguments
  0                -1  1      7040  models.common.Conv                      [3, 64, 6, 2, 2]
  1                -1  1     33024  models.common.SPDConv                   [64, 128]
  2                -1  3    156928  models.common.C3                        [128, 128, 3]
  3                -1  1    131584  models.common.SPDConv                   [128, 256]
  4                -1  6   1118208  models.common.C3                        [256, 256, 6]
  5                -1  1    525312  models.common.SPDConv                   [256, 512]
  6                -1  9   6433792  models.common.C3                        [512, 512, 9]
  7                -1  1   2099200  models.common.SPDConv                   [512, 1024]
  8                -1  3   9971712  models.common.C3                        [1024, 1024, 3]
  9                -1  1   2624512  models.common.SPPF                      [1024, 1024, 5]
 10                -1  1    525312  models.common.Conv                      [1024, 512, 1, 1]
 11                -1  1         0  torch.nn.modules.upsampling.Upsample    [None, 2, 'nearest']
 11                -1  1         0  torch.nn.modules.upsampling.Upsample    [None, 2, 'nearest']
 12           [-1, 6]  1         0  models.common.Concat                    [1]
 12           [-1, 6]  1         0  models.common.Concat                    [1]
 13                -1  3   2757632  models.common.C3                        [1024, 512, 3, False]
 13                -1  3   2757632  models.common.C3                        [1024, 512, 3, False]
 14                -1  1    131584  models.common.Conv                      [512, 256, 1, 1]
 15                -1  1         0  torch.nn.modules.upsampling.Upsample    [None, 2, 'nearest']
 16           [-1, 4]  1         0  models.common.Concat                    [1]
 17                -1  3    690688  models.common.C3                        [512, 256, 3, False]
 18                -1  1    262656  models.common.SPDConv                   [256, 256]
 19          [-1, 14]  1         0  models.common.Concat                    [1]
 20                -1  3   2495488  models.common.C3                        [512, 512, 3, False]
 21                -1  1   1049600  models.common.SPDConv                   [512, 512]
 22          [-1, 10]  1         0  models.common.Concat                    [1]
 23                -1  3   9971712  models.common.C3                        [1024, 1024, 3, False]
 24      [17, 20, 23]  1    457725  Detect                                  [80, [[10, 13, 16, 30, 33, 23], [30, 61, 62, 45, 59, 119], [116, 90, 156, 198, 373, 326]], [256, 512, 1024]]

3. 完整代码分享

https://pan.baidu.com/s/1OzzOx1Cxs4YUxeM79VF8fg?pwd=xhit

提取码: xhit 

4. GFLOPs

关于GFLOPs的计算方式可以查看百面算法工程师 | 卷积基础知识——Convolution

未改进的GFLOPs

img

改进后的GFLOPs

现在手上没有卡了,等过段时候有卡了把这补上,需要的同学自己测一下

5. 进阶

可以结合损失函数或者卷积模块进行多重改进

YOLOv5改进 | 损失函数 | EIoU、SIoU、WIoU、DIoU、FocuSIoU等多种损失函数——点击即可跳转

6. 总结 

SPD-Conv(Space-to-Depth Convolution)通过空间到通道的转换和非步幅卷积来代替传统的步幅卷积和池化层,解决了低分辨率图像和小物体检测中信息丢失的问题。SPD-Conv首先将特征图分割成多个子图,并沿着通道维度重新排列这些子图,从而减小空间维度但保留所有信息。接着,通过非步幅卷积处理这些高维特征图,提取特征并减少通道维度。这样,SPD-Conv在不丢失细节信息的情况下,实现了特征图的下采样,提高了在低分辨率图像和小物体检测任务中的表现,同时能够无缝集成到各种现有的卷积神经网络架构中。 

;