顶级期刊即插即用模块代码共享计划·2024第一期:01:波叠加原理的社会池化方法(AAAI2023)与并行补丁感知注意力模块(2024)代码实现
本文介绍了一种基于波叠加原理的社会池化方法(Wave-pooling),用于更有效地捕捉动态和高阶交互,并预测周围车辆的运动轨迹。该方法通过将每个车辆建模为具有振幅和相位的波来表示其动态状态,并通过波的叠加来捕捉它们之间的高阶动态交互。同时,本文还介绍了一种名为HCF-Net的深度学习方法,该方法通过引入多个实用模块显著提高了红外小物体检测的性能,解决了小物体检测中常见的挑战,如小物体信息丢失和背景杂乱问题。【有代码实现】
顶级期刊即插即用模块代码共享计划·2024第一期:01:波叠加原理的社会池化方法(AAAI2023)与并行补丁感知注意力模块(2024)代码实现
- 改进方案1 WSiP: Wave Superposition Inspired Pooling for Dynamic Interactions-Aware Trajectory Prediction
- 1.1 摘要总结
- 1.2 结构图
- 1.3 应用场景
- 1.4 创新模块及其介绍
- 1.5 所解决问题
- 1.6 创新点
- 1.7 代码实现及其注释
- 改进方案2 HCF-Net: Hierarchical Context Fusion Network for Infrared Small Object Detection
- 2.1 摘要总结
- 2.2 结构图
- 2.2.1 PPA模块
- 2.3创新模块及其介绍
- 2.4 创新点
- 2.5 所解决问题
- 应用场景
- 2.6 实验结果
- 2.6.1 可视化结果
- 2.6.2 消融实验
- 2.7 代码实现及其注释
改进方案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 Ffrom timm.models.layers import DropPath
# pip install timm == 1.0.8class 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) # 假设输入特征的通道数为 64input = 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,填充为 3self.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)# 卷积层 + Sigmoidout = self.sigmoid(self.conv2d(out))# 返回注意力权重乘以原始输入return out * x# 多级注意力金字塔模块
class PPA(nn.Module):def __init__(self, in_features, filters) -> None:super().__init__()# 1x1 卷积层,用于生成 skip connectionself.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 connectionx_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)# Dropout2dx = 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_dimself.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.shapeP = 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 + 1padding = kernel_size // 2# 平均池化self.pool = nn.AdaptiveAvgPool2d(output_size=1)# 1D 卷积层 + Sigmoidself.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 卷积 + Sigmoidout = 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_typeself.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("布尔大学士 提醒您:代码无误~~~~")