DEIM 的 backbone 由 HGNetv2 构成,其最前端是一段经典的 HGStem—— 两条 stride=2 的方形卷积把输入从 3 通道压到 16 通道、4 倍下采样。它是整个网络的第一层,却在设计上最 "朴素":单一路径、纯方形卷积,既没有多尺度,也没有边缘 / 方向 / 频域先验,下采样还是一次性信息丢失。我们做了一批stem_<X>替换变体,全部保持 "输出 16 通道、stride 4" 的接口不变、一行 yaml 切换,下游 HG_Stage 与 decoder 零改动。
1. 为什么盯着 "第一层" 改
一个检测器对一张图做的第一件事,就是 stem。stem 是 backbone 的第 0 层:它把原始像素(3 通道、全分辨率)变成第一张特征图(16 通道、1/4 分辨率)。
stem 是网络的门面,HGStem 却用最朴素的方式开门 —— 单路径、无先验、下采样丢信息。
| 方向 | 思路 | 典型手段 |
|---|---|---|
| 结构重参化 | 训练时多分支、推理时折叠成单卷积 | RepVGG / MobileOne 式可重参化块 |
| 空间切分重组 | 下采样前先按空间位置切分,保留全部像素信息 | space-to-depth / PixelUnshuffle 式切分 |
| 频域切分 | 用 Haar 小波把 2×2 块分解成低频 + 高频子带 | 小波变换 + 子带加权 |
| 边缘先验 | 在 stem 里显式注入边缘 / 平滑信息 | LoG(高斯拉普拉斯)边缘检测核 |
| 方向建模 | 用方向性滤波器捕捉各向异性纹理 | 方向 LoG + 方向门控 |
这个位置的特殊性在于:
所有后续特征都从这里长出来——stem 丢的信息,后面的 stage 再也找不回来;
它工作在最高分辨率—— 同样的卷积核,在 stem 上算的 FLOPs 占比很高,改它性价比极高;
它离像素最近—— 边缘、纹理、频率这些底层先验,只有在 stem 这个位置注入才最自然。
2. stem是如何改进的
我们实现了一批stem_<X>替换变体,全部满足同一个接口约定:输入 3 通道、输出 stem_dim=16 通道、整体 stride=4—— 和 HGStem 完全一致,所以下游第一个 HG_Stage(16→64)与 decoder(feat_strides=[16,32])都无需任何改动,yaml 里把 backbone 第一行的HGStem换成stem_<X>即可。
| 变体 | 路线 | 核心机制 |
|---|---|---|
stem_RepStem | 结构重参化 | 3 个 MobileOneBlock 堆叠(3×3 s2 → 3×3 dw s2 → 1×1),训练时多分支、推理时折叠成单卷积 |
stem_SRFD | 空间切分重组 | 静态 Cut 切分:2×2 位置切 4 份 concat 后 1×1 融合,下采样不丢像素;第二段 conv/maxpool/cut 三路融合 |
stem_DPAS | 自适应切分 + 门控 | 切分位置带可学习权重(softmax 加权),两条路径用 PathGate 软门控融合 |
stem_WGFS | 频域切分 | Haar 小波把 2×2 块分解为 LL/LH/HL/HH 子带,可学习 band 权重(sigmoid)再融合 |
stem_LoGStem | 边缘先验 | LoG 固定核提取边缘响应 + 高斯平滑残差 + DRFD 精炼 |
stem_ODALStem | 方向建模 | 各向同性 LoG + 方向性 LoG 双滤波,OrientationGate 方向门控 + 可学习方向缩放 |
4.代码和视频讲解
视频讲解:
DEIM:超越 YOLO,快准双绝!DEIM:让 DETR 告别慢收敛,开启实时检测新纪元_哔哩哔哩_bilibili
DEIM:超越 YOLO,快准双绝!一个视频告诉你DEIM如何搭建backbone_哔哩哔哩_bilibili
代码获取:
https://github.com/tgf123/YOLOv8_improve/blob/master/DEIM.md
5.以WTConv小波卷积为例
第一: 将下面的核心代码复制到DEIMv2-main\DEIM_YOLO\change_mode_stem
路径下,如下图所示。
第二:自适应导包与模型搭建
第三:将模型配置文件复制到DEIM.YAMY文件中
第四:yaml改进配置文件
backbone: # [from, repeats, module, args] # HG_Stage args = hgnetv2.py 里 arch_configs[B0]['stage_config'] 原样: # [in_ch, mid_ch, out_ch, num_blocks, downsample, light_block, kernel_size, layer_num] - [-1, 1, stem_DPAS, [3, 16]] # 0 stem(stem_channels) -> P2/4(stem_DPAS) - [-1, 1, HG_Stage, [16, 16, 64, 1, False, False, 3, 3]] # 1 stage1 -> P2/4 - [-1, 1, HG_Stage, [64, 32, 256, 1, True, False, 3, 3]] # 2 stage2 -> P3/8(n 档不用) - [-1, 1, HG_Stage, [256, 64, 512, 2, True, True, 5, 3]] # 3 stage3 -> P4/16, 512ch - [-1, 1, HG_Stage, [512, 128, 1024, 1, True, True, 5, 3]] # 4 stage4 -> P5/32, 1024ch head: # ---- 1) input_proj(官方 forward 的 proj_feats 循环,n 档 num_levels=2 故循环 2 次)---- # 每个尺度一个独立层,from 显式连到对应 backbone 层: - [-1, 1, input_proj, [128]] # 5 proj_feats[1] = P5': layer4(1024) -> 128 - [3, 1, input_proj, [128]] # 6 proj_feats[0] = P4': layer3( 512) -> 128 # ---- 2) intra-scale encoder(DEIM 的 HybridEncoder.encoder,作用于 use_encoder_idx=[1] 即 P5')---- - [5, 1, TransformerEncoder, [128, 8, 512, 1]] # 7 P5'' # ---- 3) 自顶向下 FPN ---- - [-1, 1, lateral_convs, [128]] # 8 Y5 = lateral_convs.0(P5'')(1x1 conv + BN,无激活) - [-1, 1, upsample_feat, [2, "nearest"]] # 9 上采样 2 倍:Y5 -> P4 分辨率 - [[-1, 6], 1, concat, [1]] # 10 concat(↑Y5, P4') -> 256ch - [-1, 1, fpn_blocks, [256, 128, 256, 21, 2]] # 11 F4 = fpn_blocks.0 (c1,c2,c3,c4,n) # ---- 4) 自底向上 PAN ---- - [-1, 1, downsample_feat, [128, 128, 3, 2]] # 12 ↓F4(SCDown: 1x1 + 3x3 dw s2) - [[-1, 8], 1, concat, [1]] # 13 concat(↓F4, Y5) -> 256ch - [-1, 1, pan_blocks, [256, 128, 256, 21, 2]] # 14 F5 = pan_blocks.0 -> P5/32 - [[11, -1], 1, DEIMDecoder, [nc, 128, 3, 300, 32, 4, [6, 6]]] # 15 Detect(F4, F5) # ^hidden, layers, queries, reg_max, reg_scale, num_points第五:模型跑出的结果