MMsegmentation 中的 BiSeNetV2:实时语义分割双边网络的结构解析与训练配置指南
2026/9/16 12:54:34 网站建设 项目流程

MMsegmentation 中的 BiSeNetV2:实时语义分割双边网络的结构解析与训练配置指南

【免费下载链接】mmsegmentationOpenMMLab Semantic Segmentation Toolbox and Benchmark.项目地址: https://gitcode.com/GitHub_Trending/mm/mmsegmentation

本指南以 OpenMMLab 语义分割工具箱 mmsegmentation 中的 BiSeNetV2 实现为主线,从论文核心思想出发,结合仓库内真实源码、配置与测试,系统讲解 Detail Branch、Semantic Branch 与 Bilateral Guided Aggregation Layer 的结构细节,并完整给出四种 Cityscapes 训练配置变体的参数说明与运行方式。读完本文,你将理解 BiSeNetV2 如何在精度与速度之间取得平衡,并能直接基于 configs/bisenetv2 目录下的配置完成训练、验证与推理。

BiSeNetV2 论文要点:为什么"双边"能兼顾速度与精度

BiSeNetV2(Bilateral Network with Guided Aggregation for Real-time Semantic Segmentation,论文发表于 IJCV,对应仓库 configs/bisenetv2/README.md 的 Abstract)针对实时语义分割中的一对核心矛盾提出解法:

  • 低层细节与高层语义都不可或缺:语义分割既需要精细的边缘与纹理(低层细节),又需要类别层面的上下文理解(高层语义);
  • 既有方案为提速往往牺牲细节:传统实时方法几乎总是通过降低低层细节来换取推理速度,导致精度明显下降。

该架构的核心主张是将空间细节与类别语义分开处理,从而同时获得高精度与高效率:

  1. Detail Branch(细节分支):通道宽、层数浅,用于捕获低层细节,生成高分辨率特征表示;
  2. Semantic Branch(语义分支):通道窄、层数深,用于获取高层语义上下文;由于缩减了通道容量并采用快速下采样策略,语义分支非常轻量;
  3. Guided Aggregation Layer(引导聚合层):增强两条分支的相互联系,融合两类特征;
  4. Booster 训练策略(助推训练):在训练阶段额外监督中间特征,不增加任何推理开销即可提升分割精度。

论文在 2048×1024 输入下于 Cityscapes 测试集取得 72.6% mIoU,并在单张 NVIDIA GeForce GTX 1080 Ti 上达到 156 FPS。注意:该数字来自论文原始陈述,仓库 README 的 Results 表格中给出的则是 mmsegmentation 复现实验(下文有完整表格)。

仓库实现:mmseg 中 BiSeNetV2 的模块级结构

mmsegmentation 将 BiSeNetV2 作为 Backbone 实现,源码位于 mmseg/models/backbones/bisenetv2.py,并通过@MODELS.register_module()注册(见该文件第 544-545 行),配置中以type='BiSeNetV2'直接引用。

从源码结构看,整个骨干网络由以下模块按顺序组合而成:

BiSeNetV2 ├── DetailBranch(细节分支) │ └── 3 个 stage,每 stage 由 stride=2 的下采样卷积 + stride=1 的普通卷积堆叠 ├── SemanticBranch(语义分支) │ ├── StemBlock(stem1):入口模块,含 stride=2 卷积、1×1 卷积 + 3×3 卷积、MaxPool 分支与融合卷积 │ ├── GELayer ×N(stem2~4 内部):Gather-and-Expansion 层,等价于倒残差(Inverted Residual)结构 │ └── CEBlock(stage4 之后):Context Embedding Block,用全局池化注入大感受野上下文 └── BGALayer(Bilateral Guided Aggregation Layer) └── 将 Detail Branch 输出与 Semantic Branch 最后一级输出融合,产出分割头输入特征

DetailBranch:宽通道、浅层、高分辨率

DetailBranch 默认三阶段通道数为(64, 64, 128)。每个阶段都以stride=2的 3×3 卷积做下采样,随后接 1~2 个stride=1的 3×3 卷积。全程保持较高分辨率(输入 1024×1024 时输出为 128×128 附近),用于保留空间细节。构造时逐个阶段存入nn.ModuleList,前向时依次通过(forward见第 96-99 行)。

