【Block总结】PConv风车卷积,更大的感受野,提高特征提取能力|即插即用
论文信息
论文标题:《Pinwheel-shaped Convolution and Scale-based Dynamic Loss for Infrared Small Target Detection》
论文链接:https://arxiv.org/pdf/2412.16986
GitHub链接:https://github.com/JN-Yang/PConv-SDloss-Data
创新点
该论文提出了两项关键创新:
-
风车型卷积(Pinwheel-shaped Convolution, PConv):PConv作为标准卷积的替代,旨在更好地适应红外小目标的像素高斯空间分布。该方法增强了特征提取能力,显著扩大了感受野,并且仅引入了极少的参数增加。
-
基于尺度的动态损失(Scale-based Dynamic Loss, SD Loss):该损失函数动态调整不同目标尺度的损失影响,解决了传统损失函数在处理不同大小目标时的灵敏度不足的问题。这种方法提高了网络对不同尺度目标的检测能力,尤其是在处理微弱小目标时表现更佳。
方法
论文中采用了以下方法:
-
PConv的设计:通过分析红外小目标的三维灰度分布,设计了PConv模块,使其更好地与目标的成像特性对齐。PConv在网络的底层使用,增强了特征提取能力。
-
SD Loss的实现:SD Loss结合了尺度和位置损失,动态调整其权重,以适应目标的大小变化。这种方法使得网络在训练过程中能够更有效地学习到不同尺度目标的特征。
PConv如何与传统卷积层相比,提升特征提取能力
PConv(风车型卷积)相较于传统卷积层在特征提取能力上的提升主要体现在以下几个方面:
-
对高斯空间分布的适应性:
PConv设计时考虑了红外小目标的像素高斯空间分布特性。传统卷积层通常采用固定形状的卷积核,无法有效捕捉到红外小目标的细微特征。而PConv通过其风车形状的卷积核,更好地对齐了目标的成像特性,从而增强了对底层特征的提取能力[2][5][6]。 -
扩大感受野:
PConv显著增加了感受野,使得网络能够在更大范围内聚合信息。这种扩展使得模型在处理复杂背景时,能够更有效地分离目标与背景,尤其是在低对比度和低信噪比的情况下,提升了小目标的检测性能[1][6][7]。 -
参数效率:
尽管PConv增加了感受野,但其引入的参数量相对较少。这意味着在保持模型复杂度相对较低的同时,PConv能够提供更强的特征提取能力,避免了传统卷积层在处理小目标时可能出现的过拟合问题[2][5][6]。 -
集成与动态损失函数的结合:
PConv与Scale-based Dynamic Loss(SD Loss)结合使用,后者动态调整不同尺度目标的损失影响。这种结合进一步提升了模型对不同大小目标的敏感性,使得PConv在特征提取时能够更好地适应目标的多样性和复杂性[5][6][7]。
SD Loss在处理不同尺度目标时的具体调整机制
Scale-based Dynamic Loss(SD Loss)是一种针对不同尺度目标的动态调整机制,旨在提高模型对各种大小目标的检测能力。其具体调整机制包括以下几个方面:
- 动态调整损失权重:
- SD Loss根据目标的大小动态调整损失函数中各个部分的权重。对于较小的目标,SD Loss会降低其损失权重,以减少小目标在训练过程中的不稳定性和对模型的负面影响。这种调整使得模型在面对小目标时,能够更专注于其特征,而不是受到背景噪声的干扰[1][8]。
- 考虑目标的尺度和位置:
- SD Loss不仅考虑目标的尺度,还结合了目标在图像中的位置。通过分析目标的相对位置,SD Loss能够更有效地调整损失函数的影响,使得模型在不同场景下都能保持较高的检测精度。这种方法有效地解决了传统损失函数在处理不同尺度目标时的局限性[1][8]。
- 减小标签不准确性的影响:
- 在目标检测中,标签的不准确性(如边界框的偏差)可能会对模型的训练造成负面影响。SD Loss通过动态调整小目标的损失权重,降低了标签不准确性对损失函数稳定性的影响,从而提高了模型的整体稳定性和准确性[1][8]。
- 增强对小目标的关注:
-通过对小目标施加较低的损失权重,SD Loss使得模型在训练时能够更好地学习小目标的特征。这种机制不仅提高了小目标的检测率,还减少了误报率,特别是在复杂背景下的表现显著提升[1][8]。
SD Loss通过动态调整损失权重、考虑目标的尺度和位置、减小标签不准确性的影响以及增强对小目标的关注,显著提升了模型在处理不同尺度目标时的检测能力。这种方法在红外小目标检测等应用中展现出了良好的效果。
实验结果
通过将PConv和SD Loss集成到最新的小目标检测算法中,研究者在多个数据集上进行了实验,包括IRSTD-1K和SIRST-UAVB。实验结果显示:
-
性能提升:与传统方法相比,采用PConv和SD Loss的模型在红外小目标检测任务中表现出显著的性能提升,尤其是在检测微弱小目标时。
-
鲁棒性增强:新方法在复杂背景下的检测能力得到了增强,能够更好地应对红外图像中常见的干扰因素,如建筑物、云层和植被。
总结
该论文通过引入Pinwheel-shaped Convolution和Scale-based Dynamic Loss,为红外小目标检测提供了新的思路和方法。PConv的设计使得卷积操作更适应红外图像的特性,而SD Loss则有效提升了模型对不同尺度目标的检测能力。实验结果验证了这些创新的有效性,表明该方法在实际应用中具有良好的前景,尤其是在军事和民用领域的红外监测任务中。
代码
import torch
import torch.nn as nn
import torch.nn.functional as F
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
class Conv(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__()
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):
"""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."""
return self.act(self.conv(x))
class PConv(nn.Module):
''' Pinwheel-shaped Convolution using the Asymmetric Padding method. '''
def __init__(self, c1, c2, k, s):
super().__init__()
# self.k = k
p = [(k, 0, 1, 0), (0, k, 0, 1), (0, 1, k, 0), (1, 0, 0, k)]
self.pad = [nn.ZeroPad2d(padding=(p[g])) for g in range(4)]
self.cw = Conv(c1, c2 // 4, (1, k), s=s, p=0)
self.ch = Conv(c1, c2 // 4, (k, 1), s=s, p=0)
self.cat = Conv(c2, c2, 2, s=1, p=0)
def forward(self, x):
yw0 = self.cw(self.pad[0](x))
yw1 = self.cw(self.pad[1](x))
yh0 = self.ch(self.pad[2](x))
yh1 = self.ch(self.pad[3](x))
return self.cat(torch.cat([yw0, yw1, yh0, yh1], dim=1))
if __name__ == "__main__":
# 如果GPU可用,将模块移动到 GPU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
# 输入张量 (batch_size, channels, height, width)
x = torch.randn(1, 32, 40, 40).to(device)
# 初始化 pconv 模块
block = PConv(c1=32, c2=32, k=3, s=1)
print(block)
block = block.to(device)
# 前向传播
output = block(x)
print("输入:", x.shape)
print("输出:", output.shape)