MMDetection 生态下的动态多尺度语义分割:MMSegmentation 中 DMNet 原理与实战指南
【免费下载链接】mmsegmentationOpenMMLab Semantic Segmentation Toolbox and Benchmark.项目地址: https://gitcode.com/GitHub_Trending/mm/mmsegmentation
DMNet(Dynamic Multi-scale Network)是 ICCV 2019 提出的一种基于动态多尺度卷积的语义分割算法,其核心思想是用"由输入图像内容动态生成的卷积核"取代传统固定的多尺度滤波器,从而在不显著增加参数量的前提下自适应捕获不同尺度的上下文信息。本文以 MMSegmentation 仓库中 DMNet 官方文档 为主体,结合 DMHead 源码、基础配置文件 与 单元测试,完整讲解 DMNet 的算法原理、代码实现、配置解析与训练推理方法,帮助读者在 MMSegmentation 中快速复现与二次开发 DMNet。
一、算法背景与核心思想
1.1 多尺度表征的困境
在语义分割任务中,同一张图片里的物体与"stuff"类别往往存在显著的尺度差异(例如近处的人与远处的建筑),因此多尺度表征是提升分割精度的关键手段。传统方法构建多尺度表征通常有以下几种路线:
- 使用不同尺寸的卷积滤波器,但参数量与计算量成倍增长;
- 使用膨胀卷积(dilated convolution)扩大感受野,但滤波器尺寸/膨胀率一旦训练完成即固定;
- 使用不同尺度的池化网格(pooling grids),同样面临参数固定、推理时无法适应输入内容的问题。
这些方法的共同缺陷是:滤波器的参数在训练结束后完全固定,推理时对输入图像的内容不具备自适应性,且往往伴随较高的计算开销或参数量。
1.2 DMNet 的解决思路
DMNet 提出用动态卷积解决上述问题:网络由多个并行排列的DCM(Dynamic Convolutional Module,动态卷积模块)组成,每个 DCM 负责估计某一特定尺度的语义表征。关键在于,DCM 中使用的卷积核并非训练后固定的参数,而是根据输入特征图内容实时生成的 context-aware filters(上下文感知滤波器)。多个 DCM 的输出经过融合后得到最终的分割结果。
原论文在 PASCAL VOC 2012、Pascal-Context 与 ADE20K 三个数据集上进行了验证:在不使用 MS COCO 预训练和后处理的情况下,DMNet 在 PASCAL VOC 2012 test 集上取得了 84.4% mIoU,并在 Pascal-Context 与 ADE20K 上取得了当时领先的结果(该数据来自论文摘要,可作为算法背景参考;当前仓库则提供了 Cityscapes 与 ADE20K 上的可复现基准,见后文"模型库"一节)。
二、核心实现剖析:DCM 与 DMHead
MMSegmentation 在 mmseg/models/decode_heads/dm_head.py 中完整实现了 DMNet 的解码头,包含两个关键组件:DCM(第 11-89 行)与DMHead(第 92-141 行),并通过@MODELS.register_module()注册到模型注册表,配置文件中以type='DMHead'即可直接引用。
2.1 DCM:动态卷积模块
DCM的核心逻辑在forward中(dm_head.py#L61-L89),其前向流程可以拆解为四步:
- 生成动态卷积核:对输入
x做F.adaptive_avg_pool2d(x, self.filter_size)自适应平均池化,将特征压缩为filter_size × filter_size的空间尺寸,再经filter_gen_conv(1×1 卷积)生成与通道数对应的滤波器。这里的filter_size即 DCM 负责的尺度。 - 输入通道压缩:
input_redu_conv用 1×1 卷积把输入通道数统一到channels。 - 动态卷积执行:将特征变形为
[1, b*c, h, w]、滤波器变形为[b*c, 1, filter_size, filter_size],随后以groups=b*c的深度可分离方式调用F.conv2d,即每个通道使用各自的动态卷积核完成卷积,再经 padding 保持空间尺寸不变。 - 归一化与激活:依次经过 norm 层(若配置了
norm_cfg)与激活层,若开启fusion则再追加一个 1×1 的fusion_conv融合本模块输出。
从源码可以看出,DCM 的动态性来源于"池化-生成-卷积"这一路径:卷积核由当前输入的内容决定,因此同一套网络参数可以在推理时对不同图像生成不同滤波器,实现对输入的自适应。
2.2 DMHead:多尺度并联与融合
DMHead继承自BaseDecodeHead(mmseg/models/decode_heads/decode_head.py),构造函数中(dm_head.py#L107-L130)根据filter_sizes元组(默认(1, 3, 5, 7))创建一组并行的DCM实例,存入nn.ModuleList。
前向过程(dm_head.py#L132-L141):
def forward(self, inputs): x = self._transform_inputs(inputs) dcm_outs = [x] for dcm_module in self.dcm_modules: dcm_outs.append(dcm_module(x)) dcm_outs = torch.cat(dcm_outs, dim=1) output = self.bottleneck(dcm_outs) output = self.cls_seg(output) return output即:原始特征x与每个 DCM 的输出沿通道维拼接(通道数变为in_channels + len(filter_sizes) * channels),再经bottleneck(3×3 卷积)融合,最后交给cls_seg得到逐像素分类 logits。每个 DCM 只对输入做一次池化/卷积,各尺度并行计算,避免了传统多尺度方法的参数量膨胀。
2.3 参数说明与单元测试验证
DMHead的构造参数如下:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
filter_sizes | tuple/list | (1, 3, 5, 7) | 各 DCM 动态卷积核的尺寸,必须是列表或元组 |
fusion | bool | False | 是否在每个 DCM 输出后追加融合卷积 |
in_channels/channels | int | — | 输入通道数 / 模块中间通道数 |
conv_cfg/norm_cfg/act_cfg | dict | — | 卷积、归一化、激活层配置 |
单元测试 对这些行为做了明确约束,可作为二次开发时的回归依据:
filter_sizes传入标量(如1)会触发AssertionError(测试第 11-13 行),源码第 109 行assert isinstance(filter_sizes, (list, tuple))与之对应;- 未配置
norm_cfg时,网络中的卷积模块不含归一化层;配置SyncBN后包含(第 15-25 行); fusion=True时head.fusion为 True,且dcm_modules中各模块的filter_size与传入元组一一对应(第 38-40 行);- 输入
[1, 8, 23, 23]的特征图,输出形状为(1, num_classes, 23, 23),空间尺寸保持不变(第 42、58 行)。
三、配置文件逐项解析
3.1 解码头基础配置
DMNet 的模型骨架在 configs/base/models/dmnet_r50-d8.py 中定义,其decode_head段落是理解 DMNet 在 MMSegmentation 中落地方式的关键:
decode_head=dict( type='DMHead', in_channels=2048, in_index=3, channels=512, filter_sizes=(1, 3, 5, 7), dropout_ratio=0.1, num_classes=19, norm_cfg=dict(type='SyncBN', requires_grad=True), align_corners=False, loss_decode=dict( type='CrossEntropyLoss', use_sigmoid=False, loss_weight=1.0)),各字段含义:
type='DMHead':对应注册表中的DMHead类,即上文源码解析的解码头;in_channels=2048:取自 ResNet 最后一个 stage(in_index=3)的输出通道数;channels=512:DCM 内部特征与最终融合前的通道数;filter_sizes=(1, 3, 5, 7):四个并行 DCM 的动态卷积核尺寸,这也是 DMNet 捕获"多尺度"的直接体现;dropout_ratio=0.1:分类层前 Dropout 比例;loss_decode:主损失为CrossEntropyLoss,权重 1.0。
同时该骨架还配置了一个FCNHead辅助头(loss_weight=0.4),与主解码头共同参与训练,帮助浅层特征学习;推理阶段辅助头不参与输出。
3.2 数据集与训练调度
以 Cityscapes 为例,dmnet_r50-d8_4xb2-40k_cityscapes-512x512.py(实际文件名为 512x1024)通过_base_继承四份基础配置:
_base_ = [ '../_base_/models/dmnet_r50-d8.py', '../_base_/datasets/cityscapes.py', '../_base_/default_runtime.py', '../_base_/schedules/schedule_40k.py' ] crop_size = (512, 1024) data_preprocessor = dict(size=crop_size) model = dict(data_preprocessor=data_preprocessor)其中:
- configs/base/datasets/cityscapes.py 定义了 Cityscapes 数据管线:训练时
RandomResize(缩放范围 0.5~2.0)、RandomCrop(512×1024,cat_max_ratio=0.75防止裁剪块类别失衡)、RandomFlip、PhotoMetricDistortion等增强;验证/测试时按(2048, 1024)等比 resize;评估器为IoUMetric,指标mIoU; - configs/base/schedules/schedule_40k.py 提供 40k 迭代的优化器与学习率策略;
- 最后的
data_preprocessor覆写为匹配裁剪尺寸(512, 1024)。
ADE20K 的配置(如 dmnet_r50-d8_4xb4-160k_ade20k-512x512.py)结构相同,差异在于:数据集切换为ade20k.py、调度为schedule_160k.py、crop_size=(512, 512),并将主/辅助头的num_classes从 19 改为 150(ADE20K 的类别数)。
四、模型库与官方复现结果
configs/dmnet/目录共提供 12 个训练配置(R-50/R-101 × Cityscapes/ADE20K × 不同调度与分辨率),所有条目均登记在 configs/dmnet/metafile.yaml 中,可通过 MIM 或tools/train.py直接调用。以下结果表格继承自 官方 README(其中 mIoU 为官方在 V100 上复现的指标,Inf time 为单卡推理帧率;"ms+flip" 表示多尺度 + 水平翻转测试增强)。
4.1 Cityscapes(19 类)
| Method | Backbone | Crop Size | Lr schd | Mem (GB) | Inf time (fps) | Device | mIoU | mIoU(ms+flip) | config |
|---|---|---|---|---|---|---|---|---|---|
| DMNet | R-50-D8 | 512x1024 | 40000 | 7.0 | 3.66 | V100 | 77.78 | 79.14 | config |
| DMNet | R-101-D8 | 512x1024 | 40000 | 10.6 | 2.54 | V100 | 78.37 | 79.72 | config |
| DMNet | R-50-D8 | 769x769 | 40000 | 7.9 | 1.57 | V100 | 78.49 | 80.27 | config |
| DMNet | R-101-D8 | 769x769 | 40000 | 12.0 | 1.01 | V100 | 77.62 | 78.94 | config |
| DMNet | R-50-D8 | 512x1024 | 80000 | - | - | V100 | 79.07 | 80.22 | config |
| DMNet | R-101-D8 | 512x1024 | 80000 | - | - | V100 | 79.64 | 80.67 | config |
| DMNet | R-50-D8 | 769x769 | 80000 | - | - | V100 | 79.22 | 80.55 | config |
| DMNet | R-101-D8 | 769x769 | 80000 | - | - | V100 | 79.19 | 80.65 | config |
4.2 ADE20K(150 类)
| Method | Backbone | Crop Size | Lr schd | Mem (GB) | Inf time (fps) | Device | mIoU | mIoU(ms+flip) | config |
|---|---|---|---|---|---|---|---|---|---|
| DMNet | R-50-D8 | 512x512 | 80000 | 9.4 | 20.95 | V100 | 42.37 | 43.62 | config |
| DMNet | R-101-D8 | 512x512 | 80000 | 13.0 | 13.88 | V100 | 45.34 | 46.13 | config |
| DMNet | R-50-D8 | 512x512 | 160000 | - | - | V100 | 43.15 | 44.17 | config |
| DMNet | R-101-D8 | 512x512 | 160000 | - | - | V100 | 45.42 | 46.76 | config |
阅读上述表格可以发现两个工程要点:
- 分辨率影响显著:Cityscapes 上 769×769 裁剪通常优于 512×1024(如 40k 的 R-50 从 77.78 提升到 78.49),但推理帧率也从 3.66 fps 降至 1.57 fps,属于典型的精度-速度权衡;
- 更长的训练调度带来稳定增益:80k 迭代相对 40k 在 Cityscapes 各配置上普遍提升约 1 个点,
ms+flip测试增强额外带来约 1 个点收益;ADE20K 上 160k 相对 80k 亦有提升(R-101 从 45.34 到 45.42)。
五、训练、测试与推理实战
5.1 训练
单机单卡(或单机多卡)训练一个 DMNet 模型,使用仓库提供的 tools/train.py:
# 单卡训练 python tools/train.py configs/dmnet/dmnet_r50-d8_4xb2-40k_cityscapes-512x1024.py # 8 卡分布式训练(与 4xb2 等配置的 batch size 含义对应:4 GPU × batch 2) bash tools/dist_train.sh configs/dmnet/dmnet_r50-d8_4xb2-40k_cityscapes-512x1024.py 8dist_train.sh 为多卡启动脚本;Slurm 集群环境可参考 slurm_train.sh。训练前需按 configs/base/datasets/cityscapes.py 中data_root = 'data/cityscapes/'的约定放置数据集(leftImg8bit/与gtFine/目录结构)。
5.2 测试与评估
使用 tools/test.py 在验证集上评测:
python tools/test.py configs/dmnet/dmnet_r50-d8_4xb2-40k_cityscapes-512x1024.py \ /path/to/checkpoint.pth --eval mIoU配置文件中的val_evaluator已默认采用IoUMetric+mIoU。若需复现表格中的ms+flip指标,可利用 cityscapes.py 中预置的tta_pipeline(6 个缩放比例 × 水平翻转的TestTimeAug),在测试时开启 TTA 即可。
5.3 单图推理
推理脚本 demo/image_demo.py 支持对单张图片进行可视化推理:
python demo/image_demo.py demo/demo.png \ configs/dmnet/dmnet_r50-d8_4xb2-40k_cityscapes-512x1024.py \ /path/to/checkpoint.pth --device cuda输出将直接叠加显示分割结果;如需批量推理或接入推理管线,可参考基于MMSegInferencer的 demo/image_demo_with_inferencer.py。
六、引用
若在学术工作中使用或复现 DMNet,请引用原论文(bibtex 来自 configs/dmnet/README.md):
@InProceedings{He_2019_ICCV, author = {He, Junjun and Deng, Zhongying and Qiao, Yu}, title = {Dynamic Multi-Scale Filters for Semantic Segmentation}, booktitle = {Proceedings of the IEEE/CVF International Conference on Computer Vision (ICCV)}, month = {October}, year = {2019} }七、小结
DMNet 的价值在于把"多尺度"从静态结构升级为动态行为:通过DCM依据输入内容即时生成多组不同尺寸的卷积核,在并行分支中捕获多尺度上下文后融合,兼顾了精度与参数效率。在 MMSegmentation 仓库中,读者可以直接基于 dm_head.py 研究其实现,通过 configs/dmnet/ 下的 12 个配置复现 Cityscapes 与 ADE20K 上的全部基准,并借助filter_sizes、fusion、channels等参数快速开展自己的实验——例如增减 DCM 数量(修改filter_sizes)、开关fusion融合、或替换 backbone 观察动态卷积在不同特征层次上的表现。
【免费下载链接】mmsegmentationOpenMMLab Semantic Segmentation Toolbox and Benchmark.项目地址: https://gitcode.com/GitHub_Trending/mm/mmsegmentation
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考