当前位置: 首页 > article >正文

【Block总结】PKI 模块,无膨胀多尺度卷积,增强特征提取的能力|即插即用

论文信息

标题: Poly Kernel Inception Network for Remote Sensing Detection

作者: Xinhao Cai, Qiuxia Lai, Yuwei Wang, Wenguan Wang, Zeren Sun, Yazhou Yao

论文链接:https://arxiv.org/pdf/2403.06258

代码链接:https://github.com/NUST-Machine-Intelligence-Laboratory/PKINet
在这里插入图片描述

创新点

Poly Kernel Inception Network (PKINet) 的主要创新在于其设计的卷积结构,旨在解决遥感图像目标检测中的几个关键挑战:

  • 多尺度特征提取: PKINet采用无膨胀的多尺度卷积核,能够有效提取不同尺度的目标特征,避免了传统大核卷积带来的背景噪声问题。

  • 上下文锚定注意力机制: 引入了上下文锚定注意(CAA)模块,以捕获远程上下文信息,增强特征提取的能力。

  • 轻量化设计: 通过并行使用深度卷积和1×1卷积,PKINet在保持高性能的同时,显著降低了模型的复杂性和计算成本。

方法

PKINet的核心方法包括以下几个方面:

  1. 无膨胀多尺度卷积: 通过使用不同大小的卷积核,PKINet能够在不同的感受野中提取丰富的纹理特征,而不依赖于膨胀卷积。

  2. 上下文锚定注意力模块: CAA模块通过全局平均池化和一维卷积,捕获远程像素之间的关系,增强了中心特征的表达能力。

  3. 自适应特征融合: 通过通道维度的自适应融合,PKINet能够有效整合局部和全局上下文信息,从而提高目标检测的准确性。

在这里插入图片描述

无膨胀多尺度卷积PKI 模块详解

Poly Kernel Inception Network (PKINet) 中的 PKI Module 是其核心组成部分,旨在有效提取遥感图像中的多尺度特征。以下是对 PKI Module 的详细解读,包括其设计理念、结构、功能和实验结果。

设计理念

PKI 模块的设计旨在解决遥感图像目标检测中面临的挑战,尤其是目标尺度的巨大变化和复杂背景。与传统方法不同,PKI 模块采用无膨胀的多尺度卷积核,以避免引入背景噪声,同时有效捕获局部上下文信息。

结构

PKI 模块主要由以下几个部分组成:

  1. 小卷积核:

    • 使用小卷积核(如 3 × 3 3 \times 3 3×3)提取局部特征,能够有效捕捉细节信息。
  2. 深度可分离卷积:

    • 采用一系列并行的深度可分离卷积(Depth-wise Convolutions),以捕获不同尺度的上下文信息。这种设计不仅减少了计算复杂度,还提高了特征提取的效率。
  3. 多尺度特征提取:

    • PKI 模块通过组合不同大小的卷积核(如 3 × 3 3 \times 3 3×3, 5 × 5 5 \times 5 5×5, 7 × 7 7 \times 7 7×7 等),实现对多尺度特征的提取,增强了模型对不同尺寸目标的适应能力。

功能

PKI 模块的主要功能包括:

  • 多尺度特征提取: 通过不同大小的卷积核,PKI 模块能够有效提取不同尺度的目标特征,适应遥感图像中目标的多样性。

  • 上下文信息捕获: 通过深度可分离卷积,PKI 模块能够捕获局部上下文信息,增强特征的表达能力。

  • 避免背景噪声: 由于不使用膨胀卷积,PKI 模块能够避免过于稀疏的特征表示,从而提高检测精度。

PKI 模块是 PKINet 的核心组件,通过创新的多尺度卷积设计和深度可分离卷积结构,有效提升了遥感图像目标检测的性能。其在特征提取和上下文信息捕获方面的优势,使得 PKINet 在多个基准数据集上取得了优异的表现,展示了其在实际应用中的潜力。

效果

在多个遥感目标检测基准数据集上进行的实验表明,PKINet在性能上优于传统方法,尤其是在处理目标尺度变化和复杂背景时表现突出。具体来说,PKINet在以下数据集上取得了显著的检测效果:

  • DOTA-v1.0
  • DOTA-v1.5
  • HRSC2016
  • DIOR-R

这些实验结果表明,PKINet不仅提高了检测精度,还在处理速度上也有良好的表现。

