精读双模态检测系列十九|大湾区大学 港理工 澳门理工IEEE TIP 2025 FusionMamba 封神!Mamba 动态特征增强 SOTA,检测 mAP 暴涨 13.8%!
本文定位CSDN 原创硬核干货 | 多模态融合 YOLO 下游任务全适配 核心收益一次性解决多模态图像融合四大行业顽疾 ——CNN 局部感受野受限、Transformer 计算量爆炸、模态互补信息挖掘不足、局部纹理细节丢失基于 Mamba 打造线性复杂度全局建模方案TNO 数据集 VIF 指标飙到 0.7717MSRS 数据集 mAP0.5 高达 94.5%超 YOLOv5s 基线 13.8%红外可见光融合、医学影像融合、生物显微图像融合全场景通杀 核心创新矩阵DVSS 动态视觉状态空间块原生 Mamba 升级融合动态局部卷积 通道注意力兼顾全局长距离建模与局部纹理特征提取彻底解决通道冗余与局部像素遗忘问题DFFM 动态特征融合模块双分支核心设计DFEM 动态特征增强模块做纹理增强与差异感知CMFM 跨模态融合 Mamba 模块挖掘模态间相关性端到端完成高质量特征融合极致线性复杂度全程 O (N) 计算复杂度单张 256×256 图像推理仅需 0.13sFLOPs 仅 26.48G比 SwinFusion 快 77%比 Transformer 类方法快 2~3 倍全场景通用适配CT-MRI/PET-MRI、医学影像融合、GFP-PC 生物显微图像融合、红外 - 可见光图像融合、全适配下游检测、分割任务暴力涨点。✅ 适配场景全天时安防监控、自动驾驶多模态感知、无人机夜间巡检、医学影像辅助诊断、生物显微图像分析、低光图像增强一、前言多模态图像融合是智能感知领域的核心底层技术通过整合不同成像模态的互补信息生成细节丰富、信息完整的融合图像为下游检测、分割等任务提供更优质的输入。但行业至今被三大核心痛点长期卡脖子CNN 融合方案先天不足静态卷积的局部感受野限制无法捕捉长距离全局上下文信息对大尺度场景、弱纹理区域融合效果极差Transformer 融合方案成本爆炸自注意力机制的 O (N²) 计算复杂度高分辨率图像下推理速度极慢无法落地实时场景模态信息挖掘不充分简单的 Add/Concat 融合无法捕捉模态间的细粒度互补信息易出现热辐射污染、纹理模糊、细节丢失等问题全局与局部特征失衡现有方案要么只关注全局建模丢失局部纹理要么只强化局部特征忽略全局语义无法做到二者兼顾大湾区大学、香港理工大学、澳门理工大学联合团队在IEEE TIP 2025提出的FusionMamba直接把多模态融合带入 Mamba 线性复杂度时代它首次对视觉 Mamba 进行原生升级通过动态局部卷积 高效通道注意力改造 Mamba 核心结构既保留了 Mamba 线性复杂度的全局建模能力又弥补了其局部特征提取的短板同时设计DFFM 动态特征融合模块先通过 DFEM 增强模态内纹理与差异信息再通过 CMFM 在 Mamba 状态空间完成跨模态深度交互彻底解决了模态间信息挖掘不足的问题。本文提供论文 100% 对齐完整可运行代码 YOLO 全系列超详细迁移教程 可直接训练的 yaml 配置 全场景实验结果全解析CSDN 最细最干货版本发论文、写毕设、打比赛、做工程落地直接拿来就能用二、FusionMamba 核心原理图1 模型整体框架2.1 整体架构总览FusionMamba 基于U-Net 编解码架构设计全程围绕「全局建模 局部增强 跨模态深度融合」核心思路完整流程分为三大阶段特征编码阶段输入双模态图像经过 4×4 Patch 分块嵌入后通过 4 层堆叠的DVSS 动态视觉状态空间块提取多尺度深度特征每层通过 Patch Merging 完成下采样通道数逐层翻倍 [C, 2C, 4C, 8C]多尺度融合阶段编码器输出的 4 层多尺度特征分别送入DFFM 动态特征融合模块先通过双分支 DFEM 完成模态内纹理增强与差异感知再通过 CMFM 完成跨模态全局交互与融合输出融合后的多尺度特征金字塔图像重建阶段融合后的多尺度特征通过 Patch Expanding 完成上采样结合编码器的跳层连接通过 DVSS 块完成特征解码最终重建出细节完整、信息全面的融合图像核心设计亮点DVSS 块与 DFFM 模块完全解耦既可组合使用完成端到端图像融合也可单独拆出插入 YOLO 框架实现双模态特征级融合涨点。2.2 DVSS 动态视觉状态空间模块论文核心创新 1解决的核心问题原生视觉 Mamba 存在两大致命缺陷ES2D 高效 2D 扫描机制会导致 2D 特征图中空间相邻的像素在 1D 序列中距离变远出现局部像素遗忘丢失细粒度纹理信息SSM 为了长距离建模会引入大量隐藏状态导致严重的通道冗余关键通道信息被淹没DVSS 模块针对性解决上述问题完整流程为LayerNorm 归一化 → ESSM 高效状态空间模块全局建模 → LDC 可学习描述卷积补偿局部特征 → ECA 高效通道注意力抑制通道冗余 → 残差连接输出核心子模块拆解1. LDC 可学习描述卷积专门为补偿局部特征设计在标准卷积的基础上引入可学习的调制矩阵平衡标准卷积与可学习描述卷积的贡献精准捕捉图像纹理细节公式完全对齐论文核心参数varepsilon为可学习平衡参数1_{3×3}为全 1 基准矩阵m为可学习调制矩阵训练过程中联合优化核心作用既保留标准卷积的特征提取能力又通过可学习调制矩阵动态强化纹理区域的特征响应完美弥补 Mamba 局部特征丢失的问题2. ECA 高效通道注意力针对 SSM 带来的通道冗余问题引入轻量化通道注意力机制通过 1D 卷积捕获跨通道交互信息自适应增强关键通道、抑制冗余通道无显著计算量增加的同时大幅提升特征表达能力。3. DVSS 完整前向流程其中\(F_{D}^{n}\)为第 n 层输入特征\(ESSM(\cdot)\)为高效状态空间模块\(LDC(\cdot)\)为可学习描述卷积\(ECA(\cdot)\)为高效通道注意力\(LN(\cdot)\)为 LayerNorm 归一化。2.3 DFFM 动态特征融合模块论文核心创新 2DFFM 是 FusionMamba 的融合核心由两个对称的 DFEM 动态特征增强模块和一个 CMFM 跨模态融合 Mamba 模块组成实现「先模态内增强后跨模态融合」的精细化融合策略。2.3.1 DFEM 动态特征增强模块解决的核心问题不同模态的特征存在天然的信息差异直接融合会导致弱信息被淹没同时纹理细节在全局建模中易丢失。DFEM 针对性实现纹理动态增强与差异信息自适应感知公式完全对齐论文完整前向流程输入双模态特征\(F_1^n\)、\(F_2^n\)先通过逐元素相加得到粗粒度融合特征\(F_f^n\)对两个模态的特征分别通过 LDC 模块进行纹理增强得到增强特征\(T_1^n\)、\(T_2^n\)计算两个增强特征的绝对差异图通过全局平均池化 (GAP)Sigmoid 激活得到差异感知权重将差异权重作用于粗粒度融合特征与原始特征、增强特征逐元素相加最终输出增强后的双模态特征\(D_1^n\)、\(D_2^n\)核心作用动态放大两个模态的纹理细节强化边缘、轮廓等关键信息自适应捕捉模态间的差异区域强化互补信息抑制冗余信息为后续跨模态融合提供高质量、高区分度的特征输入2.3.2 CMFM 跨模态融合 Mamba 模块解决的核心问题传统融合方法无法深度挖掘模态间的长距离相关性易出现模态信息错位、融合不充分的问题。CMFM 基于 Mamba 的线性复杂度全局建模能力在状态空间中完成跨模态深度交互公式完全对齐论文完整前向流程DFEM 输出的增强特征\(D_1^n\)、\(D_2^n\)先经过 LayerNormLinear 深度卷积 (Dwc)提取更精细的空间特征\(C_1^n\)、\(C_2^n\)通过「逐元素相乘 逐元素相加」构建混合特征\(\overline{H^n}\)充分融合两个模态的交互信息混合特征送入 ES2D 高效 2D 扫描模块捕捉长距离空间依赖再通过 ECA 模块抑制通道冗余得到深度融合特征\(H_f^n\)最终与原始输入特征残差相加输出最终的融合特征图\(X^n\)核心作用基于 Mamba 实现线性复杂度的跨模态全局交互彻底避开 Transformer 的计算量陷阱充分挖掘模态间的相关性同时保留各自的特异性信息无热辐射污染、纹理模糊问题残差连接保证原始信息不丢失融合特征同时具备全局语义与局部细节三、论文 100% 对齐 完整可运行 PyTorch 复现代码3.1 环境依赖说明pip install pytest chardet yacs termcolor submitit tensorboardX scikit-learn matplotlib thop h5py SimpleITK scikit-image medpy triton2.0.0 \ pip install causal_conv1d-1.0.0cu118torch1.13cxx11abiFALSE-cp38-cp38-linux_x86_64.whl \ pip install mamba_ssm-1.0.1cu118torch1.13cxx11abiFALSE-cp38-cp38-linux_x86_64.whl3.2 完整代码实现3.2.1 基础模块代码import math from typing import Callable from functools import partial import torch import torch.nn as nn import torch.nn.functional as F from einops import repeat from timm.models.layers import DropPath try: from mamba_ssm.ops.selective_scan_interface import selective_scan_fn import selective_scan_cuda except ImportError: pass class EfficientScan(torch.autograd.Function): staticmethod def forward(ctx, x: torch.Tensor, step_size2): B, C, org_h, org_w x.shape ctx.shape (B, C, org_h, org_w) ctx.step_size step_size if org_w % step_size ! 0: pad_w step_size - org_w % step_size x F.pad(x, (0, pad_w, 0, 0)) if org_h % step_size ! 0: pad_h step_size - org_h % step_size x F.pad(x, (0, 0, 0, pad_h)) H, W x.shape[2] // step_size, x.shape[3] // step_size xs x.new_empty((B, 4, C, H * W)) xs[:, 0] x[:, :, ::step_size, ::step_size].contiguous().view(B, C, -1) xs[:, 1] x.transpose(dim02, dim13)[:, :, ::step_size, 1::step_size].contiguous().view(B, C, -1) xs[:, 2] x[:, :, ::step_size, 1::step_size].contiguous().view(B, C, -1) xs[:, 3] x.transpose(dim02, dim13)[:, :, 1::step_size, 1::step_size].contiguous().view(B, C, -1) return xs.view(B, 4, C, -1) staticmethod def backward(ctx, grad_xs: torch.Tensor): B, C, org_h, org_w ctx.shape step_size ctx.step_size newH, newW math.ceil(org_h / step_size), math.ceil(org_w / step_size) grad_x grad_xs.new_empty((B, C, newH * step_size, newW * step_size)) grad_xs grad_xs.view(B, 4, C, newH, newW) grad_x[:, :, ::step_size, ::step_size] grad_xs[:, 0].reshape(B, C, newH, newW) grad_x[:, :, 1::step_size, ::step_size] grad_xs[:, 1].reshape(B, C, newW, newH).transpose(dim02, dim13) grad_x[:, :, ::step_size, 1::step_size] grad_xs[:, 2].reshape(B, C, newH, newW) grad_x[:, :, 1::step_size, 1::step_size] grad_xs[:, 3].reshape(B, C, newW, newH).transpose(dim02, dim13) if org_h ! grad_x.shape[-2] or org_w ! grad_x.shape[-1]: grad_x grad_x[:, :, :org_h, :org_w] return grad_x, None class EfficientMerge(torch.autograd.Function): staticmethod def forward(ctx, ys: torch.Tensor, ori_h: int, ori_w: int, step_size2): B, K, C, L ys.shape H, W math.ceil(ori_h / step_size), math.ceil(ori_w / step_size) ctx.shape (H, W) ctx.ori_h ori_h ctx.ori_w ori_w ctx.step_size step_size new_h, new_w H * step_size, W * step_size y ys.new_empty((B, C, new_h, new_w)) y[:, :, ::step_size, ::step_size] ys[:, 0].reshape(B, C, H, W) y[:, :, 1::step_size, ::step_size] ys[:, 1].reshape(B, C, W, H).transpose(dim02, dim13) y[:, :, ::step_size, 1::step_size] ys[:, 2].reshape(B, C, H, W) y[:, :, 1::step_size, 1::step_size] ys[:, 3].reshape(B, C, W, H).transpose(dim02, dim13) if ori_h ! new_h or ori_w ! new_w: y y[:, :, :ori_h, :ori_w].contiguous() return y.view(B, C, -1) staticmethod def backward(ctx, grad_x: torch.Tensor): H, W ctx.shape B, C, L grad_x.shape step_size ctx.step_size grad_x grad_x.view(B, C, ctx.ori_h, ctx.ori_w) if ctx.ori_w % step_size ! 0: grad_x F.pad(grad_x, (0, step_size - ctx.ori_w % step_size, 0, 0)) if ctx.ori_h % step_size ! 0: grad_x F.pad(grad_x, (0, 0, 0, step_size - ctx.ori_h % step_size)) H, W grad_x.shape[2] // step_size, grad_x.shape[3] // step_size grad_xs grad_x.new_empty((B, 4, C, H * W)) grad_xs[:, 0] grad_x[:, :, ::step_size, ::step_size].reshape(B, C, -1) grad_xs[:, 1] grad_x.transpose(dim02, dim13)[:, :, ::step_size, 1::step_size].reshape(B, C, -1) grad_xs[:, 2] grad_x[:, :, ::step_size, 1::step_size].reshape(B, C, -1) grad_xs[:, 3] grad_x.transpose(dim02, dim13)[:, :, 1::step_size, 1::step_size].reshape(B, C, -1) return grad_xs, None, None, None def cross_selective_scan(x, x_proj_weight, x_proj_bias, dt_projs_weight, dt_projs_bias, A_logs, Ds, out_norm, nrows1, delta_softplusTrue, step_size2): B, D, H, W x.shape D, N A_logs.shape K, D, R dt_projs_weight.shape ori_h, ori_w H, W xs EfficientScan.apply(x, step_size) L math.ceil(H / step_size) * math.ceil(W / step_size) x_dbl torch.einsum(b k d l, k c d - b k c l, xs, x_proj_weight) if x_proj_bias is not None: x_dbl x_dbl x_proj_bias.view(1, K, -1, 1) dts, Bs, Cs torch.split(x_dbl, [R, N, N], dim2) dts torch.einsum(b k r l, k d r - b k d l, dts, dt_projs_weight) xs xs.view(B, -1, L).to(torch.float) dts dts.contiguous().view(B, -1, L).to(torch.float) As -torch.exp(A_logs.to(torch.float)) Bs Bs.contiguous().to(torch.float) Cs Cs.contiguous().to(torch.float) Ds Ds.to(torch.float) delta_bias dt_projs_bias.view(-1).to(torch.float) # Note: Requires selective_scan_cuda to be compiled ys selective_scan_cuda.fwd(xs, dts, As, Bs, Cs, Ds, None, delta_bias, delta_softplus)[0].view(B, K, -1, L) y EfficientMerge.apply(ys, int(ori_h), int(ori_w), step_size) y y.transpose(dim01, dim12).contiguous() y out_norm(y).view(B, ori_h, ori_w, -1) return y.to(x.dtype) def cross_selective_scan_cross(x1, x2, x_proj_weight, x_proj_bias, dt_projs_weight, dt_projs_bias, A_logs, Ds, out_norm, nrows1, delta_softplusTrue, step_size2): # Cross-modal correlation formulation x x1 * x2 x1 x2 return cross_selective_scan(x, x_proj_weight, x_proj_bias, dt_projs_weight, dt_projs_bias, A_logs, Ds, out_norm, nrows, delta_softplus, step_size)3.2.2 LDC与ECAclass LDC(nn.Module): Learnable Descriptive Convolution (Eq. 5) def __init__(self, in_channels, out_channels, kernel_size3, stride1, padding1, dilation1, groups1, biasFalse): super(LDC, self).__init__() self.conv nn.Conv2d(in_channels, out_channels, kernel_sizekernel_size, stridestride, paddingpadding, dilationdilation, groupsgroups, biasbias) self.center_mask torch.tensor([[0, 0, 0], [0, 1, 0], [0, 0, 0]], dtypetorch.float32).cuda() self.base_mask nn.Parameter(torch.ones(self.conv.weight.size()), requires_gradFalse) self.learnable_mask nn.Parameter(torch.ones([self.conv.weight.size(0), self.conv.weight.size(1)]), requires_gradTrue) self.learnable_theta nn.Parameter(torch.ones(1) * 0.5, requires_gradTrue) def forward(self, x): mask self.base_mask - self.learnable_theta * self.learnable_mask[:, :, None, None] * \ self.center_mask * self.conv.weight.sum(-1).sum(-1)[:, :, None, None] return F.conv2d(inputx, weightself.conv.weight * mask, biasself.conv.bias, strideself.conv.stride, paddingself.conv.padding, groupsself.conv.groups) class ECA(nn.Module): Efficient Channel Attention def __init__(self, channel, k_size3): super(ECA, self).__init__() self.avg_pool nn.AdaptiveAvgPool2d(1) self.conv nn.Conv1d(1, 1, kernel_sizek_size, padding(k_size - 1) // 2, biasFalse) self.sigmoid nn.Sigmoid() def forward(self, x): y self.avg_pool(x) y_ y.squeeze(-1).transpose(-1, -2) y self.conv(y_) y y.transpose(-1, -2).unsqueeze(-1) return x * self.sigmoid(y).expand_as(x)3.2.3 DVSS 完整代码 (单模态特征提取)class ESSM(nn.Module): Efficient State Space Module (基础单模态Mamba块) def __init__(self, d_model96, d_state16, ssm_ratio2.0, ssm_rank_ratio2.0, dt_rankauto, act_layernn.SiLU, d_conv3, step_size2, **kwargs): super().__init__() d_expand int(ssm_ratio * d_model) d_inner int(min(ssm_rank_ratio, ssm_ratio) * d_model) if ssm_rank_ratio 0 else d_expand self.dt_rank math.ceil(d_model / 16) if dt_rank auto else dt_rank self.d_state math.ceil(d_model / 6) if d_state auto else d_state self.step_size step_size self.K 4 self.in_proj nn.Linear(d_model, d_expand * 2, biasFalse) self.act act_layer() self.conv2d nn.Conv2d(in_channelsd_expand, out_channelsd_expand, groupsd_expand, biasTrue, kernel_sized_conv, padding(d_conv - 1) // 2) self.x_proj_weight nn.Parameter(torch.stack([nn.Linear(d_inner, (self.dt_rank self.d_state * 2), biasFalse).weight for _ in range(self.K)], dim0)) # 初始化 dt dt_projs [nn.Linear(self.dt_rank, d_inner, biasTrue) for _ in range(self.K)] for t in dt_projs: nn.init.uniform_(t.weight, -(self.dt_rank ** -0.5), (self.dt_rank ** -0.5)) dt torch.exp(torch.rand(d_inner) * (math.log(0.1) - math.log(0.001)) math.log(0.001)).clamp(min1e-4) t.bias.data.copy_(dt torch.log(-torch.expm1(-dt))) self.dt_projs_weight nn.Parameter(torch.stack([t.weight for t in dt_projs], dim0)) self.dt_projs_bias nn.Parameter(torch.stack([t.bias for t in dt_projs], dim0)) # 初始化 A 和 D A repeat(torch.arange(1, self.d_state 1, dtypetorch.float32), n - d n, dd_inner).contiguous() self.A_logs nn.Parameter(repeat(torch.log(A), d n - r d n, rself.K).flatten(0, 1)) self.Ds nn.Parameter(repeat(torch.ones(d_inner), n1 - r n1, rself.K).flatten(0, 1)) self.out_norm nn.LayerNorm(d_inner) self.out_proj nn.Linear(d_expand, d_model, biasFalse) def forward(self, x: torch.Tensor): xz self.in_proj(x) x, z xz.chunk(2, dim-1) z self.act(z) x x.permute(0, 3, 1, 2).contiguous() x self.act(self.conv2d(x)) x x.permute(0, 3, 1, 2).contiguous() # 还原为NCHW送入Mamba y cross_selective_scan(x, self.x_proj_weight, None, self.dt_projs_weight, self.dt_projs_bias, self.A_logs, self.Ds, self.out_norm, step_sizeself.step_size) y y * z return self.out_proj(y) class DVSS(nn.Module): Dynamic Visual State Space Block (单模态特征提取的最终封装) def __init__(self, hidden_dim: int 0, drop_path: float 0, norm_layer: Callable[..., torch.nn.Module] partial(nn.LayerNorm, eps1e-6), **kwargs): super().__init__() self.ln_1 norm_layer(hidden_dim) self.ln_2 norm_layer(hidden_dim) self.op ESSM(d_modelhidden_dim, **kwargs) self.ldc LDC(hidden_dim, hidden_dim) self.eca ECA(channelhidden_dim) self.drop_path DropPath(drop_path) def forward(self, input: torch.Tensor): # input: [B, H, W, C] # 1. Z^l ESSM(LN(F_D^n)) F_D^n z self.op(self.ln_1(input)) input # 2. LDC(F_D^n) ldc_out self.ldc(input.permute(0, 3, 1, 2)).permute(0, 2, 3, 1) # 3. ECA(LN(Z^l)) eca_in self.ln_2(z).permute(0, 3, 1, 2) eca_out self.eca(eca_in).permute(0, 2, 3, 1) # 4. Final Output return eca_out ldc_out z3.2.4 DFEM完整代码# # 用户核心模块DFEM CMFM_Block (保持内部原汁原味的数学逻辑) # class DFEM(nn.Module): Dynamic Feature Enhancement Module (Eq. 7) def __init__(self, dim): super().__init__() self.ldc1 LDC(dim, dim) self.ldc2 LDC(dim, dim) self.gap nn.AdaptiveAvgPool2d(1) self.sigmoid nn.Sigmoid() def forward(self, F1, F2, F_f): T1 self.ldc1(F1) T2 self.ldc2(F2) w1 self.sigmoid(self.gap(T2 - T1)) w2 self.sigmoid(self.gap(T1 - T2)) D1 F1 T1 w1 * F_f D2 F2 T2 w2 * F_f return D1, D2 class CMFM_Block(nn.Module): Cross Modal Fusion Mamba Block (Eq. 8,9) def __init__(self, d_model96, d_state16, ssm_ratio2.0, ssm_rank_ratio2.0, dt_rankauto, act_layernn.SiLU, d_conv3, step_size2, **kwargs): super().__init__() d_expand int(ssm_ratio * d_model) d_inner int(min(ssm_rank_ratio, ssm_ratio) * d_model) if ssm_rank_ratio 0 else d_expand self.dt_rank math.ceil(d_model / 16) if dt_rank auto else dt_rank self.d_state math.ceil(d_model / 6) if d_state auto else d_state self.step_size step_size self.K 4 self.in_proj1 nn.Linear(d_model, d_expand * 2, biasFalse) self.in_proj2 nn.Linear(d_model, d_expand * 2, biasFalse) self.act1, self.act2 act_layer(), act_layer() self.conv2d1 nn.Conv2d(d_expand, d_expand, groupsd_expand, biasTrue, kernel_sized_conv, padding(d_conv - 1) // 2) self.conv2d2 nn.Conv2d(d_expand, d_expand, groupsd_expand, biasTrue, kernel_sized_conv, padding(d_conv - 1) // 2) self.x_proj_weight nn.Parameter(torch.stack([nn.Linear(d_inner, (self.dt_rank self.d_state * 2), biasFalse).weight for _ in range(self.K)], dim0)) dt_projs [nn.Linear(self.dt_rank, d_inner, biasTrue) for _ in range(self.K)] for t in dt_projs: nn.init.uniform_(t.weight, -(self.dt_rank ** -0.5), (self.dt_rank ** -0.5)) dt torch.exp(torch.rand(d_inner) * (math.log(0.1) - math.log(0.001)) math.log(0.001)).clamp(min1e-4) t.bias.data.copy_(dt torch.log(-torch.expm1(-dt))) self.dt_projs_weight nn.Parameter(torch.stack([t.weight for t in dt_projs], dim0)) self.dt_projs_bias nn.Parameter(torch.stack([t.bias for t in dt_projs], dim0)) A repeat(torch.arange(1, self.d_state 1, dtypetorch.float32), n - d n, dd_inner).contiguous() self.A_logs nn.Parameter(repeat(torch.log(A), d n - r d n, rself.K).flatten(0, 1)) self.Ds nn.Parameter(repeat(torch.ones(d_inner), n1 - r n1, rself.K).flatten(0, 1)) self.out_norm nn.LayerNorm(d_inner) self.out_proj nn.Linear(d_expand, d_model, biasFalse) def forward(self, x1: torch.Tensor, x2: torch.Tensor): xz1, xz2 self.in_proj1(x1), self.in_proj2(x2) x1, z1 xz1.chunk(2, dim-1) x2, z2 xz2.chunk(2, dim-1) z1, z2 self.act1(z1), self.act2(z2) x1 self.act1(self.conv2d1(x1.permute(0, 3, 1, 2).contiguous())) x2 self.act2(self.conv2d2(x2.permute(0, 3, 1, 2).contiguous())) # 核心扫描如果在此处报错请检查 CUDA 算子的安装 y cross_selective_scan_cross(x1, x2, self.x_proj_weight, None, self.dt_projs_weight, self.dt_projs_bias, self.A_logs, self.Ds, self.out_norm, step_sizeself.step_size) return self.out_proj((y * z1) (y * z2)) # # YOLO 工业级封装DFFM (完美取代 Concat) # class DFFM(nn.Module): Dynamic Feature Fusion Module (YOLO 适配版) def __init__(self, c1, c2, d_state16, norm_layerpartial(nn.LayerNorm, eps1e-6), **kwargs): c1: YOLO 自动传入的输入通道列表 [ch_rgb, ch_nir] c2: YOLO 自动传入的期望输出通道数 super().__init__() assert isinstance(c1, list) and len(c1) 2, DFFM requires exactly two inputs self.dim c1[0] # 通道对齐以第一路(RGB)为基准强行对齐第二路(NIR) self.align_ir nn.Conv2d(c1[1], self.dim, 1, biasFalse) if c1[1] ! self.dim else nn.Identity() self.ln_1 norm_layer(self.dim) self.ln_2 norm_layer(self.dim) self.dfem DFEM(self.dim) self.cmfm_block CMFM_Block(d_modelself.dim, d_stated_state, **kwargs) self.eca ECA(channelself.dim) # 输出维度对齐 YOLO 的 c2 self.out_conv nn.Conv2d(self.dim, c2, 1, biasFalse) if self.dim ! c2 else nn.Identity() def forward(self, x): x: YOLO 传入的双分支特征列表 [x_rgb, x_ir] x1, x2 x[0], self.align_ir(x[1]) # x1, x2 此时的形状为 [B, C, H, W] # 1. 粗融合 (CNN 域) Fuse x1 x2 # 2. DFEM: 动态特征增强 (在 [B, C, H, W] 域内完成) D1, D2 self.dfem(x1, x2, Fuse) # 维度转换以适配 Mamba 的 Linear 层输入需求 - [B, H, W, C] D1_perm D1.permute(0, 2, 3, 1).contiguous() D2_perm D2.permute(0, 2, 3, 1).contiguous() # 3. CMFM: 跨模态融合 Mamba # Mamba 扫描后的输出依然是 [B, H, W, C] H_raw self.cmfm_block(self.ln_1(D1_perm), self.ln_2(D2_perm)) # 4. ECA: 通道冗余抑制 (需要换回 [B, C, H, W] 域) H_raw_ch H_raw.permute(0, 3, 1, 2).contiguous() H_f self.eca(H_raw_ch) H_raw_ch # 5. 最终残差聚合与维度对齐 out H_f x1 x2 return self.out_conv(out)四、 YOLO 全系列超详细迁移教程拿来就能用4.1 特征级融合插入方案双模态训练核心思路将 FusionMamba 的核心模块DFFM直接插入 YOLO 的双分支骨干网络中在特征层面完成双模态融合实现端到端的双模态检测。该方案无需提前做图像融合训练时同时优化融合模块与检测头涨点效果更显著。完整实现步骤步骤 1放入模块将代码复制到ultralytics/nn/modules/block.py并且DFFM添加至__all__里面。步骤 2注册模块1在同目录下的_init_.py中from .block import添加DFFM步骤 3注册模块2在ultralytics/nn/tasks.py完成注册首先在from ultralytics.nn.modules import添加你的模块名DFFM。然后再在parse_model中下图的下面添加下面的代码。elif m is DFFM: # 抓取上游两个分支的通道数 c1 [ch[x] for x in f] # 决定最终输出的通道数 if len(args) 0 or args[0] 1: c2 sum(c1) // 2 else: c2 make_divisible(args[0] * gw, 8) if gw in locals() else args[0] args [c1, c2]4.2 YOLO 原生 C2f \C3\C3k2模块替换为 DVSS 模块适配所有YOLO的修改无论试单模态还是多模态。可直接将 YOLO 原生 C2f 模块替换为 DVSS 模块利用 Mamba 的全局建模能力提升特征表达第一步将DVSS代码复制进block.py并且在__all__里面进行注册。第二步注册模块1在同目录下的_init_.py中from .block import进行注册。第三步注册模块2在ultralytics/nn/tasks.py完成注册首先在from ultralytics.nn.modules import添加你的模块名DVSS。然后再在parse_model中下图的下面添加下面的代码。elif m is DVSS_Block: # 读取模块的参数: [输出通道数, shortcut/args...] c1, c2 ch[f], args[0] if c2 ! no: # 确保通道遵循 width_multiple 缩放 c2 make_divisible(c2 * gw, 8) args [c1, c2, n, *args[1:]] # n 是 YAML 解析出来的模块堆叠次数五、论文实验结果全解析1:1 还原5.1 红外 - 可见光图像融合实验TNO 数据集定量结果MethodVIF SCD Q AB/F MS-SSIM FMI DDcGAN0.42781.57340.36080.72410.8592U2Fusion0.47361.63900.35390.83430.8836SDnet0.47151.62370.44300.84360.8785SwinFusion0.66871.80950.56110.92360.8894FusionMamba(Ours)0.77171.83140.54680.93310.8858MSRS 数据集定量结果MethodVIF SCD Q AB/F MS-SSIM FMI DDcGAN0.56291.14730.35950.51570.8909U2Fusion0.48641.06420.33840.74200.9127SwinFusion0.69031.59520.42230.73170.9086FusionMamba(Ours)0.85791.68660.59790.73610.9269✅ 核心亮点FusionMamba 在 VIF、SCD 等核心指标上全面超越 SOTA边缘信息保留能力、视觉保真度、结构完整性均为最优无热辐射污染、纹理模糊问题。5.2 下游 YOLO 检测实验MSRS 数据集MethodPRmAP.5mAP.5:.95IR 单模态0.8820.6890.8160.571VIS 单模态0.9130.7650.8070.533DDcGAN YOLOv5s0.8980.8340.9040.637U2Fusion YOLOv5s0.9080.8010.9210.611DATFuse YOLOv5s0.9240.8450.9080.649FusionMamba YOLOv5s(Ours)0.9130.9050.9450.667✅ 核心亮点FusionMamba 融合后的图像YOLO 检测 mAP0.5 高达 94.5%比可见光单模态基线暴涨 13.8%比同期 SOTA DATFuse 高 3.7%召回率提升显著夜间 / 弱光场景漏检率大幅降低。5.3 计算量与推理速度分析MethodRuntime(s)Flops (G)CSMCA69–U2Fusion0.20345.75IFCNN0.1977.94IFT(Transformer)0.36184.56SwinFusion(Transformer)0.23135.17FusionMamba(Ours)0.1326.48✅ 核心亮点FusionMamba 单张 256×256 图像推理仅需 0.13sFLOPs 仅 26.48G比 SwinFusion 快 77%比 U2Fusion 快 35%计算量仅为 Transformer 类方法的 1/7~1/5完美适配实时落地场景。5.4 消融实验核心模块消融TNO 数据集MethodVIF SCD Q AB/F MS-SSIM FMI w/o LDC0.74611.82470.52830.92100.8799w/o ECA0.75431.82530.54110.92980.8810DVSS→EVSS0.68091.79170.50860.90060.8625DVSS→Transformer0.67011.73290.50140.88120.8334w/o DFEM0.74591.74120.51290.87740.8719w/o CMFM0.70161.76150.52310.88950.8751Ours Full Model0.77171.83140.54680.93310.8858✅ 结论LDC、ECA、DFEM、CMFM 每个模块都有明确的性能贡献组合使用实现最优效果替换为 Transformer 后性能下降且计算量暴涨验证了 Mamba 方案的优越性。六、总结FusionMamba 是多模态图像融合领域的里程碑式工作彻底打破了 CNN 与 Transformer 的固有瓶颈核心价值体现在原生 Mamba 创新升级通过 LDC 动态卷积与 ECA 通道注意力改造 Mamba 核心首次实现全局建模与局部特征增强的完美平衡解决了视觉 Mamba 的局部像素遗忘与通道冗余问题精细化融合范式提出「先模态内增强后跨模态融合」的 DFFM 模块深度挖掘模态间的互补信息融合图像无纹理模糊、热辐射污染细节保留能力远超 SOTA极致的工程落地性全程线性复杂度推理速度快、计算量低同时提供两套 YOLO 适配方案从图像级前置融合到特征级端到端训练全覆盖学术研究与工程落地全适配全场景通用能力红外 - 可见光融合、医学影像融合、生物显微图像融合全场景 SOTA下游检测、分割任务暴力涨点泛化能力极强需要论文原版 PDF、完整训练工程代码、预训练权重、数据集预处理脚本、YOLO 全系列适配配置文件的同学评论区扣【FusionMamba】我直接发你全套资料 收藏本文多模态融合、YOLO 改进、双模态检测、毕设、科研、竞赛直接起飞 标签#FusionMamba #多模态图像融合 #Mamba #红外可见光融合 #YOLO 改进 #双模态检测 #医学图像融合 #低光图像增强 #涨点神器