Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add backbone doc for mmpretrain #78

Open
wants to merge 1 commit into
base: mmsig
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
315 changes: 314 additions & 1 deletion mm/mmpretrain/backbone.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,315 @@
# 骨干网络贡献指南(建设中)
# 骨干网络贡献指南

本教程旨在为用户在 MMPreTrain 上支持骨干网络提供全流程支持, 骨干网络的支持不要求复现训练精度,对齐推理精度即可。

主要分为准备阶段,实现阶段,收尾阶段和最后的发起PR:

## 准备阶段

在该阶段重点完成 原始论文的精读,研究原始代码实现,以及对 MMPreTrain 框架的熟悉

### 1. 原始论文精读

在进行算法复现之前,我们推荐对原始论文进行精读,重点关注以下几部分内容:

- 了解模型结构的细节,我们推荐你带着如下问题去阅读论文
- 模型整体结构是什么样的
- 模型结构有哪些 Block 或者 Layer
- 该模型是否使用了自定义的算子
- 了解模型所使用的的数据集
- 该论文是否是在 ImageNet 数据集进行测试
- 该论文是否使用了其他数据集
- 了解模型所用的评测指标是什么
- 分类常用的指标为 Top-1/5 Accuracy, 目前 MMPreTrain 已支持该指标

### 2. 原始代码研读(如有)

当你已完成论文的研读,建议在对模型有基本了解的基础上,结合原始代码了解模型细节,重点关注一下两个部分

- 模型结构的代码实现
- 推理时的数据处理方式
- 了解模型推理阶段的数据处理策略
- 推理时使用的图片尺寸,是224,还是256,还是其他自定义尺寸?
- 使用什么样的数据处理方法(包括 Resize 和 Crop)
- Rssize 时使用的怎样的差值算法,使用的后端是 opencv 还是 PIL?

### 3. 了解 MMPreTrain 算法库

接下来,请参考以下资料,熟悉 MMPreTrain 算法库

- 结合 MMPreTrain 文档,研究 MMPreTrain 的基本使用方法
- 尝试进行 model zoo 中某个模型的训练和推理

## 实现阶段

1. 开发流程

首先,将 MMPreTrain 代码库 **fork** 一份到自己的 github 账户下,**clone** 自己账户下的 MMPreTrain repo,并 **checkout** 出一个新的分支,在新分支下进行新算法代码的实现。

```
git clone https://github.com/your_github_name/mmpretrain.git
cd mmpretrain/
git checkout dev
git checkout -b add_new_net # 分支名可以任意取,但最高有辨识度
```

2. 定义模型

模型结构主要在 `mmpretrain/models` 下进行定义,其文件结构如下所示:

```{text}
mmpretrain/models/
├── __init__.py
├── backbones/ # 定义整体的模型结构
├── classifiers/ # 分类器高阶函数,组装 backbone, neck, head 在一起
├── heads/
├── losses/
├── necks/
└── .......
```

假设我们要复现的模型为 NewNet ,一个典型的流程是:

- 在 `mmpretrain/models/backbone` 下新建一个 python 文件 newnet.py
- 在 newnet.py 中定义模型结构,我们推荐依据模型结构,参考对应的经典模型的实现,来进行定义网络,如:
- resnet.py
- vision_transformer.py
- swin_transformer.py
- 在定义过程中,对于一些常见的 Layer 或者 Block,可以优先使用 MMPreTrain 定义的结构(在 `mmpretrain/models/utils/` 文件下)

```
mmpretrain/models/utils/
├── __init__.py
├── attention.py
├── augment/
├── channel_shuffle.py
├── embed.py
├── helpers.py
├── inverted_residual.py
├── make_divisible.py
├── position_encoding.py
└── se_layer.py
```

