目录
- 论文介绍
- 题目:
- 论文地址:
- 创新点
- 方法
- 整体结构
- 即插即用模块作用
- 消融实验结果
- 即插即用模块代码
论文介绍
题目:
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/10423050class FEM(nn.Module):def __init__(self, in_planes, out_planes, stride=1, scale=0.1, map_reduce=8):super(FEM, self).__init__()self.scale = scaleself.out_channels = out_planesinter_planes = in_planes // map_reduceself.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 + shortout = self.relu(out)return outclass 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_planesself.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 Noneself.relu = nn.ReLU(inplace=True) if relu else Nonedef 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 xif __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())