diff --git a/.dev/batch_test_list.py b/.dev/batch_test_list.py index c4fd8f97e4..0d096ed943 100644 --- a/.dev/batch_test_list.py +++ b/.dev/batch_test_list.py @@ -2,25 +2,25 @@ # Inference Speed is tested on NVIDIA V100 hrnet = [ dict( - config='configs/hrnet/fcn_hr18s_512x512_160k_ade20k.py', + config='configs/hrnet/fcn_hr18s_4xb4-160k_ade20k-512x512.py', checkpoint='fcn_hr18s_512x512_160k_ade20k_20200614_214413-870f65ac.pth', # noqa eval='mIoU', metric=dict(mIoU=33.0), ), dict( - config='configs/hrnet/fcn_hr18s_512x1024_160k_cityscapes.py', + config='configs/hrnet/fcn_hr18s_4xb2-160k_cityscapes-512x1024.py', checkpoint='fcn_hr18s_512x1024_160k_cityscapes_20200602_190901-4a0797ea.pth', # noqa eval='mIoU', metric=dict(mIoU=76.31), ), dict( - config='configs/hrnet/fcn_hr48_512x512_160k_ade20k.py', + config='configs/hrnet/fcn_hr48_4xb4-160k_ade20k-512x512.py', checkpoint='fcn_hr48_512x512_160k_ade20k_20200614_214407-a52fc02c.pth', eval='mIoU', metric=dict(mIoU=42.02), ), dict( - config='configs/hrnet/fcn_hr48_512x1024_160k_cityscapes.py', + config='configs/hrnet/fcn_hr48_4xb2-160k_cityscapes-512x1024.py', checkpoint='fcn_hr48_512x1024_160k_cityscapes_20200602_190946-59b7973e.pth', # noqa eval='mIoU', metric=dict(mIoU=80.65), @@ -28,25 +28,25 @@ ] pspnet = [ dict( - config='configs/pspnet/pspnet_r50-d8_512x1024_80k_cityscapes.py', + config='configs/pspnet/pspnet_r50-d8_4xb2-80k_cityscapes-512x1024.py', checkpoint='pspnet_r50-d8_512x1024_80k_cityscapes_20200606_112131-2376f12b.pth', # noqa eval='mIoU', metric=dict(mIoU=78.55), ), dict( - config='configs/pspnet/pspnet_r101-d8_512x1024_80k_cityscapes.py', + config='configs/pspnet/pspnet_r101-d8_4xb2-80k_cityscapes-512x1024.py', checkpoint='pspnet_r101-d8_512x1024_80k_cityscapes_20200606_112211-e1e1100f.pth', # noqa eval='mIoU', metric=dict(mIoU=79.76), ), dict( - config='configs/pspnet/pspnet_r101-d8_512x512_160k_ade20k.py', + config='configs/pspnet/pspnet_r101-d8_4xb4-160k_ade20k-512x512.py', checkpoint='pspnet_r101-d8_512x512_160k_ade20k_20200615_100650-967c316f.pth', # noqa eval='mIoU', metric=dict(mIoU=44.39), ), dict( - config='configs/pspnet/pspnet_r50-d8_512x512_160k_ade20k.py', + config='configs/pspnet/pspnet_r50-d8_4xb4-160k_ade20k-512x512.py', checkpoint='pspnet_r50-d8_512x512_160k_ade20k_20200615_184358-1890b0bd.pth', # noqa eval='mIoU', metric=dict(mIoU=42.48), @@ -54,13 +54,13 @@ ] resnest = [ dict( - config='configs/resnest/pspnet_s101-d8_512x512_160k_ade20k.py', + config='configs/resnest/resnest_s101-d8_pspnet_4xb4-160k_ade20k-512x512.py', # noqa checkpoint='pspnet_s101-d8_512x512_160k_ade20k_20200807_145416-a6daa92a.pth', # noqa eval='mIoU', metric=dict(mIoU=45.44), ), dict( - config='configs/resnest/pspnet_s101-d8_512x1024_80k_cityscapes.py', + config='configs/resnest/resnest_s101-d8_pspnet_4xb2-80k_cityscapes512x1024.py', # noqa checkpoint='pspnet_s101-d8_512x1024_80k_cityscapes_20200807_140631-c75f3b99.pth', # noqa eval='mIoU', metric=dict(mIoU=78.57), @@ -68,7 +68,7 @@ ] fastscnn = [ dict( - config='configs/fastscnn/fast_scnn_lr0.12_8x4_160k_cityscapes.py', + config='configs/fastscnn/fast_scnn_8xb4-160k_cityscapes-512x1024.py', checkpoint='fast_scnn_8x4_160k_lr0.12_cityscapes-0cec9937.pth', eval='mIoU', metric=dict(mIoU=70.96), @@ -76,25 +76,25 @@ ] deeplabv3plus = [ dict( - config='configs/deeplabv3plus/deeplabv3plus_r101-d8_769x769_80k_cityscapes.py', # noqa + config='configs/deeplabv3plus/deeplabv3plus_r101-d8_4xb2-80k_cityscapes-769x769.py', # noqa checkpoint='deeplabv3plus_r101-d8_769x769_80k_cityscapes_20200607_000405-a7573d20.pth', # noqa eval='mIoU', metric=dict(mIoU=80.98), ), dict( - config='configs/deeplabv3plus/deeplabv3plus_r101-d8_512x1024_80k_cityscapes.py', # noqa + config='configs/deeplabv3plus/deeplabv3plus_r101-d8_4xb2-80k_cityscapes-512x1024.py', # noqa checkpoint='deeplabv3plus_r101-d8_512x1024_80k_cityscapes_20200606_114143-068fcfe9.pth', # noqa eval='mIoU', metric=dict(mIoU=80.97), ), dict( - config='configs/deeplabv3plus/deeplabv3plus_r50-d8_512x1024_80k_cityscapes.py', # noqa + config='configs/deeplabv3plus/deeplabv3plus_r50-d8_4xb2-80k_cityscapes-512x1024.py', # noqa checkpoint='deeplabv3plus_r50-d8_512x1024_80k_cityscapes_20200606_114049-f9fb496d.pth', # noqa eval='mIoU', metric=dict(mIoU=80.09), ), dict( - config='configs/deeplabv3plus/deeplabv3plus_r50-d8_769x769_80k_cityscapes.py', # noqa + config='configs/deeplabv3plus/deeplabv3plus_r50-d8_4xb2-80k_cityscapes-769x769.py', # noqa checkpoint='deeplabv3plus_r50-d8_769x769_80k_cityscapes_20200606_210233-0e9dfdc4.pth', # noqa eval='mIoU', metric=dict(mIoU=79.83), @@ -102,13 +102,13 @@ ] vit = [ dict( - config='configs/vit/upernet_vit-b16_ln_mln_512x512_160k_ade20k.py', + config='configs/vit/vit_vit-b16-ln_mln_upernet_8xb2-160k_ade20k-512x512.py', # noqa checkpoint='upernet_vit-b16_ln_mln_512x512_160k_ade20k-f444c077.pth', eval='mIoU', metric=dict(mIoU=47.73), ), dict( - config='configs/vit/upernet_deit-s16_ln_mln_512x512_160k_ade20k.py', + config='configs/vit/vit_deit-s16-ln_mln_upernet_512x512_160k_ade20k-512x512.py', # noqa checkpoint='upernet_deit-s16_ln_mln_512x512_160k_ade20k-c0cd652f.pth', eval='mIoU', metric=dict(mIoU=43.52), @@ -116,7 +116,7 @@ ] fp16 = [ dict( - config='configs/deeplabv3plus/deeplabv3plus_r101-d8_fp16_512x1024_80k_cityscapes.py', # noqa + config='configs/deeplabv3plus/deeplabv3plus_r101-d8_4xb2-amp-80k_cityscapes-512x1024.py', # noqa checkpoint='deeplabv3plus_r101-d8_fp16_512x1024_80k_cityscapes_20200717_230920-f1104f4b.pth', # noqa eval='mIoU', metric=dict(mIoU=80.46), @@ -124,7 +124,7 @@ ] swin = [ dict( - config='configs/swin/upernet_swin_tiny_patch4_window7_512x512_160k_ade20k_pretrain_224x224_1K.py', # noqa + config='configs/swin/swin-tiny-patch4-window7-in1k-pre_upernet_8xb2-160k_ade20k-512x512.py', # noqa checkpoint='upernet_swin_tiny_patch4_window7_512x512_160k_ade20k_pretrain_224x224_1K_20210531_112542-e380ad3e.pth', # noqa eval='mIoU', metric=dict(mIoU=44.41), diff --git a/.dev/batch_train_list.txt b/.dev/batch_train_list.txt index 17d19932e6..6c1a122dc4 100644 --- a/.dev/batch_train_list.txt +++ b/.dev/batch_train_list.txt @@ -1,19 +1,19 @@ -configs/hrnet/fcn_hr18s_512x512_160k_ade20k.py -configs/hrnet/fcn_hr18s_512x1024_160k_cityscapes.py -configs/hrnet/fcn_hr48_512x512_160k_ade20k.py -configs/hrnet/fcn_hr48_512x1024_160k_cityscapes.py -configs/pspnet/pspnet_r50-d8_512x1024_80k_cityscapes.py -configs/pspnet/pspnet_r101-d8_512x1024_80k_cityscapes.py -configs/pspnet/pspnet_r101-d8_512x512_160k_ade20k.py -configs/pspnet/pspnet_r50-d8_512x512_160k_ade20k.py -configs/resnest/pspnet_s101-d8_512x512_160k_ade20k.py -configs/resnest/pspnet_s101-d8_512x1024_80k_cityscapes.py -configs/fastscnn/fast_scnn_lr0.12_8x4_160k_cityscapes.py -configs/deeplabv3plus/deeplabv3plus_r101-d8_769x769_80k_cityscapes.py -configs/deeplabv3plus/deeplabv3plus_r101-d8_512x1024_80k_cityscapes.py -configs/deeplabv3plus/deeplabv3plus_r50-d8_512x1024_80k_cityscapes.py -configs/deeplabv3plus/deeplabv3plus_r50-d8_769x769_80k_cityscapes.py -configs/vit/upernet_vit-b16_ln_mln_512x512_160k_ade20k.py -configs/vit/upernet_deit-s16_ln_mln_512x512_160k_ade20k.py -configs/deeplabv3plus/deeplabv3plus_r101-d8_fp16_512x1024_80k_cityscapes.py -configs/swin/upernet_swin_tiny_patch4_window7_512x512_160k_ade20k_pretrain_224x224_1K.py +configs/hrnet/fcn_hr18s_4xb4-160k_ade20k-512x512.py +configs/hrnet/fcn_hr18s_4xb2-160k_cityscapes-512x1024.py +configs/hrnet/fcn_hr48_4xb4-160k_ade20k-512x512.py +configs/hrnet/fcn_hr48_4xb2-160k_cityscapes-512x1024.py +configs/pspnet/pspnet_r50-d8_4xb2-80k_cityscapes-512x1024.py +configs/pspnet/pspnet_r101-d8_4xb2-80k_cityscapes-512x1024.py +configs/pspnet/pspnet_r101-d8_4xb4-160k_ade20k-512x512.py +configs/pspnet/pspnet_r50-d8_4xb4-160k_ade20k-512x512.py +configs/resnest/resnest_s101-d8_pspnet_4xb4-160k_ade20k-512x512.py +configs/resnest/resnest_s101-d8_pspnet_4xb2-80k_cityscapes512x1024.py +configs/fastscnn/fast_scnn_8xb4-160k_cityscapes-512x1024.py +configs/deeplabv3plus/deeplabv3plus_r101-d8_4xb2-80k_cityscapes-769x769.py +configs/deeplabv3plus/deeplabv3plus_r101-d8_4xb2-80k_cityscapes-512x1024.py +configs/deeplabv3plus/deeplabv3plus_r50-d8_4xb2-80k_cityscapes-512x1024.py +configs/deeplabv3plus/deeplabv3plus_r50-d8_4xb2-80k_cityscapes-769x769.py +configs/vit/vit_vit-b16-ln_mln_upernet_8xb2-160k_ade20k-512x512.py +configs/vit/vit_deit-s16-ln_mln_upernet_512x512_160k_ade20k-512x512.py +configs/deeplabv3plus/deeplabv3plus_r101-d8_4xb2-amp-80k_cityscapes-512x1024.py +configs/swin/swin-tiny-patch4-window7-in1k-pre_upernet_8xb2-160k_ade20k-512x512.py diff --git a/README.md b/README.md index 308fca8716..9b4a580f39 100644 --- a/README.md +++ b/README.md @@ -17,8 +17,6 @@
 