SemanticBranch:窄通道、深层、轻量化

SemanticBranch 默认四阶段通道数为(16, 32, 64, 128),逐级快速下采样到 1/8、1/16、1/32。内部使用两类基础模块:

  • StemBlock(源码):先做 stride=2 卷积,再分两条路径——一条是 1×1+3×3 卷积,另一条是 MaxPool2d——最后把两条路径拼接并通过 1×1 融合卷积输出;
  • GELayer(源码):Gather-and-Expansion 层,其结构与 MobileNetV2 的倒残差一致:conv1(3×3) → dwconv(3×3, groups=in_channels, 通道扩展 exp_ratio 倍) → conv2(1×1),并带有残差连接。stride=2 时 shortcut 使用深度可分离卷积对齐分辨率与通道数;
  • CEBlock(源码):Context Embedding Block,通过AdaptiveAvgPool2d((1,1))提取全局上下文后与原始特征相加,再经 3×3 卷积输出,为语义分支补足大感受野。

semantic_expansion_ratio=6控制 GELayer 中间通道的扩展倍数(mid_channel = in_channels * exp_ratio,见第 211 行)。SemanticBranch 前向会输出每一级特征列表(第 424-430 行),这正是 Booster 辅助头所需的"中间特征"。

BGALayer:双向引导聚合

BGALayer 接收 Detail Branch 的输出x_d与 Semantic Branch 最后一级输出x_s,其融合逻辑(forward,第 523-541 行)分两步:

  1. 对细节特征做深度可分离卷积与下采样,对语义特征做卷积与深度可分离卷积;
  2. 用语义特征经sigmoid后作为门控去调制细节特征(detail_dwconv * torch.sigmoid(semantic_conv)),两条调制路径相加后经 3×3 卷积输出——即"语义引导细节、细节反哺语义"的双向聚合。

最终 BiSeNetV2.forward 将 BGA 输出与语义分支前几级特征拼接成 5 个输出(out_indices=(0,1,2,3,4)):outs[0]给主分割头,outs[1..4]分别给 4 个辅助头。

模型配置逐项解析:configs/base/models/bisenetv2.py

所有 BiSeNetV2 配置都继承自基础模型配置 configs/base/models/bisenetv2.py。其完整结构如下:

norm_cfg = dict(type='SyncBN', requires_grad=True) data_preprocessor = dict( type='SegDataPreProcessor', mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], bgr_to_rgb=True, pad_val=0, seg_pad_val=255) model = dict( type='EncoderDecoder', data_preprocessor=data_preprocessor, pretrained=None, backbone=dict( type='BiSeNetV2', detail_channels=(64, 64, 128), semantic_channels=(16, 32, 64, 128), semantic_expansion_ratio=6, bga_channels=128, out_indices=(0, 1, 2, 3, 4), init_cfg=None, align_corners=False), decode_head=dict( type='FCNHead', in_channels=128, in_index=0, channels=1024, num_convs=1, concat_input=False, dropout_ratio=0.1, num_classes=19, norm_cfg=norm_cfg, align_corners=False, loss_decode=dict( type='CrossEntropyLoss', use_sigmoid=False, loss_weight=1.0)), auxiliary_head=[ ... 4 个 FCNHead ... ], train_cfg=dict(), test_cfg=dict(mode='whole'))

关键配置项含义如下:

配置段参数默认值作用
backbonedetail_channels(64, 64, 128)Detail Branch 各阶段通道数
backbonesemantic_channels(16, 32, 64, 128)Semantic Branch 各阶段通道数
backbonesemantic_expansion_ratio6GELayer 中间通道扩展倍数
backbonebga_channels128BGALayer 中间通道数
backboneout_indices(0,1,2,3,4)输出 5 级特征:1 个 BGA 融合特征 + 4 个语义中间特征
decode_headtypeFCNHead主分割头,输入 BGA 输出(128 通道)
decode_headnum_convs1/dropout_ratio=0.1主头为单卷积 + 10% dropout
auxiliary_head4 ×FCNHead通道16/32/64/128Booster 助推头:分别监督语义分支各级中间特征
test_cfgmode'whole'整图推理(不做滑窗)

其中 Booster 策略在代码层面的体现就是auxiliary_head列表——4 个 FCNHead 分别挂在 Semantic Branch 的 stem2/stem3/stem4/CEBlock 输出上(对应in_index=1,2,3,4),训练时产生额外梯度,推理时这些分支不参与计算,因此不增加任何推理开销。主头与辅助头均使用CrossEntropyLossuse_sigmoid=False, loss_weight=1.0)。

四种 Cityscapes 训练配置变体

仓库 configs/bisenetv2 目录下共提供 4 个可直接运行/复现的训练配置,全部基于 Cityscapes 数据集,输入裁剪尺寸 1024×1024,训练 160k iterations。

1. 基线:bisenetv2_fcn_4xb4-160k_cityscapes-1024x1024.py

configs/bisenetv2/bisenetv2_fcn_4xb4-160k_cityscapes-1024x1024.py 是该系列的标准配置,继承自 4 个_base_文件:

_base_ = [ '../_base_/models/bisenetv2.py', '../_base_/datasets/cityscapes_1024x1024.py', '../_base_/default_runtime.py', '../_base_/schedules/schedule_160k.py' ] crop_size = (1024, 1024) data_preprocessor = dict(size=crop_size) model = dict(data_preprocessor=data_preprocessor) param_scheduler = [ dict(type='LinearLR', by_epoch=False, start_factor=0.1, begin=0, end=1000), dict(type='PolyLR', eta_min=1e-4, power=0.9, begin=1000, end=160000, by_epoch=False) ] optimizer = dict(type='SGD', lr=0.05, momentum=0.9, weight_decay=0.0005) optim_wrapper = dict(type='OptimWrapper', optimizer=optimizer) train_dataloader = dict(batch_size=4, num_workers=4) val_dataloader = dict(batch_size=1, num_workers=4) test_dataloader = val_dataloader

要点解读:

  • 学习率调度:前 1000 iter 用LinearLR0.1×lr线性升温(warmup),之后PolyLRpower=0.9, eta_min=1e-4)衰减至 160000 iter;
  • 优化器:SGD(lr=0.05, momentum=0.9, weight_decay=0.0005),注意这里在继承schedule_160k.py中默认lr=0.01的基础上覆写为0.05
  • 数据流水线(来自 configs/base/datasets/cityscapes_1024x1024.py):RandomResize(scale=(2048,1024), ratio_range=(0.5,2.0)) → RandomCrop(1024×1024, cat_max_ratio=0.75) → RandomFlip(0.5) → PhotoMetricDistortion,测试阶段按 (2048, 1024) 保持比例缩放后整图推理;
  • 训练循环(来自 configs/base/schedules/schedule_160k.py):IterBasedTrainLoop(max_iters=160000, val_interval=16000),即每 16000 iter 验证一次;
  • 4xb4含义:4 张 GPU × 每卡 batch_size=4,总 batch size 16(metafile 中记录为 Batch Size 16)。

2. OHEM 变体:bisenetv2_fcn_4xb4-ohem-160k_cityscapes-1024x1024.py

configs/bisenetv2/bisenetv2_fcn_4xb4-ohem-160k_cityscapes-1024x1024.py 在基线基础上引入Online Hard Example Mining(OHEM,在线难样本挖掘):主头与 4 个辅助头均配置

sampler=dict(type='OHEMPixelSampler', thresh=0.7, min_kept=10000)

即损失计算时只保留预测概率低于阈值0.7的"困难像素",且每张图至少保留10000个像素参与回传。该变体在 Cityscapes 上 mIoU 由 73.21 提升至73.57

3. 混合精度(AMP/FP16):bisenetv2_fcn_4xb4-amp-160k_cityscapes-1024x1024.py

configs/bisenetv2/bisenetv2_fcn_4xb4-amp-160k_cityscapes-1024x1024.py 极简地覆写优化器包装器:

_base_ = './bisenetv2_fcn_4xb4-160k_cityscapes-1024x1024.py' optim_wrapper = dict( _delete_=True, type='AmpOptimWrapper', optimizer=dict(type='SGD', lr=0.05, momentum=0.9, weight_decay=0.0005), loss_scale=512.)

