【版本适配实战】从MMCV 1.x到2.x:MMSegmentation升级避坑全指南

张开发
2026/4/15 23:56:06 15 分钟阅读

分享文章

【版本适配实战】从MMCV 1.x到2.x:MMSegmentation升级避坑全指南
1. 为什么需要从MMCV 1.x升级到2.x最近在帮团队升级一个老旧的图像分割项目时深刻体会到了版本升级的必要性。这个项目原本基于MMCV 1.7.2和MMSegmentation 1.2.2运行还算稳定但随着新需求不断加入老版本的局限性越来越明显。最直接的感受是性能差距。新版本的MMCV 2.x在训练速度上提升了约30%特别是在使用大batch size时内存管理更加高效。举个例子同样的ResNet-50DeepLabV3配置在1.x版本上batch size最多只能设到8而2.x版本可以轻松跑到12。这对于我们处理高分辨率医学图像特别重要。另一个关键点是功能支持。新版本加入了对Transformer结构的原生支持像Swin Transformer、Mask2Former这些新模型在老版本上要么跑不起来要么需要大量魔改。记得有次尝试在老版本上实现一个Swin-Unet光是解决各种兼容性问题就花了整整两周最后还是放弃了。社区支持也是个现实问题。现在OpenMMLab官方文档和社区讨论基本都围绕2.x版本展开遇到问题很难找到1.x版本的解决方案。上个月就遇到一个CUDA内存泄漏的bug在GitHub上搜了半天才发现是1.x版本特有的问题官方早就不维护了。2. 升级前的准备工作2.1 环境检查清单在动手升级前我习惯先做个完整的环境快照。这个习惯帮我省去了不少麻烦特别是在升级出问题时能快速回滚。具体操作# 记录当前环境状态 pip freeze requirements_old.txt mim list mim_packages_old.txt python -c import mmcv; print(mmcv.__version__) mmcv_version.txt特别注意检查这些关键依赖的版本PyTorch版本最好在1.8以上CUDA/cuDNN版本与PyTorch匹配mmcv-full的编译选项是否带CUDA支持2.2 项目代码备份策略吃过几次亏后我现在对代码备份特别谨慎。推荐使用git创建一个专门的分支git checkout -b mm_upgrade git add . git commit -m 备份升级前状态对于配置文件我习惯多复制一份cp configs/my_model.py configs/my_model_backup.py2.3 依赖关系梳理用这个命令可以生成完整的依赖树pipdeptree -p mmcv-full特别注意那些间接依赖比如mmdetection的版本。有次升级后就因为mmdet版本不匹配导致评估阶段报错排查了好久。3. 安装新版本的正确姿势3.1 清理旧环境很多人直接pip install -U就开始升级这其实很危险。我的标准操作是先彻底卸载pip uninstall mmcv mmcv-full mmsegmentation -y mim uninstall mmcv mmcv-full -y特别注意检查site-packages里是否有残留ls /path/to/python/site-packages | grep mm3.2 使用MIM安装官方现在强推MIM作为安装工具确实比pip靠谱很多。我的安装组合一般是mim install mmcv2.0.0 mim install mmsegmentation1.0.0如果遇到编译问题可以尝试指定版本mim install mmcv-full2.0.0 -f https://download.openmmlab.com/mmcv/dist/cu113/torch1.12/index.html3.3 验证安装安装完别急着跑代码先做基础验证import mmcv import mmseg print(mmcv.__version__, mmseg.__version__)我还会跑个简单的单元测试python -c from mmseg.apis import inference_model; print(API检查通过)4. 常见报错及解决方案4.1 日志系统变更老代码里常见的get_root_logger在新版本已经移除需要改为标准logging# 旧代码 from mmseg.utils import get_root_logger logger get_root_logger() # 新代码 import logging logger logging.getLogger(__name__)如果想保持原有格式可以这样配置logging.basicConfig( format%(asctime)s - %(name)s - %(levelname)s - %(message)s, levellogging.INFO)4.2 模块路径变化最大的变化是mmseg.core和mmseg.ops的迁移。这是我整理的对照表旧导入路径新导入路径mmseg.core.evaluationmmseg.evaluationmmseg.core.hooksmmseg.engine.hooksmmseg.ops.resizemmseg.models.utils.resize特别提醒build_pixel_sampler现在在from mmseg.structures import build_pixel_sampler4.3 Runner系统重构训练流程相关的改动最大原来的mmcv.runner整体迁移到了mmengine# 旧代码 from mmcv.runner import init_dist, get_dist_info # 新代码 from mmengine.dist import init_dist, get_dist_info最复杂的train_segmentor的重构# 旧代码 from mmseg.apis import train_segmentor train_segmentor(model, datasets, cfg, distributedTrue) # 新代码 from mmengine.runner import Runner runner Runner.from_cfg(cfg) runner.train()5. 配置文件迁移指南5.1 基础配置变更新版本的配置系统改用mmengine.Config但兼容旧格式。主要变化在runner字段完全重构# 旧配置 runner dict(typeEpochBasedRunner, max_epochs40) # 新配置 train_cfg dict(by_epochTrue, max_epochs40, val_interval1)优化器配置现在更接近PyTorch原生风格# 旧配置 optimizer dict(typeSGD, lr0.01, momentum0.9, weight_decay0.0005) # 新配置 optim_wrapper dict( typeOptimWrapper, optimizerdict(typeSGD, lr0.01, momentum0.9, weight_decay0.0005))5.2 数据管道调整train_pipeline和test_pipeline的改动不大但有几个关键点Normalize现在需要显式指定mean和std# 旧配置 img_norm_cfg dict(mean[123.675, 116.28, 103.53], std[58.395, 57.12, 57.375], to_rgbTrue) # 新配置 normalizedict( typeNormalize, mean[123.675, 116.28, 103.53], std[58.395, 57.12, 57.375], to_rgbTrue)Collect操作现在需要指定meta_keyscollectdict( typeCollect, keys[img, gt_semantic_seg], meta_keys[img_path, seg_map_path, ori_shape, img_shape, pad_shape, scale_factor, flip, flip_direction, img_norm_cfg])6. 自定义模块适配技巧6.1 自定义模型适配如果你的项目有自定义模型需要注意这些变化所有自定义的MODELS组件现在需要显式注册# 旧代码 from mmseg.models.builder import MODELS MODELS.register_module() class MyCustomModule(nn.Module): ... # 新代码 from mmseg.registry import MODELS MODELS.register_module() class MyCustomModule(nn.Module): ...forward_train的签名变了# 旧代码 def forward_train(self, img, img_metas, gt_semantic_seg): # 新代码 def forward_train(self, inputs, data_samples):6.2 自定义数据集处理数据集接口也有较大变化现在需要继承BaseSegDatasetfrom mmseg.datasets import BaseSegDataset DATASETS.register_module() class MyDataset(BaseSegDataset): METAINFO dict( classes(background, foreground), palette[[0,0,0], [255,255,255]]) def __init__(self, **kwargs): super().__init__( img_suffix.jpg, seg_map_suffix.png, **kwargs)数据加载现在使用PackSegInputstrain_pipeline [ dict(typeLoadImageFromFile), dict(typeLoadAnnotations), ... dict(typePackSegInputs) ]7. 验证升级是否成功7.1 基础功能检查我通常会按这个顺序验证数据加载python tools/analysis_tools/browse_dataset.py configs/my_config.py前向推理from mmseg.apis import inference_model result inference_model(configs/my_config.py, demo.jpg)单GPU训练python tools/train.py configs/my_config.py --work-dir work_dirs/tmp7.2 性能基准测试升级后一定要对比训练曲线和指标使用相同随机种子训练100iter对比loss下降曲线在验证集上跑完整评估对比mIoU等指标使用nvtop监控GPU显存占用情况7.3 常见问题排查如果遇到奇怪的问题可以尝试清理.pyc缓存文件find . -name *.pyc -delete检查环境变量echo $PYTHONPATH最小化复现import mmcv import mmseg print(基本导入成功)升级过程就像给飞行中的飞机换引擎需要格外小心。记得去年有个项目因为急着升级没做好充分测试结果在交付前一天发现评估指标计算有问题。现在我的原则是升级后至少跑完一个完整的训练周期验证所有指标正常才算成功。

更多文章