实验结果

实验中,PKINet在多个标准数据集上进行了广泛的评估,结果显示:

  • 检测精度: PKINet在各个数据集上均表现出色,尤其是在小目标和复杂背景下的检测能力显著提升。

  • 模型效率: 由于其轻量化设计,PKINet在计算资源的使用上更为高效,适合实际应用场景。

  • 对比分析: 与传统的目标检测模型相比,PKINet在多个指标上均有明显的优势,尤其是在处理多样化的上下文环境时。

总结

Poly Kernel Inception Network (PKINet) 通过创新的卷积结构和上下文注意力机制,成功应对了遥感图像目标检测中的多种挑战。其在特征提取和上下文信息捕获方面的优势,使得PKINet在多个基准数据集上取得了优异的性能,展示了其在实际应用中的潜力。未来的研究可以进一步探索PKINet在其他计算机视觉任务中的应用,以及如何进一步优化其结构以提升性能。

代码

import torch
import torch.nn as nn
from mmcv.cnn import ConvModule
from mmengine.model import BaseModule
from typing import Optional, Union, Sequence
import math
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
def make_divisible(x, divisor):
    # Returns nearest x divisible by divisor
    if isinstance(divisor, torch.Tensor):
        divisor = int(divisor.max())  # to int
    return math.ceil(x / divisor) * divisor
class GSiLU(BaseModule):
    """Global Sigmoid-Gated Linear Unit, reproduced from paper <SIMPLE CNN FOR VISION>"""
    def __init__(self):
        super().__init__()
        self.adpool = nn.AdaptiveAvgPool2d(1)

    def forward(self, x):
        return x * torch.sigmoid(self.adpool(x))


