YOLOv11-seg改进 | C3k2_iRMB轻量注意力残差混合块替换C3k2全流程指南
-
- 一、本文简介
-
- [原始 C3k2 的局限性](#原始 C3k2 的局限性)
- 本文改进核心
- [改进前后参数量 / GFLOPs 对比](#改进前后参数量 / GFLOPs 对比)
- 二、模块原理详解
-
- [2.1 层级结构总览](#2.1 层级结构总览)
- [2.2 基础组件](#2.2 基础组件)
-
- `SEAttention`
- `DropPath`
- [窗口划分与 `rearrange`](#窗口划分与
rearrange)
- [2.3 iRMB:窗口注意力局部全局融合算子(核心)](#2.3 iRMB:窗口注意力局部全局融合算子(核心))
- [2.4 iRMB:局部增强 + SE 重标定 + 残差投影](#2.4 iRMB:局部增强 + SE 重标定 + 残差投影)
- [2.5 C3k2_iRMB:完整 Bottleneck 替换逻辑](#2.5 C3k2_iRMB:完整 Bottleneck 替换逻辑)
- 三、改进思想与创新点
-
- [3.1 背景与动机](#3.1 背景与动机)
- [3.2 核心创新点](#3.2 核心创新点)
- [3.3 与现有方案的对比](#3.3 与现有方案的对比)
- [3.4 在 YOLOv11 框架中的适配设计](#3.4 在 YOLOv11 框架中的适配设计)
- 四、完整代码
-
- [4.1 来自 `ultralytics/nn/extra_modules/attention.py`](#4.1 来自
ultralytics/nn/extra_modules/attention.py) - [4.2 来自 `ultralytics/nn/extra_modules/block.py`](#4.2 来自
ultralytics/nn/extra_modules/block.py)
- [4.1 来自 `ultralytics/nn/extra_modules/attention.py`](#4.1 来自
- 五、手把手配置步骤(三步法)
-
- [Step 1:确认 `extra_modules/init.py` 导入(已自动导入,跳过)](#Step 1:确认
extra_modules/__init__.py导入(已自动导入,跳过)) - [Step 2:确认 `tasks.py` 注册(已注册,跳过)](#Step 2:确认
tasks.py注册(已注册,跳过)) - [Step 3:训练代码](#Step 3:训练代码)
- [Step 1:确认 `extra_modules/init.py` 导入(已自动导入,跳过)](#Step 1:确认
- [六、YAML 配置文件](#六、YAML 配置文件)
-
- [变体一:全面替换(Backbone + Head 全部替换,推荐作为首选配置)](#变体一:全面替换(Backbone + Head 全部替换,推荐作为首选配置))
- [变体二:仅替换 Backbone(Head 保留原版 C3k2)](#变体二:仅替换 Backbone(Head 保留原版 C3k2))
- [变体三:精度优先模式(深层全部使用 c3k=True 强力配置)](#变体三:精度优先模式(深层全部使用 c3k=True 强力配置))
- [变体四:混合模式(浅层保持原版 C3k2,深层引入 iRMB)](#变体四:混合模式(浅层保持原版 C3k2,深层引入 iRMB))
- [变体五:P2 四尺度版(增加 P2 输出层,适合小目标密集场景)](#变体五:P2 四尺度版(增加 P2 输出层,适合小目标密集场景))
- 七、常见问题(FAQ)
-
- [7.1 `NameError: name 'C3k2_iRMB' is not defined`](#7.1
NameError: name 'C3k2_iRMB' is not defined) - [7.2 需要安装哪些第三方依赖](#7.2 需要安装哪些第三方依赖)
- [7.3 `Segment` 改成 `Detect` 怎么写](#7.3
Segment改成Detect怎么写) - [7.4 YAML 参数怎么理解](#7.4 YAML 参数怎么理解)
- [7.1 `NameError: name 'C3k2_iRMB' is not defined`](#7.1
- 八、总结
专栏系列 :YOLOv11 注意力/精度改进实战
改进点 :将 YOLOv11-seg 中的C3k2替换为C3k2_iRMB,引入 EMO 中的iRMB轻量注意力残差混合块,以窗口注意力、深度卷积局部建模和 SE 通道重标定联合增强特征表达能力,在较小参数与算力增幅下提升复杂背景、多尺度与实例边界场景下的分割表现。
一、本文简介
本文引入 EMO(ICCV 2023) 中的 iRMB 模块,将其嵌入 YOLOv11 的 C3k2 结构形成 C3k2_iRMB。根据仓库文档 YOLOV11配置文件.md 第 103 项说明,当前配置来源为 EMO ICCV2023 中的 iRMB 。从实现上看,这个模块并不是简单加一个注意力层,而是将窗口自注意力、深度卷积局部增强、SE 通道重标定和残差投影组合到一个轻量残差块中,用来替换原始 C3k2 中的普通 Bottleneck。
原始 C3k2 的局限性
YOLOv11 默认 C3k2 结构高效稳定,但在实例分割任务中仍然存在几个典型问题:
- 局部与全局建模割裂:标准卷积更擅长局部聚合,缺少显式的局部全局关系建模能力。
- 特征选择能力不足 :原始
Bottleneck缺少动态注意力与通道重标定机制。 - 复杂场景表达有限:面对遮挡、小目标、复杂背景和精细边界时,基础卷积块的表达能力往往不够。
本文改进核心
C3k2_iRMB 在不改变 C2f/C3k2 外层聚合框架的前提下,仅替换内部单元为 iRMB,主要引入三点增强:
- 窗口注意力建模:在局部窗口中完成轻量多头注意力,增强局部范围内的全局依赖感知。
- 局部卷积分支补强 :注意力输出后再经过深度卷积
conv_local做局部细节增强。 - SE 通道重标定 + 残差投影:进一步提升关键通道响应,增强特征表达能力。
改进前后参数量 / GFLOPs 对比
下表结果来自项目环境下的 model.info() 实测:
python
from ultralytics import YOLO
model = YOLO("ultralytics/cfg/models/11-seg/light_impro/yolo11-seg-C3k2-iRMB.yaml")
model.info()
| 模型 | 参数量 | GFLOPs | 说明 |
|---|---|---|---|
yolo11n-seg |
2.46M(2,460,112) |
9.6 |
基线 |
yolo11n-seg-C3k2-iRMB |
2.57M(2,571,808) |
10.0 |
2026-04-21 实测 |
| 变化 | +111,696(+4.54%) |
+0.4(+4.17%) |
精度改进方向 |
当前环境下,该模型的
model.info()实测结果为10.0 GFLOPs。
从机制和实测指标看,C3k2_iRMB 属于轻量精度增强型替换块 ,比很多重注意力模块更克制,但表达力明显强于普通 Bottleneck。
二、模块原理详解
2.1 层级结构总览
text
C3k2_iRMB
├─ 继承自 C3k2
│ ├─ 继承自 C2f
│ │ ├─ cv1: Conv(c1, 2c, 1)
│ │ ├─ cv2: Conv((2+n)c, c2, 1)
│ │ └─ m: ModuleList(...)
│ └─ 将原始 Bottleneck 替换为 iRMB
├─ C3k_iRMB
│ └─ 在 C3k 内部堆叠 iRMB
└─ iRMB
├─ norm: BatchNorm2d
├─ qk: 1x1 Conv,生成 Q/K
├─ v: 1x1 Conv + act,生成 V
├─ window attention
│ ├─ padding
│ ├─ rearrange to windows
│ ├─ q @ k^T * scale
│ └─ softmax + dropout
├─ conv_local: depthwise Conv
├─ se: SEAttention
├─ proj: 1x1 Conv
└─ drop_path + residual
2.2 基础组件
SEAttention
SEAttention 是标准的 squeeze-excitation 通道注意力,核心形式为:
z = G A P ( x ) z = \mathrm{GAP}(x) z=GAP(x)
s = σ ( W 2 ( δ ( W 1 ( z ) ) ) ) s = \sigma(W_2(\delta(W_1(z)))) s=σ(W2(δ(W1(z))))
y = x ⊙ s y = x \odot s y=x⊙s
它的作用是对重要通道进行增强,对冗余通道进行抑制。
DropPath
DropPath 在残差分支上实现随机深度,训练阶段对不同样本按概率丢弃整条残差路径,有助于稳定深层网络训练并增强泛化能力。
窗口划分与 rearrange
iRMB 内部使用 einops.rearrange 把特征图划分为窗口,再在窗口内做注意力。设窗口大小为 M M M,则原始输入:
X ∈ R B × C × H × W X \in \mathbb{R}^{B \times C \times H \times W} X∈RB×C×H×W
会被重排为多个局部窗口,每个窗口内部进行多头注意力建模。这样可把全局注意力复杂度控制在局部范围内,避免直接在整张特征图上做全局注意力的高开销。
2.3 iRMB:窗口注意力局部全局融合算子(核心)
iRMB 的核心是"窗口注意力 + 局部卷积 + 通道重标定"的混合设计。
当 attn_s=True 时,它的注意力部分核心公式为:
Q , K = C o n v 1 × 1 ( X ) Q, K = \mathrm{Conv}_{1\times1}(X) Q,K=Conv1×1(X)
V = C o n v 1 × 1 ( X ) V = \mathrm{Conv}_{1\times1}(X) V=Conv1×1(X)
A t t n ( Q , K , V ) = S o f t m a x ( Q K T d ) V \mathrm{Attn}(Q, K, V)=\mathrm{Softmax}\left(\frac{QK^T}{\sqrt{d}}\right)V Attn(Q,K,V)=Softmax(d QKT)V
这里的注意力不是全局展开,而是限制在窗口内部,因此更适合检测/分割这类高分辨率特征图场景。
2.4 iRMB:局部增强 + SE 重标定 + 残差投影
注意力完成后,iRMB 会继续执行局部卷积增强:
X l o c a l = C o n v L o c a l ( X a t t n ) X_{local} = \mathrm{ConvLocal}(X_{attn}) Xlocal=ConvLocal(Xattn)
再通过 SE 模块完成通道重标定:
X s e = S E ( X l o c a l ) X_{se} = \mathrm{SE}(X_{local}) Xse=SE(Xlocal)
如果满足跳连条件,则形成:
X ′ = X a t t n + X s e X' = X_{attn} + X_{se} X′=Xattn+Xse
最后再通过投影卷积和 DropPath:
Y = P r o j ( X ′ ) Y = \mathrm{Proj}(X') Y=Proj(X′)
o u t = X + D r o p P a t h ( Y ) \mathrm{out} = X + \mathrm{DropPath}(Y) out=X+DropPath(Y)
这种做法的价值在于:
先用注意力建模局部窗口内的关系,再用深度卷积补强局部纹理,再用 SE 做通道筛选,最终通过残差方式稳定输出。
2.5 C3k2_iRMB:完整 Bottleneck 替换逻辑
C3k2_iRMB 依然沿用 C2f/C3k2 的外层拼接逻辑,只是把内部 Bottleneck 替换为 iRMB:
y 0 , y 1 = S p l i t ( c v 1 ( x ) ) y_0, y_1 = \mathrm{Split}(\mathrm{cv1}(x)) y0,y1=Split(cv1(x))
y i + 1 = i R M B ( y i ) y_{i+1} = \mathrm{iRMB}(y_i) yi+1=iRMB(yi)
o u t = c v 2 ( C o n c a t ( y 0 , y 1 , ... ) ) \mathrm{out} = \mathrm{cv2}(\mathrm{Concat}(y_0, y_1, \ldots)) out=cv2(Concat(y0,y1,...))
因此:
- 输入输出尺寸完全兼容;
- Neck / Head 结构无需大改;
- 只需替换 YAML 中的模块名即可完成接入。
三、改进思想与创新点
3.1 背景与动机
实例分割任务需要同时兼顾局部边缘细节与区域上下文一致性。原始 C3k2 主要靠卷积堆叠做特征提取,虽然效率高,但对复杂场景的上下文建模能力有限。EMO 提出的 iRMB 则试图在保持高效的前提下,将注意力、卷积和通道增强融合到一个轻量残差块中。
将其迁移到 YOLOv11 的动机很直接:
- 保留 YOLO 骨架的效率优势;
- 用窗口注意力补足局部卷积对中程依赖建模不足的问题;
- 用局部卷积分支和 SE 模块补强边缘与通道表达。
3.2 核心创新点
创新点一:窗口级轻量注意力
相较于全局自注意力,iRMB 采用窗口注意力:
A t t n ( Q , K , V ) = S o f t m a x ( Q K T d ) V \mathrm{Attn}(Q, K, V)=\mathrm{Softmax}\left(\frac{QK^T}{\sqrt{d}}\right)V Attn(Q,K,V)=Softmax(d QKT)V
但注意力仅在局部窗口内部完成,因此显著降低复杂度,更适合检测与分割骨干。
创新点二:注意力后追加局部卷积补强
很多注意力块容易牺牲卷积的局部纹理优势,而 iRMB 在注意力后保留:
C o n v L o c a l ( X ) \mathrm{ConvLocal}(X) ConvLocal(X)
并与跳连叠加,使得它不会过于偏向纯 token mixer,而是兼顾局部结构信息。
创新点三:SE 通道重标定
SEAttention 带来的通道筛选可以增强对重要特征的响应,这对复杂纹理、小目标和实例边界尤为有帮助。
创新点四:残差投影与随机深度
通过:
o u t = x + D r o p P a t h ( P r o j ( x ′ ) ) \mathrm{out}=x+\mathrm{DropPath}(\mathrm{Proj}(x')) out=x+DropPath(Proj(x′))
iRMB 保持了残差块的训练稳定性,同时通过 DropPath 提升了深层训练的鲁棒性。
3.3 与现有方案的对比
| 方法 | 局部建模 | 全局上下文 | 通道筛选 | 复杂度水平 | 适用场景 |
|---|---|---|---|---|---|
| C3k2 原版 | 常规卷积 | 弱 | 无 | 低 | 通用检测 / 分割 |
| C3k2_LFE | Shift 局部位移建模 | 弱 | 无 | 低到中 | 纹理与边缘增强 |
| C3k2_LEGM | 窗口注意力 + MLP | 强 | 动态重标定 | 中 | 复杂背景与多尺度分割 |
| C3k2_iRMB | 注意力 + depthwise local conv | 中到强 | SE | 中 | 多尺度分割、遮挡、小目标与复杂边界 |
| 全局 Transformer block | 弱局部 | 很强 | 可选 | 高 | 高算力场景 |
3.4 在 YOLOv11 框架中的适配设计
当前仓库中导入与注册已经完成:
ultralytics/nn/extra_modules/__init__.py已有from .block import *。ultralytics/nn/tasks.py的C3K2_CLASS已包含C3k2_iRMB。- 目标 YAML 已经可以被
YOLO()正常构建。
因此在当前仓库环境下,不需要额外补导入或补注册。
四、完整代码
为保证和仓库源码逐字一致,下面代码块不在块内加入人工中文注释,解释放在代码块外。
4.1 来自 ultralytics/nn/extra_modules/attention.py
python
class SEAttention(nn.Module):
def __init__(self, channel=512,reduction=16):
super().__init__()
self.avg_pool = nn.AdaptiveAvgPool2d(1)
self.fc = nn.Sequential(
nn.Linear(channel, channel // reduction, bias=False),
nn.ReLU(inplace=True),
nn.Linear(channel // reduction, channel, bias=False),
nn.Sigmoid()
)
def init_weights(self):
for m in self.modules():
if isinstance(m, nn.Conv2d):
init.kaiming_normal_(m.weight, mode='fan_out')
if m.bias is not None:
init.constant_(m.bias, 0)
elif isinstance(m, nn.BatchNorm2d):
init.constant_(m.weight, 1)
init.constant_(m.bias, 0)
elif isinstance(m, nn.Linear):
init.normal_(m.weight, std=0.001)
if m.bias is not None:
init.constant_(m.bias, 0)
def forward(self, x):
b, c, _, _ = x.size()
y = self.avg_pool(x).view(b, c)
y = self.fc(y).view(b, c, 1, 1)
return x * y.expand_as(x)
4.2 来自 ultralytics/nn/extra_modules/block.py
python
class DropPath(nn.Module):
"""Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks).
"""
def __init__(self, drop_prob=None):
super(DropPath, self).__init__()
self.drop_prob = drop_prob
def forward(self, x):
return drop_path(x, self.drop_prob, self.training)
python
class iRMB(nn.Module):
def __init__(self, dim_in, dim_out, norm_in=True, has_skip=True, exp_ratio=1.0,
act=True, v_proj=True, dw_ks=3, stride=1, dilation=1, se_ratio=0.0, dim_head=16, window_size=7,
attn_s=True, qkv_bias=False, attn_drop=0., drop=0., drop_path=0., v_group=False, attn_pre=False):
super().__init__()
self.norm = nn.BatchNorm2d(dim_in) if norm_in else nn.Identity()
self.act = Conv.default_act if act else nn.Identity()
dim_mid = int(dim_in * exp_ratio)
self.has_skip = (dim_in == dim_out and stride == 1) and has_skip
self.attn_s = attn_s
if self.attn_s:
assert dim_in % dim_head == 0, 'dim should be divisible by num_heads'
self.dim_head = dim_head
self.window_size = window_size
self.num_head = dim_in // dim_head
self.scale = self.dim_head ** -0.5
self.attn_pre = attn_pre
self.qk = nn.Conv2d(dim_in, int(dim_in * 2), 1, bias=qkv_bias)
self.v = nn.Sequential(
nn.Conv2d(dim_in, dim_mid, kernel_size=1, groups=self.num_head if v_group else 1, bias=qkv_bias),
self.act
)
self.attn_drop = nn.Dropout(attn_drop)
else:
if v_proj:
self.v = nn.Sequential(
nn.Conv2d(dim_in, dim_mid, kernel_size=1, groups=self.num_head if v_group else 1, bias=qkv_bias),
self.act
)
else:
self.v = nn.Identity()
self.conv_local = Conv(dim_mid, dim_mid, k=dw_ks, s=stride, d=dilation, g=dim_mid)
self.se = SEAttention(dim_mid, reduction=se_ratio) if se_ratio > 0.0 else nn.Identity()
self.proj_drop = nn.Dropout(drop)
self.proj = nn.Conv2d(dim_mid, dim_out, kernel_size=1)
self.drop_path = DropPath(drop_path) if drop_path else nn.Identity()
def forward(self, x):
shortcut = x
x = self.norm(x)
B, C, H, W = x.shape
if self.attn_s:
# padding
if self.window_size <= 0:
window_size_W, window_size_H = W, H
else:
window_size_W, window_size_H = self.window_size, self.window_size
pad_l, pad_t = 0, 0
pad_r = (window_size_W - W % window_size_W) % window_size_W
pad_b = (window_size_H - H % window_size_H) % window_size_H
x = F.pad(x, (pad_l, pad_r, pad_t, pad_b, 0, 0,))
n1, n2 = (H + pad_b) // window_size_H, (W + pad_r) // window_size_W
x = rearrange(x, 'b c (h1 n1) (w1 n2) -> (b n1 n2) c h1 w1', n1=n1, n2=n2).contiguous()
# attention
b, c, h, w = x.shape
qk = self.qk(x)
qk = rearrange(qk, 'b (qk heads dim_head) h w -> qk b heads (h w) dim_head', qk=2, heads=self.num_head, dim_head=self.dim_head).contiguous()
q, k = qk[0], qk[1]
attn_spa = (q @ k.transpose(-2, -1)) * self.scale
attn_spa = attn_spa.softmax(dim=-1)
attn_spa = self.attn_drop(attn_spa)
if self.attn_pre:
x = rearrange(x, 'b (heads dim_head) h w -> b heads (h w) dim_head', heads=self.num_head).contiguous()
x_spa = attn_spa @ x
x_spa = rearrange(x_spa, 'b heads (h w) dim_head -> b (heads dim_head) h w', heads=self.num_head, h=h, w=w).contiguous()
x_spa = self.v(x_spa)
else:
v = self.v(x)
v = rearrange(v, 'b (heads dim_head) h w -> b heads (h w) dim_head', heads=self.num_head).contiguous()
x_spa = attn_spa @ v
x_spa = rearrange(x_spa, 'b heads (h w) dim_head -> b (heads dim_head) h w', heads=self.num_head, h=h, w=w).contiguous()
# unpadding
x = rearrange(x_spa, '(b n1 n2) c h1 w1 -> b c (h1 n1) (w1 n2)', n1=n1, n2=n2).contiguous()
if pad_r > 0 or pad_b > 0:
x = x[:, :, :H, :W].contiguous()
else:
x = self.v(x)
x = x + self.se(self.conv_local(x)) if self.has_skip else self.se(self.conv_local(x))
x = self.proj_drop(x)
x = self.proj(x)
x = (shortcut + self.drop_path(x)) if self.has_skip else x
return x
class C3k_iRMB(C3k):
def __init__(self, c1, c2, n=1, shortcut=False, g=1, e=0.5, k=3):
super().__init__(c1, c2, n, shortcut, g, e, k)
c_ = int(c2 * e) # hidden channels
self.m = nn.Sequential(*(iRMB(c_, c_) for _ in range(n)))
class C3k2_iRMB(C3k2):
def __init__(self, c1, c2, n=1, c3k=False, e=0.5, g=1, shortcut=True):
super().__init__(c1, c2, n, c3k, e, g, shortcut)
self.m = nn.ModuleList(C3k_iRMB(self.c, self.c, 2, shortcut, g) if c3k else iRMB(self.c, self.c) for _ in range(n))
五、手把手配置步骤(三步法)
Step 1:确认 extra_modules/__init__.py 导入(已自动导入,跳过)
当前仓库 ultralytics/nn/extra_modules/__init__.py 已包含 from .block import *,因此 C3k2_iRMB 无需额外导入。
Step 2:确认 tasks.py 注册(已注册,跳过)
当前仓库 ultralytics/nn/tasks.py 的 C3K2_CLASS 中已经注册 C3k2_iRMB,无需额外补注册。
Step 3:训练代码
python
from ultralytics import YOLO
# 加载改进模型
model = YOLO("ultralytics/cfg/models/11-seg/light_impro/yolo11-seg-C3k2-iRMB.yaml")
# 查看参数量和 GFLOPs
model.info()
# 开始训练
model.train(
data="coco8-seg.yaml",
epochs=100,
imgsz=640,
batch=16,
device=0
)
六、YAML 配置文件
变体一:全面替换(Backbone + Head 全部替换,推荐作为首选配置)
适用场景:希望完整引入 iRMB 的注意力 + 局部卷积建模能力。
实测参数量:2.57M / 10.0 GFLOPs(n scale)
yaml
# YOLO11-seg C3k2_iRMB full replacement
nc: 80
scales:
n: [0.50, 0.25, 1024]
s: [0.50, 0.50, 1024]
m: [0.50, 1.00, 512]
l: [1.00, 1.00, 512]
x: [1.00, 1.50, 512]
backbone:
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
- [-1, 2, C3k2_iRMB, [256, False, 0.25]] # 2
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
- [-1, 2, C3k2_iRMB, [512, False, 0.25]] # 4
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
- [-1, 2, C3k2_iRMB, [512, True]] # 6
- [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
- [-1, 2, C3k2_iRMB, [1024, True]] # 8
- [-1, 1, SPPF, [1024, 5]] # 9
- [-1, 2, C2PSA, [1024]] # 10
head:
- [-1, 1, nn.Upsample, [None, 2, "nearest"]] # 11
- [[-1, 6], 1, Concat, [1]] # 12 cat backbone P4
- [-1, 2, C3k2_iRMB, [512, False]] # 13
- [-1, 1, nn.Upsample, [None, 2, "nearest"]] # 14
- [[-1, 4], 1, Concat, [1]] # 15 cat backbone P3
- [-1, 2, C3k2_iRMB, [256, False]] # 16 (P3/8-small)
- [-1, 1, Conv, [256, 3, 2]] # 17
- [[-1, 13], 1, Concat, [1]] # 18 cat head P4
- [-1, 2, C3k2_iRMB, [512, False]] # 19 (P4/16-medium)
- [-1, 1, Conv, [512, 3, 2]] # 20
- [[-1, 10], 1, Concat, [1]] # 21 cat head P5
- [-1, 2, C3k2_iRMB, [1024, True]] # 22 (P5/32-large)
- [[16, 19, 22], 1, Segment, [nc, 32, 256]] # 23 Segment(P3, P4, P5)
变体二:仅替换 Backbone(Head 保留原版 C3k2)
适用场景:优先验证 Backbone 侧引入 iRMB 后的收益。
yaml
# YOLO11-seg C3k2_iRMB backbone only
nc: 80
scales:
n: [0.50, 0.25, 1024]
s: [0.50, 0.50, 1024]
m: [0.50, 1.00, 512]
l: [1.00, 1.00, 512]
x: [1.00, 1.50, 512]
backbone:
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
- [-1, 2, C3k2_iRMB, [256, False, 0.25]] # 2
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
- [-1, 2, C3k2_iRMB, [512, False, 0.25]] # 4
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
- [-1, 2, C3k2_iRMB, [512, True]] # 6
- [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
- [-1, 2, C3k2_iRMB, [1024, True]] # 8
- [-1, 1, SPPF, [1024, 5]] # 9
- [-1, 2, C2PSA, [1024]] # 10
head:
- [-1, 1, nn.Upsample, [None, 2, "nearest"]] # 11
- [[-1, 6], 1, Concat, [1]] # 12 cat backbone P4
- [-1, 2, C3k2, [512, False]] # 13
- [-1, 1, nn.Upsample, [None, 2, "nearest"]] # 14
- [[-1, 4], 1, Concat, [1]] # 15 cat backbone P3
- [-1, 2, C3k2, [256, False]] # 16 (P3/8-small)
- [-1, 1, Conv, [256, 3, 2]] # 17
- [[-1, 13], 1, Concat, [1]] # 18 cat head P4
- [-1, 2, C3k2, [512, False]] # 19 (P4/16-medium)
- [-1, 1, Conv, [512, 3, 2]] # 20
- [[-1, 10], 1, Concat, [1]] # 21 cat head P5
- [-1, 2, C3k2, [1024, True]] # 22 (P5/32-large)
- [[16, 19, 22], 1, Segment, [nc, 32, 256]] # 23 Segment(P3, P4, P5)
变体三:精度优先模式(深层全部使用 c3k=True 强力配置)
适用场景:打开 c3k=True,进一步增强内部堆叠表达能力。
yaml
# YOLO11-seg C3k2_iRMB accuracy-first
nc: 80
scales:
n: [0.50, 0.25, 1024]
s: [0.50, 0.50, 1024]
m: [0.50, 1.00, 512]
l: [1.00, 1.00, 512]
x: [1.00, 1.50, 512]
backbone:
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
- [-1, 2, C3k2_iRMB, [256, True, 0.25]] # 2
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
- [-1, 2, C3k2_iRMB, [512, True, 0.25]] # 4
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
- [-1, 2, C3k2_iRMB, [512, True]] # 6
- [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
- [-1, 2, C3k2_iRMB, [1024, True]] # 8
- [-1, 1, SPPF, [1024, 5]] # 9
- [-1, 2, C2PSA, [1024]] # 10
head:
- [-1, 1, nn.Upsample, [None, 2, "nearest"]] # 11
- [[-1, 6], 1, Concat, [1]] # 12 cat backbone P4
- [-1, 2, C3k2_iRMB, [512, True]] # 13
- [-1, 1, nn.Upsample, [None, 2, "nearest"]] # 14
- [[-1, 4], 1, Concat, [1]] # 15 cat backbone P3
- [-1, 2, C3k2_iRMB, [256, True]] # 16 (P3/8-small)
- [-1, 1, Conv, [256, 3, 2]] # 17
- [[-1, 13], 1, Concat, [1]] # 18 cat head P4
- [-1, 2, C3k2_iRMB, [512, True]] # 19 (P4/16-medium)
- [-1, 1, Conv, [512, 3, 2]] # 20
- [[-1, 10], 1, Concat, [1]] # 21 cat head P5
- [-1, 2, C3k2_iRMB, [1024, True]] # 22 (P5/32-large)
- [[16, 19, 22], 1, Segment, [nc, 32, 256]] # 23 Segment(P3, P4, P5)
变体四:混合模式(浅层保持原版 C3k2,深层引入 iRMB)
适用场景:兼顾速度与精度,只在中深层使用 iRMB。
yaml
# YOLO11-seg C3k2_iRMB hybrid
nc: 80
scales:
n: [0.50, 0.25, 1024]
s: [0.50, 0.50, 1024]
m: [0.50, 1.00, 512]
l: [1.00, 1.00, 512]
x: [1.00, 1.50, 512]
backbone:
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
- [-1, 2, C3k2, [256, False, 0.25]] # 2
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
- [-1, 2, C3k2_iRMB, [512, False, 0.25]] # 4
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
- [-1, 2, C3k2_iRMB, [512, True]] # 6
- [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
- [-1, 2, C3k2_iRMB, [1024, True]] # 8
- [-1, 1, SPPF, [1024, 5]] # 9
- [-1, 2, C2PSA, [1024]] # 10
head:
- [-1, 1, nn.Upsample, [None, 2, "nearest"]] # 11
- [[-1, 6], 1, Concat, [1]] # 12 cat backbone P4
- [-1, 2, C3k2_iRMB, [512, False]] # 13
- [-1, 1, nn.Upsample, [None, 2, "nearest"]] # 14
- [[-1, 4], 1, Concat, [1]] # 15 cat backbone P3
- [-1, 2, C3k2, [256, False]] # 16 (P3/8-small)
- [-1, 1, Conv, [256, 3, 2]] # 17
- [[-1, 13], 1, Concat, [1]] # 18 cat head P4
- [-1, 2, C3k2_iRMB, [512, False]] # 19 (P4/16-medium)
- [-1, 1, Conv, [512, 3, 2]] # 20
- [[-1, 10], 1, Concat, [1]] # 21 cat head P5
- [-1, 2, C3k2_iRMB, [1024, True]] # 22 (P5/32-large)
- [[16, 19, 22], 1, Segment, [nc, 32, 256]] # 23 Segment(P3, P4, P5)
变体五:P2 四尺度版(增加 P2 输出层,适合小目标密集场景)
适用场景:小目标较多,希望把 P2/4 也接入分割输出。
注意:P2 版层索引重新计算,Segment 输出使用 [19, 22, 25, 28]。
yaml
# YOLO11-seg C3k2_iRMB P2 4-scale
nc: 80
scales:
n: [0.50, 0.25, 1024]
s: [0.50, 0.50, 1024]
m: [0.50, 1.00, 512]
l: [1.00, 1.00, 512]
x: [1.00, 1.50, 512]
backbone:
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
- [-1, 2, C3k2_iRMB, [256, False, 0.25]] # 2
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
- [-1, 2, C3k2_iRMB, [512, False, 0.25]] # 4
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
- [-1, 2, C3k2_iRMB, [512, True]] # 6
- [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
- [-1, 2, C3k2_iRMB, [1024, True]] # 8
- [-1, 1, SPPF, [1024, 5]] # 9
- [-1, 2, C2PSA, [1024]] # 10
head:
- [-1, 1, nn.Upsample, [None, 2, "nearest"]] # 11
- [[-1, 6], 1, Concat, [1]] # 12 cat backbone P4
- [-1, 2, C3k2_iRMB, [512, False]] # 13
- [-1, 1, nn.Upsample, [None, 2, "nearest"]] # 14
- [[-1, 4], 1, Concat, [1]] # 15 cat backbone P3
- [-1, 2, C3k2_iRMB, [256, False]] # 16 (P3/8-small)
- [-1, 1, nn.Upsample, [None, 2, "nearest"]] # 17
- [[-1, 2], 1, Concat, [1]] # 18 cat backbone P2
- [-1, 2, C3k2_iRMB, [128, False]] # 19 (P2/4-xsmall)
- [-1, 1, Conv, [256, 3, 2]] # 20
- [[-1, 16], 1, Concat, [1]] # 21 cat head P3
- [-1, 2, C3k2_iRMB, [256, False]] # 22 (P3/8-medium)
- [-1, 1, Conv, [256, 3, 2]] # 23
- [[-1, 13], 1, Concat, [1]] # 24 cat head P4
- [-1, 2, C3k2_iRMB, [512, False]] # 25 (P4/16-medium)
- [-1, 1, Conv, [512, 3, 2]] # 26
- [[-1, 10], 1, Concat, [1]] # 27 cat head P5
- [-1, 2, C3k2_iRMB, [1024, True]] # 28 (P5/32-large)
- [[19, 22, 25, 28], 1, Segment, [nc, 32, 256]] # 29 Segment(P2, P3, P4, P5)
七、常见问题(FAQ)
7.1 NameError: name 'C3k2_iRMB' is not defined
优先检查以下几项:
ultralytics/nn/extra_modules/block.py中是否存在C3k2_iRMB。ultralytics/nn/extra_modules/__init__.py是否仍保留from .block import *。ultralytics/nn/tasks.py的C3K2_CLASS是否包含C3k2_iRMB。
7.2 需要安装哪些第三方依赖
iRMB 这条链路至少需要:
bash
pip install einops timm
因为:
block.py顶部使用了from einops import rearrange, reduce- 仓库整体环境中使用了
timm相关组件
7.3 Segment 改成 Detect 怎么写
只需要替换最后一层:
- 三尺度版改成
[[16, 19, 22], 1, Detect, [nc]] - P2 四尺度版改成
[[19, 22, 25, 28], 1, Detect, [nc]]
7.4 YAML 参数怎么理解
C3k2_iRMB 的 YAML 参数与普通 C3k2 一致:
| 写法 | 含义 | 示例 |
|---|---|---|
[256, False, 0.25] |
c2=256, c3k=False, e=0.25 |
Backbone 浅层 |
[512, False] |
c2=512, c3k=False, e=0.5 |
Head 常用 |
[512, True] |
c2=512, c3k=True, e=0.5 |
精度优先堆叠版 |
其中:
c2是输出通道数;c3k=True时内部切换到C3k_iRMB堆叠;e是隐藏通道扩展比。
八、总结
| 对比维度 | 原始 C3k2 | C3k2_iRMB |
|---|---|---|
| 参数量(n scale) | 2.46M | 2.57M(+4.54%) |
| GFLOPs(n scale) | 9.6 | 10.0(+4.17%) |
| 局部建模方式 | 常规卷积堆叠 | 窗口注意力后接 depthwise conv_local 局部增强 |
| 上下文建模能力 | 较弱 | 窗口级自注意力增强中程依赖建模 |
| 通道筛选机制 | 无 | SEAttention 通道重标定 |
| 残差稳定性 | 基础残差 | DropPath + residual projection |
| 归一化格式 | BN(BCHW) | BN(BCHW),无额外格式切换成本 |
| 论文来源 | YOLOv11 原版 | EMO(ICCV 2023)中的 iRMB |
| 适用场景 | 通用目标检测 / 分割 | 小目标、多尺度、复杂背景、遮挡和精细实例分割 |
总结 :C3k2_iRMB 将 EMO(ICCV 2023)中的 iRMB 引入 YOLOv11,核心是用窗口注意力补足卷积块对中程上下文建模的不足,再通过深度卷积局部增强和 SE 通道筛选提升细节表达。在 n scale 下参数量增加 4.54%(+0.11M),GFLOPs 增加 4.17%(+0.4),属于增幅较小但结构收益明确的精度增强型替换块。对于多尺度实例分割、复杂背景、小目标和遮挡场景,这种模块通常比单纯卷积 Bottleneck 更有表达优势。
如果这篇文章对你有帮助,欢迎点赞、收藏、在评论区交流你实际训练后的涨点情况,也欢迎关注我的 YOLOv11 改进专栏,后面还会继续更新更多能直接落地的检测/分割结构改法。