【视频讲解】顶级期刊即插即用模块代码共享计划·2024第一期:01:波叠加原理的社会池化方法(AAAI2023)与并行补丁感知注意力模块(2024)代码实现

本文介绍了一种基于波叠加原理的社会池化方法(Wave-pooling),用于更有效地捕捉动态和高阶交互,并预测周围车辆的运动轨迹。该方法通过将每个车辆建模为具有振幅和相位的波来表示其动态状态,并通过波的叠加来捕捉它们之间的高阶动态交互。同时,本文还介绍了一种名为HCF-Net的深度学习方法,该方法通过引入多个实用模块显著提高了红外小物体检测的性能,解决了小物体检测中常见的挑战,如小物体信息丢失和背景杂乱问题。【有代码实现】

视频讲解:【布尔大学士】20分钟速通深度学习SCI论文缝模块!在读博士生带你飞!

【布尔大学士】20分钟速通深度学习SCI论文缝模块!在读博士生带你飞!

改进方案1 WSiP: Wave Superposition Inspired Pooling for Dynamic Interactions-Aware Trajectory Prediction

1.1 摘要总结

本文提出了一种基于波叠加原理的社会池化方法(Wave-pooling),用于更有效地捕捉动态和高阶交互,并预测周围车辆的运动轨迹。该方法通过将每个车辆建模为具有振幅和相位的波来表示其动态状态,并通过波的叠加来捕捉它们之间的高阶动态交互。

1.2 结构图

在这里插入图片描述

Figure 3: WSiP的框架,包含历史交互调制模块(historical interaction modulation module)、未来轨迹模拟模块(future trajectory simulation module)和轨迹预测模块(trajectory prediction module)。历史交互调制模块和未来轨迹模拟模块采用Wave-pooling分别捕获代理的历史和未来相互依赖关系。轨迹预测模块输出目标代理未来位置的多模态分布。

1.3 应用场景

  • 自动驾驶系统中的路径规划和碰撞避免,尤其是在需要考虑多辆车之间动态交互的复杂道路环境中。
    在这里插入图片描述

1.4 创新模块及其介绍

  • Wave-pooling机制:该机制受Wave-MLP启发,将每个车辆视为一个波,其中振幅反映车辆的动力学特性,而相位则调节车辆间的相互作用。通过波的叠加可以反映出车辆之间的动态交互。
  • WSiP框架:包含历史交互调制模块、未来轨迹模拟模块以及轨迹预测模块。历史交互调制模块用于模拟车辆间高阶交互;未来轨迹模拟模块通过预测邻近车辆的未来动作来模拟短期驾驶场景;轨迹预测模块生成目标车辆的未来轨迹。

1.5 所解决问题

  • 解决了传统LSTM模型在考虑车辆之间交互时存在的局限性,特别是在复杂驾驶场景下的高阶交互。
  • 改进了对周围车辆轨迹预测的准确性和可解释性。

1.6 创新点

  • 首次将车辆间的社会交互建模为波叠加过程,并提出了Wave-pooling机制来动态聚合车辆之间的交互。
  • 提出了基于编码器-解码器的学习框架WSiP,包含历史交互调制模块、未来轨迹模拟模块和轨迹预测模块,以提高车辆轨迹预测的准确性。
  • 实验结果验证了该方法的有效性,并且相比现有技术有显著改进,同时结果更具可解释性,因为车辆间的交互强度可以通过它们之间的相位差直观地反映出来。

在这里插入图片描述

图 5:三种驾驶场景的可视化。上图:热图显示目标与邻居的余弦相似度。下图:S-LSTM、CS-LSTM 和 WSiP 预测的三个示例案例。

1.7 代码实现及其注释

# WavePooling.py
# --------------------------------------------------------
# 论文:WSiP: Wave Superposition Inspired Pooling for Dynamic Interactions-Aware Trajectory Prediction (AAAI 2024)
# 论文地址: https://ojs.aaai.org/index.php/AAAI/article/download/25592/25364
# ------

