Commit 85529f35 authored by unknown's avatar unknown
Browse files

添加openmmlab测试用例

parent b21b0c01
# ONNX to TensorRT (Experimental)
<!-- TOC -->
- [Tutorial 6: ONNX to TensorRT (Experimental)](#tutorial-6-onnx-to-tensorrt-experimental)
- [How to convert models from ONNX to TensorRT](#how-to-convert-models-from-onnx-to-tensorrt)
- [Prerequisite](#prerequisite)
- [Usage](#usage)
- [List of supported models convertable to TensorRT](#list-of-supported-models-convertable-to-tensorrt)
- [Reminders](#reminders)
- [FAQs](#faqs)
<!-- TOC -->
## How to convert models from ONNX to TensorRT
### Prerequisite
1. Please refer to [install.md](https://mmclassification.readthedocs.io/en/latest/install.html#install-mmclassification) for installation of MMClassification from source.
2. Use our tool [pytorch2onnx.md](./pytorch2onnx.md) to convert the model from PyTorch to ONNX.
### Usage
```bash
python tools/deployment/onnx2tensorrt.py \
${MODEL} \
--trt-file ${TRT_FILE} \
--shape ${IMAGE_SHAPE} \
--max-batch-size ${MAX_BATCH_SIZE} \
--workspace-size ${WORKSPACE_SIZE} \
--fp16 \
--show \
--verify \
```
Description of all arguments:
- `model` : The path of an ONNX model file.
- `--trt-file`: The Path of output TensorRT engine file. If not specified, it will be set to `tmp.trt`.
- `--shape`: The height and width of model input. If not specified, it will be set to `224 224`.
- `--max-batch-size`: The max batch size of TensorRT model, should not be less than 1.
- `--fp16`: Enable fp16 mode.
- `--workspace-size` : The required GPU workspace size in GiB to build TensorRT engine. If not specified, it will be set to `1` GiB.
- `--show`: Determines whether to show the outputs of the model. If not specified, it will be set to `False`.
- `--verify`: Determines whether to verify the correctness of models between ONNXRuntime and TensorRT. If not specified, it will be set to `False`.
Example:
```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 \
```
## List of supported models convertable to TensorRT
The table below lists the models that are guaranteed to be convertable to TensorRT.
| Model | Config | Status |
| :----------: | :--------------------------------------------------------------------------: | :----: |
| MobileNetV2 | `configs/mobilenet_v2/mobilenet_v2_b32x8_imagenet.py` | Y |
| ResNet | `configs/resnet/resnet18_b16x8_cifar10.py` | Y |
| ResNeXt | `configs/resnext/resnext50_32x4d_b32x8_imagenet.py` | Y |
| ShuffleNetV1 | `configs/shufflenet_v1/shufflenet_v1_1x_b64x16_linearlr_bn_nowd_imagenet.py` | Y |
| ShuffleNetV2 | `configs/shufflenet_v2/shufflenet_v2_1x_b64x16_linearlr_bn_nowd_imagenet.py` | Y |
Notes:
- *All models above are tested with Pytorch==1.6.0 and TensorRT-7.2.1.6.Ubuntu-16.04.x86_64-gnu.cuda-10.2.cudnn8.0*
## Reminders
- If you meet any problem with the listed models above, please create an issue and it would be taken care of soon. For models not included in the list, we may not provide much help here due to the limited resources. Please try to dig a little deeper and debug by yourself.
## FAQs
- None
# Pytorch to ONNX (Experimental)
<!-- TOC -->
- [Tutorial 5: Pytorch to ONNX (Experimental)](#tutorial-5-pytorch-to-onnx-experimental)
- [How to convert models from Pytorch to ONNX](#how-to-convert-models-from-pytorch-to-onnx)
- [Prerequisite](#prerequisite)
- [Usage](#usage)
- [Description of all arguments:](#description-of-all-arguments)
- [How to evaluate ONNX models with ONNX Runtime](#how-to-evaluate-onnx-models-with-onnx-runtime)
- [Prerequisite](#prerequisite-1)
- [Usage](#usage-1)
- [Description of all arguments](#description-of-all-arguments-1)
- [Results and Models](#results-and-models)
- [List of supported models exportable to ONNX](#list-of-supported-models-exportable-to-onnx)
- [Reminders](#reminders)
- [FAQs](#faqs)
<!-- TOC -->
## How to convert models from Pytorch to ONNX
### Prerequisite
1. Please refer to [install](https://mmclassification.readthedocs.io/en/latest/install.html#install-mmclassification) for installation of MMClassification.
2. Install onnx and onnxruntime
```shell
pip install onnx onnxruntime==1.5.1
```
### Usage
```bash
python tools/deployment/pytorch2onnx.py \
${CONFIG_FILE} \
--checkpoint ${CHECKPOINT_FILE} \
--output-file ${OUTPUT_FILE} \
--shape ${IMAGE_SHAPE} \
--opset-version ${OPSET_VERSION} \
--dynamic-export \
--show \
--simplify \
--verify \
```
### Description of all arguments:
- `config` : The path of a model config file.
- `--checkpoint` : The path of a model checkpoint file.
- `--output-file`: The path of output ONNX model. If not specified, it will be set to `tmp.onnx`.
- `--shape`: The height and width of input tensor to the model. If not specified, it will be set to `224 224`.
- `--opset-version` : The opset version of ONNX. If not specified, it will be set to `11`.
- `--dynamic-export` : Determines whether to export ONNX with dynamic input shape and output shapes. If not specified, it will be set to `False`.
- `--show`: Determines whether to print the architecture of the exported model. If not specified, it will be set to `False`.
- `--simplify`: Determines whether to simplify the exported ONNX model. If not specified, it will be set to `False`.
- `--verify`: Determines whether to verify the correctness of an exported model. If not specified, it will be set to `False`.
Example:
```bash
python tools/deployment/pytorch2onnx.py \
configs/resnet/resnet18_b16x8_cifar10.py \
--checkpoint checkpoints/resnet/resnet18_b16x8_cifar10.pth \
--output-file checkpoints/resnet/resnet18_b16x8_cifar10.onnx \
--dynamic-export \
--show \
--simplify \
--verify \
```
## How to evaluate ONNX models with ONNX Runtime
We prepare a tool `tools/deployment/test.py` to evaluate ONNX models with ONNXRuntime or TensorRT.
### Prerequisite
- Install onnx and onnxruntime-gpu
```shell
pip install onnx onnxruntime-gpu
```
### Usage
```bash
python tools/deployment/test.py \
${CONFIG_FILE} \
${ONNX_FILE} \
--backend ${BACKEND} \
--out ${OUTPUT_FILE} \
--metrics ${EVALUATION_METRICS} \
--metric-options ${EVALUATION_OPTIONS} \
--show
--show-dir ${SHOW_DIRECTORY} \
--cfg-options ${CFG_OPTIONS} \
```
### Description of all arguments
- `config`: The path of a model config file.
- `model`: The path of a ONNX model file.
- `--backend`: Backend for input model to run and should be `onnxruntime` or `tensorrt`.
- `--out`: The path of output result file in pickle format.
- `--metrics`: Evaluation metrics, which depends on the dataset, e.g., "accuracy", "precision", "recall", "f1_score", "support" for single label dataset, and "mAP", "CP", "CR", "CF1", "OP", "OR", "OF1" for multi-label dataset.
- `--show`: Determines whether to show classifier outputs. If not specified, it will be set to `False`.
- `--show-dir`: Directory where painted images will be saved
- `--metrics-options`: Custom options for evaluation, the key-value pair in `xxx=yyy` format will be kwargs for `dataset.evaluate()` function
- `--cfg-options`: Override some settings in the used config file, the key-value pair in `xxx=yyy` format will be merged into config file.
### Results and Models
This part selects ImageNet for onnxruntime verification. ImageNet has multiple versions, but the most commonly used one is [ILSVRC 2012](http://www.image-net.org/challenges/LSVRC/2012/).
<table border="1" class="docutils">
<tr>
<th align="center">Model</th>
<th align="center">Config</th>
<th align="center">Metric</th>
<th align="center">PyTorch</th>
<th align="center">ONNXRuntime</th>
<th align="center">TensorRT-fp32</th>
<th align="center">TensorRT-fp16</th>
</tr>
<tr>
<td align="center">ResNet</td>
<td align="center"><code>resnet50_b32x8_imagenet.py</code></td>
<td align="center">Top 1 / 5</td>
<td align="center">76.55 / 93.15</td>
<td align="center">76.49 / 93.22</td>
<td align="center">76.49 / 93.22</td>
<td align="center">76.50 / 93.20</td>
</tr>
<tr>
<td align="center">ResNeXt</td>
<td align="center"><code>resnext50_32x4d_b32x8_imagenet.py</code></td>
<td align="center">Top 1 / 5</td>
<td align="center">77.90 / 93.66</td>
<td align="center">77.90 / 93.66</td>
<td align="center">77.90 / 93.66</td>
<td align="center">77.89 / 93.65</td>
</tr>
<tr>
<td align="center">SE-ResNet</td>
<td align="center"><code>seresnet50_b32x8_imagenet.py</code></td>
<td align="center">Top 1 / 5</td>
<td align="center">77.74 / 93.84</td>
<td align="center">77.74 / 93.84</td>
<td align="center">77.74 / 93.84</td>
<td align="center">77.74 / 93.85</td>
</tr>
<tr>
<td align="center">ShuffleNetV1</td>
<td align="center"><code>shufflenet_v1_1x_b64x16_linearlr_bn_nowd_imagenet.py</code></td>
<td align="center">Top 1 / 5</td>
<td align="center">68.13 / 87.81</td>
<td align="center">68.13 / 87.81</td>
<td align="center">68.13 / 87.81</td>
<td align="center">68.10 / 87.80</td>
</tr>
<tr>
<td align="center">ShuffleNetV2</td>
<td align="center"><code>shufflenet_v2_1x_b64x16_linearlr_bn_nowd_imagenet.py</code></td>
<td align="center">Top 1 / 5</td>
<td align="center">69.55 / 88.92</td>
<td align="center">69.55 / 88.92</td>
<td align="center">69.55 / 88.92</td>
<td align="center">69.55 / 88.92</td>
</tr>
<tr>
<td align="center">MobileNetV2</td>
<td align="center"><code>mobilenet_v2_b32x8_imagenet.py</code></td>
<td align="center">Top 1 / 5</td>
<td align="center">71.86 / 90.42</td>
<td align="center">71.86 / 90.42</td>
<td align="center">71.86 / 90.42</td>
<td align="center">71.88 / 90.40</td>
</tr>
</table>
## List of supported models exportable to ONNX
The table below lists the models that are guaranteed to be exportable to ONNX and runnable in ONNX Runtime.
| Model | Config | Batch Inference | Dynamic Shape | Note |
| :----------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------: | :-----------: | ---- |
| MobileNetV2 | [mobilenet_v2_b32x8_imagenet.py](https://github.com/open-mmlab/mmclassification/tree/master/configs/mobilenet_v2/mobilenet_v2_b32x8_imagenet.py) | Y | Y | |
| ResNet | [resnet18_b16x8_cifar10.py](https://github.com/open-mmlab/mmclassification/tree/master/configs/resnet/resnet18_b16x8_cifar10.py) | Y | Y | |
| ResNeXt | [resnext50_32x4d_b32x8_imagenet.py](https://github.com/open-mmlab/mmclassification/tree/master/configs/resnext/resnext50_32x4d_b32x8_imagenet.py) | Y | Y | |
| SE-ResNet | [seresnet50_b32x8_imagenet.py](https://github.com/open-mmlab/mmclassification/tree/master/configs/seresnet/seresnet50_b32x8_imagenet.py) | Y | Y | |
| ShuffleNetV1 | [shufflenet_v1_1x_b64x16_linearlr_bn_nowd_imagenet.py](https://github.com/open-mmlab/mmclassification/tree/master/configs/shufflenet_v1/shufflenet_v1_1x_b64x16_linearlr_bn_nowd_imagenet.py) | Y | Y | |
| ShuffleNetV2 | [shufflenet_v2_1x_b64x16_linearlr_bn_nowd_imagenet.py](https://github.com/open-mmlab/mmclassification/tree/master/configs/shufflenet_v2/shufflenet_v2_1x_b64x16_linearlr_bn_nowd_imagenet.py) | Y | Y | |
Notes:
- *All models above are tested with Pytorch==1.6.0*
## Reminders
- If you meet any problem with the listed models above, please create an issue and it would be taken care of soon. For models not included in the list, please try to dig a little deeper and debug a little bit more and hopefully solve them by yourself.
## FAQs
- None
# Tutorial 5: Pytorch to TorchScript (Experimental)
<!-- TOC -->
- [Tutorial 5: Pytorch to TorchScript (Experimental)](#tutorial-5-pytorch-to-torchscript-experimental)
- [How to convert models from Pytorch to TorchScript](#how-to-convert-models-from-pytorch-to-torchscript)
- [Usage](#usage)
- [Description of all arguments](#description-of-all-arguments)
- [Reminders](#reminders)
- [FAQs](#faqs)
<!-- TOC -->
## How to convert models from Pytorch to TorchScript
### Usage
```bash
python tools/deployment/pytorch2torchscript.py \
${CONFIG_FILE} \
--checkpoint ${CHECKPOINT_FILE} \
--output-file ${OUTPUT_FILE} \
--shape ${IMAGE_SHAPE} \
--verify \
```
### Description of all arguments
- `config` : The path of a model config file.
- `--checkpoint` : The path of a model checkpoint file.
- `--output-file`: The path of output TorchScript model. If not specified, it will be set to `tmp.pt`.
- `--shape`: The height and width of input tensor to the model. If not specified, it will be set to `224 224`.
- `--verify`: Determines whether to verify the correctness of an exported model. If not specified, it will be set to `False`.
Example:
```bash
python tools/deployment/pytorch2onnx.py \
configs/resnet/resnet18_b16x8_cifar10.py \
--checkpoint checkpoints/resnet/resnet18_b16x8_cifar10.pth \
--output-file checkpoints/resnet/resnet18_b16x8_cifar10.pt \
--verify \
```
Notes:
- *All models above are tested with Pytorch==1.8.1*
## Reminders
- For torch.jit.is_tracing() is only supported after v1.6. For users with pytorch v1.3-v1.5, we suggest early returning tensors manually.
- If you meet any problem with the models in this repo, please create an issue and it would be taken care of soon.
## FAQs
- None
# 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)
# 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 = 'MMClassification'
copyright = '2020, OpenMMLab'
author = 'MMClassification Authors'
version_file = '../mmcls/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 = ['mmcls.version']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# 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 -------------------------------------------------
source_suffix = {
'.rst': 'restructuredtext',
'.md': 'markdown',
}
# 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'
master_doc = 'index'
def builder_inited_handler(app):
subprocess.run(['./stat.py'])
def setup(app):
app.connect('builder-inited', builder_inited_handler)
# 基础教程
本文档提供 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,程序将会在需要的时候自动下载数据集。
对于用户自定义数据集的准备,请参阅 [教程 2:如何增加新数据集](tutorials/new_dataset.md)
## 使用预训练模型进行推理
MMClassification 提供了一些脚本用于进行单张图像的推理、数据集的推理和数据集的测试(如 ImageNet 等)
### 单张图像的推理
```shell
python demo/image_demo.py ${IMAGE_FILE} ${CONFIG_FILE} ${CHECKPOINT_FILE}
```
### 数据集的推理与测试
- 支持单 GPU
- 支持单节点多 GPU
- 支持多节点
用户可使用以下命令进行数据集的推理:
```shell
# 单 GPU
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) 等
例子:
假定用户将下载的模型权重文件放置在 `checkpoints/` 目录下。
在 ImageNet 验证集上,使用 ResNet-50 进行推理并获得预测标签及其对应的预测得分。
```shell
python tools/test.py configs/imagenet/resnet50_batch256.py checkpoints/xxx.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}`
### 使用多个 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 开始计数,常被用于微调模型。
### 使用多台机器进行训练
如果用户在 [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 集群下启动多个训练任务,则需要修改配置文件(通常是配置文件的倒数第 6 行)中的 `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/get_flops.py ${CONFIG_FILE} [--shape ${INPUT_SHAPE}]
```
用户将获得如下结果:
```
==============================
Input shape: (3, 224, 224)
Flops: 4.12 GFLOPs
Params: 25.56 M
==============================
```
**注意**:此工具仍处于试验阶段,我们不保证该数字正确无误。您最好将结果用于简单比较,但在技术报告或论文中采用该结果之前,请仔细检查。
- 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)
### 模型发布
在上传模型至 AWS 之前,也许会需要
- 转换模型权重至 CPU 张量
- 删除优化器状态
- 计算模型权重文件的哈希值,并添加至文件名之后
```shell
python tools/publish_model.py ${INPUT_FILENAME} ${OUTPUT_FILENAME}
```
例如:
```shell
python tools/publish_model.py work_dirs/resnet50/latest.pth imagenet_resnet50_20200708.pth
```
最终输出的文件名将会是 `imagenet_resnet50_20200708-{hash id}.pth`
## 详细教程
目前,MMClassification 提供以下几种更详细的教程:
- [如何微调模型](tutorials/finetune.md)
- [如何增加新数据集](tutorials/new_dataset.md)
- [如何设计数据处理流程](tutorials/data_pipeline.md)
- [如何增加新模块](tutorials/new_modules.md)
欢迎来到 MMClassification 中文教程!
==========================================
You can switch between Chinese and English documents in the lower-left corner of the layout.
您可以在页面左下角切换中英文文档。
.. toctree::
:maxdepth: 2
:caption: 开始你的第一步
install.md
getting_started.md
.. toctree::
:maxdepth: 2
:caption: 模型库
modelzoo_statistics.md
.. toctree::
:maxdepth: 2
:caption: 教程
tutorials/finetune.md
tutorials/new_dataset.md
tutorials/data_pipeline.md
tutorials/new_modules.md
.. toctree::
:maxdepth: 2
:caption: 实用工具
tutorials/pytorch2onnx.md
tutorials/onnx2tensorrt.md
.. toctree::
:caption: 语言切换
switch_language.md
索引与表格
==================
* :ref:`genindex`
* :ref:`search`
## 安装
### 安装依赖包
- Python 3.6+
- PyTorch 1.3+
- [MMCV](https://github.com/open-mmlab/mmcv)
MMClassification 和 MMCV 的适配关系如下,请安装正确版本的 MMCV 以避免安装问题
| MMClassification 版本 | MMCV 版本 |
|:---------------------:|:-----------:|
| master | mmcv>=1.3.1, <=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 |
### 安装 MMClassification 步骤
a. 创建 conda 虚拟环境,并激活
```shell
conda create -n open-mmlab python=3.7 -y
conda activate open-mmlab
```
b. 按照 [官方指南](https://pytorch.org/) 安装 PyTorch 和 TorchVision,如:
```shell
conda install pytorch torchvision -c pytorch
```
**注**:请确保 CUDA 编译版本和运行版本相匹配
用户可以参照 [PyTorch 官网](https://pytorch.org/) 对预编译包所支持的 CUDA 版本进行核对。
`例 1`:如果用户的 `/usr/local/cuda` 文件夹下已安装 CUDA 10.1 版本,并且想要安装 PyTorch 1.5 版本,
则需要安装 CUDA 10.1 下预编译的 PyTorch。
```shell
conda install pytorch cudatoolkit=10.1 torchvision -c pytorch
```
`例 2`:如果用户的 `/usr/local/cuda` 文件夹下已安装 CUDA 9.2 版本,并且想要安装 PyTorch 1.3.1 版本,
则需要安装 CUDA 9.2 下预编译的 PyTorch。
```shell
conda install pytorch=1.3.1 cudatoolkit=9.2 torchvision=0.4.2 -c pytorch
```
如果 PyTorch 是由源码进行编译安装(而非直接下载预编译好的安装包),则可以使用更多的 CUDA 版本(如 9.0 版本)。
c. 克隆 mmclassification 库
```shell
git clone https://github.com/open-mmlab/mmclassification.git
cd mmclassification
```
d. 安装依赖包和 MMClassification
```shell
pip install -e . # or "python setup.py develop"
```
提示:
1. 按照以上步骤,MMClassification 是以 `dev` 模式安装的,任何本地的代码修改都可以直接生效,无需重新安装(除非提交了一些 commit,并且希望提升版本号)
2. 如果希望使用 `opencv-python-headless` 而不是 `opencv-python`,可以在安装 [mmcv](https://github.com/open-mmlab/mmcv) 之前提前安装。
### 在多个 MMClassification 版本下进行开发
MMClassification 的训练和测试脚本已经修改了 `PYTHONPATH` 变量,以确保其能够运行当前目录下的 MMClassification。
如果想要运行环境下默认的 MMClassification,用户需要在训练和测试脚本中去除这一行:
```shell
PYTHONPATH="$(dirname $0)/..":$PYTHONPATH
```
#!/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/mmclassification/blob/master/'
files = sorted(glob.glob('../configs/*/README.md'))
stats = []
titles = []
num_ckpts = 0
num_configs = 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'\[model\]\((https?.*)\)', content))
if len(ckpts) == 0:
continue
_papertype = [x for x in re.findall(r'\[([A-Z]+)\]', content)]
assert len(_papertype) > 0
papertype = _papertype[0]
paper = set([(papertype, title)])
num_ckpts += len(ckpts)
titles.append(title)
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)
## <a href='https://mmclassification.readthedocs.io/en/latest/'>English</a>
## <a href='https://mmclassification.readthedocs.io/zh_CN/latest/'>简体中文</a>
This source diff could not be displayed because it is too large. You can view the blob instead.
# 教程 3:如何设计数据处理流程
## 设计数据流水线
按照典型的用法,我们通过 `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'])
]
```
# 教程 1:如何微调模型
已经证明,在 ImageNet 数据集上预先训练的分类模型对于其他数据集和其他下游任务有很好的效果。
该教程提供了如何将 [Model Zoo](../model_zoo.md) 中提供的预训练模型用于其他数据集,已获得更好的效果。
在新数据集上微调模型分为两步:
- 按照 [教程 2:如何增加新数据集](new_dataset.md) 添加对新数据集的支持。
- 按照本教程中讨论的内容修改配置文件
以 CIFAR10 数据集的微调为例,用户需要修改配置文件中的五个部分。
## 继承基础配置
为了重用不同配置之间的通用部分,我们支持从多个现有配置中继承配置。要微调 ResNet-50 模型,新配置需要继承 `_base_/models/resnet50.py` 来搭建模型的基本结构。为了使用 CIFAR10 数据集,新的配置文件可以直接继承 `_base_/datasets/cifar10.py`。而为了保留运行相关设置,比如训练调整器,新的配置文件需要继承 `_base_/default_runtime.py`
```python
_base_ = [
'../_base_/models/resnet50.py',
'../_base_/datasets/cifar10.py', '../_base_/default_runtime.py'
]
```
除此之外,用户也可以直接编写完整的配置文件,而不是使用继承,例如 `configs/mnist/lenet5.py`
## 修改分类头
接下来,新的配置文件需要按照新数据集的类别数目来修改分类头的配置。只需要修改分类头中的 `num_classes` 设置,除了最终分类头之外的绝大部分预训练模型权重都会被重用。
```python
_base_ = ['./resnet50.py']
model = dict(
pretrained=None,
head=dict(
type='LinearClsHead',
num_classes=10,
in_channels=2048,
loss=dict(type='CrossEntropyLoss', loss_weight=1.0),
))
```
## 修改数据集
用户可能还需要准备数据集并编写有关数据集的配置。我们目前支持 MNIST,CIFAR 和 ImageNet 数据集。为了在 CIFAR10 数据集上进行微调,考虑到其原始输入大小为 32,而在 ImageNet 上预训练模型的输入大小为 224,因此我们应将其大小调整为 224。
```python
_base_ = ['./cifar10.py']
img_norm_cfg = dict(
mean=[125.307, 122.961, 113.8575],
std=[51.5865, 50.847, 51.255],
to_rgb=True)
train_pipeline = [
dict(type='RandomCrop', size=32, padding=4),
dict(type='RandomFlip', flip_prob=0.5, direction='horizontal'),
dict(type='Resize', size=224)
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='Resize', size=224)
dict(type='Normalize', **img_norm_cfg),
dict(type='ImageToTensor', keys=['img']),
dict(type='Collect', keys=['img'])
]
```
## 修改训练调整设置
用于微调任务的超参数与默认配置不同,通常只需要较小的学习率和较少的训练时间。
```python
# 用于批大小为 128 的优化器学习率
optimizer = dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0001)
optimizer_config = dict(grad_clip=None)
# 学习策略
lr_config = dict(
policy='step',
step=[15])
runner = dict(type='EpochBasedRunner', max_epochs=200)
log_config = dict(interval=100)
```
## 使用预训练模型
为了使用预先训练的模型,新的配置文件中需要使用 `load_from` 添加预训练模型权重文件的链接。而为了避免训练过程中自动下载的耗时,用户可以在训练之前下载模型权重文件,并配置本地路径。
```python
load_from = 'https://s3.ap-northeast-2.amazonaws.com/open-mmlab/mmclassification/models/tbd.pth' # noqa
```
# 教程 2:如何添加新数据集
## 通过重新组织数据来自定义数据集
### 将数据集重新组织为已有格式
最简单的方法是将数据集转换为现有的数据集格式 (ImageNet)。
为了训练,根据图片的类别,存放至不同子目录下。训练数据文件夹结构如下所示:
```
imagenet
├── ...
├── train
│ ├── n01440764
│ │ ├── n01440764_10026.JPEG
│ │ ├── n01440764_10027.JPEG
│ │ ├── ...
│ ├── ...
│ ├── n15075141
│ │ ├── n15075141_999.JPEG
│ │ ├── n15075141_9993.JPEG
│ │ ├── ...
```
为了验证,我们提供了一个注释列表。列表的每一行都包含一个文件名及其相应的真实标签。格式如下:
```
ILSVRC2012_val_00000001.JPEG 65
ILSVRC2012_val_00000002.JPEG 970
ILSVRC2012_val_00000003.JPEG 230
ILSVRC2012_val_00000004.JPEG 809
ILSVRC2012_val_00000005.JPEG 516
```
注:真实标签的值应该位于 `[0, 类别数目 - 1]` 之间
### 自定义数据集的示例
用户可以编写一个继承自 `BasesDataset` 的新数据集类,并重载 `load_annotations(self)` 方法,类似 [CIFAR10](https://github.com/open-mmlab/mmclassification/blob/master/mmcls/datasets/cifar.py)[ImageNet](https://github.com/open-mmlab/mmclassification/blob/master/mmcls/datasets/imagenet.py)
通常,此方法返回一个包含所有样本的列表,其中的每个样本都是一个字典。字典中包含了必要的数据信息,例如 `img``gt_label`
假设我们将要实现一个 `Filelist` 数据集,该数据集将使用文件列表进行训练和测试。注释列表的格式如下:
```
000001.jpg 0
000002.jpg 1
```
我们可以在 `mmcls/datasets/filelist.py` 中创建一个新的数据集类以加载数据。
```python
import mmcv
import numpy as np
from .builder import DATASETS
from .base_dataset import BaseDataset
@DATASETS.register_module()
class Filelist(BaseDataset):
def load_annotations(self):
assert isinstance(self.ann_file, str)
data_infos = []
with open(self.ann_file) as f:
samples = [x.strip().split(' ') for x in f.readlines()]
for filename, gt_label in samples:
info = {'img_prefix': self.data_prefix}
info['img_info'] = {'filename': filename}
info['gt_label'] = np.array(gt_label, dtype=np.int64)
data_infos.append(info)
return data_infos
```
将新的数据集类加入到 `mmcls/datasets/__init__.py` 中:
```python
from .base_dataset import BaseDataset
...
from .filelist import Filelist
__all__ = [
'BaseDataset', ... ,'Filelist'
]
```
然后在配置文件中,为了使用 `Filelist`,用户可以按以下方式修改配置
```python
train = dict(
type='Filelist',
ann_file = 'image_list.txt',
pipeline=train_pipeline
)
```
## 通过混合数据集来自定义数据集
MMClassification 还支持混合数据集以进行训练。目前支持合并和重复数据集。
### 重复数据集
我们使用 `RepeatDataset` 作为一个重复数据集的封装。举个例子,假设原始数据集是 `Dataset_A`,为了重复它,我们需要如下的配置文件:
```python
dataset_A_train = dict(
type='RepeatDataset',
times=N,
dataset=dict( # 这里是 Dataset_A 的原始配置
type='Dataset_A',
...
pipeline=train_pipeline
)
)
```
### 类别平衡数据集
我们使用 `ClassBalancedDataset` 作为根据类别频率对数据集进行重复采样的封装类。进行重复采样的数据集需要实现函数 `self.get_cat_ids(idx)` 以支持 `ClassBalancedDataset`
举个例子,按照 `oversample_thr=1e-3``Dataset_A` 进行重复采样,需要如下的配置文件:
```python
dataset_A_train = dict(
type='ClassBalancedDataset',
oversample_thr=1e-3,
dataset=dict( # 这里是 Dataset_A 的原始配置
type='Dataset_A',
...
pipeline=train_pipeline
)
)
```
更加具体的细节,请参考 [源代码](../../mmcls/datasets/dataset_wrappers.py)
# 教程 4:如何增加新模块
## 开发新组件
我们基本上将模型组件分为 3 种类型。
- 主干网络:通常是一个特征提取网络,例如 ResNet、MobileNet
- 颈部:用于连接主干网络和头部的组件,例如 GlobalAveragePooling
- 头部:用于执行特定任务的组件,例如分类和回归
### 添加新的主干网络
这里,我们以 ResNet_CIFAR 为例,展示了如何开发一个新的主干网络组件。
ResNet_CIFAR 针对 CIFAR 32x32 的图像输入,将 ResNet 中 `kernel_size=7,
stride=2` 的设置替换为 `kernel_size=3, stride=1`,并移除了 stem 层之后的
`MaxPooling`,以避免传递过小的特征图到残差块中。
它继承自 `ResNet` 并只修改了 stem 层。
1. 创建一个新文件 `mmcls/models/backbones/resnet_cifar.py`
```python
import torch.nn as nn
from ..builder import BACKBONES
from .resnet import ResNet
@BACKBONES.register_module()
class ResNet_CIFAR(ResNet):
"""ResNet backbone for CIFAR.
(对这个主干网络的简短描述)
Args:
depth(int): Network depth, from {18, 34, 50, 101, 152}.
...
(参数文档)
"""
def __init__(self, depth, deep_stem=False, **kwargs):
# 调用基类 ResNet 的初始化函数
super(ResNet_CIFAR, self).__init__(depth, deep_stem=deep_stem **kwargs)
# 其他特殊的初始化流程
assert not self.deep_stem, 'ResNet_CIFAR do not support deep_stem'
def _make_stem_layer(self, in_channels, base_channels):
# 重载基类的方法,以实现对网络结构的修改
self.conv1 = build_conv_layer(
self.conv_cfg,
in_channels,
base_channels,
kernel_size=3,
stride=1,
padding=1,
bias=False)
self.norm1_name, norm1 = build_norm_layer(
self.norm_cfg, base_channels, postfix=1)
self.add_module(self.norm1_name, norm1)
self.relu = nn.ReLU(inplace=True)
def forward(self, x): # 需要返回一个元组
pass # 此处省略了网络的前向实现
def init_weights(self, pretrained=None):
pass # 如果有必要的话,重载基类 ResNet 的参数初始化函数
def train(self, mode=True):
pass # 如果有必要的话,重载基类 ResNet 的训练状态函数
```
2.`mmcls/models/backbones/__init__.py` 中导入新模块
```python
...
from .resnet_cifar import ResNet_CIFAR
__all__ = [
..., 'ResNet_CIFAR'
]
```
3. 在配置文件中使用新的主干网络
```python
model = dict(
...
backbone=dict(
type='ResNet_CIFAR',
depth=18,
other_arg=xxx),
...
```
### 添加新的颈部组件
这里我们以 `GlobalAveragePooling` 为例。这是一个非常简单的颈部组件,没有任何参数。
要添加新的颈部组件,我们主要需要实现 `forward` 函数,该函数对主干网络的输出进行
一些操作并将结果传递到头部。
1. 创建一个新文件 `mmcls/models/necks/gap.py`
```python
import torch.nn as nn
from ..builder import NECKS
@NECKS.register_module()
class GlobalAveragePooling(nn.Module):
def __init__(self):
self.gap = nn.AdaptiveAvgPool2d((1, 1))
def forward(self, inputs):
# 简单起见,我们默认输入是一个张量
outs = self.gap(inputs)
outs = outs.view(inputs.size(0), -1)
return outs
```
2.`mmcls/models/necks/__init__.py` 中导入新模块
```python
...
from .gap import GlobalAveragePooling
__all__ = [
..., 'GlobalAveragePooling'
]
```
3. 修改配置文件以使用新的颈部组件
```python
model = dict(
neck=dict(type='GlobalAveragePooling'),
)
```
### 添加新的头部组件
在此,我们以 `LinearClsHead` 为例,说明如何开发新的头部组件。
要添加一个新的头部组件,基本上我们需要实现 `forward_train` 函数,它接受来自颈部
或主干网络的特征图作为输入,并基于真实标签计算。
1. 创建一个文件 `mmcls/models/heads/linear_head.py`.
```python
from ..builder import HEADS
from .cls_head import ClsHead
@HEADS.register_module()
class LinearClsHead(ClsHead):
def __init__(self,
num_classes,
in_channels,
loss=dict(type='CrossEntropyLoss', loss_weight=1.0),
topk=(1, )):
super(LinearClsHead, self).__init__(loss=loss, topk=topk)
self.in_channels = in_channels
self.num_classes = num_classes
if self.num_classes <= 0:
raise ValueError(
f'num_classes={num_classes} must be a positive integer')
self._init_layers()
def _init_layers(self):
self.fc = nn.Linear(self.in_channels, self.num_classes)
def init_weights(self):
normal_init(self.fc, mean=0, std=0.01, bias=0)
def forward_train(self, x, gt_label):
cls_score = self.fc(x)
losses = self.loss(cls_score, gt_label)
return losses
```
2.`mmcls/models/heads/__init__.py` 中导入这个模块
```python
...
from .linear_head import LinearClsHead
__all__ = [
..., 'LinearClsHead'
]
```
3. 修改配置文件以使用新的头部组件。
连同 `GlobalAveragePooling` 颈部组件,完整的模型配置如下:
```python
model = dict(
type='ImageClassifier',
backbone=dict(
type='ResNet',
depth=50,
num_stages=4,
out_indices=(3, ),
style='pytorch'),
neck=dict(type='GlobalAveragePooling'),
head=dict(
type='LinearClsHead',
num_classes=1000,
in_channels=2048,
loss=dict(type='CrossEntropyLoss', loss_weight=1.0),
topk=(1, 5),
))
```
### 添加新的损失函数
要添加新的损失函数,我们主要需要在损失函数模块中 `forward` 函数。另外,利用装饰器 `weighted_loss` 可以方便的实现对每个元素的损失进行加权平均。
假设我们要模拟从另一个分类模型生成的概率分布,需要添加 `L1loss` 来实现该目的。
1. 创建一个新文件 `mmcls/models/losses/l1_loss.py`
```python
import torch
import torch.nn as nn
from ..builder import LOSSES
from .utils import weighted_loss
@weighted_loss
def l1_loss(pred, target):
assert pred.size() == target.size() and target.numel() > 0
loss = torch.abs(pred - target)
return loss
@LOSSES.register_module()
class L1Loss(nn.Module):
def __init__(self, reduction='mean', loss_weight=1.0):
super(L1Loss, 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 * l1_loss(
pred, target, weight, reduction=reduction, avg_factor=avg_factor)
return loss
```
2. 在文件 `mmcls/models/losses/__init__.py` 中导入这个模块
```python
...
from .l1_loss import L1Loss, l1_loss
__all__ = [
..., 'L1Loss', 'l1_loss'
]
```
3. 修改配置文件中的 `loss` 字段以使用新的损失函数
```python
loss=dict(type='L1Loss', loss_weight=1.0))
```
# ONNX to TensorRT (Experimental)
<!-- TOC -->
- [Tutorial 6: ONNX to TensorRT (Experimental)](#tutorial-6-onnx-to-tensorrt-experimental)
- [How to convert models from ONNX to TensorRT](#how-to-convert-models-from-onnx-to-tensorrt)
- [Prerequisite](#prerequisite)
- [Usage](#usage)
- [List of supported models convertable to TensorRT](#list-of-supported-models-convertable-to-tensorrt)
- [Reminders](#reminders)
- [FAQs](#faqs)
<!-- TOC -->
## How to convert models from ONNX to TensorRT
### Prerequisite
1. Please refer to [install.md](https://mmclassification.readthedocs.io/en/latest/install.html#install-mmclassification) for installation of MMClassification from source.
2. Use our tool [pytorch2onnx.md](./pytorch2onnx.md) to convert the model from PyTorch to ONNX.
### Usage
```bash
python tools/deployment/onnx2tensorrt.py \
${MODEL} \
--trt-file ${TRT_FILE} \
--shape ${IMAGE_SHAPE} \
--workspace-size {WORKSPACE_SIZE} \
--show \
--verify \
```
Description of all arguments:
- `model` : The path of an ONNX model file.
- `--trt-file`: The Path of output TensorRT engine file. If not specified, it will be set to `tmp.trt`.
- `--shape`: The height and width of model input. If not specified, it will be set to `224 224`.
- `--workspace-size` : The required GPU workspace size in GiB to build TensorRT engine. If not specified, it will be set to `1` GiB.
- `--show`: Determines whether to show the outputs of the model. If not specified, it will be set to `False`.
- `--verify`: Determines whether to verify the correctness of models between ONNXRuntime and TensorRT. If not specified, it will be set to `False`.
Example:
```bash
python tools/onnx2tensorrt.py \
checkpoints/resnet/resnet18_b16x8_cifar10.onnx \
--trt-file checkpoints/resnet/resnet18_b16x8_cifar10.trt \
--shape 224 224 \
--show \
--verify \
```
## List of supported models convertable to TensorRT
The table below lists the models that are guaranteed to be convertable to TensorRT.
| Model | Config | Status |
| :----------: | :----------------------------------------------------------: | :----: |
| MobileNetV2 | `configs/mobilenet_v2/mobilenet_v2_b32x8_imagenet.py` | Y |
| ResNet | `configs/resnet/resnet18_b16x8_cifar10.py` | Y |
| ResNeXt | `configs/resnext/resnext50_32x4d_b32x8_imagenet.py` | Y |
| ShuffleNetV1 | `configs/shufflenet_v1/shufflenet_v1_1x_b64x16_linearlr_bn_nowd_imagenet.py` | Y |
| ShuffleNetV2 | `configs/shufflenet_v2/shufflenet_v2_1x_b64x16_linearlr_bn_nowd_imagenet.py` | Y |
Notes:
- *All models above are tested with Pytorch==1.6.0 and TensorRT-7.2.1.6.Ubuntu-16.04.x86_64-gnu.cuda-10.2.cudnn8.0*
## Reminders
- If you meet any problem with the listed models above, please create an issue and it would be taken care of soon. For models not included in the list, we may not provide much help here due to the limited resources. Please try to dig a little deeper and debug by yourself.
## FAQs
- None
# Pytorch to ONNX (Experimental)
<!-- TOC -->
- [Tutorial 5: Pytorch to ONNX (Experimental)](#tutorial-5-pytorch-to-onnx-experimental)
- [How to convert models from Pytorch to ONNX](#how-to-convert-models-from-pytorch-to-onnx)
- [Prerequisite](#prerequisite)
- [Usage](#usage)
- [List of supported models exportable to ONNX](#list-of-supported-models-exportable-to-onnx)
- [Reminders](#reminders)
- [FAQs](#faqs)
<!-- TOC -->
## How to convert models from Pytorch to ONNX
### Prerequisite
1. Please refer to [install](https://mmclassification.readthedocs.io/en/latest/install.html#install-mmclassification) for installation of MMClassification.
2. Install onnx and onnxruntime
```shell
pip install onnx onnxruntime==1.5.1
```
### Usage
```bash
python tools/pytorch2onnx.py \
${CONFIG_FILE} \
--checkpoint ${CHECKPOINT_FILE} \
--output-file ${OUTPUT_FILE} \
--shape ${IMAGE_SHAPE} \
--opset-version ${OPSET_VERSION} \
--dynamic-shape \
--show \
--simplify \
--verify \
```
Description of all arguments:
- `config` : The path of a model config file.
- `--checkpoint` : The path of a model checkpoint file.
- `--output-file`: The path of output ONNX model. If not specified, it will be set to `tmp.onnx`.
- `--shape`: The height and width of input tensor to the model. If not specified, it will be set to `224 224`.
- `--opset-version` : The opset version of ONNX. If not specified, it will be set to `11`.
- `--dynamic-shape` : Determines whether to export ONNX with dynamic input shape. If not specified, it will be set to `False`.
- `--show`: Determines whether to print the architecture of the exported model. If not specified, it will be set to `False`.
- `--simplify`: Determines whether to simplify the exported ONNX model. If not specified, it will be set to `False`.
- `--verify`: Determines whether to verify the correctness of an exported model. If not specified, it will be set to `False`.
Example:
```bash
python tools/pytorch2onnx.py \
configs/resnet/resnet18_b16x8_cifar10.py \
--checkpoint checkpoints/resnet/resnet18_b16x8_cifar10.pth \
--output-file checkpoints/resnet/resnet18_b16x8_cifar10.onnx \
--dynamic-shape \
--show \
--simplify \
--verify \
```
## List of supported models exportable to ONNX
The table below lists the models that are guaranteed to be exportable to ONNX and runnable in ONNX Runtime.
| Model | Config | Batch Inference | Dynamic Shape | Note |
| :----------: | :----------------------------------------------------------: | :-------------: | :-----------: | ---- |
| MobileNetV2 | `configs/mobilenet_v2/mobilenet_v2_b32x8_imagenet.py` | Y | Y | |
| ResNet | `configs/resnet/resnet18_b16x8_cifar10.py` | Y | Y | |
| ResNeXt | `configs/resnext/resnext50_32x4d_b32x8_imagenet.py` | Y | Y | |
| SE-ResNet | `configs/seresnet/seresnet50_b32x8_imagenet.py` | Y | Y | |
| ShuffleNetV1 | `configs/shufflenet_v1/shufflenet_v1_1x_b64x16_linearlr_bn_nowd_imagenet.py` | Y | Y | |
| ShuffleNetV2 | `configs/shufflenet_v2/shufflenet_v2_1x_b64x16_linearlr_bn_nowd_imagenet.py` | Y | Y | |
Notes:
- *All models above are tested with Pytorch==1.6.0*
## Reminders
- If you meet any problem with the listed models above, please create an issue and it would be taken care of soon. For models not included in the list, please try to dig a little deeper and debug a little bit more and hopefully solve them by yourself.
## FAQs
- None
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