【每天一篇深度学习论文】(IEEE 2024)即插即用特征增强模块FEM

论文介绍

题目:

FFCA-YOLO for Small Object Detection in Remote Sensing Images

论文地址:

https://ieeexplore.ieee.org/document/10423050

创新点

  • FFCA-YOLO模型的设计:该研究提出了一种高效的小目标检测模型FFCA-YOLO,并针对有限计算资源进行了优化,适合未来的实时遥感应用。该模型相较于基准模型和一些当前最先进的模型,具备了较高的性能。
  • 轻量级、模块化设计:论文中提出了三个创新性的轻量级可插拔模块:特征增强模块(FEM)、特征融合模块(FFM)和空间上下文感知模块(SCAM)。这些模块分别提升了网络的局部区域感知、多尺度特征融合以及跨通道和空间的全局关联能力,从而增强了小目标的特征表达,并抑制了复杂背景的干扰。
  • 自建小目标数据集USOD:论文构建了一个新的小目标数据集USOD,具有99.9%以上的小目标比例,包含了低光照和阴影遮挡等复杂条件的场景,并设置了不同图像退化条件的测试集,作为遥感小目标检测的基准数据集。

方法

整体结构

FFCA-YOLO模型在YOLOv5框架基础上,增加了三个轻量级模块:特征增强模块(FEM)用于丰富局部特征信息,特征融合模块(FFM)通过改进的多尺度融合策略加权整合特征,空间上下文感知模块(SCAM)用全局池化获取通道和空间的上下文信息,从而提升小目标和背景的区分能力。此外,模型的轻量化版本L-FFCA-YOLO通过部分卷积(PConv)减少了计算复杂度,适合在资源受限的环境中实现实时检测。
在这里插入图片描述

  • 骨干网络:FFCA-YOLO选择了YOLOv5作为基础框架,但与原始YOLOv5不同的是,它只使用了四个卷积下采样操作作为特征提取的骨干网络。骨干网络的结构经过优化,旨在减少计算复杂度的同时保持较好的特征提取能力。
  • 特征增强模块(FEM):为了提高对小目标的检测能力,FEM模块通过多分支空洞卷积结构增加了特征丰富性,扩展了网络的局部感知能力,提升了对小目标的语义信息表达。

在这里插入图片描述

  • 特征融合模块(FFM):FFM模块通过改进的多尺度特征融合策略,将不同尺度的特征进行加权重组,使网络能够更有效地捕捉多尺度信息。FFM还改进了双向特征金字塔网络(BiFPN),并提出了CRC通道重加权策略,以更高效地利用多尺度特征。

在这里插入图片描述

  • 空间上下文感知模块(SCAM):SCAM模块通过全局池化操作获取空间和通道的上下文信息,用于增强网络对全局信息的建模能力。该模块利用全局平均池化(GAP)和全局最大池化(GMP)指导通道选择,提升了小目标和背景之间的区分能力。
    在这里插入图片描述
  • 轻量化版本L-FFCA-YOLO:为了进一步降低计算资源消耗,L-FFCA-YOLO在FFCA-YOLO的基础上使用部分卷积(PConv)重构了骨干网络和特征融合模块的部分结构,从而在保证精度的同时实现更快的速度和更小的参数规模。
    在这里插入图片描述

即插即用模块作用

FEM 作为一个即插即用模块:

  • 适用场景
    • 小目标检测任务,如遥感图像中的车辆、建筑等小物体检测。
    • 低分辨率或背景复杂的场景,例如低清晰度视频监控、航拍图像等。
    • 场景中小目标特征弱、易被背景干扰的情况。
  • 作用
    • 增强小目标特征:通过多分支空洞卷积结构捕捉丰富的局部特征,使得小目标的特征表达更明显。
    • 提升局部上下文信息感知:扩展感受野,帮助模型在识别小目标时考虑周围的上下文信息。
    • 抑制背景干扰:在复杂背景下提升模型区分目标与背景的能力,减少误检和漏检。

消融实验结果