class CAA(BaseModule):
    """Context Anchor Attention"""
    def __init__(
            self,
            channels: int,
            h_kernel_size: int = 11,
            v_kernel_size: int = 11,
            norm_cfg: Optional[dict] = dict(type='BN', momentum=0.03, eps=0.001),
            act_cfg: Optional[dict] = dict(type='SiLU'),
            init_cfg: Optional[dict] = None,
    ):
        super().__init__(init_cfg)
        self.avg_pool = nn.AvgPool2d(7, 1, 3)
        self.conv1 = ConvModule(channels, channels, 1, 1, 0,
                                norm_cfg=norm_cfg, act_cfg=act_cfg)
        self.h_conv = ConvModule(channels, channels, (1, h_kernel_size), 1,
                                 (0, h_kernel_size // 2), groups=channels,
                                 norm_cfg=None, act_cfg=None)
        self.v_conv = ConvModule(channels, channels, (v_kernel_size, 1), 1,
                                 (v_kernel_size // 2, 0), groups=channels,
                                 norm_cfg=None, act_cfg=None)
        self.conv2 = ConvModule(channels, channels, 1, 1, 0,
                                norm_cfg=norm_cfg, act_cfg=act_cfg)
        self.act = nn.Sigmoid()

    def forward(self, x):
        attn_factor = self.act(self.conv2(self.v_conv(self.h_conv(self.conv1(self.avg_pool(x))))))
        return x*attn_factor

class InceptionBottleneck(BaseModule):
    """Bottleneck with Inception module"""
    def __init__(
            self,
            in_channels: int,
            out_channels: Optional[int] = None,
            kernel_sizes: Sequence[int] = (3, 5, 7, 9, 11),
            dilations: Sequence[int] = (1, 1, 1, 1, 1),
            expansion: float = 1.0,
            add_identity: bool = True,
            with_caa: bool = True,
            caa_kernel_size: int = 11,
            norm_cfg: Optional[dict] = dict(type='BN', momentum=0.03, eps=0.001),
            act_cfg: Optional[dict] = dict(type='SiLU'),
            init_cfg: Optional[dict] = None,
    ):
        super().__init__(init_cfg)
        out_channels = out_channels or in_channels
        hidden_channels = make_divisible(int(out_channels * expansion), 8)

        self.pre_conv = ConvModule(in_channels, hidden_channels, 1, 1, 0, 1,
                                   norm_cfg=norm_cfg, act_cfg=act_cfg)

        self.dw_conv = ConvModule(hidden_channels, hidden_channels, kernel_sizes[0], 1,
                                  autopad(kernel_sizes[0], None, dilations[0]), dilations[0],
                                  groups=hidden_channels, norm_cfg=None, act_cfg=None)
        self.dw_conv1 = ConvModule(hidden_channels, hidden_channels, kernel_sizes[1], 1,
                                   autopad(kernel_sizes[1], None, dilations[1]), dilations[1],
                                   groups=hidden_channels, norm_cfg=None, act_cfg=None)
        self.dw_conv2 = ConvModule(hidden_channels, hidden_channels, kernel_sizes[2], 1,
                                   autopad(kernel_sizes[2], None, dilations[2]), dilations[2],
                                   groups=hidden_channels, norm_cfg=None, act_cfg=None)
        self.dw_conv3 = ConvModule(hidden_channels, hidden_channels, kernel_sizes[3], 1,
                                   autopad(kernel_sizes[3], None, dilations[3]), dilations[3],
                                   groups=hidden_channels, norm_cfg=None, act_cfg=None)
        self.dw_conv4 = ConvModule(hidden_channels, hidden_channels, kernel_sizes[4], 1,
                                   autopad(kernel_sizes[4], None, dilations[4]), dilations[4],
                                   groups=hidden_channels, norm_cfg=None, act_cfg=None)
        self.pw_conv = ConvModule(hidden_channels, hidden_channels, 1, 1, 0, 1,
                                  norm_cfg=norm_cfg, act_cfg=act_cfg)

        if with_caa:
            self.caa_factor = CAA(hidden_channels, caa_kernel_size, caa_kernel_size, None, None)
        else:
            self.caa_factor = None

        self.add_identity = add_identity and in_channels == out_channels

        self.post_conv = ConvModule(hidden_channels, out_channels, 1, 1, 0, 1,
                                    norm_cfg=norm_cfg, act_cfg=act_cfg)

    def forward(self, x):
        x = self.pre_conv(x)

        y = x  # if there is an inplace operation of x, use y = x.clone() instead of y = x
        x = self.dw_conv(x)
        x = x + self.dw_conv1(x) + self.dw_conv2(x) + self.dw_conv3(x) + self.dw_conv4(x)
        x = self.pw_conv(x)
        if self.caa_factor is not None:
            y = self.caa_factor(y)
        if self.add_identity:
            y = x * y
            x = x + y
        else:
            x = x * y

        x = self.post_conv(x)
        return x

if __name__ == "__main__":
    # 如果GPU可用,将模块移动到 GPU
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    # 输入张量 (batch_size, height, width,channels)
    x = torch.randn(1,32,40,40).to(device)
    # 初始化 HWD 模块
    dim=32
    block = InceptionBottleneck(32)
    print(block)
    block = block.to(device)
    # 前向传播
    output = block(x)
    print("输入:", x.shape)
    print("输出:", output.shape)

输出结果:

在这里插入图片描述


http://www.kler.cn/a/526731.html

相关文章:

  • MATLAB-Simulink并行仿真示例
  • leetcode——合并K个有序链表(java)
  • LINUX部署微服务项目步骤
  • 《深度揭秘:TPU张量计算架构如何重塑深度学习运算》
  • 【go语言】gorm 快速入门
  • 巴塞尔问题详解:计算所有正整数平方的倒数之和
  • 【华为OD-E卷 - 分积木 100分(python、java、c++、js、c)】
  • Autogen_core: test_code_executor.py
  • 算法---快速排序
  • Python3 【集合】避坑指南:常见错误解析
  • 【解决方案】MuMu模拟器移植系统进度条卡住98%无法打开
  • 快速提升网站收录:避免常见SEO误区
  • 深入解析JPA实体监听器的使用与实践
  • AI学习指南HuggingFace篇-Hugging Face 的环境搭建
  • 自由学习记录(33)
  • INCOSE需求编写指南-附录 B: 首字母缩略词和缩写
  • 详解python的单例模式
  • DeepSeek-V3技术报告解读
  • Cocos Creator 3.8 2D 游戏开发知识点整理
  • Sqoop支持ORC文件格式
  • AI大模型开发原理篇-4:神经概率语言模型NPLM
  • 【C++题解】1055. 求满足条件的整数个数
  • GWO优化GRNN回归预测matlab
  • 165. 比较版本号
  • 《解码AI大模型涌现能力:从量变到质变的智能跃迁》
  • 如何利用Docker和.NET Core实现环境一致性、简化依赖管理、快速部署与扩展,同时提高资源利用率、确保安全性和生态系统支持