- -
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/mmsegmentation)](https://pypi.org/project/mmsegmentation/) [![PyPI](https://img.shields.io/pypi/v/mmsegmentation)](https://pypi.org/project/mmsegmentation) @@ -33,6 +31,22 @@ Documentation: English | [简体中文](README_zh-CN.md) + + +
+ + + + + + + + + + + +
+ ## Introduction MMSegmentation is an open source semantic segmentation toolbox based on PyTorch. @@ -62,11 +76,11 @@ The 1.x branch works with **PyTorch 1.6+**. ## What's New -v1.0.0rc5 was released on 01/02/2023. +v1.0.0rc6 was released on 03/03/2023. Please refer to [changelog.md](docs/en/notes/changelog.md) for details and release history. -- Support ISNet (ICCV'2021) in projects ([#2400](https://github.com/open-mmlab/mmsegmentation/pull/2400)) -- Support HSSN (CVPR'2022) in projects ([#2444](https://github.com/open-mmlab/mmsegmentation/pull/2444)) +- Support MMSegInferencer ([#2413](https://github.com/open-mmlab/mmsegmentation/pull/2413), [#2658](https://github.com/open-mmlab/mmsegmentation/pull/2658)) +- Support REFUGE dataset ([#2554](https://github.com/open-mmlab/mmsegmentation/pull/2554)) ## Installation @@ -81,13 +95,14 @@ There are also [advanced tutorials](https://mmsegmentation.readthedocs.io/en/dev A Colab tutorial is also provided. You may preview the notebook [here](demo/MMSegmentation_Tutorial.ipynb) or directly [run](https://colab.research.google.com/github/open-mmlab/mmsegmentation/blob/1.x/demo/MMSegmentation_Tutorial.ipynb) on Colab. -To migrate from MMSegmentation 1.x, please refer to [migration](docs/en/migration.md). +To migrate from MMSegmentation 1.x, please refer to [migration](docs/en/migration). ## Benchmark and model zoo Results and models are available in the [model zoo](docs/en/model_zoo.md). -Supported backbones: +
+Supported backbones: - [x] ResNet (CVPR'2016) - [x] ResNeXt (CVPR'2017) @@ -103,7 +118,10 @@ Supported backbones: - [x] [MAE (CVPR'2022)](configs/mae) - [x] [PoolFormer (CVPR'2022)](configs/poolformer) -Supported methods: +
+ +
+Supported methods: - [x] [FCN (CVPR'2015/TPAMI'2017)](configs/fcn) - [x] [ERFNet (T-ITS'2017)](configs/erfnet) @@ -142,7 +160,10 @@ Supported methods: - [x] [MaskFormer (NeurIPS'2021)](configs/maskformer) - [x] [Mask2Former (CVPR'2022)](configs/mask2former) -Supported datasets: +
+ +
+Supported datasets: - [x] [Cityscapes](https://github.com/open-mmlab/mmsegmentation/blob/1.x/docs/en/user_guides/2_dataset_prepare.md#cityscapes) - [x] [PASCAL VOC](https://github.com/open-mmlab/mmsegmentation/blob/1.x/docs/en/user_guides/2_dataset_prepare.md#pascal-voc) @@ -161,8 +182,14 @@ Supported datasets: - [x] [Vaihingen](https://github.com/open-mmlab/mmsegmentation/blob/1.x/docs/en/user_guides/2_dataset_prepare.md#isprs-vaihingen) - [x] [iSAID](https://github.com/open-mmlab/mmsegmentation/blob/1.x/docs/en/user_guides/2_dataset_prepare.md#isaid) +
+ Please refer to [FAQ](docs/en/notes/faq.md) for frequently asked questions. +## Projects + +[Here](projects/README.md) are some implementations of SOTA models and solutions built on MMSegmentation, which are supported and maintained by community users. These projects demonstrate the best practices based on MMSegmentation for research and product development. We welcome and appreciate all the contributions to OpenMMLab ecosystem. + ## Contributing We appreciate all contributions to improve MMSegmentation. Please refer to [CONTRIBUTING.md](.github/CONTRIBUTING.md) for the contributing guideline. @@ -191,7 +218,7 @@ If you find this project useful in your research, please consider cite: This project is released under the [Apache 2.0 license](LICENSE). -## Projects in OpenMMLab +## OpenMMLab Family - [MMEngine](https://github.com/open-mmlab/mmengine): OpenMMLab foundational library for training deep learning models - [MMCV](https://github.com/open-mmlab/mmcv): OpenMMLab foundational library for computer vision. diff --git a/README_zh-CN.md b/README_zh-CN.md index 8db2746413..858485fd54 100644 --- a/README_zh-CN.md +++ b/README_zh-CN.md @@ -61,7 +61,7 @@ MMSegmentation 是一个基于 PyTorch 的语义分割开源工具箱。它是 O ## 更新日志 -最新版本 v1.0.0rc5 在 2023.02.01 发布。 +最新版本 v1.0.0rc6 在 2023.03.03 发布。 如果想了解更多版本更新细节和历史信息,请阅读[更新日志](docs/en/notes/changelog.md)。 ## 安装 @@ -82,7 +82,8 @@ MMSegmentation 是一个基于 PyTorch 的语义分割开源工具箱。它是 O 测试结果和模型可以在[模型库](docs/zh_cn/model_zoo.md)中找到。 -已支持的骨干网络: +
+已支持的骨干网络: - [x] ResNet (CVPR'2016) - [x] ResNeXt (CVPR'2017) @@ -98,7 +99,10 @@ MMSegmentation 是一个基于 PyTorch 的语义分割开源工具箱。它是 O - [x] [MAE (CVPR'2022)](configs/mae) - [x] [PoolFormer (CVPR'2022)](configs/poolformer) -已支持的算法: +
+ +
+已支持的算法: - [x] [FCN (CVPR'2015/TPAMI'2017)](configs/fcn) - [x] [ERFNet (T-ITS'2017)](configs/erfnet) @@ -137,7 +141,10 @@ MMSegmentation 是一个基于 PyTorch 的语义分割开源工具箱。它是 O - [x] [MaskFormer (NeurIPS'2021)](configs/maskformer) - [x] [Mask2Former (CVPR'2022)](configs/mask2former) -已支持的数据集: +
+ +
+已支持的数据集: - [x] [Cityscapes](https://github.com/open-mmlab/mmsegmentation/blob/1.x/docs/zh_cn/dataset_prepare.md#cityscapes) - [x] [PASCAL VOC](https://github.com/open-mmlab/mmsegmentation/blob/1.x/docs/zh_cn/dataset_prepare.md#pascal-voc) @@ -156,15 +163,22 @@ MMSegmentation 是一个基于 PyTorch 的语义分割开源工具箱。它是 O - [x] [Vaihingen](https://github.com/open-mmlab/mmsegmentation/blob/1.x/docs/zh_cn/dataset_prepare.md#isprs-vaihingen) - [x] [iSAID](https://github.com/open-mmlab/mmsegmentation/blob/1.x/docs/zh_cn/dataset_prepare.md#isaid) +
+ 如果遇到问题,请参考 [常见问题解答](docs/zh_cn/notes/faq.md)。 +## 社区项目 + +[这里](projects/README.md)有一些由社区用户支持和维护的基于 MMSegmentation 的 SOTA 模型和解决方案的实现。这些项目展示了基于 MMSegmentation 的研究和产品开发的最佳实践。 +我们欢迎并感谢对 OpenMMLab 生态系统的所有贡献。 + ## 贡献指南 我们感谢所有的贡献者为改进和提升 MMSegmentation 所作出的努力。请参考[贡献指南](.github/CONTRIBUTING.md)来了解参与项目贡献的相关指引。 ## 致谢 -MMSegmentation 是一个由来自不同高校和企业的研发人员共同参与贡献的开源项目。我们感谢所有为项目提供算法复现和新功能支持的贡献者,以及提供宝贵反馈的用户。 我们希望这个工具箱和基准测试可以为社区提供灵活的代码工具,供用户复现已有算法并开发自己的新模型,从而不断为开源社区提供贡献。 +MMSegmentation 是一个由来自不同高校和企业的研发人员共同参与贡献的开源项目。我们感谢所有为项目提供算法复现和新功能支持的贡献者,以及提供宝贵反馈的用户。我们希望这个工具箱和基准测试可以为社区提供灵活的代码工具,供用户复现已有算法并开发自己的新模型,从而不断为开源社区提供贡献。 ## 引用 diff --git a/configs/_base_/datasets/ade20k.py b/configs/_base_/datasets/ade20k.py index 2c01b2ff59..48340d11ee 100644 --- a/configs/_base_/datasets/ade20k.py +++ b/configs/_base_/datasets/ade20k.py @@ -25,7 +25,7 @@ ] img_ratios = [0.5, 0.75, 1.0, 1.25, 1.5, 1.75] tta_pipeline = [ - dict(type='LoadImageFromFile', backend_args=dict(backend='local')), + dict(type='LoadImageFromFile', backend_args=None), dict( type='TestTimeAug', transforms=[ diff --git a/configs/_base_/datasets/ade20k_640x640.py b/configs/_base_/datasets/ade20k_640x640.py index 866403b27f..c1f642da7f 100644 --- a/configs/_base_/datasets/ade20k_640x640.py +++ b/configs/_base_/datasets/ade20k_640x640.py @@ -25,7 +25,7 @@ ] img_ratios = [0.5, 0.75, 1.0, 1.25, 1.5, 1.75] tta_pipeline = [ - dict(type='LoadImageFromFile', backend_args=dict(backend='local')), + dict(type='LoadImageFromFile', backend_args=None), dict( type='TestTimeAug', transforms=[ diff --git a/configs/_base_/datasets/chase_db1.py b/configs/_base_/datasets/chase_db1.py index 62dd3b3cbe..ed47c2dbe5 100644 --- a/configs/_base_/datasets/chase_db1.py +++ b/configs/_base_/datasets/chase_db1.py @@ -26,7 +26,7 @@ ] img_ratios = [0.5, 0.75, 1.0, 1.25, 1.5, 1.75] tta_pipeline = [ - dict(type='LoadImageFromFile', backend_args=dict(backend='local')), + dict(type='LoadImageFromFile', backend_args=None), dict( type='TestTimeAug', transforms=[ diff --git a/configs/_base_/datasets/cityscapes.py b/configs/_base_/datasets/cityscapes.py index b7d95c1ec0..b63a4cdfe7 100644 --- a/configs/_base_/datasets/cityscapes.py +++ b/configs/_base_/datasets/cityscapes.py @@ -25,7 +25,7 @@ ] img_ratios = [0.5, 0.75, 1.0, 1.25, 1.5, 1.75] tta_pipeline = [ - dict(type='LoadImageFromFile', backend_args=dict(backend='local')), + dict(type='LoadImageFromFile', backend_args=None), dict( type='TestTimeAug', transforms=[ diff --git a/configs/_base_/datasets/coco-stuff10k.py b/configs/_base_/datasets/coco-stuff10k.py index 9d3026bd4c..5d6bb12b97 100644 --- a/configs/_base_/datasets/coco-stuff10k.py +++ b/configs/_base_/datasets/coco-stuff10k.py @@ -25,7 +25,7 @@ ] img_ratios = [0.5, 0.75, 1.0, 1.25, 1.5, 1.75] tta_pipeline = [ - dict(type='LoadImageFromFile', backend_args=dict(backend='local')), + dict(type='LoadImageFromFile', backend_args=None), dict( type='TestTimeAug', transforms=[ diff --git a/configs/_base_/datasets/coco-stuff164k.py b/configs/_base_/datasets/coco-stuff164k.py index c785e313ff..baf633f9d6 100644 --- a/configs/_base_/datasets/coco-stuff164k.py +++ b/configs/_base_/datasets/coco-stuff164k.py @@ -25,7 +25,7 @@ ] img_ratios = [0.5, 0.75, 1.0, 1.25, 1.5, 1.75] tta_pipeline = [ - dict(type='LoadImageFromFile', backend_args=dict(backend='local')), + dict(type='LoadImageFromFile', backend_args=None), dict( type='TestTimeAug', transforms=[ diff --git a/configs/_base_/datasets/drive.py b/configs/_base_/datasets/drive.py index 3bd6080aa7..6a3dd82c64 100644 --- a/configs/_base_/datasets/drive.py +++ b/configs/_base_/datasets/drive.py @@ -26,7 +26,7 @@ ] img_ratios = [0.5, 0.75, 1.0, 1.25, 1.5, 1.75] tta_pipeline = [ - dict(type='LoadImageFromFile', backend_args=dict(backend='local')), + dict(type='LoadImageFromFile', backend_args=None), dict( type='TestTimeAug', transforms=[ diff --git a/configs/_base_/datasets/hrf.py b/configs/_base_/datasets/hrf.py index b0ae34abe6..353d070472 100644 --- a/configs/_base_/datasets/hrf.py +++ b/configs/_base_/datasets/hrf.py @@ -26,7 +26,7 @@ ] img_ratios = [0.5, 0.75, 1.0, 1.25, 1.5, 1.75] tta_pipeline = [ - dict(type='LoadImageFromFile', backend_args=dict(backend='local')), + dict(type='LoadImageFromFile', backend_args=None), dict( type='TestTimeAug', transforms=[ diff --git a/configs/_base_/datasets/isaid.py b/configs/_base_/datasets/isaid.py index 8407e06ac9..5cd4309f6d 100644 --- a/configs/_base_/datasets/isaid.py +++ b/configs/_base_/datasets/isaid.py @@ -32,7 +32,7 @@ ] img_ratios = [0.5, 0.75, 1.0, 1.25, 1.5, 1.75] tta_pipeline = [ - dict(type='LoadImageFromFile', backend_args=dict(backend='local')), + dict(type='LoadImageFromFile', backend_args=None), dict( type='TestTimeAug', transforms=[ diff --git a/configs/_base_/datasets/loveda.py b/configs/_base_/datasets/loveda.py index 8ecc919654..b93bc74af1 100644 --- a/configs/_base_/datasets/loveda.py +++ b/configs/_base_/datasets/loveda.py @@ -25,7 +25,7 @@ ] img_ratios = [0.5, 0.75, 1.0, 1.25, 1.5, 1.75] tta_pipeline = [ - dict(type='LoadImageFromFile', backend_args=dict(backend='local')), + dict(type='LoadImageFromFile', backend_args=None), dict( type='TestTimeAug', transforms=[ diff --git a/configs/_base_/datasets/pascal_context_59.py b/configs/_base_/datasets/pascal_context_59.py index bb144dd202..7f31043ed0 100644 --- a/configs/_base_/datasets/pascal_context_59.py +++ b/configs/_base_/datasets/pascal_context_59.py @@ -28,7 +28,7 @@ ] img_ratios = [0.5, 0.75, 1.0, 1.25, 1.5, 1.75] tta_pipeline = [ - dict(type='LoadImageFromFile', backend_args=dict(backend='local')), + dict(type='LoadImageFromFile', backend_args=None), dict( type='TestTimeAug', transforms=[ diff --git a/configs/_base_/datasets/pascal_voc12.py b/configs/_base_/datasets/pascal_voc12.py index 0fa3d55764..5235ca9cfe 100644 --- a/configs/_base_/datasets/pascal_voc12.py +++ b/configs/_base_/datasets/pascal_voc12.py @@ -25,7 +25,7 @@ ] img_ratios = [0.5, 0.75, 1.0, 1.25, 1.5, 1.75] tta_pipeline = [ - dict(type='LoadImageFromFile', backend_args=dict(backend='local')), + dict(type='LoadImageFromFile', backend_args=None), dict( type='TestTimeAug', transforms=[ diff --git a/configs/_base_/datasets/pascal_voc12_aug.py b/configs/_base_/datasets/pascal_voc12_aug.py index 8b358cc0cd..69c3654880 100644 --- a/configs/_base_/datasets/pascal_voc12_aug.py +++ b/configs/_base_/datasets/pascal_voc12_aug.py @@ -27,7 +27,7 @@ ] img_ratios = [0.5, 0.75, 1.0, 1.25, 1.5, 1.75] tta_pipeline = [ - dict(type='LoadImageFromFile', backend_args=dict(backend='local')), + dict(type='LoadImageFromFile', backend_args=None), dict( type='TestTimeAug', transforms=[ diff --git a/configs/_base_/datasets/potsdam.py b/configs/_base_/datasets/potsdam.py index 4439f41919..95f6039351 100644 --- a/configs/_base_/datasets/potsdam.py +++ b/configs/_base_/datasets/potsdam.py @@ -25,7 +25,7 @@ ] img_ratios = [0.5, 0.75, 1.0, 1.25, 1.5, 1.75] tta_pipeline = [ - dict(type='LoadImageFromFile', backend_args=dict(backend='local')), + dict(type='LoadImageFromFile', backend_args=None), dict( type='TestTimeAug', transforms=[ diff --git a/configs/_base_/datasets/refuge.py b/configs/_base_/datasets/refuge.py new file mode 100644 index 0000000000..79bb4d4e94 --- /dev/null +++ b/configs/_base_/datasets/refuge.py @@ -0,0 +1,90 @@ +# dataset settings +dataset_type = 'REFUGEDataset' +data_root = 'data/REFUGE' +train_img_scale = (2056, 2124) +val_img_scale = (1634, 1634) +test_img_scale = (1634, 1634) +crop_size = (512, 512) + +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', reduce_zero_label=False), + dict( + type='RandomResize', + scale=train_img_scale, + ratio_range=(0.5, 2.0), + keep_ratio=True), + dict(type='RandomCrop', crop_size=crop_size, cat_max_ratio=0.75), + dict(type='RandomFlip', prob=0.5), + dict(type='PhotoMetricDistortion'), + dict(type='PackSegInputs') +] +val_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='Resize', scale=val_img_scale, keep_ratio=True), + # add loading annotation after ``Resize`` because ground truth + # does not need to do resize data transform + dict(type='LoadAnnotations', reduce_zero_label=False), + dict(type='PackSegInputs') +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='Resize', scale=test_img_scale, keep_ratio=True), + # add loading annotation after ``Resize`` because ground truth + # does not need to do resize data transform + dict(type='LoadAnnotations', reduce_zero_label=False), + dict(type='PackSegInputs') +] +img_ratios = [0.5, 0.75, 1.0, 1.25, 1.5, 1.75] +tta_pipeline = [ + dict(type='LoadImageFromFile', backend_args=dict(backend='local')), + dict( + type='TestTimeAug', + transforms=[ + [ + dict(type='Resize', scale_factor=r, keep_ratio=True) + for r in img_ratios + ], + [ + dict(type='RandomFlip', prob=0., direction='horizontal'), + dict(type='RandomFlip', prob=1., direction='horizontal') + ], [dict(type='LoadAnnotations')], [dict(type='PackSegInputs')] + ]) +] +train_dataloader = dict( + batch_size=4, + num_workers=4, + persistent_workers=True, + sampler=dict(type='InfiniteSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_prefix=dict( + img_path='images/training', seg_map_path='annotations/training'), + pipeline=train_pipeline)) +val_dataloader = dict( + batch_size=1, + num_workers=4, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_prefix=dict( + img_path='images/validation', + seg_map_path='annotations/validation'), + pipeline=val_pipeline)) +test_dataloader = dict( + batch_size=1, + num_workers=4, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_prefix=dict( + img_path='images/test', seg_map_path='annotations/test'), + pipeline=val_pipeline)) + +val_evaluator = dict(type='IoUMetric', iou_metrics=['mDice']) +test_evaluator = val_evaluator diff --git a/configs/_base_/datasets/stare.py b/configs/_base_/datasets/stare.py index e55519b595..b7545dc623 100644 --- a/configs/_base_/datasets/stare.py +++ b/configs/_base_/datasets/stare.py @@ -26,7 +26,7 @@ ] img_ratios = [0.5, 0.75, 1.0, 1.25, 1.5, 1.75] tta_pipeline = [ - dict(type='LoadImageFromFile', backend_args=dict(backend='local')), + dict(type='LoadImageFromFile', backend_args=None), dict( type='TestTimeAug', transforms=[ diff --git a/configs/_base_/datasets/vaihingen.py b/configs/_base_/datasets/vaihingen.py index 2b3fa76093..6c78994fe7 100644 --- a/configs/_base_/datasets/vaihingen.py +++ b/configs/_base_/datasets/vaihingen.py @@ -25,7 +25,7 @@ ] img_ratios = [0.5, 0.75, 1.0, 1.25, 1.5, 1.75] tta_pipeline = [ - dict(type='LoadImageFromFile', backend_args=dict(backend='local')), + dict(type='LoadImageFromFile', backend_args=None), dict( type='TestTimeAug', transforms=[ diff --git a/configs/_base_/models/fpn_poolformer_s12.py b/configs/_base_/models/fpn_poolformer_s12.py index 483d823308..b6893f6977 100644 --- a/configs/_base_/models/fpn_poolformer_s12.py +++ b/configs/_base_/models/fpn_poolformer_s12.py @@ -1,7 +1,10 @@ # model settings norm_cfg = dict(type='SyncBN', requires_grad=True) checkpoint_file = 'https://download.openmmlab.com/mmclassification/v0/poolformer/poolformer-s12_3rdparty_32xb128_in1k_20220414-f8d83051.pth' # noqa -custom_imports = dict(imports='mmcls.models', allow_failed_imports=False) +# TODO: delete custom_imports after mmcls supports auto import +# please install mmcls>=1.0 +# import mmcls.models to trigger register_module in mmcls +custom_imports = dict(imports=['mmcls.models'], allow_failed_imports=False) data_preprocessor = dict( type='SegDataPreProcessor', mean=[123.675, 116.28, 103.53], diff --git a/configs/mask2former/mask2former_r50_8xb2-90k_cityscapes-512x1024.py b/configs/mask2former/mask2former_r50_8xb2-90k_cityscapes-512x1024.py index fc132a698f..d2211b66a3 100644 --- a/configs/mask2former/mask2former_r50_8xb2-90k_cityscapes-512x1024.py +++ b/configs/mask2former/mask2former_r50_8xb2-90k_cityscapes-512x1024.py @@ -1,7 +1,5 @@ _base_ = ['../_base_/default_runtime.py', '../_base_/datasets/cityscapes.py'] -custom_imports = dict(imports='mmdet.models', allow_failed_imports=False) - crop_size = (512, 1024) data_preprocessor = dict( type='SegDataPreProcessor', diff --git a/configs/mask2former/mask2former_swin-b-in1k-384x384-pre_8xb2-160k_ade20k-640x640.py b/configs/mask2former/mask2former_swin-b-in1k-384x384-pre_8xb2-160k_ade20k-640x640.py index 4e4036db3a..b8b1d6cfff 100644 --- a/configs/mask2former/mask2former_swin-b-in1k-384x384-pre_8xb2-160k_ade20k-640x640.py +++ b/configs/mask2former/mask2former_swin-b-in1k-384x384-pre_8xb2-160k_ade20k-640x640.py @@ -3,7 +3,6 @@ ] pretrained = 'https://download.openmmlab.com/mmsegmentation/v0.5/pretrain/swin/swin_base_patch4_window12_384_20220317-55b0104a.pth' # noqa -custom_imports = dict(imports='mmdet.models', allow_failed_imports=False) crop_size = (640, 640) data_preprocessor = dict( diff --git a/configs/mobilenet_v2/README.md b/configs/mobilenet_v2/README.md index c1010044a9..30f1fe3ce2 100644 --- a/configs/mobilenet_v2/README.md +++ b/configs/mobilenet_v2/README.md @@ -39,12 +39,12 @@ The MobileNetV2 architecture is based on an inverted residual structure where th ### Cityscapes -| Method | Backbone | Crop Size | Lr schd | Mem (GB) | Inf time (fps) | mIoU | mIoU(ms+flip) | config | download | -| ---------- | -------- | --------- | ------: | -------: | -------------- | ----: | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| FCN | M-V2-D8 | 512x1024 | 80000 | 3.4 | 14.2 | 61.54 | - | [config](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/configs/mobilenet_v2/mobilenet-v2-d8_fcn_4xb2-80k_cityscapes-512x1024.py) | [model](https://download.openmmlab.com/mmsegmentation/v0.5/mobilenet_v2/fcn_m-v2-d8_512x1024_80k_cityscapes/fcn_m-v2-d8_512x1024_80k_cityscapes_20200825_124817-d24c28c1.pth) \| [log](https://download.openmmlab.com/mmsegmentation/v0.5/mobilenet_v2/fcn_m-v2-d8_512x1024_80k_cityscapes/fcn_m-v2-d8_512x1024_80k_cityscapes-20200825_124817.log.json) | -| PSPNet | M-V2-D8 | 512x1024 | 80000 | 3.6 | 11.2 | 70.23 | - | [config](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/configs/mobilenet_v2/mobilenet-v2-d8_pspnet_4xb2-80k_cityscapes-512x1024.py) | [model](https://download.openmmlab.com/mmsegmentation/v0.5/mobilenet_v2/pspnet_m-v2-d8_512x1024_80k_cityscapes/pspnet_m-v2-d8_512x1024_80k_cityscapes_20200825_124817-19e81d51.pth) \| [log](https://download.openmmlab.com/mmsegmentation/v0.5/mobilenet_v2/pspnet_m-v2-d8_512x1024_80k_cityscapes/pspnet_m-v2-d8_512x1024_80k_cityscapes-20200825_124817.log.json) | -| DeepLabV3 | M-V2-D8 | 512x1024 | 80000 | 3.9 | 8.4 | 73.84 | - | [config](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/configs/mobilenet_v2/mobilenet-v2-d8_deeplabv3_4xb2-80k_cityscapes-512x1024.py) | [model](https://download.openmmlab.com/mmsegmentation/v0.5/mobilenet_v2/deeplabv3_m-v2-d8_512x1024_80k_cityscapes/deeplabv3_m-v2-d8_512x1024_80k_cityscapes_20200825_124836-bef03590.pth) \| [log](https://download.openmmlab.com/mmsegmentation/v0.5/mobilenet_v2/deeplabv3_m-v2-d8_512x1024_80k_cityscapes/deeplabv3_m-v2-d8_512x1024_80k_cityscapes-20200825_124836.log.json) | -| DeepLabV3+ | M-V2-D8 | 512x1024 | 80000 | 5.1 | 8.4 | 75.20 | - | [config](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/configs/mobilenet_v2/mobilenet-v2-d8_deeplabv3plus_4xb2-80k_cityscapes-512x1024.py) | [model](https://download.openmmlab.com/mmsegmentation/v0.5/mobilenet_v2/deeplabv3plus_m-v2-d8_512x1024_80k_cityscapes/deeplabv3plus_m-v2-d8_512x1024_80k_cityscapes_20200825_124836-d256dd4b.pth) \| [log](https://download.openmmlab.com/mmsegmentation/v0.5/mobilenet_v2/deeplabv3plus_m-v2-d8_512x1024_80k_cityscapes/deeplabv3plus_m-v2-d8_512x1024_80k_cityscapes-20200825_124836.log.json) | +| Method | Backbone | Crop Size | Lr schd | Mem (GB) | Inf time (fps) | mIoU | mIoU(ms+flip) | config | download | +| ---------- | -------- | --------- | ------: | -------: | -------------- | ----: | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| FCN | M-V2-D8 | 512x1024 | 80000 | 3.4 | 14.2 | 71.19 | 73.34 | [config](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/configs/mobilenet_v2/mobilenet-v2-d8_fcn_4xb2-80k_cityscapes-512x1024.py) | [model](https://download.openmmlab.com/mmsegmentation/v0.5/mobilenet_v2/mobilenet-v2-d8_fcn_4xb2-80k_cityscapes-512x1024/mobilenet-v2-d8_fcn_4xb2-80k_cityscapes-512x1024-20230224_185436-13fef4ea.pth) \| [log](https://download.openmmlab.com/mmsegmentation/v0.5/mobilenet_v2/mobilenet-v2-d8_fcn_4xb2-80k_cityscapes-512x1024/mobilenet-v2-d8_fcn_4xb2-80k_cityscapes-512x1024_20230224_185436.json) | +| PSPNet | M-V2-D8 | 512x1024 | 80000 | 3.6 | 11.2 | 70.23 | - | [config](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/configs/mobilenet_v2/mobilenet-v2-d8_pspnet_4xb2-80k_cityscapes-512x1024.py) | [model](https://download.openmmlab.com/mmsegmentation/v0.5/mobilenet_v2/pspnet_m-v2-d8_512x1024_80k_cityscapes/pspnet_m-v2-d8_512x1024_80k_cityscapes_20200825_124817-19e81d51.pth) \| [log](https://download.openmmlab.com/mmsegmentation/v0.5/mobilenet_v2/pspnet_m-v2-d8_512x1024_80k_cityscapes/pspnet_m-v2-d8_512x1024_80k_cityscapes-20200825_124817.log.json) | +| DeepLabV3 | M-V2-D8 | 512x1024 | 80000 | 3.9 | 8.4 | 73.84 | - | [config](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/configs/mobilenet_v2/mobilenet-v2-d8_deeplabv3_4xb2-80k_cityscapes-512x1024.py) | [model](https://download.openmmlab.com/mmsegmentation/v0.5/mobilenet_v2/deeplabv3_m-v2-d8_512x1024_80k_cityscapes/deeplabv3_m-v2-d8_512x1024_80k_cityscapes_20200825_124836-bef03590.pth) \| [log](https://download.openmmlab.com/mmsegmentation/v0.5/mobilenet_v2/deeplabv3_m-v2-d8_512x1024_80k_cityscapes/deeplabv3_m-v2-d8_512x1024_80k_cityscapes-20200825_124836.log.json) | +| DeepLabV3+ | M-V2-D8 | 512x1024 | 80000 | 5.1 | 8.4 | 75.20 | - | [config](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/configs/mobilenet_v2/mobilenet-v2-d8_deeplabv3plus_4xb2-80k_cityscapes-512x1024.py) | [model](https://download.openmmlab.com/mmsegmentation/v0.5/mobilenet_v2/deeplabv3plus_m-v2-d8_512x1024_80k_cityscapes/deeplabv3plus_m-v2-d8_512x1024_80k_cityscapes_20200825_124836-d256dd4b.pth) \| [log](https://download.openmmlab.com/mmsegmentation/v0.5/mobilenet_v2/deeplabv3plus_m-v2-d8_512x1024_80k_cityscapes/deeplabv3plus_m-v2-d8_512x1024_80k_cityscapes-20200825_124836.log.json) | ### ADE20K diff --git a/configs/mobilenet_v2/mobilenet_v2.yml b/configs/mobilenet_v2/mobilenet_v2.yml index 69d73d568a..6d87401ce8 100644 --- a/configs/mobilenet_v2/mobilenet_v2.yml +++ b/configs/mobilenet_v2/mobilenet_v2.yml @@ -17,9 +17,10 @@ Models: - Task: Semantic Segmentation Dataset: Cityscapes Metrics: - mIoU: 61.54 + mIoU: 71.19 + mIoU(ms+flip): 73.34 Config: configs/mobilenet_v2/mobilenet-v2-d8_fcn_4xb2-80k_cityscapes-512x1024.py - Weights: https://download.openmmlab.com/mmsegmentation/v0.5/mobilenet_v2/fcn_m-v2-d8_512x1024_80k_cityscapes/fcn_m-v2-d8_512x1024_80k_cityscapes_20200825_124817-d24c28c1.pth + Weights: https://download.openmmlab.com/mmsegmentation/v0.5/mobilenet_v2/mobilenet-v2-d8_fcn_4xb2-80k_cityscapes-512x1024/mobilenet-v2-d8_fcn_4xb2-80k_cityscapes-512x1024-20230224_185436-13fef4ea.pth - Name: mobilenet-v2-d8_pspnet_4xb2-80k_cityscapes-512x1024 In Collection: PSPNet Metadata: diff --git a/configs/ocrnet/README.md b/configs/ocrnet/README.md index 5cbfbabfce..4bd9c7d0b0 100644 --- a/configs/ocrnet/README.md +++ b/configs/ocrnet/README.md @@ -46,17 +46,17 @@ In this paper, we address the problem of semantic segmentation and focus on the #### HRNet backbone -| Method | Backbone | Crop Size | Lr schd | Mem (GB) | Inf time (fps) | mIoU | mIoU(ms+flip) | config | download | -| ------ | ------------------ | --------- | ------: | -------- | -------------- | ----: | ------------: | -------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| OCRNet | HRNetV2p-W18-Small | 512x1024 | 40000 | 3.5 | 10.45 | 74.30 | 75.95 | [config](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/configs/ocrnet/ocrnet_hr18s_4xb2-40k_cityscapes-512x1024.py) | [model](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr18s_512x1024_40k_cityscapes/ocrnet_hr18s_512x1024_40k_cityscapes_20200601_033304-fa2436c2.pth) \| [log](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr18s_512x1024_40k_cityscapes/ocrnet_hr18s_512x1024_40k_cityscapes_20200601_033304.log.json) | -| OCRNet | HRNetV2p-W18 | 512x1024 | 40000 | 4.7 | 7.50 | 77.72 | 79.49 | [config](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/configs/ocrnet/ocrnet_hr18_4xb2-40k_cityscapes-512x1024.py) | [model](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr18_512x1024_40k_cityscapes/ocrnet_hr18_512x1024_40k_cityscapes_20200601_033320-401c5bdd.pth) \| [log](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr18_512x1024_40k_cityscapes/ocrnet_hr18_512x1024_40k_cityscapes_20200601_033320.log.json) | -| OCRNet | HRNetV2p-W48 | 512x1024 | 40000 | 8 | 4.22 | 80.58 | 81.79 | [config](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/configs/ocrnet/ocrnet_hr48_4xb2-40k_cityscapes-512x1024.pyy) | [model](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr48_512x1024_40k_cityscapes/ocrnet_hr48_512x1024_40k_cityscapes_20200601_033336-55b32491.pth) \| [log](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr48_512x1024_40k_cityscapes/ocrnet_hr48_512x1024_40k_cityscapes_20200601_033336.log.json) | -| OCRNet | HRNetV2p-W18-Small | 512x1024 | 80000 | - | - | 77.16 | 78.66 | [config](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/configs/ocrnet/ocrnet_hr18s_4xb2-80k_cityscapes-512x1024.py) | [model](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr18s_512x1024_80k_cityscapes/ocrnet_hr18s_512x1024_80k_cityscapes_20200601_222735-55979e63.pth) \| [log](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr18s_512x1024_80k_cityscapes/ocrnet_hr18s_512x1024_80k_cityscapes_20200601_222735.log.json) | -| OCRNet | HRNetV2p-W18 | 512x1024 | 80000 | - | - | 78.57 | 80.46 | [config](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/configs/ocrnet/ocrnet_hr18_4xb2-80k_cityscapes-512x1024.py) | [model](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr18_512x1024_80k_cityscapes/ocrnet_hr18_512x1024_80k_cityscapes_20200614_230521-c2e1dd4a.pth) \| [log](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr18_512x1024_80k_cityscapes/ocrnet_hr18_512x1024_80k_cityscapes_20200614_230521.log.json) | -| OCRNet | HRNetV2p-W48 | 512x1024 | 80000 | - | - | 80.70 | 81.87 | [config](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/configs/ocrnet/ocrnet_hr48_4xb2-80k_cityscapes-512x1024.py) | [model](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr48_512x1024_80k_cityscapes/ocrnet_hr48_512x1024_80k_cityscapes_20200601_222752-9076bcdf.pth) \| [log](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr48_512x1024_80k_cityscapes/ocrnet_hr48_512x1024_80k_cityscapes_20200601_222752.log.json) | -| OCRNet | HRNetV2p-W18-Small | 512x1024 | 160000 | - | - | 78.45 | 79.97 | [config](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/configs/ocrnet/ocrnet_hr18s_4xb2-160k_cityscapes-512x1024.py) | [model](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr18s_512x1024_160k_cityscapes/ocrnet_hr18s_512x1024_160k_cityscapes_20200602_191005-f4a7af28.pth) \| [log](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr18s_512x1024_160k_cityscapes/ocrnet_hr18s_512x1024_160k_cityscapes_20200602_191005.log.json) | -| OCRNet | HRNetV2p-W18 | 512x1024 | 160000 | - | - | 79.47 | 80.91 | [config](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/configs/ocrnet/ocrnet_hr18_4xb2-160k_cityscapes-512x1024.py) | [model](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr18_512x1024_160k_cityscapes/ocrnet_hr18_512x1024_160k_cityscapes_20200602_191001-b9172d0c.pth) \| [log](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr18_512x1024_160k_cityscapes/ocrnet_hr18_512x1024_160k_cityscapes_20200602_191001.log.json) | -| OCRNet | HRNetV2p-W48 | 512x1024 | 160000 | - | - | 81.35 | 82.70 | [config](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/configs/ocrnet/ocrnet_hr48_4xb2-160k_cityscapes-512x1024.py) | [model](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr48_512x1024_160k_cityscapes/ocrnet_hr48_512x1024_160k_cityscapes_20200602_191037-dfbf1b0c.pth) \| [log](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr48_512x1024_160k_cityscapes/ocrnet_hr48_512x1024_160k_cityscapes_20200602_191037.log.json) | +| Method | Backbone | Crop Size | Lr schd | Mem (GB) | Inf time (fps) | mIoU | mIoU(ms+flip) | config | download | +| ------ | ------------------ | --------- | ------: | -------- | -------------- | ----: | ------------: | -------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| OCRNet | HRNetV2p-W18-Small | 512x1024 | 40000 | 3.5 | 10.45 | 76.61 | 78.01 | [config](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/configs/ocrnet/ocrnet_hr18s_4xb2-40k_cityscapes-512x1024.py) | [model](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr18s_4xb2-40k_cityscapes-512x1024/ocrnet_hr18s_4xb2-40k_cityscapes-512x1024_20230227_145026-6c052a14.pth) \| [log](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr18s_4xb2-40k_cityscapes-512x1024/ocrnet_hr18s_4xb2-40k_cityscapes-512x1024_20230227_145026.json) | +| OCRNet | HRNetV2p-W18 | 512x1024 | 40000 | 4.7 | 7.50 | 77.72 | 79.49 | [config](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/configs/ocrnet/ocrnet_hr18_4xb2-40k_cityscapes-512x1024.py) | [model](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr18_512x1024_40k_cityscapes/ocrnet_hr18_512x1024_40k_cityscapes_20200601_033320-401c5bdd.pth) \| [log](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr18_512x1024_40k_cityscapes/ocrnet_hr18_512x1024_40k_cityscapes_20200601_033320.log.json) | +| OCRNet | HRNetV2p-W48 | 512x1024 | 40000 | 8 | 4.22 | 80.58 | 81.79 | [config](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/configs/ocrnet/ocrnet_hr48_4xb2-40k_cityscapes-512x1024.pyy) | [model](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr48_512x1024_40k_cityscapes/ocrnet_hr48_512x1024_40k_cityscapes_20200601_033336-55b32491.pth) \| [log](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr48_512x1024_40k_cityscapes/ocrnet_hr48_512x1024_40k_cityscapes_20200601_033336.log.json) | +| OCRNet | HRNetV2p-W18-Small | 512x1024 | 80000 | - | - | 77.16 | 78.66 | [config](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/configs/ocrnet/ocrnet_hr18s_4xb2-80k_cityscapes-512x1024.py) | [model](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr18s_512x1024_80k_cityscapes/ocrnet_hr18s_512x1024_80k_cityscapes_20200601_222735-55979e63.pth) \| [log](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr18s_512x1024_80k_cityscapes/ocrnet_hr18s_512x1024_80k_cityscapes_20200601_222735.log.json) | +| OCRNet | HRNetV2p-W18 | 512x1024 | 80000 | - | - | 78.57 | 80.46 | [config](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/configs/ocrnet/ocrnet_hr18_4xb2-80k_cityscapes-512x1024.py) | [model](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr18_512x1024_80k_cityscapes/ocrnet_hr18_512x1024_80k_cityscapes_20200614_230521-c2e1dd4a.pth) \| [log](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr18_512x1024_80k_cityscapes/ocrnet_hr18_512x1024_80k_cityscapes_20200614_230521.log.json) | +| OCRNet | HRNetV2p-W48 | 512x1024 | 80000 | - | - | 80.70 | 81.87 | [config](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/configs/ocrnet/ocrnet_hr48_4xb2-80k_cityscapes-512x1024.py) | [model](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr48_512x1024_80k_cityscapes/ocrnet_hr48_512x1024_80k_cityscapes_20200601_222752-9076bcdf.pth) \| [log](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr48_512x1024_80k_cityscapes/ocrnet_hr48_512x1024_80k_cityscapes_20200601_222752.log.json) | +| OCRNet | HRNetV2p-W18-Small | 512x1024 | 160000 | - | - | 78.45 | 79.97 | [config](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/configs/ocrnet/ocrnet_hr18s_4xb2-160k_cityscapes-512x1024.py) | [model](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr18s_512x1024_160k_cityscapes/ocrnet_hr18s_512x1024_160k_cityscapes_20200602_191005-f4a7af28.pth) \| [log](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr18s_512x1024_160k_cityscapes/ocrnet_hr18s_512x1024_160k_cityscapes_20200602_191005.log.json) | +| OCRNet | HRNetV2p-W18 | 512x1024 | 160000 | - | - | 79.47 | 80.91 | [config](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/configs/ocrnet/ocrnet_hr18_4xb2-160k_cityscapes-512x1024.py) | [model](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr18_512x1024_160k_cityscapes/ocrnet_hr18_512x1024_160k_cityscapes_20200602_191001-b9172d0c.pth) \| [log](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr18_512x1024_160k_cityscapes/ocrnet_hr18_512x1024_160k_cityscapes_20200602_191001.log.json) | +| OCRNet | HRNetV2p-W48 | 512x1024 | 160000 | - | - | 81.35 | 82.70 | [config](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/configs/ocrnet/ocrnet_hr48_4xb2-160k_cityscapes-512x1024.py) | [model](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr48_512x1024_160k_cityscapes/ocrnet_hr48_512x1024_160k_cityscapes_20200602_191037-dfbf1b0c.pth) \| [log](https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr48_512x1024_160k_cityscapes/ocrnet_hr48_512x1024_160k_cityscapes_20200602_191037.log.json) | #### ResNet backbone diff --git a/configs/ocrnet/ocrnet.yml b/configs/ocrnet/ocrnet.yml index a81aec2c75..20002e8864 100644 --- a/configs/ocrnet/ocrnet.yml +++ b/configs/ocrnet/ocrnet.yml @@ -33,10 +33,10 @@ Models: - Task: Semantic Segmentation Dataset: Cityscapes Metrics: - mIoU: 74.3 - mIoU(ms+flip): 75.95 + mIoU: 76.61 + mIoU(ms+flip): 78.01 Config: configs/ocrnet/ocrnet_hr18s_4xb2-40k_cityscapes-512x1024.py - Weights: https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr18s_512x1024_40k_cityscapes/ocrnet_hr18s_512x1024_40k_cityscapes_20200601_033304-fa2436c2.pth + Weights: https://download.openmmlab.com/mmsegmentation/v0.5/ocrnet/ocrnet_hr18s_4xb2-40k_cityscapes-512x1024/ocrnet_hr18s_4xb2-40k_cityscapes-512x1024_20230227_145026-6c052a14.pth - Name: ocrnet_hr18_4xb2-40k_cityscapes-512x1024 In Collection: OCRNet Metadata: diff --git a/demo/MMSegmentation_Tutorial.ipynb b/demo/MMSegmentation_Tutorial.ipynb index 89d6e52613..1d92342ae6 100644 --- a/demo/MMSegmentation_Tutorial.ipynb +++ b/demo/MMSegmentation_Tutorial.ipynb @@ -460,12 +460,8 @@ "outputs": [], "source": [ "from mmengine.runner import Runner\n", - "from mmseg.utils import register_all_modules\n", "\n", - "# register all modules in mmseg into the registries\n", - "# do not init the default scope here because it will be init in the runner\n", - "register_all_modules(init_default_scope=False)\n", - "runner = Runner.from_cfg(cfg)\n" + "runner = Runner.from_cfg(cfg)" ] }, { @@ -523,7 +519,7 @@ "provenance": [] }, "kernelspec": { - "display_name": "Python 3.8.5 ('tensorflow')", + "display_name": "Python 3.10.6 ('pt1.12')", "language": "python", "name": "python3" }, @@ -537,7 +533,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.10.6" }, "pycharm": { "stem_cell": { @@ -550,7 +546,7 @@ }, "vscode": { "interpreter": { - "hash": "20d4b83e0c8b3730b580c42434163d64f4b735d580303a8fade7c849d4d29eba" + "hash": "0442e67aee3d9cbb788fa6e86d60c4ffa94ad7f1943c65abfecb99a6f4696c58" } } }, diff --git a/demo/image_demo.py b/demo/image_demo.py index fe11b7693a..231aacb9dd 100644 --- a/demo/image_demo.py +++ b/demo/image_demo.py @@ -4,7 +4,6 @@ from mmengine.model import revert_sync_batchnorm from mmseg.apis import inference_model, init_model, show_result_pyplot -from mmseg.utils import register_all_modules def main(): @@ -24,8 +23,6 @@ def main(): '--title', default='result', help='The image identifier.') args = parser.parse_args() - register_all_modules() - # build the model from a config file and a checkpoint file model = init_model(args.config, args.checkpoint, device=args.device) if args.device == 'cpu': diff --git a/demo/image_demo_with_inferencer.py b/demo/image_demo_with_inferencer.py new file mode 100644 index 0000000000..26bf0f257c --- /dev/null +++ b/demo/image_demo_with_inferencer.py @@ -0,0 +1,45 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from argparse import ArgumentParser + +from mmseg.apis import MMSegInferencer + + +def main(): + parser = ArgumentParser() + parser.add_argument('img', help='Image file') + parser.add_argument('model', help='Config file') + parser.add_argument('--checkpoint', default=None, help='Checkpoint file') + parser.add_argument( + '--out-dir', default='', help='Path to save result file') + parser.add_argument( + '--show', + action='store_true', + default=False, + help='Whether to display the drawn image.') + parser.add_argument( + '--dataset-name', + default='cityscapes', + help='Color palette used for segmentation map') + parser.add_argument( + '--device', default='cuda:0', help='Device used for inference') + parser.add_argument( + '--opacity', + type=float, + default=0.5, + help='Opacity of painted segmentation map. In (0, 1] range.') + args = parser.parse_args() + + # build the model from a config file and a checkpoint file + mmseg_inferencer = MMSegInferencer( + args.model, + args.checkpoint, + dataset_name=args.dataset_name, + device=args.device) + + # test a single image + mmseg_inferencer( + args.img, show=args.show, out_dir=args.out_dir, opacity=args.opacity) + + +if __name__ == '__main__': + main() diff --git a/demo/inference_demo.ipynb b/demo/inference_demo.ipynb index f05a947483..3a29a96466 100644 --- a/demo/inference_demo.ipynb +++ b/demo/inference_demo.ipynb @@ -2,9 +2,28 @@ "cells": [ { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "mkdir: ../checkpoints: File exists\n", + "--2023-02-23 19:23:01-- https://download.openmmlab.com/mmsegmentation/v0.5/pspnet/pspnet_r50-d8_512x1024_40k_cityscapes/pspnet_r50-d8_512x1024_40k_cityscapes_20200605_003338-2966598c.pth\n", + "正在解析主机 download.openmmlab.com (download.openmmlab.com)... 116.0.89.205, 116.0.89.209, 116.0.89.207, ...\n", + "正在连接 download.openmmlab.com (download.openmmlab.com)|116.0.89.205|:443... 已连接。\n", + "已发出 HTTP 请求,正在等待回应... 200 OK\n", + "长度:196205945 (187M) [application/octet-stream]\n", + "正在保存至: “../checkpoints/pspnet_r50-d8_512x1024_40k_cityscapes_20200605_003338-2966598c.pth.3”\n", + "\n", + "pspnet_r50-d8_512x1 100%[===================>] 187.12M 861KB/s 用时 2m 56s \n", + "\n", + "2023-02-23 19:25:57 (1.06 MB/s) - 已保存 “../checkpoints/pspnet_r50-d8_512x1024_40k_cityscapes_20200605_003338-2966598c.pth.3” [196205945/196205945])\n", + "\n" + ] + } + ], "source": [ "!mkdir ../checkpoints\n", "!wget https://download.openmmlab.com/mmsegmentation/v0.5/pspnet/pspnet_r50-d8_512x1024_40k_cityscapes/pspnet_r50-d8_512x1024_40k_cityscapes_20200605_003338-2966598c.pth -P ../checkpoints" @@ -12,7 +31,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": { "pycharm": { "is_executing": true @@ -24,14 +43,12 @@ "import mmcv\n", "import matplotlib.pyplot as plt\n", "from mmengine.model.utils import revert_sync_batchnorm\n", - "from mmseg.apis import init_model, inference_model, show_result_pyplot\n", - "from mmseg.utils import register_all_modules\n", - "register_all_modules()" + "from mmseg.apis import init_model, inference_model, show_result_pyplot" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": { "pycharm": { "is_executing": true @@ -39,15 +56,33 @@ }, "outputs": [], "source": [ - "config_file = '../configs/pspnet/pspnet_r50-d8_512x1024_40k_cityscapes.py'\n", + "config_file = '../configs/pspnet/pspnet_r50-d8_4xb2-40k_cityscapes-512x1024.py'\n", "checkpoint_file = '../checkpoints/pspnet_r50-d8_512x1024_40k_cityscapes_20200605_003338-2966598c.pth'" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/xxc/Desktop/pjlab/mmsegv2/mmseg/models/builder.py:36: UserWarning: ``build_loss`` would be deprecated soon, please use ``mmseg.registry.MODELS.build()`` \n", + " warnings.warn('``build_loss`` would be deprecated soon, please use '\n", + "/Users/xxc/Desktop/pjlab/mmsegv2/mmseg/models/losses/cross_entropy_loss.py:235: UserWarning: Default ``avg_non_ignore`` is False, if you would like to ignore the certain label and average loss over non-ignore labels, which is the same with PyTorch official cross_entropy, set ``avg_non_ignore=True``.\n", + " warnings.warn(\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Loads checkpoint by local backend from path: ../checkpoints/pspnet_r50-d8_512x1024_40k_cityscapes_20200605_003338-2966598c.pth\n" + ] + } + ], "source": [ "# build the model from a config file and a checkpoint file\n", "model = init_model(config_file, checkpoint_file, device='cuda:0')" @@ -55,7 +90,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ @@ -68,9 +103,38 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/opt/anaconda3/envs/pt1.13/lib/python3.10/site-packages/mmengine/visualization/visualizer.py:163: UserWarning: `Visualizer` backend is not initialized because save_dir is None.\n", + " warnings.warn('`Visualizer` backend is not initialized '\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "# show the results\n", "vis_result = show_result_pyplot(model, img, result)\n", @@ -87,7 +151,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3.10.4 ('pt1.11-v2')", + "display_name": "pt1.13", "language": "python", "name": "python3" }, @@ -101,7 +165,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.4" + "version": "3.10.9" }, "pycharm": { "stem_cell": { @@ -114,7 +178,7 @@ }, "vscode": { "interpreter": { - "hash": "fdab7187f8cbd4ce42bbf864ddb4c4693e7329271a15a7fa96e4bdb82b9302c9" + "hash": "f61d5b8fecdd960739697f6c2860080d7b76a5be5d896cb034bdb275ab3ddda0" } } }, diff --git a/demo/video_demo.py b/demo/video_demo.py index 3eb326b7af..7e6f3d605c 100644 --- a/demo/video_demo.py +++ b/demo/video_demo.py @@ -6,7 +6,6 @@ from mmseg.apis import inference_model, init_model from mmseg.apis.inference import show_result_pyplot -from mmseg.utils import register_all_modules def main(): @@ -53,8 +52,6 @@ def main(): assert args.show or args.output_file, \ 'At least one output should be enabled.' - register_all_modules() - # build the model from a config file and a checkpoint file model = init_model(args.config, args.checkpoint, device=args.device) if args.device == 'cpu': diff --git a/docker/serve/Dockerfile b/docker/serve/Dockerfile index 5ae1eb607d..cf127ddbe6 100644 --- a/docker/serve/Dockerfile +++ b/docker/serve/Dockerfile @@ -4,7 +4,7 @@ ARG CUDNN="8" FROM pytorch/pytorch:${PYTORCH}-cuda${CUDA}-cudnn${CUDNN}-devel ARG MMCV="2.0.0rc4" -ARG MMSEG="1.0.0rc5" +ARG MMSEG="1.0.0rc6" ENV PYTHONUNBUFFERED TRUE diff --git a/docs/en/advanced_guides/add_dataset.md b/docs/en/advanced_guides/add_datasets.md similarity index 99% rename from docs/en/advanced_guides/add_dataset.md rename to docs/en/advanced_guides/add_datasets.md index 4149014e64..f33f3d32c6 100644 --- a/docs/en/advanced_guides/add_dataset.md +++ b/docs/en/advanced_guides/add_datasets.md @@ -1,4 +1,4 @@ -# Add New Datasets +# \[WIP\] Add New Datasets ## Customize datasets by reorganizing data diff --git a/docs/en/advanced_guides/add_metrics.md b/docs/en/advanced_guides/add_metrics.md new file mode 100644 index 0000000000..0a25a81fc4 --- /dev/null +++ b/docs/en/advanced_guides/add_metrics.md @@ -0,0 +1 @@ +# Add New Metrics diff --git a/docs/en/advanced_guides/add_transform.md b/docs/en/advanced_guides/add_transform.md deleted file mode 100644 index 69de9d317b..0000000000 --- a/docs/en/advanced_guides/add_transform.md +++ /dev/null @@ -1,37 +0,0 @@ -# Adding New Data Transforms - -1. Write a new pipeline in any file, e.g., `my_pipeline.py`. It takes a dict as input and return a dict. - - ```python - from mmseg.datasets import TRANSFORMS - @TRANSFORMS.register_module() - class MyTransform: - def transform(self, results): - results['dummy'] = True - return results - ``` - -2. Import the new class. - - ```python - from .my_pipeline import MyTransform - ``` - -3. Use it in config files. - - ```python - crop_size = (512, 1024) - train_pipeline = [ - dict(type='LoadImageFromFile'), - dict(type='LoadAnnotations'), - dict(type='RandomResize', - scale=(2048, 1024), - ratio_range=(0.5, 2.0), - keep_ratio=True), - dict(type='RandomCrop', crop_size=crop_size, cat_max_ratio=0.75), - dict(type='RandomFlip', flip_ratio=0.5), - dict(type='PhotoMetricDistortion'), - dict(type='MyTransform'), - dict(type='PackSegInputs'), - ] - ``` diff --git a/docs/en/advanced_guides/add_transforms.md b/docs/en/advanced_guides/add_transforms.md new file mode 100644 index 0000000000..ca336ce046 --- /dev/null +++ b/docs/en/advanced_guides/add_transforms.md @@ -0,0 +1,52 @@ +# Adding New Data Transforms + +## Customization data transformation + +The customized data transformation must inherited from `BaseTransform` and implement `transform` function. +Here we use a simple flipping transformation as example: + +```python +import random +import mmcv +from mmcv.transforms import BaseTransform, TRANSFORMS + +@TRANSFORMS.register_module() +class MyFlip(BaseTransform): + def __init__(self, direction: str): + super().__init__() + self.direction = direction + + def transform(self, results: dict) -> dict: + img = results['img'] + results['img'] = mmcv.imflip(img, direction=self.direction) + return results +``` + +Moreover, import the new class. + +```python +from .my_pipeline import MyFlip +``` + +Thus, we can instantiate a `MyFlip` object and use it to process the data dict. + +```python +import numpy as np + +transform = MyFlip(direction='horizontal') +data_dict = {'img': np.random.rand(224, 224, 3)} +data_dict = transform(data_dict) +processed_img = data_dict['img'] +``` + +Or, we can use `MyFlip` transformation in data pipeline in our config file. + +```python +pipeline = [ + ... + dict(type='MyFlip', direction='horizontal'), + ... +] +``` + +Note that if you want to use `MyFlip` in config, you must ensure the file containing `MyFlip` is imported during runtime. diff --git a/docs/en/advanced_guides/customize_runtime.md b/docs/en/advanced_guides/customize_runtime.md index f138c226fd..33281bfe4a 100644 --- a/docs/en/advanced_guides/customize_runtime.md +++ b/docs/en/advanced_guides/customize_runtime.md @@ -1,245 +1,168 @@ # Customize Runtime Settings -## Customize optimization settings +## Customize hooks -### Customize optimizer supported by Pytorch +### Step 1: Implement a new hook -We already support to use all the optimizers implemented by PyTorch, and the only modification is to change the `optimizer` field of config files. -For example, if you want to use `ADAM` (note that the performance could drop a lot), the modification could be as the following. +MMEngine has implemented commonly used [hooks](https://github.com/open-mmlab/mmengine/blob/main/docs/en/tutorials/hook.md) for training and test, +When users have requirements for customization, they can follow examples below. +For example, if some hyper-parameter of the model needs to be changed when model training, we can implement a new hook for it: ```python -optimizer = dict(type='Adam', lr=0.0003, weight_decay=0.0001) -``` - -To modify the learning rate of the model, the users only need to modify the `lr` in the config of optimizer. The users can directly set arguments following the [API doc](https://pytorch.org/docs/stable/optim.html?highlight=optim#module-torch.optim) of PyTorch. - -### Customize self-implemented optimizer +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Optional, Sequence -#### 1. Define a new optimizer +from mmengine.hooks import Hook +from mmengine.model import is_model_wrapper -A customized optimizer could be defined as following. - -Assume you want to add a optimizer named `MyOptimizer`, which has arguments `a`, `b`, and `c`. -You need to create a new directory named `mmseg/core/optimizer`. -And then implement the new optimizer in a file, e.g., in `mmseg/core/optimizer/my_optimizer.py`: - -```python -from .registry import OPTIMIZERS -from torch.optim import Optimizer +from mmseg.registry import HOOKS -@OPTIMIZERS.register_module() -class MyOptimizer(Optimizer): +@HOOKS.register_module() +class NewHook(Hook): + """Docstring for NewHook. + """ - def __init__(self, a, b, c) + def __init__(self, a: int, b: int) -> None: + self.a = a + self.b = b + def before_train_iter(self, + runner, + batch_idx: int, + data_batch: Optional[Sequence[dict]] = None) -> None: + cur_iter = runner.iter + # acquire this model when it is in a wrapper + if is_model_wrapper(runner.model): + model = runner.model.module + model.hyper_parameter = self.a * cur_iter + self.b ``` -#### 2. Add the optimizer to registry - -To find the above module defined above, this module should be imported into the main namespace at first. There are two options to achieve it. +### Step 2: Import a new hook -- Modify `mmseg/core/optimizer/__init__.py` to import it. +The module which is defined above needs to be imported into main namespace first to ensure being registered. +We assume `NewHook` is implemented in `mmseg/engine/hooks/new_hook.py`, there are two ways to import it: - The newly defined module should be imported in `mmseg/core/optimizer/__init__.py` so that the registry will - find the new module and add it: +- Import it by modifying `mmseg/engine/hooks/__init__.py`. + Modules should be imported in `mmseg/engine/hooks/__init__.py` thus these new modules can be found and added by registry. ```python -from .my_optimizer import MyOptimizer +from .new_hook import NewHook + +__all__ = [..., NewHook] ``` -- Use `custom_imports` in the config to manually import it +- Import it manually by `custom_imports` in config file. ```python -custom_imports = dict(imports=['mmseg.core.optimizer.my_optimizer'], allow_failed_imports=False) +custom_imports = dict(imports=['mmseg.engine.hooks.new_hook'], allow_failed_imports=False) ``` -The module `mmseg.core.optimizer.my_optimizer` will be imported at the beginning of the program and the class `MyOptimizer` is then automatically registered. -Note that only the package containing the class `MyOptimizer` should be imported. -`mmseg.core.optimizer.my_optimizer.MyOptimizer` **cannot** be imported directly. - -Actually users can use a totally different file directory structure using this importing method, as long as the module root can be located in `PYTHONPATH`. - -#### 3. Specify the optimizer in the config file +### Step 3: Modify config file -Then you can use `MyOptimizer` in `optimizer` field of config files. -In the configs, the optimizers are defined by the field `optimizer` like the following: +Users can set and use customized hooks in training and test followed methods below. +The execution priority of hooks at the same place of `Runner` can be referred [here](https://github.com/open-mmlab/mmengine/blob/main/docs/en/tutorials/hook.md#built-in-hooks), +Default priority of customized hook is `NORMAL`. ```python -optimizer = dict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.0001) +custom_hooks = [ + dict(type='NewHook', a=a_value, b=b_value, priority='ABOVE_NORMAL') +] ``` -To use your own optimizer, the field can be changed to - -```python -optimizer = dict(type='MyOptimizer', a=a_value, b=b_value, c=c_value) -``` +## Customize optimizer -### Customize optimizer constructor +### Step 1: Implement a new optimizer -Some models may have some parameter-specific settings for optimization, e.g. weight decay for BatchNorm layers. -The users can do those fine-grained parameter tuning through customizing optimizer constructor. +We recommend the customized optimizer implemented in `mmseg/engine/optimizers/my_optimizer.py`. Here is an example of a new optimizer `MyOptimizer` which has parameters `a`, `b` and `c`: ```python -from mmcv.utils import build_from_cfg - -from mmcv.runner.optimizer import OPTIMIZER_BUILDERS, OPTIMIZERS -from mmseg.utils import get_root_logger -from .my_optimizer import MyOptimizer - - -@OPTIMIZER_BUILDERS.register_module() -class MyOptimizerConstructor(object): +from mmseg.registry import OPTIMIZERS +from torch.optim import Optimizer - def __init__(self, optim_wrapper_cfg, paramwise_cfg=None): - def __call__(self, model): - - return my_optimizer +@OPTIMIZERS.register_module() +class MyOptimizer(Optimizer): + def __init__(self, a, b, c) ``` -The default optimizer constructor is implemented [here](https://github.com/open-mmlab/mmcv/blob/9ecd6b0d5ff9d2172c49a182eaa669e9f27bb8e7/mmcv/runner/optimizer/default_constructor.py#L11), which could also serve as a template for new optimizer constructor. - -### Additional settings - -Tricks not implemented by the optimizer should be implemented through optimizer constructor (e.g., set parameter-wise learning rates) or hooks. We list some common settings that could stabilize the training or accelerate the training. Feel free to create PR, issue for more settings. - -- __Use gradient clip to stabilize training__: - Some models need gradient clip to clip the gradients to stabilize the training process. An example is as below: - - ```python - optimizer_config = dict( - _delete_=True, grad_clip=dict(max_norm=35, norm_type=2)) - ``` - - If your config inherits the base config which already sets the `optimizer_config`, you might need `_delete_=True` to override the unnecessary settings. See the [config documentation](https://mmsegmentation.readthedocs.io/en/latest/config.html) for more details. - -- __Use momentum schedule to accelerate model convergence__: - We support momentum scheduler to modify model's momentum according to learning rate, which could make the model converge in a faster way. - Momentum scheduler is usually used with LR scheduler, for example, the following config is used in 3D detection to accelerate convergence. - For more details, please refer to the implementation of [CyclicLrUpdater](https://github.com/open-mmlab/mmcv/blob/f48241a65aebfe07db122e9db320c31b685dc674/mmcv/runner/hooks/lr_updater.py#L327) and [CyclicMomentumUpdater](https://github.com/open-mmlab/mmcv/blob/f48241a65aebfe07db122e9db320c31b685dc674/mmcv/runner/hooks/momentum_updater.py#L130). - - ```python - lr_config = dict( - policy='cyclic', - target_ratio=(10, 1e-4), - cyclic_times=1, - step_ratio_up=0.4, - ) - momentum_config = dict( - policy='cyclic', - target_ratio=(0.85 / 0.95, 1), - cyclic_times=1, - step_ratio_up=0.4, - ) - ``` - -## Customize training schedules - -By default we use step learning rate with 40k/80k schedule, this calls [`PolyLrUpdaterHook`](https://github.com/open-mmlab/mmcv/blob/826d3a7b68596c824fa1e2cb89b6ac274f52179c/mmcv/runner/hooks/lr_updater.py#L196) in MMCV. -We support many other learning rate schedule [here](https://github.com/open-mmlab/mmcv/blob/master/mmcv/runner/hooks/lr_updater.py), such as `CosineAnnealing` and `Poly` schedule. Here are some examples - -- Step schedule: - - ```python - lr_config = dict(policy='step', step=[9, 10]) - ``` - -- ConsineAnnealing schedule: - - ```python - lr_config = dict( - policy='CosineAnnealing', - warmup='linear', - warmup_iters=1000, - warmup_ratio=1.0 / 10, - min_lr_ratio=1e-5) - ``` +### Step 2: Import a new optimizer -## Customize workflow +The module which is defined above needs to be imported into main namespace first to ensure being registered. +We assume `MyOptimizer` is implemented in `mmseg/engine/optimizers/my_optimizer.py`, there are two ways to import it: -Workflow is a list of (phase, epochs) to specify the running order and epochs. -By default it is set to be +- Import it by modifying `mmseg/engine/optimizers/__init__.py`. + Modules should be imported in `mmseg/engine/optimizers/__init__.py` thus these new modules can be found and added by registry. ```python -workflow = [('train', 1)] +from .my_optimizer import MyOptimizer ``` -which means running 1 epoch for training. -Sometimes user may want to check some metrics (e.g. loss, accuracy) about the model on the validate set. -In such case, we can set the workflow as +- Import it manually by `custom_imports` in config file. ```python -[('train', 1), ('val', 1)] +custom_imports = dict(imports=['mmseg.engine.optimizers.my_optimizer'], allow_failed_imports=False) ``` -so that 1 epoch for training and 1 epoch for validation will be run iteratively. - -:::{note} +### Step 3: Modify config file -1. The parameters of model will not be updated during val epoch. -2. Keyword `total_epochs` in the config only controls the number of training epochs and will not affect the validation workflow. -3. Workflows `[('train', 1), ('val', 1)]` and `[('train', 1)]` will not change the behavior of `EvalHook` because `EvalHook` is called by `after_train_epoch` and validation workflow only affect hooks that are called through `after_val_epoch`. Therefore, the only difference between `[('train', 1), ('val', 1)]` and `[('train', 1)]` is that the runner will calculate losses on validation set after each training epoch. +Then it needs to modify `optimizer` in `optim_wrapper` of config file, if users want to use customized `MyOptimizer`, it can be modified as: -::: +```python +optim_wrapper = dict(type='OptimWrapper', + optimizer=dict(type='MyOptimizer', + a=a_value, b=b_value, c=c_value), + clip_grad=None) +``` -## Customize hooks +## Customize optimizer constructor -### Use hooks implemented in MMCV +### Step 1: Implement a new optimizer constructor -If the hook is already implemented in MMCV, you can directly modify the config to use the hook as below +Optimizer constructor is used to create optimizer and optimizer wrapper for model training, which has powerful functions like specifying learning rate and weight decay for different model layers. +Here is an example for a customized optimizer constructor. ```python -custom_hooks = [ - dict(type='MyHook', a=a_value, b=b_value, priority='NORMAL') -] -``` +from mmengine.optim import DefaultOptimWrapperConstructor +from mmseg.registry import OPTIM_WRAPPER_CONSTRUCTORS -### Modify default runtime hooks +@OPTIM_WRAPPER_CONSTRUCTORS.register_module() +class LearningRateDecayOptimizerConstructor(DefaultOptimWrapperConstructor): + def __init__(self, optim_wrapper_cfg, paramwise_cfg=None): -There are some common hooks that are not registered through `custom_hooks`, they are + def __call__(self, model): -- log_config -- checkpoint_config -- evaluation -- lr_config -- optimizer_config -- momentum_config + return my_optimizer +``` -In those hooks, only the logger hook has the `VERY_LOW` priority, others' priority are `NORMAL`. -The above-mentioned tutorials already covers how to modify `optimizer_config`, `momentum_config`, and `lr_config`. -Here we reveals how what we can do with `log_config`, `checkpoint_config`, and `evaluation`. +Default optimizer constructor is implemented [here](https://github.com/open-mmlab/mmengine/blob/main/mmengine/optim/optimizer/default_constructor.py#L19). +It can also be used as base class of new optimizer constructor. -#### Checkpoint config +### Step 2: Import a new optimizer constructor -The MMCV runner will use `checkpoint_config` to initialize [`CheckpointHook`](https://github.com/open-mmlab/mmcv/blob/9ecd6b0d5ff9d2172c49a182eaa669e9f27bb8e7/mmcv/runner/hooks/checkpoint.py#L9). +The module which is defined above needs to be imported into main namespace first to ensure being registered. +We assume `MyOptimizerConstructor` is implemented in `mmseg/engine/optimizers/my_optimizer_constructor.py`, there are two ways to import it: + +- Import it by modifying `mmseg/engine/optimizers/__init__.py`. + Modules should be imported in `mmseg/engine/optimizers/__init__.py` thus these new modules can be found and added by registry. ```python -checkpoint_config = dict(interval=1) +from .my_optimizer_constructor import MyOptimizerConstructor ``` -The users could set `max_keep_ckpts` to only save only small number of checkpoints or decide whether to store state dict of optimizer by `save_optimizer`. More details of the arguments are [here](https://mmcv.readthedocs.io/en/latest/api.html#mmcv.runner.CheckpointHook) - -#### Log config - -The `log_config` wraps multiple logger hooks and enables to set intervals. Now MMCV supports `WandbLoggerHook`, `MlflowLoggerHook`, and `TensorboardLoggerHook`. -The detail usages can be found in the [doc](https://mmcv.readthedocs.io/en/latest/api.html#mmcv.runner.LoggerHook). +- Import it manually by `custom_imports` in config file. ```python -log_config = dict( - interval=50, - hooks=[ - dict(type='TextLoggerHook'), - dict(type='TensorboardLoggerHook') - ]) +custom_imports = dict(imports=['mmseg.engine.optimizers.my_optimizer_constructor'], allow_failed_imports=False) ``` -#### Evaluation config +### Step 3: Modify config file -The config of `evaluation` will be used to initialize the [`EvalHook`](https://github.com/open-mmlab/mmsegmentation/blob/e3f6f655d69b777341aec2fe8829871cc0beadcb/mmseg/core/evaluation/eval_hooks.py#L7). -Except the key `interval`, other arguments such as `metric` will be passed to the `dataset.evaluate()` +Then it needs to modify `constructor` in `optim_wrapper` of config file, if users want to use customized `MyOptimizerConstructor`, it can be modified as: ```python -evaluation = dict(interval=1, metric='mIoU') +optim_wrapper = dict(type='OptimWrapper', + constructor='MyOptimizerConstructor', + clip_grad=None) ``` diff --git a/docs/en/advanced_guides/datasets.md b/docs/en/advanced_guides/datasets.md index 733e2a26d9..a1b8044b3d 100644 --- a/docs/en/advanced_guides/datasets.md +++ b/docs/en/advanced_guides/datasets.md @@ -15,8 +15,8 @@ Instantiate Cityscapes training dataset: ```python from mmseg.datasets import CityscapesDataset -from mmseg.utils import register_all_modules -register_all_modules() +from mmengine.registry import init_default_scope +init_default_scope('mmseg') data_root = 'data/cityscapes/' data_prefix=dict(img_path='leftImg8bit/train', seg_map_path='gtFine/train') diff --git a/docs/en/advanced_guides/evaluation.md b/docs/en/advanced_guides/evaluation.md index 55728281a9..ee5a927ff7 100644 --- a/docs/en/advanced_guides/evaluation.md +++ b/docs/en/advanced_guides/evaluation.md @@ -81,7 +81,7 @@ The arguments of the constructor: - `process` method processes one batch of data and data_samples. - `compute_metrics` method computes the metrics from processed results. -#### IoUMetric.process +### IoUMetric.process Parameters: @@ -92,7 +92,7 @@ Returns: This method doesn't have returns since the processed results would be stored in `self.results`, which will be used to compute the metrics when all batches have been processed. -#### IoUMetric.compute_metrics +### IoUMetric.compute_metrics Parameters: diff --git a/docs/en/advanced_guides/index.rst b/docs/en/advanced_guides/index.rst index 1cae420c1c..53ef8c5e73 100644 --- a/docs/en/advanced_guides/index.rst +++ b/docs/en/advanced_guides/index.rst @@ -19,7 +19,7 @@ Component Customization .. toctree:: :maxdepth: 1 - add_modules.md + add_models.md add_datasets.md add_transforms.md add_metrics.md diff --git a/docs/en/advanced_guides/training_tricks.md b/docs/en/advanced_guides/training_tricks.md index 6c43230c71..8fa89131d5 100644 --- a/docs/en/advanced_guides/training_tricks.md +++ b/docs/en/advanced_guides/training_tricks.md @@ -1,4 +1,4 @@ -# Training Tricks +# \[WIP\] Training Tricks MMSegmentation support following training tricks out of box. diff --git a/docs/en/advanced_guides/transforms.md b/docs/en/advanced_guides/transforms.md index d42d61a9ef..e0c4155b57 100644 --- a/docs/en/advanced_guides/transforms.md +++ b/docs/en/advanced_guides/transforms.md @@ -6,7 +6,9 @@ The structure of this guide is as follows: - [Data Transforms](#data-transforms) - [Design of Data pipelines](#design-of-data-pipelines) - - [Customization data transformation](#customization-data-transformation) + - [Data loading](#data-loading) + - [Pre-processing](#pre-processing) + - [Formatting](#formatting) ## Design of Data pipelines @@ -125,48 +127,3 @@ The position of random contrast is in second or second to last(mode 0 or 1 below - add: `inputs`, `data_sample` - remove: keys specified by `meta_keys` (merged into the metainfo of data_sample), all other keys - -## Customization data transformation - -The customized data transformation must inherited from `BaseTransform` and implement `transform` function. -Here we use a simple flipping transformation as example: - -```python -import random -import mmcv -from mmcv.transforms import BaseTransform, TRANSFORMS - -@TRANSFORMS.register_module() -class MyFlip(BaseTransform): - def __init__(self, direction: str): - super().__init__() - self.direction = direction - - def transform(self, results: dict) -> dict: - img = results['img'] - results['img'] = mmcv.imflip(img, direction=self.direction) - return results -``` - -Thus, we can instantiate a `MyFlip` object and use it to process the data dict. - -```python -import numpy as np - -transform = MyFlip(direction='horizontal') -data_dict = {'img': np.random.rand(224, 224, 3)} -data_dict = transform(data_dict) -processed_img = data_dict['img'] -``` - -Or, we can use `MyFlip` transformation in data pipeline in our config file. - -```python -pipeline = [ - ... - dict(type='MyFlip', direction='horizontal'), - ... -] -``` - -Note that if you want to use `MyFlip` in config, you must ensure the file containing `MyFlip` is imported during runtime. diff --git a/docs/en/api.rst b/docs/en/api.rst index 94f64313d0..2f1a25ef9d 100644 --- a/docs/en/api.rst +++ b/docs/en/api.rst @@ -11,11 +11,6 @@ datasets .. automodule:: mmseg.datasets :members: -samplers -^^^^^^^^^^ -.. automodule:: mmseg.datasets.samplers - :members: - transforms ^^^^^^^^^^^^ .. automodule:: mmseg.datasets.transforms @@ -35,7 +30,7 @@ optimizers :members: mmseg.evaluation --------------- +----------------- metrics ^^^^^^^^^^ diff --git a/docs/en/device/npu.md b/docs/en/device/npu.md new file mode 100644 index 0000000000..a90d6ac433 --- /dev/null +++ b/docs/en/device/npu.md @@ -0,0 +1,39 @@ +# NPU (HUAWEI Ascend) + +## Usage + +Please refer to the [building documentation of MMCV](https://mmcv.readthedocs.io/en/latest/get_started/build.html#build-mmcv-full-on-ascend-npu-machine) to install MMCV on NPU devices + +Here we use 4 NPUs on your computer to train the model with the following command: + +```shell +bash tools/dist_train.sh configs/deeplabv3/deeplabv3_r50-d8_4xb2-40k_cityscapes-512x1024.py 4 +``` + +Also, you can use only one NPU to train the model with the following command: + +```shell +python tools/train.py configs/deeplabv3/deeplabv3_r50-d8_4xb2-40k_cityscapes-512x1024.py +``` + +## Models Results + +| Model | mIoU | Config | Download | +| :-----------------: | :---: | :----------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------ | +| [deeplabv3](<>) | 78.85 | [config](https://github.com/open-mmlab/mmsegmentation/tree/1.x/configs/deeplabv3/deeplabv3_r50-d8_4xb2-40k_cityscapes-512x1024.py) | [log](https://download.openmmlab.com/mmsegmentation/v0.5/device/npu/deeplabv3_r50-d8_4xb2-40k_cityscapes-512x1024_20230115_205626.json) | +| [deeplabv3plus](<>) | 79.23 | [config](https://github.com/open-mmlab/mmsegmentation/tree/1.x/configs/deeplabv3plus/deeplabv3plus_r50-d8_4xb2-40k_cityscapes-512x1024.py) | [log](https://download.openmmlab.com/mmsegmentation/v0.5/device/npu/deeplabv3plus_r50-d8_4xb2-40k_cityscapes-512x1024_20230116_043450.json) | +| [hrnet](<>) | 78.1 | [config](https://github.com/open-mmlab/mmsegmentation/tree/1.x/configs/hrnet/fcn_hr18_4xb2-40k_cityscapes-512x1024.py) | [log](https://download.openmmlab.com/mmsegmentation/v0.5/device/npu/fcn_hr18_4xb2-40k_cityscapes-512x1024_20230116_215821.json) | +| [fcn](<>) | 74.15 | [config](https://github.com/open-mmlab/mmsegmentation/tree/1.x/configs/fcn/fcn_r50-d8_4xb2-40k_cityscapes-512x1024.py) | [log](https://download.openmmlab.com/mmsegmentation/v0.5/device/npu/fcn_r50-d8_4xb2-40k_cityscapes-512x1024_20230111_083014.json) | +| [icnet](<>) | 69.25 | [config](https://github.com/open-mmlab/mmsegmentation/tree/1.x/configs/icnet/icnet_r50-d8_4xb2-80k_cityscapes-832x832.py) | [log](https://download.openmmlab.com/mmsegmentation/v0.5/device/npu/icnet_r50-d8_4xb2-80k_cityscapes-832x832_20230119_002929.json) | +| [pspnet](<>) | 77.21 | [config](https://github.com/open-mmlab/mmsegmentation/tree/1.x/configs/pspnet/pspnet_r50b-d8_4xb2-80k_cityscapes-512x1024.py) | [log](https://download.openmmlab.com/mmsegmentation/v0.5/device/npu/pspnet_r50b-d8_4xb2-80k_cityscapes-512x1024_20230114_042721.json) | +| [unet](<>) | 68.86 | [config](https://github.com/open-mmlab/mmsegmentation/tree/1.x/configs/unet/unet-s5-d16_fcn_4xb4-160k_cityscapes-512x1024.py) | [log](https://download.openmmlab.com/mmsegmentation/v0.5/device/npu/unet-s5-d16_fcn_4xb4-160k_cityscapes-512x1024_20230129_224750.json) | +| [upernet](<>) | 77.81 | [config](https://github.com/open-mmlab/mmsegmentation/tree/1.x/configs/upernet/upernet_r50_4xb2-40k_cityscapes-512x1024.py) | [log](https://download.openmmlab.com/mmsegmentation/v0.5/device/npu/upernet_r50_4xb2-40k_cityscapes-512x1024_20230129_014634.json) | +| [apcnet](<>) | 78.02 | [config](https://github.com/open-mmlab/mmsegmentation/tree/1.x/configs/apcnet/apcnet_r50-d8_4xb2-40k_cityscapes-512x1024.py) | [log](https://download.openmmlab.com/mmsegmentation/v0.5/device/npu/apcnet_r50-d8_4xb2-40k_cityscapes-512x1024_20230209_212545.json) | +| [bisenetv1](<>) | 76.04 | [config](https://github.com/open-mmlab/mmsegmentation/tree/1.x/configs/bisenetv1/bisenetv1_r50-d32_4xb4-160k_cityscapes-1024x1024.py) | [log](https://download.openmmlab.com/mmsegmentation/v0.5/device/npu/bisenetv1_r50-d32_4xb4-160k_cityscapes-1024x1024_20230201_023946.json) | +| [bisenetv2](<>) | 72.44 | [config](https://github.com/open-mmlab/mmsegmentation/tree/1.x/configs/bisenetv2/bisenetv2_fcn_4xb4-amp-160k_cityscapes-1024x1024.py) | [log](https://download.openmmlab.com/mmsegmentation/v0.5/device/npu/bisenetv2_fcn_4xb4-amp-160k_cityscapes-1024x1024_20230205_215606.json) | + +**Notes:** + +- If not specially marked, the results on NPU with amp are the basically same as those on the GPU with FP32. + +**All above models are provided by Huawei Ascend group.** diff --git a/docs/en/get_started.md b/docs/en/get_started.md index 313501e0d3..cf861b1fe8 100644 --- a/docs/en/get_started.md +++ b/docs/en/get_started.md @@ -91,10 +91,8 @@ Option (b). If you install mmsegmentation with pip, open you python interpreter ```python from mmseg.apis import inference_model, init_model, show_result_pyplot -from mmseg.utils import register_all_modules import mmcv -register_all_modules() config_file = 'pspnet_r50-d8_4xb2-40k_cityscapes-512x1024.py' checkpoint_file = 'pspnet_r50-d8_512x1024_40k_cityscapes_20200605_003338-2966598c.pth' diff --git a/docs/en/index.rst b/docs/en/index.rst index 63cfb924c4..cdf8622f94 100644 --- a/docs/en/index.rst +++ b/docs/en/index.rst @@ -45,13 +45,17 @@ Welcome to MMSegmentation's documentation! notes/changelog.md notes/faq.md +.. toctree:: + :caption: Device Support + + device/npu.md + .. toctree:: :caption: Switch Language switch_language.md - Indices and tables ================== diff --git a/docs/en/migration/interface.md b/docs/en/migration/interface.md index 1bc3d206e2..d75f8ec3ef 100644 --- a/docs/en/migration/interface.md +++ b/docs/en/migration/interface.md @@ -237,7 +237,7 @@ test_pipeline = [ ] img_ratios = [0.5, 0.75, 1.0, 1.25, 1.5, 1.75] tta_pipeline = [ - dict(type='LoadImageFromFile', backend_args=dict(backend='local')), + dict(type='LoadImageFromFile', backend_args=None), dict( type='TestTimeAug', transforms=[ diff --git a/docs/en/migration/package.md b/docs/en/migration/package.md index 95fefe1310..c0aa1d6e31 100644 --- a/docs/en/migration/package.md +++ b/docs/en/migration/package.md @@ -82,7 +82,7 @@ Here is the changes of `mmseg.apis`: | Function | Changes | | :-------------------: | :---------------------------------------------- | | `init_segmentor` | Renamed to `init_model` | -| `inference_segmentor` | Rename to `inference_segmentor` | +| `inference_segmentor` | Rename to `inference_model` | | `show_result_pyplot` | Implemented based on `SegLocalVisualizer` | | `train_model` | Removed, use `runner.train` to train. | | `multi_gpu_test` | Removed, use `runner.test` to test. | diff --git a/docs/en/modelzoo_statistics.md b/docs/en/modelzoo_statistics.md new file mode 100644 index 0000000000..c8fa46d013 --- /dev/null +++ b/docs/en/modelzoo_statistics.md @@ -0,0 +1,102 @@ +# Model Zoo Statistics + +- Number of papers: 47 + + - ALGORITHM: 36 + - BACKBONE: 11 + +- Number of checkpoints: 612 + + - \[ALGORITHM\] [ANN](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/ann) (16 ckpts) + + - \[ALGORITHM\] [APCNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/apcnet) (12 ckpts) + + - \[BACKBONE\] [BEiT](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/beit) (2 ckpts) + + - \[ALGORITHM\] [BiSeNetV1](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/bisenetv1) (11 ckpts) + + - \[ALGORITHM\] [BiSeNetV2](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/bisenetv2) (4 ckpts) + + - \[ALGORITHM\] [CCNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/ccnet) (16 ckpts) + + - \[ALGORITHM\] [CGNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/cgnet) (2 ckpts) + + - \[BACKBONE\] [ConvNeXt](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/convnext) (6 ckpts) + + - \[ALGORITHM\] [DANet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/danet) (16 ckpts) + + - \[ALGORITHM\] [DeepLabV3](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/deeplabv3) (41 ckpts) + + - \[ALGORITHM\] [DeepLabV3+](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/deeplabv3plus) (42 ckpts) + + - \[ALGORITHM\] [DMNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/dmnet) (12 ckpts) + + - \[ALGORITHM\] [DNLNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/dnlnet) (12 ckpts) + + - \[ALGORITHM\] [DPT](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/dpt) (1 ckpts) + + - \[ALGORITHM\] [EMANet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/emanet) (4 ckpts) + + - \[ALGORITHM\] [EncNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/encnet) (12 ckpts) + + - \[ALGORITHM\] [ERFNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/erfnet) (1 ckpts) + + - \[ALGORITHM\] [FastFCN](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/fastfcn) (12 ckpts) + + - \[ALGORITHM\] [Fast-SCNN](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/fastscnn) (1 ckpts) + + - \[ALGORITHM\] [FCN](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/fcn) (41 ckpts) + + - \[ALGORITHM\] [GCNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/gcnet) (16 ckpts) + + - \[BACKBONE\] [HRNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/hrnet) (37 ckpts) + + - \[ALGORITHM\] [ICNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/icnet) (12 ckpts) + + - \[ALGORITHM\] [ISANet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/isanet) (16 ckpts) + + - \[ALGORITHM\] [K-Net](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/knet) (7 ckpts) + + - \[BACKBONE\] [MAE](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/mae) (1 ckpts) + + - \[ALGORITHM\] [Mask2Former](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/mask2former) (13 ckpts) + + - \[ALGORITHM\] [MaskFormer](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/maskformer) (4 ckpts) + + - \[BACKBONE\] [MobileNetV2](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/mobilenet_v2) (8 ckpts) + + - \[BACKBONE\] [MobileNetV3](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/mobilenet_v3) (4 ckpts) + + - \[ALGORITHM\] [NonLocal Net](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/nonlocal_net) (16 ckpts) + + - \[ALGORITHM\] [OCRNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/ocrnet) (24 ckpts) + + - \[ALGORITHM\] [PointRend](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/point_rend) (4 ckpts) + + - \[BACKBONE\] [PoolFormer](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/poolformer) (5 ckpts) + + - \[ALGORITHM\] [PSANet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/psanet) (16 ckpts) + + - \[ALGORITHM\] [PSPNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/pspnet) (54 ckpts) + + - \[BACKBONE\] [ResNeSt](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/resnest) (8 ckpts) + + - \[ALGORITHM\] [SegFormer](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/segformer) (13 ckpts) + + - \[ALGORITHM\] [Segmenter](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/segmenter) (5 ckpts) + + - \[ALGORITHM\] [Semantic FPN](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/sem_fpn) (4 ckpts) + + - \[ALGORITHM\] [SETR](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/setr) (7 ckpts) + + - \[ALGORITHM\] [STDC](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/stdc) (4 ckpts) + + - \[BACKBONE\] [Swin Transformer](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/swin) (6 ckpts) + + - \[BACKBONE\] [Twins](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/twins) (12 ckpts) + + - \[ALGORITHM\] [UNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/unet) (25 ckpts) + + - \[ALGORITHM\] [UPerNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/upernet) (16 ckpts) + + - \[BACKBONE\] [Vision Transformer](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/vit) (11 ckpts) diff --git a/docs/en/notes/changelog.md b/docs/en/notes/changelog.md index 963cd6945b..518bfb314e 100644 --- a/docs/en/notes/changelog.md +++ b/docs/en/notes/changelog.md @@ -1,5 +1,40 @@ # Changelog of v1.x +## v1.0.0rc6(03/03/2023) + +### Highlights + +- Support MMSegInferencer ([#2413](https://github.com/open-mmlab/mmsegmentation/pull/2413), [#2658](https://github.com/open-mmlab/mmsegmentation/pull/2658)) +- Support REFUGE dataset ([#2554](https://github.com/open-mmlab/mmsegmentation/pull/2554)) + +### Features + +- Support auto import modules from registry ([#2481](https://github.com/open-mmlab/mmsegmentation/pull/2481)) +- Replace numpy ascontiguousarray with torch contiguous to speed-up ([#2604](https://github.com/open-mmlab/mmsegmentation/pull/2604)) +- Add browse_dataset.py tool ([#2649](https://github.com/open-mmlab/mmsegmentation/pull/2649)) + +### Bug fix + +- Rename and Fix bug of projects HieraSeg ([#2565](https://github.com/open-mmlab/mmsegmentation/pull/2565)) +- Add out_channels in `CascadeEncoderDecoder` and update OCRNet and MobileNet v2 results ([#2656](https://github.com/open-mmlab/mmsegmentation/pull/2656)) + +### Documentation + +- Add dataflow documentation of Chinese version ([#2652](https://github.com/open-mmlab/mmsegmentation/pull/2652)) +- Add custmized runtime documentation of English version ([#2533](https://github.com/open-mmlab/mmsegmentation/pull/2533)) +- Add documentation for visualizing feature map using wandb backend ([#2557](https://github.com/open-mmlab/mmsegmentation/pull/2557)) +- Add documentation for benchmark results on NPU (HUAWEI Ascend) ([#2569](https://github.com/open-mmlab/mmsegmentation/pull/2569), [#2596](https://github.com/open-mmlab/mmsegmentation/pull/2596), [#2610](https://github.com/open-mmlab/mmsegmentation/pull/2610)) +- Fix api name error in the migration doc ([#2601](https://github.com/open-mmlab/mmsegmentation/pull/2601)) +- Refine projects documentation ([#2586](https://github.com/open-mmlab/mmsegmentation/pull/2586)) +- Refine MMSegmentation documentation ([#2668](https://github.com/open-mmlab/mmsegmentation/pull/2668), [#2659](https://github.com/open-mmlab/mmsegmentation/pull/2659)) + +### New Contributors + +- @zccjjj made their first contribution in https://github.com/open-mmlab/mmsegmentation/pull/2548 +- @liuruiqiang made their first contribution in https://github.com/open-mmlab/mmsegmentation/pull/2554 +- @wangjiangben-hw made their first contribution in https://github.com/open-mmlab/mmsegmentation/pull/2569 +- @jinxianwei made their first contribution in https://github.com/open-mmlab/mmsegmentation/pull/2557 + ## v1.0.0rc5(02/01/2023) ### Bug fix diff --git a/docs/en/notes/faq.md b/docs/en/notes/faq.md index bb09873cf0..fe5cac3834 100644 --- a/docs/en/notes/faq.md +++ b/docs/en/notes/faq.md @@ -1,4 +1,4 @@ -# Frequently Asked Questions (FAQ) +# \[WIP\] Frequently Asked Questions (FAQ) We list some common troubles faced by many users and their corresponding solutions here. Feel free to enrich the list if you find any frequent issues and have ways to help others to solve them. If the contents here do not cover your issue, please create an issue using the [provided templates](https://github.com/open-mmlab/mmsegmentation/blob/master/.github/ISSUE_TEMPLATE/error-report.md/) and make sure you fill in all required information in the template. @@ -8,16 +8,21 @@ The compatible MMSegmentation, MMCV and MMEngine versions are as below. Please i | MMSegmentation version | MMCV version | MMEngine version | MMClassification (optional) version | MMDetection (optional) version | | :--------------------: | :----------------------------: | :---------------: | :---------------------------------: | :----------------------------: | -| dev-1.x branch | mmcv >= 2.0.0rc4 | MMEngine >= 0.2.0 | mmcls>=1.0.0rc0 | mmdet>3.0.0rc5 | -| 1.x branch | mmcv >= 2.0.0rc4 | MMEngine >= 0.2.0 | mmcls>=1.0.0rc0 | mmdet>3.0.0rc5 | -| 1.0.0rc5 | mmcv >= 2.0.0rc4 | MMEngine >= 0.2.0 | mmcls>=1.0.0rc0 | mmdet>3.0.0rc5 | +| dev-1.x branch | mmcv >= 2.0.0rc4 | MMEngine >= 0.5.0 | mmcls>=1.0.0rc0 | mmdet >= 3.0.0rc6 | +| 1.x branch | mmcv >= 2.0.0rc4 | MMEngine >= 0.5.0 | mmcls>=1.0.0rc0 | mmdet >= 3.0.0rc6 | +| 1.0.0rc6 | mmcv >= 2.0.0rc4 | MMEngine >= 0.5.0 | mmcls>=1.0.0rc0 | mmdet >= 3.0.0rc6 | +| 1.0.0rc5 | mmcv >= 2.0.0rc4 | MMEngine >= 0.2.0 | mmcls>=1.0.0rc0 | mmdet>=3.0.0rc6 | | 1.0.0rc4 | mmcv == 2.0.0rc3 | MMEngine >= 0.1.0 | mmcls>=1.0.0rc0 | mmdet>=3.0.0rc4, \<=3.0.0rc5 | | 1.0.0rc3 | mmcv == 2.0.0rc3 | MMEngine >= 0.1.0 | mmcls>=1.0.0rc0 | mmdet>=3.0.0rc4 \<=3.0.0rc5 | | 1.0.0rc2 | mmcv == 2.0.0rc3 | MMEngine >= 0.1.0 | mmcls>=1.0.0rc0 | mmdet>=3.0.0rc4 \<=3.0.0rc5 | | 1.0.0rc1 | mmcv >= 2.0.0rc1, \<=2.0.0rc3> | MMEngine >= 0.1.0 | mmcls>=1.0.0rc0 | Not required | | 1.0.0rc0 | mmcv >= 2.0.0rc1, \<=2.0.0rc3> | MMEngine >= 0.1.0 | mmcls>=1.0.0rc0 | Not required | -Notes: To install MMSegmentation 0.x and master branch, please refer to [the faq 0.x document](https://mmsegmentation.readthedocs.io/en/latest/faq.html#installation) to check compatible versions of MMCV. +Notes: + +- MMClassification and MMDetatction are optional for MMSegmentation. If you didn't install them, `ConvNeXt` (required MMClassification) and MaskFormer, Mask2Former (required MMDetection) cannot be used. We recommend to install them with source code. Please refer to [MMClasssication](https://github.com/open-mmlab/mmclassification) and [MMDetection](https://github.com/open-mmlab/mmdetection) for more details about their installation. + +- To install MMSegmentation 0.x and master branch, please refer to [the faq 0.x document](https://mmsegmentation.readthedocs.io/en/latest/faq.html#installation) to check compatible versions of MMCV. ## How to know the number of GPUs needed to train the model diff --git a/docs/en/user_guides/2_dataset_prepare.md b/docs/en/user_guides/2_dataset_prepare.md index e9c7683dc0..5d36061d89 100644 --- a/docs/en/user_guides/2_dataset_prepare.md +++ b/docs/en/user_guides/2_dataset_prepare.md @@ -145,6 +145,15 @@ mmsegmentation │ │ ├── ann_dir │ │ │ ├── train │ │ │ ├── val +│ ├── REFUGE +│ │ ├── images +│ │ │ ├── training +│ │ │ ├── validation +│ │ │ ├── test +│ │ ├── annotations +│ │ │ ├── training +│ │ │ ├── validation +│ │ │ ├── test ``` ### Cityscapes @@ -330,7 +339,7 @@ For Potsdam dataset, please run the following command to download and re-organiz python tools/dataset_converters/potsdam.py /path/to/potsdam ``` -In our default setting, it will generate 3,456 images for training and 2,016 images for validation. +In our default setting, it will generate 3456 images for training and 2016 images for validation. ### ISPRS Vaihingen @@ -383,7 +392,7 @@ You may need to follow the following structure for dataset preparation after dow python tools/dataset_converters/isaid.py /path/to/iSAID ``` -In our default setting (`patch_width`=896, `patch_height`=896, `overlap_area`=384), it will generate 33,978 images for training and 11,644 images for validation. +In our default setting (`patch_width`=896, `patch_height`=896, `overlap_area`=384), it will generate 33978 images for training and 11644 images for validation. ## LIP(Look Into Person) dataset @@ -436,7 +445,7 @@ cd ./RawData/Training Then create `train.txt` and `val.txt` to split dataset. -According to TransUNet, the following is the data set division. +According to TransUnet, the following is the data set division. train.txt @@ -500,7 +509,45 @@ Then, use this command to convert synapse dataset. python tools/dataset_converters/synapse.py --dataset-path /path/to/synapse ``` -In our default setting, it will generate 2,211 2D images for training and 1,568 2D images for validation. - Noted that MMSegmentation default evaluation metric (such as mean dice value) is calculated on 2D slice image, which is not comparable to results of 3D scan in some paper such as [TransUNet](https://arxiv.org/abs/2102.04306). + +### REFUGE + +Register in [REFUGE Challenge](https://refuge.grand-challenge.org) and download [REFUGE dataset](https://refuge.grand-challenge.org/REFUGE2Download). + +Then, unzip `REFUGE2.zip` and the contents of original datasets include: + +```none +├── REFUGE2 +│ ├── REFUGE2 +│ │ ├── Annotation-Training400.zip +│ │ ├── REFUGE-Test400.zip +│ │ ├── REFUGE-Test-GT.zip +│ │ ├── REFUGE-Training400.zip +│ │ ├── REFUGE-Validation400.zip +│ │ ├── REFUGE-Validation400-GT.zip +│ ├── __MACOSX +``` + +Please run the following command to convert REFUGE dataset: + +```shell +python tools/convert_datasets/refuge.py --raw_data_root=/path/to/refuge/REFUGE2/REFUGE2 +``` + +The script will make directory structure below: + +```none +│ ├── REFUGE +│ │ ├── images +│ │ │ ├── training +│ │ │ ├── validation +│ │ │ ├── test +│ │ ├── annotations +│ │ │ ├── training +│ │ │ ├── validation +│ │ │ ├── test +``` + +It includes 400 images for training, 400 images for validation and 400 images for testing which is the same as REFUGE 2018 dataset. diff --git a/docs/en/user_guides/3_inference.md b/docs/en/user_guides/3_inference.md index 6b6f6f7f3b..c9f4e62f10 100644 --- a/docs/en/user_guides/3_inference.md +++ b/docs/en/user_guides/3_inference.md @@ -4,13 +4,132 @@ MMSegmentation provides pre-trained models for semantic segmentation in [Model Z This note will show how to use existing models to inference on given images. As for how to test existing models on standard datasets, please see this [guide](./4_train_test.md) -## Inference API - MMSegmentation provides several interfaces for users to easily use pre-trained models for inference. -- [mmseg.apis.init_model](#mmsegapisinit_model) -- [mmseg.apis.inference_model](#mmsegapisinference_model) -- [mmseg.apis.show_result_pyplot](#mmsegapisshow_result_pyplot) +- [Tutorial 3: Inference with existing models](#tutorial-3-inference-with-existing-models) + - [Inferencer](#inferencer) + - [Basic Usage](#basic-usage) + - [Initialization](#initialization) + - [Visualize prediction](#visualize-prediction) + - [List model](#list-model) + - [Inference API](#inference-api) + - [mmseg.apis.init_model](#mmsegapisinit_model) + - [mmseg.apis.inference_model](#mmsegapisinference_model) + - [mmseg.apis.show_result_pyplot](#mmsegapisshow_result_pyplot) + +## Inferencer + +We provides the most **convenient** way to use the model in MMSegmentation `MMSegInferencer`. You can get segmentation mask for an image with only 3 lines of code. + +### Basic Usage + +The following example shows how to use `MMSegInferencer` to perform inference on a single image. + +``` +>>> from mmseg.apis import MMSegInferencer +>>> # Load models into memory +>>> inferencer = MMSegInferencer(model='deeplabv3plus_r18-d8_4xb2-80k_cityscapes-512x1024') +>>> # Inference +>>> inferencer('demo/demo.png', show=True) +``` + +The visualization result should look like: + +
+https://user-images.githubusercontent.com/76149310/221507927-ae01e3a7-016f-4425-b966-7b19cbbe494e.png +
+ +Moreover, you can use `MMSegInferencer` to process a list of images: + +``` +# Input a list of images +>>> images = [image1, image2, ...] # image1 can be a file path or a np.ndarray +>>> inferencer(images, show=True, wait_time=0.5) # wait_time is delay time, and 0 means forever. + +# Or input image directory +>>> images = $IMAGESDIR +>>> inferencer(images, show=True, wait_time=0.5) + +# Save visualized rendering color maps and predicted results +# out_dir is the directory to save the output results, img_out_dir and pred_out_dir are subdirectories of out_dir +# to save visualized rendering color maps and predicted results +>>> inferencer(images, out_dir='outputs', img_out_dir='vis', pred_out_dir='pred') +``` + +There is a optional parameter of inferencer, `return_datasamples`, whose default value is False, and +return value of inferencer is a `dict` type by default, including 2 keys 'visualization' and 'predictions'. +If `return_datasamples=True` inferencer will return [`SegDataSample`](../advanced_guides/structures.md), or list of it. + +``` +result = inferencer('demo/demo.png') +# result is a `dict` including 2 keys 'visualization' and 'predictions'. +# 'visualization' includes color segmentation map +print(result['visualization'].shape) +# (512, 683, 3) + +# 'predictions' includes segmentation mask with label indice +print(result['predictions'].shape) +# (512, 683) + +result = inferencer('demo/demo.png', return_datasamples=True) +print(type(result)) +# + +# Input a list of images +results = inferencer(images) +# The output is list +print(type(results['visualization']), results['visualization'][0].shape) +# (512, 683, 3) +print(type(results['predictions']), results['predictions'][0].shape) +# (512, 683) + +results = inferencer(images, return_datasamples=True) +# +print(type(results[0])) +# +``` + +### Initialization + +`MMSegInferencer` must be initialized from a `model`, which can be a model name or a `Config` even a path of config file. +The model names can be found in models' metafile, like one model name of maskformer is `maskformer_r50-d32_8xb2-160k_ade20k-512x512`, and if input model name and the weights of the model will be download automatically. Below are other input parameters: + +- weights (str, optional) - Path to the checkpoint. If it is not specified and model is a model name of metafile, the weights will be loaded + from metafile. Defaults to None. +- classes (list, optional) - Input classes for result rendering, as the prediction of segmentation + model is a segment map with label indices, `classes` is a list which includes + items responding to the label indices. If classes is not defined, visualizer will take `cityscapes` classes by default. Defaults to None. +- palette (list, optional) - Input palette for result rendering, which is a list of color palette + responding to the classes. If palette is not defined, visualizer will take `cityscapes` palette by default. Defaults to None. +- dataset_name (str, optional)[Dataset name or alias](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/mmseg/utils/class_names.py#L302-L317) + visulizer will use the meta information of the dataset i.e. classes and palette, + but the `classes` and `palette` have higher priority. Defaults to None. +- device (str, optional) - Device to run inference. If None, the available device will be automatically used. Defaults to None. +- scope (str, optional) - The scope of the model. Defaults to 'mmseg'. + +### Visualize prediction + +`MMSegInferencer` supports 4 parameters for visualize prediction, you can use them when call initialized inferencer: + +- show (bool) - Whether to display the image in a popup window. Defaults to False. +- wait_time (float) - The interval of show (s). Defaults to 0. +- img_out_dir (str) - Subdirectory of `out_dir`, used to save rendering color segmentation mask, so `out_dir` must be defined + if you would like to save predicted mask. Defaults to 'vis'. +- opacity (int, float) - The transparency of segmentation mask. Defaults to 0.8. + +The examples of these parameters is in [Basic Usage](#basic-usage) + +### List model + +There is a very easy to list all model names in MMSegmentation + +``` +>>> from mmseg.apis import MMSegInferencer +# models is a list of model names, and them will print automatically +>>> models = MMSegInferencer.list_models('mmseg') +``` + +## Inference API ### mmseg.apis.init_model @@ -31,14 +150,10 @@ Example: ```python from mmseg.apis import init_model -from mmseg.utils import register_all_modules config_path = 'configs/pspnet/pspnet_r50-d8_4xb2-40k_cityscapes-512x1024.py' checkpoint_path = 'checkpoints/pspnet_r50-d8_512x1024_40k_cityscapes_20200605_003338-2966598c.pth' -# register all modules in mmseg into the registries -register_all_modules() - # initialize model without checkpoint model = init_model(config_path) @@ -76,14 +191,11 @@ Example: ```python from mmseg.apis import init_model, inference_model -from mmseg.utils import register_all_modules config_path = 'configs/pspnet/pspnet_r50-d8_4xb2-40k_cityscapes-512x1024.py' checkpoint_path = 'checkpoints/pspnet_r50-d8_512x1024_40k_cityscapes_20200605_003338-2966598c.pth' img_path = 'demo/demo.png' -# register all modules in mmseg into the registries -register_all_modules() model = init_model(config_path, checkpoint_path) result = inference_model(model, img_path) @@ -115,14 +227,11 @@ Example: ```python from mmseg.apis import init_model, inference_model, show_result_pyplot -from mmseg.utils import register_all_modules config_path = 'configs/pspnet/pspnet_r50-d8_4xb2-40k_cityscapes-512x1024.py' checkpoint_path = 'checkpoints/pspnet_r50-d8_512x1024_40k_cityscapes_20200605_003338-2966598c.pth' img_path = 'demo/demo.png' -# register all modules in mmseg into the registries -register_all_modules() # build the model from a config file and a checkpoint file model = init_model(config_path, checkpoint_path, device='cuda:0') diff --git a/docs/en/user_guides/deployment.md b/docs/en/user_guides/deployment.md index 036db997da..a23f4b404b 100644 --- a/docs/en/user_guides/deployment.md +++ b/docs/en/user_guides/deployment.md @@ -1,4 +1,4 @@ -# Deployment +# \[WIP\] Deployment > ## [Try the new MMDeploy to deploy your model](https://mmdeploy.readthedocs.io/) diff --git a/docs/en/user_guides/useful_tools.md b/docs/en/user_guides/useful_tools.md index 128397b804..0d8677854b 100644 --- a/docs/en/user_guides/useful_tools.md +++ b/docs/en/user_guides/useful_tools.md @@ -1,4 +1,4 @@ -# Useful Tools +# \[WIP\] Useful Tools Apart from training/testing scripts, We provide lots of useful tools under the `tools/` directory. diff --git a/docs/zh_cn/advanced_guides/add_datasets.md b/docs/zh_cn/advanced_guides/add_datasets.md index 512df8b983..4ea14934ed 100644 --- a/docs/zh_cn/advanced_guides/add_datasets.md +++ b/docs/zh_cn/advanced_guides/add_datasets.md @@ -1,4 +1,4 @@ -# 自定义数据集(待更新) +# 新增自定义数据集(待更新) ## 通过重新组织数据来定制数据集 diff --git a/docs/zh_cn/advanced_guides/add_metric.md b/docs/zh_cn/advanced_guides/add_metric.md deleted file mode 100644 index dfd94487d1..0000000000 --- a/docs/zh_cn/advanced_guides/add_metric.md +++ /dev/null @@ -1 +0,0 @@ -# 添加评测指标 diff --git a/docs/zh_cn/advanced_guides/add_metrics.md b/docs/zh_cn/advanced_guides/add_metrics.md new file mode 100644 index 0000000000..3a371e357e --- /dev/null +++ b/docs/zh_cn/advanced_guides/add_metrics.md @@ -0,0 +1 @@ +# 新增评测指标 (待更新) diff --git a/docs/zh_cn/advanced_guides/add_models.md b/docs/zh_cn/advanced_guides/add_models.md new file mode 100644 index 0000000000..3f86a0c7c6 --- /dev/null +++ b/docs/zh_cn/advanced_guides/add_models.md @@ -0,0 +1,3 @@ +# 新增模块(待更新) + +中文版文档支持中,请先阅读[英文版本](../../en/advanced_guides/add_models.md) diff --git a/docs/zh_cn/advanced_guides/add_modules.md b/docs/zh_cn/advanced_guides/add_modules.md deleted file mode 100644 index e20dadd242..0000000000 --- a/docs/zh_cn/advanced_guides/add_modules.md +++ /dev/null @@ -1,230 +0,0 @@ -# 自定义模型(待更新) - -## 自定义优化器 (optimizer) - -假设您想增加一个新的叫 `MyOptimizer` 的优化器,它的参数分别为 `a`, `b`, 和 `c`。 -您首先需要在一个文件里实现这个新的优化器,例如在 `mmseg/core/optimizer/my_optimizer.py` 里面: - -```python -from mmcv.runner import OPTIMIZERS -from torch.optim import Optimizer - - -@OPTIMIZERS.register_module -class MyOptimizer(Optimizer): - - def __init__(self, a, b, c) - -``` - -然后增加这个模块到 `mmseg/core/optimizer/__init__.py` 里面,这样注册器 (registry) 将会发现这个新的模块并添加它: - -```python -from .my_optimizer import MyOptimizer -``` - -之后您可以在配置文件的 `optimizer` 域里使用 `MyOptimizer`, -如下所示,在配置文件里,优化器被 `optimizer` 域所定义: - -```python -optimizer = dict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.0001) -``` - -为了使用您自己的优化器,域可以被修改为: - -```python -optimizer = dict(type='MyOptimizer', a=a_value, b=b_value, c=c_value) -``` - -我们已经支持了 PyTorch 自带的全部优化器,唯一修改的地方是在配置文件里的 `optimizer` 域。例如,如果您想使用 `ADAM`,尽管数值表现会掉点,还是可以如下修改: - -```python -optimizer = dict(type='Adam', lr=0.0003, weight_decay=0.0001) -``` - -使用者可以直接按照 PyTorch [文档教程](https://pytorch.org/docs/stable/optim.html?highlight=optim#module-torch.optim) 去设置参数。 - -## 定制优化器的构造器 (optimizer constructor) - -对于优化,一些模型可能会有一些特别定义的参数,例如批归一化 (BatchNorm) 层里面的权重衰减 (weight decay)。 -使用者可以通过定制优化器的构造器来微调这些细粒度的优化器参数。 - -```python -from mmcv.utils import build_from_cfg - -from mmcv.runner import OPTIMIZER_BUILDERS -from .cocktail_optimizer import CocktailOptimizer - - -@OPTIMIZER_BUILDERS.register_module -class CocktailOptimizerConstructor(object): - - def __init__(self, optim_wrapper_cfg, paramwise_cfg=None): - - def __call__(self, model): - - return my_optimizer - -``` - -## 开发和增加新的组件(Module) - -MMSegmentation 里主要有2种组件: - -- 主干网络 (backbone): 通常是卷积网络的堆叠,来做特征提取,例如 ResNet, HRNet -- 解码头 (decoder head): 用于语义分割图的解码的组件(得到分割结果) - -### 添加新的主干网络 - -这里我们以 MobileNet 为例,展示如何增加新的主干组件: - -1. 创建一个新的文件 `mmseg/models/backbones/mobilenet.py` - -```python -import torch.nn as nn - -from ..registry import BACKBONES - - -@BACKBONES.register_module -class MobileNet(nn.Module): - - def __init__(self, arg1, arg2): - pass - - def forward(self, x): # should return a tuple - pass - - def init_weights(self, pretrained=None): - pass -``` - -2. 在 `mmseg/models/backbones/__init__.py` 里面导入模块 - -```python -from .mobilenet import MobileNet -``` - -3. 在您的配置文件里使用它 - -```python -model = dict( - ... - backbone=dict( - type='MobileNet', - arg1=xxx, - arg2=xxx), - ... -``` - -### 增加新的解码头 (decoder head)组件 - -在 MMSegmentation 里面,对于所有的分割头,我们提供一个基类解码头 [BaseDecodeHead](https://github.com/open-mmlab/mmsegmentation/blob/master/mmseg/models/decode_heads/decode_head.py) 。 -所有新建的解码头都应该继承它。这里我们以 [PSPNet](https://arxiv.org/abs/1612.01105) 为例, -展示如何开发和增加一个新的解码头组件: - -首先,在 `mmseg/models/decode_heads/psp_head.py` 里添加一个新的解码头。 -PSPNet 中实现了一个语义分割的解码头。为了实现一个解码头,我们只需要在新构造的解码头中实现如下的3个函数: - -```python -@HEADS.register_module() -class PSPHead(BaseDecodeHead): - - def __init__(self, pool_scales=(1, 2, 3, 6), **kwargs): - super(PSPHead, self).__init__(**kwargs) - - def init_weights(self): - - def forward(self, inputs): - -``` - -接着,使用者需要在 `mmseg/models/decode_heads/__init__.py` 里面添加这个模块,这样对应的注册器 (registry) 可以查找并加载它们。 - -PSPNet的配置文件如下所示: - -```python -norm_cfg = dict(type='SyncBN', requires_grad=True) -model = dict( - type='EncoderDecoder', - pretrained='pretrain_model/resnet50_v1c_trick-2cccc1ad.pth', - backbone=dict( - type='ResNetV1c', - depth=50, - num_stages=4, - out_indices=(0, 1, 2, 3), - dilations=(1, 1, 2, 4), - strides=(1, 2, 1, 1), - norm_cfg=norm_cfg, - norm_eval=False, - style='pytorch', - contract_dilation=True), - decode_head=dict( - type='PSPHead', - in_channels=2048, - in_index=3, - channels=512, - pool_scales=(1, 2, 3, 6), - 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))) - -``` - -### 增加新的损失函数 - -假设您想添加一个新的损失函数 `MyLoss` 到语义分割解码器里。 -为了添加一个新的损失函数,使用者需要在 `mmseg/models/losses/my_loss.py` 里面去实现它。 -`weighted_loss` 可以对计算损失时的每个样本做加权。 - -```python -import torch -import torch.nn as nn - -from ..builder import LOSSES -from .utils import weighted_loss - -@weighted_loss -def my_loss(pred, target): - assert pred.size() == target.size() and target.numel() > 0 - loss = torch.abs(pred - target) - return loss - -@LOSSES.register_module -class MyLoss(nn.Module): - - def __init__(self, reduction='mean', loss_weight=1.0): - super(MyLoss, self).__init__() - self.reduction = reduction - self.loss_weight = loss_weight - - def forward(self, - pred, - target, - weight=None, - avg_factor=None, - reduction_override=None): - assert reduction_override in (None, 'none', 'mean', 'sum') - reduction = ( - reduction_override if reduction_override else self.reduction) - loss = self.loss_weight * my_loss( - pred, target, weight, reduction=reduction, avg_factor=avg_factor) - return loss -``` - -然后使用者需要在 `mmseg/models/losses/__init__.py` 里面添加它: - -```python -from .my_loss import MyLoss, my_loss - -``` - -为了使用它,修改 `loss_xxx` 域。之后您需要在解码头组件里修改 `loss_decode` 域。 -`loss_weight` 可以被用来对不同的损失函数做加权。 - -```python -loss_decode=dict(type='MyLoss', loss_weight=1.0)) -``` diff --git a/docs/zh_cn/advanced_guides/add_transforms.md b/docs/zh_cn/advanced_guides/add_transforms.md index 2fa55f0c05..58a2485e04 100644 --- a/docs/zh_cn/advanced_guides/add_transforms.md +++ b/docs/zh_cn/advanced_guides/add_transforms.md @@ -1,166 +1,3 @@ -# 自定义数据流程(待更新) +# 新增数据增强(待更新) -## 数据流程的设计 - -按照通常的惯例,我们使用 `Dataset` 和 `DataLoader` 做多线程的数据加载。`Dataset` 返回一个数据内容的字典,里面对应于模型前传方法的各个参数。 -因为在语义分割中,输入的图像数据具有不同的大小,我们在 MMCV 里引入一个新的 `DataContainer` 类别去帮助收集和分发不同大小的输入数据。 - -更多细节,请查看[这里](https://github.com/open-mmlab/mmcv/blob/master/mmcv/parallel/data_container.py) 。 - -数据的准备流程和数据集是解耦的。通常一个数据集定义了如何处理标注数据(annotations)信息,而一个数据流程定义了准备一个数据字典的所有步骤。一个流程包括了一系列操作,每个操作里都把一个字典作为输入,然后再输出一个新的字典给下一个变换操作。 - -这些操作可分为数据加载 (data loading),预处理 (pre-processing),格式变化 (formatting) 和测试时数据增强 (test-time augmentation)。 - -下面的例子就是 PSPNet 的一个流程: - -```python -img_norm_cfg = dict( - mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True) -crop_size = (512, 1024) -train_pipeline = [ - dict(type='LoadImageFromFile'), - dict(type='LoadAnnotations'), - dict(type='Resize', img_scale=(2048, 1024), ratio_range=(0.5, 2.0)), - dict(type='RandomCrop', crop_size=crop_size, cat_max_ratio=0.75), - dict(type='RandomFlip', flip_ratio=0.5), - dict(type='PhotoMetricDistortion'), - dict(type='Normalize', **img_norm_cfg), - dict(type='Pad', size=crop_size, pad_val=0, seg_pad_val=255), - dict(type='DefaultFormatBundle'), - dict(type='Collect', keys=['img', 'gt_semantic_seg']), -] -test_pipeline = [ - dict(type='LoadImageFromFile'), - dict( - type='MultiScaleFlipAug', - img_scale=(2048, 1024), - # img_ratios=[0.5, 0.75, 1.0, 1.25, 1.5, 1.75], - flip=False, - transforms=[ - dict(type='Resize', keep_ratio=True), - dict(type='RandomFlip'), - dict(type='Normalize', **img_norm_cfg), - dict(type='ImageToTensor', keys=['img']), - dict(type='Collect', keys=['img']), - ]) -] -``` - -对于每个操作,我们列出它添加、更新、移除的相关字典域 (dict fields): - -### 数据加载 Data loading - -`LoadImageFromFile` - -- 增加: img, img_shape, ori_shape - -`LoadAnnotations` - -- 增加: gt_semantic_seg, seg_fields - -### 预处理 Pre-processing - -`Resize` - -- 增加: scale, scale_idx, pad_shape, scale_factor, keep_ratio -- 更新: img, img_shape, \*seg_fields - -`RandomFlip` - -- 增加: flip -- 更新: img, \*seg_fields - -`Pad` - -- 增加: pad_fixed_size, pad_size_divisor -- 更新: img, pad_shape, \*seg_fields - -`RandomCrop` - -- 更新: img, pad_shape, \*seg_fields - -`Normalize` - -- 增加: img_norm_cfg -- 更新: img - -`SegRescale` - -- 更新: gt_semantic_seg - -`PhotoMetricDistortion` - -- 更新: img - -### 格式 Formatting - -`ToTensor` - -- 更新: 由 `keys` 指定 - -`ImageToTensor` - -- 更新: 由 `keys` 指定 - -`Transpose` - -- 更新: 由 `keys` 指定 - -`ToDataContainer` - -- 更新: 由 `keys` 指定 - -`DefaultFormatBundle` - -- 更新: img, gt_semantic_seg - -`Collect` - -- 增加: img_meta (the keys of img_meta is specified by `meta_keys`) -- 移除: all other keys except for those specified by `keys` - -### 测试时数据增强 Test time augmentation - -`MultiScaleFlipAug` - -## 拓展和使用自定义的流程 - -1. 在任何一个文件里写一个新的流程,例如 `my_pipeline.py`,它以一个字典作为输入并且输出一个字典 - - ```python - from mmseg.datasets import PIPELINES - - @PIPELINES.register_module() - class MyTransform: - - def __call__(self, results): - results['dummy'] = True - return results - ``` - -2. 导入一个新类 - - ```python - from .my_pipeline import MyTransform - ``` - -3. 在配置文件里使用它 - - ```python - img_norm_cfg = dict( - mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True) - crop_size = (512, 1024) - train_pipeline = [ - dict(type='LoadImageFromFile'), - dict(type='LoadAnnotations'), - dict(type='Resize', img_scale=(2048, 1024), ratio_range=(0.5, 2.0)), - dict(type='RandomCrop', crop_size=crop_size, cat_max_ratio=0.75), - dict(type='RandomFlip', flip_ratio=0.5), - dict(type='PhotoMetricDistortion'), - dict(type='Normalize', **img_norm_cfg), - dict(type='Pad', size=crop_size, pad_val=0, seg_pad_val=255), - dict(type='MyTransform'), - dict(type='DefaultFormatBundle'), - dict(type='Collect', keys=['img', 'gt_semantic_seg']), - ] - ``` +中文版文档支持中,请先阅读[英文版本](../../en/advanced_guides/add_transform.md) diff --git a/docs/zh_cn/advanced_guides/data_flow.md b/docs/zh_cn/advanced_guides/data_flow.md index 960b4e6586..0716d36d1b 100644 --- a/docs/zh_cn/advanced_guides/data_flow.md +++ b/docs/zh_cn/advanced_guides/data_flow.md @@ -1 +1,90 @@ # 数据流 + +在本章节中,我们将介绍 [Runner](https://mmengine.readthedocs.io/zh_CN/latest/tutorials/runner.html) 管理的内部模块之间的数据流和数据格式约定。 + +## 数据流概述 + +[Runner](https://github.com/open-mmlab/mmengine/blob/main/docs/zh_cn/design/runner.md) 相当于 MMEngine 中的“集成器”。它覆盖了框架的所有方面,并肩负着组织和调度几乎所有模块的责任,这意味着各模块之间的数据流也由 `Runner` 控制。 如 [MMEngine 中的 Runner 文档](https://mmengine.readthedocs.io/zh_CN/latest/tutorials/runner.html)所示,下图展示了基本的数据流。 + +![Basic dataflow](https://user-images.githubusercontent.com/112053249/199228350-5f80699e-7fd2-4b4c-ac32-0b16b1922c2e.png) + +虚线边框、灰色填充形状代表不同的数据格式,而实心框表示模块/方法。由于 MMEngine 极大的灵活性和可扩展性,一些重要的基类可以被继承,并且它们的方法可以被覆写。 上图所示数据流仅适用于当用户没有自定义 `Runner` 中的 `TrainLoop`、`ValLoop` 和 `TestLoop`,并且没有在其自定义模型中覆写 `train_step`、`val_step` 和 `test_step` 方法时。MMSegmentation 中 loop 的默认设置如下:使用`IterBasedTrainLoop` 训练模型,共计 20000 次迭代,并且在每 2000 次迭代后进行一次验证。 + +```python +train_cfg = dict(type='IterBasedTrainLoop', max_iters=20000, val_interval=2000) +val_cfg = dict(type='ValLoop') +test_cfg = dict(type='TestLoop') +``` + +在上图中,红色线表示 [train_step](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/docs/en/advanced_guides/models.md#train_step) ***([中文链接待更新](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/docs/zh_cn/advanced_guides/models.md#train_step))*** ,在每次训练迭代中,数据加载器(dataloader)从存储中加载图像并传输到数据预处理器(data preprocessor),数据预处理器会将图像放到特定的设备上,并将数据堆叠到批处理中,之后模型接受批处理数据作为输入,最后将模型的输出发送给优化器(optimizer)。蓝色线表示 [val_step](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/docs/en/advanced_guides/models.md#val_step) 和 [test_step](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/docs/en/advanced_guides/models.md#test_step) ***([中文链接待更新](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/docs/zh_cn/advanced_guides/models.md#test_step))*** 。这两个过程的数据流除了模型输出与 `train_step` 不同外,其余均和 `train_step` 类似。由于在评估时模型参数会被冻结,因此模型的输出将被传递给 [Evaluator](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/docs/en/advanced_guides/evaluation.md#ioumetric) ***([中文链接待更新](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/docs/zh_cn/advanced_guides/evaluation.md#ioumetric))*** +来计算指标。 + +## MMSegmentation 中的数据流约定 + +在上面的图中,我们可以看到基本的数据流。在本节中,我们将分别介绍数据流中涉及的数据的格式约定。 + +### 数据加载器到数据预处理器 + +数据加载器(DataLoader)是 MMEngine 的训练和测试流程中的一个重要组件。 +从概念上讲,它源于 [PyTorch](https://pytorch.org/) 并保持一致。DataLoader 从文件系统加载数据,原始数据通过数据准备流程后被发送给数据预处理器。 + +MMSegmentation 在 [PackSegInputs](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/mmseg/datasets/transforms/formatting.py#L12) 中定义了默认数据格式, 它是 `train_pipeline` 和 `test_pipeline` 的最后一个组件。有关数据转换 `pipeline` 的更多信息,请参阅[数据转换文档](https://mmsegmentation.readthedocs.io/en/dev-1.x/advanced_guides/transforms.html)。 ***([中文链接待更新](https://mmsegmentation.readthedocs.io/zh_CN/dev-1.x/advanced_guides/transforms.html))*** + +在没有任何修改的情况下,PackSegInputs 的返回值通常是一个包含 `inputs` 和 `data_samples` 的 `dict`。以下伪代码展示了 mmseg 中数据加载器输出的数据类型,它是从数据集中获取的一批数据样本,数据加载器将它们打包成一个字典列表。`inputs` 是输入进模型的张量列表,`data_samples` 包含了输入图像的 meta information 和相应的 ground truth。 + +```python +dict( + inputs=List[torch.Tensor], + data_samples=List[SegDataSample] +) +``` + +**注意:** [SegDataSample](https://github.com/open-mmlab/mmsegmentation/blob/1.x/mmseg/structures/seg_data_sample.py) 是 MMSegmentation 的数据结构接口,用于连接不同组件。`SegDataSample` 实现了抽象数据元素 `mmengine.structures.BaseDataElement`,更多信息请在 [MMEngine](https://github.com/open-mmlab/mmengine) 中参阅 [SegDataSample 文档](https://mmsegmentation.readthedocs.io/zh_CN/1.x/advanced_guides/structures.html)和[数据元素文档](https://mmengine.readthedocs.io/zh_CN/latest/advanced_tutorials/data_element.html)。 + +### 数据预处理器到模型 + +虽然在[上面的图](##数据流概述)中分开绘制了数据预处理器和模型,但数据预处理器是模型的一部分,因此可以在[模型教程](https://mmsegmentation.readthedocs.io/en/dev-1.x/advanced_guides/models.html)中找到数据预处理器章节。 ***([中文链接待更新](https://mmsegmentation.readthedocs.io/zh_CN/dev-1.x/advanced_guides/models.html))*** + +数据预处理器的返回值是一个包含 `inputs` 和 `data_samples` 的字典,其中 `inputs` 是批处理图像的 4D 张量,`data_samples` 中添加了一些用于数据预处理的额外元信息。当传递给网络时,字典将被解包为两个值。 以下伪代码展示了数据预处理器的返回值和模型的输入值。 + +```python +dict( + inputs=torch.Tensor, + data_samples=List[SegDataSample] +) +``` + +```python +class Network(BaseSegmentor): + + def forward(self, inputs: torch.Tensor, data_samples: List[SegDataSample], mode: str): + pass +``` + +**注意:** 模型的前向传播有 3 种模式,由输入参数 mode 控制,更多信息请参阅[模型教程](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/docs/en/advanced_guides/models.md)。 ***([中文链接待更新](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/docs/zh_cn/advanced_guides/models.md))*** + +### 模型输出 + +如[模型教程](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/docs/en/advanced_guides/models.md#forward) ***([中文链接待更新](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/docs/zh_cn/advanced_guides/models.md#forward))*** 所提到的 3 种前向传播具有 3 种输出。 +`train_step` 和 `test_step`(或 `val_step`)分别对应于 `'loss'` 和 `'predict'`。 + +在 `test_step` 或 `val_step` 中,推理结果会被传递给 `Evaluator` 。您可以参阅[评估文档](https://mmsegmentation.readthedocs.io/en/dev-1.x/advanced_guides/evaluation.html) ***([中文链接待更新](https://mmsegmentation.readthedocs.io/zh_CN/dev-1.x/advanced_guides/evaluation.html))*** 来获取更多关于 `Evaluator` 的信息。 + +在推理后,MMSegmentation 中的 [BaseSegmentor](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/mmseg/models/segmentors/base.py#L15) 会对推理结果进行简单的后处理以打包推理结果。神经网络生成的分割 logits,经过 `argmax` 操作后的分割 mask 和 ground truth(如果存在)将被打包到类似 `SegDataSample` 的实例。 [postprocess_result](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/mmseg/models/segmentors/base.py#L132) 的返回值是一个 **`SegDataSample`的`List`**。下图显示了这些 `SegDataSample` 实例的关键属性。 + +![SegDataSample](https://user-images.githubusercontent.com/15952744/209912225-ab46a8d9-904a-43cb-8bf1-8bec4938ed29.png) + +与数据预处理器一致,损失函数也是模型的一部分,它是[解码头](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/mmseg/models/decode_heads/decode_head.py#L142)的属性之一。 + +在 MMSegmentation 中,`decode_head` 的 [loss_by_feat](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/mmseg/models/decode_heads/decode_head.py#L291) 方法是用于计算损失的统一接口。 + +参数: + +- seg_logits (Tensor):解码头前向函数的输出 +- batch_data_samples (List\[SegDataSample\]):分割数据样本,通常包括如 `metainfo` 和 `gt_sem_seg` 等信息 + +返回值: + +- dict\[str, Tensor\]:一个损失组件的字典 + +**注意:** `train_step` 将损失传递进 OptimWrapper 以更新模型中的权重,更多信息请参阅 [train_step](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/docs/en/advanced_guides/models.md#train_step)。 ***([中文链接待更新](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/docs/zh_cn/advanced_guides/models.md#train_step))*** diff --git a/docs/zh_cn/advanced_guides/datasets.md b/docs/zh_cn/advanced_guides/datasets.md index 0f3ad2b682..546e97f70d 100644 --- a/docs/zh_cn/advanced_guides/datasets.md +++ b/docs/zh_cn/advanced_guides/datasets.md @@ -9,9 +9,10 @@ 实例化 Cityscapes 训练数据集: ```python +from mmengine.registry import init_default_scope from mmseg.datasets import CityscapesDataset -from mmseg.utils import register_all_modules -register_all_modules() + +init_default_scope('mmseg') data_root = 'data/cityscapes/' data_prefix=dict(img_path='leftImg8bit/train', seg_map_path='gtFine/train') diff --git a/docs/zh_cn/advanced_guides/evaluation.md b/docs/zh_cn/advanced_guides/evaluation.md index d07fcf1048..a82311ccc7 100644 --- a/docs/zh_cn/advanced_guides/evaluation.md +++ b/docs/zh_cn/advanced_guides/evaluation.md @@ -1 +1,3 @@ -# 模型评测 +# 模型评测 + +中文版文档支持中,请先阅读[英文版本](../../en/advanced_guides/evaluation.md) diff --git a/docs/zh_cn/advanced_guides/index.rst b/docs/zh_cn/advanced_guides/index.rst index b706742603..2aec1ac9cf 100644 --- a/docs/zh_cn/advanced_guides/index.rst +++ b/docs/zh_cn/advanced_guides/index.rst @@ -19,7 +19,7 @@ .. toctree:: :maxdepth: 1 - add_modules.md + add_models.md add_datasets.md add_transforms.md add_metrics.md diff --git a/docs/zh_cn/advanced_guides/models.md b/docs/zh_cn/advanced_guides/models.md index bebf4ef44f..62dbea38c4 100644 --- a/docs/zh_cn/advanced_guides/models.md +++ b/docs/zh_cn/advanced_guides/models.md @@ -1 +1,3 @@ # 模型 + +中文版文档支持中,请先阅读[英文版本](../../en/advanced_guides/models.md) diff --git a/docs/zh_cn/advanced_guides/transforms.md b/docs/zh_cn/advanced_guides/transforms.md index c96b688bd9..1cbe79ba49 100644 --- a/docs/zh_cn/advanced_guides/transforms.md +++ b/docs/zh_cn/advanced_guides/transforms.md @@ -1 +1,3 @@ -# 数据增广 +# 数据增强变化 + +中文版文档支持中,请先阅读[英文版本](../../en/advanced_guides/transforms.md) diff --git a/docs/zh_cn/api.rst b/docs/zh_cn/api.rst index 94f64313d0..3478aa9361 100644 --- a/docs/zh_cn/api.rst +++ b/docs/zh_cn/api.rst @@ -11,11 +11,6 @@ datasets .. automodule:: mmseg.datasets :members: -samplers -^^^^^^^^^^ -.. automodule:: mmseg.datasets.samplers - :members: - transforms ^^^^^^^^^^^^ .. automodule:: mmseg.datasets.transforms diff --git a/docs/zh_cn/device/npu.md b/docs/zh_cn/device/npu.md new file mode 100644 index 0000000000..d50439d040 --- /dev/null +++ b/docs/zh_cn/device/npu.md @@ -0,0 +1,39 @@ +# NPU (华为 昇腾) + +## 使用方法 + +请参考 [MMCV 的安装文档](https://mmcv.readthedocs.io/en/latest/get_started/build.html#build-mmcv-full-on-ascend-npu-machine) 来安装 NPU 版本的 MMCV。 + +以下展示单机四卡场景的运行指令: + +```shell +bash tools/dist_train.sh configs/deeplabv3/deeplabv3_r50-d8_4xb2-40k_cityscapes-512x1024.py 4 +``` + +以下展示单机单卡下的运行指令: + +```shell +python tools/train.py configs/deeplabv3/deeplabv3_r50-d8_4xb2-40k_cityscapes-512x1024.py +``` + +## 模型验证结果 + +| Model | mIoU | Config | Download | +| :-----------------: | :---: | :----------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------ | +| [deeplabv3](<>) | 78.85 | [config](https://github.com/open-mmlab/mmsegmentation/tree/1.x/configs/deeplabv3/deeplabv3_r50-d8_4xb2-40k_cityscapes-512x1024.py) | [log](https://download.openmmlab.com/mmsegmentation/v0.5/device/npu/deeplabv3_r50-d8_4xb2-40k_cityscapes-512x1024_20230115_205626.json) | +| [deeplabv3plus](<>) | 79.23 | [config](https://github.com/open-mmlab/mmsegmentation/tree/1.x/configs/deeplabv3plus/deeplabv3plus_r50-d8_4xb2-40k_cityscapes-512x1024.py) | [log](https://download.openmmlab.com/mmsegmentation/v0.5/device/npu/deeplabv3plus_r50-d8_4xb2-40k_cityscapes-512x1024_20230116_043450.json) | +| [hrnet](<>) | 78.1 | [config](https://github.com/open-mmlab/mmsegmentation/tree/1.x/configs/hrnet/fcn_hr18_4xb2-40k_cityscapes-512x1024.py) | [log](https://download.openmmlab.com/mmsegmentation/v0.5/device/npu/fcn_hr18_4xb2-40k_cityscapes-512x1024_20230116_215821.json) | +| [fcn](<>) | 74.15 | [config](https://github.com/open-mmlab/mmsegmentation/tree/1.x/configs/fcn/fcn_r50-d8_4xb2-40k_cityscapes-512x1024.py) | [log](https://download.openmmlab.com/mmsegmentation/v0.5/device/npu/fcn_r50-d8_4xb2-40k_cityscapes-512x1024_20230111_083014.json) | +| [icnet](<>) | 69.25 | [config](https://github.com/open-mmlab/mmsegmentation/tree/1.x/configs/icnet/icnet_r50-d8_4xb2-80k_cityscapes-832x832.py) | [log](https://download.openmmlab.com/mmsegmentation/v0.5/device/npu/icnet_r50-d8_4xb2-80k_cityscapes-832x832_20230119_002929.json) | +| [pspnet](<>) | 77.21 | [config](https://github.com/open-mmlab/mmsegmentation/tree/1.x/configs/pspnet/pspnet_r50b-d8_4xb2-80k_cityscapes-512x1024.py) | [log](https://download.openmmlab.com/mmsegmentation/v0.5/device/npu/pspnet_r50b-d8_4xb2-80k_cityscapes-512x1024_20230114_042721.json) | +| [unet](<>) | 68.86 | [config](https://github.com/open-mmlab/mmsegmentation/tree/1.x/configs/unet/unet-s5-d16_fcn_4xb4-160k_cityscapes-512x1024.py) | [log](https://download.openmmlab.com/mmsegmentation/v0.5/device/npu/unet-s5-d16_fcn_4xb4-160k_cityscapes-512x1024_20230129_224750.json) | +| [upernet](<>) | 77.81 | [config](https://github.com/open-mmlab/mmsegmentation/tree/1.x/configs/upernet/upernet_r50_4xb2-40k_cityscapes-512x1024.py) | [log](https://download.openmmlab.com/mmsegmentation/v0.5/device/npu/upernet_r50_4xb2-40k_cityscapes-512x1024_20230129_014634.json) | +| [apcnet](<>) | 78.02 | [config](https://github.com/open-mmlab/mmsegmentation/tree/1.x/configs/apcnet/apcnet_r50-d8_4xb2-40k_cityscapes-512x1024.py) | [log](https://download.openmmlab.com/mmsegmentation/v0.5/device/npu/apcnet_r50-d8_4xb2-40k_cityscapes-512x1024_20230209_212545.json) | +| [bisenetv1](<>) | 76.04 | [config](https://github.com/open-mmlab/mmsegmentation/tree/1.x/configs/bisenetv1/bisenetv1_r50-d32_4xb4-160k_cityscapes-1024x1024.py) | [log](https://download.openmmlab.com/mmsegmentation/v0.5/device/npu/bisenetv1_r50-d32_4xb4-160k_cityscapes-1024x1024_20230201_023946.json) | +| [bisenetv2](<>) | 72.44 | [config](https://github.com/open-mmlab/mmsegmentation/tree/1.x/configs/bisenetv2/bisenetv2_fcn_4xb4-amp-160k_cityscapes-1024x1024.py) | [log](https://download.openmmlab.com/mmsegmentation/v0.5/device/npu/bisenetv2_fcn_4xb4-amp-160k_cityscapes-1024x1024_20230205_215606.json) | + +**注意:** + +- 如果没有特别标记,NPU 上的使用混合精度训练的结果与使用 FP32 的 GPU 上的结果相同。 + +**以上模型结果由华为昇腾团队提供** diff --git a/docs/zh_cn/get_started.md b/docs/zh_cn/get_started.md index fff70a2560..da6d728a15 100644 --- a/docs/zh_cn/get_started.md +++ b/docs/zh_cn/get_started.md @@ -34,7 +34,7 @@ conda install pytorch torchvision cpuonly -c pytorch ## 安装 -我们建议用户遵循我们的最佳实践来安装 MMSegmentation 。但是整个过程是高度自定义的。更多信息请参见[自定义安装](#自定义安装)部分。 +我们建议用户遵循我们的最佳实践来安装 MMSegmentation 。但是整个过程是高度自定义的。更多信息请参见[自定义安装](##自定义安装)部分。 ### 最佳实践 @@ -92,10 +92,8 @@ python demo/image_demo.py demo/demo.png configs/pspnet/pspnet_r50-d8_4xb2-40k_ci ```python from mmseg.apis import inference_model, init_model, show_result_pyplot -from mmseg.utils import register_all_modules import mmcv -register_all_modules() config_file = 'pspnet_r50-d8_4xb2-40k_cityscapes-512x1024.py' checkpoint_file = 'pspnet_r50-d8_512x1024_40k_cityscapes_20200605_003338-2966598c.pth' diff --git a/docs/zh_cn/migration.md b/docs/zh_cn/migration.md index 5168bb0bd5..3f19b26714 100644 --- a/docs/zh_cn/migration.md +++ b/docs/zh_cn/migration.md @@ -1 +1,3 @@ # 迁移文档 + +中文迁移文档在支持中,请先阅读[英文版迁移文档](../en/migration/) diff --git a/docs/zh_cn/modelzoo_statistics.md b/docs/zh_cn/modelzoo_statistics.md new file mode 100644 index 0000000000..b057575a25 --- /dev/null +++ b/docs/zh_cn/modelzoo_statistics.md @@ -0,0 +1,102 @@ +# 模型库统计数据 + +- 论文数量: 47 + + - ALGORITHM: 36 + - BACKBONE: 11 + +- 模型数量: 612 + + - \[ALGORITHM\] [ANN](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/ann) (16 ckpts) + + - \[ALGORITHM\] [APCNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/apcnet) (12 ckpts) + + - \[BACKBONE\] [BEiT](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/beit) (2 ckpts) + + - \[ALGORITHM\] [BiSeNetV1](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/bisenetv1) (11 ckpts) + + - \[ALGORITHM\] [BiSeNetV2](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/bisenetv2) (4 ckpts) + + - \[ALGORITHM\] [CCNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/ccnet) (16 ckpts) + + - \[ALGORITHM\] [CGNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/cgnet) (2 ckpts) + + - \[BACKBONE\] [ConvNeXt](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/convnext) (6 ckpts) + + - \[ALGORITHM\] [DANet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/danet) (16 ckpts) + + - \[ALGORITHM\] [DeepLabV3](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/deeplabv3) (41 ckpts) + + - \[ALGORITHM\] [DeepLabV3+](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/deeplabv3plus) (42 ckpts) + + - \[ALGORITHM\] [DMNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/dmnet) (12 ckpts) + + - \[ALGORITHM\] [DNLNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/dnlnet) (12 ckpts) + + - \[ALGORITHM\] [DPT](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/dpt) (1 ckpts) + + - \[ALGORITHM\] [EMANet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/emanet) (4 ckpts) + + - \[ALGORITHM\] [EncNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/encnet) (12 ckpts) + + - \[ALGORITHM\] [ERFNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/erfnet) (1 ckpts) + + - \[ALGORITHM\] [FastFCN](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/fastfcn) (12 ckpts) + + - \[ALGORITHM\] [Fast-SCNN](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/fastscnn) (1 ckpts) + + - \[ALGORITHM\] [FCN](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/fcn) (41 ckpts) + + - \[ALGORITHM\] [GCNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/gcnet) (16 ckpts) + + - \[BACKBONE\] [HRNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/hrnet) (37 ckpts) + + - \[ALGORITHM\] [ICNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/icnet) (12 ckpts) + + - \[ALGORITHM\] [ISANet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/isanet) (16 ckpts) + + - \[ALGORITHM\] [K-Net](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/knet) (7 ckpts) + + - \[BACKBONE\] [MAE](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/mae) (1 ckpts) + + - \[ALGORITHM\] [Mask2Former](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/mask2former) (13 ckpts) + + - \[ALGORITHM\] [MaskFormer](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/maskformer) (4 ckpts) + + - \[BACKBONE\] [MobileNetV2](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/mobilenet_v2) (8 ckpts) + + - \[BACKBONE\] [MobileNetV3](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/mobilenet_v3) (4 ckpts) + + - \[ALGORITHM\] [NonLocal Net](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/nonlocal_net) (16 ckpts) + + - \[ALGORITHM\] [OCRNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/ocrnet) (24 ckpts) + + - \[ALGORITHM\] [PointRend](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/point_rend) (4 ckpts) + + - \[BACKBONE\] [PoolFormer](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/poolformer) (5 ckpts) + + - \[ALGORITHM\] [PSANet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/psanet) (16 ckpts) + + - \[ALGORITHM\] [PSPNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/pspnet) (54 ckpts) + + - \[BACKBONE\] [ResNeSt](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/resnest) (8 ckpts) + + - \[ALGORITHM\] [SegFormer](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/segformer) (13 ckpts) + + - \[ALGORITHM\] [Segmenter](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/segmenter) (5 ckpts) + + - \[ALGORITHM\] [Semantic FPN](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/sem_fpn) (4 ckpts) + + - \[ALGORITHM\] [SETR](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/setr) (7 ckpts) + + - \[ALGORITHM\] [STDC](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/stdc) (4 ckpts) + + - \[BACKBONE\] [Swin Transformer](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/swin) (6 ckpts) + + - \[BACKBONE\] [Twins](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/twins) (12 ckpts) + + - \[ALGORITHM\] [UNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/unet) (25 ckpts) + + - \[ALGORITHM\] [UPerNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/upernet) (16 ckpts) + + - \[BACKBONE\] [Vision Transformer](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/vit) (11 ckpts) diff --git a/docs/zh_cn/user_guides/2_dataset_prepare.md b/docs/zh_cn/user_guides/2_dataset_prepare.md index a8dde9211a..c9c3606977 100644 --- a/docs/zh_cn/user_guides/2_dataset_prepare.md +++ b/docs/zh_cn/user_guides/2_dataset_prepare.md @@ -1,406 +1,3 @@ ## 准备数据集(待更新) -推荐用软链接, 将数据集根目录链接到 `$MMSEGMENTATION/data` 里. 如果您的文件夹结构是不同的, 您也许可以试着修改配置文件里对应的路径. - -```none -mmsegmentation -├── mmseg -├── tools -├── configs -├── data -│ ├── cityscapes -│ │ ├── leftImg8bit -│ │ │ ├── train -│ │ │ ├── val -│ │ ├── gtFine -│ │ │ ├── train -│ │ │ ├── val -│ ├── VOCdevkit -│ │ ├── VOC2012 -│ │ │ ├── JPEGImages -│ │ │ ├── SegmentationClass -│ │ │ ├── ImageSets -│ │ │ │ ├── Segmentation -│ │ ├── VOC2010 -│ │ │ ├── JPEGImages -│ │ │ ├── SegmentationClassContext -│ │ │ ├── ImageSets -│ │ │ │ ├── SegmentationContext -│ │ │ │ │ ├── train.txt -│ │ │ │ │ ├── val.txt -│ │ │ ├── trainval_merged.json -│ │ ├── VOCaug -│ │ │ ├── dataset -│ │ │ │ ├── cls -│ ├── ade -│ │ ├── ADEChallengeData2016 -│ │ │ ├── annotations -│ │ │ │ ├── training -│ │ │ │ ├── validation -│ │ │ ├── images -│ │ │ │ ├── training -│ │ │ │ ├── validation -│ ├── CHASE_DB1 -│ │ ├── images -│ │ │ ├── training -│ │ │ ├── validation -│ │ ├── annotations -│ │ │ ├── training -│ │ │ ├── validation -│ ├── DRIVE -│ │ ├── images -│ │ │ ├── training -│ │ │ ├── validation -│ │ ├── annotations -│ │ │ ├── training -│ │ │ ├── validation -│ ├── HRF -│ │ ├── images -│ │ │ ├── training -│ │ │ ├── validation -│ │ ├── annotations -│ │ │ ├── training -│ │ │ ├── validation -│ ├── STARE -│ │ ├── images -│ │ │ ├── training -│ │ │ ├── validation -│ │ ├── annotations -│ │ │ ├── training -│ │ │ ├── validation -| ├── dark_zurich -| │   ├── gps -| │   │   ├── val -| │   │   └── val_ref -| │   ├── gt -| │   │   └── val -| │   ├── LICENSE.txt -| │   ├── lists_file_names -| │   │   ├── val_filenames.txt -| │   │   └── val_ref_filenames.txt -| │   ├── README.md -| │   └── rgb_anon -| │   | ├── val -| │   | └── val_ref -| ├── NighttimeDrivingTest -| | ├── gtCoarse_daytime_trainvaltest -| | │   └── test -| | │   └── night -| | └── leftImg8bit -| | | └── test -| | | └── night -│ ├── loveDA -│ │ ├── img_dir -│ │ │ ├── train -│ │ │ ├── val -│ │ │ ├── test -│ │ ├── ann_dir -│ │ │ ├── train -│ │ │ ├── val -│ ├── potsdam -│ │ ├── img_dir -│ │ │ ├── train -│ │ │ ├── val -│ │ ├── ann_dir -│ │ │ ├── train -│ │ │ ├── val -│ ├── vaihingen -│ │ ├── img_dir -│ │ │ ├── train -│ │ │ ├── val -│ │ ├── ann_dir -│ │ │ ├── train -│ │ │ ├── val -│ ├── iSAID -│ │ ├── img_dir -│ │ │ ├── train -│ │ │ ├── val -│ │ │ ├── test -│ │ ├── ann_dir -│ │ │ ├── train -│ │ │ ├── val -│ ├── synapse -│ │ ├── img_dir -│ │ │ ├── train -│ │ │ ├── val -│ │ ├── ann_dir -│ │ │ ├── train -│ │ │ ├── val -``` - -### Cityscapes - -注册成功后, 数据集可以在 [这里](https://www.cityscapes-dataset.com/downloads/) 下载. - -通常情况下, `**labelTrainIds.png` 被用来训练 cityscapes. -基于 [cityscapesscripts](https://github.com/mcordts/cityscapesScripts), -我们提供了一个 [脚本](https://github.com/open-mmlab/mmsegmentation/blob/master/tools/convert_datasets/cityscapes.py), -去生成 `**labelTrainIds.png`. - -```shell -# --nproc 8 意味着有 8 个进程用来转换,它也可以被忽略. -python tools/convert_datasets/cityscapes.py data/cityscapes --nproc 8 -``` - -### Pascal VOC - -Pascal VOC 2012 可以在 [这里](http://host.robots.ox.ac.uk/pascal/VOC/voc2012/VOCtrainval_11-May-2012.tar) 下载. -此外, 许多最近在 Pascal VOC 数据集上的工作都会利用增广的数据, 它们可以在 [这里](http://www.eecs.berkeley.edu/Research/Projects/CS/vision/grouping/semantic_contours/benchmark.tgz) 找到. - -如果您想使用增广后的 VOC 数据集, 请运行下面的命令来将数据增广的标注转成正确的格式. - -```shell -# --nproc 8 意味着有 8 个进程用来转换,它也可以被忽略. -python tools/convert_datasets/voc_aug.py data/VOCdevkit data/VOCdevkit/VOCaug --nproc 8 -``` - -关于如何拼接数据集 (concatenate) 并一起训练它们, 更多细节请参考 [拼接连接数据集](https://github.com/open-mmlab/mmsegmentation/blob/master/docs/zh_cn/tutorials/customize_datasets.md#%E6%8B%BC%E6%8E%A5%E6%95%B0%E6%8D%AE%E9%9B%86) . - -### ADE20K - -ADE20K 的训练集和验证集可以在 [这里](http://data.csail.mit.edu/places/ADEchallenge/ADEChallengeData2016.zip) 下载. -您还可以在 [这里](http://data.csail.mit.edu/places/ADEchallenge/release_test.zip) 下载验证集. - -### Pascal Context - -Pascal Context 的训练集和验证集可以在 [这里](http://host.robots.ox.ac.uk/pascal/VOC/voc2010/VOCtrainval_03-May-2010.tar) 下载. -注册成功后, 您还可以在 [这里](http://host.robots.ox.ac.uk:8080/eval/downloads/VOC2010test.tar) 下载验证集. - -为了从原始数据集里切分训练集和验证集, 您可以在 [这里](https://codalabuser.blob.core.windows.net/public/trainval_merged.json) -下载 trainval_merged.json. - -如果您想使用 Pascal Context 数据集, -请安装 [细节](https://github.com/zhanghang1989/detail-api) 然后再运行如下命令来把标注转换成正确的格式. - -```shell -python tools/convert_datasets/pascal_context.py data/VOCdevkit data/VOCdevkit/VOC2010/trainval_merged.json -``` - -### CHASE DB1 - -CHASE DB1 的训练集和验证集可以在 [这里](https://staffnet.kingston.ac.uk/~ku15565/CHASE_DB1/assets/CHASEDB1.zip) 下载. - -为了将 CHASE DB1 数据集转换成 MMSegmentation 的格式,您需要运行如下命令: - -```shell -python tools/convert_datasets/chase_db1.py /path/to/CHASEDB1.zip -``` - -这个脚本将自动生成正确的文件夹结构. - -### DRIVE - -DRIVE 的训练集和验证集可以在 [这里](https://drive.grand-challenge.org/) 下载. -在此之前, 您需要注册一个账号, 当前 '1st_manual' 并未被官方提供, 因此需要您从其他地方获取. - -为了将 DRIVE 数据集转换成 MMSegmentation 格式, 您需要运行如下命令: - -```shell -python tools/convert_datasets/drive.py /path/to/training.zip /path/to/test.zip -``` - -这个脚本将自动生成正确的文件夹结构. - -### HRF - -首先, 下载 [healthy.zip](https://www5.cs.fau.de/fileadmin/research/datasets/fundus-images/healthy.zip) [glaucoma.zip](https://www5.cs.fau.de/fileadmin/research/datasets/fundus-images/glaucoma.zip), [diabetic_retinopathy.zip](https://www5.cs.fau.de/fileadmin/research/datasets/fundus-images/diabetic_retinopathy.zip), [healthy_manualsegm.zip](https://www5.cs.fau.de/fileadmin/research/datasets/fundus-images/healthy_manualsegm.zip), [glaucoma_manualsegm.zip](https://www5.cs.fau.de/fileadmin/research/datasets/fundus-images/glaucoma_manualsegm.zip) 以及 [diabetic_retinopathy_manualsegm.zip](https://www5.cs.fau.de/fileadmin/research/datasets/fundus-images/diabetic_retinopathy_manualsegm.zip). - -为了将 HRF 数据集转换成 MMSegmentation 格式, 您需要运行如下命令: - -```shell -python tools/convert_datasets/hrf.py /path/to/healthy.zip /path/to/healthy_manualsegm.zip /path/to/glaucoma.zip /path/to/glaucoma_manualsegm.zip /path/to/diabetic_retinopathy.zip /path/to/diabetic_retinopathy_manualsegm.zip -``` - -这个脚本将自动生成正确的文件夹结构. - -### STARE - -首先, 下载 [stare-images.tar](http://cecas.clemson.edu/~ahoover/stare/probing/stare-images.tar), [labels-ah.tar](http://cecas.clemson.edu/~ahoover/stare/probing/labels-ah.tar) 和 [labels-vk.tar](http://cecas.clemson.edu/~ahoover/stare/probing/labels-vk.tar). - -为了将 STARE 数据集转换成 MMSegmentation 格式, 您需要运行如下命令: - -```shell -python tools/convert_datasets/stare.py /path/to/stare-images.tar /path/to/labels-ah.tar /path/to/labels-vk.tar -``` - -这个脚本将自动生成正确的文件夹结构. - -### Dark Zurich - -因为我们只支持在此数据集上测试模型, 所以您只需下载[验证集](https://data.vision.ee.ethz.ch/csakarid/shared/GCMA_UIoU/Dark_Zurich_val_anon.zip). - -### Nighttime Driving - -因为我们只支持在此数据集上测试模型,所以您只需下载[测试集](http://data.vision.ee.ethz.ch/daid/NighttimeDriving/NighttimeDrivingTest.zip). - -### LoveDA - -可以从 Google Drive 里下载 [LoveDA数据集](https://drive.google.com/drive/folders/1ibYV0qwn4yuuh068Rnc-w4tPi0U0c-ti?usp=sharing). - -或者它还可以从 [zenodo](https://zenodo.org/record/5706578#.YZvN7SYRXdF) 下载, 您需要运行如下命令: - -```shell -# Download Train.zip -wget https://zenodo.org/record/5706578/files/Train.zip -# Download Val.zip -wget https://zenodo.org/record/5706578/files/Val.zip -# Download Test.zip -wget https://zenodo.org/record/5706578/files/Test.zip -``` - -对于 LoveDA 数据集,请运行以下命令下载并重新组织数据集: - -```shell -python tools/convert_datasets/loveda.py /path/to/loveDA -``` - -请参照 [这里](https://github.com/open-mmlab/mmsegmentation/blob/master/docs/zh_cn/inference.md) 来使用训练好的模型去预测 LoveDA 测试集并且提交到官网. - -关于 LoveDA 的更多细节可以在[这里](https://github.com/Junjue-Wang/LoveDA) 找到. - -### ISPRS Potsdam - -[Potsdam](https://www2.isprs.org/commissions/comm2/wg4/benchmark/2d-sem-label-potsdam/) -数据集是一个有着2D 语义分割内容标注的城市遥感数据集. -数据集可以从挑战[主页](https://www2.isprs.org/commissions/comm2/wg4/benchmark/data-request-form/) 获得. -需要其中的 `2_Ortho_RGB.zip` 和 `5_Labels_all_noBoundary.zip`. - -对于 Potsdam 数据集,请运行以下命令下载并重新组织数据集 - -```shell -python tools/convert_datasets/potsdam.py /path/to/potsdam -``` - -使用我们默认的配置, 将生成 3,456 张图片的训练集和 2,016 张图片的验证集. - -### ISPRS Vaihingen - -[Vaihingen](https://www2.isprs.org/commissions/comm2/wg4/benchmark/2d-sem-label-vaihingen/) -数据集是一个有着2D 语义分割内容标注的城市遥感数据集. - -数据集可以从挑战 [主页](https://www2.isprs.org/commissions/comm2/wg4/benchmark/data-request-form/). -需要其中的 'ISPRS_semantic_labeling_Vaihingen.zip' 和 'ISPRS_semantic_labeling_Vaihingen_ground_truth_eroded_COMPLETE.zip'. - -对于 Vaihingen 数据集, 请运行以下命令下载并重新组织数据集 - -```shell -python tools/convert_datasets/vaihingen.py /path/to/vaihingen -``` - -使用我们默认的配置 (`clip_size`=512, `stride_size`=256), 将生成 344 张图片的训练集和 398 张图片的验证集. - -### iSAID - -iSAID 数据集(训练集/验证集/测试集)的图像可以从 [DOTA-v1.0](https://captain-whu.github.io/DOTA/dataset.html) 下载. - -iSAID 数据集(训练集/验证集)的注释可以从 [iSAID](https://captain-whu.github.io/iSAID/dataset.html) 下载. - -该数据集是一个大规模的实例分割(也可以用于语义分割)的遥感数据集. - -下载后, 在数据集转换前, 您需要将数据集文件夹调整成如下格式. - -``` -│ ├── iSAID -│ │ ├── train -│ │ │ ├── images -│ │ │ │ ├── part1.zip -│ │ │ │ ├── part2.zip -│ │ │ │ ├── part3.zip -│ │ │ ├── Semantic_masks -│ │ │ │ ├── images.zip -│ │ ├── val -│ │ │ ├── images -│ │ │ │ ├── part1.zip -│ │ │ ├── Semantic_masks -│ │ │ │ ├── images.zip -│ │ ├── test -│ │ │ ├── images -│ │ │ │ ├── part1.zip -│ │ │ │ ├── part2.zip -``` - -```shell -python tools/convert_datasets/isaid.py /path/to/iSAID -``` - -使用我们默认的配置 (`patch_width`=896, `patch_height`=896, `overlap_area`=384), 将生成 33,978 张图片的训练集和 11,644 张图片的验证集. - -## Synapse dataset - -这个数据集可以在这个[网页](https://www.synapse.org/#!Synapse:syn3193805/wiki/) 里被下载. -我们参考了 [TransUNet](https://arxiv.org/abs/2102.04306) 里面的数据集预处理的设置, 它将原始数据集 (30 套 3D 样例) 切分出 18 套用于训练, 12 套用于验证. 请参考以下步骤来准备该数据集: - -```shell -unzip RawData.zip -cd ./RawData/Training -``` - -随后新建 `train.txt` 和 `val.txt`. - -根据 TransUNet 来将训练集和验证集如下划分: - -train.txt - -```none -img0005.nii.gz -img0006.nii.gz -img0007.nii.gz -img0009.nii.gz -img0010.nii.gz -img0021.nii.gz -img0023.nii.gz -img0024.nii.gz -img0026.nii.gz -img0027.nii.gz -img0028.nii.gz -img0030.nii.gz -img0031.nii.gz -img0033.nii.gz -img0034.nii.gz -img0037.nii.gz -img0039.nii.gz -img0040.nii.gz -``` - -val.txt - -```none -img0008.nii.gz -img0022.nii.gz -img0038.nii.gz -img0036.nii.gz -img0032.nii.gz -img0002.nii.gz -img0029.nii.gz -img0003.nii.gz -img0001.nii.gz -img0004.nii.gz -img0025.nii.gz -img0035.nii.gz -``` - -此时, synapse 数据集包括了以下内容: - -```none -├── Training -│ ├── img -│ │ ├── img0001.nii.gz -│ │ ├── img0002.nii.gz -│ │ ├── ... -│ ├── label -│ │ ├── label0001.nii.gz -│ │ ├── label0002.nii.gz -│ │ ├── ... -│ ├── train.txt -│ ├── val.txt -``` - -随后, 运行下面的数据集转换脚本来处理 synapse 数据集: - -```shell -python tools/dataset_converters/synapse.py --dataset-path /path/to/synapse -``` - -使用我们默认的配置, 将生成 2,211 张 2D 图片的训练集和 1,568 张图片的验证集. - -需要注意的是 MMSegmentation 默认的评价指标 (例如平均 Dice 值) 都是基于每帧 2D 图片计算的, 这与基于每套 3D 图片计算评价指标的 [TransUNet](https://arxiv.org/abs/2102.04306) 是不同的. +中文版文档支持中,请先阅读[英文版本](../../en/user_guides/2_dataset_prepare.md) diff --git a/docs/zh_cn/user_guides/3_inference.md b/docs/zh_cn/user_guides/3_inference.md index b90f73420c..d2fe60076f 100644 --- a/docs/zh_cn/user_guides/3_inference.md +++ b/docs/zh_cn/user_guides/3_inference.md @@ -1,127 +1,3 @@ ## 使用预训练模型推理(待更新) -我们提供测试脚本来评估完整数据集(Cityscapes, PASCAL VOC, ADE20k 等)上的结果,同时为了使其他项目的整合更容易,也提供一些高级 API。 - -### 测试一个数据集 - -- 单卡 GPU -- CPU -- 单节点多卡 GPU -- 多节点 - -您可以使用以下命令来测试一个数据集。 - -```shell -# 单卡 GPU 测试 -python tools/test.py ${配置文件} ${检查点文件} [--out ${结果文件}] [--eval ${评估指标}] [--show] - -# CPU: 如果机器没有 GPU, 则跟上述单卡 GPU 测试一致 -# CPU: 如果机器有 GPU, 那么先禁用 GPU 再运行单 GPU 测试脚本 -export CUDA_VISIBLE_DEVICES=-1 # 禁用 GPU -python tools/test.py ${配置文件} ${检查点文件} [--out ${结果文件}] [--eval ${评估指标}] [--show] - -# 多卡GPU 测试 -./tools/dist_test.sh ${配置文件} ${检查点文件} ${GPU数目} [--out ${结果文件}] [--eval ${评估指标}] -``` - -可选参数: - -- `RESULT_FILE`: pickle 格式的输出结果的文件名,如果不专门指定,结果将不会被专门保存成文件。(MMseg v0.17 之后,args.out 将只会保存评估时的中间结果或者是分割图的保存路径。) -- `EVAL_METRICS`: 在结果里将被评估的指标。这主要取决于数据集, `mIoU` 对于所有数据集都可获得,像 Cityscapes 数据集可以通过 `cityscapes` 命令来专门评估,就像标准的 `mIoU`一样。 -- `--show`: 如果被指定,分割结果将会在一张图像里画出来并且在另一个窗口展示。它仅仅是用来调试与可视化,并且仅针对单卡 GPU 测试。请确认 GUI 在您的环境里可用,否则您也许会遇到报错 `cannot connect to X server` -- `--show-dir`: 如果被指定,分割结果将会在一张图像里画出来并且保存在指定文件夹里。它仅仅是用来调试与可视化,并且仅针对单卡GPU测试。使用该参数时,您的环境不需要 GUI。 -- `--eval-options`: 评估时的可选参数,当设置 `efficient_test=True` 时,它将会保存中间结果至本地文件里以节约 CPU 内存。请确认您本地硬盘有足够的存储空间(大于20GB)。(MMseg v0.17 之后,`efficient_test` 不再生效,我们重构了 test api,通过使用一种渐近式的方式来提升评估和保存结果的效率。) - -例子: - -假设您已经下载检查点文件至文件夹 `checkpoints/` 里。 - -1. 测试 PSPNet 并可视化结果。按下任何键会进行到下一张图 - - ```shell - python tools/test.py configs/pspnet/pspnet_r50-d8_512x1024_40k_cityscapes.py \ - checkpoints/pspnet_r50-d8_512x1024_40k_cityscapes_20200605_003338-2966598c.pth \ - --show - ``` - -2. 测试 PSPNet 并保存画出的图以便于之后的可视化 - - ```shell - python tools/test.py configs/pspnet/pspnet_r50-d8_512x1024_40k_cityscapes.py \ - checkpoints/pspnet_r50-d8_512x1024_40k_cityscapes_20200605_003338-2966598c.pth \ - --show-dir psp_r50_512x1024_40ki_cityscapes_results - ``` - -3. 在数据集 PASCAL VOC (不保存测试结果) 上测试 PSPNet 并评估 mIoU - - ```shell - python tools/test.py configs/pspnet/pspnet_r50-d8_512x1024_20k_voc12aug.py \ - checkpoints/pspnet_r50-d8_512x1024_20k_voc12aug_20200605_003338-c57ef100.pth \ - --eval mAP - ``` - -4. 使用4卡 GPU 测试 PSPNet,并且在标准 mIoU 和 cityscapes 指标里评估模型 - - ```shell - ./tools/dist_test.sh configs/pspnet/pspnet_r50-d8_512x1024_40k_cityscapes.py \ - checkpoints/pspnet_r50-d8_512x1024_40k_cityscapes_20200605_003338-2966598c.pth \ - 4 --out results.pkl --eval mIoU cityscapes - ``` - - 注意:在 cityscapes mIoU 和我们的 mIoU 指标会有一些差异 (~0.1%) 。因为 cityscapes 默认是根据类别样本数的多少进行加权平均,而我们对所有的数据集都是采取直接平均的方法来得到 mIoU。 - -5. 在 cityscapes 数据集上4卡 GPU 测试 PSPNet, 并生成 png 文件以便提交给官方评估服务器 - - 首先,在配置文件里添加内容: `configs/pspnet/pspnet_r50-d8_512x1024_40k_cityscapes.py`, - - ```python - data = dict( - test=dict( - img_dir='leftImg8bit/test', - ann_dir='gtFine/test')) - ``` - - 随后,进行测试。 - - ```shell - ./tools/dist_test.sh configs/pspnet/pspnet_r50-d8_512x1024_40k_cityscapes.py \ - checkpoints/pspnet_r50-d8_512x1024_40k_cityscapes_20200605_003338-2966598c.pth \ - 4 --format-only --eval-options "imgfile_prefix=./pspnet_test_results" - ``` - - 您会在文件夹 `./pspnet_test_results` 里得到生成的 png 文件。 - 您也许可以运行 `zip -r results.zip pspnet_test_results/` 并提交 zip 文件给 [evaluation server](https://www.cityscapes-dataset.com/submit/) 。 - -6. 在 Cityscapes 数据集上使用 CPU 高效内存选项来测试 DeeplabV3+ `mIoU` 指标 (没有保存测试结果) - - ```shell - python tools/test.py \ - configs/deeplabv3plus/deeplabv3plus_r18-d8_512x1024_80k_cityscapes.py \ - deeplabv3plus_r18-d8_512x1024_80k_cityscapes_20201226_080942-cff257fe.pth \ - --eval-options efficient_test=True \ - --eval mIoU - ``` - - 使用 `pmap` 可查看 CPU 内存情况, `efficient_test=True` 会使用约 2.25GB 的 CPU 内存, `efficient_test=False` 会使用约 11.06GB 的 CPU 内存。 这个可选参数可以节约很多 CPU 内存。(MMseg v0.17 之后, `efficient_test` 参数将不再生效, 我们使用了一种渐近的方式来更加有效快速地评估和保存结果。) - -7. 在 LoveDA 数据集上1卡 GPU 测试 PSPNet, 并生成 png 文件以便提交给官方评估服务器 - - 首先,在配置文件里添加内容: `configs/pspnet/pspnet_r50-d8_512x512_80k_loveda.py`, - - ```python - data = dict( - test=dict( - img_dir='img_dir/test', - ann_dir='ann_dir/test')) - ``` - - 随后,进行测试。 - - ```shell - python ./tools/test.py configs/pspnet/pspnet_r50-d8_512x512_80k_loveda.py \ - checkpoints/pspnet_r50-d8_512x512_80k_loveda_20211104_155728-88610f9f.pth \ - --format-only --eval-options "imgfile_prefix=./pspnet_test_results" - ``` - - 您会在文件夹 `./pspnet_test_results` 里得到生成的 png 文件。 - 您也许可以运行 `zip -r -j Results.zip pspnet_test_results/` 并提交 zip 文件给 [evaluation server](https://codalab.lisn.upsaclay.fr/competitions/421) 。 +中文版文档支持中,请先阅读[英文版本](../../en/user_guides/3_inference.md) diff --git a/docs/zh_cn/user_guides/4_train_test.md b/docs/zh_cn/user_guides/4_train_test.md index b26132e765..309e046b2d 100644 --- a/docs/zh_cn/user_guides/4_train_test.md +++ b/docs/zh_cn/user_guides/4_train_test.md @@ -43,7 +43,7 @@ python tools/train.py ${配置文件} --resume --cfg-options load_from=${检查 export CUDA_VISIBLE_DEVICES=-1 ``` -然后运行[上方](#在单GPU上训练)脚本。 +然后运行[上方](###在单GPU上训练)脚本。 ### 在单GPU上测试 @@ -69,7 +69,7 @@ python tools/test.py ${配置文件} ${模型权重文件} [可选参数] export CUDA_VISIBLE_DEVICES=-1 ``` -然后运行[上方](#在单GPU上测试)脚本。 +然后运行[上方](###在单GPU上测试)脚本。 ## 多GPU、多机器上训练和测试 @@ -85,7 +85,7 @@ OpenMMLab2.0 通过 `MMDistributedDataParallel`实现 **分布式** 训练。 sh tools/dist_train.sh ${配置文件} ${GPU数量} [可选参数] ``` -可选参数与[上方](#在单GPU上训练)相同并且还增加了可以指定gpu数量的参数。 +可选参数与[上方](###在单GPU上训练)相同并且还增加了可以指定gpu数量的参数。 示例: @@ -112,7 +112,7 @@ ln -s ${您的工作路径} ${MMSEG 路径}/work_dirs sh tools/dist_test.sh ${配置文件} ${检查点文件} ${GPU数量} [可选参数] ``` -可选参数与[上方](#在单GPU上测试)相同并且增加了可以指定 gpu 数量的参数。 +可选参数与[上方](###在单GPU上测试)相同并且增加了可以指定 gpu 数量的参数。 示例: diff --git a/docs/zh_cn/user_guides/index.rst b/docs/zh_cn/user_guides/index.rst index dacac79698..d0a313d31e 100644 --- a/docs/zh_cn/user_guides/index.rst +++ b/docs/zh_cn/user_guides/index.rst @@ -18,3 +18,4 @@ visualization.md useful_tools.md deployment.md + visualization_feature_map.md diff --git a/docs/zh_cn/user_guides/visualization.md b/docs/zh_cn/user_guides/visualization.md index ac8b9e289f..2ef020ba85 100644 --- a/docs/zh_cn/user_guides/visualization.md +++ b/docs/zh_cn/user_guides/visualization.md @@ -69,7 +69,7 @@ default_hooks = dict( work_dirs/test_visual/20220810_115248/vis_data/vis_image ``` -另外,如果在 `vis_backends` 中添加 `TensorboardVisBackend` ,如 [TensorBoard 的配置](#tensorboard-configuration),我们还可以运行下面的命令在 TensorBoard 中查看它们: +另外,如果在 `vis_backends` 中添加 `TensorboardVisBackend` ,如 [TensorBoard 的配置](###TensorBoard的配置),我们还可以运行下面的命令在 TensorBoard 中查看它们: ```shell tensorboard --logdir work_dirs/test_visual/20220810_115248/vis_data diff --git a/docs/zh_cn/user_guides/visualization_feature_map.md b/docs/zh_cn/user_guides/visualization_feature_map.md new file mode 100644 index 0000000000..fda99bb5ab --- /dev/null +++ b/docs/zh_cn/user_guides/visualization_feature_map.md @@ -0,0 +1,201 @@ +# wandb记录特征图可视化 + +MMSegmentation 1.x 提供了 Weights & Biases 的后端支持,方便对项目代码结果的可视化和管理。 + +## Wandb的配置 + +安装 Weights & Biases 的过程可以参考 [官方安装指南](https://docs.wandb.ai/quickstart),具体的步骤如下: + +```shell +pip install wandb +wandb login +``` + +在 `vis_backend` 中添加 `WandbVisBackend`。 + +```python +vis_backends=[dict(type='LocalVisBackend'), + dict(type='TensorboardVisBackend'), + dict(type='WandbVisBackend')] +``` + +## 测试数据和结果及特征图的可视化 + +`SegLocalVisualizer` 是继承自 MMEngine 中 `Visualizer` 类的子类,适用于 MMSegmentation 可视化,有关 `Visualizer` 的详细信息请参考在 MMEngine 中的[可视化教程](https://mmengine.readthedocs.io/zh_CN/latest/advanced_tutorials/visualization.html) 。 + +以下是一个关于 `SegLocalVisualizer` 的示例,首先你可以使用下面的命令下载这个案例中的数据: + +
+ +
+ +```shell +wget https://user-images.githubusercontent.com/24582831/189833109-eddad58f-f777-4fc0-b98a-6bd429143b06.png --output-document aachen_000000_000019_leftImg8bit.png +wget https://user-images.githubusercontent.com/24582831/189833143-15f60f8a-4d1e-4cbb-a6e7-5e2233869fac.png --output-document aachen_000000_000019_gtFine_labelTrainIds.png + +wget https://download.openmmlab.com/mmsegmentation/v0.5/ann/ann_r50-d8_512x1024_40k_cityscapes/ann_r50-d8_512x1024_40k_cityscapes_20200605_095211-049fc292.pth + +``` + +```python +# Copyright (c) OpenMMLab. All rights reserved. +from argparse import ArgumentParser +from typing import Type + +import mmcv +import torch +import torch.nn as nn + +from mmengine.model import revert_sync_batchnorm +from mmengine.structures import PixelData +from mmseg.apis import inference_model, init_model +from mmseg.structures import SegDataSample +from mmseg.utils import register_all_modules +from mmseg.visualization import SegLocalVisualizer + + +class Recorder: + """record the forward output feature map and save to data_buffer.""" + + def __init__(self) -> None: + self.data_buffer = list() + + def __enter__(self, ): + self._data_buffer = list() + + def record_data_hook(self, model: nn.Module, input: Type, output: Type): + self.data_buffer.append(output) + + def __exit__(self, *args, **kwargs): + pass + + +def visualize(args, model, recorder, result): + seg_visualizer = SegLocalVisualizer( + vis_backends=[dict(type='WandbVisBackend')], + save_dir='temp_dir', + alpha=0.5) + seg_visualizer.dataset_meta = dict( + classes=model.dataset_meta['classes'], + palette=model.dataset_meta['palette']) + + image = mmcv.imread(args.img, 'color') + + seg_visualizer.add_datasample( + name='predict', + image=image, + data_sample=result, + draw_gt=False, + draw_pred=True, + wait_time=0, + out_file=None, + show=False) + + # add feature map to wandb visualizer + for i in range(len(recorder.data_buffer)): + feature = recorder.data_buffer[i][0] # remove the batch + drawn_img = seg_visualizer.draw_featmap( + feature, image, channel_reduction='select_max') + seg_visualizer.add_image(f'feature_map{i}', drawn_img) + + if args.gt_mask: + sem_seg = mmcv.imread(args.gt_mask, 'unchanged') + sem_seg = torch.from_numpy(sem_seg) + gt_mask = dict(data=sem_seg) + gt_mask = PixelData(**gt_mask) + data_sample = SegDataSample() + data_sample.gt_sem_seg = gt_mask + + seg_visualizer.add_datasample( + name='gt_mask', + image=image, + data_sample=data_sample, + draw_gt=True, + draw_pred=False, + wait_time=0, + out_file=None, + show=False) + + seg_visualizer.add_image('image', image) + + +def main(): + parser = ArgumentParser( + description='Draw the Feature Map During Inference') + parser.add_argument('img', help='Image file') + parser.add_argument('config', help='Config file') + parser.add_argument('checkpoint', help='Checkpoint file') + parser.add_argument('--gt_mask', default=None, help='Path of gt mask file') + parser.add_argument('--out-file', default=None, help='Path to output file') + parser.add_argument( + '--device', default='cuda:0', help='Device used for inference') + parser.add_argument( + '--opacity', + type=float, + default=0.5, + help='Opacity of painted segmentation map. In (0, 1] range.') + parser.add_argument( + '--title', default='result', help='The image identifier.') + args = parser.parse_args() + + register_all_modules() + + # build the model from a config file and a checkpoint file + model = init_model(args.config, args.checkpoint, device=args.device) + if args.device == 'cpu': + model = revert_sync_batchnorm(model) + + # show all named module in the model and use it in source list below + for name, module in model.named_modules(): + print(name) + + source = [ + 'decode_head.fusion.stages.0.query_project.activate', + 'decode_head.context.stages.0.key_project.activate', + 'decode_head.context.bottleneck.activate' + ] + source = dict.fromkeys(source) + + count = 0 + recorder = Recorder() + # registry the forward hook + for name, module in model.named_modules(): + if name in source: + count += 1 + module.register_forward_hook(recorder.record_data_hook) + if count == len(source): + break + + with recorder: + # test a single image, and record feature map to data_buffer + result = inference_model(model, args.img) + + visualize(args, model, recorder, result) + + +if __name__ == '__main__': + main() + +``` + +将上述代码保存为 feature_map_visual.py,在终端执行如下代码 + +```shell +python feature_map_visual.py ${图像} ${配置文件} ${检查点文件} [可选参数] +``` + +样例 + +```shell +python feature_map_visual.py \ +aachen_000000_000019_leftImg8bit.png \ +configs/ann/ann_r50-d8_4xb2-40k_cityscapes-512x1024.py \ +ann_r50-d8_512x1024_40k_cityscapes_20200605_095211-049fc292.pth \ +--gt_mask aachen_000000_000019_gtFine_labelTrainIds.png +``` + +可视化后的图像结果和它的对应的 feature map图像会出现在wandb账户中 + +
+ +
diff --git a/mmseg/__init__.py b/mmseg/__init__.py index 765ff4a042..9f171ccb0a 100644 --- a/mmseg/__init__.py +++ b/mmseg/__init__.py @@ -9,7 +9,7 @@ MMCV_MIN = '2.0.0rc4' MMCV_MAX = '2.1.0' -MMENGINE_MIN = '0.2.0' +MMENGINE_MIN = '0.5.0' MMENGINE_MAX = '1.0.0' diff --git a/mmseg/apis/__init__.py b/mmseg/apis/__init__.py index 9933b99b3c..d22dc3f0ad 100644 --- a/mmseg/apis/__init__.py +++ b/mmseg/apis/__init__.py @@ -1,4 +1,7 @@ # Copyright (c) OpenMMLab. All rights reserved. from .inference import inference_model, init_model, show_result_pyplot +from .mmseg_inferencer import MMSegInferencer -__all__ = ['init_model', 'inference_model', 'show_result_pyplot'] +__all__ = [ + 'init_model', 'inference_model', 'show_result_pyplot', 'MMSegInferencer' +] diff --git a/mmseg/apis/inference.py b/mmseg/apis/inference.py index d1cc545598..4aadffc798 100644 --- a/mmseg/apis/inference.py +++ b/mmseg/apis/inference.py @@ -9,6 +9,7 @@ import torch from mmengine import Config from mmengine.dataset import Compose +from mmengine.registry import init_default_scope from mmengine.runner import load_checkpoint from mmengine.utils import mkdir_or_exist @@ -48,6 +49,8 @@ def init_model(config: Union[str, Path, Config], config.model.backbone.init_cfg = None config.model.pretrained = None config.model.train_cfg = None + init_default_scope(config.get('default_scope', 'mmseg')) + model = MODELS.build(config.model) if checkpoint is not None: checkpoint = load_checkpoint(model, checkpoint, map_location='cpu') diff --git a/mmseg/apis/mmseg_inferencer.py b/mmseg/apis/mmseg_inferencer.py new file mode 100644 index 0000000000..cb387b10b3 --- /dev/null +++ b/mmseg/apis/mmseg_inferencer.py @@ -0,0 +1,361 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os.path as osp +import warnings +from typing import List, Optional, Sequence, Union + +import mmcv +import mmengine +import numpy as np +import torch +import torch.nn as nn +from mmcv.transforms import Compose +from mmengine.infer.infer import BaseInferencer, ModelType +from mmengine.model import revert_sync_batchnorm +from mmengine.registry import init_default_scope +from mmengine.runner.checkpoint import _load_checkpoint_to_model +from PIL import Image + +from mmseg.structures import SegDataSample +from mmseg.utils import ConfigType, SampleList, get_classes, get_palette +from mmseg.visualization import SegLocalVisualizer + +InputType = Union[str, np.ndarray] +InputsType = Union[InputType, Sequence[InputType]] +PredType = Union[SegDataSample, SampleList] + + +class MMSegInferencer(BaseInferencer): + """Semantic segmentation inferencer, provides inference and visualization + interfaces. Note: MMEngine >= 0.5.0 is required. + + Args: + model (str, optional): Path to the config file or the model name + defined in metafile. Take the `mmseg metafile `_ + as an example the `model` could be + "fcn_r50-d8_4xb2-40k_cityscapes-512x1024", and the weights of model + will be download automatically. If use config file, like + "configs/fcn/fcn_r50-d8_4xb2-40k_cityscapes-512x1024.py", the + `weights` should be defined. + weights (str, optional): Path to the checkpoint. If it is not specified + and model is a model name of metafile, the weights will be loaded + from metafile. Defaults to None. + classes (list, optional): Input classes for result rendering, as the + prediction of segmentation model is a segment map with label + indices, `classes` is a list which includes items responding to the + label indices. If classes is not defined, visualizer will take + `cityscapes` classes by default. Defaults to None. + palette (list, optional): Input palette for result rendering, which is + a list of color palette responding to the classes. If palette is + not defined, visualizer will take `cityscapes` palette by default. + Defaults to None. + dataset_name (str, optional): `Dataset name or alias `_ + visulizer will use the meta information of the dataset i.e. classes + and palette, but the `classes` and `palette` have higher priority. + Defaults to None. + device (str, optional): Device to run inference. If None, the available + device will be automatically used. Defaults to None. + scope (str, optional): The scope of the model. Defaults to 'mmseg'. + """ # noqa + + preprocess_kwargs: set = set() + forward_kwargs: set = {'mode', 'out_dir'} + visualize_kwargs: set = {'show', 'wait_time', 'img_out_dir', 'opacity'} + postprocess_kwargs: set = {'pred_out_dir', 'return_datasample'} + + def __init__(self, + model: Union[ModelType, str], + weights: Optional[str] = None, + classes: Optional[Union[str, List]] = None, + palette: Optional[Union[str, List]] = None, + dataset_name: Optional[str] = None, + device: Optional[str] = None, + scope: Optional[str] = 'mmseg') -> None: + # A global counter tracking the number of images processes, for + # naming of the output images + self.num_visualized_imgs = 0 + self.num_pred_imgs = 0 + init_default_scope(scope if scope else 'mmseg') + super().__init__( + model=model, weights=weights, device=device, scope=scope) + + if device == 'cpu' or not torch.cuda.is_available(): + self.model = revert_sync_batchnorm(self.model) + + assert isinstance(self.visualizer, SegLocalVisualizer) + self.visualizer.set_dataset_meta(palette, classes, dataset_name) + + def _load_weights_to_model(self, model: nn.Module, + checkpoint: Optional[dict], + cfg: Optional[ConfigType]) -> None: + """Loading model weights and meta information from cfg and checkpoint. + + Subclasses could override this method to load extra meta information + from ``checkpoint`` and ``cfg`` to model. + + Args: + model (nn.Module): Model to load weights and meta information. + checkpoint (dict, optional): The loaded checkpoint. + cfg (Config or ConfigDict, optional): The loaded config. + """ + + if checkpoint is not None: + _load_checkpoint_to_model(model, checkpoint) + checkpoint_meta = checkpoint.get('meta', {}) + # save the dataset_meta in the model for convenience + if 'dataset_meta' in checkpoint_meta: + # mmsegmentation 1.x + model.dataset_meta = { + 'classes': checkpoint_meta['dataset_meta'].get('classes'), + 'palette': checkpoint_meta['dataset_meta'].get('palette') + } + elif 'CLASSES' in checkpoint_meta: + # mmsegmentation 0.x + classes = checkpoint_meta['CLASSES'] + palette = checkpoint_meta.get('PALETTE', None) + model.dataset_meta = {'classes': classes, 'palette': palette} + else: + warnings.warn( + 'dataset_meta or class names are not saved in the ' + 'checkpoint\'s meta data, use classes of Cityscapes by ' + 'default.') + model.dataset_meta = { + 'classes': get_classes('cityscapes'), + 'palette': get_palette('cityscapes') + } + else: + warnings.warn('Checkpoint is not loaded, and the inference ' + 'result is calculated by the randomly initialized ' + 'model!') + warnings.warn( + 'weights is None, use cityscapes classes by default.') + model.dataset_meta = { + 'classes': get_classes('cityscapes'), + 'palette': get_palette('cityscapes') + } + + def __call__(self, + inputs: InputsType, + return_datasamples: bool = False, + batch_size: int = 1, + show: bool = False, + wait_time: int = 0, + out_dir: str = '', + img_out_dir: str = 'vis', + pred_out_dir: str = 'pred', + **kwargs) -> dict: + """Call the inferencer. + + Args: + inputs (Union[list, str, np.ndarray]): Inputs for the inferencer. + return_datasamples (bool): Whether to return results as + :obj:`SegDataSample`. Defaults to False. + batch_size (int): Batch size. Defaults to 1. + show (bool): Whether to display the rendering color segmentation + mask in a popup window. Defaults to False. + wait_time (float): The interval of show (s). Defaults to 0. + out_dir (str): Output directory of inference results. Defaults + to ''. + img_out_dir (str): Subdirectory of `out_dir`, used to save + rendering color segmentation mask, so `out_dir` must be defined + if you would like to save predicted mask. Defaults to 'vis'. + pred_out_dir (str): Subdirectory of `out_dir`, used to save + predicted mask file, so `out_dir` must be defined if you would + like to save predicted mask. Defaults to 'pred'. + + **kwargs: Other keyword arguments passed to :meth:`preprocess`, + :meth:`forward`, :meth:`visualize` and :meth:`postprocess`. + Each key in kwargs should be in the corresponding set of + ``preprocess_kwargs``, ``forward_kwargs``, ``visualize_kwargs`` + and ``postprocess_kwargs``. + + + Returns: + dict: Inference and visualization results. + """ + + if out_dir != '': + pred_out_dir = osp.join(out_dir, pred_out_dir) + img_out_dir = osp.join(out_dir, img_out_dir) + else: + pred_out_dir = '' + img_out_dir = '' + + return super().__call__( + inputs=inputs, + return_datasamples=return_datasamples, + batch_size=batch_size, + show=show, + wait_time=wait_time, + img_out_dir=img_out_dir, + pred_out_dir=pred_out_dir, + **kwargs) + + def visualize(self, + inputs: list, + preds: List[dict], + show: bool = False, + wait_time: int = 0, + img_out_dir: str = '', + opacity: float = 0.8) -> List[np.ndarray]: + """Visualize predictions. + + Args: + inputs (list): Inputs preprocessed by :meth:`_inputs_to_list`. + preds (Any): Predictions of the model. + show (bool): Whether to display the image in a popup window. + Defaults to False. + wait_time (float): The interval of show (s). Defaults to 0. + img_out_dir (str): Output directory of rendering prediction i.e. + color segmentation mask. Defaults: '' + opacity (int, float): The transparency of segmentation mask. + Defaults to 0.8. + + Returns: + List[np.ndarray]: Visualization results. + """ + if self.visualizer is None or (not show and img_out_dir == ''): + return None + + if getattr(self, 'visualizer') is None: + raise ValueError('Visualization needs the "visualizer" term' + 'defined in the config, but got None') + self.visualizer.set_dataset_meta(**self.model.dataset_meta) + self.visualizer.alpha = opacity + + results = [] + + for single_input, pred in zip(inputs, preds): + if isinstance(single_input, str): + img_bytes = mmengine.fileio.get(single_input) + img = mmcv.imfrombytes(img_bytes) + img = img[:, :, ::-1] + img_name = osp.basename(single_input) + elif isinstance(single_input, np.ndarray): + img = single_input.copy() + img_num = str(self.num_visualized_imgs).zfill(8) + '_vis' + img_name = f'{img_num}.jpg' + else: + raise ValueError('Unsupported input type:' + f'{type(single_input)}') + + out_file = osp.join(img_out_dir, img_name) if img_out_dir != ''\ + else None + + self.visualizer.add_datasample( + img_name, + img, + pred, + show=show, + wait_time=wait_time, + draw_gt=False, + draw_pred=True, + out_file=out_file) + results.append(self.visualizer.get_image()) + self.num_visualized_imgs += 1 + + return results + + def postprocess(self, + preds: PredType, + visualization: List[np.ndarray], + return_datasample: bool = False, + pred_out_dir: str = '') -> dict: + """Process the predictions and visualization results from ``forward`` + and ``visualize``. + + This method should be responsible for the following tasks: + + 1. Pack the predictions and visualization results and return them. + 2. Save the predictions, if it needed. + + Args: + preds (List[Dict]): Predictions of the model. + visualization (List[np.ndarray]): The list of rendering color + segmentation mask. + return_datasample (bool): Whether to return results as datasamples. + Defaults to False. + pred_out_dir: File to save the inference results w/o + visualization. If left as empty, no file will be saved. + Defaults to ''. + + Returns: + dict: Inference and visualization results with key ``predictions`` + and ``visualization`` + + - ``visualization (Any)``: Returned by :meth:`visualize` + - ``predictions`` (List[np.ndarray], np.ndarray): Returned by + :meth:`forward` and processed in :meth:`postprocess`. + If ``return_datasample=False``, it will be the segmentation mask + with label indice. + """ + if return_datasample: + if len(preds) == 1: + return preds[0] + else: + return preds + + results_dict = {} + + results_dict['predictions'] = [] + results_dict['visualization'] = [] + + for i, pred in enumerate(preds): + pred_data = pred.pred_sem_seg.numpy().data[0] + results_dict['predictions'].append(pred_data) + if visualization is not None: + vis = visualization[i] + results_dict['visualization'].append(vis) + if pred_out_dir != '': + mmengine.mkdir_or_exist(pred_out_dir) + img_name = str(self.num_pred_imgs).zfill(8) + '_pred.png' + img_path = osp.join(pred_out_dir, img_name) + output = Image.fromarray(pred_data.astype(np.uint8)) + output.save(img_path) + self.num_pred_imgs += 1 + + if len(results_dict['predictions']) == 1: + results_dict['predictions'] = results_dict['predictions'][0] + if visualization is not None: + results_dict['visualization'] = \ + results_dict['visualization'][0] + return results_dict + + def _init_pipeline(self, cfg: ConfigType) -> Compose: + """Initialize the test pipeline. + + Return a pipeline to handle various input data, such as ``str``, + ``np.ndarray``. It is an abstract method in BaseInferencer, and should + be implemented in subclasses. + + The returned pipeline will be used to process a single data. + It will be used in :meth:`preprocess` like this: + + .. code-block:: python + def preprocess(self, inputs, batch_size, **kwargs): + ... + dataset = map(self.pipeline, dataset) + ... + """ + pipeline_cfg = cfg.test_dataloader.dataset.pipeline + # Loading annotations is also not applicable + idx = self._get_transform_idx(pipeline_cfg, 'LoadAnnotations') + if idx != -1: + del pipeline_cfg[idx] + load_img_idx = self._get_transform_idx(pipeline_cfg, + 'LoadImageFromFile') + + if load_img_idx == -1: + raise ValueError( + 'LoadImageFromFile is not found in the test pipeline') + pipeline_cfg[load_img_idx]['type'] = 'InferencerLoader' + return Compose(pipeline_cfg) + + def _get_transform_idx(self, pipeline_cfg: ConfigType, name: str) -> int: + """Returns the index of the transform in a pipeline. + + If the transform is not found, returns -1. + """ + for i, transform in enumerate(pipeline_cfg): + if transform['type'] == name: + return i + return -1 diff --git a/mmseg/datasets/__init__.py b/mmseg/datasets/__init__.py index 8aa2e8d1a8..0dd19ee312 100644 --- a/mmseg/datasets/__init__.py +++ b/mmseg/datasets/__init__.py @@ -17,6 +17,7 @@ from .night_driving import NightDrivingDataset from .pascal_context import PascalContextDataset, PascalContextDataset59 from .potsdam import PotsdamDataset +from .refuge import REFUGEDataset from .stare import STAREDataset from .synapse import SynapseDataset # yapf: disable @@ -48,5 +49,5 @@ 'DecathlonDataset', 'LIPDataset', 'ResizeShortestEdge', 'BioMedicalGaussianNoise', 'BioMedicalGaussianBlur', 'BioMedicalRandomGamma', 'BioMedical3DPad', 'RandomRotFlip', - 'SynapseDataset' + 'SynapseDataset', 'REFUGEDataset' ] diff --git a/mmseg/datasets/basesegdataset.py b/mmseg/datasets/basesegdataset.py index bf433b2094..ddf476bae9 100644 --- a/mmseg/datasets/basesegdataset.py +++ b/mmseg/datasets/basesegdataset.py @@ -73,38 +73,36 @@ class BaseSegDataset(BaseDataset): ignore_index (int): The label index to be ignored. Default: 255 reduce_zero_label (bool): Whether to mark label zero as ignored. Default to False. - backend_args (dict): Arguments to instantiate a file backend. + backend_args (dict, Optional): Arguments to instantiate a file backend. See https://mmengine.readthedocs.io/en/latest/api/fileio.htm - for details. Defaults to ``dict(backend='local')`` + for details. Defaults to None. Notes: mmcv>=2.0.0rc4, mmengine>=0.2.0 required. """ METAINFO: dict = dict() - def __init__( - self, - ann_file: str = '', - img_suffix='.jpg', - seg_map_suffix='.png', - metainfo: Optional[dict] = None, - data_root: Optional[str] = None, - data_prefix: dict = dict(img_path='', seg_map_path=''), - filter_cfg: Optional[dict] = None, - indices: Optional[Union[int, Sequence[int]]] = None, - serialize_data: bool = True, - pipeline: List[Union[dict, Callable]] = [], - test_mode: bool = False, - lazy_init: bool = False, - max_refetch: int = 1000, - ignore_index: int = 255, - reduce_zero_label: bool = False, - backend_args: dict = dict(backend='local') - ) -> None: + def __init__(self, + ann_file: str = '', + img_suffix='.jpg', + seg_map_suffix='.png', + metainfo: Optional[dict] = None, + data_root: Optional[str] = None, + data_prefix: dict = dict(img_path='', seg_map_path=''), + filter_cfg: Optional[dict] = None, + indices: Optional[Union[int, Sequence[int]]] = None, + serialize_data: bool = True, + pipeline: List[Union[dict, Callable]] = [], + test_mode: bool = False, + lazy_init: bool = False, + max_refetch: int = 1000, + ignore_index: int = 255, + reduce_zero_label: bool = False, + backend_args: Optional[dict] = None) -> None: self.img_suffix = img_suffix self.seg_map_suffix = seg_map_suffix self.ignore_index = ignore_index self.reduce_zero_label = reduce_zero_label - self.backend_args = backend_args.copy() + self.backend_args = backend_args.copy() if backend_args else None self.data_root = data_root self.data_prefix = copy.copy(data_prefix) diff --git a/mmseg/datasets/refuge.py b/mmseg/datasets/refuge.py new file mode 100644 index 0000000000..4016a825a3 --- /dev/null +++ b/mmseg/datasets/refuge.py @@ -0,0 +1,28 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import mmengine.fileio as fileio + +from mmseg.registry import DATASETS +from .basesegdataset import BaseSegDataset + + +@DATASETS.register_module() +class REFUGEDataset(BaseSegDataset): + """REFUGE dataset. + + In segmentation map annotation for REFUGE, 0 stands for background, which + is not included in 2 categories. ``reduce_zero_label`` is fixed to True. + The ``img_suffix`` is fixed to '.png' and ``seg_map_suffix`` is fixed to + '.png'. + """ + METAINFO = dict( + classes=('background', ' Optic Cup', 'Optic Disc'), + palette=[[120, 120, 120], [6, 230, 230], [56, 59, 120]]) + + def __init__(self, **kwargs) -> None: + super().__init__( + img_suffix='.png', + seg_map_suffix='.png', + reduce_zero_label=False, + **kwargs) + assert fileio.exists( + self.data_prefix['img_path'], backend_args=self.backend_args) diff --git a/mmseg/datasets/transforms/formatting.py b/mmseg/datasets/transforms/formatting.py index f4018f788f..4391161dfd 100644 --- a/mmseg/datasets/transforms/formatting.py +++ b/mmseg/datasets/transforms/formatting.py @@ -63,8 +63,12 @@ def transform(self, results: dict) -> dict: img = results['img'] if len(img.shape) < 3: img = np.expand_dims(img, -1) - img = np.ascontiguousarray(img.transpose(2, 0, 1)) - packed_results['inputs'] = to_tensor(img) + if not img.flags.c_contiguous: + img = to_tensor(np.ascontiguousarray(img.transpose(2, 0, 1))) + else: + img = img.transpose(2, 0, 1) + img = to_tensor(img).contiguous() + packed_results['inputs'] = img data_sample = SegDataSample() if 'gt_seg_map' in results: diff --git a/mmseg/datasets/transforms/loading.py b/mmseg/datasets/transforms/loading.py index 5a413717b6..d2e93b1abb 100644 --- a/mmseg/datasets/transforms/loading.py +++ b/mmseg/datasets/transforms/loading.py @@ -1,6 +1,6 @@ # Copyright (c) OpenMMLab. All rights reserved. import warnings -from typing import Dict +from typing import Dict, Optional, Union import mmcv import mmengine.fileio as fileio @@ -56,14 +56,14 @@ class LoadAnnotations(MMCV_LoadAnnotations): Defaults to 'pillow'. backend_args (dict): Arguments to instantiate a file backend. See https://mmengine.readthedocs.io/en/latest/api/fileio.htm - for details. Defaults to ``dict(backend='local')`` + for details. Defaults to None. Notes: mmcv>=2.0.0rc4, mmengine>=0.2.0 required. """ def __init__( self, reduce_zero_label=None, - backend_args=dict(backend='local'), + backend_args=None, imdecode_backend='pillow', ) -> None: super().__init__( @@ -203,23 +203,21 @@ class LoadBiomedicalImageFromFile(BaseTransform): to_float32 (bool): Whether to convert the loaded image to a float32 numpy array. If set to False, the loaded image is an float64 array. Defaults to True. - backend_args (dict): Arguments to instantiate a file backend. + backend_args (dict, Optional): Arguments to instantiate a file backend. See https://mmengine.readthedocs.io/en/latest/api/fileio.htm - for details. Defaults to ``dict(backend='local')`` + for details. Defaults to None. Notes: mmcv>=2.0.0rc4, mmengine>=0.2.0 required. """ - def __init__( - self, - decode_backend: str = 'nifti', - to_xyz: bool = False, - to_float32: bool = True, - backend_args: dict = dict(backend='local') - ) -> None: + def __init__(self, + decode_backend: str = 'nifti', + to_xyz: bool = False, + to_float32: bool = True, + backend_args: Optional[dict] = None) -> None: self.decode_backend = decode_backend self.to_xyz = to_xyz self.to_float32 = to_float32 - self.backend_args = backend_args.copy() + self.backend_args = backend_args.copy() if backend_args else None def transform(self, results: Dict) -> Dict: """Functions to load image. @@ -295,24 +293,22 @@ class LoadBiomedicalAnnotation(BaseTransform): to_float32 (bool): Whether to convert the loaded seg map to a float32 numpy array. If set to False, the loaded image is an float64 array. Defaults to True. - backend_args (dict): Arguments to instantiate a file backend. + backend_args (dict, Optional): Arguments to instantiate a file backend. See :class:`mmengine.fileio` for details. - Defaults to ``dict(backend='local')``. + Defaults to None. Notes: mmcv>=2.0.0rc4, mmengine>=0.2.0 required. """ - def __init__( - self, - decode_backend: str = 'nifti', - to_xyz: bool = False, - to_float32: bool = True, - backend_args: dict = dict(backend='local') - ) -> None: + def __init__(self, + decode_backend: str = 'nifti', + to_xyz: bool = False, + to_float32: bool = True, + backend_args: Optional[dict] = None) -> None: super().__init__() self.decode_backend = decode_backend self.to_xyz = to_xyz self.to_float32 = to_float32 - self.backend_args = backend_args.copy() + self.backend_args = backend_args.copy() if backend_args else None def transform(self, results: Dict) -> Dict: """Functions to load image. @@ -384,23 +380,21 @@ class LoadBiomedicalData(BaseTransform): backend is 'nifti'. Defaults to 'nifti'. to_xyz (bool): Whether transpose data from Z, Y, X to X, Y, Z. Defaults to False. - backend_args (dict): Arguments to instantiate a file backend. + backend_args (dict, Optional): Arguments to instantiate a file backend. See https://mmengine.readthedocs.io/en/latest/api/fileio.htm - for details. Defaults to ``dict(backend='local')`` + for details. Defaults to None. Notes: mmcv>=2.0.0rc4, mmengine>=0.2.0 required. """ - def __init__( - self, - with_seg=False, - decode_backend: str = 'numpy', - to_xyz: bool = False, - backend_args: dict = dict(backend='local') - ) -> None: # noqa + def __init__(self, + with_seg=False, + decode_backend: str = 'numpy', + to_xyz: bool = False, + backend_args: Optional[dict] = None) -> None: # noqa self.with_seg = with_seg self.decode_backend = decode_backend self.to_xyz = to_xyz - self.backend_args = backend_args.copy() + self.backend_args = backend_args.copy() if backend_args else None def transform(self, results: Dict) -> Dict: """Functions to load image. @@ -443,3 +437,59 @@ def __repr__(self) -> str: f'to_xyz={self.to_xyz}, ' f'backend_args={self.backend_args})') return repr_str + + +@TRANSFORMS.register_module() +class InferencerLoader(BaseTransform): + """Load an image from ``results['img']``. + + Similar with :obj:`LoadImageFromFile`, but the image has been loaded as + :obj:`np.ndarray` in ``results['img']``. Can be used when loading image + from webcam. + + Required Keys: + + - img + + Modified Keys: + + - img + - img_path + - img_shape + - ori_shape + + Args: + to_float32 (bool): Whether to convert the loaded image to a float32 + numpy array. If set to False, the loaded image is an uint8 array. + Defaults to False. + """ + + def __init__(self, **kwargs) -> None: + super().__init__() + self.from_file = TRANSFORMS.build( + dict(type='LoadImageFromFile', **kwargs)) + self.from_ndarray = TRANSFORMS.build( + dict(type='LoadImageFromNDArray', **kwargs)) + + def transform(self, single_input: Union[str, np.ndarray, dict]) -> dict: + """Transform function to add image meta information. + + Args: + results (dict): Result dict with Webcam read image in + ``results['img']``. + + Returns: + dict: The dict contains loaded image and meta information. + """ + if isinstance(single_input, str): + inputs = dict(img_path=single_input) + elif isinstance(single_input, np.ndarray): + inputs = dict(img=single_input) + elif isinstance(single_input, dict): + inputs = single_input + else: + raise NotImplementedError + + if 'img' in inputs: + return self.from_ndarray(inputs) + return self.from_file(inputs) diff --git a/mmseg/engine/hooks/visualization_hook.py b/mmseg/engine/hooks/visualization_hook.py index 25aa1cf8b5..1e7c97afe8 100644 --- a/mmseg/engine/hooks/visualization_hook.py +++ b/mmseg/engine/hooks/visualization_hook.py @@ -1,7 +1,7 @@ # Copyright (c) OpenMMLab. All rights reserved. import os.path as osp import warnings -from typing import Sequence +from typing import Optional, Sequence import mmcv import mmengine.fileio as fileio @@ -30,9 +30,9 @@ class SegVisualizationHook(Hook): interval (int): The interval of visualization. Defaults to 50. show (bool): Whether to display the drawn image. Default to False. wait_time (float): The interval of show (s). Defaults to 0. - backend_args (dict): Arguments to instantiate a file backend. + backend_args (dict, Optional): Arguments to instantiate a file backend. See https://mmengine.readthedocs.io/en/latest/api/fileio.htm - for details. Defaults to ``dict(backend='local')`` + for details. Defaults to None. Notes: mmcv>=2.0.0rc4, mmengine>=0.2.0 required. """ @@ -41,7 +41,7 @@ def __init__(self, interval: int = 50, show: bool = False, wait_time: float = 0., - backend_args: dict = dict(backend='local')): + backend_args: Optional[dict] = None): self._visualizer: SegLocalVisualizer = \ SegLocalVisualizer.get_current_instance() self.interval = interval @@ -55,7 +55,7 @@ def __init__(self, 'needs to be excluded.') self.wait_time = wait_time - self.backend_args = backend_args.copy() + self.backend_args = backend_args.copy() if backend_args else None self.draw = draw if not self.draw: warnings.warn('The draw is False, it means that the ' diff --git a/mmseg/models/segmentors/cascade_encoder_decoder.py b/mmseg/models/segmentors/cascade_encoder_decoder.py index c932b43069..0184a3533a 100644 --- a/mmseg/models/segmentors/cascade_encoder_decoder.py +++ b/mmseg/models/segmentors/cascade_encoder_decoder.py @@ -68,6 +68,7 @@ def _init_decode_head(self, decode_head: ConfigType) -> None: self.decode_head.append(MODELS.build(decode_head[i])) self.align_corners = self.decode_head[-1].align_corners self.num_classes = self.decode_head[-1].num_classes + self.out_channels = self.decode_head[-1].out_channels def encode_decode(self, inputs: Tensor, batch_img_metas: List[dict]) -> Tensor: diff --git a/mmseg/registry/__init__.py b/mmseg/registry/__init__.py index c646b7e5ac..ee514d1a2a 100644 --- a/mmseg/registry/__init__.py +++ b/mmseg/registry/__init__.py @@ -1,13 +1,15 @@ # Copyright (c) OpenMMLab. All rights reserved. -from .registry import (DATA_SAMPLERS, DATASETS, HOOKS, LOOPS, METRICS, - MODEL_WRAPPERS, MODELS, OPTIM_WRAPPER_CONSTRUCTORS, - OPTIMIZERS, PARAM_SCHEDULERS, RUNNER_CONSTRUCTORS, - RUNNERS, TASK_UTILS, TRANSFORMS, VISBACKENDS, - VISUALIZERS, WEIGHT_INITIALIZERS) +from .registry import (DATA_SAMPLERS, DATASETS, EVALUATOR, HOOKS, INFERENCERS, + LOG_PROCESSORS, LOOPS, METRICS, MODEL_WRAPPERS, MODELS, + OPTIM_WRAPPER_CONSTRUCTORS, OPTIM_WRAPPERS, OPTIMIZERS, + PARAM_SCHEDULERS, RUNNER_CONSTRUCTORS, RUNNERS, + TASK_UTILS, TRANSFORMS, VISBACKENDS, VISUALIZERS, + WEIGHT_INITIALIZERS) __all__ = [ - 'RUNNERS', 'RUNNER_CONSTRUCTORS', 'HOOKS', 'DATASETS', 'DATA_SAMPLERS', - 'TRANSFORMS', 'MODELS', 'WEIGHT_INITIALIZERS', 'OPTIMIZERS', - 'OPTIM_WRAPPER_CONSTRUCTORS', 'TASK_UTILS', 'PARAM_SCHEDULERS', 'METRICS', - 'MODEL_WRAPPERS', 'LOOPS', 'VISBACKENDS', 'VISUALIZERS' + 'HOOKS', 'DATASETS', 'DATA_SAMPLERS', 'TRANSFORMS', 'MODELS', + 'WEIGHT_INITIALIZERS', 'OPTIMIZERS', 'OPTIM_WRAPPER_CONSTRUCTORS', + 'TASK_UTILS', 'PARAM_SCHEDULERS', 'METRICS', 'MODEL_WRAPPERS', + 'VISBACKENDS', 'VISUALIZERS', 'RUNNERS', 'RUNNER_CONSTRUCTORS', 'LOOPS', + 'EVALUATOR', 'LOG_PROCESSORS', 'OPTIM_WRAPPERS', 'INFERENCERS' ] diff --git a/mmseg/registry/registry.py b/mmseg/registry/registry.py index 5c9977ab8d..32684e758f 100644 --- a/mmseg/registry/registry.py +++ b/mmseg/registry/registry.py @@ -10,6 +10,7 @@ from mmengine.registry import DATASETS as MMENGINE_DATASETS from mmengine.registry import EVALUATOR as MMENGINE_EVALUATOR from mmengine.registry import HOOKS as MMENGINE_HOOKS +from mmengine.registry import INFERENCERS as MMENGINE_INFERENCERS from mmengine.registry import LOG_PROCESSORS as MMENGINE_LOG_PROCESSORS from mmengine.registry import LOOPS as MMENGINE_LOOPS from mmengine.registry import METRICS as MMENGINE_METRICS @@ -39,45 +40,82 @@ # manage all kinds of loops like `EpochBasedTrainLoop` LOOPS = Registry('loop', parent=MMENGINE_LOOPS) # manage all kinds of hooks like `CheckpointHook` -HOOKS = Registry('hook', parent=MMENGINE_HOOKS) +HOOKS = Registry( + 'hook', parent=MMENGINE_HOOKS, locations=['mmseg.engine.hooks']) # manage data-related modules -DATASETS = Registry('dataset', parent=MMENGINE_DATASETS) -DATA_SAMPLERS = Registry('data sampler', parent=MMENGINE_DATA_SAMPLERS) -TRANSFORMS = Registry('transform', parent=MMENGINE_TRANSFORMS) +DATASETS = Registry( + 'dataset', parent=MMENGINE_DATASETS, locations=['mmseg.datasets']) +DATA_SAMPLERS = Registry( + 'data sampler', + parent=MMENGINE_DATA_SAMPLERS, + locations=['mmseg.datasets.samplers']) +TRANSFORMS = Registry( + 'transform', + parent=MMENGINE_TRANSFORMS, + locations=['mmseg.datasets.transforms']) # mangage all kinds of modules inheriting `nn.Module` -MODELS = Registry('model', parent=MMENGINE_MODELS) +MODELS = Registry('model', parent=MMENGINE_MODELS, locations=['mmseg.models']) # mangage all kinds of model wrappers like 'MMDistributedDataParallel' -MODEL_WRAPPERS = Registry('model_wrapper', parent=MMENGINE_MODEL_WRAPPERS) +MODEL_WRAPPERS = Registry( + 'model_wrapper', + parent=MMENGINE_MODEL_WRAPPERS, + locations=['mmseg.models']) # mangage all kinds of weight initialization modules like `Uniform` WEIGHT_INITIALIZERS = Registry( - 'weight initializer', parent=MMENGINE_WEIGHT_INITIALIZERS) + 'weight initializer', + parent=MMENGINE_WEIGHT_INITIALIZERS, + locations=['mmseg.models']) # mangage all kinds of optimizers like `SGD` and `Adam` -OPTIMIZERS = Registry('optimizer', parent=MMENGINE_OPTIMIZERS) +OPTIMIZERS = Registry( + 'optimizer', + parent=MMENGINE_OPTIMIZERS, + locations=['mmseg.engine.optimizers']) # manage optimizer wrapper -OPTIM_WRAPPERS = Registry('optim_wrapper', parent=MMENGINE_OPTIM_WRAPPERS) +OPTIM_WRAPPERS = Registry( + 'optim_wrapper', + parent=MMENGINE_OPTIM_WRAPPERS, + locations=['mmseg.engine.optimizers']) # manage constructors that customize the optimization hyperparameters. OPTIM_WRAPPER_CONSTRUCTORS = Registry( 'optimizer wrapper constructor', - parent=MMENGINE_OPTIM_WRAPPER_CONSTRUCTORS) + parent=MMENGINE_OPTIM_WRAPPER_CONSTRUCTORS, + locations=['mmseg.engine.optimizers']) # mangage all kinds of parameter schedulers like `MultiStepLR` PARAM_SCHEDULERS = Registry( - 'parameter scheduler', parent=MMENGINE_PARAM_SCHEDULERS) + 'parameter scheduler', + parent=MMENGINE_PARAM_SCHEDULERS, + locations=['mmseg.engine.schedulers']) # manage all kinds of metrics -METRICS = Registry('metric', parent=MMENGINE_METRICS) +METRICS = Registry( + 'metric', parent=MMENGINE_METRICS, locations=['mmseg.evaluation']) # manage evaluator -EVALUATOR = Registry('evaluator', parent=MMENGINE_EVALUATOR) +EVALUATOR = Registry( + 'evaluator', parent=MMENGINE_EVALUATOR, locations=['mmseg.evaluation']) # manage task-specific modules like ohem pixel sampler -TASK_UTILS = Registry('task util', parent=MMENGINE_TASK_UTILS) +TASK_UTILS = Registry( + 'task util', parent=MMENGINE_TASK_UTILS, locations=['mmseg.models']) # manage visualizer -VISUALIZERS = Registry('visualizer', parent=MMENGINE_VISUALIZERS) +VISUALIZERS = Registry( + 'visualizer', + parent=MMENGINE_VISUALIZERS, + locations=['mmseg.visualization']) # manage visualizer backend -VISBACKENDS = Registry('vis_backend', parent=MMENGINE_VISBACKENDS) +VISBACKENDS = Registry( + 'vis_backend', + parent=MMENGINE_VISBACKENDS, + locations=['mmseg.visualization']) # manage logprocessor -LOG_PROCESSORS = Registry('log_processor', parent=MMENGINE_LOG_PROCESSORS) +LOG_PROCESSORS = Registry( + 'log_processor', + parent=MMENGINE_LOG_PROCESSORS, + locations=['mmseg.visualization']) + +# manage inferencer +INFERENCERS = Registry('inferencer', parent=MMENGINE_INFERENCERS) diff --git a/mmseg/version.py b/mmseg/version.py index 10ceca8120..ef8e391a29 100644 --- a/mmseg/version.py +++ b/mmseg/version.py @@ -1,6 +1,6 @@ # Copyright (c) Open-MMLab. All rights reserved. -__version__ = '1.0.0rc5' +__version__ = '1.0.0rc6' def parse_version_info(version_str): diff --git a/mmseg/visualization/local_visualizer.py b/mmseg/visualization/local_visualizer.py index 27443f2c57..d11ad79c81 100644 --- a/mmseg/visualization/local_visualizer.py +++ b/mmseg/visualization/local_visualizer.py @@ -1,5 +1,5 @@ # Copyright (c) OpenMMLab. All rights reserved. -from typing import Dict, List, Optional, Tuple, Union +from typing import Dict, List, Optional import mmcv import numpy as np @@ -24,6 +24,17 @@ class SegLocalVisualizer(Visualizer): Defaults to None. save_dir (str, optional): Save file dir for all storage backends. If it is None, the backend storage will not save any data. + classes (list, optional): Input classes for result rendering, as the + prediction of segmentation model is a segment map with label + indices, `classes` is a list which includes items responding to the + label indices. If classes is not defined, visualizer will take + `cityscapes` classes by default. Defaults to None. + palette (list, optional): Input palette for result rendering, which is + a list of color palette responding to the classes. Defaults to None. + dataset_name (str, optional): `Dataset name or alias `_ + visulizer will use the meta information of the dataset i.e. classes + and palette, but the `classes` and `palette` have higher priority. + Defaults to None. alpha (int, float): The transparency of segmentation mask. Defaults to 0.8. @@ -49,43 +60,40 @@ class SegLocalVisualizer(Visualizer): >>> seg_local_visualizer.add_datasample( ... 'visualizer_example', image, ... gt_seg_data_sample, show=True) - """ + """ # noqa def __init__(self, name: str = 'visualizer', image: Optional[np.ndarray] = None, vis_backends: Optional[Dict] = None, save_dir: Optional[str] = None, - palette: Optional[Union[str, List]] = None, - classes: Optional[Union[str, List]] = None, + classes: Optional[List] = None, + palette: Optional[List] = None, dataset_name: Optional[str] = None, alpha: float = 0.8, **kwargs): super().__init__(name, image, vis_backends, save_dir, **kwargs) self.alpha: float = alpha - # Set default value. When calling - # `SegLocalVisualizer().dataset_meta=xxx`, - # it will override the default value. - if dataset_name is None: - dataset_name = 'cityscapes' - classes = classes if classes else get_classes(dataset_name) - palette = palette if palette else get_palette(dataset_name) - assert len(classes) == len( - palette), 'The length of classes should be equal to palette' - self.dataset_meta: dict = {'classes': classes, 'palette': palette} + self.set_dataset_meta(palette, classes, dataset_name) def _draw_sem_seg(self, image: np.ndarray, sem_seg: PixelData, - classes: Optional[Tuple[str]], - palette: Optional[List[List[int]]]) -> np.ndarray: + classes: Optional[List], + palette: Optional[List]) -> np.ndarray: """Draw semantic seg of GT or prediction. Args: image (np.ndarray): The image to draw. - sem_seg (:obj:`PixelData`): Data structure for - pixel-level annotations or predictions. - classes (Tuple[str], optional): Category information. - palette (List[List[int]], optional): The palette of - segmentation map. + sem_seg (:obj:`PixelData`): Data structure for pixel-level + annotations or predictions. + classes (list, optional): Input classes for result rendering, as + the prediction of segmentation model is a segment map with + label indices, `classes` is a list which includes items + responding to the label indices. If classes is not defined, + visualizer will take `cityscapes` classes by default. + Defaults to None. + palette (list, optional): Input palette for result rendering, which + is a list of color palette responding to the classes. + Defaults to None. Returns: np.ndarray: the drawn image which channel is RGB. @@ -109,6 +117,38 @@ def _draw_sem_seg(self, image: np.ndarray, sem_seg: PixelData, return self.get_image() + def set_dataset_meta(self, + classes: Optional[List] = None, + palette: Optional[List] = None, + dataset_name: Optional[str] = None) -> None: + """Set meta information to visualizer. + + Args: + classes (list, optional): Input classes for result rendering, as + the prediction of segmentation model is a segment map with + label indices, `classes` is a list which includes items + responding to the label indices. If classes is not defined, + visualizer will take `cityscapes` classes by default. + Defaults to None. + palette (list, optional): Input palette for result rendering, which + is a list of color palette responding to the classes. + Defaults to None. + dataset_name (str, optional): `Dataset name or alias `_ + visulizer will use the meta information of the dataset i.e. + classes and palette, but the `classes` and `palette` have + higher priority. Defaults to None. + """ # noqa + # Set default value. When calling + # `SegLocalVisualizer().dataset_meta=xxx`, + # it will override the default value. + if dataset_name is None: + dataset_name = 'cityscapes' + classes = classes if classes else get_classes(dataset_name) + palette = palette if palette else get_palette(dataset_name) + assert len(classes) == len( + palette), 'The length of classes should be equal to palette' + self.dataset_meta: dict = {'classes': classes, 'palette': palette} + @master_only def add_datasample( self, @@ -186,6 +226,6 @@ def add_datasample( self.show(drawn_img, win_name=name, wait_time=wait_time) if out_file is not None: - mmcv.imwrite(drawn_img, out_file) + mmcv.imwrite(mmcv.bgr2rgb(drawn_img), out_file) else: self.add_image(name, drawn_img, step) diff --git a/projects/README.md b/projects/README.md index 40d515eda3..5482c479aa 100644 --- a/projects/README.md +++ b/projects/README.md @@ -1,9 +1,19 @@ # Projects -Implementing new models and features into OpenMMLab's algorithm libraries could be troublesome due to the rigorous requirements on code quality, which could hinder the fast iteration of SOTA models and might discourage our members from sharing their latest outcomes here. +The OpenMMLab ecosystem can only grow through the contributions of the community. +Everyone is welcome to post their implementation of any great ideas in this folder! If you wish to start your own project, please go through the [example project](example_project/) for the best practice. For common questions about projects, please read our [faq](faq.md). -And that's why we have this `Projects/` folder now, where some experimental features, frameworks and models are placed, only needed to satisfy the minimum requirement on the code quality, and can be used as standalone libraries. Users are welcome to use them if they [use MMSegmentation from source](https://mmsegmentation.readthedocs.io/en/dev-1.x/get_started.html#best-practices). +## External Projects -Everyone is welcome to post their implementation of any great ideas in this folder! If you wish to start your own project, please go through the [example project](example_project/) for the best practice. +There are also selected external projects released in the community that use MMSegmentation: -Note: The core maintainers of MMSegmentation only ensure the results are reproducible and the code quality meets its claim at the time each project was submitted, but they may not be responsible for future maintenance. The original authors take responsibility for maintaining their own projects. +- [SegNeXt: Rethinking Convolutional Attention Design for Semantic Segmentation](https://github.com/visual-attention-network/segnext) +- [Vision Transformer Adapter for Dense Predictions](https://github.com/czczup/ViT-Adapter) +- [UniFormer: Unifying Convolution and Self-attention for Visual Recognition](https://github.com/Sense-X/UniFormer) +- [Multi-Scale High-Resolution Vision Transformer for Semantic Segmentation](https://github.com/facebookresearch/HRViT) +- [ViTAE: Vision Transformer Advanced by Exploring Intrinsic Inductive Bias](https://github.com/ViTAE-Transformer/ViTAE-Transformer) +- [DAFormer: Improving Network Architectures and Training Strategies for Domain-Adaptive Semantic Segmentation](https://github.com/lhoyer/DAFormer) +- [MPViT : Multi-Path Vision Transformer for Dense Prediction](https://github.com/youngwanLEE/MPViT) +- [TopFormer: Token Pyramid Transformer for Mobile Semantic Segmentation](https://github.com/hustvl/TopFormer) + +Note: These projects are supported and maintained by their own contributors. The core maintainers of MMSegmentation only ensure the results are reproducible and the code quality meets its claim at the time each project was submitted, but they may not be responsible for future maintenance. diff --git a/projects/example_project/README.md b/projects/example_project/README.md index 27ca5d4e2a..4338b8acac 100644 --- a/projects/example_project/README.md +++ b/projects/example_project/README.md @@ -1,20 +1,26 @@ # Dummy ResNet Wrapper -This is an example README for community `projects/`. We have provided detailed explanations for each field in the form of html comments, which are visible when you read the source of this README file. If you wish to submit your project to our main repository, then all the fields in this README are mandatory for others to understand what you have achieved in this implementation. For more details, read our [contribution guide](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/.github/CONTRIBUTING.md) or approach us in [Discussions](https://github.com/open-mmlab/mmsegmentation/discussions). +> A README.md template for releasing a project. +> +> All the fields in this README are **mandatory** for others to understand what you have achieved in this implementation. +> Please read our [Projects FAQ](../faq.md) if you still feel unclear about the requirements, or raise an [issue](https://github.com/open-mmlab/mmsegmentation/issues) to us! ## Description - +Author: @xxx. This project implements a dummy ResNet wrapper, which literally does nothing new but prints "hello world" during initialization. ## Usage - +> For a typical model, this section should contain the commands for training and testing. +> You are also suggested to dump your environment specification to env.yml by `conda env export > env.yml`. ### Prerequisites @@ -47,9 +53,8 @@ mim train mmsegmentation configs/fcn_dummy-r50-d8_4xb2-40k_cityscapes-512x1024.p mim test mmsegmentation configs/fcn_dummy-r50-d8_4xb2-40k_cityscapes-512x1024.py --work-dir work_dirs/dummy_resnet --checkpoint ${CHECKPOINT_PATH} ``` - +> List the results as usually done in other model's README. \[Example\](https://github.com/open-mmlab/mmsegmentation/tree/dev-1.x/configs/fcn#results-and-models +> You should claim whether this is based on the pre-trained weights, which are converted from the official release; or it's a reproduced result obtained from retraining the model in this project | Method | Backbone | Crop Size | Lr schd | Mem (GB) | Inf time (fps) | mIoU | mIoU(ms+flip) | config | download | | ------ | -------- | --------- | ------: | -------- | -------------- | ----: | ------------: | ------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | @@ -57,7 +62,7 @@ You should claim whether this is based on the pre-trained weights, which are con ## Citation - +> You may remove this section if not applicable. ```bibtex @misc{mmseg2020, @@ -72,58 +77,58 @@ You should claim whether this is based on the pre-trained weights, which are con Here is a checklist illustrating a usual development workflow of a successful project, and also serves as an overview of this project's progress. - +> A project does not necessarily have to be finished in a single PR, but it's essential for the project to at least reach the first milestone in its very first PR. - [ ] Milestone 1: PR-ready, and acceptable to be one of the `projects/`. - [ ] Finish the code - +> The code's design shall follow existing interfaces and convention. For example, each model component should be registered into `mmseg.registry.MODELS` and configurable via a config file. - - [ ] Basic docstrings & proper citation +- [ ] Basic docstrings & proper citation - +> Each major object should contain a docstring, describing its functionality and arguments. If you have adapted the code from other open-source projects, don't forget to cite the source project in docstring and make sure your behavior is not against its license. Typically, we do not accept any code snippet under GPL license. [A Short Guide to Open Source Licenses](https://medium.com/nationwide-technology/a-short-guide-to-open-source-licenses-cf5b1c329edd) - - [ ] Test-time correctness +- [ ] Test-time correctness - +> If you are reproducing the result from a paper, make sure your model's inference-time performance matches that in the original paper. The weights usually could be obtained by simply renaming the keys in the official pre-trained weights. This test could be skipped though, if you are able to prove the training-time correctness and check the second milestone. - - [ ] A full README +- [ ] A full README - +> As this template does. - [ ] Milestone 2: Indicates a successful model implementation. - [ ] Training-time correctness - +> If you are reproducing the result from a paper, checking this item means that you should have trained your model from scratch based on the original paper's specification and verified that the final result matches the report within a minor error range. - [ ] Milestone 3: Good to be a part of our core package! - [ ] Type hints and docstrings - +> Ideally *all* the methods should have [type hints](https://www.pythontutorial.net/python-basics/python-type-hints/) and [docstrings](https://google.github.io/styleguide/pyguide.html#381-docstrings). [Example](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/mmseg/utils/io.py#L9) - - [ ] Unit tests +- [ ] Unit tests - +> Unit tests for each module are required. [Example](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/tests/test_utils/test_io.py#L14) - - [ ] Code polishing +- [ ] Code polishing - +> Refactor your code according to reviewer's comment. - - [ ] Metafile.yml +- [ ] Metafile.yml - +> It will be parsed by MIM and Inferencer. [Example](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/configs/fcn/fcn.yml) - [ ] Move your modules into the core package following the codebase's file hierarchy structure. - +> In particular, you may have to refactor this README into a standard one. [Example](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/configs/fcn/README.md) - [ ] Refactor your modules into the core package following the codebase's file hierarchy structure. diff --git a/projects/example_project/configs/fcn_dummy-r50-d8_4xb2-40k_cityscapes-512x1024.py b/projects/example_project/configs/fcn_dummy-r50-d8_4xb2-40k_cityscapes-512x1024.py index b0ec67b691..43015364eb 100644 --- a/projects/example_project/configs/fcn_dummy-r50-d8_4xb2-40k_cityscapes-512x1024.py +++ b/projects/example_project/configs/fcn_dummy-r50-d8_4xb2-40k_cityscapes-512x1024.py @@ -1,6 +1,6 @@ -_base_ = ['../../../configs/fcn/fcn_r50-d8_4xb2-40k_cityscapes-512x1024.py'] +_base_ = ['mmseg::fcn/fcn_r50-d8_4xb2-40k_cityscapes-512x1024.py'] -custom_imports = dict(imports=['projects.example_project.dummy']) +custom_imports = dict(imports=['dummy']) crop_size = (512, 1024) data_preprocessor = dict(size=crop_size) diff --git a/projects/faq.md b/projects/faq.md new file mode 100644 index 0000000000..724c1cf6a5 --- /dev/null +++ b/projects/faq.md @@ -0,0 +1,19 @@ +Q1: Why set up `projects/` folder? + +Implementing new models and features into OpenMMLab's algorithm libraries could be troublesome due to the rigorous requirements on code quality, which could hinder the fast iteration of SOTA models and might discourage our members from sharing their latest outcomes here. And that's why we have this `projects/` folder now, where some experimental features, frameworks and models are placed, only needed to satisfy the minimum requirement on the code quality, and can be used as standalone libraries. Users are welcome to use them if they [use MMSegmentation from source](https://mmsegmentation.readthedocs.io/en/dev-1.x/get_started.html#best-practices). + +Q2: Why should there be a checklist for a project? + +This checkelist is crucial not only for this project's developers but the entire community, since there might be some other contributors joining this project and deciding their starting point from this list. It also helps maintainers accurately estimate time and effort on further code polishing, if needed. + +Q3: What kind of PR will be merged? + +Reaching the first milestone means that this project suffices the minimum requirement of being merged into 'projects/'. That is, the very first PR of a project must have all the terms in the first milestone checked. We do not have any extra requirements on the project's following PRs, so they can be a minor bug fix or update, and do not have to achieve one milestone at once. But keep in mind that this project is only eligible to become a part of the core package upon attaining the last milestone. + +Q4: Compared to other models in the core packages, why do the model implementations in projects have different training/testing commands? + +Projects are organized independently from the core package, and therefore their modules cannot be directly imported by train.py and test.py. Each model implementation in projects should either use `mim` for training/testing as suggested in the example project or provide a custom train.py/test.py. + +Q5: How to debug a project with a debugger? + +Debugger makes our lives easier, but using it becomes a bit tricky if we have to train/test a model via `mim`. The way to circumvent that is that we can take advantage of relative path to import these modules. Assuming that we are developing a project X and the core modules are placed under `projects/X/modules`, then simply adding `custom_imports = dict(imports='projects.X.modules')` to the config allows us to debug from usual entrypoints (e.g. `tools/train.py`) from the root directory of the algorithm library. Just don't forget to remove 'projects.X' before project publishment. diff --git a/projects/HieraSeg/README.md b/projects/hssn/README.md similarity index 82% rename from projects/HieraSeg/README.md rename to projects/hssn/README.md index 5519ec6916..c2a74c69f9 100644 --- a/projects/HieraSeg/README.md +++ b/projects/hssn/README.md @@ -1,12 +1,10 @@ -# HieraSeg - -Support `Deep Hierarchical Semantic Segmentation` interface on `cityscapes` +# HSSN ## Description Author: AI-Tianlong -This project implements `HieraSeg` inference in the `cityscapes` dataset +This project implements `Deep Hierarchical Semantic Segmentation` inference on `cityscapes` dataset ## Usage @@ -14,17 +12,17 @@ This project implements `HieraSeg` inference in the `cityscapes` dataset - Python 3.8 - PyTorch 1.6 or higher -- [MMSegmentation](https://github.com/open-mmlab/mmsegmentation) v1.0.0rc3 -- mmcv v2.0.0rc3 -- mmengine +- [MMSegmentation](https://github.com/open-mmlab/mmsegmentation) v1.0.0rc5 +- mmcv v2.0.0rc4 +- mmengine >=0.4.0 ### Dataset preparing -preparing `cityscapes` dataset like this [structure](https://github.com/open-mmlab/mmsegmentation/blob/master/docs/en/dataset_prepare.md#prepare-datasets) +Preparing `cityscapes` dataset following this [Dataset Preparing Guide](https://github.com/open-mmlab/mmsegmentation/blob/master/docs/en/dataset_prepare.md#prepare-datasets) ### Testing commands -please put [`hieraseg_deeplabv3plus_r101-d8_4xb2-80k_cityscapes-512x1024_20230112_125023-bc59a3d1.pth`](https://download.openmmlab.com/mmsegmentation/v0.5/hieraseg/hieraseg_deeplabv3plus_r101-d8_4xb2-80k_cityscapes-512x1024_20230112_125023-bc59a3d1.pth) to `mmsegmentation/checkpoints` +Please put [`hieraseg_deeplabv3plus_r101-d8_4xb2-80k_cityscapes-512x1024_20230112_125023-bc59a3d1.pth`](https://download.openmmlab.com/mmsegmentation/v0.5/hieraseg/hieraseg_deeplabv3plus_r101-d8_4xb2-80k_cityscapes-512x1024_20230112_125023-bc59a3d1.pth) to `mmsegmentation/checkpoints` #### Multi-GPUs Test @@ -36,7 +34,7 @@ bash tools/dist_test.sh [configs] [model weights] [number of gpu] --tta #### Example ```shell -bash tools/dist_test.sh projects/HieraSeg_project/configs/hieraseg/hieraseg_deeplabv3plus_r101-d8_4xb2-80l_cityscapes-512x1024.py checkpoints/hieraseg_deeplabv3plus_r101-d8_4xb2-80k_cityscapes-512x1024_20230112_125023-bc59a3d1.pth 2 --tta +bash tools/dist_test.sh projects/hssn/configs/hssn/hieraseg_deeplabv3plus_r101-d8_4xb2-80l_cityscapes-512x1024.py checkpoints/hieraseg_deeplabv3plus_r101-d8_4xb2-80k_cityscapes-512x1024_20230112_125023-bc59a3d1.pth 2 --tta ``` ## Results diff --git a/projects/HieraSeg/configs/_base_/datasets/cityscapes.py b/projects/hssn/configs/_base_/datasets/cityscapes.py similarity index 100% rename from projects/HieraSeg/configs/_base_/datasets/cityscapes.py rename to projects/hssn/configs/_base_/datasets/cityscapes.py diff --git a/projects/HieraSeg/configs/_base_/default_runtime.py b/projects/hssn/configs/_base_/default_runtime.py similarity index 100% rename from projects/HieraSeg/configs/_base_/default_runtime.py rename to projects/hssn/configs/_base_/default_runtime.py diff --git a/projects/HieraSeg/configs/_base_/models/deeplabv3plus_r50-d8_vd_contrast.py b/projects/hssn/configs/_base_/models/deeplabv3plus_r50-d8_vd_contrast.py similarity index 100% rename from projects/HieraSeg/configs/_base_/models/deeplabv3plus_r50-d8_vd_contrast.py rename to projects/hssn/configs/_base_/models/deeplabv3plus_r50-d8_vd_contrast.py diff --git a/projects/HieraSeg/configs/_base_/schedules/schedule_80k.py b/projects/hssn/configs/_base_/schedules/schedule_80k.py similarity index 100% rename from projects/HieraSeg/configs/_base_/schedules/schedule_80k.py rename to projects/hssn/configs/_base_/schedules/schedule_80k.py diff --git a/projects/HieraSeg/configs/hieraseg/hieraseg_deeplabv3plus_r101-d8_4xb2-80l_cityscapes-512x1024.py b/projects/hssn/configs/hssn/hieraseg_deeplabv3plus_r101-d8_4xb2-80l_cityscapes-512x1024.py similarity index 82% rename from projects/HieraSeg/configs/hieraseg/hieraseg_deeplabv3plus_r101-d8_4xb2-80l_cityscapes-512x1024.py rename to projects/hssn/configs/hssn/hieraseg_deeplabv3plus_r101-d8_4xb2-80l_cityscapes-512x1024.py index 0d02bef5dc..8f04a2d656 100644 --- a/projects/HieraSeg/configs/hieraseg/hieraseg_deeplabv3plus_r101-d8_4xb2-80l_cityscapes-512x1024.py +++ b/projects/hssn/configs/hssn/hieraseg_deeplabv3plus_r101-d8_4xb2-80l_cityscapes-512x1024.py @@ -5,8 +5,8 @@ ] custom_imports = dict(imports=[ - 'projects.HieraSeg.decode_head.sep_aspp_contrast_head', - 'projects.HieraSeg.losses.hiera_triplet_loss_cityscape' + 'projects.hssn.decode_head.sep_aspp_contrast_head', + 'projects.hssn.losses.hiera_triplet_loss_cityscape' ]) model = dict( diff --git a/projects/HieraSeg/decode_head/__init__.py b/projects/hssn/decode_head/__init__.py similarity index 100% rename from projects/HieraSeg/decode_head/__init__.py rename to projects/hssn/decode_head/__init__.py diff --git a/projects/HieraSeg/decode_head/sep_aspp_contrast_head.py b/projects/hssn/decode_head/sep_aspp_contrast_head.py similarity index 76% rename from projects/HieraSeg/decode_head/sep_aspp_contrast_head.py rename to projects/hssn/decode_head/sep_aspp_contrast_head.py index 75f67e7457..d1d087362c 100644 --- a/projects/HieraSeg/decode_head/sep_aspp_contrast_head.py +++ b/projects/hssn/decode_head/sep_aspp_contrast_head.py @@ -1,5 +1,5 @@ # Copyright (c) OpenMMLab. All rights reserved. -from typing import List +from typing import List, Tuple import torch import torch.nn as nn @@ -10,6 +10,7 @@ from mmseg.models.losses import accuracy from mmseg.models.utils import resize from mmseg.registry import MODELS +from mmseg.utils import SampleList class ProjectionHead(nn.Module): @@ -61,34 +62,16 @@ def __init__(self, proj: str = 'convmlp', **kwargs): dim_in=2048, norm_cfg=self.norm_cfg, proj=proj) self.register_buffer('step', torch.zeros(1)) - def forward(self, inputs): + def forward(self, inputs) -> Tuple[Tensor]: """Forward function.""" + output = super().forward(inputs) + self.step += 1 embedding = self.proj_head(inputs[-1]) - x = self._transform_inputs(inputs) - aspp_outs = [ - resize( - self.image_pool(x), - size=x.size()[2:], - mode='bilinear', - align_corners=self.align_corners) - ] - aspp_outs.extend(self.aspp_modules(x)) - aspp_outs = torch.cat(aspp_outs, dim=1) - output = self.bottleneck(aspp_outs) - if self.c1_bottleneck is not None: - c1_output = self.c1_bottleneck(inputs[0]) - output = resize( - input=output, - size=c1_output.shape[2:], - mode='bilinear', - align_corners=self.align_corners) - output = torch.cat([output, c1_output], dim=1) - output = self.sep_bottleneck(output) - output = self.cls_seg(output) + return output, embedding - def predict_by_feat(self, seg_logits: Tensor, + def predict_by_feat(self, seg_logits: Tuple[Tensor], batch_img_metas: List[dict]) -> Tensor: """Transform a batch of output seg_logits to the input shape. @@ -100,12 +83,13 @@ def predict_by_feat(self, seg_logits: Tensor, Returns: Tensor: Outputs segmentation logits map. """ - # HieraSeg decode_head output is: (out, embedding) :tuple, + # HSSN decode_head output is: (out, embedding): tuple # only need 'out' here. if isinstance(seg_logits, tuple): seg_logit = seg_logits[0] - if seg_logit.size(1) == 26: + if seg_logit.size(1) == 26: # For cityscapes dataset,19 + 7 + hiera_num_classes = 7 seg_logit[:, 0:2] += seg_logit[:, -7] seg_logit[:, 2:5] += seg_logit[:, -6] seg_logit[:, 5:8] += seg_logit[:, -5] @@ -113,14 +97,18 @@ def predict_by_feat(self, seg_logits: Tensor, seg_logit[:, 10:11] += seg_logit[:, -3] seg_logit[:, 11:13] += seg_logit[:, -2] seg_logit[:, 13:19] += seg_logit[:, -1] - elif seg_logit.size(1) == 12: + + elif seg_logit.size(1) == 12: # For Pascal_person dataset, 7 + 5 + hiera_num_classes = 5 seg_logit[:, 0:1] = seg_logit[:, 0:1] + \ seg_logit[:, 7] + seg_logit[:, 10] seg_logit[:, 1:5] = seg_logit[:, 1:5] + \ seg_logit[:, 8] + seg_logit[:, 11] seg_logit[:, 5:7] = seg_logit[:, 5:7] + \ seg_logit[:, 9] + seg_logit[:, 11] - elif seg_logit.size(1) == 25: + + elif seg_logit.size(1) == 25: # For LIP dataset, 20 + 5 + hiera_num_classes = 5 seg_logit[:, 0:1] = seg_logit[:, 0:1] + \ seg_logit[:, 20] + seg_logit[:, 23] seg_logit[:, 1:8] = seg_logit[:, 1:8] + \ @@ -136,8 +124,10 @@ def predict_by_feat(self, seg_logits: Tensor, seg_logit[:, 16:20] = seg_logit[:, 16:20] + \ seg_logit[:, 22] + seg_logit[:, 24] - # seg_logit = seg_logit[:,:-self.test_cfg['hiera_num_classes']] - seg_logit = seg_logit[:, :-7] + # elif seg_logit.size(1) == 144 # For Mapillary dataset, 124+16+4 + # unofficial repository not release mapillary until 2023/2/6 + + seg_logit = seg_logit[:, :-hiera_num_classes] seg_logit = resize( input=seg_logit, size=batch_img_metas[0]['img_shape'], @@ -146,10 +136,27 @@ def predict_by_feat(self, seg_logits: Tensor, return seg_logit - def losses(self, results, seg_label): - """Compute segmentation loss.""" - seg_logit_before = results[0] - embedding = results[1] + def loss_by_feat( + self, + seg_logits: Tuple[Tensor], # (out, embedding) + batch_data_samples: SampleList) -> dict: + """Compute segmentation loss. Will fix in future. + + Args: + seg_logits (Tuple[Tensor]): The output from decode head + forward function. + For this decode_head output are (out, embedding): tuple + batch_data_samples (List[:obj:`SegDataSample`]): The seg + data samples. It usually includes information such + as `metainfo` and `gt_sem_seg`. + + Returns: + dict[str, Tensor]: a dictionary of loss components + """ + seg_logit_before = seg_logits[0] + embedding = seg_logits[1] + seg_label = self._stack_batch_gt(batch_data_samples) + loss = dict() seg_logit = resize( input=seg_logit_before, @@ -166,6 +173,7 @@ def losses(self, results, seg_label): scale_factor=0.5, mode='bilinear', align_corners=self.align_corners) + loss['loss_seg'] = self.loss_decode( self.step, embedding, diff --git a/projects/HieraSeg/losses/__init__.py b/projects/hssn/losses/__init__.py similarity index 100% rename from projects/HieraSeg/losses/__init__.py rename to projects/hssn/losses/__init__.py diff --git a/projects/HieraSeg/losses/hiera_triplet_loss_cityscape.py b/projects/hssn/losses/hiera_triplet_loss_cityscape.py similarity index 100% rename from projects/HieraSeg/losses/hiera_triplet_loss_cityscape.py rename to projects/hssn/losses/hiera_triplet_loss_cityscape.py diff --git a/projects/HieraSeg/losses/tree_triplet_loss.py b/projects/hssn/losses/tree_triplet_loss.py similarity index 100% rename from projects/HieraSeg/losses/tree_triplet_loss.py rename to projects/hssn/losses/tree_triplet_loss.py diff --git a/requirements/mminstall.txt b/requirements/mminstall.txt index 11a6d5a57f..df073e0c1b 100644 --- a/requirements/mminstall.txt +++ b/requirements/mminstall.txt @@ -1,4 +1,2 @@ -mmcls>=1.0.0rc0 mmcv>=2.0.0rc4 --e git+https://github.com/open-mmlab/mmdetection.git@dev-3.x#egg=mmdet -mmengine>=0.2.0,<1.0.0 +mmengine>=0.5.0,<1.0.0 diff --git a/requirements/readthedocs.txt b/requirements/readthedocs.txt index 1b5d8443b4..9627504884 100644 --- a/requirements/readthedocs.txt +++ b/requirements/readthedocs.txt @@ -1,5 +1,5 @@ mmcv>=2.0.0rc1,<2.1.0 -mmengine>=0.1.0,<1.0.0 +mmengine>=0.4.0,<1.0.0 prettytable scipy torch diff --git a/tests/data/pseudo_refuge_dataset/ann_dir/pseudo_g0001.png b/tests/data/pseudo_refuge_dataset/ann_dir/pseudo_g0001.png new file mode 100644 index 0000000000..4e69365a9c Binary files /dev/null and b/tests/data/pseudo_refuge_dataset/ann_dir/pseudo_g0001.png differ diff --git a/tests/data/pseudo_refuge_dataset/img_dir/pseudo_g0001.png b/tests/data/pseudo_refuge_dataset/img_dir/pseudo_g0001.png new file mode 100644 index 0000000000..e424c3cd21 Binary files /dev/null and b/tests/data/pseudo_refuge_dataset/img_dir/pseudo_g0001.png differ diff --git a/tests/test_apis/test_inferencer.py b/tests/test_apis/test_inferencer.py new file mode 100644 index 0000000000..497eae4a01 --- /dev/null +++ b/tests/test_apis/test_inferencer.py @@ -0,0 +1,113 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import tempfile + +import numpy as np +import torch +import torch.nn as nn +from mmengine import ConfigDict +from torch.utils.data import DataLoader, Dataset + +from mmseg.apis import MMSegInferencer +from mmseg.models import EncoderDecoder +from mmseg.models.decode_heads.decode_head import BaseDecodeHead +from mmseg.registry import MODELS +from mmseg.utils import register_all_modules + + +@MODELS.register_module(name='InferExampleHead') +class ExampleDecodeHead(BaseDecodeHead): + + def __init__(self, num_classes=19, out_channels=None): + super().__init__( + 3, 3, num_classes=num_classes, out_channels=out_channels) + + def forward(self, inputs): + return self.cls_seg(inputs[0]) + + +@MODELS.register_module(name='InferExampleBackbone') +class ExampleBackbone(nn.Module): + + def __init__(self): + super().__init__() + self.conv = nn.Conv2d(3, 3, 3) + + def init_weights(self, pretrained=None): + pass + + def forward(self, x): + return [self.conv(x)] + + +@MODELS.register_module(name='InferExampleModel') +class ExampleModel(EncoderDecoder): + + def __init__(self, **kwargs): + super().__init__(**kwargs) + + +class ExampleDataset(Dataset): + + def __init__(self) -> None: + super().__init__() + self.pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations'), + dict(type='PackSegInputs') + ] + + def __getitem__(self, idx): + return dict(img=torch.tensor([1]), img_metas=dict()) + + def __len__(self): + return 1 + + +def test_inferencer(): + register_all_modules() + test_dataset = ExampleDataset() + data_loader = DataLoader( + test_dataset, + batch_size=1, + sampler=None, + num_workers=0, + shuffle=False, + ) + + visualizer = dict( + type='SegLocalVisualizer', + vis_backends=[dict(type='LocalVisBackend')], + name='visualizer') + + cfg_dict = dict( + model=dict( + type='InferExampleModel', + data_preprocessor=dict(type='SegDataPreProcessor'), + backbone=dict(type='InferExampleBackbone'), + decode_head=dict(type='InferExampleHead'), + test_cfg=dict(mode='whole')), + visualizer=visualizer, + test_dataloader=data_loader) + cfg = ConfigDict(cfg_dict) + model = MODELS.build(cfg.model) + + ckpt = model.state_dict() + ckpt_filename = tempfile.mktemp() + torch.save(ckpt, ckpt_filename) + + # test initialization + infer = MMSegInferencer(cfg, ckpt_filename) + + # test forward + img = np.random.randint(0, 256, (4, 4, 3)) + infer(img) + + imgs = [img, img] + infer(imgs) + results = infer(imgs, out_dir=tempfile.gettempdir()) + + # test results + assert 'predictions' in results + assert 'visualization' in results + assert len(results['predictions']) == 2 + assert results['predictions'][0].shape == (4, 4) diff --git a/tests/test_config.py b/tests/test_config.py index bd664ed74f..13de460181 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -6,10 +6,10 @@ import numpy as np from mmengine import Config from mmengine.dataset import Compose +from mmengine.registry import init_default_scope from torch import nn from mmseg.models import build_segmentor -from mmseg.utils import register_all_modules def _get_config_directory(): @@ -70,7 +70,7 @@ def test_config_data_pipeline(): xdoctest -m tests/test_config.py test_config_build_data_pipeline """ - register_all_modules() + init_default_scope('mmseg') config_dpath = _get_config_directory() print(f'Found config_dpath = {config_dpath!r}') diff --git a/tests/test_datasets/test_dataset.py b/tests/test_datasets/test_dataset.py index 7c37204a6c..b97cbae3a4 100644 --- a/tests/test_datasets/test_dataset.py +++ b/tests/test_datasets/test_dataset.py @@ -8,7 +8,8 @@ from mmseg.datasets import (ADE20KDataset, BaseSegDataset, CityscapesDataset, COCOStuffDataset, DecathlonDataset, ISPRSDataset, LIPDataset, LoveDADataset, PascalVOCDataset, - PotsdamDataset, SynapseDataset, iSAIDDataset) + PotsdamDataset, REFUGEDataset, SynapseDataset, + iSAIDDataset) from mmseg.registry import DATASETS from mmseg.utils import get_classes, get_palette @@ -232,6 +233,19 @@ def test_synapse(): assert len(test_dataset) == 2 +def test_refuge(): + test_dataset = REFUGEDataset( + pipeline=[], + data_prefix=dict( + img_path=osp.join( + osp.dirname(__file__), + '../data/pseudo_refuge_dataset/img_dir'), + seg_map_path=osp.join( + osp.dirname(__file__), + '../data/pseudo_refuge_dataset/ann_dir'))) + assert len(test_dataset) == 1 + + def test_isaid(): test_dataset = iSAIDDataset( pipeline=[], diff --git a/tests/test_datasets/test_dataset_builder.py b/tests/test_datasets/test_dataset_builder.py index 099c5b1df0..b67b1e7aaf 100644 --- a/tests/test_datasets/test_dataset_builder.py +++ b/tests/test_datasets/test_dataset_builder.py @@ -2,12 +2,12 @@ import os.path as osp from mmengine.dataset import ConcatDataset, RepeatDataset +from mmengine.registry import init_default_scope from mmseg.datasets import MultiImageMixDataset from mmseg.registry import DATASETS -from mmseg.utils import register_all_modules -register_all_modules() +init_default_scope('mmseg') @DATASETS.register_module() diff --git a/tests/test_datasets/test_loading.py b/tests/test_datasets/test_loading.py index 100eb042e2..5ce624bff6 100644 --- a/tests/test_datasets/test_loading.py +++ b/tests/test_datasets/test_loading.py @@ -57,9 +57,9 @@ def test_load_seg(self): results = transform(copy.deepcopy(results)) assert results['gt_seg_map'].shape == (288, 512) assert results['gt_seg_map'].dtype == np.uint8 - # assert repr(transform) == transform.__class__.__name__ + \ - # "(reduce_zero_label=True, imdecode_backend='pillow', " + \ - # "backend_args={'backend': 'local'})" + assert repr(transform) == transform.__class__.__name__ + \ + "(reduce_zero_label=True, imdecode_backend='pillow', " + \ + 'backend_args=None)' # reduce_zero_label transform = LoadAnnotations(reduce_zero_label=True) @@ -241,7 +241,7 @@ def test_load_biomedical_img(self): "decode_backend='nifti', " 'to_xyz=False, ' 'to_float32=True, ' - "backend_args={'backend': 'local'})") + 'backend_args=None)') def test_load_biomedical_annotation(self): results = dict( @@ -265,7 +265,7 @@ def test_load_biomedical_data(self): 'with_seg=True, ' "decode_backend='numpy', " 'to_xyz=False, ' - "backend_args={'backend': 'local'})") + 'backend_args=None)') transform = LoadBiomedicalData(with_seg=False) results = transform(copy.deepcopy(input_results)) @@ -275,4 +275,4 @@ def test_load_biomedical_data(self): 'with_seg=False, ' "decode_backend='numpy', " 'to_xyz=False, ' - "backend_args={'backend': 'local'})") + 'backend_args=None)') diff --git a/tests/test_datasets/test_transform.py b/tests/test_datasets/test_transform.py index 906b3c27e8..a9136bebc8 100644 --- a/tests/test_datasets/test_transform.py +++ b/tests/test_datasets/test_transform.py @@ -5,6 +5,7 @@ import mmcv import numpy as np import pytest +from mmengine.registry import init_default_scope from PIL import Image from mmseg.datasets.transforms import * # noqa @@ -12,9 +13,8 @@ LoadBiomedicalImageFromFile, PhotoMetricDistortion, RandomCrop) from mmseg.registry import TRANSFORMS -from mmseg.utils import register_all_modules -register_all_modules() +init_default_scope('mmseg') def test_resize(): diff --git a/tests/test_engine/test_layer_decay_optimizer_constructor.py b/tests/test_engine/test_layer_decay_optimizer_constructor.py index 72dc6c5123..e7d13db1d6 100644 --- a/tests/test_engine/test_layer_decay_optimizer_constructor.py +++ b/tests/test_engine/test_layer_decay_optimizer_constructor.py @@ -5,12 +5,12 @@ import torch.nn as nn from mmcv.cnn import ConvModule from mmengine.optim.optimizer import build_optim_wrapper +from mmengine.registry import init_default_scope from mmseg.engine.optimizers.layer_decay_optimizer_constructor import \ LearningRateDecayOptimizerConstructor -from mmseg.utils import register_all_modules -register_all_modules() +init_default_scope('mmseg') base_lr = 1 decay_rate = 2 diff --git a/tests/test_models/test_backbones/test_unet.py b/tests/test_models/test_backbones/test_unet.py index d0eaccd393..4d3faf68cc 100644 --- a/tests/test_models/test_backbones/test_unet.py +++ b/tests/test_models/test_backbones/test_unet.py @@ -2,14 +2,14 @@ import pytest import torch from mmcv.cnn import ConvModule +from mmengine.registry import init_default_scope from mmseg.models.backbones.unet import (BasicConvBlock, DeconvModule, InterpConv, UNet, UpConvBlock) from mmseg.models.utils import Upsample -from mmseg.utils import register_all_modules from .utils import check_norm_state -register_all_modules() +init_default_scope('mmseg') def test_unet_basic_conv_block(): diff --git a/tests/test_models/test_forward.py b/tests/test_models/test_forward.py index ab88e4393a..7f72efae2a 100644 --- a/tests/test_models/test_forward.py +++ b/tests/test_models/test_forward.py @@ -9,14 +9,14 @@ import torch import torch.nn as nn from mmengine.model.utils import revert_sync_batchnorm +from mmengine.registry import init_default_scope from mmengine.structures import PixelData from mmengine.utils import is_list_of, is_tuple_of from torch import Tensor from mmseg.structures import SegDataSample -from mmseg.utils import register_all_modules -register_all_modules() +init_default_scope('mmseg') def _demo_mm_inputs(batch_size=2, image_shapes=(3, 32, 32), num_classes=5): diff --git a/tests/test_models/test_heads/test_maskformer_head.py b/tests/test_models/test_heads/test_maskformer_head.py index fe4bf96fea..6a47239b03 100644 --- a/tests/test_models/test_heads/test_maskformer_head.py +++ b/tests/test_models/test_heads/test_maskformer_head.py @@ -3,15 +3,15 @@ import torch from mmengine import Config +from mmengine.registry import init_default_scope from mmengine.structures import PixelData from mmseg.registry import MODELS from mmseg.structures import SegDataSample -from mmseg.utils import register_all_modules def test_maskformer_head(): - register_all_modules() + init_default_scope('mmseg') repo_dpath = dirname(dirname(__file__)) cfg = Config.fromfile( join( diff --git a/tests/test_models/test_segmentors/test_seg_tta_model.py b/tests/test_models/test_segmentors/test_seg_tta_model.py index c0e76b22f4..3c9699e8df 100644 --- a/tests/test_models/test_segmentors/test_seg_tta_model.py +++ b/tests/test_models/test_segmentors/test_seg_tta_model.py @@ -2,14 +2,14 @@ import torch from mmengine import ConfigDict from mmengine.model import BaseTTAModel +from mmengine.registry import init_default_scope from mmengine.structures import PixelData from mmseg.registry import MODELS from mmseg.structures import SegDataSample -from mmseg.utils import register_all_modules from .utils import * # noqa: F401,F403 -register_all_modules() +init_default_scope('mmseg') def test_encoder_decoder_tta(): diff --git a/tools/analysis_tools/benchmark.py b/tools/analysis_tools/benchmark.py index bcb3948a6e..afaeabac85 100644 --- a/tools/analysis_tools/benchmark.py +++ b/tools/analysis_tools/benchmark.py @@ -8,11 +8,11 @@ from mmengine import Config from mmengine.fileio import dump from mmengine.model.utils import revert_sync_batchnorm +from mmengine.registry import init_default_scope from mmengine.runner import Runner, load_checkpoint from mmengine.utils import mkdir_or_exist from mmseg.registry import MODELS -from mmseg.utils import register_all_modules def parse_args(): @@ -32,8 +32,10 @@ def parse_args(): def main(): args = parse_args() - register_all_modules() cfg = Config.fromfile(args.config) + + init_default_scope(cfg.get('default_scope', 'mmseg')) + timestamp = time.strftime('%Y%m%d_%H%M%S', time.localtime()) if args.work_dir is not None: mkdir_or_exist(osp.abspath(args.work_dir)) diff --git a/tools/analysis_tools/browse_dataset.py b/tools/analysis_tools/browse_dataset.py new file mode 100644 index 0000000000..925c14a8ab --- /dev/null +++ b/tools/analysis_tools/browse_dataset.py @@ -0,0 +1,77 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import argparse +import os.path as osp + +from mmengine.config import Config, DictAction +from mmengine.utils import ProgressBar + +from mmseg.registry import DATASETS, VISUALIZERS +from mmseg.utils import register_all_modules + + +def parse_args(): + parser = argparse.ArgumentParser(description='Browse a dataset') + parser.add_argument('config', help='train config file path') + parser.add_argument( + '--output-dir', + default=None, + type=str, + help='If there is no display interface, you can save it') + parser.add_argument('--not-show', default=False, action='store_true') + parser.add_argument( + '--show-interval', + type=float, + default=2, + help='the interval of show (s)') + parser.add_argument( + '--cfg-options', + nargs='+', + action=DictAction, + help='override some settings in the used config, the key-value pair ' + 'in xxx=yyy format will be merged into config file. If the value to ' + 'be overwritten is a list, it should be like key="[a,b]" or key=a,b ' + 'It also allows nested list/tuple values, e.g. key="[(a,b),(c,d)]" ' + 'Note that the quotation marks are necessary and that no white space ' + 'is allowed.') + args = parser.parse_args() + return args + + +def main(): + args = parse_args() + cfg = Config.fromfile(args.config) + if args.cfg_options is not None: + cfg.merge_from_dict(args.cfg_options) + + # register all modules in mmdet into the registries + register_all_modules() + + dataset = DATASETS.build(cfg.train_dataloader.dataset) + visualizer = VISUALIZERS.build(cfg.visualizer) + visualizer.dataset_meta = dataset.metainfo + + progress_bar = ProgressBar(len(dataset)) + for item in dataset: + img = item['inputs'].permute(1, 2, 0).numpy() + img = img[..., [2, 1, 0]] # bgr to rgb + data_sample = item['data_samples'].numpy() + img_path = osp.basename(item['data_samples'].img_path) + + out_file = osp.join( + args.output_dir, + osp.basename(img_path)) if args.output_dir is not None else None + + visualizer.add_datasample( + name=osp.basename(img_path), + image=img, + data_sample=data_sample, + draw_gt=True, + draw_pred=False, + wait_time=args.show_interval, + out_file=out_file, + show=not args.not_show) + progress_bar.update() + + +if __name__ == '__main__': + main() diff --git a/tools/dataset_converters/refuge.py b/tools/dataset_converters/refuge.py new file mode 100644 index 0000000000..1186866ab3 --- /dev/null +++ b/tools/dataset_converters/refuge.py @@ -0,0 +1,110 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import argparse +import os +import os.path as osp +import tempfile +import zipfile + +import mmcv +import numpy as np +from mmengine.utils import mkdir_or_exist + + +def parse_args(): + parser = argparse.ArgumentParser( + description='Convert REFUGE dataset to mmsegmentation format') + parser.add_argument('--raw_data_root', help='the root path of raw data') + + parser.add_argument('--tmp_dir', help='path of the temporary directory') + parser.add_argument('-o', '--out_dir', help='output path') + args = parser.parse_args() + return args + + +def extract_img(root: str, + cur_dir: str, + out_dir: str, + mode: str = 'train', + file_type: str = 'img') -> None: + """_summary_ + + Args: + Args: + root (str): root where the extracted data is saved + cur_dir (cur_dir): dir where the zip_file exists + out_dir (str): root dir where the data is saved + + mode (str, optional): Defaults to 'train'. + file_type (str, optional): Defaults to 'img',else to 'mask'. + """ + zip_file = zipfile.ZipFile(cur_dir) + zip_file.extractall(root) + for cur_dir, dirs, files in os.walk(root): + # filter child dirs and directories with "Illustration" and "MACOSX" + if len(dirs) == 0 and \ + cur_dir.split('\\')[-1].find('Illustration') == -1 and \ + cur_dir.find('MACOSX') == -1: + + file_names = [ + file for file in files + if file.endswith('.jpg') or file.endswith('.bmp') + ] + for filename in sorted(file_names): + img = mmcv.imread(osp.join(cur_dir, filename)) + + if file_type == 'annotations': + img = img[:, :, 0] + img[np.where(img == 0)] = 1 + img[np.where(img == 128)] = 2 + img[np.where(img == 255)] = 0 + mmcv.imwrite( + img, + osp.join(out_dir, file_type, mode, + osp.splitext(filename)[0] + '.png')) + + +def main(): + args = parse_args() + + raw_data_root = args.raw_data_root + if args.out_dir is None: + out_dir = osp.join('./data', 'REFUGE') + + else: + out_dir = args.out_dir + + print('Making directories...') + mkdir_or_exist(out_dir) + mkdir_or_exist(osp.join(out_dir, 'images')) + mkdir_or_exist(osp.join(out_dir, 'images', 'training')) + mkdir_or_exist(osp.join(out_dir, 'images', 'validation')) + mkdir_or_exist(osp.join(out_dir, 'images', 'test')) + mkdir_or_exist(osp.join(out_dir, 'annotations')) + mkdir_or_exist(osp.join(out_dir, 'annotations', 'training')) + mkdir_or_exist(osp.join(out_dir, 'annotations', 'validation')) + mkdir_or_exist(osp.join(out_dir, 'annotations', 'test')) + + print('Generating images and annotations...') + # process data from the child dir on the first rank + cur_dir, dirs, files = list(os.walk(raw_data_root))[0] + print('====================') + + files = list(filter(lambda x: x.endswith('.zip'), files)) + + with tempfile.TemporaryDirectory(dir=args.tmp_dir) as tmp_dir: + for file in files: + # search data folders for training,validation,test + mode = list( + filter(lambda x: file.lower().find(x) != -1, + ['training', 'test', 'validation']))[0] + file_root = osp.join(tmp_dir, file[:-4]) + file_type = 'images' if file.find('Anno') == -1 and file.find( + 'GT') == -1 else 'annotations' + extract_img(file_root, osp.join(cur_dir, file), out_dir, mode, + file_type) + + print('Done!') + + +if __name__ == '__main__': + main() diff --git a/tools/misc/browse_dataset.py b/tools/misc/browse_dataset.py index b2852c21ab..7863eb74f2 100644 --- a/tools/misc/browse_dataset.py +++ b/tools/misc/browse_dataset.py @@ -3,10 +3,10 @@ import os.path as osp from mmengine import Config, DictAction +from mmengine.registry import init_default_scope from mmengine.utils import ProgressBar from mmseg.registry import DATASETS, VISUALIZERS -from mmseg.utils import register_all_modules def parse_args(): @@ -44,7 +44,7 @@ def main(): cfg.merge_from_dict(args.cfg_options) # register all modules in mmseg into the registries - register_all_modules() + init_default_scope('mmseg') dataset = DATASETS.build(cfg.train_dataloader.dataset) cfg.visualizer['save_dir'] = args.output_dir diff --git a/tools/test.py b/tools/test.py index b21b990f26..7bfde58206 100644 --- a/tools/test.py +++ b/tools/test.py @@ -6,8 +6,6 @@ from mmengine.config import Config, DictAction from mmengine.runner import Runner -from mmseg.utils import register_all_modules - # TODO: support fuse_conv_bn, visualization, and format_only def parse_args(): @@ -77,10 +75,6 @@ def trigger_visualization_hook(cfg, args): def main(): args = parse_args() - # register all modules in mmseg into the registries - # do not init the default scope here because it will be init in the runner - register_all_modules(init_default_scope=False) - # load config cfg = Config.fromfile(args.config) cfg.launcher = args.launcher diff --git a/tools/train.py b/tools/train.py index 172815a9fe..1721306664 100644 --- a/tools/train.py +++ b/tools/train.py @@ -6,10 +6,9 @@ from mmengine.config import Config, DictAction from mmengine.logging import print_log -from mmengine.registry import RUNNERS from mmengine.runner import Runner -from mmseg.utils import register_all_modules +from mmseg.registry import RUNNERS def parse_args(): @@ -52,10 +51,6 @@ def parse_args(): def main(): args = parse_args() - # register all modules in mmseg into the registries - # do not init the default scope here because it will be init in the runner - register_all_modules(init_default_scope=False) - # load config cfg = Config.fromfile(args.config) cfg.launcher = args.launcher