当你完成模型的定义后,请在 [`/mmpretrain/models/backbones/__init__.py`](https://github.com/open-mmlab/mmpretrain/blob/main/mmpretrain/models/__init__.py) 中 import 定义的 NewNet,以完成模型的注册。

```python
........
from .newnet import NewNet
__all__ = [
....
'NewNet'
]
```

3. 配置文件

如果对MMPreTrain的配置文件不熟悉,可以阅读[相关文档](https://mmpretrain.readthedocs.io/en/latest/user_guides/config.html)学习 OpenMMLab 的 Config 机制。

**添加新的配置文件时,建议基于已有的算法配置,直接替换model的设置,让其可以运行起来。**

为了能够进行模型的推理,我们需要在 `configs/` 中加入新模型的config文件夹。

```{text}
#当前configs的文件目录如下:
configs/
├── _base_/
│ ├── datasets/ # 数据集相关,找一个与支持模型相近的使用, 常用的有 resnet, ViT, Swin, ConvNext。
│ ├── default_runtime.py # 默认运行设置,支持推理时不用管
│ └── schedules/ # 训练优化设置, 支持推理时不用管
├── resnet/
│ ├── README.md
│ ├── resnet50_8xb32_in1k.py
│ └── ......
├── convnext/
│ ├── README.md
│ ├── convnext-base_32xb128_in1k-384px.py
│ └── ............
├── ......
└── ......
```

在 configs 目录下下新建一个新模型的文件夹,在其中定义各个具体尺寸或配置的模型,如 [`configs/riformer/`](https://github.com/open-mmlab/mmpretrain/tree/main/configs/riformer) 所示:

```
configs/convnext/
├── README.md # 模型的整体介绍,模型的可用模型的整理,
├── riformer-m36_8xb128_in1k.py
├── riformer-m36_8xb64_in1k-384px.py
├── riformer-m48_8xb64_in1k-384px.py
├── riformer-m48_8xb64_in1k.py
├── c.......
└── metafile.yml # 该模型的各个配置的模型信息汇总,方便统一管理
```

我们以 [`configs/riformer/riformer-m48_8xb64_in1k.py`](https://github.com/open-mmlab/mmpretrain/blob/main/configs/riformer/riformer-m48_8xb64_in1k.py) 为例解释其内容:

```python
# _base_ 中直接导入 configs/_base_ 里已经写好的结构。细心的同学会发现,这里是直接复制 poolformer 的内容
_base_ = [
'../_base_/datasets/imagenet_bs128_poolformer_medium_224.py',
'../_base_/schedules/imagenet_bs1024_adamw_swin.py',
'../_base_/default_runtime.py',
]
# Model settings 这里定义了推理模型的结构
model = dict(
type='ImageClassifier',
backbone=dict(
type='RIFormer',
arch='m48',
drop_path_rate=0.1,
init_cfg=[
dict(
type='TruncNormal',
layer=['Conv2d', 'Linear'],
std=.02,
bias=0.),
dict(type='Constant', layer=['GroupNorm'], val=1., bias=0.),
]),
neck=dict(type='GlobalAveragePooling'),
head=dict(
type='LinearClsHead',
num_classes=1000,
in_channels=768,
loss=dict(type='CrossEntropyLoss', loss_weight=1.0),
))
# 下面是一些训练时的配置,在对齐推理精度时可以忽略
# schedule settings
optim_wrapper = dict(
optimizer=dict(lr=4e-3),
clip_grad=dict(max_norm=5.0),
)
# NOTE: `auto_scale_lr` is for automatically scaling LR
# based on the actual training batch size.
# base_batch_size = (32 GPUs) x (128 samples per GPU)
auto_scale_lr = dict(base_batch_size=4096)
```

它仿照 PoolFormer 的结构,仅仅只修改了 `model`, 基于已经有的算法配置,将 `model` 替换成新的主干网络是最简便的方式。

4. 权重转换

当你完成模型的配置文件构建时,距离模型的推理对齐,又近了一步。此时,为了获得 MMPreTrain 可以使用的模型,你需要完成以下几步:

- 下载官方提供的推理模型
- 参考 [`tools/convert_models`](https://github.com/open-mmlab/mmpretrain/tree/main/tools/model_converters) 中写xxx_to_mmpretrain.py,实现待复现模型的权重转换脚本,在这个过程中,你需要先使用前面实现的配置文件和模型结构,来启动一次推理任务,进而获得模型参数在 mmpretrain 中的name和shape,方便对官方模型进行转换。
- 在对齐过程中,可以使用 [`.dev_scripts/ckpt_tree.py`](https://github.com/open-mmlab/mmpretrain/blob/main/.dev_scripts/ckpt_tree.py) 帮助你查看模型权重中的键名。

```{text}
tools/convert_models
├── efficientnet_to_mmcls.py # mmpretrain 以前叫 mmcls
├── mlpmixer_to_mmcls.py
├── mobilenetv2_to_mmcls.py
├── publish_model.py
├── reparameterize_model.py
├── reparameterize_repvgg.py
├── repvgg_to_mmcls.py
├── shufflenetv2_to_mmcls.py
├── torchvision_to_mmcls.py
├── twins2mmcls.py
├── van2mmcls.py
└── vgg_to_mmcls.py
```

5. 对齐推理精度

如果你要复现的模型使用的是标准 ImageNet 数据集,常用的推理阶段数据流水线如下:

```
test_pipeline = [
dict(type='LoadImageFromFile'),
dict(type='ResizeEdge', scale=256, edge='short'), # 缩放短边至某一长度
dict(type='CenterCrop', crop_size=224), # 从图像中心裁剪某一尺寸图像
dict(type='PackClsInputs'),
]
```

需要注意几点:

- 缩放短边时的短边尺寸
- CenterCrop 时的图像尺寸
- 缩放时所使用的具体方法,比如官方代码使用 torchvision 的 transform 进行数据处理,则会使用 pillow 进行缩放,此时应当设置 ResizeEdge 参数 backend='pillow';如果官方代码缩放时指定了缩放算法, 如 bicubic,则还应当设置 ResizeEdge 参数 interpolation='bicubic'。

在完成模型的定义,配置文件构建以及权重转换之后,即可使用tools中的工具进行模型的推理,对齐模型精度

## 收尾阶段

这部分选做,做完上面部分可以发起 PR, Reviewer 会及时反馈。

1. Metafile构建

Metafile 是为 MMPreTrain 统一管理支持的算法,因此,我们要求在复现模型的最好需要为模型撰写metafile,可以查看 [ConvNeXt](https://github.com/open-mmlab/mmpretrain/blob/main/configs/convnext/metafile.yml) 的例子:

主要由两部分构成:

- Collections:一般一篇论文相关的模型会放在一个合集里

- Name:合集名称,一般为对应算法简称
- Metadata(可选):所有模型共用的一些具体信息,在合集中主要包括
- Training Data:训练所使用的数据集
- Architecture:模型包含的结构(只列举主要的一些结构即可,名称可以参考 https://paperswithcode.com/methods)
- Paper:论文信息
- URL:论文摘要页,一般为 Arxiv 链接
- Title:论文标题
- README:与该 metafile 相关联的算法 readme 文件路径
- Code:
- Version:代码实现所在的版本,一般为下一次发版的版本
- URL:主干网络代码链接

- Models:主要包括各个模型信息,一般一个 checkpoint 对应一个模型

- Name:模型名称,命名规则参见 配置文件命名规则
- Metadata:模型的一些具体信息,主要包括
- FLOPs:模型 FLOPs 指标, 开始可空着,后面有工具批量计算
- Parameters:模型参数数量, 开始可空着,后面有工具批量计算
- Training Data:如果该模型使用的训练数据集与 Collection 中指定的不一致,则可以在这里覆写
- In Collection:模型所在合集
- Results:模型指标信息
- Dataset:评测该模型使用的数据集
- Metrics:评测结果,一般包括 Top 1 Accuracy 和 Top 5 Accuracy
- Task:评测任务,一般为 Image Classification
- Weights:权重文件下载链接(将权重文件或者权重转换脚本发给 maintainer 即可)
- Config:模型对应的配置文件路径
- Converted From(可选):如果该模型是通过官方模型转权重获得的,需要填写这部分
- Weight:官方权重下载路径
- Code:官方代码路径

2. 加入 `model-index.yml` 中

最后,需要将该 metafile 文件的路径添加至根目录下的 [model-index.yml](https://github.com/open-mmlab/mmpretrain/blob/main/model-index.yml) 中

3. 模型数据分析

为了获得所复现算法的各个尺寸模型的FLOPs和 Parameters,我们提供了如下工具:

如果你已经编写了上述 metafile 并加入了 model-index.yml,可以使用 [.dev_scripts/benchmark_regression/1-benchmark_valid.py](https://github.com/open-mmlab/mmpretrain/blob/main/.dev_scripts/benchmark_regression/1-benchmark_valid.py) 批量计算

`python .dev_scripts/benchmark_regression/1-benchmark_valid.py --models xxx --flops`

如果没有加入 metafile,可以使用 [tools/analysis_tools/get_flops.py](https://github.com/open-mmlab/mmpretrain/blob/main/tools/analysis_tools/get_flops.py) 计算某个配置文件的参数:

`python tools/analysis_tools/get_flops.py ${配置文件}`

4. 格式检测单元测试

在完成模型推理和metafile构建之后,请对所有的代码和文档进行格式检测,我们使用pre-commit hooks进行格式检查,可使用如下步骤:

```
# 格式检查
pip install pre-commit
pre-commit install
pre-commit run --all-files
```

5. 单元测试

添加相关模型的单元测试, 如果已经配置了相关 metafile,可以直接指定模型名进行测试,直接在 [test_list](https://github.com/open-mmlab/mmpretrain/blob/e80418a424aaefb81c95df458216bb3e9af246c4/tests/test_models/test_models.py#L22) 中添加相关链接。

## 发起PR

恭喜你,你已经完成了所有步骤,最后就是发起PR了!!!

此时将对代码的修改进行commit,并提起pull request(PR),同时指定相关同学进行code review,根据review意见修改代码。

当 reviewer 同意你的 PR 后,就会合并进 `dev`, 等待后续的新版本发布,一般每一个月都会发布一个版本。