把 MambaOut 塞进 YOLOv11:会有什么样的反应
yolov11改进系列第15篇
作者:小探
发布时间:2026年6月
关键词:Mamba,yolov11改进
1. 改进介绍
Mamba 最近在 CV 圈很火,也很多人进行了改进尝试,不过把它直接塞进检测器的结果都比较一般,显存和推理速度也不怎么友好。
MambaOut (Yu et al.) 做了一个犀利的消融实验:
论文: https://arxiv.org/abs/2405.07992
代码: https://github.com/yuweihao/MambaOut
把 Mamba 的核心(SSM)去掉,只保留剩余结构(门控 CNN),在 ImageNet 上居然和原版 Mamba 打得有来有回。 既然门控 CNN 块又好又轻,为什么不把它放进 YOLO?
这就是本文尝试做的事情。
2. MambaOut 的核心:GatedCNNBlock
MambaOut 的主体结构拆解出来就一个东西------Gated CNN Block:
输入 → LayerNorm → FC 扩展 (8/3×) → 三路拆分:
├── gate (门控信号)
├── identity (恒等直通)
└── conv (深度可分离卷积)
↓
gate × concat(identity, conv)
↓
FC 投影回原通道
↓
+ 残差连接 + DropPath
几个关键设计:
-
门控机制:从 Mamba 那里借来的,通道扩展后用 GELU 激活 gate 分支,逐元素乘到特征上。这个门控相当于一个输入依赖的特征筛选器。
-
部分卷积 (partial conv) :
conv_ratio控制走深度卷积的通道比例。设为 0.5 时只有一半通道做卷积,剩下直接 bypass,省计算。 -
纯 CNN 实现:没有 SSM 的状态空间计算,没有 RNN 的时序依赖,全部是标准卷积算子,TensorRT/ONNX 部署零障碍。
3. 怎么塞进 YOLOv11
Ultralytics 的模块注册机制很干净,只需要三步就可以嵌入mambaout模块:
Step 1 --- 写模块
在 ultralytics/nn/modules/mambaout.py 中实现 GatedCNNBlock(c1, c2, kernel_size=7, conv_ratio=1.0, expansion_ratio=8/3):
python
class GatedCNNBlock(nn.Module):
def __init__(self, c1, c2, kernel_size=7, conv_ratio=1.0,
expansion_ratio=8/3, drop_path_rate=0.0):
super().__init__()
dim = c2
hidden = int(expansion_ratio * dim)
conv_channels = int(conv_ratio * dim)
self.proj = nn.Conv2d(c1, dim, 1) if c1 != dim else nn.Identity()
self.norm = LayerNormGeneral((dim, 1, 1), (1, 2, 3))
self.fc1 = nn.Conv2d(dim, hidden * 2, 1) # expand
self.conv = nn.Conv2d(conv_channels, conv_channels,
kernel_size, padding=kernel_size//2,
groups=conv_channels) # depthwise
self.fc2 = nn.Conv2d(hidden, dim, 1) # project
self.act = nn.GELU()
self.drop_path = DropPath(drop_path_rate)
self.split_indices = (hidden, hidden - conv_channels, conv_channels)
def forward(self, x):
x = self.proj(x)
shortcut = x
x = self.norm(x)
g, i, c = torch.split(self.fc1(x), self.split_indices, dim=1)
c = self.conv(c)
x = self.fc2(self.act(g) * torch.cat((i, c), dim=1))
return shortcut + self.drop_path(x)
这里做了一个实用改动:当 c1 ≠ c2 时加一个 1×1 的投影卷积,适配 YOLO 中通道数变化的场景。
Step 2 --- 注册
__init__.py里加from .mambaout import GatedCNNBlocktasks.py里加GatedCNNBlock到base_modules集合,让它自动享受width_multiple缩放
Step 3 --- 写 YAML
把 yolo11.yaml 里所有的 C3k2 替换成 GatedCNNBlock:
yaml
backbone:
- [-1, 1, Conv, [64, 3, 2]]
- [-1, 1, Conv, [128, 3, 2]]
- [-1, 1, GatedCNNBlock, [256, 7, 1.0]] # ← 替代 C3k2
- [-1, 1, Conv, [256, 3, 2]]
...
4. 初测数据
用 YOLOv11n 的 scale 参数跑了一个 epoch 的 smoke test:
| 指标 | YOLOv11n (原版) | YOLOv11-MambaOut |
|---|---|---|
| 参数量 | 2.6M | 3.9M |
| GFLOPs | 6.6 | 12.7 |
| 显存占用 | ~1.1G | ~1.4G |
参数和计算量确实涨了不少------因为 expansion_ratio=8/3 的通道膨胀比较激进,中间层的通道数会跳到 c2 × 2.67。
下一步调参方向:
- 降低
expansion_ratio到 2.0 或 1.5 - 减小
conv_ratio到 0.5(只让一半通道走卷积) - 只在 backbone 深层(P4/P5)替换,浅层保留 C3k2
- 搭配 GFLOPs 约束做架构搜索
5. 一键跑通
bash
# 用 conda 环境
conda activate yolov11
# 训练(注意设 PYTHONPATH 用本地修改版)
PYTHONPATH=. yolo detect train \
model=ultralytics/cfg/models/11/yolo11-mambaout.yaml \
data=coco.yaml \
epochs=300 imgsz=640
完整代码已开源在 Ultralytics fork 的 ultralytics/nn/modules/mambaout.py 中,可私信获取开源代码。
6. 小结
MambaOut 的思路很好------不要为了追热点而塞 SSM,门控 CNN 本身就是一个很强的基线。把它嵌入 YOLOv11 的技术成本很低(一个文件 + 三处注册),剩下的就是调参找 sweet spot。
