GSConv和VoVGSCSP
def channel_shuffle(x, groups: int = 2): """通道洗牌(ShuffleNet 风格)。若不能整除 groups 则直接返回原张量。""" b, c, h, w = x.size() if groups <= 1 or c % groups != 0: return x x = x.view(b, groups, c // groups, h, w) x = x.transpose(1, 2).contiguous() return x.view(b, c, h, w) class GSConv(nn.Module): """ 轻量化 GSConv 签名:GSConv(c1, c2, k=3, s=1, act=True) 在 YOLO YAML 中写法示例: [-1, 1, GSConv, [256, 3, 1]] """ def __init__(self, c1, c2, k: int = 3, s: int = 1, act: bool = True): super().__init__() # 将输出通道分为 fast 和 cheap 两路 c_fast = c2 // 2 c_cheap = c2 - c_fast # 快速路径:1x1 conv(支持 stride) self.cv_fast = Conv(c1, c_fast, k=1, s=s, act=act) # 便宜路径:1x1 -> depthwise 3x3 self.cv_pw = Conv(c1, c_cheap, k=1, s=1, act=act) self.cv_dw = nn.Sequential( nn.Conv2d(c_cheap, c_cheap, k, s, autopad(k), groups=c_cheap, bias=False), nn.BatchNorm2d(c_cheap), nn.SiLU(inplace=True) if act else nn.Identity() ) # 只有当 c2 可被 2 整除时才做 shuffle self.groups = 2 if c2 % 2 == 0 else 1 def forward(self, x): y1 = self.cv_fast(x) y2 = self.cv_dw(self.cv_pw(x)) y = torch.cat([y1, y2], dim=1) if self.groups > 1: y = channel_shuffle(y, self.groups) return y class VoVGSCSP(nn.Module): """ VoVNet 风格 + GSConv + CSP 变体 签名:VoVGSCSP(c1, c2, n=1, shortcut=True, e=0.5) YAML 中使用示例: - [-1, 2, VoVGSCSP, [256]] # 只传 c2,n/shortcut/e 使用默认值 - [-1, 2, VoVGSCSP, [512, 3, False, 0.5]] 说明: - c1 由构建器自动传入(前一层输出通道) - c2 必填,表示模块最终输出通道 - n:右支 GSConv 层数(默认1) - shortcut:当 c1==c2 且为 True 时将添加输入残差 - e:expansion 比例,用于计算中间通道 c_ = max(1, int(c2*e)) """ def __init__(self, c1, c2, n: int = 1, shortcut: bool = True, e: float = 0.5): super().__init__() # 中间隐藏通道,避免为0 c_ = max(1, int(c2 * e)) # 两路分流(CSP) self.cv_short = Conv(c1, c_, 1, 1) # 快捷/残差分支(保留低开销信息) self.cv_main = Conv(c1, c_, 1, 1) # 主分支进入 GSConv 堆叠 # 右支:n 个 GSConv self.gs_blocks = nn.ModuleList([GSConv(c_, c_, k=3, s=1, act=True) for _ in range(n)]) # OSA 风格聚合:把初始 right + 各层输出 concat,再 conv 回 c_ self.agg = Conv((n + 1) * c_, c_, 1, 1) # 最终融合:concat(shortcut_branch, agg) -> conv -> 输出 c2 self.out_conv = Conv(2 * c_, c2, 1, 1) # 是否加残差(只有当输入输出通道一致且用户开启 shortcut) self.use_res = shortcut and (c1 == c2) def forward(self, x): sc = self.cv_short(x) # shortcut 分支 y = self.cv_main(x) # 主分支初始 feats = [y] for m in self.gs_blocks: y = m(y) feats.append(y) y = torch.cat(feats, dim=1) y = self.agg(y) out = self.out_conv(torch.cat([y, sc], dim=1)) return out + x if self.use_res else out
✅ GSConv 模块逻辑检查
-
通道混洗 (channel_shuffle)
-
目的是让分组卷积后的特征互相“交流”,避免信息隔离。
-
必须保证输出通道数
c2
能被 groups 整除(默认 2)。 -
✅ 如果你设置
GSConv(256, 256)
或GSConv(128, 256)
,都是偶数通道,不会出错。
-
-
DWConv + PWConv
-
DWConv
: 深度可分离卷积(只在通道内卷积,降低 FLOPs); -
PWConv
: 1x1 卷积(跨通道整合)。 -
✅ 这个组合跟 ShuffleNet 思路一致,能轻量化。
-
-
激活函数
-
默认用 YOLO 的
SiLU
,兼容性 OK。
-
-
依赖
-
用到
autopad(k)
(YOLO 的自动 padding),所以和 YOLO11 框架兼容。
-
✅ VoVGSCSP 模块逻辑检查
核心思想:
-
输入 → Conv 降通道 → 分两路
-
一路直接走(残差/shortcut);
-
一路进入 GSConv 堆叠。
-
-
堆叠多层 GSConv → 聚合
-
借鉴 VoVNet 的 OSA:把多个中间层的输出拼接,再卷积融合。
-
-
Concat 两路 → Conv 融合 → 输出
🔹 1. GSConv(Ghost Shuffle Convolution)
核心思想:轻量化卷积
👉 结合了 GhostConv 和 ShuffleNet 的思路,用 深度卷积 + 点卷积 再加上 通道混洗 来减少计算量但保持特征表达能力。
结构流程
-
DWConv (Depthwise Convolution)
-
每个通道独立卷积,计算量大幅下降。
-
如果输入 256 通道,DWConv 就是 256 个 3x3 卷积,而不是标准卷积那样 256x256 个。
-
-
PWConv (Pointwise Convolution, 1x1)
-
跨通道的整合,把 DWConv 产生的“弱特征”组合成“强特征”。
-
-
Channel Shuffle (通道混洗)
-
避免分组卷积带来的“通道隔离”问题,让信息在不同组之间流动。
-
类似 ShuffleNet 的 trick。
-
好处
✅ 轻量化:相比标准卷积,参数量和 FLOPs 更少;
✅ 特征交互:通道混洗提升表达能力;
✅ 适合小模型(如 YOLO11n、YOLO11s)或算力有限的设备(边缘端、移动端)。
🔹 2. VoVGSCSP(VoVNet + GSConv + CSP)
核心思想:高效骨干特征提取
👉 这是一个融合结构,把 VoVNet(并行卷积 + 一次性拼接输出) 和 CSP(Cross Stage Partial) 框架结合起来,同时用 GSConv 来进一步轻量化。
结构流程
-
CSP(Cross Stage Partial)
-
将特征分为两部分:一部分直接走捷径(shortcut),另一部分进入深度卷积堆叠。
-
这样能降低计算量,同时保持梯度流动。
-
-
VoVNet Block
-
一种类似 ResNet 的改进结构,但是所有中间层的输出都会被拼接(concat)到最后输出。
-
比 ResNet 更高效,特征表达能力更强。
-
-
GSConv 替代普通卷积
-
在 CSP 和 VoVNet 的基础模块中用 GSConv 替代普通卷积块。
-
相当于进一步“轻量化”。
-
好处
✅ 兼顾速度与精度:比普通 CSPBlock 更快,精度下降有限;
✅ 高效特征融合:VoVNet 的拼接方式让浅层和深层特征结合得更好;
✅ 可替换 CSPDarkNet 的部分结构,用于 backbone 或 neck。
🔹 在 YOLO11 里的作用
-
GSConv:
通常用来替换 Conv 或 C3 模块(尤其是在 Neck 部分),目的是减少参数量和推理耗时。 -
VoVGSCSP:
通常作为 Backbone 的中间层(类似 C3/C2f 替代品),它可以在保证特征表达能力的同时减轻模型规模。-
例如,把 YOLO11 里原来的
C3k2
、C2PSA
替换成VoVGSCSP
,就能得到一个更轻量的变体。
-
🔹 总结对比
模块 | 用途 | 特点 | 适用位置 |
---|---|---|---|
GSConv | 轻量化卷积 | DWConv + PWConv + 通道混洗 | Neck / 替换 Conv |
VoVGSCSP | 高效特征提取块 | VoVNet 拼接 + CSP + GSConv | Backbone / 替换 C3 |
✅ 修改要点
-
Backbone 部分
-
用
GSConv
替换了部分Conv
,提升轻量化和特征提取能力。 -
用
VoVGSCSP
替换了C3k2
,增强特征聚合能力。
-
-
Head 部分
-
把一些降通道
Conv
换成GSConv
。 -
主要的聚合层 (
C3k2
) 换成VoVGSCSP
,保持语义一致性。
-
生成的yaml文件:
# YOLO11 + 自定义模块融合版 nc: 80 scales: n: [0.50, 0.25, 1024] # Backbone backbone: - [-1, 1, Conv, [64, 3, 2]] # 0-P1/2 - [-1, 1, Conv, [128, 3, 2]] # 1-P2/4 - [-1, 2, VoVGSCSP, [256]] # 2 自定义替换C3k2 - [-1, 1, Conv, [256, 3, 2]] # 3-P3/8 - [-1, 2, VoVGSCSP, [512]] # 4 自定义替换C3k2 - [-1, 1, Conv, [512, 3, 2]] # 5-P4/16 - [-1, 2, VoVGSCSP, [512]] # 6 自定义替换C3k2 - [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32 - [-1, 2, VoVGSCSP, [1024]] # 8 自定义替换C3k2 - [-1, 1, SPPF, [1024, 5]] # 9 - [-1, 2, C2PSA, [1024]] # 10 - [-1, 1, CoTAttention, [1024]] # 11 Backbone末端 # Head head: # P5 -> P4 上采样融合 - [-1, 1, CARAFE, [1024, 512, 2]] # 12 上采样2x - [[-1, 6], 1, Concat, [1]] # 13 concat CARAFE + P4 - [-1, 2, GSConv, [512]] # 14 降通道 - [-1, 1, CoTAttention, [512]] # 15 # P4 -> P3 上采样融合 - [-1, 1, CARAFE, [512, 256, 2]] # 16 上采样2x - [[-1, 4], 1, Concat, [1]] # 17 concat CARAFE + P3 - [-1, 2, GSConv, [256]] # 18 降通道 - [-1, 1, CoTAttention, [256]] # 19 # P3 -> P4 下采样融合 - [-1, 1, GSConv, [256, 3, 2]] # 20 下采样2x - [[-1, 15], 1, Concat, [1]] # 21 concat 下采样 + P4上采样 - [-1, 2, GSConv, [512]] # 22 降通道 - [-1, 1, CoTAttention, [512]] # 23 # P4 -> P5 下采样融合 - [-1, 1, GSConv, [512, 3, 2]] # 24 下采样2x - [[-1, 11], 1, Concat, [1]] # 25 concat 下采样 + P5 backbone - [-1, 2, GSConv, [1024]] # 26 降通道 - [-1, 1, CoTAttention, [1024]] # 27 # Detect层 - [[19, 23, 27], 1, Detect, [nc]] # 28 Detect(P3, P4, P5)