在这里插入图片描述

  • 分析了特征增强模块(FEM)、特征融合模块(FFM)和空间上下文感知模块(SCAM)对模型性能的影响。
  • 消融实验结果表明,每个模块的加入都显著提高了各项评价指标,尤其是在小目标检测方面。具体来说,FEM增强了模型对复杂背景中小目标的区分能力,FFM改善了多尺度特征的融合效果,而SCAM通过全局上下文信息的建模进一步增强了小目标的特征表示。因此,这些模块的结合使FFCA-YOLO在小目标检测任务中具备更强的特征表达和背景抑制能力。

即插即用模块代码


import torch
import torch.nn as nn

#论文:FFCA-YOLO for Small Object Detection in Remote Sensing Images[TGRS]
#论文地址:https://ieeexplore.ieee.org/document/10423050

class FEM(nn.Module):
    def __init__(self, in_planes, out_planes, stride=1, scale=0.1, map_reduce=8):
        super(FEM, self).__init__()
        self.scale = scale
        self.out_channels = out_planes
        inter_planes = in_planes // map_reduce
        self.branch0 = nn.Sequential(
            BasicConv(in_planes, 2 * inter_planes, kernel_size=1, stride=stride),
            BasicConv(2 * inter_planes, 2 * inter_planes, kernel_size=3, stride=1, padding=1, relu=False)
        )
        self.branch1 = nn.Sequential(
            BasicConv(in_planes, inter_planes, kernel_size=1, stride=1),
            BasicConv(inter_planes, (inter_planes // 2) * 3, kernel_size=(1, 3), stride=stride, padding=(0, 1)),
            BasicConv((inter_planes // 2) * 3, 2 * inter_planes, kernel_size=(3, 1), stride=stride, padding=(1, 0)),
            BasicConv(2 * inter_planes, 2 * inter_planes, kernel_size=3, stride=1, padding=5, dilation=5, relu=False)
        )
        self.branch2 = nn.Sequential(
            BasicConv(in_planes, inter_planes, kernel_size=1, stride=1),
            BasicConv(inter_planes, (inter_planes // 2) * 3, kernel_size=(3, 1), stride=stride, padding=(1, 0)),
            BasicConv((inter_planes // 2) * 3, 2 * inter_planes, kernel_size=(1, 3), stride=stride, padding=(0, 1)),
            BasicConv(2 * inter_planes, 2 * inter_planes, kernel_size=3, stride=1, padding=5, dilation=5, relu=False)
        )

        self.ConvLinear = BasicConv(6 * inter_planes, out_planes, kernel_size=1, stride=1, relu=False)
        self.shortcut = BasicConv(in_planes, out_planes, kernel_size=1, stride=stride, relu=False)
        self.relu = nn.ReLU(inplace=False)

    def forward(self, x):
        x0 = self.branch0(x)
        x1 = self.branch1(x)
        x2 = self.branch2(x)

        out = torch.cat((x0, x1, x2), 1)
        out = self.ConvLinear(out)
        short = self.shortcut(x)
        out = out * self.scale + short
        out = self.relu(out)

        return out

class BasicConv(nn.Module):
    def __init__(self, in_planes, out_planes, kernel_size, stride=1, padding=0, dilation=1, groups=1, relu=True,
                 bn=True, bias=False):
        super(BasicConv, self).__init__()
        self.out_channels = out_planes
        self.conv = nn.Conv2d(in_planes, out_planes, kernel_size=kernel_size, stride=stride, padding=padding,
                              dilation=dilation, groups=groups, bias=bias)
        self.bn = nn.BatchNorm2d(out_planes, eps=1e-5, momentum=0.01, affine=True) if bn else None
        self.relu = nn.ReLU(inplace=True) if relu else None

    def forward(self, x):
        x = self.conv(x)
        if self.bn is not None:
            x = self.bn(x)
        if self.relu is not None:
            x = self.relu(x)
        return x


if __name__ == '__main__':

    input = torch.randn(1, 64, 128, 128)
    block = FEM(in_planes=64, out_planes=64)
    print(input.size())
    output = block(input)
    # 打印输出的形状    print(output.size())

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值