[Doc] Add Chinese Documentation (#666)

* Add chinese doc base (#593)

* [Doc] Add Chinese doc for useful_tools_md (#642)

* get_started_docs_zh

* inference_zh.md

* train_zh.md

* get_started_zh.md

* train_zh.md

* get_started_zh

* fix nospace between ZH and ENG

* change README_zh-CN link

* checkout space again

* checkout space again

* checkout space again

* pipeline

* cus_model

* cus_model

* cus_model

* runtime_md

* dataset_prepare

* useful_tools

* refine

* Update useful_tools.md

* Update useful_tools.md

Co-authored-by: Junjun2016 <hejunjun@sjtu.edu.cn>

* [Doc] Add Chinese doc for get_started (#615)

* get_started_docs_zh

* inference_zh.md

* train_zh.md

* get_started_zh.md

* train_zh.md

* get_started_zh

* fix nospace between ZH and ENG

* change README_zh-CN link

* checkout space again

* checkout space again

* checkout space again

* get_started_md

* refine_get_started_md

* [Doc] Add Chinese doc for tutorial03_tutorial_datapipeline_md (#629)

* get_started_docs_zh

* inference_zh.md

* train_zh.md

* get_started_zh.md

* train_zh.md

* get_started_zh

* fix nospace between ZH and ENG

* change README_zh-CN link

* checkout space again

* checkout space again

* checkout space again

* pipeline

* refine

* Update data_pipeline.md

Co-authored-by: Junjun2016 <hejunjun@sjtu.edu.cn>

* [Doc] Add Chinese doc for tutorials04_customized_models_md (#630)

* get_started_docs_zh

* inference_zh.md

* train_zh.md

* get_started_zh.md

* train_zh.md

* get_started_zh

* fix nospace between ZH and ENG

* change README_zh-CN link

* checkout space again

* checkout space again

* checkout space again

* pipeline

* cus_model

* cus_model

* cus_model

* refine

* refine

* Update customize_models.md

Co-authored-by: Junjun2016 <hejunjun@sjtu.edu.cn>

* [Doc] Add Chinese doc for dataset_prepare_md (#640)

* get_started_docs_zh

* inference_zh.md

* train_zh.md

* get_started_zh.md

* train_zh.md

* get_started_zh

* fix nospace between ZH and ENG

* change README_zh-CN link

* checkout space again

* checkout space again

* checkout space again

* pipeline

* cus_model

* cus_model

* cus_model

* runtime_md

* dataset_prepare

* Update dataset_prepare.md

Co-authored-by: Junjun2016 <hejunjun@sjtu.edu.cn>

* [Doc] Add Chinese doc for tutorials05_training_tricks_md (#631)

* get_started_docs_zh

* inference_zh.md

* train_zh.md

* get_started_zh.md

* train_zh.md

* get_started_zh

* fix nospace between ZH and ENG

* change README_zh-CN link

* checkout space again

* checkout space again

* checkout space again

* pipeline

* cus_model

* cus_model

* cus_model

* traning tricks md

* traning tricks md

* refine

* refine

* refine

* Update training_tricks.md

Co-authored-by: Junjun2016 <hejunjun@sjtu.edu.cn>

* [Doc] Add Chinese doc for tutorials06_customized_runtime_md (#637)

* get_started_docs_zh

* inference_zh.md

* train_zh.md

* get_started_zh.md

* train_zh.md

* get_started_zh

* fix nospace between ZH and ENG

* change README_zh-CN link

* checkout space again

* checkout space again

* checkout space again

* pipeline

* cus_model

* cus_model

* cus_model

* runtime_md

* Update customize_runtime.md

Co-authored-by: Junjun2016 <hejunjun@sjtu.edu.cn>

* [Doc] Add Chinese doc for tutorials01_config_md (#628)

* get_started_docs_zh

* inference_zh.md

* train_zh.md

* get_started_zh.md

* train_zh.md

* get_started_zh

* fix nospace between ZH and ENG

* change README_zh-CN link

* checkout space again

* checkout space again

* checkout space again

* new_config_md

* new_config_md1

* new_config_md1

* refine

* refine

* Update config.md

Co-authored-by: Junjun2016 <hejunjun@sjtu.edu.cn>

* [Doc] Add Chinese for modelzoo (#597)

* [Doc] Add Chinese for modelzoo

* add missing

* [Doc] Add Chinese doc for tutorial02_customized_dataset_md (#620)

* get_started_docs_zh

* inference_zh.md

* train_zh.md

* get_started_zh.md

* train_zh.md

* get_started_zh

* fix nospace between ZH and ENG

* change README_zh-CN link

* checkout space again

* checkout space again

* checkout space again

* tutorial_customized_dataset

* refine

* Update customize_datasets.md

* fixconflict

Co-authored-by: Junjun2016 <hejunjun@sjtu.edu.cn>

* [Doc] Add Chinese doc for train.md (#616)

* get_started_docs_zh

* inference_zh.md

* train_zh.md

* get_started_zh.md

* train_zh.md

* get_started_zh

* fix nospace between ZH and ENG

* change README_zh-CN link

* checkout space again

* checkout space again

* checkout space again

* train_md

* refine

* refine_last

* refine_last

* refine_last

* refine_last

* refine_last

* temp

* refine_last

* qwe

Co-authored-by: yuanzhang <yuanzhang@yuanzhangdeMacBook-Pro.local>

* [Doc] Add Chinese doc for inference.md (#617)

* get_started_docs_zh

* inference_zh.md

* train_zh.md

* get_started_zh.md

* train_zh.md

* get_started_zh

* fix nospace between ZH and ENG

* change README_zh-CN link

* checkout space again

* checkout space again

* checkout space again

* inference_zh_md

* Update docs_zh-CN/inference.md

Directly delete this sentence?

Co-authored-by: Junjun2016 <hejunjun@sjtu.edu.cn>

* qwe

* temp

* qw

* Update docs_zh-CN/inference.md

* Update docs_zh-CN/inference.md

* Update docs_zh-CN/inference.md

* Update docs_zh-CN/inference.md

* Update docs_zh-CN/inference.md

* Update inference.md

Co-authored-by: Junjun2016 <hejunjun@sjtu.edu.cn>

* fixed some dir

* fixed typo

Co-authored-by: MengzhangLI <mcmong@pku.edu.cn>
Co-authored-by: Junjun2016 <hejunjun@sjtu.edu.cn>
Co-authored-by: yuanzhang <yuanzhang@yuanzhangdeMacBook-Pro.local>
This commit is contained in:
Jerry Jiarui XU 2021-07-03 08:54:32 -07:00 committed by GitHub
parent 9e2a9cbd52
commit 0529952270
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 2578 additions and 9 deletions

View File

@ -4,14 +4,14 @@
<br />
[![PyPI](https://img.shields.io/pypi/v/mmsegmentation)](https://pypi.org/project/mmsegmentation)
[![docs](https://img.shields.io/badge/docs-latest-blue)](https://mmsegmentation.readthedocs.io/en/latest/)
[![docs](https://img.shields.io/badge/docs-latest-blue)](https://mmsegmentation.readthedocs.io/zh_CN/latest/)
[![badge](https://github.com/open-mmlab/mmsegmentation/workflows/build/badge.svg)](https://github.com/open-mmlab/mmsegmentation/actions)
[![codecov](https://codecov.io/gh/open-mmlab/mmsegmentation/branch/master/graph/badge.svg)](https://codecov.io/gh/open-mmlab/mmsegmentation)
[![license](https://img.shields.io/github/license/open-mmlab/mmsegmentation.svg)](https://github.com/open-mmlab/mmsegmentation/blob/master/LICENSE)
[![issue resolution](https://isitmaintained.com/badge/resolution/open-mmlab/mmsegmentation.svg)](https://github.com/open-mmlab/mmsegmentation/issues)
[![open issues](https://isitmaintained.com/badge/open/open-mmlab/mmsegmentation.svg)](https://github.com/open-mmlab/mmsegmentation/issues)
文档: https://mmsegmentation.readthedocs.io/
文档: https://mmsegmentation.readthedocs.io/zh_CN/latest
[English](README.md) | 简体中文
@ -52,7 +52,7 @@ MMSegmentation 是一个基于 PyTorch 的语义分割开源工具箱。它是 O
## 基准测试和模型库
测试结果和模型可以在[模型库](docs/model_zoo.md)中找到。
测试结果和模型可以在[模型库](docs_zh-CN/model_zoo.md)中找到。
已支持的骨干网络:
@ -94,13 +94,13 @@ MMSegmentation 是一个基于 PyTorch 的语义分割开源工具箱。它是 O
## 安装
请参考[快速入门文档](docs/get_started.md#installation)进行安装和数据集准备。
请参考[快速入门文档](docs_zh-CN/get_started.md#installation)进行安装和数据集准备。
## 快速入门
请参考[训练教程](docs/train.md)和[测试教程](docs/inference.md)学习 MMSegmentation 的基本使用。
我们也提供了一些进阶教程,内容覆盖了[增加自定义数据集](docs/tutorials/customize_datasets.md)[设计新的数据预处理流程](docs/tutorials/data_pipeline.md)[增加自定义模型](docs/tutorials/customize_models.md)[增加自定义的运行时配置](docs/tutorials/customize_runtime.md)。
除此之外,我们也提供了很多实用的[训练技巧说明](docs/tutorials/training_tricks.md)。
请参考[训练教程](docs_zh-CN/train.md)和[测试教程](docs_zh-CN/inference.md)学习 MMSegmentation 的基本使用。
我们也提供了一些进阶教程,内容覆盖了[增加自定义数据集](docs_zh-CN/tutorials/customize_datasets.md)[设计新的数据预处理流程](docs_zh-CN/tutorials/data_pipeline.md)[增加自定义模型](docs_zh-CN/tutorials/customize_models.md)[增加自定义的运行时配置](docs_zh-CN/tutorials/customize_runtime.md)。
除此之外,我们也提供了很多实用的[训练技巧说明](docs_zh-CN/tutorials/training_tricks.md)。
同时,我们提供了 Colab 教程。你可以在[这里](demo/MMSegmentation_Tutorial.ipynb)浏览教程,或者直接在 Colab 上[运行](https://colab.research.google.com/github/open-mmlab/mmsegmentation/blob/master/demo/MMSegmentation_Tutorial.ipynb)。
@ -144,7 +144,7 @@ MMSegmentation 是一个由来自不同高校和企业的研发人员共同参
扫描下方的二维码可关注 OpenMMLab 团队的 [知乎官方账号](https://www.zhihu.com/people/openmmlab),加入 OpenMMLab 团队的 [官方交流 QQ 群](https://jq.qq.com/?_wv=1027&k=aCvMxdr3)
<div align="center">
<img src="docs/imgs/zhihu_qrcode.jpg" height="400" /> <img src="docs/imgs/qq_group_qrcode.jpg" height="400" />
<img src="docs_zh-CN/imgs/zhihu_qrcode.jpg" height="400" /> <img src="docs_zh-CN/imgs/qq_group_qrcode.jpg" height="400" />
</div>
我们会在 OpenMMLab 社区为大家

View File

@ -19,7 +19,7 @@ sys.path.insert(0, os.path.abspath('..'))
# -- Project information -----------------------------------------------------
project = 'MMSegmentation'
copyright = '2020-2020, OpenMMLab'
copyright = '2020-2021, OpenMMLab'
author = 'MMSegmentation Authors'
version_file = '../mmseg/version.py'
@ -79,6 +79,8 @@ html_theme = 'sphinx_rtd_theme'
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
language = 'zh_CN'
def builder_inited_handler(app):
subprocess.run(['./stat.py'])

View File

@ -45,6 +45,11 @@ Welcome to MMSegmenation's documentation!
changelog.md
.. toctree::
:caption: Switch Language
switch_language.md
.. toctree::
:caption: API Reference

3
docs/switch_language.md Normal file
View File

@ -0,0 +1,3 @@
## <a href='https://mmsegmentation.readthedocs.io/en/latest/'>English</a>
## <a href='https://mmsegmentation.readthedocs.io/zh_CN/latest/'>简体中文</a>

20
docs_zh-CN/Makefile Normal file
View File

@ -0,0 +1,20 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

61
docs_zh-CN/api.rst Normal file
View File

@ -0,0 +1,61 @@
API Reference
==============
mmseg.apis
--------------
.. automodule:: mmseg.apis
:members:
mmseg.core
--------------
seg
^^^^^^^^^^
.. automodule:: mmseg.core.seg
:members:
evaluation
^^^^^^^^^^
.. automodule:: mmseg.core.evaluation
:members:
utils
^^^^^^^^^^
.. automodule:: mmseg.core.utils
:members:
mmseg.datasets
--------------
datasets
^^^^^^^^^^
.. automodule:: mmseg.datasets
:members:
pipelines
^^^^^^^^^^
.. automodule:: mmseg.datasets.pipelines
:members:
mmseg.models
--------------
segmentors
^^^^^^^^^^
.. automodule:: mmseg.models.segmentors
:members:
backbones
^^^^^^^^^^
.. automodule:: mmseg.models.backbones
:members:
decode_heads
^^^^^^^^^^^^
.. automodule:: mmseg.models.decode_heads
:members:
losses
^^^^^^^^^^
.. automodule:: mmseg.models.losses
:members:

90
docs_zh-CN/conf.py Normal file
View File

@ -0,0 +1,90 @@
# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import os
import subprocess
import sys
sys.path.insert(0, os.path.abspath('..'))
# -- Project information -----------------------------------------------------
project = 'MMSegmentation'
copyright = '2020-2021, OpenMMLab'
author = 'MMSegmentation Authors'
version_file = '../mmseg/version.py'
def get_version():
with open(version_file, 'r') as f:
exec(compile(f.read(), version_file, 'exec'))
return locals()['__version__']
# The full version, including alpha/beta/rc tags
release = get_version()
# -- General configuration ---------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.napoleon',
'sphinx.ext.viewcode',
'recommonmark',
'sphinx_markdown_tables',
]
autodoc_mock_imports = ['matplotlib', 'pycocotools', 'mmseg.version']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
source_suffix = {
'.rst': 'restructuredtext',
'.md': 'markdown',
}
# The master toctree document.
master_doc = 'index'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
language = 'zh_CN'
def builder_inited_handler(app):
subprocess.run(['./stat.py'])
def setup(app):
app.connect('builder-inited', builder_inited_handler)

View File

@ -0,0 +1,169 @@
## 准备数据集
推荐用软链接,将数据集根目录链接到 `$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
```
### 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/tutorials/new_dataset.md#concatenate-dataset) 。
### 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
```
这个脚本将自动生成正确的文件夹结构。

210
docs_zh-CN/get_started.md Normal file
View File

@ -0,0 +1,210 @@
## 依赖
- Linux or macOS (Windows下支持需要 mmcv-full但运行时可能会有一些问题。)
- Python 3.6+
- PyTorch 1.3+
- CUDA 9.2+ (如果您基于源文件编译 PyTorch, CUDA 9.0也可以使用)
- GCC 5+
- [MMCV](https://mmcv.readthedocs.io/en/latest/#installation)
可编译的 MMSegmentation 和 MMCV 版本如下所示,请对照对应版本安装以避免安装问题。
| MMSegmentation 版本 | MMCV 版本 |
|:-------------------:|:-------------------:|
| master | mmcv-full>=1.3.7, <1.4.0 |
| 0.14.1 | mmcv-full>=1.3.7, <1.4.0 |
| 0.14.0 | mmcv-full>=1.3.1, <1.4.0 |
| 0.13.0 | mmcv-full>=1.3.1, <1.4.0 |
| 0.12.0 | mmcv-full>=1.1.4, <1.4.0 |
| 0.11.0 | mmcv-full>=1.1.4, <1.3.0 |
| 0.10.0 | mmcv-full>=1.1.4, <1.3.0 |
| 0.9.0 | mmcv-full>=1.1.4, <1.3.0 |
| 0.8.0 | mmcv-full>=1.1.4, <1.2.0 |
| 0.7.0 | mmcv-full>=1.1.2, <1.2.0 |
| 0.6.0 | mmcv-full>=1.1.2, <1.2.0 |
注意: 如果您已经安装好 mmcv, 您首先需要运行 `pip uninstall mmcv`。如果 mmcv 和 mmcv-full 同时被安装,会报错 `ModuleNotFoundError`
## 安装
a. 创建一个 conda 虚拟环境并激活它。
```shell
conda create -n open-mmlab python=3.7 -y
conda activate open-mmlab
```
b. 按照[官方教程](https://pytorch.org/) 安装 PyTorch 和 totchvision。
这里我们使用 PyTorch1.6.0 和 CUDA10.1。
您也可以切换至其他版本。
```shell
conda install pytorch=1.6.0 torchvision cudatoolkit=10.1 -c pytorch
```
c. 按照 [官方教程](https://mmcv.readthedocs.io/en/latest/#installation) 安装 [MMCV](https://mmcv.readthedocs.io/en/latest/) 。
`mmcv``mmcv-full` 和 MMSegmentation 均兼容,但对于 CCNet 和 PSANet`mmcv-full` 里的 CUDA 运算是必须的。
**在 Linux 下安装 mmcv:**
通过运行
```shell
pip install mmcv-full -f https://download.openmmlab.com/mmcv/dist/cu101/torch1.5.0/index.html
```
可以安装好 mmcv-full (PyTorch 1.5 和 CUDA 10.1) 版本。
其他 PyTorch 和 CUDA 版本的 MMCV 安装请参照[这里](https://mmcv.readthedocs.io/en/latest/#install-with-pip)
**在 Windows 下安装 mmcv (有风险):**
对于 Windows, MMCV 的安装需要本地 C++ 编译工具, 例如 cl.exe. 请添加编译工具至 %PATH%.
如果您已经在电脑上安装好Windows SDK 和 Visual Studiocl.exe 的一个典型路径看起来如下:
```shell
C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.26.28801\bin\Hostx86\x64
```
或者您需要从网上下载 cl 编译工具并安装至路径。
随后,从 github 克隆 mmcv 并通过 pip 安装:
```shell
git clone https://github.com/open-mmlab/mmcv.git
cd mmcv
pip install -e .
```
或直接:
```shell
pip install mmcv
```
当前mmcv-full 并不完全在 windows 上支持。
d. 安装 MMSegmentation.
```shell
pip install mmsegmentation # 安装最新版本
```
或者
```shell
pip install git+https://github.com/open-mmlab/mmsegmentation.git # 安装 master 分支
```
此外,如果您想安装 `dev` 模式的 MMSegmentation, 运行如下命令:
```shell
git clone https://github.com/open-mmlab/mmsegmentation.git
cd mmsegmentation
pip install -e . # 或者 "python setup.py develop"
```
注意:
1. 当在 windows 下训练和测试模型时,请确保路径下所有的'\\' 被替换成 '/'。在 python 代码里可以使用`.replace('\\', '/')`处理路径的字符串。
2. `version+git_hash` 也将被保存进 meta 训练模型里即0.5.0+c415a2e。
3. 当 MMsegmentation 以 `dev` 模式被安装时,本地对代码的修改将不需要重新安装即可产生作用。
4. 如果您想使用 `opencv-python-headless` 替换 `opencv-python`,您可以在安装 MMCV 前安装它。
5. 一些依赖项是可选的。简单的运行 `pip install -e .` 将仅安装最必要的一些依赖。为了使用可选的依赖项如`cityscapessripts`,要么手动使用 `pip install -r requirements/optional.txt` 安装要么专门从pip下安装(即 `pip install -e .[optional]` 其中选项可设置为 `all`, `tests`, `build`, 和 `optional`).
### 完成的安装脚本
#### Linux
这里便是一个完整安装 MMSegmentation 的脚本,使用 conda 并链接了数据集的路径(以您的数据集路径为 $DATA_ROOT 来安装)。
```shell
conda create -n open-mmlab python=3.7 -y
conda activate open-mmlab
conda install pytorch=1.6.0 torchvision cudatoolkit=10.1 -c pytorch
pip install mmcv-full==latest+torch1.5.0+cu101 -f https://download.openmmlab.com/mmcv/dist/index.html
git clone https://github.com/open-mmlab/mmsegmentation.git
cd mmsegmentation
pip install -e . # 或者 "python setup.py develop"
mkdir data
ln -s $DATA_ROOT data
```
#### Windows(有风险)
这里便是一个完整安装 MMSegmentation 的脚本,使用 conda 并链接了数据集的路径(以您的数据集路径为 %DATA_ROOT% 来安装)。注意:它必须是一个绝对路径。
```shell
conda create -n open-mmlab python=3.7 -y
conda activate open-mmlab
conda install pytorch=1.6.0 torchvision cudatoolkit=10.1 -c pytorch
set PATH=full\path\to\your\cpp\compiler;%PATH%
pip install mmcv
git clone https://github.com/open-mmlab/mmsegmentation.git
cd mmsegmentation
pip install -e . # 或者 "python setup.py develop"
mklink /D data %DATA_ROOT%
```
#### 使用多版本 MMSegmentation 进行开发
训练和测试脚本已经修改了 `PYTHONPATH` 来确保使用当前路径的MMSegmentation。
为了使用当前环境默认安装的 MMSegmentation 而不是正在工作的 MMSegmentation您可以在那些脚本里移除下面的内容
```shell
PYTHONPATH="$(dirname $0)/..":$PYTHONPATH
```
## 验证
为了验证 MMSegmentation 和它所需要的环境是否正确安装,我们可以使用样例 python 代码来初始化一个 segmentor 并推理一张 demo 图像。
```python
from mmseg.apis import inference_segmentor, init_segmentor
import mmcv
config_file = 'configs/pspnet/pspnet_r50-d8_512x1024_40k_cityscapes.py'
checkpoint_file = 'checkpoints/pspnet_r50-d8_512x1024_40k_cityscapes_20200605_003338-2966598c.pth'
# 从一个 config 配置文件和 checkpoint 文件里创建分割模型
model = init_segmentor(config_file, checkpoint_file, device='cuda:0')
# 测试一张样例图片并得到结果
img = 'test.jpg' # 或者 img = mmcv.imread(img), 这将只加载图像一次.
result = inference_segmentor(model, img)
# 在新的窗口里可视化结果
model.show_result(img, result, show=True)
# 或者保存图片文件的可视化结果
# 您可以改变 segmentation map 的不透明度(opacity),在(0, 1]之间。
model.show_result(img, result, out_file='result.jpg', opacity=0.5)
# 测试一个视频并得到分割结果
video = mmcv.VideoReader('video.mp4')
for frame in video:
result = inference_segmentor(model, frame)
model.show_result(frame, result, wait_time=1)
```
当您完成 MMSegmentation 的安装时,上述代码应该可以成功运行。
我们还提供一个 demo 脚本去可视化单张图片
```shell
python demo/image_demo.py ${IMAGE_FILE} ${CONFIG_FILE} ${CHECKPOINT_FILE} [--device ${DEVICE_NAME}] [--palette-thr ${PALETTE}]
```
样例:
```shell
python demo/image_demo.py demo/demo.jpg configs/pspnet/pspnet_r50-d8_512x1024_40k_cityscapes.py \
checkpoints/pspnet_r50-d8_512x1024_40k_cityscapes_20200605_003338-2966598c.pth --device cuda:0 --palette cityscapes
```
推理的 demo 文档可在此查询:[demo/inference_demo.ipynb](../demo/inference_demo.ipynb).

View File

Before

Width:  |  Height:  |  Size: 200 KiB

After

Width:  |  Height:  |  Size: 200 KiB

View File

Before

Width:  |  Height:  |  Size: 388 KiB

After

Width:  |  Height:  |  Size: 388 KiB

62
docs_zh-CN/index.rst Normal file
View File

@ -0,0 +1,62 @@
欢迎来到 MMSegmenation 的文档!
=======================================
.. toctree::
:maxdepth: 2
:caption: 开始你的第一步
get_started.md
.. toctree::
:maxdepth: 1
:caption: 数据集准备
dataset_prepare.md
.. toctree::
:maxdepth: 1
:caption: 模型库
model_zoo.md
modelzoo_statistics.md
.. toctree::
:maxdepth: 2
:caption: 快速启动
train.md
inference.md
.. toctree::
:maxdepth: 2
:caption: 教程
tutorials/index.rst
.. toctree::
:maxdepth: 2
:caption: 实用工具与脚本
useful_tools.md
.. toctree::
:maxdepth: 2
:caption: 说明
changelog.md
.. toctree::
:caption: 语言切换
switch_language.md
.. toctree::
:caption: 接口文档(英文)
api.rst
Indices and tables
==================
* :ref:`genindex`
* :ref:`search`

99
docs_zh-CN/inference.md Normal file
View File

@ -0,0 +1,99 @@
## 使用预训练模型推理
我们提供测试脚本来评估完整数据集Cityscapes, PASCAL VOC, ADE20k 等) 上的结果,同时为了使其他项目的整合更容易,也提供一些高级 API。
### 测试一个数据集
- 单卡 GPU
- 单节点多卡 GPU
- 多节点
您可以使用以下命令来测试一个数据集。
```shell
# 单卡 GPU 测试
python tools/test.py ${配置文件} ${检查点文件} [--out ${结果文件}] [--eval ${评估指标}] [--show]
# 多卡GPU 测试
./tools/dist_test.sh ${配置文件} ${检查点文件} ${GPU数目} [--out ${结果文件}] [--eval ${评估指标}]
```
可选参数:
- `RESULT_FILE`: pickle 格式的输出结果的文件名,如果不专门指定,结果将不会被专门保存成文件。
- `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
例子:
假设您已经下载检查点文件至文件夹 `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 内存。

35
docs_zh-CN/make.bat Normal file
View File

@ -0,0 +1,35 @@
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=.
set BUILDDIR=_build
if "%1" == "" goto help
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
:end
popd

152
docs_zh-CN/model_zoo.md Normal file
View File

@ -0,0 +1,152 @@
# 标准与模型库
## 共同设定
* 我们默认使用 4 卡分布式训练
* 所有 PyTorch 风格的 ImageNet 预训练网络由我们自己训练,和 [论文](https://arxiv.org/pdf/1812.01187.pdf) 保持一致。
我们的 ResNet 网络是基于 ResNetV1c 的变种,在这里输入层的 7x7 卷积被 3个 3x3 取代。
* 为了在不同的硬件上保持一致,我们以 `torch.cuda.max_memory_allocated()` 的最大值作为 GPU 占用率,同时设置 `torch.backends.cudnn.benchmark=False`
注意,这通常比 `nvidia-smi` 显示的要少。
* 我们以网络 forward 和后处理的时间加和作为推理时间,除去数据加载时间。我们使用脚本 `tools/benchmark.py` 来获取推理时间,它在 `torch.backends.cudnn.benchmark=False` 的设定下,计算 200 张图片的平均推理时间。
* 在框架中,有两种推理模式。
* `slide` 模式(滑动模式):测试的配置文件字段 `test_cfg` 会是 `dict(mode='slide', crop_size=(769, 769), stride=(513, 513))`.
在这个模式下,从原图中裁剪多个小图分别输入网络中进行推理。小图的大小和小图之间的距离由 `crop_size``stride` 决定,重合区域会进行平均。
* `whole` 模式 (全图模式):测试的配置文件字段 `test_cfg` 会是 `dict(mode='whole')`. 在这个模式下,全图会被直接输入到网络中进行推理。
对于 769x769 下训练的模型,我们默认使用 `slide` 进行推理,其余模型用 `whole` 进行推理。
* 对于输入大小为 8x+1 比如769我们使用 `align_corners=True`。其余情况,对于输入大小为 8x+1 (比如 5121024),我们使用 `align_corners=False`
## 基线
### FCN
请参考 [FCN](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/fcn) for details.
### PSPNet
请参考 [PSPNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/pspnet) for details.
### DeepLabV3
请参考 [DeepLabV3](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/deeplabv3) for details.
### PSANet
请参考 [PSANet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/psanet) for details.
### DeepLabV3+
请参考 [DeepLabV3+](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/deeplabv3plus) for details.
### UPerNet
请参考 [UPerNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/upernet) for details.
### NonLocal Net
请参考 [NonLocal Net](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/nlnet) for details.
### EncNet
请参考 [EncNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/encnet) for details.
### CCNet
请参考 [CCNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/ccnet) for details.
### DANet
请参考 [DANet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/danet) for details.
### APCNet
请参考 [APCNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/apcnet) for details.
### HRNet
请参考 [HRNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/hrnet) for details.
### GCNet
请参考 [GCNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/gcnet) for details.
### DMNet
请参考 [DMNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/dmnet) for details.
### ANN
请参考 [ANN](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/ann) for details.
### OCRNet
请参考 [OCRNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/ocrnet) for details.
### Fast-SCNN
请参考 [Fast-SCNN](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/fastscnn) for details.
### ResNeSt
请参考 [ResNeSt](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/resnest) for details.
### Semantic FPN
请参考 [Semantic FPN](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/semfpn) for details.
### PointRend
请参考 [PointRend](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/point_rend) for details.
### MobileNetV2
请参考 [MobileNetV2](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/mobilenet_v2) for details.
### MobileNetV3
请参考 [MobileNetV3](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/mobilenet_v3) for details.
### EMANet
请参考 [EMANet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/emanet) for details.
### DNLNet
请参考 [DNLNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/dnlnet) for details.
### CGNet
请参考 [CGNet](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/cgnet) for details.
### Mixed Precision (FP16) Training
Please refer [Mixed Precision (FP16) Training](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/fp16/README.md) for details.
## 速度标定
### 硬件
* 8 NVIDIA Tesla V100 (32G) GPUs
* Intel(R) Xeon(R) Gold 6148 CPU @ 2.40GHz
### 软件环境
* Python 3.7
* PyTorch 1.5
* CUDA 10.1
* CUDNN 7.6.03
* NCCL 2.4.08
### 训练速度
为了公平比较,我们全部使用 ResNet-101V1c 进行标定。输入大小为 1024x512批量样本数为 2。
训练速度如下表,指标为每次迭代的时间,以秒为单位,越低越快。
| Implementation | PSPNet (s/iter) | DeepLabV3+ (s/iter) |
|----------------|-----------------|---------------------|
| [MMSegmentation](https://github.com/open-mmlab/mmsegmentation) | **0.83** | **0.85** |
| [SegmenTron](https://github.com/LikeLy-Journey/SegmenTron) | 0.84 | 0.85 |
| [CASILVision](https://github.com/CSAILVision/semantic-segmentation-pytorch) | 1.15 | N/A |
| [vedaseg](https://github.com/Media-Smart/vedaseg) | 0.95 | 1.25 |
注意DeepLabV3+ 的输出步长为 8。

64
docs_zh-CN/stat.py Executable file
View File

@ -0,0 +1,64 @@
#!/usr/bin/env python
import functools as func
import glob
import os.path as osp
import re
import numpy as np
url_prefix = 'https://github.com/open-mmlab/mmsegmentation/blob/master/'
files = sorted(glob.glob('../configs/*/README.md'))
stats = []
titles = []
num_ckpts = 0
for f in files:
url = osp.dirname(f.replace('../', url_prefix))
with open(f, 'r') as content_file:
content = content_file.read()
title = content.split('\n')[0].replace('#', '').strip()
ckpts = set(x.lower().strip()
for x in re.findall(r'https?://download.*\.pth', content)
if 'mmsegmentation' in x)
if len(ckpts) == 0:
continue
_papertype = [
x for x in re.findall(r'<!--\s*\[([A-Z]*?)\]\s*-->', content)
]
assert len(_papertype) > 0
papertype = _papertype[0]
paper = set([(papertype, title)])
titles.append(title)
num_ckpts += len(ckpts)
statsmsg = f"""
\t* [{papertype}] [{title}]({url}) ({len(ckpts)} ckpts)
"""
stats.append((paper, ckpts, statsmsg))
allpapers = func.reduce(lambda a, b: a.union(b), [p for p, _, _ in stats])
msglist = '\n'.join(x for _, _, x in stats)
papertypes, papercounts = np.unique([t for t, _ in allpapers],
return_counts=True)
countstr = '\n'.join(
[f' - {t}: {c}' for t, c in zip(papertypes, papercounts)])
modelzoo = f"""
# 模型库统计数据
* 论文数量: {len(set(titles))}
{countstr}
* 模型数量: {num_ckpts}
{msglist}
"""
with open('modelzoo_statistics.md', 'w') as f:
f.write(modelzoo)

View File

@ -0,0 +1,3 @@
## <a href='https://mmsegmentation.readthedocs.io/en/latest/'>English</a>
## <a href='https://mmsegmentation.readthedocs.io/zh_CN/latest/'>简体中文</a>

82
docs_zh-CN/train.md Normal file
View File

@ -0,0 +1,82 @@
## 训练一个模型
MMSegmentation 可以执行分布式训练和非分布式训练,分别使用 `MMDistributedDataParallel``MMDataParallel` 命令。
所有的输出(日志 log 和检查点 checkpoints )将被保存到工作路径文件夹里,它可以通过配置文件里的 `work_dir` 指定。
在一定迭代轮次后,我们默认在验证集上评估模型表现。您可以在训练配置文件中添加间隔参数来改变评估间隔。
```python
evaluation = dict(interval=4000) # 每4000 iterations 评估一次模型的性能
```
**\*Important\***: 在配置文件里的默认学习率是针对4卡 GPU 和2张图/GPU (此时 batchsize = 4x2 = 8)来设置的。
同样您也可以使用8卡 GPU 和 1张图/GPU 的设置,因为所有的模型均使用 cross-GPU 的 SyncBN 模式。
我们可以在训练速度和 GPU 显存之间做平衡。当模型或者 Batch Size 比较大的时,可以传递`--options model.backbone.with_cp=True` ,使用 `with_cp` 来节省显存,但是速度会更慢,因为原先使用 `ith_cp` 时,是逐层反向传播(Back Propagation, BP),不会保存所有的梯度。
### 使用单卡 GPU 训练
```shell
python tools/train.py ${配置文件} [可选参数]
```
如果您想在命令里定义工作文件夹路径,您可以添加一个参数`--work-dir ${YOUR_WORK_DIR}`
### 使用多卡 GPU 训练
```shell
./tools/dist_train.sh ${配置文件} ${GPU 个数} [可选参数]
```
可选参数可以为:
- `--no-validate` (**不推荐**): 训练时代码库默认会在每 k 轮迭代后在验证集上进行评估,如果不需评估使用命令 `--no-validate`
- `--work-dir ${工作路径}`: 在配置文件里重写工作路径文件夹。
- `--resume-from ${检查点文件}`: 继续使用先前的检查点 (checkpoint) 文件(可以继续训练过程)。
- `--load-from ${检查点文件}`: 从一个检查点 (checkpoint) 文件里加载权重(对另一个任务进行精调)。
`resume-from``load-from` 的区别:
- `resume-from` 加载出模型权重和优化器状态包括迭代轮数等。
- `load-from` 仅加载模型权重从第0轮开始训练。
### 使用多个机器训练
如果您在一个集群上以[slurm](https://slurm.schedmd.com/) 运行 MMSegmentation
您可以使用脚本 `slurm_train.sh`(这个脚本同样支持单个机器的训练)。
```shell
[GPUS=${GPU 数量}] ./tools/slurm_train.sh ${分区} ${任务名称} ${配置文件} --work-dir ${工作路径}
```
这里是在 dev 分区里使用16块 GPU 训练 PSPNet 的例子。
```shell
GPUS=16 ./tools/slurm_train.sh dev pspr50 configs/pspnet/pspnet_r50-d8_512x1024_40k_cityscapes.py /nfs/xxxx/psp_r50_512x1024_40ki_cityscapes
```
您可以查看 [slurm_train.sh](../tools/slurm_train.sh) 以熟悉全部的参数与环境变量。
如果您多个机器已经有以太网连接, 您可以参考 PyTorch
[launch utility](https://pytorch.org/docs/stable/distributed_deprecated.html#launch-utility) 。
若您没有像 InfiniBand 这样高速的网络连接,多机器训练通常会比较慢。
### 在单个机器上启动多个任务
如果您在单个机器上启动多个任务例如在8卡 GPU 的一个机器上有2个4卡 GPU 的训练任务您需要特别对每个任务指定不同的端口默认为29500来避免通讯冲突。
否则,将会有报错信息 `RuntimeError: Address already in use`
如果您使用命令 `dist_train.sh` 来启动一个训练任务,您可以在命令行的用环境变量 `PORT` 设置端口。
```shell
CUDA_VISIBLE_DEVICES=0,1,2,3 PORT=29500 ./tools/dist_train.sh ${配置文件} 4
CUDA_VISIBLE_DEVICES=4,5,6,7 PORT=29501 ./tools/dist_train.sh ${配置文件} 4
```
如果您使用命令 `slurm_train.sh` 来启动训练任务,您可以在命令行的用环境变量 `MASTER_PORT` 设置端口。
```shell
MASTER_PORT=29500 ./tools/slurm_train.sh ${分区} ${任务名称} ${配置文件}
MASTER_PORT=29501 ./tools/slurm_train.sh ${分区} ${任务名称} ${配置文件}
```

View File

@ -0,0 +1,377 @@
# 教程 1: 学习配置文件
我们整合了模块和继承设计到我们的配置里,这便于做很多实验。如果您想查看配置文件,您可以运行 `python tools/print_config.py /PATH/TO/CONFIG` 去查看完整的配置文件。您还可以传递参数
`--options xxx.yyy=zzz` 去查看更新的配置。
## 配置文件的结构
`config/_base_` 文件夹下面有4种基本组件类型 数据集(dataset),模型(model),训练策略(schedule)和运行时的默认设置(default runtime)。许多方法都可以方便地通过组合这些组件进行实现。
这样,像 DeepLabV3, PSPNet 这样的模型可以容易地被构造。被来自 `_base_` 下的组件来构建的配置叫做 _原始配置 (primitive)_
对于所有在同一个文件夹下的配置文件,推荐**只有一个**对应的**原始配置**文件。所有其他的配置文件都应该继承自这个**原始配置**文件。这样就能保证配置文件的最大继承深度为 3。
为了便于理解,我们推荐社区贡献者继承已有的方法配置文件。
例如,如果一些修改是基于 DeepLabV3使用者首先首先应该通过指定 `_base_ = ../deeplabv3/deeplabv3_r50_512x1024_40ki_cityscapes.py`来继承基础 DeepLabV3 结构,再去修改配置文件里其他内容以完成继承。
如果您正在构建一个完整的新模型,它完全没有和已有的方法共享一些结构,您可能需要在 `configs` 下面创建一个文件夹 `xxxnet`
更详细的文档,请参照 [mmcv](https://mmcv.readthedocs.io/en/latest/utils.html#config) 。
## 配置文件命名风格
我们按照下面的风格去命名配置文件。社区贡献者被建议使用同样的风格。
```
{model}_{backbone}_[misc]_[gpu x batch_per_gpu]_{resolution}_{schedule}_{dataset}
```
`{xxx}` 是被要求的文件 `[yyy]` 是可选的。
- `{model}`: 模型种类,例如 `psp` `deeplabv3` 等等。
- `{backbone}`: 主干网络种类,例如 `r50` (ResNet-50) `x101` (ResNeXt-101)。
- `[misc]`: 模型中各式各样的设置/插件,例如 `dconv` `gcb` `attention` `mstrain`
- `[gpu x batch_per_gpu]`: GPU数目 和每个 GPU 的样本数, 默认为 `8x2`
- `{schedule}`: 训练方案, `20ki` 意思是 20k 迭代轮数.
- `{dataset}`: 数据集,如 `cityscapes` `voc12aug` `ade`
## PSPNet 的一个例子
为了帮助使用者熟悉这个流行的语义分割框架的完整配置文件和模块,我们在下面对使用 ResNet50V1c 的 PSPNet 的配置文件做了详细的注释说明。
更多的详细使用和其他模块的替代项请参考 API 文档。
```python
norm_cfg = dict(type='SyncBN', requires_grad=True) # 分割框架通常使用 SyncBN
model = dict(
type='EncoderDecoder', # 分割器(segmentor)的名字
pretrained='open-mmlab://resnet50_v1c', # 将被加载的 ImageNet 预训练主干网络
backbone=dict(
type='ResNetV1c', # 主干网络的类别。 可用选项请参考 mmseg/backbone/resnet.py
depth=50, # 主干网络的深度。通常为 50 和 101。
num_stages=4, # 主干网络状态(stages)的数目,这些状态产生的特征图作为后续的 head 的输入。
out_indices=(0, 1, 2, 3), # 每个状态产生的特征图输出的索引。
dilations=(1, 1, 2, 4), # 每一层(layer)的空心率(dilation rate)。
strides=(1, 2, 1, 1), # 每一层(layer)的步长(stride)。
norm_cfg=dict( # 归一化层(norm layer)的配置项。
type='SyncBN', # 归一化层的类别。通常是 SyncBN。
requires_grad=True), # 是否训练归一化里的 gamma 和 beta。
norm_eval=False, # 是否冻结 BN 里的统计项。
style='pytorch', # 主干网络的风格,'pytorch' 意思是步长为2的层为 3x3 卷积, 'caffe' 意思是步长为2的层为 1x1 卷积。
contract_dilation=True), # 当空洞 > 1, 是否压缩第一个空洞层。
decode_head=dict(
type='PSPHead', # 解码头(decode head)的类别。 可用选项请参考 mmseg/models/decode_heads。
in_channels=2048, # 解码头的输入通道数。
in_index=3, # 被选择的特征图(feature map)的索引。
channels=512, # 解码头中间态(intermediate)的通道数。
pool_scales=(1, 2, 3, 6), # PSPHead 平均池化(avg pooling)的规模(scales)。 细节请参考文章内容。
dropout_ratio=0.1, # 进入最后分类层(classification layer)之前的 dropout 比例。
num_classes=19, # 分割前景的种类数目。 通常情况下cityscapes 为19VOC为21ADE20k 为150。
norm_cfg=dict(type='SyncBN', requires_grad=True), # 归一化层的配置项。
align_corners=False, # 解码里调整大小(resize)的 align_corners 参数。
loss_decode=dict( # 解码头(decode_head)里的损失函数的配置项。
type='CrossEntropyLoss', # 在分割里使用的损失函数的类别。
use_sigmoid=False, # 在分割里是否使用 sigmoid 激活。
loss_weight=1.0)), # 解码头里损失的权重。
auxiliary_head=dict(
type='FCNHead', # 辅助头(auxiliary head)的种类。可用选项请参考 mmseg/models/decode_heads。
in_channels=1024, # 辅助头的输入通道数。
in_index=2, # 被选择的特征图(feature map)的索引。
channels=256, # 辅助头中间态(intermediate)的通道数。
num_convs=1, # FCNHead 里卷积(convs)的数目. 辅助头里通常为1。
concat_input=False, # 在分类层(classification layer)之前是否连接(concat)输入和卷积的输出。
dropout_ratio=0.1, # 进入最后分类层(classification layer)之前的 dropout 比例。
num_classes=19, # 分割前景的种类数目。 通常情况下cityscapes 为19VOC为21ADE20k 为150。
norm_cfg=dict(type='SyncBN', requires_grad=True), # 归一化层的配置项。
align_corners=False, # 解码里调整大小(resize)的 align_corners 参数。
loss_decode=dict( # 辅助头(auxiliary head)里的损失函数的配置项。
type='CrossEntropyLoss', # 在分割里使用的损失函数的类别。
use_sigmoid=False, # 在分割里是否使用 sigmoid 激活。
loss_weight=0.4))) # 辅助头里损失的权重。默认设置为0.4。
train_cfg = dict() # train_cfg 当前仅是一个占位符。
test_cfg = dict(mode='whole') # 测试模式, 选项是 'whole' 和 'sliding'. 'whole': 整张图像全卷积(fully-convolutional)测试。 'sliding': 图像上做滑动裁剪窗口(sliding crop window)。
dataset_type = 'CityscapesDataset' # 数据集类型,这将被用来定义数据集。
data_root = 'data/cityscapes/' # 数据的根路径。
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'), # 第1个流程从文件路径里加载图像。
dict(type='LoadAnnotations'), # 第2个流程对于当前图像加载它的注释信息。
dict(type='Resize', # 变化图像和其注释大小的数据增广的流程。
img_scale=(2048, 1024), # 图像的最大规模。
ratio_range=(0.5, 2.0)), # 数据增广的比例范围。
dict(type='RandomCrop', # 随机裁剪当前图像和其注释大小的数据增广的流程。
crop_size=(512, 1024), # 随机裁剪图像生成 patch 的大小。
cat_max_ratio=0.75), # 单个类别可以填充的最大区域的比例。
dict(
type='RandomFlip', # 翻转图像和其注释大小的数据增广的流程。
flip_ratio=0.5), # 翻转图像的概率
dict(type='PhotoMetricDistortion'), # 光学上使用一些方法扭曲当前图像和其注释的数据增广的流程。
dict(
type='Normalize', # 归一化当前图像的数据增广的流程。
mean=[123.675, 116.28, 103.53], # 这些键与 img_norm_cfg 一致,因为 img_norm_cfg 被
std=[58.395, 57.12, 57.375], # 用作参数。
to_rgb=True),
dict(type='Pad', # 填充当前图像到指定大小的数据增广的流程。
size=(512, 1024), # 填充的图像大小。
pad_val=0, # 图像的填充值。
seg_pad_val=255), # 'gt_semantic_seg'的填充值。
dict(type='DefaultFormatBundle'), # 流程里收集数据的默认格式捆。
dict(type='Collect', # 决定数据里哪些键被传递到分割器里的流程。
keys=['img', 'gt_semantic_seg'])
]
test_pipeline = [
dict(type='LoadImageFromFile'), # 第1个流程从文件路径里加载图像。
dict(
type='MultiScaleFlipAug', # 封装测试时数据增广(test time augmentations)。
img_scale=(2048, 1024), # 决定测试时可改变图像的最大规模。用于改变图像大小的流程。
flip=False, # 测试时是否翻转图像。
transforms=[
dict(type='Resize', # 使用改变图像大小的数据增广。
keep_ratio=True), # 是否保持宽和高的比例,这里的图像比例设置将覆盖上面的图像规模大小的设置。
dict(type='RandomFlip'), # 考虑到 RandomFlip 已经被添加到流程里,当 flip=False 时它将不被使用。
dict(
type='Normalize', # 归一化配置项,值来自 img_norm_cfg。
mean=[123.675, 116.28, 103.53],
std=[58.395, 57.12, 57.375],
to_rgb=True),
dict(type='ImageToTensor', # 将图像转为张量
keys=['img']),
dict(type='Collect', # 收集测试时必须的键的收集流程。
keys=['img'])
])
]
data = dict(
samples_per_gpu=2, # 单个 GPU 的 Batch size
workers_per_gpu=2, # 单个 GPU 分配的数据加载线程数
train=dict( # 训练数据集配置
type='CityscapesDataset', # 数据集的类别, 细节参考自 mmseg/datasets/。
data_root='data/cityscapes/', # 数据集的根目录。
img_dir='leftImg8bit/train', # 数据集图像的文件夹。
ann_dir='gtFine/train', # 数据集注释的文件夹。
pipeline=[ # 流程, 由之前创建的 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=(512, 1024), cat_max_ratio=0.75),
dict(type='RandomFlip', flip_ratio=0.5),
dict(type='PhotoMetricDistortion'),
dict(
type='Normalize',
mean=[123.675, 116.28, 103.53],
std=[58.395, 57.12, 57.375],
to_rgb=True),
dict(type='Pad', size=(512, 1024), pad_val=0, seg_pad_val=255),
dict(type='DefaultFormatBundle'),
dict(type='Collect', keys=['img', 'gt_semantic_seg'])
]),
val=dict( # 验证数据集的配置
type='CityscapesDataset',
data_root='data/cityscapes/',
img_dir='leftImg8bit/val',
ann_dir='gtFine/val',
pipeline=[ # 由之前创建的 test_pipeline 传递的流程。
dict(type='LoadImageFromFile'),
dict(
type='MultiScaleFlipAug',
img_scale=(2048, 1024),
flip=False,
transforms=[
dict(type='Resize', keep_ratio=True),
dict(type='RandomFlip'),
dict(
type='Normalize',
mean=[123.675, 116.28, 103.53],
std=[58.395, 57.12, 57.375],
to_rgb=True),
dict(type='ImageToTensor', keys=['img']),
dict(type='Collect', keys=['img'])
])
]),
test=dict(
type='CityscapesDataset',
data_root='data/cityscapes/',
img_dir='leftImg8bit/val',
ann_dir='gtFine/val',
pipeline=[
dict(type='LoadImageFromFile'),
dict(
type='MultiScaleFlipAug',
img_scale=(2048, 1024),
flip=False,
transforms=[
dict(type='Resize', keep_ratio=True),
dict(type='RandomFlip'),
dict(
type='Normalize',
mean=[123.675, 116.28, 103.53],
std=[58.395, 57.12, 57.375],
to_rgb=True),
dict(type='ImageToTensor', keys=['img']),
dict(type='Collect', keys=['img'])
])
]))
log_config = dict( # 注册日志钩 (register logger hook) 的配置文件。
interval=50, # 打印日志的间隔
hooks=[
# dict(type='TensorboardLoggerHook') # 同样支持 Tensorboard 日志
dict(type='TextLoggerHook', by_epoch=False)
])
dist_params = dict(backend='nccl') # 用于设置分布式训练的参数,端口也同样可被设置。
log_level = 'INFO' # 日志的级别。
load_from = None # 从一个给定路径里加载模型作为预训练模型,它并不会消耗训练时间。
resume_from = None # 从给定路径里恢复检查点(checkpoints),训练模式将从检查点保存的轮次开始恢复训练。
workflow = [('train', 1)] # runner 的工作流程。 [('train', 1)] 意思是只有一个工作流程而且工作流程 'train' 仅执行一次。根据 `runner.max_iters` 工作流程训练模型的迭代轮数为40000次。
cudnn_benchmark = True # 是否是使用 cudnn_benchmark 去加速,它对于固定输入大小的可以提高训练速度。
optimizer = dict( # 用于构建优化器的配置文件。支持 PyTorch 中的所有优化器同时它们的参数与PyTorch里的优化器参数一致。
type='SGD', # 优化器种类,更多细节可参考 https://github.com/open-mmlab/mmcv/blob/master/mmcv/runner/optimizer/default_constructor.py#L13
lr=0.01, # 优化器的学习率,参数的使用细节请参照对应的 PyTorch 文档。
momentum=0.9, # 动量 (Momentum)
weight_decay=0.0005) # SGD 的衰减权重 (weight decay)。
optimizer_config = dict() # 用于构建优化器钩 (optimizer hook) 的配置文件,执行细节请参考 https://github.com/open-mmlab/mmcv/blob/master/mmcv/runner/hooks/optimizer.py#L8
lr_config = dict(
policy='poly', # 调度流程的策略,同样支持 Step, CosineAnnealing, Cyclic 等. 请从 https://github.com/open-mmlab/mmcv/blob/master/mmcv/runner/hooks/lr_updater.py#L9 参考 LrUpdater 的细节。
power=0.9, # 多项式衰减 (polynomial decay) 的幂。
min_lr=0.0001, # 用来稳定训练的最小学习率。
by_epoch=False) # 是否按照每个 epoch 去算学习率。
runner = dict(
type='IterBasedRunner', # 将使用的 runner 的类别 (例如 IterBasedRunner 或 EpochBasedRunner)。
max_iters=40000) # 全部迭代轮数大小,对于 EpochBasedRunner 使用 `max_epochs`
checkpoint_config = dict( # 设置检查点钩子 (checkpoint hook) 的配置文件。执行时请参考 https://github.com/open-mmlab/mmcv/blob/master/mmcv/runner/hooks/checkpoint.py。
by_epoch=False, # 是否按照每个 epoch 去算 runner。
interval=4000) # 保存的间隔
evaluation = dict( # 构建评估钩 (evaluation hook) 的配置文件。细节请参考 mmseg/core/evaulation/eval_hook.py。
interval=4000, # 评估的间歇点
metric='mIoU') # 评估的指标
```
## FAQ
### 忽略基础配置文件里的一些域内容。
有时,您也许会设置 `_delete_=True` 去忽略基础配置文件里的一些域内容。
您也许可以参照 [mmcv](https://mmcv.readthedocs.io/en/latest/utils.html#inherit-from-base-config-with-ignored-fields) 来获得一些简单的指导。
在 MMSegmentation 里,例如为了改变 PSPNet 的主干网络的某些内容:
```python
norm_cfg = dict(type='SyncBN', requires_grad=True)
model = dict(
type='MaskRCNN',
pretrained='torchvision://resnet50',
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(...),
auxiliary_head=dict(...))
```
`ResNet``HRNet` 使用不同的关键词去构建。
```python
_base_ = '../pspnet/psp_r50_512x1024_40ki_cityscpaes.py'
norm_cfg = dict(type='SyncBN', requires_grad=True)
model = dict(
pretrained='open-mmlab://msra/hrnetv2_w32',
backbone=dict(
_delete_=True,
type='HRNet',
norm_cfg=norm_cfg,
extra=dict(
stage1=dict(
num_modules=1,
num_branches=1,
block='BOTTLENECK',
num_blocks=(4, ),
num_channels=(64, )),
stage2=dict(
num_modules=1,
num_branches=2,
block='BASIC',
num_blocks=(4, 4),
num_channels=(32, 64)),
stage3=dict(
num_modules=4,
num_branches=3,
block='BASIC',
num_blocks=(4, 4, 4),
num_channels=(32, 64, 128)),
stage4=dict(
num_modules=3,
num_branches=4,
block='BASIC',
num_blocks=(4, 4, 4, 4),
num_channels=(32, 64, 128, 256)))),
decode_head=dict(...),
auxiliary_head=dict(...))
```
`_delete_=True` 将用新的键去替换 `backbone` 域内所有老的键。
### 使用配置文件里的中间变量
配置文件里会使用一些中间变量,例如数据集里的 `train_pipeline`/`test_pipeline`
需要注意的是,在子配置文件里修改中间变量时,使用者需要再次传递这些变量给对应的域。
例如我们想改变在训练或测试时PSPNet 的多尺度策略 (multi scale strategy)`train_pipeline`/`test_pipeline` 是我们想要修改的中间变量。
```python
_base_ = '../pspnet/psp_r50_512x1024_40ki_cityscapes.py'
crop_size = (512, 1024)
img_norm_cfg = dict(
mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True)
train_pipeline = [
dict(type='LoadImageFromFile'),
dict(type='LoadAnnotations'),
dict(type='Resize', img_scale=(2048, 1024), ratio_range=(1.0, 2.0)), # 改成 [1., 2.]
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], # 改成多尺度测试 (multi scale testing)。
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']),
])
]
data = dict(
train=dict(pipeline=train_pipeline),
val=dict(pipeline=test_pipeline),
test=dict(pipeline=test_pipeline))
```
我们首先定义新的 `train_pipeline`/`test_pipeline` 然后传递到 `data` 里。
同样的,如果我们想从 `SyncBN` 切换到 `BN` 或者 `MMSyncBN`,我们需要配置文件里的每一个 `norm_cfg`
```python
_base_ = '../pspnet/psp_r50_512x1024_40ki_cityscpaes.py'
norm_cfg = dict(type='BN', requires_grad=True)
model = dict(
backbone=dict(norm_cfg=norm_cfg),
decode_head=dict(norm_cfg=norm_cfg),
auxiliary_head=dict(norm_cfg=norm_cfg))
```

View File

@ -0,0 +1,173 @@
# 教程 2: 自定义数据集
## 通过重新组织数据来定制数据集
最简单的方法是将您的数据集进行转化,并组织成文件夹的形式。
如下的文件结构就是一个例子。
```none
├── data
│ ├── my_dataset
│ │ ├── img_dir
│ │ │ ├── train
│ │ │ │ ├── xxx{img_suffix}
│ │ │ │ ├── yyy{img_suffix}
│ │ │ │ ├── zzz{img_suffix}
│ │ │ ├── val
│ │ ├── ann_dir
│ │ │ ├── train
│ │ │ │ ├── xxx{seg_map_suffix}
│ │ │ │ ├── yyy{seg_map_suffix}
│ │ │ │ ├── zzz{seg_map_suffix}
│ │ │ ├── val
```
一个训练对将由 img_dir/ann_dir 里同样首缀的文件组成。
如果给定 `split` 参数,只有部分在 img_dir/ann_dir 里的文件会被加载。
我们可以对被包括在 split 文本里的文件指定前缀。
除此以外,一个 split 文本如下所示:
```none
xxx
zzz
```
只有
`data/my_dataset/img_dir/train/xxx{img_suffix}`,
`data/my_dataset/img_dir/train/zzz{img_suffix}`,
`data/my_dataset/ann_dir/train/xxx{seg_map_suffix}`,
`data/my_dataset/ann_dir/train/zzz{seg_map_suffix}` 将被加载。
注意:标注是跟图像同样的形状 (H, W),其中的像素值的范围是 `[0, num_classes - 1]`
您也可以使用 [pillow](https://pillow.readthedocs.io/en/stable/handbook/concepts.html#palette) 的 `'P'` 模式去创建包含颜色的标注。
## 通过混合数据去定制数据集
MMSegmentation 同样支持混合数据集去训练。
当前它支持拼接 (concat) 和 重复 (repeat) 数据集。
### 重复数据集
我们使用 `RepeatDataset` 作为包装 (wrapper) 去重复数据集。
例如,假设原始数据集是 `Dataset_A`,为了重复它,配置文件如下:
```python
dataset_A_train = dict(
type='RepeatDataset',
times=N,
dataset=dict( # 这是 Dataset_A 数据集的原始配置
type='Dataset_A',
...
pipeline=train_pipeline
)
)
```
### 拼接数据集
有2种方式去拼接数据集。
1. 如果您想拼接的数据集是同样的类型,但有不同的标注文件,
您可以按如下操作去拼接数据集的配置文件:
1. 您也许可以拼接两个标注文件夹 `ann_dir`
```python
dataset_A_train = dict(
type='Dataset_A',
img_dir = 'img_dir',
ann_dir = ['anno_dir_1', 'anno_dir_2'],
pipeline=train_pipeline
)
```
2. 您也可以去拼接两个 `split` 文件列表。
```python
dataset_A_train = dict(
type='Dataset_A',
img_dir = 'img_dir',
ann_dir = 'anno_dir',
split = ['split_1.txt', 'split_2.txt'],
pipeline=train_pipeline
)
```
3. 您也可以同时拼接 `ann_dir` 文件夹和 `split` 文件列表。
```python
dataset_A_train = dict(
type='Dataset_A',
img_dir = 'img_dir',
ann_dir = ['anno_dir_1', 'anno_dir_2'],
split = ['split_1.txt', 'split_2.txt'],
pipeline=train_pipeline
)
```
在这样的情况下, `ann_dir_1``ann_dir_2` 分别对应于 `split_1.txt``split_2.txt`
2. 如果您想拼接不同的数据集,您可以如下去拼接数据集的配置文件:
```python
dataset_A_train = dict()
dataset_B_train = dict()
data = dict(
imgs_per_gpu=2,
workers_per_gpu=2,
train = [
dataset_A_train,
dataset_B_train
],
val = dataset_A_val,
test = dataset_A_test
)
```
一个更复杂的例子如下:分别重复 `Dataset_A``Dataset_B` N 次和 M 次,然后再去拼接重复后的数据集。
```python
dataset_A_train = dict(
type='RepeatDataset',
times=N,
dataset=dict(
type='Dataset_A',
...
pipeline=train_pipeline
)
)
dataset_A_val = dict(
...
pipeline=test_pipeline
)
dataset_A_test = dict(
...
pipeline=test_pipeline
)
dataset_B_train = dict(
type='RepeatDataset',
times=M,
dataset=dict(
type='Dataset_B',
...
pipeline=train_pipeline
)
)
data = dict(
imgs_per_gpu=2,
workers_per_gpu=2,
train = [
dataset_A_train,
dataset_B_train
],
val = dataset_A_val,
test = dataset_A_test
)
```

View File

@ -0,0 +1,230 @@
# 教程 4: 自定义模型
## 自定义优化器 (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, optimizer_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))
```

View File

@ -0,0 +1,246 @@
# 教程 6: 自定义运行设定
## 自定义优化设定
### 自定义 PyTorch 支持的优化器
我们已经支持 PyTorch 自带的所有优化器,唯一需要修改的地方是在配置文件里的 `optimizer` 域里面。
例如,如果您想使用 `ADAM` (注意如下操作可能会让模型表现下降),可以使用如下修改:
```python
optimizer = dict(type='Adam', lr=0.0003, weight_decay=0.0001)
```
为了修改模型的学习率,使用者仅需要修改配置文件里 optimizer 的 `lr` 即可。
使用者可以参照 PyTorch 的 [API 文档](https://pytorch.org/docs/stable/optim.html?highlight=optim#module-torch.optim)
直接设置参数。
### 自定义 自己实现的优化器
#### 1. 定义一个新的优化器
一个自定义的优化器可以按照如下去定义:
假如您想增加一个叫做 `MyOptimizer` 的优化器,它的参数分别有 `a`, `b`, 和 `c`
您需要创建一个叫 `mmseg/core/optimizer` 的新文件夹。
然后再在文件,即 `mmseg/core/optimizer/my_optimizer.py` 里面去实现这个新优化器:
```python
from .registry import OPTIMIZERS
from torch.optim import Optimizer
@OPTIMIZERS.register_module()
class MyOptimizer(Optimizer):
def __init__(self, a, b, c)
```
#### 2. 增加优化器到注册表 (registry)
为了让上述定义的模块被框架发现,首先这个模块应该被导入到主命名空间 (main namespace) 里。
有两种方式可以实现它。
- 修改 `mmseg/core/optimizer/__init__.py` 来导入它。
新的被定义的模块应该被导入到 `mmseg/core/optimizer/__init__.py` 这样注册表将会发现新的模块并添加它。
```python
from .my_optimizer import MyOptimizer
```
- 在配置文件里使用 `custom_imports` 去手动导入它。
```python
custom_imports = dict(imports=['mmseg.core.optimizer.my_optimizer'], allow_failed_imports=False)
```
`mmseg.core.optimizer.my_optimizer` 模块将会在程序运行的开始被导入,并且 `MyOptimizer` 类将会自动注册。
需要注意只有包含 `MyOptimizer` 类的包 (package) 应当被导入。
`mmseg.core.optimizer.my_optimizer.MyOptimizer` **不能** 被直接导入。
事实上,使用者完全可以用另一个按这样导入方法的文件夹结构,只要模块的根路径已经被添加到 `PYTHONPATH` 里面。
#### 3. 在配置文件里定义优化器
之后您可以在配置文件的 `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)
```
### 自定义优化器的构造器 (constructor)
有些模型可能需要在优化器里有一些特别参数的设置,例如 批归一化层 (BatchNorm layers) 的 权重衰减 (weight decay)。
使用者可以通过自定义优化器的构造器去微调这些细粒度参数。
```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):
def __init__(self, optimizer_cfg, paramwise_cfg=None):
def __call__(self, model):
return my_optimizer
```
默认的优化器构造器的实现可以参照 [这里](https://github.com/open-mmlab/mmcv/blob/9ecd6b0d5ff9d2172c49a182eaa669e9f27bb8e7/mmcv/runner/optimizer/default_constructor.py#L11) ,它也可以被用作新的优化器构造器的模板。
### 额外的设置
优化器没有实现的一些技巧应该通过优化器构造器 (optimizer constructor) 或者钩子 (hook) 去实现,如设置基于参数的学习率 (parameter-wise learning rates)。我们列出一些常见的设置,它们可以稳定或加速模型的训练。
如果您有更多的设置,欢迎在 PR 和 issue 里面提交。
- __使用梯度截断 (gradient clip) 去稳定训练__:
一些模型需要梯度截断去稳定训练过程,如下所示:
```python
optimizer_config = dict(
_delete_=True, grad_clip=dict(max_norm=35, norm_type=2))
```
如果您的配置继承自已经设置了 `optimizer_config` 的基础配置 (base config),您可能需要 `_delete_=True` 来重写那些不需要的设置。更多细节请参照 [配置文件文档](https://mmsegmentation.readthedocs.io/en/latest/config.html) 。
- __使用动量计划表 (momentum schedule) 去加速模型收敛__:
我们支持动量计划表去让模型基于学习率修改动量,这样可能让模型收敛地更快。
动量计划表经常和学习率计划表 (LR scheduler) 一起使用,例如如下配置文件就在 3D 检测里经常使用以加速收敛。
更多细节请参考 [CyclicLrUpdater](https://github.com/open-mmlab/mmcv/blob/f48241a65aebfe07db122e9db320c31b685dc674/mmcv/runner/hooks/lr_updater.py#L327) 和 [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,
)
```
## 自定义训练计划表
我们根据默认的训练迭代步数 40k/80k 来设置学习率,这在 MMCV 里叫做 [`PolyLrUpdaterHook`](https://github.com/open-mmlab/mmcv/blob/826d3a7b68596c824fa1e2cb89b6ac274f52179c/mmcv/runner/hooks/lr_updater.py#L196) 。
我们也支持许多其他的学习率计划表:[这里](https://github.com/open-mmlab/mmcv/blob/master/mmcv/runner/hooks/lr_updater.py) ,例如 `CosineAnnealing``Poly` 计划表。下面是一些例子:
- 步计划表 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)
```
## 自定义工作流 (workflow)
工作流是一个专门定义运行顺序和轮数 (running order and epochs) 的列表 (phase, epochs)。
默认情况下它设置成:
```python
workflow = [('train', 1)]
```
意思是训练是跑 1 个 epoch。有时候使用者可能想检查模型在验证集上的一些指标如 损失 loss精确性 accuracy我们可以这样设置工作流
```python
[('train', 1), ('val', 1)]
```
于是 1 个 epoch 训练1 个 epoch 验证将交替运行。
**注意**:
1. 模型的参数在验证的阶段不会被自动更新。
2. 配置文件里的关键词 `total_epochs` 仅控制训练的 epochs 数目,而不会影响验证时的工作流。
3. 工作流 `[('train', 1), ('val', 1)]``[('train', 1)]` 将不会改变 `EvalHook` 的行为,因为 `EvalHook``after_train_epoch`
调用而且验证的工作流仅仅影响通过调用 `after_val_epoch` 的钩子 (hooks)。因此, `[('train', 1), ('val', 1)]``[('train', 1)]`
的区别仅在于 runner 将在每次训练 epoch 结束后计算在验证集上的损失。
## 自定义钩 (hooks)
### 使用 MMCV 实现的钩子 (hooks)
如果钩子已经在 MMCV 里被实现,如下所示,您可以直接修改配置文件来使用钩子:
```python
custom_hooks = [
dict(type='MyHook', a=a_value, b=b_value, priority='NORMAL')
]
```
### 修改默认的运行时间钩子 (runtime hooks)
以下的常用的钩子没有被 `custom_hooks` 注册:
- log_config
- checkpoint_config
- evaluation
- lr_config
- optimizer_config
- momentum_config
在这些钩子里,只有 logger hook 有 `VERY_LOW` 优先级,其他的优先级都是 `NORMAL`
上述提及的教程已经包括了如何修改 `optimizer_config``momentum_config``lr_config`
这里我们展示我们如何处理 `log_config` `checkpoint_config``evaluation`
#### 检查点配置文件 (Checkpoint config)
MMCV runner 将使用 `checkpoint_config` 去初始化 [`CheckpointHook`](https://github.com/open-mmlab/mmcv/blob/9ecd6b0d5ff9d2172c49a182eaa669e9f27bb8e7/mmcv/runner/hooks/checkpoint.py#L9).
```python
checkpoint_config = dict(interval=1)
```
使用者可以设置 `max_keep_ckpts` 来仅保存一小部分检查点或者通过 `save_optimizer` 来决定是否保存优化器的状态字典 (state dict of optimizer)。 更多使用参数的细节请参考 [这里](https://mmcv.readthedocs.io/en/latest/api.html#mmcv.runner.CheckpointHook) 。
#### 日志配置文件 (Log config)
`log_config` 包裹了许多日志钩 (logger hooks) 而且能去设置间隔 (intervals)。现在 MMCV 支持 `WandbLoggerHook` `MlflowLoggerHook``TensorboardLoggerHook`
详细的使用请参照 [文档](https://mmcv.readthedocs.io/en/latest/api.html#mmcv.runner.LoggerHook) 。
```python
log_config = dict(
interval=50,
hooks=[
dict(type='TextLoggerHook'),
dict(type='TensorboardLoggerHook')
])
```
#### 评估配置文件 (Evaluation config)
`evaluation` 的配置文件将被用来初始化 [`EvalHook`](https://github.com/open-mmlab/mmsegmentation/blob/e3f6f655d69b777341aec2fe8829871cc0beadcb/mmseg/core/evaluation/eval_hooks.py#L7) 。
除了 `interval` 键,其他的像 `metric` 这样的参数将被传递给 `dataset.evaluate()`
```python
evaluation = dict(interval=1, metric='mIoU')
```

View File

@ -0,0 +1,166 @@
# 教程 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']),
]
```

View File

@ -0,0 +1,9 @@
.. toctree::
:maxdepth: 2
config.md
customize_datasets.md
data_pipeline.md
customize_models.md
training_tricks.md
customize_runtime.md

View File

@ -0,0 +1,51 @@
# 教程 5: 训练技巧
MMSegmentation 支持如下训练技巧:
## 主干网络和解码头组件使用不同的学习率 (Learning Rate, LR)
在语义分割里,一些方法会让解码头组件的学习率大于主干网络的学习率,这样可以获得更好的表现或更快的收敛。
在 MMSegmentation 里面您也可以在配置文件里添加如下行来让解码头组件的学习率是主干组件的10倍。
```python
optimizer=dict(
paramwise_cfg = dict(
custom_keys={
'head': dict(lr_mult=10.)}))
```
通过这种修改,任何被分组到 `'head'` 的参数的学习率都将乘以10。您也可以参照 [MMCV 文档](https://mmcv.readthedocs.io/en/latest/api.html#mmcv.runner.DefaultOptimizerConstructor) 获取更详细的信息。
## 在线难样本挖掘 (Online Hard Example Mining, OHEM)
对于训练时采样,我们在 [这里](https://github.com/open-mmlab/mmsegmentation/tree/master/mmseg/core/seg/sampler) 做了像素采样器。
如下例子是使用 PSPNet 训练并采用 OHEM 策略的配置:
```python
_base_ = './pspnet_r50-d8_512x1024_40k_cityscapes.py'
model=dict(
decode_head=dict(
sampler=dict(type='OHEMPixelSampler', thresh=0.7, min_kept=100000)) )
```
通过这种方式只有置信分数在0.7以下的像素值点会被拿来训练。在训练时我们至少要保留100000个像素值点。如果 `thresh` 并未被指定,前 ``min_kept``
个损失的像素值点才会被选择。
## 类别平衡损失 (Class Balanced Loss)
对于不平衡类别分布的数据集,您也许可以改变每个类别的损失权重。这里以 cityscapes 数据集为例:
```python
_base_ = './pspnet_r50-d8_512x1024_40k_cityscapes.py'
model=dict(
decode_head=dict(
loss_decode=dict(
type='CrossEntropyLoss', use_sigmoid=False, loss_weight=1.0,
# DeepLab 对 cityscapes 使用这种权重
class_weight=[0.8373, 0.9180, 0.8660, 1.0345, 1.0166, 0.9969, 0.9754,
1.0489, 0.8786, 1.0023, 0.9539, 0.9843, 1.1116, 0.9037,
1.0865, 1.0955, 1.0865, 1.1529, 1.0507])))
```
`class_weight` 将被作为 `weight` 参数,传递给 `CrossEntropyLoss`。详细信息请参照 [PyTorch 文档](https://pytorch.org/docs/stable/nn.html?highlight=crossentropy#torch.nn.CrossEntropyLoss) 。

260
docs_zh-CN/useful_tools.md Normal file
View File

@ -0,0 +1,260 @@
## 常用工具
除了训练和测试的脚本,我们在 `tools/` 文件夹路径下还提供许多有用的工具。
### 计算参数量params和计算量 FLOPs (试验性)
我们基于 [flops-counter.pytorch](https://github.com/sovrasov/flops-counter.pytorch)
提供了一个用于计算给定模型参数量和计算量的脚本。
```shell
python tools/get_flops.py ${CONFIG_FILE} [--shape ${INPUT_SHAPE}]
```
您将得到如下的结果:
```none
==============================
Input shape: (3, 2048, 1024)
Flops: 1429.68 GMac
Params: 48.98 M
==============================
```
**注意**: 这个工具仍然是试验性的,我们无法保证数字是正确的。您可以拿这些结果做简单的实验的对照,在写技术文档报告或者论文前您需要再次确认一下。
(1) 计算量与输入的形状有关,而参数量与输入的形状无关,默认的输入形状是 (1, 3, 1280, 800)
(2) 一些运算操作,如 GN 和其他定制的运算操作没有加入到计算量的计算中。
### 发布模型
在您上传一个模型到云服务器之前,您需要做以下几步:
(1) 将模型权重转成 CPU 张量;
(2) 删除记录优化器状态 (optimizer states)的相关信息;
(3) 计算检查点文件 (checkpoint file) 的哈希编码hash id并且将哈希编码加到文件名中。
```shell
python tools/publish_model.py ${INPUT_FILENAME} ${OUTPUT_FILENAME}
```
例如,
```shell
python tools/publish_model.py work_dirs/pspnet/latest.pth psp_r50_hszhao_200ep.pth
```
最终输出文件将是 `psp_r50_512x1024_40ki_cityscapes-{hash id}.pth`.
### 导出 ONNX (试验性)
我们提供了一个脚本来导出模型到 [ONNX](https://github.com/onnx/onnx) 格式。被转换的模型可以通过工具 [Netron](https://github.com/lutzroeder/netron)
来可视化。除此以外,我们同样支持对 PyTorch 和 ONNX 模型的输出结果做对比。
```bash
python tools/pytorch2onnx.py \
${CONFIG_FILE} \
--checkpoint ${CHECKPOINT_FILE} \
--output-file ${ONNX_FILE} \
--input-img ${INPUT_IMG} \
--shape ${INPUT_SHAPE} \
--rescale-shape ${RESCALE_SHAPE} \
--show \
--verify \
--dynamic-export \
--cfg-options \
model.test_cfg.mode="whole"
```
各个参数的描述:
- `config` : 模型配置文件的路径。
- `--checkpoint` : 模型检查点文件的路径。
- `--output-file`: 输出的 ONNX 模型的路径。如果没有专门指定,它默认是 `tmp.onnx`
- `--input-img` : 用来转换和可视化的一张输入图像的路径。
- `--shape`: 模型的输入张量的高和宽。如果没有专门指定,它将被设置成 `test_pipeline``img_scale`
- `--rescale-shape`: 改变输出的形状。设置这个值来避免 OOM它仅在 `slide` 模式下可以用。
- `--show`: 是否打印输出模型的结构。如果没有被专门指定,它将被设置成 `False`
- `--verify`: 是否验证一个输出模型的正确性 (correctness)。如果没有被专门指定,它将被设置成 `False`
- `--dynamic-export`: 是否导出形状变化的输入与输出的 ONNX 模型。如果没有被专门指定,它将被设置成 `False`
- `--cfg-options`: 更新配置选项。
**注意**: 这个工具仍然是试验性的,目前一些自定义操作还没有被支持。
### 评估 ONNX 模型
我们提供 `tools/deploy_test.py` 去评估不同后端的 ONNX 模型。
#### 先决条件
- 安装 onnx 和 onnxruntime-gpu
```shell
pip install onnx onnxruntime-gpu
```
- 参考 [如何在 MMCV 里构建 tensorrt 插件](https://mmcv.readthedocs.io/en/latest/tensorrt_plugin.html#how-to-build-tensorrt-plugins-in-mmcv) 安装TensorRT (可选)。
#### 使用方法
```bash
python tools/deploy_test.py \
${CONFIG_FILE} \
${MODEL_FILE} \
${BACKEND} \
--out ${OUTPUT_FILE} \
--eval ${EVALUATION_METRICS} \
--show \
--show-dir ${SHOW_DIRECTORY} \
--options ${CFG_OPTIONS} \
--eval-options ${EVALUATION_OPTIONS} \
--opacity ${OPACITY} \
```
各个参数的描述:
- `config`: 模型配置文件的路径。
- `model`: 被转换的模型文件的路径。
- `backend`: 推理的后端,可选项:`onnxruntime` `tensorrt`
- `--out`: 输出结果成 pickle 格式文件的路径。
- `--format-only` : 不评估直接给输出结果的格式。通常用在当您想把结果输出成一些测试服务器需要的特定格式时。如果没有被专门指定,它将被设置成 `False`。 注意这个参数是用 `--eval` 来 **手动添加**
- `--eval`: 评估指标,取决于每个数据集的要求,例如 "mIoU" 是大多数据集的指标而 "cityscapes" 仅针对 Cityscapes 数据集。注意这个参数是用 `--format-only`**手动添加**
- `--show`: 是否展示结果
- `--show-dir`: 涂上结果的图像被保存的文件夹的路径。
- `--options`: 重写配置文件里的一些设置。`xxx=yyy` 格式的键值对将被覆盖到配置文件里。
- `--eval-options`: 自定义的评估的选项。 `xxx=yyy` 格式的键值对将成为 `dataset.evaluate()` 函数的参数变量。
- `--opacity`: 涂上结果的分割图的透明度。范围在 (0, 1] 之间。
#### 结果和模型
| 模型 | 配置文件 | 数据集 | 评价指标 | PyTorch | ONNX 运行时间 | TensorRT-fp32 | TensorRT-fp16 |
| :--------: | :---------------------------------------------: | :--------: | :----: | :-----: | :---------: | :-----------: | :-----------: |
| FCN | fcn_r50-d8_512x1024_40k_cityscapes.py | cityscapes | mIoU | 72.2 | 72.2 | 72.2 | 72.2 |
| PSPNet | pspnet_r50-d8_512x1024_40k_cityscapes.py | cityscapes | mIoU | 77.8 | 77.8 | 77.8 | 77.8 |
| deeplabv3 | deeplabv3_r50-d8_512x1024_40k_cityscapes.py | cityscapes | mIoU | 79.0 | 79.0 | 79.0 | 79.0 |
| deeplabv3+ | deeplabv3plus_r50-d8_512x1024_40k_cityscapes.py | cityscapes | mIoU | 79.6 | 79.5 | 79.5 | 79.5 |
| PSPNet | pspnet_r50-d8_769x769_40k_cityscapes.py | cityscapes | mIoU | 78.2 | 78.1 | | |
| deeplabv3 | deeplabv3_r50-d8_769x769_40k_cityscapes.py | cityscapes | mIoU | 78.5 | 78.3 | | |
| deeplabv3+ | deeplabv3plus_r50-d8_769x769_40k_cityscapes.py | cityscapes | mIoU | 78.9 | 78.7 | | |
**注意**: TensorRT 仅在使用 `whole mode` 测试模式时的配置文件里可用。
### 导出 TorchScript (试验性)
我们同样提供一个脚本去把模型导出成 [TorchScript](https://pytorch.org/docs/stable/jit.html) 格式。您可以使用 pytorch C++ API [LibTorch](https://pytorch.org/docs/stable/cpp_index.html) 去推理训练好的模型。
被转换的模型能被像 [Netron](https://github.com/lutzroeder/netron) 的工具来可视化。此外,我们还支持 PyTorch 和 TorchScript 模型的输出结果的比较。
```shell
python tools/pytorch2torchscript.py \
${CONFIG_FILE} \
--checkpoint ${CHECKPOINT_FILE} \
--output-file ${ONNX_FILE}
--shape ${INPUT_SHAPE}
--verify \
--show
```
各个参数的描述:
- `config` : pytorch 模型的配置文件的路径。
- `--checkpoint` : pytorch 模型的检查点文件的路径。
- `--output-file`: TorchScript 模型输出的路径。 如果没有被专门指定,它将被设置成 `tmp.pt`
- `--input-img` : 用来转换和可视化的输入图像的路径。
- `--shape`: 模型的输入张量的宽和高。如果没有被专门指定,它将被设置成 `512 512`
- `--show`: 是否打印输出模型的追踪图 (traced graph)。如果没有被专门指定,它将被设置成 `False`
- `--verify`: 是否验证一个输出模型的正确性 (correctness)。如果没有被专门指定,它将被设置成 `False`
**注意**: 目前仅支持 PyTorch>=1.8.0 版本.
**注意**: 这个工具仍然是试验性的,一些自定义操作符目前还不被支持。
例子:
- 导出 PSPNet 在 cityscapes 数据集上的 pytorch 模型。
```shell
python tools/pytorch2torchscript.py configs/pspnet/pspnet_r50-d8_512x1024_40k_cityscapes.py \
--checkpoint checkpoints/pspnet_r50-d8_512x1024_40k_cityscapes_20200605_003338-2966598c.pth \
--output-file checkpoints/pspnet_r50-d8_512x1024_40k_cityscapes_20200605_003338-2966598c.pt \
--shape 512 1024
```
### 导出 TensorRT (试验性)
一个导出 [ONNX](https://github.com/onnx/onnx) 模型成 [TensorRT](https://developer.nvidia.com/tensorrt) 格式的脚本。
先决条件
- 按照 [ONNXRuntime in mmcv](https://mmcv.readthedocs.io/en/latest/onnxruntime_op.html) 和 [TensorRT plugin in mmcv](https://github.com/open-mmlab/mmcv/blob/master/docs/tensorrt_plugin.md) ,用 ONNXRuntime 自定义运算 (custom ops) 和 TensorRT 插件安装 `mmcv-full`
- 使用 [pytorch2onnx](#convert-to-onnx-experimental) 将模型从 PyTorch 转成 ONNX。
使用方法
```bash
python ${MMSEG_PATH}/tools/onnx2tensorrt.py \
${CFG_PATH} \
${ONNX_PATH} \
--trt-file ${OUTPUT_TRT_PATH} \
--min-shape ${MIN_SHAPE} \
--max-shape ${MAX_SHAPE} \
--input-img ${INPUT_IMG} \
--show \
--verify
```
各个参数的描述:
- `config` : 模型的配置文件。
- `model` : 输入的 ONNX 模型的路径。
- `--trt-file` : 输出的 TensorRT 引擎的路径。
- `--max-shape` : 模型的输入的最大形状。
- `--min-shape` : 模型的输入的最小形状。
- `--fp16` : 做 fp16 模型转换。
- `--workspace-size` : 在 GiB 里的最大工作空间大小 (Max workspace size)。
- `--input-img` : 用来可视化的图像。
- `--show` : 做结果的可视化。
- `--dataset` : Palette provider, 默认为 `CityscapesDataset`
- `--verify` : 验证 ONNXRuntime 和 TensorRT 的输出。
- `--verbose` : 当创建 TensorRT 引擎时,是否详细做信息日志。默认为 False。
**注意**: 仅在全图测试模式 (whole mode) 下测试过。
## 其他内容
### 打印完整的配置文件
`tools/print_config.py` 会逐字逐句的打印整个配置文件,展开所有的导入。
```shell
python tools/print_config.py \
${CONFIG} \
--graph \
--options ${OPTIONS [OPTIONS...]} \
```
各个参数的描述:
- `config` : pytorch 模型的配置文件的路径。
- `--graph` : 是否打印模型的图 (models graph)。
- `--options`: 自定义替换配置文件的选项。
### 对训练日志 (training logs) 画图
`tools/analyze_logs.py` 会画出给定的训练日志文件的 loss/mIoU 曲线,首先需要 `pip install seaborn` 安装依赖包。
```shell
python tools/analyze_logs.py xxx.log.json [--keys ${KEYS}] [--legend ${LEGEND}] [--backend ${BACKEND}] [--style ${STYLE}] [--out ${OUT_FILE}]
```
示例:
- 对 mIoU, mAcc, aAcc 指标画图。
```shell
python tools/analyze_logs.py log.json --keys mIoU mAcc aAcc --legend mIoU mAcc aAcc
```
- 对 loss 指标画图。
```shell
python tools/analyze_logs.py log.json --keys loss --legend loss
```