_delete_=True表示删除继承来的OptimWrapper,改用AmpOptimWrapper(自动混合精度,loss_scale=512)。效果上显存占用从 7.64 GB 降至5.77 GB,推理速度从 31.77 FPS 提升至 36.65 FPS(V100),mIoU 基本持平(73.07 vs 73.21)。

4. 更大 batch:bisenetv2_fcn_4xb8-160k_cityscapes-1024x1024.py

configs/bisenetv2/bisenetv2_fcn_4xb8-160k_cityscapes-1024x1024.py 仅将train_dataloader.batch_size由 4 改为8(即 4 卡 × 8 = 总 batch 32)。更大的 batch 带来明显精度增益:mIoU 由 73.21 提升至75.76(ms+flip 达 77.79),代价是显存翻倍至 15.05 GB。

实验结果一览(Cityscapes)

下表完整继承自 configs/bisenetv2/README.md 的 Results 章节,为 mmsegmentation 在 4×V100 上的复现结果:

MethodBackboneCrop SizeLr schdMem (GB)Inf time (fps)DevicemIoUmIoU(ms+flip)configdownload
BiSeNetV2BiSeNetV21024x10241600007.6431.77V10073.2175.74configmodel | log
BiSeNetV2BiSeNetV2 (OHEM)1024x10241600007.64-V10073.5775.80configmodel | log
BiSeNetV2BiSeNetV2 (4x8)1024x102416000015.05-V10075.7677.79configmodel | log
BiSeNetV2BiSeNetV2 (FP16)1024x10241600005.7736.65V10073.0775.13configmodel | log

表格备注(继承自 README):

  • OHEM:训练中采用在线难样本挖掘;
  • FP16:训练中采用混合精度(FP16);
  • 4x8:4 张 GPU、每卡 8 个样本进行训练。

上述模型的元数据(训练数据、batch size、显存、权重与日志地址)同时维护在 configs/bisenetv2/metafile.yaml 中,供模型索引与自动下载使用。

如何训练、测试与推理

在 mmsegmentation 中使用以下命令(以tools/dist_train.sh/tools/dist_test.sh为例)即可复现上述实验:

# 4 卡分布式训练(与官方复现环境一致) bash tools/dist_train.sh configs/bisenetv2/bisenetv2_fcn_4xb4-160k_cityscapes-1024x1024.py 4 # 单卡训练 python tools/train.py configs/bisenetv2/bisenetv2_fcn_4xb4-160k_cityscapes-1024x1024.py # 测试并输出 mIoU(加载官方权重或自训权重) python tools/test.py configs/bisenetv2/bisenetv2_fcn_4xb4-160k_cityscapes-1024x1024.py /path/to/checkpoint.pth --out results.pkl

推理阶段由test_cfg = dict(mode='whole')控制为整图直接前向(不做滑窗切块),这与 BiSeNetV2 面向实时场景的设计一致。若要验证模型的输出形状与实现正确性,可参考单元测试 tests/test_models/test_backbones/test_bisenetv2.py:该测试以(2, 3, 128, 256)输入验证 backbone 输出 5 级特征,并断言各输出张量形状——feat[0][2, 128, 16, 32](BGA 融合特征,供主分割头),feat[1..4]分别为[2,16,32,64][2,32,16,32][2,64,8,16][2,128,4,8](供 4 个 Booster 辅助头),同时覆盖了 DetailBranch、SemanticBranch、BGALayer 三个子模块的独立测试。

引用

若在研究中使用了 BiSeNetV2 或本仓库实现,可引用以下文献(来自 configs/bisenetv2/README.md 的 Citation 章节):

@article{yu2021bisenet, title={Bisenet v2: Bilateral network with guided aggregation for real-time semantic segmentation}, author={Yu, Changqian and Gao, Changxin and Wang, Jingbo and Yu, Gang and Shen, Chunhua and Sang, Nong}, journal={International Journal of Computer Vision}, pages={1--18}, year={2021}, publisher={Springer} }

【免费下载链接】mmsegmentationOpenMMLab Semantic Segmentation Toolbox and Benchmark.项目地址: https://gitcode.com/GitHub_Trending/mm/mmsegmentation

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询