from __future__ import division
import torch
import torch.nn as nn
import torch.nn.functional as F

from timm.models.layers import DropPath
# pip install timm == 1.0.8

class Mlp(nn.Module):  # 定义一个多层感知机类
    def __init__(self, in_features, hidden_features=None, out_features=None, act_layer=nn.GELU, drop=0.):  # 构造函数
        super().__init__()  # 初始化父类
        out_features = out_features or in_features  # 输出特征数默认等于输入特征数
        hidden_features = hidden_features or in_features  # 隐藏层特征数默认等于输入特征数
        self.act = act_layer()  # 激活层
        self.drop = nn.Dropout(drop)  # Dropout 层
        self.fc1 = nn.Conv2d(in_features, hidden_features, 1, 1)  # 第一个卷积层
        self.fc2 = nn.Conv2d(hidden_features, out_features, 1, 1)  # 第二个卷积层

    def forward(self, x):  # 前向传播函数
        x = self.fc1(x)  # 输入通过第一个卷积层
        x = self.act(x)  # 通过激活层
        x = self.drop(x)  # 通过 Dropout 层
        x = self.fc2(x)  # 输入通过第二个卷积层
        x = self.drop(x)  # 再次通过 Dropout 层
        return x  # 返回处理后的张量

class PATM(nn.Module):  # 定义相位注意力变换模块类
    def __init__(self, dim, qkv_bias=False, qk_scale=None, attn_drop=0., proj_drop=0., mode='fc'):  # 构造函数
        super().__init__()  # 初始化父类
        self.fc_h = nn.Conv2d(dim, dim, 1, 1, bias=qkv_bias)  # 用于提取水平方向的特征
        self.fc_w = nn.Conv2d(dim, dim, 1, 1, bias=qkv_bias)  # 用于提取垂直方向的特征
        self.fc_c = nn.Conv2d(dim, dim, 1, 1, bias=qkv_bias)  # 用于提取通道方向的特征
        self.tfc_h = nn.Conv2d(2 * dim, dim, (1, 7), stride=1, padding=(0, 7 // 2), groups=dim, bias=False)  # 用于处理水平方向的特征
        self.tfc_w = nn.Conv2d(2 * dim, dim, (7, 1), stride=1, padding=(7 // 2, 0), groups=dim, bias=False)  # 用于处理垂直方向的特征
        self.reweight = Mlp(dim, dim // 4, dim * 3)  # 用于重新加权
        self.proj = nn.Conv2d(dim, dim, 1, 1, bias=True)  # 投影层
        self.proj_drop = nn.Dropout(proj_drop)  # Dropout 层
        self.mode = mode  # 模式选择
        if mode == 'fc':  # 如果模式是全连接
            self.theta_h_conv = nn.Sequential(  # 水平方向相位计算
                nn.Conv2d(dim, dim, 1, 1, bias=True),
                nn.BatchNorm2d(dim),
                nn.ReLU()
            )
            self.theta_w_conv = nn.Sequential(  # 垂直方向相位计算
                nn.Conv2d(dim, dim, 1, 1, bias=True),
                nn.BatchNorm2d(dim),
                nn.ReLU()
            )
        else:  # 如果不是全连接模式
            self.theta_h_conv = nn.Sequential(  # 水平方向相位计算
                nn.Conv2d(dim, dim, 3, stride=1, padding=1, groups=dim, bias=False),
                nn.BatchNorm2d(dim),
                nn.ReLU()
            )
            self.theta_w_conv = nn.Sequential(  # 垂直方向相位计算
                nn.Conv2d(dim, dim, 3, stride=1, padding=1, groups=dim, bias=False),
                nn.BatchNorm2d(dim),
                nn.ReLU()
            )

    def forward(self, x):  # 前向传播函数
        B, C, H, W = x.shape  # 获取输入张量的维度
        theta_h = self.theta_h_conv(x)  # 计算水平方向的相位
        theta_w = self.theta_w_conv(x)  # 计算垂直方向的相位
        x_h = self.fc_h(x)  # 提取水平方向的振幅
        x_w = self.fc_w(x)  # 提取垂直方向的振幅
        x_h = torch.cat([x_h * torch.cos(theta_h), x_h * torch.sin(theta_h)], dim=1)  # 欧拉公式展开水平方向
        x_w = torch.cat([x_w * torch.cos(theta_w), x_w * torch.sin(theta_w)], dim=1)  # 欧拉公式展开垂直方向
        h = self.tfc_h(x_h)  # 处理水平方向的特征
        w = self.tfc_w(x_w)  # 处理垂直方向的特征
        c = self.fc_c(x)  # 提取通道方向的特征
        a = F.adaptive_avg_pool2d(h + w + c, output_size=1)  # 平均池化
        a = self.reweight(a).reshape(B, C, 3).permute(2, 0, 1).softmax(dim=0).unsqueeze(-1).unsqueeze(-1)  # 重新加权
        x = h * a[0] + w * a[1] + c * a[2]  # 加权组合
        x = self.proj(x)  # 通过投影层
        x = self.proj_drop(x)  # 通过 Dropout 层
        return x  # 返回处理后的张量

class WaveBlock(nn.Module):  # 定义波形块类
    def __init__(self, dim, mlp_ratio=4., qkv_bias=False, qk_scale=None, drop=0., attn_drop=0.,
                 drop_path=0., act_layer=nn.GELU, norm_layer=nn.BatchNorm2d, mode='fc'):  # 构造函数
        super().__init__()  # 初始化父类
        self.norm1 = norm_layer(dim)  # 第一个规范化层
        self.attn = PATM(dim, qkv_bias=qkv_bias, qk_scale=None, attn_drop=attn_drop, mode=mode)  # 相位注意力变换模块
        self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()  # DropPath 层
        self.norm2 = norm_layer(dim)  # 第二个规范化层
        mlp_hidden_dim = int(dim * mlp_ratio)  # MLP 的隐藏层维度
        self.mlp = Mlp(in_features=dim, hidden_features=mlp_hidden_dim, act_layer=act_layer)  # 多层感知机模块

    def forward(self, x):  # 前向传播函数
        x = x + self.drop_path(self.attn(self.norm1(x)))  # 注意力变换
        x = x + self.drop_path(self.mlp(self.norm2(x)))  # MLP 变换
        return x  # 返回处理后的张量

if __name__ == '__main__':  # 主程序入口
    # 实例化模块并定义输入
    block = WaveBlock(dim=64)  # 假设输入特征的通道数为 64
    input = torch.rand(10, 64, 32, 32)  # 假设输入大小为 (batch_size=10, channels=64, height=32, width=32)

    # 运行前向传播
    output = block(input)  # 调用波形块的前向传播

    # 打印输入和输出的大小
    print("输入大小:", input.size())  # 打印输入张量的大小
    print("输出大小:", output.size())  # 打印输出张量的大小
    print("抖音、B站、小红书、CSDN同号")
    print("布尔大学士 提醒您:代码无误~~~~")

改进方案2 HCF-Net: Hierarchical Context Fusion Network for Infrared Small Object Detection

2.1 摘要总结

本文提出了一种名为HCF-Net的深度学习方法,该方法通过引入多个实用模块显著提高了红外小物体检测的性能。这些模块解决了小物体检测中常见的挑战,如小物体信息丢失和背景杂乱问题。

2.2 结构图

在这里插入图片描述

Fig. 1. 网络架构。编码器主要由并行化的块感知注意 (PPA) 模块和最大池化层组成,而解码器主要由 PPA 和卷积转置 (CT) 层组成。我们整合了多扩张通道细化器 (MDCR) 模块作为中间层来连接编码器和解码器。在跳跃连接组件中,我们引入了维度感知选择性集成 (DASI) 模块,以增强跨不同网络层的特征融合和传播。

2.2.1 PPA模块

在这里插入图片描述

图 2. parallelized patch-aware attention module(PPA)。该模块主要由两个组件组成:多分支融合和注意机制。多分支融合组件包括补丁感知和级联卷积。补丁感知中的“p”参数设置为 2 和 4,分别代表局部和全局分支。

2.3创新模块及其介绍

  • PPA模块(Parallelized Patch-Aware Attention):采用多分支特征提取策略,捕捉不同尺度和级别的特征信息,确保关键信息在多次下采样过程中得以保留。
  • DASI模块(Dimension-Aware Selective Integration):增强U-Net中的跳过连接,专注于高维度与低维度特征的适应性选择与精细融合,以增强小物体的显著性。
  • MDCR模块(Multi-Dilated Channel Refiner):通过多个深度可分离卷积层捕获不同感受野范围的空间特征,更精细地建模对象与背景之间的差异,从而增强定位小物体的能力。

2.4 创新点

  • 将红外小物体检测建模为语义分割问题,并提出HCF-Net这一层级上下文融合网络,能够从头开始训练。
  • 有机地结合了PPA、DASI和MDCR三个模块,有效解决了小物体检测的挑战,提高了检测性能和鲁棒性。

2.5 所解决问题

  • 解决了红外图像中小物体检测面临的挑战,包括物体尺寸小和背景复杂的问题。
  • 提升了小物体的识别率和定位精度,特别是在复杂背景下。
应用场景
  • 红外成像中的小物体检测,例如在军事侦察、安防监控和自然灾害监测等领域。

2.6 实验结果

2.6.1 可视化结果

在这里插入图片描述

2.6.2 消融实验

在这里插入图片描述

2.7 代码实现及其注释

# HCFNet.py
# --------------------------------------------------------
# 论文:HCF-Net: Hierarchical Context Fusion Network for Infrared Small Object Detection (arxiv 2024)
# 论文地址:https://arxiv.org/abs/2403.10778
# ------

# --------------------------------------------------------
# 论文:HCF-Net: Hierarchical Context Fusion Network for Infrared Small Object Detection (arxiv 2024)
# GitHub 地址: https://github.com/zhengshuchen/HCFNet
# ------

import math
import torch
import torch.nn as nn
import torch.nn.functional as F

# 空间注意力模块
class SpatialAttentionModule(nn.Module):
    def __init__(self):
        super(SpatialAttentionModule, self).__init__()
        # 定义一个 2 通道输入的卷积层,输出通道为 1,卷积核大小为 7,步长为 1,填充为 3
        self.conv2d = nn.Conv2d(in_channels=2, out_channels=1, kernel_size=7, stride=1, padding=3)
        # Sigmoid 激活函数
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        # 计算平均值
        avgout = torch.mean(x, dim=1, keepdim=True)
        # 计算最大值
        maxout, _ = torch.max(x, dim=1, keepdim=True)
        # 沿通道维度拼接平均值和最大值
        out = torch.cat([avgout, maxout], dim=1)
        # 卷积层 + Sigmoid
        out = self.sigmoid(self.conv2d(out))
        # 返回注意力权重乘以原始输入
        return out * x

# 多级注意力金字塔模块
class PPA(nn.Module):
    def __init__(self, in_features, filters) -> None:
        super().__init__()

        # 1x1 卷积层,用于生成 skip connection
        self.skip = conv_block(in_features=in_features,
                               out_features=filters,
                               kernel_size=(1, 1),
                               padding=(0, 0),
                               norm_type='bn',
                               activation=False)
        # 第一个 3x3 卷积层
        self.c1 = conv_block(in_features=in_features,
                             out_features=filters,
                             kernel_size=(3, 3),
                             padding=(1, 1),
                             norm_type='bn',
                             activation=True)
        # 第二个 3x3 卷积层
        self.c2 = conv_block(in_features=filters,
                             out_features=filters,
                             kernel_size=(3, 3),
                             padding=(1, 1),
                             norm_type='bn',
                             activation=True)
        # 第三个 3x3 卷积层
        self.c3 = conv_block(in_features=filters,
                             out_features=filters,
                             kernel_size=(3, 3),
                             padding=(1, 1),
                             norm_type='bn',
                             activation=True)
        # 空间注意力模块
        self.sa = SpatialAttentionModule()
        # ECA 注意力模块
        self.cn = ECA(filters)
        # 2x2 局部全局注意力模块
        self.lga2 = LocalGlobalAttention(filters, 2)
        # 4x4 局部全局注意力模块
        self.lga4 = LocalGlobalAttention(filters, 4)

        # 批量归一化层
        self.bn1 = nn.BatchNorm2d(filters)
        # Dropout2d 层
        self.drop = nn.Dropout2d(0.1)
        # ReLU 激活函数
        self.relu = nn.ReLU()
        # GELU 激活函数
        self.gelu = nn.GELU()

    def forward(self, x):
        # 生成 skip connection
        x_skip = self.skip(x)
        # 2x2 局部全局注意力
        x_lga2 = self.lga2(x_skip)
        # 4x4 局部全局注意力
        x_lga4 = self.lga4(x_skip)
        # 第一个 3x3 卷积
        x1 = self.c1(x)
        # 第二个 3x3 卷积
        x2 = self.c2(x1)
        # 第三个 3x3 卷积
        x3 = self.c3(x2)
        # 各个分支结果相加
        x = x1 + x2 + x3 + x_skip + x_lga2 + x_lga4
        # ECA 注意力
        x = self.cn(x)
        # 空间注意力
        x = self.sa(x)
        # Dropout2d
        x = self.drop(x)
        # 批量归一化
        x = self.bn1(x)
        # ReLU 激活
        x = self.relu(x)
        # 返回最终输出
        return x

# 局部全局注意力模块
class LocalGlobalAttention(nn.Module):
    def __init__(self, output_dim, patch_size):
        super().__init__()
        self.output_dim = output_dim
        self.patch_size = patch_size
        # 线性层
        self.mlp1 = nn.Linear(patch_size * patch_size, output_dim // 2)
        # 层归一化
        self.norm = nn.LayerNorm(output_dim // 2)
        # 线性层
        self.mlp2 = nn.Linear(output_dim // 2, output_dim)
        # 1x1 卷积层
        self.conv = nn.Conv2d(output_dim, output_dim, kernel_size=1)
        # 可学习的提示向量
        self.prompt = torch.nn.parameter.Parameter(torch.randn(output_dim, requires_grad=True))
        # 可学习的变换矩阵
        self.top_down_transform = torch.nn.parameter.Parameter(torch.eye(output_dim), requires_grad=True)

    def forward(self, x):
        # 调整维度顺序
        x = x.permute(0, 2, 3, 1)
        B, H, W, C = x.shape
        P = self.patch_size

        # 局部分支
        # 局部补丁提取
        local_patches = x.unfold(1, P, P).unfold(2, P, P)  # (B, H/P, W/P, P, P, C)
        # 调整形状
        local_patches = local_patches.reshape(B, -1, P * P, C)  # (B, H/P*W/P, P*P, C)
        # 计算每个局部补丁的平均值
        local_patches = local_patches.mean(dim=-1)  # (B, H/P*W/P, P*P)

        # MLP 层
        local_patches = self.mlp1(local_patches)  # (B, H/P*W/P, input_dim // 2)
        # 层归一化
        local_patches = self.norm(local_patches)  # (B, H/P*W/P, input_dim // 2)
        # MLP 层
        local_patches = self.mlp2(local_patches)  # (B, H/P*W/P, output_dim)

        # Softmax 激活
        local_attention = F.softmax(local_patches, dim=-1)  # (B, H/P*W/P, output_dim)
        # 注意力加权
        local_out = local_patches * local_attention  # (B, H/P*W/P, output_dim)

        # Cosine 相似性计算
        cos_sim = F.normalize(local_out, dim=-1) @ F.normalize(self.prompt[None, ..., None], dim=1)  # B, N, 1
        # 掩码
        mask = cos_sim.clamp(0, 1)
        # 应用掩码
        local_out = local_out * mask
        # 应用变换
        local_out = local_out @ self.top_down_transform

        # 恢复形状
        local_out = local_out.reshape(B, H // P, W // P, self.output_dim)  # (B, H/P, W/P, output_dim)
        # 调整维度顺序
        local_out = local_out.permute(0, 3, 1, 2)
        # 上采样
        local_out = F.interpolate(local_out, size=(H, W), mode='bilinear', align_corners=False)
        # 1x1 卷积
        output = self.conv(local_out)

        # 返回最终输出
        return output

# ECA 注意力模块
class ECA(nn.Module):
    def __init__(self, in_channel, gamma=2, b=1):
        super(ECA, self).__init__()
        # 计算卷积核大小
        k = int(abs((math.log(in_channel, 2) + b) / gamma))
        kernel_size = k if k % 2 else k + 1
        padding = kernel_size // 2
        # 平均池化
        self.pool = nn.AdaptiveAvgPool2d(output_size=1)
        # 1D 卷积层 + Sigmoid
        self.conv = nn.Sequential(
            nn.Conv1d(in_channels=1, out_channels=1, kernel_size=kernel_size, padding=padding, bias=False),
            nn.Sigmoid()
        )

    def forward(self, x):
        # 平均池化
        out = self.pool(x)
        # 调整维度
        out = out.view(x.size(0), 1, x.size(1))
        # 1D 卷积 + Sigmoid
        out = self.conv(out)
        # 调整维度
        out = out.view(x.size(0), x.size(1), 1, 1)
        # 返回注意力权重乘以原始输入
        return out * x

# 卷积块
class conv_block(nn.Module):
    def __init__(self,
                 in_features,
                 out_features,
                 kernel_size=(3, 3),
                 stride=(1, 1),
                 padding=(1, 1),
                 dilation=(1, 1),
                 norm_type='bn',
                 activation=True,
                 use_bias=True,
                 groups=1
                 ):
        super().__init__()
        # 定义卷积层
        self.conv = nn.Conv2d(in_channels=in_features,
                              out_channels=out_features,
                              kernel_size=kernel_size,
                              stride=stride,
                              padding=padding,
                              dilation=dilation,
                              bias=use_bias,
                              groups=groups)

        self.norm_type = norm_type
        self.act = activation

        # 根据归一化类型选择不同的归一化层
        if self.norm_type == 'gn':
            self.norm = nn.GroupNorm(32 if out_features >= 32 else out_features, out_features)
        elif self.norm_type == 'bn':
            self.norm = nn.BatchNorm2d(out_features)
        # 激活函数
        if self.act:
            # self.relu = nn.GELU()
            self.relu = nn.ReLU(inplace=False)

    def forward(self, x):
        # 卷积层
        x = self.conv(x)
        # 归一化层
        if self.norm_type is not None:
            x = self.norm(x)
        # 激活函数
        if self.act:
            x = self.relu(x)
        # 返回输出
        return x

# 主程序入口
if __name__ == '__main__':
    # 创建 PPA 模块实例
    block = PPA(in_features=64, filters=64)  # in_features:输入通道数,filters:输出通道数
    # 创建随机输入
    input = torch.rand(32, 64, 32, 32)
    # 前向传播
    output = block(input)
    # 打印输入和输出的大小
    print(input.size())
    print(output.size())
    print("抖音、B站、小红书、CSDN同号")
    print("布尔大学士 提醒您:代码无误~~~~")

  • 31
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

布尔大学士

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值