Commit 0fd8347d authored by unknown's avatar unknown
Browse files

添加mmclassification-0.24.1代码,删除mmclassification-speed-benchmark

parent cc567e9e
# NPU (华为昇腾)
## 使用方法
首先,请参考 {external+mmcv:doc}`教程 <get_started/build>` 安装带有 NPU 支持的 MMCV。
使用如下命令,可以利用 8 个 NPU 在机器上训练模型(以 ResNet 为例):
```shell
bash tools/dist_train.sh configs/cspnet/resnet50_8xb32_in1k.py 8 --device npu
```
或者,使用如下命令,在一个 NPU 上训练模型(以 ResNet 为例):
```shell
python tools/train.py configs/cspnet/resnet50_8xb32_in1k.py --device npu
```
## 经过验证的模型
| 模型 | Top-1 (%) | Top-5 (%) | 配置文件 | 相关下载 |
| :--------------------------------------------------------: | :-------: | :-------: | :------------------------------------------------------------: | :------------------------------------------------------------: |
| [CSPResNeXt50](../papers/cspnet.md) | 77.10 | 93.55 | [config](https://github.com/open-mmlab/mmclassification/blob/master/configs/cspnet/cspresnext50_8xb32_in1k.py) | [model](<>) \| [log](https://download.openmmlab.com/mmclassification/v0/device/npu/cspresnext50_8xb32_in1k.log.json) |
| [DenseNet121](../papers/densenet.md) | 72.62 | 91.04 | [config](https://github.com/open-mmlab/mmclassification/blob/master/configs/densenet/densenet121_4xb256_in1k.py) | [model](<>) \| [log](https://download.openmmlab.com/mmclassification/v0/device/npu/densenet121_4xb256_in1k.log.json) |
| [EfficientNet-B4(AA + AdvProp)](../papers/efficientnet.md) | 75.55 | 92.86 | [config](https://github.com/open-mmlab/mmclassification/blob/master/configs/efficientnet/efficientnet-b4_8xb32-01norm_in1k.py) | [model](<>) \| [log](https://download.openmmlab.com/mmclassification/v0/device/npu/efficientnet-b4_8xb32-01norm_in1k.log.json) |
| [HRNet-W18](../papers/hrnet.md) | 77.01 | 93.46 | [config](https://github.com/open-mmlab/mmclassification/blob/master/configs/hrnet/hrnet-w18_4xb32_in1k.py) | [model](<>) \| [log](https://download.openmmlab.com/mmclassification/v0/device/npu/hrnet-w18_4xb32_in1k.log.json) |
| [ResNetV1D-152](../papers/resnet.md) | 77.11 | 94.54 | [config](https://github.com/open-mmlab/mmclassification/blob/master/configs/resnet/resnetv1d152_8xb32_in1k.py) | [model](<>) \| [log](<>) |
| [ResNet-50](../papers/resnet.md) | 76.40 | - | [config](https://github.com/open-mmlab/mmclassification/blob/master/configs/resnet/resnet50_8xb32_in1k.py) | [model](<>) \| [log](<>) |
| [ResNetXt-32x4d-50](../papers/resnext.md) | 77.55 | 93.75 | [config](https://github.com/open-mmlab/mmclassification/blob/master/configs/resnext/resnext50-32x4d_8xb32_in1k.py) | [model](<>) \| [log](https://download.openmmlab.com/mmclassification/v0/device/npu/resnext50-32x4d_8xb32_in1k.log.json) |
| [SE-ResNet-50](../papers/seresnet.md) | 77.64 | 93.76 | [config](https://github.com/open-mmlab/mmclassification/blob/master/configs/seresnet/seresnet50_8xb32_in1k.py) | [model](<>) \| [log](https://download.openmmlab.com/mmclassification/v0/device/npu/seresnet50_8xb32_in1k.log.json) |
| [VGG-11](../papers/vgg.md) | 68.92 | 88.83 | [config](https://github.com/open-mmlab/mmclassification/blob/master/configs/vgg/vgg11_8xb32_in1k.py) | [model](<>) \| [log](https://download.openmmlab.com/mmclassification/v0/device/npu/vgg11_8xb32_in1k.log.json) |
| [ShuffleNetV2 1.0x](../papers/shufflenet_v2.md) | 69.53 | 88.82 | [config](https://github.com/open-mmlab/mmclassification/blob/master/configs/shufflenet_v2/shufflenet-v2-1x_16xb64_in1k.py) | [model](<>) \| [log](<>) |
**以上所有模型权重及训练日志均由华为昇腾团队提供**
# 常见问题
我们在这里列出了一些常见问题及其相应的解决方案。如果您发现任何常见问题并有方法
帮助解决,欢迎随时丰富列表。如果这里的内容没有涵盖您的问题,请按照
[提问模板](https://github.com/open-mmlab/mmclassification/issues/new/choose)
在 GitHub 上提出问题,并补充模板中需要的信息。
## 安装
- MMCV 与 MMClassification 的兼容问题。如遇到
"AssertionError: MMCV==xxx is used but incompatible. Please install mmcv>=xxx, \<=xxx."
这里我们列举了各版本 MMClassification 对 MMCV 版本的依赖,请选择合适的 MMCV
版本来避免安装和使用中的问题。
| MMClassification version | MMCV version |
| :----------------------: | :--------------------: |
| dev | mmcv>=1.7.0, \<1.9.0 |
| 0.24.1 (master) | mmcv>=1.4.2, \<1.9.0 |
| 0.23.2 | mmcv>=1.4.2, \<1.7.0 |
| 0.22.1 | mmcv>=1.4.2, \<1.6.0 |
| 0.21.0 | mmcv>=1.4.2, \<=1.5.0 |
| 0.20.1 | mmcv>=1.4.2, \<=1.5.0 |
| 0.19.0 | mmcv>=1.3.16, \<=1.5.0 |
| 0.18.0 | mmcv>=1.3.16, \<=1.5.0 |
| 0.17.0 | mmcv>=1.3.8, \<=1.5.0 |
| 0.16.0 | mmcv>=1.3.8, \<=1.5.0 |
| 0.15.0 | mmcv>=1.3.8, \<=1.5.0 |
| 0.15.0 | mmcv>=1.3.8, \<=1.5.0 |
| 0.14.0 | mmcv>=1.3.8, \<=1.5.0 |
| 0.13.0 | mmcv>=1.3.8, \<=1.5.0 |
| 0.12.0 | mmcv>=1.3.1, \<=1.5.0 |
| 0.11.1 | mmcv>=1.3.1, \<=1.5.0 |
| 0.11.0 | mmcv>=1.3.0 |
| 0.10.0 | mmcv>=1.3.0 |
| 0.9.0 | mmcv>=1.1.4 |
| 0.8.0 | mmcv>=1.1.4 |
| 0.7.0 | mmcv>=1.1.4 |
| 0.6.0 | mmcv>=1.1.4 |
```{note}
由于 `dev` 分支处于频繁开发中,MMCV 版本依赖可能不准确。如果您在使用
`dev` 分支时遇到问题,请尝试更新 MMCV 到最新版。
```
- 使用 Albumentations
如果你希望使用 `albumentations` 相关的功能,我们建议使用 `pip install -r requirements/optional.txt` 或者
`pip install -U albumentations>=0.3.2 --no-binary qudida,albumentations` 命令进行安装。
如果你直接使用 `pip install albumentations>=0.3.2` 来安装,它会同时安装 `opencv-python-headless`
(即使你已经安装了 `opencv-python`)。具体细节可参阅
[官方文档](https://albumentations.ai/docs/getting_started/installation/#note-on-opencv-dependencies)
## 开发
- 如果我对源码进行了改动,需要重新安装以使改动生效吗?
如果你遵照[最佳实践](install.md)的指引,从源码安装 mmcls,那么任何本地修改都不需要重新安装即可生效。
- 如何在多个 MMClassification 版本下进行开发?
通常来说,我们推荐通过不同虚拟环境来管理多个开发目录下的 MMClassification。
但如果你希望在不同目录(如 mmcls-0.21, mmcls-0.23 等)使用同一个环境进行开发,
我们提供的训练和测试 shell 脚本会自动使用当前目录的 mmcls,其他 Python 脚本
则可以在命令前添加 `` PYTHONPATH=`pwd` `` 来使用当前目录的代码。
反过来,如果你希望 shell 脚本使用环境中安装的 MMClassification,而不是当前目录的,
则可以去掉 shell 脚本中如下一行代码:
```shell
PYTHONPATH="$(dirname $0)/..":$PYTHONPATH
```
# 基础教程
本文档提供 MMClassification 相关用法的基本教程。
## 准备数据集
MMClassification 建议用户将数据集根目录链接到 `$MMCLASSIFICATION/data` 下。
如果用户的文件夹结构与默认结构不同,则需要在配置文件中进行对应路径的修改。
```
mmclassification
├── mmcls
├── tools
├── configs
├── docs
├── data
│ ├── imagenet
│ │ ├── meta
│ │ ├── train
│ │ ├── val
│ ├── cifar
│ │ ├── cifar-10-batches-py
│ ├── mnist
│ │ ├── train-images-idx3-ubyte
│ │ ├── train-labels-idx1-ubyte
│ │ ├── t10k-images-idx3-ubyte
│ │ ├── t10k-labels-idx1-ubyte
```
对于 ImageNet,其存在多个版本,但最为常用的一个是 [ILSVRC 2012](http://www.image-net.org/challenges/LSVRC/2012/),可以通过以下步骤获取该数据集。
1. 注册账号并登录 [下载页面](http://www.image-net.org/download-images)
2. 获取 ILSVRC2012 下载链接并下载以下文件
- ILSVRC2012_img_train.tar (~138GB)
- ILSVRC2012_img_val.tar (~6.3GB)
3. 解压下载的文件
4. 使用 [该脚本](https://github.com/BVLC/caffe/blob/master/data/ilsvrc12/get_ilsvrc_aux.sh) 获取元数据
对于 MNIST,CIFAR10 和 CIFAR100,程序将会在需要的时候自动下载数据集。
对于用户自定义数据集的准备,请参阅 [教程 3:如何自定义数据集
](tutorials/new_dataset.md)
## 使用预训练模型进行推理
MMClassification 提供了一些脚本用于进行单张图像的推理、数据集的推理和数据集的测试(如 ImageNet 等)
### 单张图像的推理
```shell
python demo/image_demo.py ${IMAGE_FILE} ${CONFIG_FILE} ${CHECKPOINT_FILE}
# Example
python demo/image_demo.py demo/demo.JPEG configs/resnet/resnet50_8xb32_in1k.py \
https://download.openmmlab.com/mmclassification/v0/resnet/resnet50_8xb32_in1k_20210831-ea4938fc.pth
```
### 数据集的推理与测试
- 支持单 GPU
- 支持 CPU
- 支持单节点多 GPU
- 支持多节点
用户可使用以下命令进行数据集的推理:
```shell
# 单 GPU
python tools/test.py ${CONFIG_FILE} ${CHECKPOINT_FILE} [--metrics ${METRICS}] [--out ${RESULT_FILE}]
# CPU: 禁用 GPU 并运行单 GPU 测试脚本
export CUDA_VISIBLE_DEVICES=-1
python tools/test.py ${CONFIG_FILE} ${CHECKPOINT_FILE} [--metrics ${METRICS}] [--out ${RESULT_FILE}]
# 多 GPU
./tools/dist_test.sh ${CONFIG_FILE} ${CHECKPOINT_FILE} ${GPU_NUM} [--metrics ${METRICS}] [--out ${RESULT_FILE}]
# 基于 slurm 分布式环境的多节点
python tools/test.py ${CONFIG_FILE} ${CHECKPOINT_FILE} [--metrics ${METRICS}] [--out ${RESULT_FILE}] --launcher slurm
```
可选参数:
- `RESULT_FILE`:输出结果的文件名。如果未指定,结果将不会保存到文件中。支持 json, yaml, pickle 格式。
- `METRICS`:数据集测试指标,如准确率 (accuracy), 精确率 (precision), 召回率 (recall) 等
例子:
在 ImageNet 验证集上,使用 ResNet-50 进行推理并获得预测标签及其对应的预测得分。
```shell
python tools/test.py configs/resnet/resnet50_8xb16_cifar10.py \
https://download.openmmlab.com/mmclassification/v0/resnet/resnet50_b16x8_cifar10_20210528-f54bfad9.pth \
--out result.pkl
```
## 模型训练
MMClassification 使用 `MMDistributedDataParallel` 进行分布式训练,使用 `MMDataParallel` 进行非分布式训练。
所有的输出(日志文件和模型权重文件)会被将保存到工作目录下。工作目录通过配置文件中的参数 `work_dir` 指定。
默认情况下,MMClassification 在每个周期后会在验证集上评估模型,可以通过在训练配置中修改 `interval` 参数来更改评估间隔
```python
evaluation = dict(interval=12) # 每进行 12 轮训练后评估一次模型
```
### 使用单个 GPU 进行训练
```shell
python tools/train.py ${CONFIG_FILE} [optional arguments]
```
如果用户想在命令中指定工作目录,则需要增加参数 `--work-dir ${YOUR_WORK_DIR}`
### 使用 CPU 训练
使用 CPU 训练的流程和使用单 GPU 训练的流程一致,我们仅需要在训练流程开始前禁用 GPU。
```shell
export CUDA_VISIBLE_DEVICES=-1
```
之后运行单 GPU 训练脚本即可。
```{warning}
我们不推荐用户使用 CPU 进行训练,这太过缓慢。我们支持这个功能是为了方便用户在没有 GPU 的机器上进行调试。
```
### 使用单台机器多个 GPU 进行训练
```shell
./tools/dist_train.sh ${CONFIG_FILE} ${GPU_NUM} [optional arguments]
```
可选参数为:
- `--no-validate` (**不建议**): 默认情况下,程序将会在训练期间的每 k (默认为 1) 个周期进行一次验证。要禁用这一功能,使用 `--no-validate`
- `--work-dir ${WORK_DIR}`:覆盖配置文件中指定的工作目录。
- `--resume-from ${CHECKPOINT_FILE}`:从以前的模型权重文件恢复训练。
`resume-from``load-from` 的不同点:
`resume-from` 加载模型参数和优化器状态,并且保留检查点所在的周期数,常被用于恢复意外被中断的训练。
`load-from` 只加载模型参数,但周期数从 0 开始计数,常被用于微调模型。
### 使用多台机器进行训练
如果您想使用由 ethernet 连接起来的多台机器, 您可以使用以下命令:
在第一台机器上:
```shell
NNODES=2 NODE_RANK=0 PORT=$MASTER_PORT MASTER_ADDR=$MASTER_ADDR sh tools/dist_train.sh $CONFIG $GPUS
```
在第二台机器上:
```shell
NNODES=2 NODE_RANK=1 PORT=$MASTER_PORT MASTER_ADDR=$MASTER_ADDR sh tools/dist_train.sh $CONFIG $GPUS
```
但是,如果您不使用高速网路连接这几台机器的话,训练将会非常慢。
如果用户在 [slurm](https://slurm.schedmd.com/) 集群上运行 MMClassification,可使用 `slurm_train.sh` 脚本。(该脚本也支持单台机器上进行训练)
```shell
[GPUS=${GPUS}] ./tools/slurm_train.sh ${PARTITION} ${JOB_NAME} ${CONFIG_FILE} ${WORK_DIR}
```
用户可以在 [slurm_train.sh](https://github.com/open-mmlab/mmclassification/blob/master/tools/slurm_train.sh) 中检查所有的参数和环境变量
如果用户的多台机器通过 Ethernet 连接,则可以参考 pytorch [launch utility](https://pytorch.org/docs/stable/distributed.html#launch-utility)。如果用户没有高速网络,如 InfiniBand,速度将会非常慢。
### 使用单台机器启动多个任务
如果用使用单台机器启动多个任务,如在有 8 块 GPU 的单台机器上启动 2 个需要 4 块 GPU 的训练任务,则需要为每个任务指定不同端口,以避免通信冲突。
如果用户使用 `dist_train.sh` 脚本启动训练任务,则可以通过以下命令指定端口
```shell
CUDA_VISIBLE_DEVICES=0,1,2,3 PORT=29500 ./tools/dist_train.sh ${CONFIG_FILE} 4
CUDA_VISIBLE_DEVICES=4,5,6,7 PORT=29501 ./tools/dist_train.sh ${CONFIG_FILE} 4
```
如果用户在 slurm 集群下启动多个训练任务,则需要修改配置文件中的 `dist_params` 变量,以设置不同的通信端口。
`config1.py` 中,
```python
dist_params = dict(backend='nccl', port=29500)
```
`config2.py` 中,
```python
dist_params = dict(backend='nccl', port=29501)
```
之后便可启动两个任务,分别对应 `config1.py``config2.py`
```shell
CUDA_VISIBLE_DEVICES=0,1,2,3 GPUS=4 ./tools/slurm_train.sh ${PARTITION} ${JOB_NAME} config1.py ${WORK_DIR}
CUDA_VISIBLE_DEVICES=4,5,6,7 GPUS=4 ./tools/slurm_train.sh ${PARTITION} ${JOB_NAME} config2.py ${WORK_DIR}
```
## 实用工具
我们在 `tools/` 目录下提供的一些对训练和测试十分有用的工具
### 计算 FLOPs 和参数量(试验性的)
我们根据 [flops-counter.pytorch](https://github.com/sovrasov/flops-counter.pytorch) 提供了一个脚本用于计算给定模型的 FLOPs 和参数量
```shell
python tools/analysis_tools/get_flops.py ${CONFIG_FILE} [--shape ${INPUT_SHAPE}]
```
用户将获得如下结果:
```
==============================
Input shape: (3, 224, 224)
Flops: 4.12 GFLOPs
Params: 25.56 M
==============================
```
```{warning}
此工具仍处于试验阶段,我们不保证该数字正确无误。您最好将结果用于简单比较,但在技术报告或论文中采用该结果之前,请仔细检查。
- FLOPs 与输入的尺寸有关,而参数量与输入尺寸无关。默认输入尺寸为 (1, 3, 224, 224)
- 一些运算不会被计入 FLOPs 的统计中,例如 GN 和自定义运算。详细信息请参考 [`mmcv.cnn.get_model_complexity_info()`](https://github.com/open-mmlab/mmcv/blob/master/mmcv/cnn/utils/flops_counter.py)
```
### 模型发布
在发布模型之前,你也许会需要
1. 转换模型权重至 CPU 张量
2. 删除优化器状态
3. 计算模型权重文件的哈希值,并添加至文件名之后
```shell
python tools/convert_models/publish_model.py ${INPUT_FILENAME} ${OUTPUT_FILENAME}
```
例如:
```shell
python tools/convert_models/publish_model.py work_dirs/resnet50/latest.pth imagenet_resnet50.pth
```
最终输出的文件名将会是 `imagenet_resnet50_{date}-{hash id}.pth`
## 详细教程
目前,MMClassification 提供以下几种更详细的教程:
- [如何编写配置文件](tutorials/config.md)
- [如何微调模型](tutorials/finetune.md)
- [如何增加新数据集](tutorials/new_dataset.md)
- [如何设计数据处理流程](tutorials/data_pipeline.md)
- [如何增加新模块](tutorials/new_modules.md)
- [如何自定义优化策略](tutorials/schedule.md)
- [如何自定义运行参数](tutorials/runtime.md)。
欢迎来到 MMClassification 中文教程!
==========================================
You can switch between Chinese and English documentation in the lower-left corner of the layout.
您可以在页面左下角切换中英文文档。
.. toctree::
:maxdepth: 1
:caption: 开始你的第一步
install.md
getting_started.md
.. toctree::
:maxdepth: 1
:caption: 教程
tutorials/config.md
tutorials/finetune.md
tutorials/new_dataset.md
tutorials/data_pipeline.md
tutorials/new_modules.md
tutorials/schedule.md
tutorials/runtime.md
.. toctree::
:maxdepth: 1
:caption: 模型库
:glob:
modelzoo_statistics.md
model_zoo.md
papers/*
.. toctree::
:maxdepth: 1
:caption: 实用工具
tools/pytorch2onnx.md
tools/onnx2tensorrt.md
tools/pytorch2torchscript.md
tools/model_serving.md
tools/visualization.md
tools/analysis.md
tools/miscellaneous.md
.. toctree::
:maxdepth: 1
:caption: 社区
community/CONTRIBUTING.md
.. toctree::
:caption: API 参考文档
mmcls.apis <api/apis>
mmcls.core <api/core>
mmcls.models <api/models>
mmcls.models.utils <api/models.utils>
mmcls.datasets <api/datasets>
数据转换 <api/transforms>
批数据增强 <api/models.utils.augment>
mmcls.utils <api/utils>
.. toctree::
:maxdepth: 1
:caption: 其他说明
changelog.md
compatibility.md
faq.md
.. toctree::
:maxdepth: 1
:caption: 设备支持
device/npu.md
.. toctree::
:caption: 语言切换
English <https://mmclassification.readthedocs.io/en/latest/>
简体中文 <https://mmclassification.readthedocs.io/zh_CN/latest/>
索引与表格
==================
* :ref:`genindex`
* :ref:`search`
# 依赖环境
在本节中,我们将演示如何准备 PyTorch 相关的依赖环境。
MMClassification 适用于 Linux、Windows 和 macOS。它需要 Python 3.6+、CUDA 9.2+ 和 PyTorch 1.5+。
```{note}
如果你对配置 PyTorch 环境已经很熟悉,并且已经完成了配置,可以直接进入[下一节](#安装)。
否则的话,请依照以下步骤完成配置。
```
**第 1 步**[官网](https://docs.conda.io/en/latest/miniconda.html)下载并安装 Miniconda。
**第 2 步** 创建一个 conda 虚拟环境并激活它。
```shell
conda create --name openmmlab python=3.8 -y
conda activate openmmlab
```
**第 3 步** 按照[官方指南](https://pytorch.org/get-started/locally/)安装 PyTorch。例如:
在 GPU 平台:
```shell
conda install pytorch torchvision -c pytorch
```
```{warning}
以上命令会自动安装最新版的 PyTorch 与对应的 cudatoolkit,请检查它们是否与你的环境匹配。
```
在 CPU 平台:
```shell
conda install pytorch torchvision cpuonly -c pytorch
```
# 安装
我们推荐用户按照我们的最佳实践来安装 MMClassification。但除此之外,如果你想根据
你的习惯完成安装流程,也可以参见[自定义安装](#自定义安装)一节来获取更多信息。
## 最佳实践
**第 1 步** 使用 [MIM](https://github.com/open-mmlab/mim) 安装 [MMCV](https://github.com/open-mmlab/mmcv)
```shell
pip install -U openmim
mim install mmcv-full
```
**第 2 步** 安装 MMClassification
根据具体需求,我们支持两种安装模式:
- [从源码安装(推荐)](#从源码安装):希望基于 MMClassification 框架开发自己的图像分类任务,需要添加新的功能,比如新的模型或是数据集,或者使用我们提供的各种工具。
- [作为 Python 包安装](#作为-python-包安装):只是希望调用 MMClassification 的 API 接口,或者在自己的项目中导入 MMClassification 中的模块。
### 从源码安装
这种情况下,从源码按如下方式安装 mmcls:
```shell
git clone https://github.com/open-mmlab/mmclassification.git
cd mmclassification
pip install -v -e .
# "-v" 表示输出更多安装相关的信息
# "-e" 表示以可编辑形式安装,这样可以在不重新安装的情况下,让本地修改直接生效
```
另外,如果你希望向 MMClassification 贡献代码,或者使用试验中的功能,请签出到 `dev` 分支。
```shell
git checkout dev
```
### 作为 Python 包安装
直接使用 pip 安装即可。
```shell
pip install mmcls
```
## 验证安装
为了验证 MMClassification 的安装是否正确,我们提供了一些示例代码来执行模型推理。
**第 1 步** 我们需要下载配置文件和模型权重文件
```shell
mim download mmcls --config resnet50_8xb32_in1k --dest .
```
**第 2 步** 验证示例的推理流程
如果你是**从源码安装**的 mmcls,那么直接运行以下命令进行验证:
```shell
python demo/image_demo.py demo/demo.JPEG resnet50_8xb32_in1k.py resnet50_8xb32_in1k_20210831-ea4938fc.pth --device cpu
```
你可以看到命令行中输出了结果字典,包括 `pred_label``pred_score``pred_class` 三个字段。另外如果你拥有图形
界面(而不是使用远程终端),那么可以启用 `--show` 选项,将示例图像和对应的预测结果在窗口中进行显示。
如果你是**作为 PyThon 包安装**,那么可以打开你的 Python 解释器,并粘贴如下代码:
```python
from mmcls.apis import init_model, inference_model
config_file = 'resnet50_8xb32_in1k.py'
checkpoint_file = 'resnet50_8xb32_in1k_20210831-ea4938fc.pth'
model = init_model(config_file, checkpoint_file, device='cpu') # 或者 device='cuda:0'
inference_model(model, 'demo/demo.JPEG')
```
你会看到输出一个字典,包含预测的标签、得分及类别名。
## 自定义安装
### CUDA 版本
安装 PyTorch 时,需要指定 CUDA 版本。如果您不清楚选择哪个,请遵循我们的建议:
- 对于 Ampere 架构的 NVIDIA GPU,例如 GeForce 30 series 以及 NVIDIA A100,CUDA 11 是必需的。
- 对于更早的 NVIDIA GPU,CUDA 11 是向前兼容的,但 CUDA 10.2 能够提供更好的兼容性,也更加轻量。
请确保你的 GPU 驱动版本满足最低的版本需求,参阅[这张表](https://docs.nvidia.com/cuda/cuda-toolkit-release-notes/index.html#cuda-major-component-versions__table-cuda-toolkit-driver-versions)
```{note}
如果按照我们的最佳实践进行安装,CUDA 运行时库就足够了,因为我们提供相关 CUDA 代码的预编译,你不需要进行本地编译。
但如果你希望从源码进行 MMCV 的编译,或是进行其他 CUDA 算子的开发,那么就必须安装完整的 CUDA 工具链,参见
[NVIDIA 官网](https://developer.nvidia.com/cuda-downloads),另外还需要确保该 CUDA 工具链的版本与 PyTorch 安装时
的配置相匹配(如用 `conda install` 安装 PyTorch 时指定的 cudatoolkit 版本)。
```
### 不使用 MIM 安装 MMCV
MMCV 包含 C++ 和 CUDA 扩展,因此其对 PyTorch 的依赖比较复杂。MIM 会自动解析这些
依赖,选择合适的 MMCV 预编译包,使安装更简单,但它并不是必需的。
要使用 pip 而不是 MIM 来安装 MMCV,请遵照 [MMCV 安装指南](https://mmcv.readthedocs.io/zh_CN/latest/get_started/installation.html)
它需要你用指定 url 的形式手动指定对应的 PyTorch 和 CUDA 版本。
举个例子,如下命令将会安装基于 PyTorch 1.10.x 和 CUDA 11.3 编译的 mmcv-full。
```shell
pip install mmcv-full -f https://download.openmmlab.com/mmcv/dist/cu113/torch1.10/index.html
```
### 在 CPU 环境中安装
MMClassification 可以仅在 CPU 环境中安装,在 CPU 模式下,你可以完成训练(需要 MMCV 版本 >= 1.4.4)、测试和模型推理等所有操作。
在 CPU 模式下,MMCV 的部分功能将不可用,通常是一些 GPU 编译的算子。不过不用担心,
MMClassification 中几乎所有的模型都不会依赖这些算子。
### 在 Google Colab 中安装
[Google Colab](https://research.google.com/) 通常已经包含了 PyTorch 环境,因此我们只需要安装 MMCV 和 MMClassification 即可,命令如下:
**第 1 步** 使用 [MIM](https://github.com/open-mmlab/mim) 安装 [MMCV](https://github.com/open-mmlab/mmcv)
```shell
!pip3 install openmim
!mim install mmcv-full
```
**第 2 步** 从源码安装 MMClassification
```shell
!git clone https://github.com/open-mmlab/mmclassification.git
%cd mmclassification
!pip install -e .
```
**第 3 步** 验证
```python
import mmcls
print(mmcls.__version__)
# 预期输出: 0.23.0 或更新的版本号
```
```{note}
在 Jupyter 中,感叹号 `!` 用于执行外部命令,而 `%cd` 是一个[魔术命令](https://ipython.readthedocs.io/en/stable/interactive/magics.html#magic-cd),用于切换 Python 的工作路径。
```
### 通过 Docker 使用 MMClassification
MMClassification 提供 [Dockerfile](https://github.com/open-mmlab/mmclassification/blob/master/docker/Dockerfile)
用于构建镜像。请确保你的 [Docker 版本](https://docs.docker.com/engine/install/) >=19.03。
```shell
# 构建默认的 PyTorch 1.8.1,CUDA 10.2 版本镜像
# 如果你希望使用其他版本,请修改 Dockerfile
docker build -t mmclassification docker/
```
用以下命令运行 Docker 镜像:
```shell
docker run --gpus all --shm-size=8g -it -v {DATA_DIR}:/mmclassification/data mmclassification
```
## 故障解决
如果你在安装过程中遇到了什么问题,请先查阅[常见问题](faq.md)。如果没有找到解决方法,可以在 GitHub
[提出 issue](https://github.com/open-mmlab/mmclassification/issues/new/choose)
#!/usr/bin/env python
import functools as func
import glob
import os
import re
from pathlib import Path
import numpy as np
MMCLS_ROOT = Path(__file__).absolute().parents[1]
url_prefix = 'https://github.com/open-mmlab/mmclassification/blob/master/'
papers_root = Path('papers')
papers_root.mkdir(exist_ok=True)
files = [Path(f) for f in sorted(glob.glob('../../configs/*/README.md'))]
stats = []
titles = []
num_ckpts = 0
num_configs = 0
for f in files:
with open(f, 'r') as content_file:
content = content_file.read()
# Extract checkpoints
ckpts = set(x.lower().strip()
for x in re.findall(r'\[model\]\((https?.*)\)', content))
if len(ckpts) == 0:
continue
num_ckpts += len(ckpts)
# Extract paper title
match_res = list(re.finditer(r'> \[(.*)\]\((.*)\)', content))
if len(match_res) > 0:
title, paperlink = match_res[0].groups()
else:
title = content.split('\n')[0].replace('# ', '').strip()
paperlink = None
titles.append(title)
# Replace paper link to a button
if paperlink is not None:
start = match_res[0].start()
end = match_res[0].end()
link_button = f'[{title}]({paperlink})'
content = content[:start] + link_button + content[end:]
# Extract paper type
_papertype = [x for x in re.findall(r'\[([A-Z]+)\]', content)]
assert len(_papertype) > 0
papertype = _papertype[0]
paper = set([(papertype, title)])
# Write a copy of README
copy = papers_root / (f.parent.name + '.md')
if copy.exists():
os.remove(copy)
def replace_link(matchobj):
# Replace relative link to GitHub link.
name = matchobj.group(1)
link = matchobj.group(2)
if not link.startswith('http') and (f.parent / link).exists():
rel_link = (f.parent / link).absolute().relative_to(MMCLS_ROOT)
link = url_prefix + str(rel_link)
return f'[{name}]({link})'
content = re.sub(r'\[([^\]]+)\]\(([^)]+)\)', replace_link, content)
with open(copy, 'w') as copy_file:
copy_file.write(content)
statsmsg = f"""
\t* [{papertype}] [{title}]({copy}) ({len(ckpts)} ckpts)
"""
stats.append(dict(paper=paper, ckpts=ckpts, statsmsg=statsmsg, copy=copy))
allpapers = func.reduce(lambda a, b: a.union(b),
[stat['paper'] for stat in stats])
msglist = '\n'.join(stat['statsmsg'] for stat 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)
# 分析
<!-- TOC -->
- [日志分析](#日志分析)
- [绘制曲线图](#绘制曲线图)
- [统计训练时间](#统计训练时间)
- [结果分析](#结果分析)
- [评估结果](#查看典型结果)
- [查看典型结果](#查看典型结果)
- [模型复杂度分析](#模型复杂度分析)
- [常见问题](#常见问题)
<!-- TOC -->
## 日志分析
### 绘制曲线图
指定一个训练日志文件,可通过 `tools/analysis_tools/analyze_logs.py` 脚本绘制指定键值的变化曲线
<div align=center><img src="../_static/image/tools/analysis/analyze_log.jpg" style=" width: 75%; height: 30%; "></div>
```shell
python tools/analysis_tools/analyze_logs.py plot_curve \
${JSON_LOGS} \
[--keys ${KEYS}] \
[--title ${TITLE}] \
[--legend ${LEGEND}] \
[--backend ${BACKEND}] \
[--style ${STYLE}] \
[--out ${OUT_FILE}] \
[--window-size ${WINDOW_SIZE}]
```
所有参数的说明
- `json_logs` :模型配置文件的路径(可同时传入多个,使用空格分开)。
- `--keys` :分析日志的关键字段,数量为 `len(${JSON_LOGS}) * len(${KEYS})` 默认为 'loss'。
- `--title` :分析日志的图片名称,默认使用配置文件名, 默认为空。
- `--legend` :图例名(可同时传入多个,使用空格分开,数目与 `${JSON_LOGS} * ${KEYS}` 数目一致)。默认使用 `"${JSON_LOG}-${KEYS}"`
- `--backend` :matplotlib 的绘图后端,默认由 matplotlib 自动选择。
- `--style` :绘图配色风格,默认为 `whitegrid`
- `--out` :保存分析图片的路径,如不指定则不保存。
- `--window-size`: 可视化窗口大小,如果没有指定,默认为 `12*7`。如果需要指定,需按照格式 `'W*H'`
```{note}
`--style` 选项依赖于第三方库 `seaborn`,需要设置绘图风格请现安装该库。
```
例如:
- 绘制某日志文件对应的损失曲线图。
```shell
python tools/analysis_tools/analyze_logs.py plot_curve your_log_json --keys loss --legend loss
```
- 绘制某日志文件对应的 top-1 和 top-5 准确率曲线图,并将曲线图导出为 results.jpg 文件。
```shell
python tools/analysis_tools/analyze_logs.py plot_curve your_log_json --keys accuracy_top-1 accuracy_top-5 --legend top1 top5 --out results.jpg
```
- 在同一图像内绘制两份日志文件对应的 top-1 准确率曲线图。
```shell
python tools/analysis_tools/analyze_logs.py plot_curve log1.json log2.json --keys accuracy_top-1 --legend run1 run2
```
```{note}
本工具会自动根据关键字段选择从日志的训练部分还是验证部分读取,因此如果你添加了
自定义的验证指标,请把相对应的关键字段加入到本工具的 `TEST_METRICS` 变量中。
```
### 统计训练时间
`tools/analysis_tools/analyze_logs.py` 也可以根据日志文件统计训练耗时。
```shell
python tools/analysis_tools/analyze_logs.py cal_train_time \
${JSON_LOGS}
[--include-outliers]
```
**所有参数的说明**
- `json_logs` :模型配置文件的路径(可同时传入多个,使用空格分开)。
- `--include-outliers` :如果指定,将不会排除每个轮次中第一轮迭代的记录(有时第一轮迭代会耗时较长)
**示例**:
```shell
python tools/analysis_tools/analyze_logs.py cal_train_time work_dirs/some_exp/20200422_153324.log.json
```
预计输出结果如下所示:
```text
-----Analyze train time of work_dirs/some_exp/20200422_153324.log.json-----
slowest epoch 68, average time is 0.3818
fastest epoch 1, average time is 0.3694
time std over epochs is 0.0020
average iter time: 0.3777 s/iter
```
## 结果分析
利用 `tools/test.py``--out` 参数,我们可以将所有的样本的推理结果保存到输出
文件中。利用这一文件,我们可以进行进一步的分析。
### 评估结果
`tools/analysis_tools/eval_metric.py` 可以用来再次计算评估结果。
```shell
python tools/analysis_tools/eval_metric.py \
${CONFIG} \
${RESULT} \
[--metrics ${METRICS}] \
[--cfg-options ${CFG_OPTIONS}] \
[--metric-options ${METRIC_OPTIONS}]
```
**所有参数说明**
- `config` :配置文件的路径。
- `result``tools/test.py` 的输出结果文件。
- `metrics` : 评估的衡量指标,可接受的值取决于数据集类。
- `--cfg-options`: 额外的配置选项,会被合入配置文件,参考[教程 1:如何编写配置文件](https://mmclassification.readthedocs.io/zh_CN/latest/tutorials/config.html)
- `--metric-options`: 如果指定了,这些选项将被传递给数据集 `evaluate` 函数的 `metric_options` 参数。
```{note}
在 `tools/test.py` 中,我们支持使用 `--out-items` 选项来选择保存哪些结果。为了使用本工具,请确保结果文件中包含 "class_scores"。
```
**示例**
```shell
python tools/analysis_tools/eval_metric.py configs/t2t_vit/t2t-vit-t-14_8xb64_in1k.py ./result.pkl --metrics accuracy --metric-options "topk=(1,5)"
```
### 查看典型结果
`tools/analysis_tools/analyze_results.py` 可以保存预测成功/失败,同时得分最高的 k 个图像。
```shell
python tools/analysis_tools/analyze_results.py \
${CONFIG} \
${RESULT} \
[--out-dir ${OUT_DIR}] \
[--topk ${TOPK}] \
[--cfg-options ${CFG_OPTIONS}]
```
**所有参数说明**
- `config` :配置文件的路径。
- `result``tools/test.py` 的输出结果文件。
- `--out-dir` :保存结果分析的文件夹路径。
- `--topk` :分别保存多少张预测成功/失败的图像。如果不指定,默认为 `20`
- `--cfg-options`: 额外的配置选项,会被合入配置文件,参考[教程 1:如何编写配置文件](https://mmclassification.readthedocs.io/zh_CN/latest/tutorials/config.html)
```{note}
在 `tools/test.py` 中,我们支持使用 `--out-items` 选项来选择保存哪些结果。为了使用本工具,请确保结果文件中包含 "pred_score"、"pred_label" 和 "pred_class"。
```
**示例**
```shell
python tools/analysis_tools/analyze_results.py \
configs/resnet/resnet50_xxxx.py \
result.pkl \
--out-dir results \
--topk 50
```
## 模型复杂度分析
### 计算 FLOPs 和参数量(试验性的)
我们根据 [flops-counter.pytorch](https://github.com/sovrasov/flops-counter.pytorch) 提供了一个脚本用于计算给定模型的 FLOPs 和参数量。
```shell
python tools/analysis_tools/get_flops.py ${CONFIG_FILE} [--shape ${INPUT_SHAPE}]
```
**所有参数说明**
- `config` :配置文件的路径。
- `--shape`: 输入尺寸,支持单值或者双值, 如: `--shape 256``--shape 224 256`。默认为`224 224`
用户将获得如下结果:
```text
==============================
Input shape: (3, 224, 224)
Flops: 4.12 GFLOPs
Params: 25.56 M
==============================
```
```{warning}
此工具仍处于试验阶段,我们不保证该数字正确无误。您最好将结果用于简单比较,但在技术报告或论文中采用该结果之前,请仔细检查。
- FLOPs 与输入的尺寸有关,而参数量与输入尺寸无关。默认输入尺寸为 (1, 3, 224, 224)
- 一些运算不会被计入 FLOPs 的统计中,例如 GN 和自定义运算。详细信息请参考 [`mmcv.cnn.get_model_complexity_info()`](https://github.com/open-mmlab/mmcv/blob/master/mmcv/cnn/utils/flops_counter.py)
```
## 常见问题
- 无
# 其他工具
<!-- TOC -->
- [打印完整配置](#打印完整配置)
- [检查数据集](#检查数据集)
- [常见问题](#常见问题)
<!-- TOC -->
## 打印完整配置
`tools/misc/print_config.py` 脚本会解析所有输入变量,并打印完整配置信息。
```shell
python tools/misc/print_config.py ${CONFIG} [--cfg-options ${CFG_OPTIONS}]
```
**所有参数说明**
- `config` :配置文件的路径。
- `--cfg-options`: 额外的配置选项,会被合入配置文件,参考[教程 1:如何编写配置文件](https://mmclassification.readthedocs.io/zh_CN/latest/tutorials/config.html)
**示例**
```shell
python tools/misc/print_config.py configs/t2t_vit/t2t-vit-t-14_8xb64_in1k.py
```
## 检查数据集
`tools/misc/verify_dataset.py` 脚本会检查数据集的所有图片,查看是否有已经损坏的图片。
```shell
python tools/print_config.py \
${CONFIG} \
[--out-path ${OUT-PATH}] \
[--phase ${PHASE}] \
[--num-process ${NUM-PROCESS}]
[--cfg-options ${CFG_OPTIONS}]
```
**所有参数说明**:
- `config` : 配置文件的路径。
- `--out-path` : 输出结果路径,默认为 'brokenfiles.log'。
- `--phase` : 检查哪个阶段的数据集,可用值为 "train" 、"test" 或者 "val", 默认为 "train"。
- `--num-process` : 指定的进程数,默认为1。
- `--cfg-options`: 额外的配置选项,会被合入配置文件,参考[教程 1:如何编写配置文件](https://mmclassification.readthedocs.io/zh_CN/latest/tutorials/config.html)
**示例**:
```shell
python tools/misc/verify_dataset.py configs/t2t_vit/t2t-vit-t-14_8xb64_in1k.py --out-path broken_imgs.log --phase val --num-process 8
```
## 常见问题
-
# 模型部署至 TorchServe
为了使用 [`TorchServe`](https://pytorch.org/serve/) 部署一个 `MMClassification` 模型,需要进行以下几步:
## 1. 转换 MMClassification 模型至 TorchServe
```shell
python tools/deployment/mmcls2torchserve.py ${CONFIG_FILE} ${CHECKPOINT_FILE} \
--output-folder ${MODEL_STORE} \
--model-name ${MODEL_NAME}
```
```{note}
${MODEL_STORE} 需要是一个文件夹的绝对路径。
```
示例:
```shell
python tools/deployment/mmcls2torchserve.py \
configs/resnet/resnet18_8xb32_in1k.py \
checkpoints/resnet18_8xb32_in1k_20210831-fbbb1da6.pth \
--output-folder ./checkpoints \
--model-name resnet18_in1k
```
## 2. 构建 `mmcls-serve` docker 镜像
```shell
docker build -t mmcls-serve:latest docker/serve/
```
## 3. 运行 `mmcls-serve` 镜像
请参考官方文档 [基于 docker 运行 TorchServe](https://github.com/pytorch/serve/blob/master/docker/README.md#running-torchserve-in-a-production-docker-environment).
为了使镜像能够使用 GPU 资源,需要安装 [nvidia-docker](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html)。之后可以传递 `--gpus` 参数以在 GPU 上运。
示例:
```shell
docker run --rm \
--cpus 8 \
--gpus device=0 \
-p8080:8080 -p8081:8081 -p8082:8082 \
--mount type=bind,source=`realpath ./checkpoints`,target=/home/model-server/model-store \
mmcls-serve:latest
```
```{note}
`realpath ./checkpoints` 是 "./checkpoints" 的绝对路径,你可以将其替换为你保存 TorchServe 模型的目录的绝对路径。
```
参考 [该文档](https://github.com/pytorch/serve/blob/master/docs/rest_api.md) 了解关于推理 (8080),管理 (8081) 和指标 (8082) 等 API 的信息。
## 4. 测试部署
```shell
curl http://127.0.0.1:8080/predictions/${MODEL_NAME} -T demo/demo.JPEG
```
您应该获得类似于以下内容的响应:
```json
{
"pred_label": 58,
"pred_score": 0.38102269172668457,
"pred_class": "water snake"
}
```
另外,你也可以使用 `test_torchserver.py` 来比较 TorchServe 和 PyTorch 的结果,并进行可视化。
```shell
python tools/deployment/test_torchserver.py ${IMAGE_FILE} ${CONFIG_FILE} ${CHECKPOINT_FILE} ${MODEL_NAME}
[--inference-addr ${INFERENCE_ADDR}] [--device ${DEVICE}]
```
示例:
```shell
python tools/deployment/test_torchserver.py \
demo/demo.JPEG \
configs/resnet/resnet18_8xb32_in1k.py \
checkpoints/resnet18_8xb32_in1k_20210831-fbbb1da6.pth \
resnet18_in1k
```
# ONNX 转 TensorRT(试验性的)
<!-- TOC -->
- [如何将模型从 ONNX 转换到 TensorRT](#如何将模型从-onnx-转换到-tensorrt)
- [准备工作](#准备工作)
- [使用方法](#使用方法)
- [支持转换至 TensorRT 的模型列表](#支持转换至-tensorrt-的模型列表)
- [提示](#提示)
- [常见问题](#常见问题)
<!-- TOC -->
## 如何将模型从 ONNX 转换到 TensorRT
### 准备工作
1. 请参照 [安装指南](https://mmclassification.readthedocs.io/zh_CN/latest/install.html#mmclassification) 从源码安装 MMClassification。
2. 使用我们的工具 [pytorch2onnx.md](./pytorch2onnx.md) 将 PyTorch 模型转换至 ONNX。
### 使用方法
```bash
python tools/deployment/onnx2tensorrt.py \
${MODEL} \
--trt-file ${TRT_FILE} \
--shape ${IMAGE_SHAPE} \
--workspace-size {WORKSPACE_SIZE} \
--show \
--verify \
```
所有参数的说明:
- `model` : ONNX 模型的路径。
- `--trt-file`: TensorRT 引擎文件的输出路径。如果没有指定,默认为当前脚本执行路径下的 `tmp.trt`
- `--shape`: 模型输入的高度和宽度。如果没有指定,默认为 `224 224`
- `--workspace-size` : 构建 TensorRT 引擎所需要的 GPU 空间大小,单位为 GiB。如果没有指定,默认为 `1` GiB。
- `--show`: 是否展示模型的输出。如果没有指定,默认为 `False`
- `--verify`: 是否使用 ONNXRuntime 和 TensorRT 验证模型转换的正确性。如果没有指定,默认为`False`
示例:
```bash
python tools/deployment/onnx2tensorrt.py \
checkpoints/resnet/resnet18_b16x8_cifar10.onnx \
--trt-file checkpoints/resnet/resnet18_b16x8_cifar10.trt \
--shape 224 224 \
--show \
--verify \
```
## 支持转换至 TensorRT 的模型列表
下表列出了保证可转换为 TensorRT 的模型。
| 模型 | 配置文件 | 状态 |
| :----------: | :-----------------------------------------------------: | :--: |
| MobileNetV2 | `configs/mobilenet_v2/mobilenet-v2_8xb32_in1k.py` | Y |
| ResNet | `configs/resnet/resnet18_8xb16_cifar10.py` | Y |
| ResNeXt | `configs/resnext/resnext50-32x4d_8xb32_in1k.py` | Y |
| ShuffleNetV1 | `configs/shufflenet_v1/shufflenet-v1-1x_16xb64_in1k.py` | Y |
| ShuffleNetV2 | `configs/shufflenet_v2/shufflenet-v2-1x_16xb64_in1k.py` | Y |
注:
- *以上所有模型转换测试基于 Pytorch==1.6.0 和 TensorRT-7.2.1.6.Ubuntu-16.04.x86_64-gnu.cuda-10.2.cudnn8.0 进行*
## 提示
- 如果你在上述模型的转换中遇到问题,请在 GitHub 中创建一个 issue,我们会尽快处理。未在上表中列出的模型,由于资源限制,我们可能无法提供很多帮助,如果遇到问题,请尝试自行解决。
## 常见问题
-
# Pytorch 转 ONNX (试验性的)
<!-- TOC -->
- [如何将模型从 PyTorch 转换到 ONNX](#如何将模型从-pytorch-转换到-onnx)
- [准备工作](#准备工作)
- [使用方法](#使用方法)
- [支持导出至 ONNX 的模型列表](#支持导出至-onnx-的模型列表)
- [提示](#提示)
- [常见问题](#常见问题)
<!-- TOC -->
## 如何将模型从 PyTorch 转换到 ONNX
### 准备工作
1. 请参照 [安装指南](https://mmclassification.readthedocs.io/zh_CN/latest/install.html#mmclassification) 从源码安装 MMClassification。
2. 安装 onnx 和 onnxruntime。
```shell
pip install onnx onnxruntime==1.5.1
```
### 使用方法
```bash
python tools/deployment/pytorch2onnx.py \
${CONFIG_FILE} \
--checkpoint ${CHECKPOINT_FILE} \
--output-file ${OUTPUT_FILE} \
--shape ${IMAGE_SHAPE} \
--opset-version ${OPSET_VERSION} \
--dynamic-shape \
--show \
--simplify \
--verify \
```
所有参数的说明:
- `config` : 模型配置文件的路径。
- `--checkpoint` : 模型权重文件的路径。
- `--output-file`: ONNX 模型的输出路径。如果没有指定,默认为当前脚本执行路径下的 `tmp.onnx`
- `--shape`: 模型输入的高度和宽度。如果没有指定,默认为 `224 224`
- `--opset-version` : ONNX 的 opset 版本。如果没有指定,默认为 `11`
- `--dynamic-shape` : 是否以动态输入尺寸导出 ONNX。 如果没有指定,默认为 `False`
- `--show`: 是否打印导出模型的架构。如果没有指定,默认为 `False`
- `--simplify`: 是否精简导出的 ONNX 模型。如果没有指定,默认为 `False`
- `--verify`: 是否验证导出模型的正确性。如果没有指定,默认为`False`
示例:
```bash
python tools/deployment/pytorch2onnx.py \
configs/resnet/resnet18_8xb16_cifar10.py \
--checkpoint checkpoints/resnet/resnet18_b16x8_cifar10.pth \
--output-file checkpoints/resnet/resnet18_b16x8_cifar10.onnx \
--dynamic-shape \
--show \
--simplify \
--verify \
```
## 支持导出至 ONNX 的模型列表
下表列出了保证可导出至 ONNX,并在 ONNX Runtime 中运行的模型。
| 模型 | 配置文件 | 批推理 | 动态输入尺寸 | 备注 |
| :----------: | :-----------------------------------------------------: | :----: | :----------: | ---- |
| MobileNetV2 | `configs/mobilenet_v2/mobilenet-v2_8xb32_in1k.py` | Y | Y | |
| ResNet | `configs/resnet/resnet18_8xb16_cifar10.py` | Y | Y | |
| ResNeXt | `configs/resnext/resnext50-32x4d_8xb32_in1k.py` | Y | Y | |
| SE-ResNet | `configs/seresnet/seresnet50_8xb32_in1k.py` | Y | Y | |
| ShuffleNetV1 | `configs/shufflenet_v1/shufflenet-v1-1x_16xb64_in1k.py` | Y | Y | |
| ShuffleNetV2 | `configs/shufflenet_v2/shufflenet-v2-1x_16xb64_in1k.py` | Y | Y | |
注:
- *以上所有模型转换测试基于 Pytorch==1.6.0 进行*
## 提示
- 如果你在上述模型的转换中遇到问题,请在 GitHub 中创建一个 issue,我们会尽快处理。未在上表中列出的模型,由于资源限制,我们可能无法提供很多帮助,如果遇到问题,请尝试自行解决。
## 常见问题
-
# Pytorch 转 TorchScript (试验性的)
<!-- TOC -->
- [如何将 PyTorch 模型转换至 TorchScript](#如何将-pytorch-模型转换至-torchscript)
- [使用方法](#使用方法)
- [提示](#提示)
- [常见问题](#常见问题)
<!-- TOC -->
## 如何将 PyTorch 模型转换至 TorchScript
### 使用方法
```bash
python tools/deployment/pytorch2torchscript.py \
${CONFIG_FILE} \
--checkpoint ${CHECKPOINT_FILE} \
--output-file ${OUTPUT_FILE} \
--shape ${IMAGE_SHAPE} \
--verify \
```
所有参数的说明:
- `config` : 模型配置文件的路径。
- `--checkpoint` : 模型权重文件的路径。
- `--output-file`: TorchScript 模型的输出路径。如果没有指定,默认为当前脚本执行路径下的 `tmp.pt`
- `--shape`: 模型输入的高度和宽度。如果没有指定,默认为 `224 224`
- `--verify`: 是否验证导出模型的正确性。如果没有指定,默认为`False`
示例:
```bash
python tools/deployment/pytorch2onnx.py \
configs/resnet/resnet18_8xb16_cifar10.py \
--checkpoint checkpoints/resnet/resnet18_b16x8_cifar10.pth \
--output-file checkpoints/resnet/resnet18_b16x8_cifar10.pt \
--verify \
```
注:
- *所有模型基于 Pytorch==1.8.1 通过了转换测试*
## 提示
- 由于 `torch.jit.is_tracing()` 只在 PyTorch 1.6 之后的版本中得到支持,对于 PyTorch 1.3-1.5 的用户,我们建议手动提前返回结果。
- 如果你在本仓库的模型转换中遇到问题,请在 GitHub 中创建一个 issue,我们会尽快处理。
## 常见问题
-
# 可视化
<!-- TOC -->
- [数据流水线可视化](#数据流水线可视化)
- [学习率策略可视化](#学习率策略可视化)
- [类别激活图可视化](#类别激活图可视化)
- [常见问题](#常见问题)
<!-- TOC -->
## 数据流水线可视化
```bash
python tools/visualizations/vis_pipeline.py \
${CONFIG_FILE} \
[--output-dir ${OUTPUT_DIR}] \
[--phase ${DATASET_PHASE}] \
[--number ${BUNBER_IMAGES_DISPLAY}] \
[--skip-type ${SKIP_TRANSFORM_TYPE}] \
[--mode ${DISPLAY_MODE}] \
[--show] \
[--adaptive] \
[--min-edge-length ${MIN_EDGE_LENGTH}] \
[--max-edge-length ${MAX_EDGE_LENGTH}] \
[--bgr2rgb] \
[--window-size ${WINDOW_SIZE}] \
[--cfg-options ${CFG_OPTIONS}]
```
**所有参数的说明**
- `config` : 模型配置文件的路径。
- `--output-dir`: 保存图片文件夹,如果没有指定,默认为 `''`,表示不保存。
- `--phase`: 可视化数据集的阶段,只能为 `[train, val, test]` 之一,默认为 `train`
- `--number`: 可视化样本数量。如果没有指定,默认展示数据集的所有图片。
- `--skip-type`: 预设跳过的数据流水线过程。如果没有指定,默认为 `['ToTensor', 'Normalize', 'ImageToTensor', 'Collect']`
- `--mode`: 可视化的模式,只能为 `[original, transformed, concat, pipeline]` 之一,如果没有指定,默认为 `concat`
- `--show`: 将可视化图片以弹窗形式展示。
- `--adaptive`: 自动调节可视化图片的大小。
- `--min-edge-length`: 最短边长度,当使用了 `--adaptive` 时有效。 当图片任意边小于 `${MIN_EDGE_LENGTH}` 时,会保持长宽比不变放大图片,短边对齐至 `${MIN_EDGE_LENGTH}`,默认为200。
- `--max-edge-length`: 最长边长度,当使用了 `--adaptive` 时有效。 当图片任意边大于 `${MAX_EDGE_LENGTH}` 时,会保持长宽比不变缩小图片,短边对齐至 `${MAX_EDGE_LENGTH}`,默认为1000。
- `--bgr2rgb`: 将图片的颜色通道翻转。
- `--window-size`: 可视化窗口大小,如果没有指定,默认为 `12*7`。如果需要指定,按照格式 `'W*H'`
- `--cfg-options` : 对配置文件的修改,参考[教程 1:如何编写配置文件](https://mmclassification.readthedocs.io/zh_CN/latest/tutorials/config.html)
```{note}
1. 如果不指定 `--mode`,默认设置为 `concat`,获取原始图片和预处理后图片拼接的图片;如果 `--mode` 设置为 `original`,则获取原始图片;如果 `--mode` 设置为 `transformed`,则获取预处理后的图片;如果 `--mode` 设置为 `pipeline`,则获得数据流水线所有中间过程图片。
2. 当指定了 `--adaptive` 选项时,会自动的调整尺寸过大和过小的图片,你可以通过设定 `--min-edge-length` 与 `--max-edge-length` 来指定自动调整的图片尺寸。
```
**示例**
1. **'original'** 模式,可视化 `CIFAR100` 验证集中的100张原始图片,显示并保存在 `./tmp` 文件夹下:
```shell
python ./tools/visualizations/vis_pipeline.py configs/resnet/resnet50_8xb16_cifar100.py --phase val --output-dir tmp --mode original --number 100 --show --adaptive --bgr2rgb
```
<div align=center><img src="https://user-images.githubusercontent.com/18586273/146117528-1ec2d918-57f8-4ae4-8ca3-a8d31b602f64.jpg" style=" width: auto; height: 40%; "></div>
2. **'transformed'** 模式,可视化 `ImageNet` 训练集的所有经过预处理的图片,并以弹窗形式显示:
```shell
python ./tools/visualizations/vis_pipeline.py ./configs/resnet/resnet50_8xb32_in1k.py --show --mode transformed
```
<div align=center><img src="https://user-images.githubusercontent.com/18586273/146117553-8006a4ba-e2fa-4f53-99bc-42a4b06e413f.jpg" style=" width: auto; height: 40%; "></div>
3. **'concat'** 模式,可视化 `ImageNet` 训练集的10张原始图片与预处理后图片对比图,保存在 `./tmp` 文件夹下:
```shell
python ./tools/visualizations/vis_pipeline.py configs/swin_transformer/swin_base_224_b16x64_300e_imagenet.py --phase train --output-dir tmp --number 10 --adaptive
```
<div align=center><img src="https://user-images.githubusercontent.com/18586273/146128259-0a369991-7716-411d-8c27-c6863e6d76ea.JPEG" style=" width: auto; height: 40%; "></div>
4. **'pipeline'** 模式,可视化 `ImageNet` 训练集经过数据流水线的过程图像:
```shell
python ./tools/visualizations/vis_pipeline.py configs/swin_transformer/swin_base_224_b16x64_300e_imagenet.py --phase train --adaptive --mode pipeline --show
```
<div align=center><img src="https://user-images.githubusercontent.com/18586273/146128201-eb97c2aa-a615-4a81-a649-38db1c315d0e.JPEG" style=" width: auto; height: 40%; "></div>
## 学习率策略可视化
```bash
python tools/visualizations/vis_lr.py \
${CONFIG_FILE} \
[--dataset-size ${Dataset_Size}] \
[--ngpus ${NUM_GPUs}] \
[--save-path ${SAVE_PATH}] \
[--title ${TITLE}] \
[--style ${STYLE}] \
[--window-size ${WINDOW_SIZE}] \
[--cfg-options ${CFG_OPTIONS}] \
```
**所有参数的说明**
- `config` : 模型配置文件的路径。
- `--dataset-size` : 数据集的大小。如果指定,`build_dataset` 将被跳过并使用这个大小作为数据集大小,默认使用 `build_dataset` 所得数据集的大小。
- `--ngpus` : 使用 GPU 的数量。
- `--save-path` : 保存的可视化图片的路径,默认不保存。
- `--title` : 可视化图片的标题,默认为配置文件名。
- `--style` : 可视化图片的风格,默认为 `whitegrid`
- `--window-size`: 可视化窗口大小,如果没有指定,默认为 `12*7`。如果需要指定,按照格式 `'W*H'`
- `--cfg-options` : 对配置文件的修改,参考[教程 1:如何编写配置文件](https://mmclassification.readthedocs.io/zh_CN/latest/tutorials/config.html)
```{note}
部分数据集在解析标注阶段比较耗时,可直接将 `dataset-size` 指定数据集的大小,以节约时间。
```
**示例**
```bash
python tools/visualizations/vis_lr.py configs/resnet/resnet50_b16x8_cifar100.py
```
<div align=center><img src="../_static/image/tools/visualization/lr_schedule1.png" style=" width: auto; height: 40%; "></div>
当数据集为 ImageNet 时,通过直接指定数据集大小来节约时间,并保存图片:
```bash
python tools/visualizations/vis_lr.py configs/repvgg/repvgg-B3g4_4xb64-autoaug-lbs-mixup-coslr-200e_in1k.py --dataset-size 1281167 --ngpus 4 --save-path ./repvgg-B3g4_4xb64-lr.jpg
```
<div align=center><img src="../_static/image/tools/visualization/lr_schedule2.png" style=" width: auto; height: 40%; "></div>
## 类别激活图可视化
MMClassification 提供 `tools\visualizations\vis_cam.py` 工具来可视化类别激活图。请使用 `pip install "grad-cam>=1.3.6"` 安装依赖的 [pytorch-grad-cam](https://github.com/jacobgil/pytorch-grad-cam)
目前支持的方法有:
| Method | What it does |
| :----------: | :-----------------------------------------------------------------------------------------------: |
| GradCAM | 使用平均梯度对 2D 激活进行加权 |
| GradCAM++ | 类似 GradCAM,但使用了二阶梯度 |
| XGradCAM | 类似 GradCAM,但通过归一化的激活对梯度进行了加权 |
| EigenCAM | 使用 2D 激活的第一主成分(无法区分类别,但效果似乎不错) |
| EigenGradCAM | 类似 EigenCAM,但支持类别区分,使用了激活 * 梯度的第一主成分,看起来和 GradCAM 差不多,但是更干净 |
| LayerCAM | 使用正梯度对激活进行空间加权,对于浅层有更好的效果 |
**命令行**
```bash
python tools/visualizations/vis_cam.py \
${IMG} \
${CONFIG_FILE} \
${CHECKPOINT} \
[--target-layers ${TARGET-LAYERS}] \
[--preview-model] \
[--method ${METHOD}] \
[--target-category ${TARGET-CATEGORY}] \
[--save-path ${SAVE_PATH}] \
[--vit-like] \
[--num-extra-tokens ${NUM-EXTRA-TOKENS}]
[--aug_smooth] \
[--eigen_smooth] \
[--device ${DEVICE}] \
[--cfg-options ${CFG-OPTIONS}]
```
**所有参数的说明**
- `img`:目标图片路径。
- `config`:模型配置文件的路径。
- `checkpoint`:权重路径。
- `--target-layers`:所查看的网络层名称,可输入一个或者多个网络层, 如果不设置,将使用最后一个`block`中的`norm`层。
- `--preview-model`:是否查看模型所有网络层。
- `--method`:类别激活图图可视化的方法,目前支持 `GradCAM`, `GradCAM++`, `XGradCAM`, `EigenCAM`, `EigenGradCAM`, `LayerCAM`,不区分大小写。如果不设置,默认为 `GradCAM`
- `--target-category`:查看的目标类别,如果不设置,使用模型检测出来的类别做为目标类别。
- `--save-path`:保存的可视化图片的路径,默认不保存。
- `--eigen-smooth`:是否使用主成分降低噪音,默认不开启。
- `--vit-like`: 是否为 `ViT` 类似的 Transformer-based 网络
- `--num-extra-tokens`: `ViT` 类网络的额外的 tokens 通道数,默认使用主干网络的 `num_extra_tokens`
- `--aug-smooth`:是否使用测试时增强
- `--device`:使用的计算设备,如果不设置,默认为'cpu'。
- `--cfg-options`:对配置文件的修改,参考[教程 1:如何编写配置文件](https://mmclassification.readthedocs.io/zh_CN/latest/tutorials/config.html)
```{note}
在指定 `--target-layers` 时,如果不知道模型有哪些网络层,可使用命令行添加 `--preview-model` 查看所有网络层名称;
```
**示例(CNN)**
`--target-layers``Resnet-50` 中的一些示例如下:
- `'backbone.layer4'`,表示第四个 `ResLayer` 层的输出。
- `'backbone.layer4.2'` 表示第四个 `ResLayer` 层中第三个 `BottleNeck` 块的输出。
- `'backbone.layer4.2.conv1'` 表示上述 `BottleNeck` 块中 `conv1` 层的输出。
```{note}
对于 `ModuleList` 或者 `Sequential` 类型的网络层,可以直接使用索引的方式指定子模块。比如 `backbone.layer4[-1]` 和 `backbone.layer4.2` 是相同的,因为 `layer4` 是一个拥有三个子模块的 `Sequential`。
```
1. 使用不同方法可视化 `ResNet50`,默认 `target-category` 为模型检测的结果,使用默认推导的 `target-layers`
```shell
python tools/visualizations/vis_cam.py \
demo/bird.JPEG \
configs/resnet/resnet50_8xb32_in1k.py \
https://download.openmmlab.com/mmclassification/v0/resnet/resnet50_batch256_imagenet_20200708-cfb998bf.pth \
--method GradCAM
# GradCAM++, XGradCAM, EigenCAM, EigenGradCAM, LayerCAM
```
| Image | GradCAM | GradCAM++ | EigenGradCAM | LayerCAM |
| ------------------------------------ | --------------------------------------- | ----------------------------------------- | -------------------------------------------- | ---------------------------------------- |
| <div align=center><img src='https://user-images.githubusercontent.com/18586273/144429496-628d3fb3-1f6e-41ff-aa5c-1b08c60c32a9.JPEG' height="auto" width="160" ></div> | <div align=center><img src='https://user-images.githubusercontent.com/18586273/147065002-f1c86516-38b2-47ba-90c1-e00b49556c70.jpg' height="auto" width="150" ></div> | <div align=center><img src='https://user-images.githubusercontent.com/18586273/147065119-82581fa1-3414-4d6c-a849-804e1503c74b.jpg' height="auto" width="150"></div> | <div align=center><img src='https://user-images.githubusercontent.com/18586273/147065096-75a6a2c1-6c57-4789-ad64-ebe5e38765f4.jpg' height="auto" width="150"></div> | <div align=center><img src='https://user-images.githubusercontent.com/18586273/147065129-814d20fb-98be-4106-8c5e-420adcc85295.jpg' height="auto" width="150"></div> |
2. 同一张图不同类别的激活图效果图,在 `ImageNet` 数据集中,类别238为 'Greater Swiss Mountain dog',类别281为 'tabby, tabby cat'。
```shell
python tools/visualizations/vis_cam.py \
demo/cat-dog.png configs/resnet/resnet50_8xb32_in1k.py \
https://download.openmmlab.com/mmclassification/v0/resnet/resnet50_batch256_imagenet_20200708-cfb998bf.pth \
--target-layers 'backbone.layer4.2' \
--method GradCAM \
--target-category 238
# --target-category 281
```
| Category | Image | GradCAM | XGradCAM | LayerCAM |
| -------- | ---------------------------------------------- | ------------------------------------------------ | ------------------------------------------------- | ------------------------------------------------- |
| Dog | <div align=center><img src='https://user-images.githubusercontent.com/18586273/144429526-f27f4cce-89b9-4117-bfe6-55c2ca7eaba6.png' height="auto" width="165" ></div> | <div align=center><img src='https://user-images.githubusercontent.com/18586273/144433562-968a57bc-17d9-413e-810e-f91e334d648a.jpg' height="auto" width="150" ></div> | <div align=center><img src='https://user-images.githubusercontent.com/18586273/144433853-319f3a8f-95f2-446d-b84f-3028daca5378.jpg' height="auto" width="150" ></div> | <div align=center><img src='https://user-images.githubusercontent.com/18586273/144433937-daef5a69-fd70-428f-98a3-5e7747f4bb88.jpg' height="auto" width="150" ></div> |
| Cat | <div align=center><img src='https://user-images.githubusercontent.com/18586273/144429526-f27f4cce-89b9-4117-bfe6-55c2ca7eaba6.png' height="auto" width="165" ></div> | <div align=center><img src='https://user-images.githubusercontent.com/18586273/144434518-867ae32a-1cb5-4dbd-b1b9-5e375e94ea48.jpg' height="auto" width="150" ></div> | <div align=center><img src='https://user-images.githubusercontent.com/18586273/144434603-0a2fd9ec-c02e-4e6c-a17b-64c234808c56.jpg' height="auto" width="150" ></div> | <div align=center><img src='https://user-images.githubusercontent.com/18586273/144434623-b4432cc2-c663-4b97-aed3-583d9d3743e6.jpg' height="auto" width="150" ></div> |
3. 使用 `--eigen-smooth` 以及 `--aug-smooth` 获取更好的可视化效果。
```shell
python tools/visualizations/vis_cam.py \
demo/dog.jpg \
configs/mobilenet_v3/mobilenet-v3-large_8xb32_in1k.py \
https://download.openmmlab.com/mmclassification/v0/mobilenet_v3/convert/mobilenet_v3_large-3ea3c186.pth \
--target-layers 'backbone.layer16' \
--method LayerCAM \
--eigen-smooth --aug-smooth
```
| Image | LayerCAM | eigen-smooth | aug-smooth | eigen&aug |
| ------------------------------------ | --------------------------------------- | ------------------------------------------- | ----------------------------------------- | ----------------------------------------- |
| <div align=center><img src='https://user-images.githubusercontent.com/18586273/144557492-98ac5ce0-61f9-4da9-8ea7-396d0b6a20fa.jpg' height="auto" width="160"></div> | <div align=center><img src='https://user-images.githubusercontent.com/18586273/144557541-a4cf7d86-7267-46f9-937c-6f657ea661b4.jpg' height="auto" width="145" ></div> | <div align=center><img src='https://user-images.githubusercontent.com/18586273/144557547-2731b53e-e997-4dd2-a092-64739cc91959.jpg' height="auto" width="145" ></div> | <div align=center><img src='https://user-images.githubusercontent.com/18586273/144557545-8189524a-eb92-4cce-bf6a-760cab4a8065.jpg' height="auto" width="145" ></div> | <div align=center><img src='https://user-images.githubusercontent.com/18586273/144557548-c1e3f3ec-3c96-43d4-874a-3b33cd3351c5.jpg' height="auto" width="145" ></div> |
**示例(Transformer)**
`--target-layers` 在 Transformer-based 网络中的一些示例如下:
- Swin-Transformer 中:`'backbone.norm3'`
- ViT 中:`'backbone.layers[-1].ln1'`
对于 Transformer-based 的网络,比如 ViT、T2T-ViT 和 Swin-Transformer,特征是被展平的。为了绘制 CAM 图,我们需要指定 `--vit-like` 选项,从而让被展平的特征恢复方形的特征图。
除了特征被展平之外,一些类 ViT 的网络还会添加额外的 tokens。比如 ViT 和 T2T-ViT 中添加了分类 token,DeiT 中还添加了蒸馏 token。在这些网络中,分类计算在最后一个注意力模块之后就已经完成了,分类得分也只和这些额外的 tokens 有关,与特征图无关,也就是说,分类得分对这些特征图的导数为 0。因此,我们不能使用最后一个注意力模块的输出作为 CAM 绘制的目标层。
另外,为了去除这些额外的 toekns 以获得特征图,我们需要知道这些额外 tokens 的数量。MMClassification 中几乎所有 Transformer-based 的网络都拥有 `num_extra_tokens` 属性。而如果你希望将此工具应用于新的,或者第三方的网络,而且该网络没有指定 `num_extra_tokens` 属性,那么可以使用 `--num-extra-tokens` 参数手动指定其数量。
1.`Swin Transformer` 使用默认 `target-layers` 进行 CAM 可视化:
```shell
python tools/visualizations/vis_cam.py \
demo/bird.JPEG \
configs/swin_transformer/swin-tiny_16xb64_in1k.py \
https://download.openmmlab.com/mmclassification/v0/swin-transformer/swin_tiny_224_b16x64_300e_imagenet_20210616_090925-66df6be6.pth \
--vit-like
```
2.`Vision Transformer(ViT)` 进行 CAM 可视化:
```shell
python tools/visualizations/vis_cam.py \
demo/bird.JPEG \
configs/vision_transformer/vit-base-p16_ft-64xb64_in1k-384.py \
https://download.openmmlab.com/mmclassification/v0/vit/finetune/vit-base-p16_in21k-pre-3rdparty_ft-64xb64_in1k-384_20210928-98e8652b.pth \
--vit-like \
--target-layers 'backbone.layers[-1].ln1'
```
3.`T2T-ViT` 进行 CAM 可视化:
```shell
python tools/visualizations/vis_cam.py \
demo/bird.JPEG \
configs/t2t_vit/t2t-vit-t-14_8xb64_in1k.py \
https://download.openmmlab.com/mmclassification/v0/t2t-vit/t2t-vit-t-14_3rdparty_8xb64_in1k_20210928-b7c09b62.pth \
--vit-like \
--target-layers 'backbone.encoder[-1].ln1'
```
| Image | ResNet50 | ViT | Swin | T2T-ViT |
| --------------------------------------- | ------------------------------------------ | -------------------------------------- | --------------------------------------- | ------------------------------------------ |
| <div align=center><img src='https://user-images.githubusercontent.com/18586273/144429496-628d3fb3-1f6e-41ff-aa5c-1b08c60c32a9.JPEG' height="auto" width="165" ></div> | <div align=center><img src=https://user-images.githubusercontent.com/18586273/144431491-a2e19fe3-5c12-4404-b2af-a9552f5a95d9.jpg height="auto" width="150" ></div> | <div align=center><img src='https://user-images.githubusercontent.com/18586273/144436218-245a11de-6234-4852-9c08-ff5069f6a739.jpg' height="auto" width="150" ></div> | <div align=center><img src='https://user-images.githubusercontent.com/18586273/144436168-01b0e565-442c-4e1e-910c-17c62cff7cd3.jpg' height="auto" width="150" ></div> | <div align=center><img src='https://user-images.githubusercontent.com/18586273/144436198-51dbfbda-c48d-48cc-ae06-1a923d19b6f6.jpg' height="auto" width="150" ></div> |
## 常见问题
-
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
# 教程 1:如何编写配置文件
MMClassification 主要使用 python 文件作为配置文件。其配置文件系统的设计将模块化与继承整合进来,方便用户进行各种实验。所有配置文件都放置在 `configs` 文件夹下,主要包含 `_base_` 原始配置文件夹 以及 `resnet`, `swin_transformer``vision_transformer` 等诸多算法文件夹。
可以使用 `python tools/misc/print_config.py /PATH/TO/CONFIG` 命令来查看完整的配置信息,从而方便检查所对应的配置文件。
<!-- TOC -->
- [配置文件以及权重命名规则](#配置文件以及权重命名规则)
- [配置文件结构](#配置文件结构)
- [继承并修改配置文件](#继承并修改配置文件)
- [使用配置文件里的中间变量](#使用配置文件里的中间变量)
- [忽略基础配置文件里的部分内容](#忽略基础配置文件里的部分内容)
- [引用基础配置文件里的变量](#引用基础配置文件里的变量)
- [通过命令行参数修改配置信息](#通过命令行参数修改配置信息)
- [导入用户自定义模块](#导入用户自定义模块)
- [常见问题](#常见问题)
<!-- TOC -->
## 配置文件以及权重命名规则
MMClassification 按照以下风格进行配置文件命名,代码库的贡献者需要遵循相同的命名规则。文件名总体分为四部分:算法信息,模块信息,训练信息和数据信息。逻辑上属于不同部分的单词之间用下划线 `'_'` 连接,同一部分有多个单词用短横线 `'-'` 连接。
```
{algorithm info}_{module info}_{training info}_{data info}.py
```
- `algorithm info`:算法信息,算法名称或者网络架构,如 resnet 等;
- `module info`: 模块信息,因任务而异,用以表示一些特殊的 neck、head 和 pretrain 信息;
- `training info`:一些训练信息,训练策略设置,包括 batch size,schedule 数据增强等;
- `data info`:数据信息,数据集名称、模态、输入尺寸等,如 imagenet, cifar 等;
### 算法信息
指论文中的算法名称缩写,以及相应的分支架构信息。例如:
- `resnet50`
- `mobilenet-v3-large`
- `vit-small-patch32` : `patch32` 表示 `ViT` 切分的分块大小
- `seresnext101-32x4d` : `SeResNet101` 基本网络结构,`32x4d` 表示在 `Bottleneck``groups``width_per_group` 分别为32和4
### 模块信息
指一些特殊的 `neck``head` 或者 `pretrain` 的信息, 在分类中常见为预训练信息,比如:
- `in21k-pre` : 在 `ImageNet21k` 上预训练
- `in21k-pre-3rd-party` : 在 `ImageNet21k` 上预训练,其权重来自其他仓库
### 训练信息
训练策略的一些设置,包括训练类型、 `batch size``lr schedule`、 数据增强以及特殊的损失函数等等,比如:
Batch size 信息:
- 格式为`{gpu x batch_per_gpu}`, 如 `8xb32`
训练类型(主要见于 transformer 网络,如 `ViT` 算法,这类算法通常分为预训练和微调两种模式):
- `ft` : Finetune config,用于微调的配置文件
- `pt` : Pretrain config,用于预训练的配置文件
训练策略信息,训练策略以复现配置文件为基础,此基础不必标注训练策略。但如果在此基础上进行改进,则需注明训练策略,按照应用点位顺序排列,如:`{pipeline aug}-{train aug}-{loss trick}-{scheduler}-{epochs}`
- `coslr-200e` : 使用 cosine scheduler, 训练 200 个 epoch
- `autoaug-mixup-lbs-coslr-50e` : 使用了 `autoaug``mixup``label smooth``cosine scheduler`, 训练了 50 个轮次
### 数据信息
- `in1k` : `ImageNet1k` 数据集,默认使用 `224x224` 大小的图片
- `in21k` : `ImageNet21k` 数据集,有些地方也称为 `ImageNet22k` 数据集,默认使用 `224x224` 大小的图片
- `in1k-384px` : 表示训练的输出图片大小为 `384x384`
- `cifar100`
### 配置文件命名案例:
```
repvgg-D2se_deploy_4xb64-autoaug-lbs-mixup-coslr-200e_in1k.py
```
- `repvgg-D2se`: 算法信息
- `repvgg`: 主要算法名称。
- `D2se`: 模型的结构。
- `deploy`:模块信息,该模型为推理状态。
- `4xb64-autoaug-lbs-mixup-coslr-200e`: 训练信息
- `4xb64`: 使用4块 GPU 并且 每块 GPU 的批大小为64。
- `autoaug`: 使用 `AutoAugment` 数据增强方法。
- `lbs`: 使用 `label smoothing` 损失函数。
- `mixup`: 使用 `mixup` 训练增强方法。
- `coslr`: 使用 `cosine scheduler` 优化策略。
- `200e`: 训练 200 轮次。
- `in1k`: 数据信息。 配置文件用于 `ImageNet1k` 数据集上使用 `224x224` 大小图片训练。
```{note}
部分配置文件目前还没有遵循此命名规范,相关文件命名近期会更新。
```
### 权重命名规则
权重的命名主要包括配置文件名,日期和哈希值。
```
{config_name}_{date}-{hash}.pth
```
## 配置文件结构
`configs/_base_` 文件夹下有 4 个基本组件类型,分别是:
- [模型(model)](https://github.com/open-mmlab/mmclassification/tree/master/configs/_base_/models)
- [数据(data)](https://github.com/open-mmlab/mmclassification/tree/master/configs/_base_/datasets)
- [训练策略(schedule)](https://github.com/open-mmlab/mmclassification/tree/master/configs/_base_/schedules)
- [运行设置(runtime)](https://github.com/open-mmlab/mmclassification/blob/master/configs/_base_/default_runtime.py)
你可以通过继承一些基本配置文件轻松构建自己的训练配置文件。由来自`_base_` 的组件组成的配置称为 _primitive_。
为了帮助用户对 MMClassification 检测系统中的完整配置和模块有一个基本的了解,我们使用 [ResNet50 原始配置文件](https://github.com/open-mmlab/mmclassification/blob/master/configs/resnet/resnet50_8xb32_in1k.py) 作为案例进行说明并注释每一行含义。更详细的用法和各个模块对应的替代方案,请参考 API 文档。
```python
_base_ = [
'../_base_/models/resnet50.py', # 模型
'../_base_/datasets/imagenet_bs32.py', # 数据
'../_base_/schedules/imagenet_bs256.py', # 训练策略
'../_base_/default_runtime.py' # 默认运行设置
]
```
下面对这四个部分分别进行说明,仍然以上述 ResNet50 原始配置文件作为案例。
### 模型
模型参数 `model` 在配置文件中为一个 `python` 字典,主要包括网络结构、损失函数等信息:
- `type` : 分类器名称, 目前 MMClassification 只支持 `ImageClassifier`, 参考 [API 文档](https://mmclassification.readthedocs.io/zh_CN/latest/api/models.html#classifier)
- `backbone` : 主干网类型,可用选项参考 [API 文档](https://mmclassification.readthedocs.io/zh_CN/latest/api/models.html#backbones)
- `neck` : 颈网络类型,目前 MMClassification 只支持 `GlobalAveragePooling`, 参考 [API 文档](https://mmclassification.readthedocs.io/zh_CN/latest/api/models.html#necks)
- `head` : 头网络类型, 包括单标签分类与多标签分类头网络,可用选项参考 [API 文档](https://mmclassification.readthedocs.io/zh_CN/latest/api/models.html#heads)
- `loss` : 损失函数类型, 支持 `CrossEntropyLoss`, [`LabelSmoothLoss`](https://github.com/open-mmlab/mmclassification/blob/master/configs/_base_/models/resnet50_label_smooth.py) 等,可用选项参考 [API 文档](https://mmclassification.readthedocs.io/zh_CN/latest/api/models.html#losses)
- `train_cfg` :训练配置, 支持 [`mixup`](https://github.com/open-mmlab/mmclassification/blob/master/configs/_base_/models/resnet50_mixup.py), [`cutmix`](https://github.com/open-mmlab/mmclassification/blob/master/configs/_base_/models/resnet50_cutmix.py) 等训练增强。
```{note}
配置文件中的 'type' 不是构造时的参数,而是类名。
```
```python
model = dict(
type='ImageClassifier', # 分类器类型
backbone=dict(
type='ResNet', # 主干网络类型
depth=50, # 主干网网络深度, ResNet 一般有18, 34, 50, 101, 152 可以选择
num_stages=4, # 主干网络状态(stages)的数目,这些状态产生的特征图作为后续的 head 的输入。
out_indices=(3, ), # 输出的特征图输出索引。越远离输入图像,索引越大
frozen_stages=-1, # 网络微调时,冻结网络的stage(训练时不执行反相传播算法),若num_stages=4,backbone包含stem 与 4 个 stages。frozen_stages为-1时,不冻结网络; 为0时,冻结 stem; 为1时,冻结 stem 和 stage1; 为4时,冻结整个backbone
style='pytorch'), # 主干网络的风格,'pytorch' 意思是步长为2的层为 3x3 卷积, 'caffe' 意思是步长为2的层为 1x1 卷积。
neck=dict(type='GlobalAveragePooling'), # 颈网络类型
head=dict(
type='LinearClsHead', # 线性分类头,
num_classes=1000, # 输出类别数,这与数据集的类别数一致
in_channels=2048, # 输入通道数,这与 neck 的输出通道一致
loss=dict(type='CrossEntropyLoss', loss_weight=1.0), # 损失函数配置信息
topk=(1, 5), # 评估指标,Top-k 准确率, 这里为 top1 与 top5 准确率
))
```
### 数据
数据参数 `data` 在配置文件中为一个 `python` 字典,主要包含构造数据集加载器(dataloader)配置信息:
- `samples_per_gpu` : 构建 dataloader 时,每个 GPU 的 Batch Size
- `workers_per_gpu` : 构建 dataloader 时,每个 GPU 的 线程数
- `train | val | test` : 构造数据集
- `type` : 数据集类型, MMClassification 支持 `ImageNet``Cifar` 等 ,参考[API 文档](https://mmclassification.readthedocs.io/zh_CN/latest/api/datasets.html)
- `data_prefix` : 数据集根目录
- `pipeline` : 数据处理流水线,参考相关教程文档 [如何设计数据处理流水线](https://mmclassification.readthedocs.io/zh_CN/latest/tutorials/data_pipeline.html)
评估参数 `evaluation` 也是一个字典, 为 `evaluation hook` 的配置信息, 主要包括评估间隔、评估指标等。
```python
# dataset settings
dataset_type = 'ImageNet' # 数据集名称,
img_norm_cfg = dict( #图像归一化配置,用来归一化输入的图像。
mean=[123.675, 116.28, 103.53], # 预训练里用于预训练主干网络模型的平均值。
std=[58.395, 57.12, 57.375], # 预训练里用于预训练主干网络模型的标准差。
to_rgb=True) # 是否反转通道,使用 cv2, mmcv 读取图片默认为 BGR 通道顺序,这里 Normalize 均值方差数组的数值是以 RGB 通道顺序, 因此需要反转通道顺序。
# 训练数据流水线
train_pipeline = [
dict(type='LoadImageFromFile'), # 读取图片
dict(type='RandomResizedCrop', size=224), # 随机缩放抠图
dict(type='RandomFlip', flip_prob=0.5, direction='horizontal'), # 以概率为0.5随机水平翻转图片
dict(type='Normalize', **img_norm_cfg), # 归一化
dict(type='ImageToTensor', keys=['img']), # image 转为 torch.Tensor
dict(type='ToTensor', keys=['gt_label']), # gt_label 转为 torch.Tensor
dict(type='Collect', keys=['img', 'gt_label']) # 决定数据中哪些键应该传递给检测器的流程
]
# 测试数据流水线
test_pipeline = [
dict(type='LoadImageFromFile'),
dict(type='Resize', size=(256, -1)),
dict(type='CenterCrop', crop_size=224),
dict(type='Normalize', **img_norm_cfg),
dict(type='ImageToTensor', keys=['img']),
dict(type='Collect', keys=['img']) # test 时不传递 gt_label
]
data = dict(
samples_per_gpu=32, # 单个 GPU 的 Batch size
workers_per_gpu=2, # 单个 GPU 的 线程数
train=dict( # 训练数据信息
type=dataset_type, # 数据集名称
data_prefix='data/imagenet/train', # 数据集目录,当不存在 ann_file 时,类别信息从文件夹自动获取
pipeline=train_pipeline), # 数据集需要经过的 数据流水线
val=dict( # 验证数据集信息
type=dataset_type,
data_prefix='data/imagenet/val',
ann_file='data/imagenet/meta/val.txt', # 标注文件路径,存在 ann_file 时,不通过文件夹自动获取类别信息
pipeline=test_pipeline),
test=dict( # 测试数据集信息
type=dataset_type,
data_prefix='data/imagenet/val',
ann_file='data/imagenet/meta/val.txt',
pipeline=test_pipeline))
evaluation = dict( # evaluation hook 的配置
interval=1, # 验证期间的间隔,单位为 epoch 或者 iter, 取决于 runner 类型。
metric='accuracy') # 验证期间使用的指标。
```
### 训练策略
主要包含 优化器设置、 `optimizer hook` 设置、学习率策略和 `runner`设置:
- `optimizer` : 优化器设置信息, 支持 `pytorch` 所有的优化器,参考相关 [mmcv](https://mmcv.readthedocs.io/zh_CN/latest/_modules/mmcv/runner/optimizer/default_constructor.html#DefaultOptimizerConstructor) 文档
- `optimizer_config` : `optimizer hook` 的配置文件,如设置梯度限制,参考相关 [mmcv](https://github.com/open-mmlab/mmcv/blob/master/mmcv/runner/hooks/optimizer.py#L8) 代码
- `lr_config` : 学习率策略,支持 "CosineAnnealing"、 "Step"、 "Cyclic" 等等,参考相关 [mmcv](https://mmcv.readthedocs.io/zh_CN/latest/_modules/mmcv/runner/hooks/lr_updater.html#LrUpdaterHook) 文档
- `runner` : 有关 `runner` 可以参考 `mmcv` 对于 [`runner`](https://mmcv.readthedocs.io/zh_CN/latest/understand_mmcv/runner.html) 介绍文档
```python
# 用于构建优化器的配置文件。支持 PyTorch 中的所有优化器,同时它们的参数与 PyTorch 里的优化器参数一致。
optimizer = dict(type='SGD', # 优化器类型
lr=0.1, # 优化器的学习率,参数的使用细节请参照对应的 PyTorch 文档。
momentum=0.9, # 动量(Momentum)
weight_decay=0.0001) # 权重衰减系数(weight decay)。
# optimizer hook 的配置文件
optimizer_config = dict(grad_clip=None) # 大多数方法不使用梯度限制(grad_clip)。
# 学习率调整配置,用于注册 LrUpdater hook。
lr_config = dict(policy='step', # 调度流程(scheduler)的策略,也支持 CosineAnnealing, Cyclic, 等。
step=[30, 60, 90]) # 在 epoch 为 30, 60, 90 时, lr 进行衰减
runner = dict(type='EpochBasedRunner', # 将使用的 runner 的类别,如 IterBasedRunner 或 EpochBasedRunner。
max_epochs=100) # runner 总回合数, 对于 IterBasedRunner 使用 `max_iters`
```
### 运行设置
本部分主要包括保存权重策略、日志配置、训练参数、断点权重路径和工作目录等等。
```python
# Checkpoint hook 的配置文件。
checkpoint_config = dict(interval=1) # 保存的间隔是 1,单位会根据 runner 不同变动,可以为 epoch 或者 iter。
# 日志配置信息。
log_config = dict(
interval=100, # 打印日志的间隔, 单位 iters
hooks=[
dict(type='TextLoggerHook'), # 用于记录训练过程的文本记录器(logger)。
# dict(type='TensorboardLoggerHook') # 同样支持 Tensorboard 日志
])
dist_params = dict(backend='nccl') # 用于设置分布式训练的参数,端口也同样可被设置。
log_level = 'INFO' # 日志的输出级别。
resume_from = None # 从给定路径里恢复检查点(checkpoints),训练模式将从检查点保存的轮次开始恢复训练。
workflow = [('train', 1)] # runner 的工作流程,[('train', 1)] 表示只有一个工作流且工作流仅执行一次。
work_dir = 'work_dir' # 用于保存当前实验的模型检查点和日志的目录文件地址。
```
## 继承并修改配置文件
为了精简代码、更快的修改配置文件以及便于理解,我们建议继承现有方法。
对于在同一算法文件夹下的所有配置文件,MMClassification 推荐只存在 **一个** 对应的 _原始配置_ 文件。
所有其他的配置文件都应该继承 _原始配置_ 文件,这样就能保证配置文件的最大继承深度为 3。
例如,如果在 ResNet 的基础上做了一些修改,用户首先可以通过指定 `_base_ = './resnet50_8xb32_in1k.py'`(相对于你的配置文件的路径),来继承基础的 ResNet 结构、数据集以及其他训练配置信息,然后修改配置文件中的必要参数以完成继承。如想在基础 resnet50 的基础上将训练轮数由 100 改为 300 和修改学习率衰减轮数,同时修改数据集路径,可以建立新的配置文件 `configs/resnet/resnet50_8xb32-300e_in1k.py`, 文件中写入以下内容:
```python
_base_ = './resnet50_8xb32_in1k.py'
runner = dict(max_epochs=300)
lr_config = dict(step=[150, 200, 250])
data = dict(
train=dict(data_prefix='mydata/imagenet/train'),
val=dict(data_prefix='mydata/imagenet/train', ),
test=dict(data_prefix='mydata/imagenet/train', )
)
```
### 使用配置文件里的中间变量
用一些中间变量,中间变量让配置文件更加清晰,也更容易修改。
例如数据集里的 `train_pipeline` / `test_pipeline` 是作为数据流水线的中间变量。我们首先要定义 `train_pipeline` / `test_pipeline`,然后将它们传递到 `data` 中。如果想修改训练或测试时输入图片的大小,就需要修改 `train_pipeline` / `test_pipeline` 这些中间变量。
```python
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='RandomResizedCrop', size=384, backend='pillow',),
dict(type='RandomFlip', flip_prob=0.5, direction='horizontal'),
dict(type='Normalize', **img_norm_cfg),
dict(type='ImageToTensor', keys=['img']),
dict(type='ToTensor', keys=['gt_label']),
dict(type='Collect', keys=['img', 'gt_label'])
]
test_pipeline = [
dict(type='LoadImageFromFile'),
dict(type='Resize', size=384, backend='pillow'),
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))
```
### 忽略基础配置文件里的部分内容
有时,您需要设置 `_delete_=True` 去忽略基础配置文件里的一些域内容。 可以参照 [mmcv](https://mmcv.readthedocs.io/zh_CN/latest/understand_mmcv/config.html#inherit-from-base-config-with-ignored-fields) 来获得一些简单的指导。
以下是一个简单应用案例。 如果在上述 ResNet50 案例中 使用 cosine schedule ,使用继承并直接修改会报 `get unexcepected keyword 'step'` 错, 因为基础配置文件 lr_config 域信息的 `'step'` 字段被保留下来了,需要加入 `_delete_=True` 去忽略基础配置文件里的 `lr_config` 相关域内容:
```python
_base_ = '../../configs/resnet/resnet50_8xb32_in1k.py'
lr_config = dict(
_delete_=True,
policy='CosineAnnealing',
min_lr=0,
warmup='linear',
by_epoch=True,
warmup_iters=5,
warmup_ratio=0.1
)
```
### 引用基础配置文件里的变量
有时,您可以引用 `_base_` 配置信息的一些域内容,这样可以避免重复定义。 可以参照 [mmcv](https://mmcv.readthedocs.io/zh_CN/latest/understand_mmcv/config.html#reference-variables-from-base) 来获得一些简单的指导。
以下是一个简单应用案例,在训练数据预处理流水线中使用 auto augment 数据增强,参考配置文件 [`configs/_base_/datasets/imagenet_bs64_autoaug.py`](https://github.com/open-mmlab/mmclassification/blob/master/configs/_base_/datasets/imagenet_bs64_autoaug.py)。 在定义 `train_pipeline` 时,可以直接在 `_base_` 中加入定义 auto augment 数据增强的文件命名,再通过 `{{_base_.auto_increasing_policies}}` 引用变量:
```python
_base_ = ['./pipelines/auto_aug.py']
# dataset settings
dataset_type = 'ImageNet'
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='RandomResizedCrop', size=224),
dict(type='RandomFlip', flip_prob=0.5, direction='horizontal'),
dict(type='AutoAugment', policies={{_base_.auto_increasing_policies}}),
dict(type='Normalize', **img_norm_cfg),
dict(type='ImageToTensor', keys=['img']),
dict(type='ToTensor', keys=['gt_label']),
dict(type='Collect', keys=['img', 'gt_label'])
]
test_pipeline = [...]
data = dict(
samples_per_gpu=64,
workers_per_gpu=2,
train=dict(..., pipeline=train_pipeline),
val=dict(..., pipeline=test_pipeline))
evaluation = dict(interval=1, metric='accuracy')
```
## 通过命令行参数修改配置信息
当用户使用脚本 "tools/train.py" 或者 "tools/test.py" 提交任务,以及使用一些工具脚本时,可以通过指定 `--cfg-options` 参数来直接修改所使用的配置文件内容。
- 更新配置文件内的字典
可以按照原始配置文件中字典的键的顺序指定配置选项。
例如,`--cfg-options model.backbone.norm_eval=False` 将主干网络中的所有 BN 模块更改为 `train` 模式。
- 更新配置文件内列表的键
一些配置字典在配置文件中会形成一个列表。例如,训练流水线 `data.train.pipeline` 通常是一个列表。
例如,`[dict(type='LoadImageFromFile'), dict(type='TopDownRandomFlip', flip_prob=0.5), ...]` 。如果要将流水线中的 `'flip_prob=0.5'` 更改为 `'flip_prob=0.0'`,您可以这样指定 `--cfg-options data.train.pipeline.1.flip_prob=0.0`
- 更新列表/元组的值。
当配置文件中需要更新的是一个列表或者元组,例如,配置文件通常会设置 `workflow=[('train', 1)]`,用户如果想更改,
需要指定 `--cfg-options workflow="[(train,1),(val,1)]"`。注意这里的引号 " 对于列表以及元组数据类型的修改是必要的,
并且 **不允许** 引号内所指定的值的书写存在空格。
## 导入用户自定义模块
```{note}
本部分仅在当将 MMClassification 当作库构建自己项目时可能用到,初学者可跳过。
```
在学习完后续教程 [如何添加新数据集](https://mmclassification.readthedocs.io/zh_CN/latest/tutorials/new_dataset.html)[如何设计数据处理流程](https://mmclassification.readthedocs.io/zh_CN/latest/tutorials/data_pipeline.html)[如何增加新模块](https://mmclassification.readthedocs.io/zh_CN/latest/tutorials/new_modules.html) 后,您可能使用 MMClassification 完成自己的项目并在项目中自定义了数据集、模型、数据增强等。为了精简代码,可以将 MMClassification 作为一个第三方库,只需要保留自己的额外的代码,并在配置文件中导入自定义的模块。案例可以参考 [OpenMMLab 算法大赛项目](https://github.com/zhangrui-wolf/openmmlab-competition-2021)
只需要在你的配置文件中添加以下代码:
```python
custom_imports = dict(
imports=['your_dataset_class',
'your_transforme_class',
'your_model_class',
'your_module_class'],
allow_failed_imports=False)
```
## 常见问题
-
# 教程 4:如何设计数据处理流程
## 设计数据流水线
按照典型的用法,我们通过 `Dataset``DataLoader` 来使用多个 worker 进行数据加
载。对 `Dataset` 的索引操作将返回一个与模型的 `forward` 方法的参数相对应的字典。
数据流水线和数据集在这里是解耦的。通常,数据集定义如何处理标注文件,而数据流水
线定义所有准备数据字典的步骤。流水线由一系列操作组成。每个操作都将一个字典作为
输入,并输出一个字典。
这些操作分为数据加载,预处理和格式化。
这里使用 ResNet-50 在 ImageNet 数据集上的数据流水线作为示例。
```python
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='RandomResizedCrop', size=224),
dict(type='RandomFlip', flip_prob=0.5, direction='horizontal'),
dict(type='Normalize', **img_norm_cfg),
dict(type='ImageToTensor', keys=['img']),
dict(type='ToTensor', keys=['gt_label']),
dict(type='Collect', keys=['img', 'gt_label'])
]
test_pipeline = [
dict(type='LoadImageFromFile'),
dict(type='Resize', size=256),
dict(type='CenterCrop', crop_size=224),
dict(type='Normalize', **img_norm_cfg),
dict(type='ImageToTensor', keys=['img']),
dict(type='Collect', keys=['img'])
]
```
对于每个操作,我们列出了添加、更新、删除的相关字典字段。在流水线的最后,我们使
`Collect` 仅保留进行模型 `forward` 方法所需的项。
### 数据加载
`LoadImageFromFile` - 从文件中加载图像
- 添加:img, img_shape, ori_shape
默认情况下,`LoadImageFromFile` 将会直接从硬盘加载图像,但对于一些效率较高、规
模较小的模型,这可能会导致 IO 瓶颈。MMCV 支持多种数据加载后端来加速这一过程。例
如,如果训练设备上配置了 [memcached](https://memcached.org/),那么我们按照如下
方式修改配置文件。
```
memcached_root = '/mnt/xxx/memcached_client/'
train_pipeline = [
dict(
type='LoadImageFromFile',
file_client_args=dict(
backend='memcached',
server_list_cfg=osp.join(memcached_root, 'server_list.conf'),
client_cfg=osp.join(memcached_root, 'client.conf'))),
]
```
更多支持的数据加载后端,可以参见 [mmcv.fileio.FileClient](https://github.com/open-mmlab/mmcv/blob/master/mmcv/fileio/file_client.py)
### 预处理
`Resize` - 缩放图像尺寸
- 添加:scale, scale_idx, pad_shape, scale_factor, keep_ratio
- 更新:img, img_shape
`RandomFlip` - 随机翻转图像
- 添加:flip, flip_direction
- 更新:img
`RandomCrop` - 随机裁剪图像
- 更新:img, pad_shape
`Normalize` - 图像数据归一化
- 添加:img_norm_cfg
- 更新:img
### 格式化
`ToTensor` - 转换(标签)数据至 `torch.Tensor`
- 更新:根据参数 `keys` 指定
`ImageToTensor` - 转换图像数据至 `torch.Tensor`
- 更新:根据参数 `keys` 指定
`Collect` - 保留指定键值
- 删除:除了参数 `keys` 指定以外的所有键值对
## 扩展及使用自定义流水线
1. 编写一个新的数据处理操作,并放置在 `mmcls/datasets/pipelines/` 目录下的任何
一个文件中,例如 `my_pipeline.py`。这个类需要重载 `__call__` 方法,接受一个
字典作为输入,并返回一个字典。
```python
from mmcls.datasets import PIPELINES
@PIPELINES.register_module()
class MyTransform(object):
def __call__(self, results):
# 对 results['img'] 进行变换操作
return results
```
2.`mmcls/datasets/pipelines/__init__.py` 中导入这个新的类。
```python
...
from .my_pipeline import MyTransform
__all__ = [
..., 'MyTransform'
]
```
3. 在数据流水线的配置中添加这一操作。
```python
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='RandomResizedCrop', size=224),
dict(type='RandomFlip', flip_prob=0.5, direction='horizontal'),
dict(type='MyTransform'),
dict(type='Normalize', **img_norm_cfg),
dict(type='ImageToTensor', keys=['img']),
dict(type='ToTensor', keys=['gt_label']),
dict(type='Collect', keys=['img', 'gt_label'])
]
```
## 流水线可视化
设计好数据流水线后,可以使用[可视化工具](../tools/visualization.md)查看具体的效果。
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment