【论文笔记】Slim-neck by GSConv

前言

在这里插入图片描述
作者提出了一种新方法GSConv来减轻模型复杂度,保持准确性。GSConv可以更好地平衡模型的准确性和速度。并且,提供了一种设计范式Slim-Neck,以实现检测器更高的计算成本效益。实验过程中,与原始网络相比,改进方法获得了最优秀的检测结果。

论文地址:https://arxiv.org/abs/2206.02424

Github:https://github.com/AlanLi1997/Slim-neck-by-GSConv


1. 简介

目标检测是计算机视觉中一项艰巨的下游任务。对于车载边缘计算平台,大模型很难达到实时检测的要求。而且,由大量深度可分离卷积层构建的轻量级模型无法达到足够的准确性。因此本文引入了一种新方法 GSConv 来减轻模型的复杂度并保持准确性。GSConv 可以更好地平衡模型的准确性和速度。并且,提供了一种设计范式,Slim-Neck,以实现检测器更高的计算成本效益。在实验中,与原始网络相比,本文方法获得了最先进的结果(例如,SODA10M 在 Tesla T4 上以 ~100FPS 的速度获得了 70.9% mAP0.5)

MobileNet、ShuffleNets这些轻量级模型都采用了DSC操作来提升检测器的速度。但是当这些模型应用于自动驾驶汽车的时候,准确性就不够了。

但是,DSC 的缺点也很明显:输入图像的通道信息在计算过程中是分离的。
在这里插入图片描述
对于自动驾驶,速度和准确性同样重要。通过 GSConv 引入了 Slim-Neck 方法,以减轻模型的复杂度同时可以保持精度。GSConv 更好地平衡了模型的准确性和速度。

如上图所示,作者在SODA10M无人驾驶数据集上比较了最先进了Slim Neck 检测器和原始检测器的速度和准确度,并证实了该方法的有效性。

2. GSConv

在这里插入图片描述
通过上图可以知道,GSConv首先输入进行一个普通卷积的下采样,然后使用DWConv深度卷积,并将两个conv的结果拼接起来(一个SC一个DSC);最后进行shuffle操作 ,让之前两个卷积的对应通道数挨在一起,通过上方图片也可以看出来。(表述的可能不太清楚,看图片我觉得要清晰一点哈哈哈)

搭配代码食用或许能更好理解一点:

扫描二维码关注公众号,回复: 17377468 查看本文章
class GSConv(nn.Module):
    def __init__(self, c1, c2, k=1, s=1, g=1, act=True):
        super().__init__()
        c_ = c2 // 2
        self.cv1 = Conv(c1, c_, k, s, None, g, act)	# g:gract:分组卷积
        self.cv2 = Conv(c_, c_, 5, 1, None, c_, act)	# 分组为c_
 
    def forward(self, x):
        x1 = self.cv1(x)
        x2 = torch.cat((x1, self.cv2(x1)), 1)
        # shuffle
        b, n, h, w = x2.data.size()
        b_n = b * n // 2
        y = x2.reshape(b_n, 2, h * w)
        y = y.permute(1, 0, 2)
        y = y.reshape(2, -1, n // 2, h, w)
        return torch.cat((y[0], y[1]), 1)

这么做的目的,主要还是为了使DSC的输出尽可能接近SC,这也是GSConv地目的。使用 shuffle 将 SC 生成的信息(密集卷积操作)渗透到 DSC 生成的信息的每个部分。这种方法允许来自 SC 的信息完全混合到 DSC 的输出中,没有花里胡哨的东西。
在这里插入图片描述
如上图所示,展现了普通卷积、DSC卷积和GSC卷积地结果。可以看出,GSConv地太feature map与 SC 的相似性明显高于 DSC 与 SC 的相似,就说明模型的准确性非常接近普通卷积。

看到这,感觉就像是一半普通卷积,一半深度可分离卷积,把他们拼接在了一起。。

当在 Backbone 使用 SC,在Neck使用 GSConv(slim-neck)时,模型的准确率非常接近原始;如果添加一些技巧,模型的准确性和速度就会超过原始模型。采用 GSConv 方法的Slim-Neck可最大限度地减少 DSC 缺陷对模型的负面影响,并有效利用 DSC 的优势。

综上,GSConv的贡献总结如下:

  1. 引入了一种新方法 GSConv 来代替 SC 操作。该方法使卷积计算的输出尽可能接近 SC,同时降低计算成本;

  2. 为自动驾驶汽车的检测器架构提供了一种新的设计范式,即带有标准 Backbone 的 Slim-Neck 设计;

  3. 验证了不同 Trick 的有效性,可以作为该领域研究的参考。


4. 为什么要在Neck中使用GSConv

为了加速预测的计算,CNN 中的馈送图像几乎必须在 Backbone 中经历类似的转换过程:空间信息逐步向通道传输。并且每次特征图的空间(宽度和高度)压缩和通道扩展都会导致语义信息的部分丢失。密集卷积计算最大限度地保留了每个通道之间的隐藏连接,而稀疏卷积则完全切断了这些连接。

GSConv 尽可能地保留这些连接。但是如果在模型的所有阶段都使用它,模型的网络层会更深,深层会加剧对数据流的阻力,显著增加推理时间。当这些特征图走到 Neck 时,它们已经变得细长(通道维度达到最大,宽高维度达到最小),不再需要进行变换。因此,更好的选择是仅在 Neck 使用 GSConv(Slim-Neck + 标准Backbone)。在这个阶段,使用 GSConv 处理 concatenated feature maps 刚刚好:冗余重复信息少,不需要压缩,注意力模块效果更好,例如 SPP 和 CA。

看得不是很懂啊这段,先留个坑吧,对此我暂时的理解是backbone正在将语义信息传输到通道中,如果此时你使用GSConv,就会导致这些语义信息的丢失。

3. Slim-Neck

Slim-Neck中的模块

作者研究了增强 CNN 学习能力的通用方法,例如 DensNet、VoVNet 和 CSPNet,然后根据这些方法的理论设计了 Slim-Neck 结构。

首先,使用轻量级卷积方法 GSConv 来代替 SC。其计算成本约为 SC 的60%~70%,但其对模型学习能力的贡献与后者不相上下。然后,在 GSConv 的基础上继续引入 GSbottleneck。如下图所示。
在这里插入图片描述
同样,使用一次性聚合方法来设计跨级部分网络 (GSCSP) 模块 VoV-GSCSP。VoV-GSCSP 模块降低了计算和网络结构的复杂性,但保持了足够的精度。图 5 (b) 显示了 VoV-GSCSP 的结构。值得注意的是,如果我们使用 VoV-GSCSP 代替 Neck 的 CSP,其中 CSP 层由标准卷积组成,FLOPs 将平均比后者减少 15.72%。

最后,需要灵活地使用3个模块,GSConv、GSbottleneck 和 VoV-GSCSP。

代码如下:

class GSBottleneck(nn.Module):
    # GS Bottleneck https://github.com/AlanLi1997/slim-neck-by-gsconv
    def __init__(self, c1, c2, k=3, s=1):
        super().__init__()
        c_ = c2 // 2
        # for lighting
        self.conv_lighting = nn.Sequential(
            GSConv(c1, c_, 1, 1),
            GSConv(c_, c2, 1, 1, act=False))
        # for receptive field
        self.conv = nn.Sequential(	# 没用到
            GSConv(c1, c_, 3, 1),
            GSConv(c_, c2, 3, 1, act=False))
        self.shortcut = Conv(c1, c2, 3, 1, act=False)
 
    def forward(self, x):
        return self.conv_lighting(x) + self.shortcut(x)
        
class VoVGSCSP(nn.Module):
    # VoV-GSCSP https://github.com/AlanLi1997/slim-neck-by-gsconv
    def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):
        super().__init__()
        c_ = int(c2 * e)
        self.cv1 = Conv(c1, c_, 1, 1)
        self.cv2 = Conv(2 * c_, c2, 1)
        self.m = nn.Sequential(*(GSBottleneck(c_, c_) for _ in range(n)))
    def forward(self, x):
        x1 = self.cv1(x)
        return self.cv2(torch.cat((self.m(x1), x1), dim=1))

Slim-Neck针对YOLO系列的设计

在这里插入图片描述


一些问题

  1. 为什么要放在Neck而不放在backbone,没看懂他的解释。

总结

本篇介绍了GSConv来代替SC,并在此基础上提出了仅在Neck使用(即Slim-Neck + 标准Backbone),因为在backbone中使用GSConv可能会导致计算复杂度过高,而在Neck部分此时的feature map已经变得细长(通道维度达到最大,宽高维度达到最小),不再需要进行变换。然后引出了另外的模块GSbottleneck 和 VoV-GSCSP在Neck使用。文章后面还提到了Slim-Neck针对YOLO系列的几种设计。

References

改进Yolov5 | 用 GSConv+Slim Neck 一步步把 Yolov5 提升到极致!!!
目标检测算法——YOLOv5/YOLOv7改进之GSConv+Slim Neck(优化成本)

猜你喜欢

转载自blog.csdn.net/weixin_51322383/article/details/130745449