Initial snapshot: hand motion pipeline (Dyn-HaMR + dex-retargeting + SPIDER)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-15 14:13:49 +08:00
commit 7e4ef6f98b
7002 changed files with 1452249 additions and 0 deletions
@@ -0,0 +1,20 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
@@ -0,0 +1,6 @@
.header-logo {
background-image: url("../images/mmpose-logo.png");
background-size: 120px 50px;
height: 50px;
width: 120px;
}
+109
View File
@@ -0,0 +1,109 @@
mmpose.apis
-------------
.. automodule:: mmpose.apis
:members:
mmpose.core
-------------
evaluation
^^^^^^^^^^^
.. automodule:: mmpose.core.evaluation
:members:
fp16
^^^^^^^^^^^
.. automodule:: mmpose.core.fp16
:members:
utils
^^^^^^^^^^^
.. automodule:: mmpose.core.utils
:members:
post_processing
^^^^^^^^^^^^^^^^
.. automodule:: mmpose.core.post_processing
:members:
mmpose.models
---------------
backbones
^^^^^^^^^^^
.. automodule:: mmpose.models.backbones
:members:
necks
^^^^^^^^^^^
.. automodule:: mmpose.models.necks
:members:
detectors
^^^^^^^^^^^
.. automodule:: mmpose.models.detectors
:members:
heads
^^^^^^^^^^^^^^^
.. automodule:: mmpose.models.heads
:members:
losses
^^^^^^^^^^^
.. automodule:: mmpose.models.losses
:members:
misc
^^^^^^^^^^^
.. automodule:: mmpose.models.misc
:members:
mmpose.datasets
-----------------
.. automodule:: mmpose.datasets
:members:
datasets
^^^^^^^^^^^
.. automodule:: mmpose.datasets.datasets.top_down
:members:
.. automodule:: mmpose.datasets.datasets.bottom_up
:members:
pipelines
^^^^^^^^^^^
.. automodule:: mmpose.datasets.pipelines
:members:
.. automodule:: mmpose.datasets.pipelines.loading
:members:
.. automodule:: mmpose.datasets.pipelines.shared_transform
:members:
.. automodule:: mmpose.datasets.pipelines.top_down_transform
:members:
.. automodule:: mmpose.datasets.pipelines.bottom_up_transform
:members:
.. automodule:: mmpose.datasets.pipelines.mesh_transform
:members:
.. automodule:: mmpose.datasets.pipelines.pose3d_transform
:members:
samplers
^^^^^^^^^^^
.. automodule:: mmpose.datasets.samplers
:members:
mmpose.utils
---------------
.. automodule:: mmpose.utils
:members:
@@ -0,0 +1,3 @@
# 基准测试
内容建设中……
+101
View File
@@ -0,0 +1,101 @@
#!/usr/bin/env python
# Copyright (c) OpenMMLab. All rights reserved.
import os
import re
from glob import glob
from titlecase import titlecase
os.makedirs('topics', exist_ok=True)
os.makedirs('papers', exist_ok=True)
# Step 1: get subtopics: a mix of topic and task
minisections = [
x.split('/')[-2:] for x in glob('../../configs/*/*') if '_base_' not in x
]
alltopics = sorted(list(set(x[0] for x in minisections)))
subtopics = []
for t in alltopics:
data = [x[1].split('_') for x in minisections if x[0] == t]
valid_ids = []
for i in range(len(data[0])):
if len(set(x[i] for x in data)) > 1:
valid_ids.append(i)
if len(valid_ids) > 0:
subtopics.extend([
f"{titlecase(t)}({','.join([d[i].title() for i in valid_ids])})",
t, '_'.join(d)
] for d in data)
else:
subtopics.append([titlecase(t), t, '_'.join(data[0])])
contents = {}
for subtopic, topic, task in sorted(subtopics):
# Step 2: get all datasets
datasets = sorted(
list(
set(
x.split('/')[-2]
for x in glob(f'../../configs/{topic}/{task}/*/*/'))))
contents[subtopic] = {d: {} for d in datasets}
for dataset in datasets:
# Step 3: get all settings: algorithm + backbone + trick
for file in glob(f'../../configs/{topic}/{task}/*/{dataset}/*.md'):
keywords = (file.split('/')[-3],
*file.split('/')[-1].split('_')[:-1])
with open(file, 'r') as f:
contents[subtopic][dataset][keywords] = f.read()
# Step 4: write files by topic
for subtopic, datasets in contents.items():
lines = [f'# {subtopic}', '']
for dataset, keywords in datasets.items():
if len(keywords) == 0:
continue
lines += [
'<hr/>', '<br/><br/>', '', f'## {titlecase(dataset)} Dataset', ''
]
for keyword, info in keywords.items():
keyword_strs = [titlecase(x.replace('_', ' ')) for x in keyword]
lines += [
'<br/>', '',
(f'### {" + ".join(keyword_strs)}'
f' on {titlecase(dataset)}'), '', info, ''
]
with open(f'topics/{subtopic.lower()}.md', 'w') as f:
f.write('\n'.join(lines))
# Step 5: write files by paper
allfiles = [x.split('/')[-2:] for x in glob('../en/papers/*/*.md')]
sections = sorted(list(set(x[0] for x in allfiles)))
for section in sections:
lines = [f'# {titlecase(section)}', '']
files = [f for s, f in allfiles if s == section]
for file in files:
with open(f'../en/papers/{section}/{file}', 'r') as f:
keyline = [
line for line in f.readlines() if line.startswith('<summary')
][0]
papername = re.sub(r'\<.*?\>', '', keyline).strip()
paperlines = []
for subtopic, datasets in contents.items():
for dataset, keywords in datasets.items():
keywords = {k: v for k, v in keywords.items() if keyline in v}
if len(keywords) == 0:
continue
for keyword, info in keywords.items():
keyword_strs = [
titlecase(x.replace('_', ' ')) for x in keyword
]
paperlines += [
'<br/>', '',
(f'### {" + ".join(keyword_strs)}'
f' on {titlecase(dataset)}'), '', info, ''
]
if len(paperlines) > 0:
lines += ['<hr/>', '<br/><br/>', '', f'## {papername}', '']
lines += paperlines
with open(f'papers/{section}.md', 'w') as f:
f.write('\n'.join(lines))
+112
View File
@@ -0,0 +1,112 @@
# Copyright (c) OpenMMLab. All rights reserved.
# 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
import pytorch_sphinx_theme
sys.path.insert(0, os.path.abspath('../..'))
# -- Project information -----------------------------------------------------
project = 'MMPose'
copyright = '2020-2021, OpenMMLab'
author = 'MMPose Authors'
# The full version, including alpha/beta/rc tags
version_file = '../../mmpose/version.py'
def get_version():
with open(version_file, 'r') as f:
exec(compile(f.read(), version_file, 'exec'))
return locals()['__version__']
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',
'sphinx_markdown_tables', 'sphinx_copybutton', 'myst_parser'
]
autodoc_mock_imports = ['json_tricks', 'mmpose.version']
# Ignore >>> when copying code
copybutton_prompt_text = r'>>> |\.\.\. '
copybutton_prompt_is_regexp = True
# 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 = 'pytorch_sphinx_theme'
html_theme_path = [pytorch_sphinx_theme.get_html_theme_path()]
html_theme_options = {
'menu': [{
'name':
'教程',
'url':
'https://colab.research.google.com/github/'
'open-mmlab/mmpose/blob/master/demo/MMPose_Tutorial.ipynb'
}, {
'name': 'GitHub',
'url': 'https://github.com/open-mmlab/mmpose'
}],
'menu_lang':
'cn'
}
# 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".
language = 'zh_CN'
html_static_path = ['_static']
html_css_files = ['css/readthedocs.css']
# Enable ::: for my_st
myst_enable_extensions = ['colon_fence']
master_doc = 'index'
def builder_inited_handler(app):
subprocess.run(['./collect.py'])
subprocess.run(['./merge_docs.sh'])
subprocess.run(['./stats.py'])
def setup(app):
app.connect('builder-inited', builder_inited_handler)
@@ -0,0 +1,13 @@
# 准备数据集
MMPose支持多种姿态估计任务,对应的数据集准备方法请参考下列文档。
- [2D人体关键点](tasks/2d_body_keypoint.md)
- [3D人体关键点](tasks/3d_body_keypoint.md)
- [3D人体网格模型](tasks/3d_body_mesh.md)
- [2D手部关键点](tasks/2d_hand_keypoint.md)
- [3D手部关键点](tasks/3d_hand_keypoint.md)
- [2D人脸关键点](tasks/2d_face_keypoint.md)
- [2D全身人体关键点](tasks/2d_wholebody_keypoint.md)
- [2D服装关键点](tasks/2d_fashion_landmark.md)
- [2D动物关键点](tasks/2d_animal_keypoint.md)
@@ -0,0 +1,3 @@
# 常见问题
内容建设中……
@@ -0,0 +1,270 @@
# 基础教程
本文档提供 MMPose 的基础使用教程。请先参阅 [安装指南](install.md),进行 MMPose 的安装。
<!-- TOC -->
- [准备数据集](#准备数据集)
- [使用预训练模型进行推理](#使用预训练模型进行推理)
- [测试某个数据集](#测试某个数据集)
- [运行演示](#运行演示)
- [如何训练模型](#如何训练模型)
- [使用单个 GPU 训练](#使用单个-GPU-训练)
- [使用 CPU 训练](#使用-CPU-训练)
- [使用多个 GPU 训练](#使用多个-GPU-训练)
- [使用多台机器训练](#使用多台机器训练)
- [使用单台机器启动多个任务](#使用单台机器启动多个任务)
- [基准测试](#基准测试)
- [进阶教程](#进阶教程)
<!-- TOC -->
## 准备数据集
MMPose 支持各种不同的任务。请根据需要,查阅对应的数据集准备教程。
- [2D 人体关键点检测](/docs/zh_cn/tasks/2d_body_keypoint.md)
- [3D 人体关键点检测](/docs/zh_cn/tasks/3d_body_keypoint.md)
- [3D 人体形状恢复](/docs/zh_cn/tasks/3d_body_mesh.md)
- [2D 人手关键点检测](/docs/zh_cn/tasks/2d_hand_keypoint.md)
- [3D 人手关键点检测](/docs/zh_cn/tasks/3d_hand_keypoint.md)
- [2D 人脸关键点检测](/docs/zh_cn/tasks/2d_face_keypoint.md)
- [2D 全身人体关键点检测](/docs/zh_cn/tasks/2d_wholebody_keypoint.md)
- [2D 服饰关键点检测](/docs/zh_cn/tasks/2d_fashion_landmark.md)
- [2D 动物关键点检测](/docs/zh_cn/tasks/2d_animal_keypoint.md)
## 使用预训练模型进行推理
MMPose 提供了一些测试脚本用于测试数据集上的指标(如 COCO, MPII 等),
并提供了一些高级 API,使您可以轻松使用 MMPose。
### 测试某个数据集
- [x] 单 GPU 测试
- [x] CPU 测试
- [x] 单节点多 GPU 测试
- [x] 多节点测试
用户可使用以下命令测试数据集
```shell
# 单 GPU 测试
python tools/test.py ${CONFIG_FILE} ${CHECKPOINT_FILE} [--out ${RESULT_FILE}] [--fuse-conv-bn] \
[--eval ${EVAL_METRICS}] [--gpu_collect] [--tmpdir ${TMPDIR}] [--cfg-options ${CFG_OPTIONS}] \
[--launcher ${JOB_LAUNCHER}] [--local_rank ${LOCAL_RANK}]
# CPU 测试:禁用 GPU 并运行测试脚本
export CUDA_VISIBLE_DEVICES=-1
python tools/test.py ${CONFIG_FILE} ${CHECKPOINT_FILE} [--out ${RESULT_FILE}] \
[--eval ${EVAL_METRICS}]
# 多 GPU 测试
./tools/dist_test.sh ${CONFIG_FILE} ${CHECKPOINT_FILE} ${GPU_NUM} [--out ${RESULT_FILE}] [--eval ${EVAL_METRICS}] \
[--gpu-collect] [--tmpdir ${TMPDIR}] [--options ${OPTIONS}] [--average-clips ${AVG_TYPE}] \
[--launcher ${JOB_LAUNCHER}] [--local_rank ${LOCAL_RANK}]
```
此处的 `CHECKPOINT_FILE` 可以是本地的模型权重文件的路径,也可以是模型的下载链接。
可选参数:
- `RESULT_FILE`:输出结果文件名。如果没有被指定,则不会保存测试结果。
- `--fuse-conv-bn`: 是否融合 BN 和 Conv 层。该操作会略微提升模型推理速度。
- `EVAL_METRICS`:测试指标。其可选值与对应数据集相关,如 `mAP`,适用于 COCO 等数据集,`PCK` `AUC` `EPE` 适用于 OneHand10K 等数据集等。
- `--gpu-collect`:如果被指定,姿态估计结果将会通过 GPU 通信进行收集。否则,它将被存储到不同 GPU 上的 `TMPDIR` 文件夹中,并在 rank 0 的进程中被收集。
- `TMPDIR`:用于存储不同进程收集的结果文件的临时文件夹。该变量仅当 `--gpu-collect` 没有被指定时有效。
- `CFG_OPTIONS`:覆盖配置文件中的一些实验设置。比如,可以设置'--cfg-options model.backbone.depth=18 model.backbone.with_cp=True',在线修改配置文件内容。
- `JOB_LAUNCHER`:分布式任务初始化启动器选项。可选值有 `none`,`pytorch`,`slurm`,`mpi`。特别地,如果被设置为 `none`, 则会以非分布式模式进行测试。
- `LOCAL_RANK`:本地 rank 的 ID。如果没有被指定,则会被设置为 0。
例子:
假定用户将下载的模型权重文件放置在 `checkpoints/` 目录下。
1. 在 COCO 数据集下测试 ResNet50(不存储测试结果为文件),并验证 `mAP` 指标
```shell
./tools/dist_test.sh configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/res50_coco_256x192.py \
checkpoints/SOME_CHECKPOINT.pth 1 \
--eval mAP
```
1. 使用 8 块 GPU 在 COCO 数据集下测试 ResNet。在线下载模型权重,并验证 `mAP` 指标。
```shell
./tools/dist_test.sh configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/res50_coco_256x192.py \
https://download.openmmlab.com/mmpose/top_down/resnet/res50_coco_256x192-ec54d7f3_20200709.pth 8 \
--eval mAP
```
1. 在 slurm 分布式环境中测试 ResNet50 在 COCO 数据集下的 `mAP` 指标
```shell
./tools/slurm_test.sh slurm_partition test_job \
configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/res50_coco_256x192.py \
checkpoints/SOME_CHECKPOINT.pth \
--eval mAP
```
### 运行演示
我们提供了丰富的脚本,方便大家快速运行演示。
下面是 多人人体姿态估计 的演示示例,此处我们使用了人工标注的人体框作为输入。
```shell
python demo/top_down_img_demo.py \
${MMPOSE_CONFIG_FILE} ${MMPOSE_CHECKPOINT_FILE} \
--img-root ${IMG_ROOT} --json-file ${JSON_FILE} \
--out-img-root ${OUTPUT_DIR} \
[--show --device ${GPU_ID}] \
[--kpt-thr ${KPT_SCORE_THR}]
```
例子:
```shell
python demo/top_down_img_demo.py \
configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/hrnet_w48_coco_256x192.py \
https://download.openmmlab.com/mmpose/top_down/hrnet/hrnet_w48_coco_256x192-b9e0b3ab_20200708.pth \
--img-root tests/data/coco/ --json-file tests/data/coco/test_coco.json \
--out-img-root vis_results
```
更多实例和细节可以查看 [demo文件夹](/demo) 和 [demo文档](https://mmpose.readthedocs.io/en/latest/demo.html)。
## 如何训练模型
MMPose 使用 `MMDistributedDataParallel` 进行分布式训练,使用 `MMDataParallel` 进行非分布式训练。
对于单机多卡与多台机器的情况,MMPose 使用分布式训练。假设服务器有 8 块 GPU,则会启动 8 个进程,并且每台 GPU 对应一个进程。
每个进程拥有一个独立的模型,以及对应的数据加载器和优化器。
模型参数同步只发生于最开始。之后,每经过一次前向与后向计算,所有 GPU 中梯度都执行一次 allreduce 操作,而后优化器将更新模型参数。
由于梯度执行了 allreduce 操作,因此不同 GPU 中模型参数将保持一致。
### 训练配置
所有的输出(日志文件和模型权重文件)会被将保存到工作目录下。工作目录通过配置文件中的参数 `work_dir` 指定。
默认情况下,MMPose 在每轮训练轮后会在验证集上评估模型,可以通过在训练配置中修改 `interval` 参数来更改评估间隔
```python
evaluation = dict(interval=5) # 每 5 轮训练进行一次模型评估
```
根据 [Linear Scaling Rule](https://arxiv.org/abs/1706.02677),当 GPU 数量或每个 GPU 上的视频批大小改变时,用户可根据批大小按比例地调整学习率,如,当 4 GPUs x 2 video/gpu 时,lr=0.01;当 16 GPUs x 4 video/gpu 时,lr=0.08。
### 使用单个 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 训练脚本即可。
**注意**:
我们不推荐用户使用 CPU 进行训练,这太过缓慢。我们支持这个功能是为了方便用户在没有 GPU 的机器上进行调试。
### 使用多个 GPU 训练
```shell
./tools/dist_train.sh ${CONFIG_FILE} ${GPU_NUM} [optional arguments]
```
可选参数为:
- `--work-dir ${WORK_DIR}`:覆盖配置文件中指定的工作目录。
- `--resume-from ${CHECKPOINT_FILE}`:从以前的模型权重文件恢复训练。
- `--no-validate`: 在训练过程中,不进行验证。
- `--gpus ${GPU_NUM}`:使用的 GPU 数量,仅适用于非分布式训练。
- `--gpu-ids ${GPU_IDS}`:使用的 GPU ID,仅适用于非分布式训练。
- `--seed ${SEED}`:设置 python,numpy 和 pytorch 里的种子 ID,已用于生成随机数。
- `--deterministic`:如果被指定,程序将设置 CUDNN 后端的确定化选项。
- `--cfg-options CFG_OPTIONS`:覆盖配置文件中的一些实验设置。比如,可以设置'--cfg-options model.backbone.depth=18 model.backbone.with_cp=True',在线修改配置文件内容。
- `--launcher ${JOB_LAUNCHER}`:分布式任务初始化启动器选项。可选值有 `none`,`pytorch`,`slurm`,`mpi`。特别地,如果被设置为 `none`, 则会以非分布式模式进行测试。
- `--autoscale-lr`:根据 [Linear Scaling Rule](https://arxiv.org/abs/1706.02677),当 GPU 数量或每个 GPU 上的视频批大小改变时,用户可根据批大小按比例地调整学习率。
- `LOCAL_RANK`:本地 rank 的 ID。如果没有被指定,则会被设置为 0。
`resume-from` 和 `load-from` 的区别:
`resume-from` 加载模型参数和优化器状态,并且保留检查点所在的训练轮数,常被用于恢复意外被中断的训练。
`load-from` 只加载模型参数,但训练轮数从 0 开始计数,常被用于微调模型。
这里提供一个使用 8 块 GPU 加载 ResNet50 模型权重文件的例子。
```shell
./tools/dist_train.sh configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/res50_coco_256x192.py 8 --resume_from work_dirs/res50_coco_256x192/latest.pth
```
### 使用多台机器训练
如果用户在 [slurm](https://slurm.schedmd.com/) 集群上运行 MMPose,可使用 `slurm_train.sh` 脚本。(该脚本也支持单台机器上训练)
```shell
[GPUS=${GPUS}] ./tools/slurm_train.sh ${PARTITION} ${JOB_NAME} ${CONFIG_FILE} [--work-dir ${WORK_DIR}]
```
这里给出一个在 slurm 集群上的 dev 分区使用 16 块 GPU 训练 ResNet50 的例子。
使用 `GPUS_PER_NODE=8` 参数来指定一个有 8 块 GPUS 的 slurm 集群节点,使用 `CPUS_PER_TASK=2` 来指定每个任务拥有2块cpu。
```shell
GPUS=16 GPUS_PER_NODE=8 CPUS_PER_TASK=2 ./tools/slurm_train.sh Test res50 configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/res50_coco_256x192.py work_dirs/res50_coco_256x192
```
用户可以查看 [slurm_train.sh](/tools/slurm_train.sh) 文件来检查完整的参数和环境变量。
如果用户的多台机器通过 Ethernet 连接,则可以参考 pytorch [launch utility](https://pytorch.org/docs/en/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 集群下启动多个训练任务,则需要修改配置文件(通常是配置文件的第 4 行)中的 `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 ${WORK_DIR}]
CUDA_VISIBLE_DEVICES=4,5,6,7 GPUS=4 ./tools/slurm_train.sh ${PARTITION} ${JOB_NAME} config2.py [--work-dir ${WORK_DIR}]
```
## 进阶教程
目前, MMPose 提供了以下更详细的教程:
- [如何编写配置文件](tutorials/0_config.md)
- [如何微调模型](tutorials/1_finetune.md)
- [如何增加新数据集](tutorials/2_new_dataset.md)
- [如何设计数据处理流程](tutorials/3_data_pipeline.md)
- [如何增加新模块](tutorials/4_new_modules.md)
- [如何导出模型为 onnx 格式](tutorials/5_export_model.md)
- [如何自定义模型运行参数](tutorials/6_customize_runtime.md)
@@ -0,0 +1,97 @@
欢迎来到 MMPose 中文文档!
==================================
您可以在页面左下角切换文档语言。
You can change the documentation language at the lower-left corner of the page.
.. toctree::
:maxdepth: 2
install.md
getting_started.md
demo.md
benchmark.md
inference_speed_summary.md
.. toctree::
:maxdepth: 2
:caption: 数据集
datasets.md
tasks/2d_body_keypoint.md
tasks/2d_wholebody_keypoint.md
tasks/2d_face_keypoint.md
tasks/2d_hand_keypoint.md
tasks/2d_fashion_landmark.md
tasks/2d_animal_keypoint.md
tasks/3d_body_keypoint.md
tasks/3d_body_mesh.md
tasks/3d_hand_keypoint.md
.. toctree::
:maxdepth: 2
:caption: 模型池
modelzoo.md
topics/animal.md
topics/body(2d,kpt,sview,img).md
topics/body(2d,kpt,sview,vid).md
topics/body(3d,kpt,sview,img).md
topics/body(3d,kpt,sview,vid).md
topics/body(3d,kpt,mview,img).md
topics/body(3d,mesh,sview,img).md
topics/face.md
topics/fashion.md
topics/hand(2d).md
topics/hand(3d).md
topics/wholebody.md
.. toctree::
:maxdepth: 2
:caption: 模型池(按论文整理)
papers/algorithms.md
papers/backbones.md
papers/datasets.md
papers/techniques.md
.. toctree::
:maxdepth: 2
:caption: 教程
tutorials/0_config.md
tutorials/1_finetune.md
tutorials/2_new_dataset.md
tutorials/3_data_pipeline.md
tutorials/4_new_modules.md
tutorials/5_export_model.md
tutorials/6_customize_runtime.md
.. toctree::
:maxdepth: 2
:caption: 常用工具
useful_tools.md
.. toctree::
:maxdepth: 2
:caption: Notes
faq.md
.. toctree::
:caption: API文档
api.rst
.. toctree::
:caption: 语言
Language.md
Indices and tables
==================
* :ref:`genindex`
* :ref:`search`
@@ -0,0 +1,114 @@
# 推理速度总结
这里总结了 MMPose 中主要模型的复杂度信息和推理速度,包括模型的计算复杂度、参数数量,以及以不同的批处理大小在 CPU 和 GPU 上的推理速度。还比较了不同模型在 COCO 人体关键点数据集上的全类别平均正确率,展示了模型性能和模型复杂度之间的折中。
## 比较规则
为了保证比较的公平性,在相同的硬件和软件环境下使用相同的数据集进行了比较实验。还列出了模型在 COCO 人体关键点数据集上的全类别平均正确率以及相应的配置文件。
对于模型复杂度信息,计算具有相应输入形状的模型的浮点数运算次数和参数数量。请注意,当前某些网络层或算子还未支持,如 `DeformConv2d` ,因此您可能需要检查是否所有操作都已支持,并验证浮点数运算次数和参数数量的计算是否正确。
对于推理速度,忽略了数据预处理的时间,只测量模型前向计算和数据后处理的时间。对于每个模型设置,保持相同的数据预处理方法,以确保相同的特征输入。分别测量了在 CPU 和 GPU 设备上的推理速度。对于自上而下的热图模型,我们还测试了批处理量较大(例如,10)情况,以测试拥挤场景下的模型性能。
推断速度是用每秒处理的帧数 (FPS) 来衡量的,即每秒模型的平均迭代次数,它可以显示模型处理输入的速度。这个数值越高,表示推理速度越快,模型性能越好。
### 硬件
- GPU: GeForce GTX 1660 SUPER
- CPU: Intel(R) Core(TM) i7-8700 CPU @ 3.20GHz
### 软件环境
- Ubuntu 16.04
- Python 3.8
- PyTorch 1.10
- CUDA 10.2
- mmcv-full 1.3.17
- mmpose 0.20.0
## MMPose 中主要模型的复杂度信息和推理速度总结
| Algorithm | Model | config | Input size | mAP | Flops (GFLOPs) | Params (M) | GPU Inference Speed<br>(FPS)<sup>1</sup> | GPU Inference Speed<br>(FPS, bs=10)<sup>2</sup> | CPU Inference Speed<br>(FPS) | CPU Inference Speed<br>(FPS, bs=10) |
| :--- | :---------------: | :-----------------: |:--------------------: | :----------------------------: | :-----------------: | :---------------: |:--------------------: | :----------------------------: | :-----------------: | :-----------------: |
| topdown_heatmap | Alexnet | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/alexnet_coco_256x192.py) | (3, 192, 256) | 0.397 | 1.42 | 5.62 | 229.21 ± 16.91 | 33.52 ± 1.14 | 13.92 ± 0.60 | 1.38 ± 0.02 |
| topdown_heatmap | CPM | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/cpm_coco_256x192.py) | (3, 192, 256) | 0.623 | 63.81 | 31.3 | 11.35 ± 0.22 | 3.87 ± 0.07 | 0.31 ± 0.01 | 0.03 ± 0.00 |
| topdown_heatmap | CPM | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/cpm_coco_384x288.py) | (3, 288, 384) | 0.65 | 143.57 | 31.3 | 7.09 ± 0.14 | 2.10 ± 0.05 | 0.14 ± 0.00 | 0.01 ± 0.00 |
| topdown_heatmap | Hourglass-52 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/hourglass52_coco_256x256.py) | (3, 256, 256) | 0.726 | 28.67 | 94.85 | 25.50 ± 1.68 | 3.99 ± 0.07 | 0.92 ± 0.03 | 0.09 ± 0.00 |
| topdown_heatmap | Hourglass-52 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/hourglass52_coco_384x384.py) | (3, 384, 384) | 0.746 | 64.5 | 94.85 | 14.74 ± 0.8 | 1.86 ± 0.06 | 0.43 ± 0.03 | 0.04 ± 0.00 |
| topdown_heatmap | HRNet-W32 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/hrnet_w32_coco_256x192.py) | (3, 192, 256) | 0.746 | 7.7 | 28.54 | 22.73 ± 1.12 | 6.60 ± 0.14 | 2.73 ± 0.11 | 0.32 ± 0.00 |
| topdown_heatmap | HRNet-W32 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/hrnet_w32_coco_384x288.py) | (3, 288, 384) | 0.76 | 17.33 | 28.54 | 22.78 ± 1.21 | 3.28 ± 0.08 | 1.35 ± 0.05 | 0.14 ± 0.00 |
| topdown_heatmap | HRNet-W48 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/hrnet_w48_coco_256x192.py) | (3, 192, 256) | 0.756 | 15.77 | 63.6 | 22.01 ± 1.10 | 3.74 ± 0.10 | 1.46 ± 0.05 | 0.16 ± 0.00 |
| topdown_heatmap | HRNet-W48 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/hrnet_w48_coco_384x288.py) | (3, 288, 384) | 0.767 | 35.48 | 63.6 | 15.03 ± 1.03 | 1.80 ± 0.03 | 0.68 ± 0.02 | 0.07 ± 0.00 |
| topdown_heatmap | LiteHRNet-30 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/litehrnet_30_coco_256x192.py) | (3, 192, 256) | 0.675 | 0.42 | 1.76 | 11.86 ± 0.38 | 9.77 ± 0.23 | 5.84 ± 0.39 | 0.80 ± 0.00 |
| topdown_heatmap | LiteHRNet-30 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/litehrnet_30_coco_384x288.py) | (3, 288, 384) | 0.7 | 0.95 | 1.76 | 11.52 ± 0.39 | 5.18 ± 0.11 | 3.45 ± 0.22 | 0.37 ± 0.00 |
| topdown_heatmap | MobilenetV2 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/mobilenetv2_coco_256x192.py) | (3, 192, 256) | 0.646 | 1.59 | 9.57 | 91.82 ± 10.98 | 17.85 ± 0.32 | 10.44 ± 0.80 | 1.05 ± 0.01 |
| topdown_heatmap | MobilenetV2 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/mobilenetv2_coco_384x288.py) | (3, 288, 384) | 0.673 | 3.57 | 9.57 | 71.27 ± 6.82 | 8.00 ± 0.15 | 5.01 ± 0.32 | 0.46 ± 0.00 |
| topdown_heatmap | MSPN-50 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/mspn50_coco_256x192.py) | (3, 192, 256) | 0.723 | 5.11 | 25.11 | 59.65 ± 3.74 | 9.51 ± 0.15 | 3.98 ± 0.21 | 0.43 ± 0.00 |
| topdown_heatmap | 2xMSPN-50 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/2xmspn50_coco_256x192.py) | (3, 192, 256) | 0.754 | 11.35 | 56.8 | 30.64 ± 2.61 | 4.74 ± 0.12 | 1.85 ± 0.08 | 0.20 ± 0.00 |
| topdown_heatmap | 3xMSPN-50 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/3xmspn50_coco_256x192.py) | (3, 192, 256) | 0.758 | 17.59 | 88.49 | 20.90 ± 1.82 | 3.22 ± 0.08 | 1.23 ± 0.04 | 0.13 ± 0.00 |
| topdown_heatmap | 4xMSPN-50 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/4xmspn50_coco_256x192.py) | (3, 192, 256) | 0.764 | 23.82 | 120.18 | 15.79 ± 1.14 | 2.45 ± 0.05 | 0.90 ± 0.03 | 0.10 ± 0.00 |
| topdown_heatmap | ResNest-50 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/resnest50_coco_256x192.py) | (3, 192, 256) | 0.721 | 6.73 | 35.93 | 48.36 ± 4.12 | 7.48 ± 0.13 | 3.00 ± 0.13 | 0.33 ± 0.00 |
| topdown_heatmap | ResNest-50 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/resnest50_coco_384x288.py) | (3, 288, 384) | 0.737 | 15.14 | 35.93 | 30.30 ± 2.30 | 3.62 ± 0.09 | 1.43 ± 0.05 | 0.13 ± 0.00 |
| topdown_heatmap | ResNest-101 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/resnest101_coco_256x192.py) | (3, 192, 256) | 0.725 | 10.38 | 56.61 | 29.21 ± 1.98 | 5.30 ± 0.12 | 2.01 ± 0.08 | 0.22 ± 0.00 |
| topdown_heatmap | ResNest-101 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/resnest101_coco_384x288.py) | (3, 288, 384) | 0.746 | 23.36 | 56.61 | 19.02 ± 1.40 | 2.59 ± 0.05 | 0.97 ± 0.03 | 0.09 ± 0.00 |
| topdown_heatmap | ResNest-200 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/resnest200_coco_256x192.py) | (3, 192, 256) | 0.732 | 17.5 | 78.54 | 16.11 ± 0.71 | 3.29 ± 0.07 | 1.33 ± 0.02 | 0.14 ± 0.00 |
| topdown_heatmap | ResNest-200 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/resnest200_coco_384x288.py) | (3, 288, 384) | 0.754 | 39.37 | 78.54 | 11.48 ± 0.68 | 1.58 ± 0.02 | 0.63 ± 0.01 | 0.06 ± 0.00 |
| topdown_heatmap | ResNest-269 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/resnest269_coco_256x192.py) | (3, 192, 256) | 0.738 | 22.45 | 119.27 | 12.02 ± 0.47 | 2.60 ± 0.05 | 1.03 ± 0.01 | 0.11 ± 0.00 |
| topdown_heatmap | ResNest-269 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/resnest269_coco_384x288.py) | (3, 288, 384) | 0.755 | 50.5 | 119.27 | 8.82 ± 0.42 | 1.24 ± 0.02 | 0.49 ± 0.01 | 0.05 ± 0.00 |
| topdown_heatmap | ResNet-50 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/res50_coco_256x192.py) | (3, 192, 256) | 0.718 | 5.46 | 34 | 64.23 ± 6.05 | 9.33 ± 0.21 | 4.00 ± 0.10 | 0.41 ± 0.00 |
| topdown_heatmap | ResNet-50 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/res50_coco_384x288.py) | (3, 288, 384) | 0.731 | 12.29 | 34 | 36.78 ± 3.05 | 4.48 ± 0.12 | 1.92 ± 0.04 | 0.19 ± 0.00 |
| topdown_heatmap | ResNet-101 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/res101_coco_256x192.py) | (3, 192, 256) | 0.726 | 9.11 | 52.99 | 43.35 ± 4.36 | 6.44 ± 0.14 | 2.57 ± 0.05 | 0.27 ± 0.00 |
| topdown_heatmap | ResNet-101 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/res101_coco_384x288.py) | (3, 288, 384) | 0.748 | 20.5 | 52.99 | 23.29 ± 1.83 | 3.12 ± 0.09 | 1.23 ± 0.03 | 0.11 ± 0.00 |
| topdown_heatmap | ResNet-152 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/res152_coco_256x192.py) | (3, 192, 256) | 0.735 | 12.77 | 68.64 | 32.31 ± 2.84 | 4.88 ± 0.17 | 1.89 ± 0.03 | 0.20 ± 0.00 |
| topdown_heatmap | ResNet-152 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/res152_coco_384x288.py) | (3, 288, 384) | 0.75 | 28.73 | 68.64 | 17.32 ± 1.17 | 2.40 ± 0.04 | 0.91 ± 0.01 | 0.08 ± 0.00 |
| topdown_heatmap | ResNetV1d-50 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/resnetv1d50_coco_256x192.py) | (3, 192, 256) | 0.722 | 5.7 | 34.02 | 63.44 ± 6.09 | 9.09 ± 0.10 | 3.82 ± 0.10 | 0.39 ± 0.00 |
| topdown_heatmap | ResNetV1d-50 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/resnetv1d50_coco_384x288.py) | (3, 288, 384) | 0.73 | 12.82 | 34.02 | 36.21 ± 3.10 | 4.30 ± 0.12 | 1.82 ± 0.04 | 0.16 ± 0.00 |
| topdown_heatmap | ResNetV1d-101 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/resnetv1d101_coco_256x192.py) | (3, 192, 256) | 0.731 | 9.35 | 53.01 | 41.48 ± 3.76 | 6.33 ± 0.15 | 2.48 ± 0.05 | 0.26 ± 0.00 |
| topdown_heatmap | ResNetV1d-101 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/resnetv1d101_coco_384x288.py) | (3, 288, 384) | 0.748 | 21.04 | 53.01 | 23.49 ± 1.76 | 3.07 ± 0.07 | 1.19 ± 0.02 | 0.11 ± 0.00 |
| topdown_heatmap | ResNetV1d-152 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/resnetv1d152_coco_256x192.py) | (3, 192, 256) | 0.737 | 13.01 | 68.65 | 31.96 ± 2.87 | 4.69 ± 0.18 | 1.87 ± 0.02 | 0.19 ± 0.00 |
| topdown_heatmap | ResNetV1d-152 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/resnetv1d152_coco_384x288.py) | (3, 288, 384) | 0.752 | 29.26 | 68.65 | 17.31 ± 1.13 | 2.32 ± 0.04 | 0.88 ± 0.01 | 0.08 ± 0.00 |
| topdown_heatmap | ResNext-50 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/resnext50_coco_256x192.py) | (3, 192, 256) | 0.714 | 5.61 | 33.47 | 48.34 ± 3.85 | 7.66 ± 0.13 | 3.71 ± 0.10 | 0.37 ± 0.00 |
| topdown_heatmap | ResNext-50 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/resnext50_coco_384x288.py) | (3, 288, 384) | 0.724 | 12.62 | 33.47 | 30.66 ± 2.38 | 3.64 ± 0.11 | 1.73 ± 0.03 | 0.15 ± 0.00 |
| topdown_heatmap | ResNext-101 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/resnext101_coco_256x192.py) | (3, 192, 256) | 0.726 | 9.29 | 52.62 | 27.33 ± 2.35 | 5.09 ± 0.13 | 2.45 ± 0.04 | 0.25 ± 0.00 |
| topdown_heatmap | ResNext-101 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/resnext101_coco_384x288.py) | (3, 288, 384) | 0.743 | 20.91 | 52.62 | 18.19 ± 1.38 | 2.42 ± 0.04 | 1.15 ± 0.01 | 0.10 ± 0.00 |
| topdown_heatmap | ResNext-152 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/resnext152_coco_256x192.py) | (3, 192, 256) | 0.73 | 12.98 | 68.39 | 19.61 ± 1.61 | 3.80 ± 0.13 | 1.83 ± 0.02 | 0.18 ± 0.00 |
| topdown_heatmap | ResNext-152 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/resnext152_coco_384x288.py) | (3, 288, 384) | 0.742 | 29.21 | 68.39 | 13.14 ± 0.75 | 1.82 ± 0.03 | 0.85 ± 0.01 | 0.08 ± 0.00 |
| topdown_heatmap | RSN-18 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/rsn18_coco_256x192.py) | (3, 192, 256) | 0.704 | 2.27 | 9.14 | 47.80 ± 4.50 | 13.68 ± 0.25 | 6.70 ± 0.28 | 0.70 ± 0.00 |
| topdown_heatmap | RSN-50 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/rsn50_coco_256x192.py) | (3, 192, 256) | 0.723 | 4.11 | 19.33 | 27.22 ± 1.61 | 8.81 ± 0.13 | 3.98 ± 0.12 | 0.45 ± 0.00 |
| topdown_heatmap | 2xRSN-50 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/2xrsn50_coco_256x192.py) | (3, 192, 256) | 0.745 | 8.29 | 39.26 | 13.88 ± 0.64 | 4.78 ± 0.13 | 2.02 ± 0.04 | 0.23 ± 0.00 |
| topdown_heatmap | 3xRSN-50 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/3xrsn50_coco_256x192.py) | (3, 192, 256) | 0.75 | 12.47 | 59.2 | 9.40 ± 0.32 | 3.37 ± 0.09 | 1.34 ± 0.03 | 0.15 ± 0.00 |
| topdown_heatmap | SCNet-50 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/scnet50_coco_256x192.py) | (3, 192, 256) | 0.728 | 5.31 | 34.01 | 40.76 ± 3.08 | 8.35 ± 0.19 | 3.82 ± 0.08 | 0.40 ± 0.00 |
| topdown_heatmap | SCNet-50 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/scnet50_coco_384x288.py) | (3, 288, 384) | 0.751 | 11.94 | 34.01 | 32.61 ± 2.97 | 4.19 ± 0.10 | 1.85 ± 0.03 | 0.17 ± 0.00 |
| topdown_heatmap | SCNet-101 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/scnet101_coco_256x192.py) | (3, 192, 256) | 0.733 | 8.51 | 53.01 | 24.28 ± 1.19 | 5.80 ± 0.13 | 2.49 ± 0.05 | 0.27 ± 0.00 |
| topdown_heatmap | SCNet-101 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/scnet101_coco_384x288.py) | (3, 288, 384) | 0.752 | 19.14 | 53.01 | 20.43 ± 1.76 | 2.91 ± 0.06 | 1.23 ± 0.02 | 0.12 ± 0.00 |
| topdown_heatmap | SeresNet-50 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/seresnet50_coco_256x192.py) | (3, 192, 256) | 0.728 | 5.47 | 36.53 | 54.83 ± 4.94 | 8.80 ± 0.12 | 3.85 ± 0.10 | 0.40 ± 0.00 |
| topdown_heatmap | SeresNet-50 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/seresnet50_coco_384x288.py) | (3, 288, 384) | 0.748 | 12.3 | 36.53 | 33.00 ± 2.67 | 4.26 ± 0.12 | 1.86 ± 0.04 | 0.17 ± 0.00 |
| topdown_heatmap | SeresNet-101 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/seresnet101_coco_256x192.py) | (3, 192, 256) | 0.734 | 9.13 | 57.77 | 33.90 ± 2.65 | 6.01 ± 0.13 | 2.48 ± 0.05 | 0.26 ± 0.00 |
| topdown_heatmap | SeresNet-101 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/seresnet101_coco_384x288.py) | (3, 288, 384) | 0.753 | 20.53 | 57.77 | 20.57 ± 1.57 | 2.96 ± 0.07 | 1.20 ± 0.02 | 0.11 ± 0.00 |
| topdown_heatmap | SeresNet-152 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/seresnet152_coco_256x192.py) | (3, 192, 256) | 0.73 | 12.79 | 75.26 | 24.25 ± 1.95 | 4.45 ± 0.10 | 1.82 ± 0.02 | 0.19 ± 0.00 |
| topdown_heatmap | SeresNet-152 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/seresnet152_coco_384x288.py) | (3, 288, 384) | 0.753 | 28.76 | 75.26 | 15.11 ± 0.99 | 2.25 ± 0.04 | 0.88 ± 0.01 | 0.08 ± 0.00 |
| topdown_heatmap | ShuffleNetV1 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/shufflenetv1_coco_256x192.py) | (3, 192, 256) | 0.585 | 1.35 | 6.94 | 80.79 ± 8.95 | 21.91 ± 0.46 | 11.84 ± 0.59 | 1.25 ± 0.01 |
| topdown_heatmap | ShuffleNetV1 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/shufflenetv1_coco_384x288.py) | (3, 288, 384) | 0.622 | 3.05 | 6.94 | 63.45 ± 5.21 | 9.84 ± 0.10 | 6.01 ± 0.31 | 0.57 ± 0.00 |
| topdown_heatmap | ShuffleNetV2 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/shufflenetv2_coco_256x192.py) | (3, 192, 256) | 0.599 | 1.37 | 7.55 | 82.36 ± 7.30 | 22.68 ± 0.53 | 12.40 ± 0.66 | 1.34 ± 0.02 |
| topdown_heatmap | ShuffleNetV2 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/shufflenetv2_coco_384x288.py) | (3, 288, 384) | 0.636 | 3.08 | 7.55 | 63.63 ± 5.72 | 10.47 ± 0.16 | 6.32 ± 0.28 | 0.63 ± 0.01 |
| topdown_heatmap | VGG16 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/vgg16_bn_coco_256x192.py) | (3, 192, 256) | 0.698 | 16.22 | 18.92 | 51.91 ± 2.98 | 6.18 ± 0.13 | 1.64 ± 0.03 | 0.15 ± 0.00 |
| topdown_heatmap | VIPNAS + ResNet-50 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/vipnas_res50_coco_256x192.py) | (3, 192, 256) | 0.711 | 1.49 | 7.29 | 34.88 ± 2.45 | 10.29 ± 0.13 | 6.51 ± 0.17 | 0.65 ± 0.00 |
| topdown_heatmap | VIPNAS + MobileNetV3 | [config](/configs/body/2d_kpt_sview_rgb_img/topdown_heatmap/coco/vipnas_mbv3_coco_256x192.py) | (3, 192, 256) | 0.7 | 0.76 | 5.9 | 53.62 ± 6.59 | 11.54 ± 0.18 | 1.26 ± 0.02 | 0.13 ± 0.00 |
| Associative Embedding | HigherHRNet-W32 | [config](/configs/body/2d_kpt_sview_rgb_img/associative_embedding/coco/higherhrnet_w32_coco_512x512.py) | (3, 512, 512) | 0.677 | 46.58 | 28.65 | 7.80 ± 0.67 | / | 0.28 ± 0.02 | / |
| Associative Embedding | HigherHRNet-W32 | [config](/configs/body/2d_kpt_sview_rgb_img/associative_embedding/coco/higherhrnet_w32_coco_640x640.py) | (3, 640, 640) | 0.686 | 72.77 | 28.65 | 5.30 ± 0.37 | / | 0.17 ± 0.01 | / |
| Associative Embedding | HigherHRNet-W48 | [config](/configs/body/2d_kpt_sview_rgb_img/associative_embedding/coco/higherhrnet_w48_coco_512x512.py) | (3, 512, 512) | 0.686 | 96.17 | 63.83 | 4.55 ± 0.35 | / | 0.15 ± 0.01 | / |
| Associative Embedding | Hourglass-AE | [config](/configs/body/2d_kpt_sview_rgb_img/associative_embedding/coco/hourglass_ae_coco_512x512.py) | (3, 512, 512) | 0.613 | 221.58 | 138.86 | 3.55 ± 0.24 | / | 0.08 ± 0.00 | / |
| Associative Embedding | HRNet-W32 | [config](/configs/body/2d_kpt_sview_rgb_img/associative_embedding/coco/hrnet_w32_coco_512x512.py) | (3, 512, 512) | 0.654 | 41.1 | 28.54 | 8.93 ± 0.76 | / | 0.33 ± 0.02 | / |
| Associative Embedding | HRNet-W48 | [config](/configs/body/2d_kpt_sview_rgb_img/associative_embedding/coco/hrnet_w48_coco_512x512.py) | (3, 512, 512) | 0.665 | 84.12 | 63.6 | 5.27 ± 0.43 | / | 0.18 ± 0.01 | / |
| Associative Embedding | MobilenetV2 | [config](/configs/body/2d_kpt_sview_rgb_img/associative_embedding/coco/mobilenetv2_coco_512x512.py) | (3, 512, 512) | 0.38 | 8.54 | 9.57 | 21.24 ± 1.34 | / | 0.81 ± 0.06 | / |
| Associative Embedding | ResNet-50 | [config](/configs/body/2d_kpt_sview_rgb_img/associative_embedding/coco/res50_coco_512x512.py) | (3, 512, 512) | 0.466 | 29.2 | 34 | 11.71 ± 0.97 | / | 0.41 ± 0.02 | / |
| Associative Embedding | ResNet-50 | [config](/configs/body/2d_kpt_sview_rgb_img/associative_embedding/coco/res50_coco_640x640.py) | (3, 640, 640) | 0.479 | 45.62 | 34 | 8.20 ± 0.58 | / | 0.26 ± 0.02 | / |
| Associative Embedding | ResNet-101 | [config](/configs/body/2d_kpt_sview_rgb_img/associative_embedding/coco/res101_coco_512x512.py) | (3, 512, 512) | 0.554 | 48.67 | 53 | 8.26 ± 0.68 | / | 0.28 ± 0.02 | / |
| Associative Embedding | ResNet-101 | [config](/configs/body/2d_kpt_sview_rgb_img/associative_embedding/coco/res152_coco_512x512.py) | (3, 512, 512) | 0.595 | 68.17 | 68.64 | 6.25 ± 0.53 | / | 0.21 ± 0.01 | / |
| DeepPose | ResNet-50 | [config](/configs/body/2d_kpt_sview_rgb_img/deeppose/coco/res50_coco_256x192.py) | (3, 192, 256) | 0.526 | 4.04 | 23.58 | 82.20 ± 7.54 | / | 5.50 ± 0.18 | / |
| DeepPose | ResNet-101 | [config](/configs/body/2d_kpt_sview_rgb_img/deeppose/coco/res101_coco_256x192.py) | (3, 192, 256) | 0.56 | 7.69 | 42.57 | 48.93 ± 4.02 | / | 3.10 ± 0.07 | / |
| DeepPose | ResNet-152 | [config](/configs/body/2d_kpt_sview_rgb_img/deeppose/coco/res152_coco_256x192.py) | (3, 192, 256) | 0.583 | 11.34 | 58.21 | 35.06 ± 3.50 | / | 2.19 ± 0.04 | / |
<sup>1</sup> 注意,这里运行迭代多次,并记录每次迭代的时间,同时展示了 FPS 数值的平均值和标准差。
<sup>2</sup> FPS 定义为每秒的平均迭代次数,与此迭代中的批处理大小无关。
@@ -0,0 +1,202 @@
# 安装
本文档提供了安装 MMPose 的相关步骤。
<!-- TOC -->
- [安装依赖包](#安装依赖包)
- [准备环境](#准备环境)
- [MMPose 的安装步骤](#MMPose-的安装步骤)
- [CPU 环境下的安装步骤](#CPU-环境下的安装步骤)
- [利用 Docker 镜像安装 MMPose](#利用-Docker-镜像安装-MMPose)
- [源码安装 MMPose](#源码安装-MMPose)
- [在多个 MMPose 版本下进行开发](#在多个-MMPose-版本下进行开发)
<!-- TOC -->
## 安装依赖包
- Linux (Windows 系统暂未有官方支持)
- Python 3.6+
- PyTorch 1.3+
- CUDA 9.2+ (如果从源码编译 PyTorch,则可以兼容 CUDA 9.0 版本)
- GCC 5+
- [mmcv](https://github.com/open-mmlab/mmcv) 请安装最新版本的 mmcv-full
- Numpy
- cv2
- json_tricks
- [xtcocotools](https://github.com/jin-s13/xtcocoapi)
可选项:
- [mmdet](https://github.com/open-mmlab/mmdetection) (用于“姿态估计”)
- [mmtrack](https://github.com/open-mmlab/mmtracking) (用于“姿态跟踪”)
- [pyrender](https://pyrender.readthedocs.io/en/latest/install/index.html) (用于“三维人体形状恢复”)
- [smplx](https://github.com/vchoutas/smplx) (用于“三维人体形状恢复”)
## 准备环境
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 的编译版本和 CUDA 的运行版本相匹配。
用户可以参照 [PyTorch 官网](https://pytorch.org/) 对预编译包所支持的 CUDA 版本进行核对。
`例 1`:如果用户的 `/usr/local/cuda` 文件夹下已安装 CUDA 10.2 版本,并且想要安装 PyTorch 1.8.0 版本,
则需要安装 CUDA 10.2 下预编译的 PyTorch。
```shell
conda install pytorch==1.8.0 torchvision==0.9.0 cudatoolkit=10.2 -c pytorch
```
`例 2`:如果用户的 `/usr/local/cuda` 文件夹下已安装 CUDA 9.2 版本,并且想要安装 PyTorch 1.7.0 版本,
则需要安装 CUDA 9.2 下预编译的 PyTorch。
```shell
conda install pytorch==1.7.0 torchvision==0.8.0 cudatoolkit=9.2 -c pytorch
```
如果 PyTorch 是由源码进行编译安装(而非直接下载预编译好的安装包),则可以使用更多的 CUDA 版本(如 9.0 版本)。
## MMPose 的安装步骤
a. 安装最新版本的 mmcv-full。MMPose 推荐用户使用如下的命令安装预编译好的 mmcv。
```shell
# pip install mmcv-full -f https://download.openmmlab.com/mmcv/dist/{cu_version}/{torch_version}/index.html
pip install mmcv-full -f https://download.openmmlab.com/mmcv/dist/cu102/torch1.9.0/index.html
# 我们可以忽略 PyTorch 的小版本号
pip install mmcv-full -f https://download.openmmlab.com/mmcv/dist/cu102/torch1.9/index.html
```
PyTorch 在 1.x.0 和 1.x.1 之间通常是兼容的,故 mmcv-full 只提供 1.x.0 的编译包。如果你的 PyTorch 版本是 1.x.1,你可以放心地安装在 1.x.0 版本编译的 mmcv-full。
可查阅 [这里](https://github.com/open-mmlab/mmcv#installation) 以参考不同版本的 MMCV 所兼容的 PyTorch 和 CUDA 版本。
另外,用户也可以通过使用以下命令从源码进行编译:
```shell
git clone https://github.com/open-mmlab/mmcv.git
cd mmcv
MMCV_WITH_OPS=1 pip install -e . # mmcv-full 包含一些 cuda 算子,执行该步骤会安装 mmcv-full(而非 mmcv)
# 或者使用 pip install -e . # 这个命令安装的 mmcv 将不包含 cuda ops,通常适配 CPU(无 GPU)环境
cd ..
```
**注意**:如果之前安装过 mmcv,那么需要先使用 `pip uninstall mmcv` 命令进行卸载。如果 mmcv 和 mmcv-full 同时被安装, 会报 `ModuleNotFoundError` 的错误。
b. 克隆 MMPose 库。
```shell
git clone https://github.com/open-mmlab/mmpose.git
cd mmpose
```
c. 安装依赖包和 MMPose。
```shell
pip install -r requirements.txt
pip install -v -e . # or "python setup.py develop"
```
如果是在 macOS 环境安装 MMPose,则需使用如下命令:
```shell
CC=clang CXX=clang++ CFLAGS='-stdlib=libc++' pip install -e .
```
d. 安装其他可选依赖。
如果用户不需要做相关任务,这部分步骤可以选择跳过。
可选项:
- [mmdet](https://github.com/open-mmlab/mmdetection) (用于“姿态估计”)
- [mmtrack](https://github.com/open-mmlab/mmtracking) (用于“姿态跟踪”)
- [pyrender](https://pyrender.readthedocs.io/en/latest/install/index.html) (用于“三维人体形状恢复”)
- [smplx](https://github.com/vchoutas/smplx) (用于“三维人体形状恢复”)
注意:
1. 在步骤 c 中,git commit 的 id 将会被写到版本号中,如 0.6.0+2e7045c。这个版本号也会被保存到训练好的模型中。
这里推荐用户每次在步骤 b 中对本地代码和 github 上的源码进行同步。如果 C++/CUDA 代码被修改,就必须进行这一步骤。
1. 根据上述步骤,MMPose 就会以 `dev` 模式被安装,任何本地的代码修改都会立刻生效,不需要再重新安装一遍(除非用户提交了 commits,并且想更新版本号)。
1. 如果用户想使用 `opencv-python-headless` 而不是 `opencv-python`,可再安装 MMCV 前安装 `opencv-python-headless`。
1. 如果 mmcv 已经被安装,用户需要使用 `pip uninstall mmcv` 命令进行卸载。如果 mmcv 和 mmcv-full 同时被安装, 会报 `ModuleNotFoundError` 的错误。
1. 一些依赖包是可选的。运行 `python setup.py develop` 将只会安装运行代码所需的最小要求依赖包。
要想使用一些可选的依赖包,如 `smplx`,用户需要通过 `pip install -r requirements/optional.txt` 进行安装,
或者通过调用 `pip`(如 `pip install -v -e .[optional]`,这里的 `[optional]` 可替换为 `all`,`tests`,`build` 或 `optional`) 指定安装对应的依赖包,如 `pip install -v -e .[tests,build]`。
## CPU 环境下的安装步骤
MMPose 可以在只有 CPU 的环境下安装(即无法使用 GPU 的环境)。
在 CPU 模式下,用户可以运行 `demo/demo.py` 的代码。
## 源码安装 MMPose
这里提供了 conda 下安装 MMPose 并链接 COCO 数据集路径的完整脚本(假设 COCO 数据的路径在 $COCO_ROOT)。
```shell
conda create -n open-mmlab python=3.7 -y
conda activate open-mmlab
# 安装最新的,使用默认版本的 CUDA 版本(一般为最新版本)预编译的 PyTorch 包
conda install -c pytorch pytorch torchvision -y
# 安装 mmcv-full。其中,命令里 url 的 ``{cu_version}`` 和 ``{torch_version}`` 变量需由用户进行指定。
# 可查阅 [这里](https://github.com/open-mmlab/mmcv#installation) 以参考不同版本的 MMCV 所兼容的 PyTorch 和 CUDA 版本。
pip install mmcv-full -f https://download.openmmlab.com/mmcv/dist/{cu_version}/{torch_version}/index.html
# 安装 mmpose
git clone git@github.com:open-mmlab/mmpose.git
cd mmpose
pip install -r requirements.txt
python setup.py develop
mkdir data
ln -s $COCO_ROOT data/coco
```
## 利用 Docker 镜像安装 MMPose
MMPose 提供一个 [Dockerfile](/docker/Dockerfile) 用户创建 docker 镜像。
```shell
# 创建拥有 PyTorch 1.6.0, CUDA 10.1, CUDNN 7 配置的 docker 镜像.
docker build -f ./docker/Dockerfile --rm -t mmpose .
```
**注意**:用户需要确保已经安装了 [nvidia-container-toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#docker)。
运行以下命令:
```shell
docker run --gpus all\
--shm-size=8g \
-it -v {DATA_DIR}:/mmpose/data mmpose
```
## 在多个 MMPose 版本下进行开发
MMPose 的训练和测试脚本已经修改了 `PYTHONPATH` 变量,以确保其能够运行当前目录下的 MMPose。
如果想要运行环境下默认的 MMPose,用户需要在训练和测试脚本中去除这一行:
```shell
PYTHONPATH="$(dirname $0)/..":$PYTHONPATH
```
@@ -0,0 +1,3 @@
## <a href='https://mmpose.readthedocs.io/en/latest/'>English</a>
## <a href='https://mmpose.readthedocs.io/zh_CN/latest/'>简体中文</a>
@@ -0,0 +1,35 @@
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=.
set BUILDDIR=_build
if "%1" == "" goto help
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
:end
popd
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env bash
# Copyright (c) OpenMMLab. All rights reserved.
sed -i '$a\\n' ../../demo/docs/*_demo.md
cat ../../demo/docs/*_demo.md | sed "s/#/#&/" | sed "s/md###t/html#t/g" | sed '1i\# 示例' | sed 's=](/docs/zh_cn/=](/=g' | sed 's=](/=](https://github.com/open-mmlab/mmpose/tree/master/=g' >demo.md
# remove /docs_zh-CN/ for link used in doc site
sed -i 's=](/docs/zh_cn/=](=g' ./tutorials/*.md
sed -i 's=](/docs/zh_cn/=](=g' ./tasks/*.md
sed -i 's=](/docs/zh_cn/=](=g' ./papers/*.md
sed -i 's=](/docs/zh_cn/=](=g' ./topics/*.md
sed -i 's=](/docs/zh_cn/=](=g' data_preparation.md
sed -i 's=](/docs/zh_cn/=](=g' getting_started.md
sed -i 's=](/docs/zh_cn/=](=g' install.md
sed -i 's=](/docs/zh_cn/=](=g' benchmark.md
# sed -i 's=](/docs/zh_cn/=](=g' changelog.md
sed -i 's=](/docs/zh_cn/=](=g' faq.md
sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/master/=g' ./tutorials/*.md
sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/master/=g' ./tasks/*.md
sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/master/=g' ./papers/*.md
sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/master/=g' ./topics/*.md
sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/master/=g' data_preparation.md
sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/master/=g' getting_started.md
sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/master/=g' install.md
sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/master/=g' benchmark.md
# sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/master/=g' changelog.md
sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/master/=g' faq.md
+176
View File
@@ -0,0 +1,176 @@
#!/usr/bin/env python
# Copyright (c) OpenMMLab. All rights reserved.
import functools as func
import glob
import re
from os.path import basename, splitext
import numpy as np
import titlecase
def anchor(name):
return re.sub(r'-+', '-', re.sub(r'[^a-zA-Z0-9]', '-',
name.strip().lower())).strip('-')
# Count algorithms
files = sorted(glob.glob('topics/*.md'))
stats = []
for f in files:
with open(f, 'r') as content_file:
content = content_file.read()
# title
title = content.split('\n')[0].replace('#', '')
# count papers
papers = set(
(papertype, titlecase.titlecase(paper.lower().strip()))
for (papertype, paper) in re.findall(
r'<!--\s*\[([A-Z]*?)\]\s*-->\s*\n.*?\btitle\s*=\s*{(.*?)}',
content, re.DOTALL))
# paper links
revcontent = '\n'.join(list(reversed(content.splitlines())))
paperlinks = {}
for _, p in papers:
print(p)
paperlinks[p] = ', '.join(
((f'[{paperlink} ⇨]'
f'(topics/{splitext(basename(f))[0]}.html#{anchor(paperlink)})')
for paperlink in re.findall(
rf'\btitle\s*=\s*{{\s*{p}\s*}}.*?\n### (.*?)\s*[,;]?\s*\n',
revcontent, re.DOTALL | re.IGNORECASE)))
print(' ', paperlinks[p])
paperlist = '\n'.join(
sorted(f' - [{t}] {x} ({paperlinks[x]})' for t, x in papers))
# count configs
configs = set(x.lower().strip()
for x in re.findall(r'.*configs/.*\.py', content))
# count ckpts
ckpts = set(x.lower().strip()
for x in re.findall(r'https://download.*\.pth', content)
if 'mmpose' in x)
statsmsg = f"""
## [{title}]({f})
* 模型权重文件数量: {len(ckpts)}
* 配置文件数量: {len(configs)}
* 论文数量: {len(papers)}
{paperlist}
"""
stats.append((papers, configs, ckpts, statsmsg))
allpapers = func.reduce(lambda a, b: a.union(b), [p for p, _, _, _ in stats])
allconfigs = func.reduce(lambda a, b: a.union(b), [c for _, c, _, _ in stats])
allckpts = func.reduce(lambda a, b: a.union(b), [c for _, _, c, _ in stats])
# Summarize
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(allckpts)}
* 配置文件数量: {len(allconfigs)}
* 论文数量: {len(allpapers)}
{countstr}
已支持的数据集详细信息请见 [数据集](datasets.md).
{msglist}
"""
with open('modelzoo.md', 'w') as f:
f.write(modelzoo)
# Count datasets
files = sorted(glob.glob('tasks/*.md'))
# files = sorted(glob.glob('docs/tasks/*.md'))
datastats = []
for f in files:
with open(f, 'r') as content_file:
content = content_file.read()
# title
title = content.split('\n')[0].replace('#', '')
# count papers
papers = set(
(papertype, titlecase.titlecase(paper.lower().strip()))
for (papertype, paper) in re.findall(
r'<!--\s*\[([A-Z]*?)\]\s*-->\s*\n.*?\btitle\s*=\s*{(.*?)}',
content, re.DOTALL))
# paper links
revcontent = '\n'.join(list(reversed(content.splitlines())))
paperlinks = {}
for _, p in papers:
print(p)
paperlinks[p] = ', '.join(
(f'[{p} ⇨](tasks/{splitext(basename(f))[0]}.html#{anchor(p)})'
for p in re.findall(
rf'\btitle\s*=\s*{{\s*{p}\s*}}.*?\n## (.*?)\s*[,;]?\s*\n',
revcontent, re.DOTALL | re.IGNORECASE)))
print(' ', paperlinks[p])
paperlist = '\n'.join(
sorted(f' - [{t}] {x} ({paperlinks[x]})' for t, x in papers))
# count configs
configs = set(x.lower().strip()
for x in re.findall(r'https.*configs/.*\.py', content))
# count ckpts
ckpts = set(x.lower().strip()
for x in re.findall(r'https://download.*\.pth', content)
if 'mmpose' in x)
statsmsg = f"""
## [{title}]({f})
* 论文数量: {len(papers)}
{paperlist}
"""
datastats.append((papers, configs, ckpts, statsmsg))
alldatapapers = func.reduce(lambda a, b: a.union(b),
[p for p, _, _, _ in datastats])
# Summarize
msglist = '\n'.join(x for _, _, _, x in stats)
datamsglist = '\n'.join(x for _, _, _, x in datastats)
papertypes, papercounts = np.unique([t for t, _ in alldatapapers],
return_counts=True)
countstr = '\n'.join(
[f' - {t}: {c}' for t, c in zip(papertypes, papercounts)])
modelzoo = f"""
# 概览
* 论文数量: {len(alldatapapers)}
{countstr}
已支持的算法详细信息请见 [模型池](modelzoo.md).
{datamsglist}
"""
with open('datasets.md', 'w') as f:
f.write(modelzoo)
@@ -0,0 +1,3 @@
# 2D动物关键点数据集
内容建设中……
@@ -0,0 +1,496 @@
# 2D 人体关键点数据集
我们建议您将数据集的根目录放置在 `$MMPOSE/data` 下。
如果您的文件结构比较特别,您需要在配置文件中修改相应的路径。
MMPose 支持的数据集如下所示:
- 图像
- [COCO](#coco) \[ [主页](http://cocodataset.org/) \]
- [MPII](#mpii) \[ [主页](http://human-pose.mpi-inf.mpg.de/) \]
- [MPII-TRB](#mpii-trb) \[ [主页](https://github.com/kennymckormick/Triplet-Representation-of-human-Body) \]
- [AI Challenger](#aic) \[ [主页](https://github.com/AIChallenger/AI_Challenger_2017) \]
- [CrowdPose](#crowdpose) \[ [主页](https://github.com/Jeff-sjtu/CrowdPose) \]
- [OCHuman](#ochuman) \[ [主页](https://github.com/liruilong940607/OCHumanApi) \]
- [MHP](#mhp) \[ [主页](https://lv-mhp.github.io/dataset) \]
- 视频
- [PoseTrack18](#posetrack18) \[ [主页](https://posetrack.net/users/download.php) \]
- [sub-JHMDB](#sub-jhmdb-dataset) \[ [主页](http://jhmdb.is.tue.mpg.de/dataset) \]
## COCO
<!-- [DATASET] -->
<details>
<summary align="right"><a href="https://link.springer.com/chapter/10.1007/978-3-319-10602-1_48">COCO (ECCV'2014)</a></summary>
```bibtex
@inproceedings{lin2014microsoft,
title={Microsoft coco: Common objects in context},
author={Lin, Tsung-Yi and Maire, Michael and Belongie, Serge and Hays, James and Perona, Pietro and Ramanan, Deva and Doll{\'a}r, Piotr and Zitnick, C Lawrence},
booktitle={European conference on computer vision},
pages={740--755},
year={2014},
organization={Springer}
}
```
</details>
请从此链接 [COCO download](http://cocodataset.org/#download) 下载数据集。请注意,2017 Train/Val 对于 COCO 关键点的训练和评估是非常必要的。
[HRNet-Human-Pose-Estimation](https://github.com/HRNet/HRNet-Human-Pose-Estimation) 提供了 COCO val2017 的检测结果,可用于复现我们的多人姿态估计的结果。
请从 [OneDrive](https://1drv.ms/f/s!AhIXJn_J-blWzzDXoz5BeFl8sWM-) 或 [GoogleDrive](https://drive.google.com/drive/folders/1fRUDNUDxe9fjqcRZ2bnF_TKMlO0nB_dk?usp=sharing)下载。
可选地, 为了在 COCO'2017 test-dev 上评估, 请下载 [image-info](https://download.openmmlab.com/mmpose/datasets/person_keypoints_test-dev-2017.json)。
请将数据置于 $MMPOSE/data 目录下,并整理成如下的格式:
```text
mmpose
├── mmpose
├── docs
├── tests
├── tools
├── configs
`── data
│── coco
│-- annotations
│ │-- person_keypoints_train2017.json
│ |-- person_keypoints_val2017.json
│ |-- person_keypoints_test-dev-2017.json
|-- person_detection_results
| |-- COCO_val2017_detections_AP_H_56_person.json
| |-- COCO_test-dev2017_detections_AP_H_609_person.json
│-- train2017
│ │-- 000000000009.jpg
│ │-- 000000000025.jpg
│ │-- 000000000030.jpg
│ │-- ...
`-- val2017
│-- 000000000139.jpg
│-- 000000000285.jpg
│-- 000000000632.jpg
│-- ...
```
## MPII
<!-- [DATASET] -->
<details>
<summary align="right"><a href="http://openaccess.thecvf.com/content_cvpr_2014/html/Andriluka_2D_Human_Pose_2014_CVPR_paper.html">MPII (CVPR'2014)</a></summary>
```bibtex
@inproceedings{andriluka14cvpr,
author = {Mykhaylo Andriluka and Leonid Pishchulin and Peter Gehler and Schiele, Bernt},
title = {2D Human Pose Estimation: New Benchmark and State of the Art Analysis},
booktitle = {IEEE Conference on Computer Vision and Pattern Recognition (CVPR)},
year = {2014},
month = {June}
}
```
</details>
请从此链接 [MPII Human Pose Dataset](http://human-pose.mpi-inf.mpg.de/) 下载数据集。
我们已经将原来的标注文件转成了 json 格式,请从此链接 [mpii_annotations](https://download.openmmlab.com/mmpose/datasets/mpii_annotations.tar) 下载。
请将数据置于 $MMPOSE/data 目录下,并整理成如下的格式:
```text
mmpose
├── mmpose
├── docs
├── tests
├── tools
├── configs
`── data
│── mpii
|── annotations
| |── mpii_gt_val.mat
| |── mpii_test.json
| |── mpii_train.json
| |── mpii_trainval.json
| `── mpii_val.json
`── images
|── 000001163.jpg
|── 000003072.jpg
```
在训练和推理过程中,预测结果将会被默认保存为 '.mat' 的格式。我们提供了一个工具将这种 '.mat' 的格式转换成更加易读的 '.json' 格式。
```shell
python tools/dataset/mat2json ${PRED_MAT_FILE} ${GT_JSON_FILE} ${OUTPUT_PRED_JSON_FILE}
```
比如,
```shell
python tools/dataset/mat2json work_dirs/res50_mpii_256x256/pred.mat data/mpii/annotations/mpii_val.json pred.json
```
## MPII-TRB
<!-- [DATASET] -->
<details>
<summary align="right"><a href="http://openaccess.thecvf.com/content_ICCV_2019/html/Duan_TRB_A_Novel_Triplet_Representation_for_Understanding_2D_Human_Body_ICCV_2019_paper.html">MPII-TRB (ICCV'2019)</a></summary>
```bibtex
@inproceedings{duan2019trb,
title={TRB: A Novel Triplet Representation for Understanding 2D Human Body},
author={Duan, Haodong and Lin, Kwan-Yee and Jin, Sheng and Liu, Wentao and Qian, Chen and Ouyang, Wanli},
booktitle={Proceedings of the IEEE International Conference on Computer Vision},
pages={9479--9488},
year={2019}
}
```
</details>
请从此链接[MPII Human Pose Dataset](http://human-pose.mpi-inf.mpg.de/)下载数据集,并从此链接 [mpii_trb_annotations](https://download.openmmlab.com/mmpose/datasets/mpii_trb_annotations.tar) 下载标注文件。
请将数据置于 $MMPOSE/data 目录下,并整理成如下的格式:
```text
mmpose
├── mmpose
├── docs
├── tests
├── tools
├── configs
`── data
│── mpii
|── annotations
| |── mpii_trb_train.json
| |── mpii_trb_val.json
`── images
|── 000001163.jpg
|── 000003072.jpg
```
## AIC
<!-- [DATASET] -->
<details>
<summary align="right"><a href="https://arxiv.org/abs/1711.06475">AI Challenger (ArXiv'2017)</a></summary>
```bibtex
@article{wu2017ai,
title={Ai challenger: A large-scale dataset for going deeper in image understanding},
author={Wu, Jiahong and Zheng, He and Zhao, Bo and Li, Yixin and Yan, Baoming and Liang, Rui and Wang, Wenjia and Zhou, Shipei and Lin, Guosen and Fu, Yanwei and others},
journal={arXiv preprint arXiv:1711.06475},
year={2017}
}
```
</details>
请从此链接 [AI Challenger 2017](https://github.com/AIChallenger/AI_Challenger_2017) 下载 [AIC](https://github.com/AIChallenger/AI_Challenger_2017) 数据集。请注意,2017 Train/Val 对于关键点的训练和评估是必要的。
请从此链接 [aic_annotations](https://download.openmmlab.com/mmpose/datasets/aic_annotations.tar) 下载标注文件。
请将数据置于 $MMPOSE/data 目录下,并整理成如下的格式:
```text
mmpose
├── mmpose
├── docs
├── tests
├── tools
├── configs
`── data
│── aic
│-- annotations
│ │-- aic_train.json
│ |-- aic_val.json
│-- ai_challenger_keypoint_train_20170902
│ │-- keypoint_train_images_20170902
│ │ │-- 0000252aea98840a550dac9a78c476ecb9f47ffa.jpg
│ │ │-- 000050f770985ac9653198495ef9b5c82435d49c.jpg
│ │ │-- ...
`-- ai_challenger_keypoint_validation_20170911
│-- keypoint_validation_images_20170911
│-- 0002605c53fb92109a3f2de4fc3ce06425c3b61f.jpg
│-- 0003b55a2c991223e6d8b4b820045bd49507bf6d.jpg
│-- ...
```
## CrowdPose
<!-- [DATASET] -->
<details>
<summary align="right"><a href="http://openaccess.thecvf.com/content_CVPR_2019/html/Li_CrowdPose_Efficient_Crowded_Scenes_Pose_Estimation_and_a_New_Benchmark_CVPR_2019_paper.html">CrowdPose (CVPR'2019)</a></summary>
```bibtex
@article{li2018crowdpose,
title={CrowdPose: Efficient Crowded Scenes Pose Estimation and A New Benchmark},
author={Li, Jiefeng and Wang, Can and Zhu, Hao and Mao, Yihuan and Fang, Hao-Shu and Lu, Cewu},
journal={arXiv preprint arXiv:1812.00324},
year={2018}
}
```
</details>
请从此链接 [CrowdPose](https://github.com/Jeff-sjtu/CrowdPose) 下载数据集,并从此链接 [crowdpose_annotations](https://download.openmmlab.com/mmpose/datasets/crowdpose_annotations.tar) 下载标注文件和人体检测结果。
对于 top-down 方法,我们仿照 [CrowdPose](https://arxiv.org/abs/1812.00324),使用 [YOLOv3](https://github.com/eriklindernoren/PyTorch-YOLOv3)的[预训练权重](https://pjreddie.com/media/files/yolov3.weights) 来产生人体的检测框。
对于模型训练, 我们仿照 [HigherHRNet](https://github.com/HRNet/HigherHRNet-Human-Pose-Estimation),在 CrowdPose 训练/验证 数据集上训练模型, 并在 CrowdPose 测试集上评估模型。
请将数据置于 $MMPOSE/data 目录下,并整理成如下的格式:
```text
mmpose
├── mmpose
├── docs
├── tests
├── tools
├── configs
`── data
│── crowdpose
│-- annotations
│ │-- mmpose_crowdpose_train.json
│ │-- mmpose_crowdpose_val.json
│ │-- mmpose_crowdpose_trainval.json
│ │-- mmpose_crowdpose_test.json
│ │-- det_for_crowd_test_0.1_0.5.json
│-- images
│-- 100000.jpg
│-- 100001.jpg
│-- 100002.jpg
│-- ...
```
## OCHuman
<!-- [DATASET] -->
<details>
<summary align="right"><a href="http://openaccess.thecvf.com/content_CVPR_2019/html/Zhang_Pose2Seg_Detection_Free_Human_Instance_Segmentation_CVPR_2019_paper.html">OCHuman (CVPR'2019)</a></summary>
```bibtex
@inproceedings{zhang2019pose2seg,
title={Pose2seg: Detection free human instance segmentation},
author={Zhang, Song-Hai and Li, Ruilong and Dong, Xin and Rosin, Paul and Cai, Zixi and Han, Xi and Yang, Dingcheng and Huang, Haozhi and Hu, Shi-Min},
booktitle={Proceedings of the IEEE conference on computer vision and pattern recognition},
pages={889--898},
year={2019}
}
```
</details>
请从此链接 [OCHuman](https://github.com/liruilong940607/OCHumanApi) 下载数据集的图像和标注文件。
请将数据置于 $MMPOSE/data 目录下,并整理成如下的格式:
```text
mmpose
├── mmpose
├── docs
├── tests
├── tools
├── configs
`── data
│── ochuman
│-- annotations
│ │-- ochuman_coco_format_val_range_0.00_1.00.json
│ |-- ochuman_coco_format_test_range_0.00_1.00.json
|-- images
│-- 000001.jpg
│-- 000002.jpg
│-- 000003.jpg
│-- ...
```
## MHP
<!-- [DATASET] -->
<details>
<summary align="right"><a href="https://dl.acm.org/doi/abs/10.1145/3240508.3240509">MHP (ACM MM'2018)</a></summary>
```bibtex
@inproceedings{zhao2018understanding,
title={Understanding humans in crowded scenes: Deep nested adversarial learning and a new benchmark for multi-human parsing},
author={Zhao, Jian and Li, Jianshu and Cheng, Yu and Sim, Terence and Yan, Shuicheng and Feng, Jiashi},
booktitle={Proceedings of the 26th ACM international conference on Multimedia},
pages={792--800},
year={2018}
}
```
</details>
请从此链接 [MHP](https://lv-mhp.github.io/dataset)下载数据文件,并从此链接 [mhp_annotations](https://download.openmmlab.com/mmpose/datasets/mhp_annotations.tar.gz)下载标注文件。
请将数据置于 $MMPOSE/data 目录下,并整理成如下的格式:
```text
mmpose
├── mmpose
├── docs
├── tests
├── tools
├── configs
`── data
│── mhp
│-- annotations
│ │-- mhp_train.json
│ │-- mhp_val.json
│
`-- train
│ │-- images
│ │ │-- 1004.jpg
│ │ │-- 10050.jpg
│ │ │-- ...
│
`-- val
│ │-- images
│ │ │-- 10059.jpg
│ │ │-- 10068.jpg
│ │ │-- ...
│
`-- test
│ │-- images
│ │ │-- 1005.jpg
│ │ │-- 10052.jpg
│ │ │-- ...~~~~
```
## PoseTrack18
<!-- [DATASET] -->
<details>
<summary align="right"><a href="http://openaccess.thecvf.com/content_cvpr_2018/html/Andriluka_PoseTrack_A_Benchmark_CVPR_2018_paper.html">PoseTrack18 (CVPR'2018)</a></summary>
```bibtex
@inproceedings{andriluka2018posetrack,
title={Posetrack: A benchmark for human pose estimation and tracking},
author={Andriluka, Mykhaylo and Iqbal, Umar and Insafutdinov, Eldar and Pishchulin, Leonid and Milan, Anton and Gall, Juergen and Schiele, Bernt},
booktitle={Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition},
pages={5167--5176},
year={2018}
}
```
</details>
请从此链接 [PoseTrack18](https://posetrack.net/users/download.php)下载数据文件,并从此链接下载 [posetrack18_annotations](https://download.openmmlab.com/mmpose/datasets/posetrack18_annotations.tar)下载标注文件。
我们已将官方提供的所有单视频标注文件合并为两个 json 文件 (posetrack18_train & posetrack18_val.json),并生成了 [mask files](https://download.openmmlab.com/mmpose/datasets/posetrack18_mask.tar) 来加速训练。
对于 top-down 的方法, 我们使用 [MMDetection](https://github.com/open-mmlab/mmdetection) 的预训练 [Cascade R-CNN](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_rcnn_x101_64x4d_fpn_20e_coco/cascade_rcnn_x101_64x4d_fpn_20e_coco_20200509_224357-051557b1.pth) (X-101-64x4d-FPN) 来生成人体的检测框。
请将数据置于 $MMPOSE/data 目录下,并整理成如下的格式:
```text
mmpose
├── mmpose
├── docs
├── tests
├── tools
├── configs
`── data
│── posetrack18
│-- annotations
│ │-- posetrack18_train.json
│ │-- posetrack18_val.json
│ │-- posetrack18_val_human_detections.json
│ │-- train
│ │ │-- 000001_bonn_train.json
│ │ │-- 000002_bonn_train.json
│ │ │-- ...
│ │-- val
│ │ │-- 000342_mpii_test.json
│ │ │-- 000522_mpii_test.json
│ │ │-- ...
│ `-- test
│ │-- 000001_mpiinew_test.json
│ │-- 000002_mpiinew_test.json
│ │-- ...
│
`-- images
│ │-- train
│ │ │-- 000001_bonn_train
│ │ │ │-- 000000.jpg
│ │ │ │-- 000001.jpg
│ │ │ │-- ...
│ │ │-- ...
│ │-- val
│ │ │-- 000342_mpii_test
│ │ │ │-- 000000.jpg
│ │ │ │-- 000001.jpg
│ │ │ │-- ...
│ │ │-- ...
│ `-- test
│ │-- 000001_mpiinew_test
│ │ │-- 000000.jpg
│ │ │-- 000001.jpg
│ │ │-- ...
│ │-- ...
`-- mask
│-- train
│ │-- 000002_bonn_train
│ │ │-- 000000.jpg
│ │ │-- 000001.jpg
│ │ │-- ...
│ │-- ...
`-- val
│-- 000522_mpii_test
│ │-- 000000.jpg
│ │-- 000001.jpg
│ │-- ...
│-- ...
```
请从 Github 上安装 PoseTrack 官方评估工具:
```shell
pip install git+https://github.com/svenkreiss/poseval.git
```
## sub-JHMDB dataset
<!-- [DATASET] -->
<details>
<summary align="right"><a href="https://link.springer.com/chapter/10.1007/978-3-030-58580-8_27">RSN (ECCV'2020)</a></summary>
```bibtex
@misc{cai2020learning,
title={Learning Delicate Local Representations for Multi-Person Pose Estimation},
author={Yuanhao Cai and Zhicheng Wang and Zhengxiong Luo and Binyi Yin and Angang Du and Haoqian Wang and Xinyu Zhou and Erjin Zhou and Xiangyu Zhang and Jian Sun},
year={2020},
eprint={2003.04030},
archivePrefix={arXiv},
primaryClass={cs.CV}
}
```
</details>
对于 [sub-JHMDB](http://jhmdb.is.tue.mpg.de/dataset) 数据集,请从此链接 [images](<(http://files.is.tue.mpg.de/jhmdb/Rename_Images.tar.gz)>) (来自 [JHMDB](http://jhmdb.is.tue.mpg.de/dataset))下载,
请从此链接 [jhmdb_annotations](https://download.openmmlab.com/mmpose/datasets/jhmdb_annotations.tar)下载标注文件。
将它们移至 $MMPOSE/data目录下, 使得文件呈如下的格式:
```text
mmpose
├── mmpose
├── docs
├── tests
├── tools
├── configs
`── data
│── jhmdb
│-- annotations
│ │-- Sub1_train.json
│ |-- Sub1_test.json
│ │-- Sub2_train.json
│ |-- Sub2_test.json
│ │-- Sub3_train.json
│ |-- Sub3_test.json
|-- Rename_Images
│-- brush_hair
│ │--April_09_brush_hair_u_nm_np1_ba_goo_0
| │ │--00001.png
| │ │--00002.png
│-- catch
│-- ...
```
@@ -0,0 +1,3 @@
# 2D人脸关键点数据集
内容建设中……
@@ -0,0 +1,3 @@
# 2D服装关键点数据集
内容建设中……
@@ -0,0 +1,3 @@
# 2D手部关键点数据集
内容建设中……
@@ -0,0 +1,3 @@
# 2D全身人体关键点数据集
内容建设中……
@@ -0,0 +1,3 @@
# 3D人体关键点数据集
内容建设中……
@@ -0,0 +1,3 @@
# 3D人体网格模型数据集
内容建设中……
@@ -0,0 +1,3 @@
# 3D手部关键点数据集
内容建设中……
@@ -0,0 +1,234 @@
# 教程 0: 模型配置文件
我们使用 python 文件作为配置文件,将模块化设计和继承设计结合到配置系统中,便于进行各种实验。
您可以在 `$MMPose/configs` 下找到所有提供的配置。如果要检查配置文件,您可以运行
`python tools/analysis/print_config.py /PATH/TO/CONFIG` 来查看完整的配置。
<!-- TOC -->
- [通过脚本参数修改配置](#通过脚本参数修改配置)
- [配置文件命名约定](#配置文件命名约定)
- [配置系统](#配置系统)
- [常见问题](#常见问题)
- [在配置中使用中间变量](#在配置中使用中间变量)
<!-- TOC -->
## 通过脚本参数修改配置
当使用 "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)]"` 。
请注意,引号 \" 是必要的,以支持列表 / 元组数据类型,并且指定值的引号内 **不允许** 有空格。
## 配置文件命名约定
我们按照下面的样式命名配置文件。建议贡献者也遵循同样的风格。
```
configs/{topic}/{task}/{algorithm}/{dataset}/{backbone}_[model_setting]_{dataset}_[input_size]_[technique].py
```
`{xxx}` 是必填字段,`[yyy]` 是可选字段.
- `{topic}`: 主题类型,如 `body`, `face`, `hand`, `animal` 等。
- `{task}`: 任务类型, `[2d | 3d]_[kpt | mesh]_[sview | mview]_[rgb | rgbd]_[img | vid]` 。任务类型从5个维度定义:(1)二维或三维姿态估计;(2)姿态表示形式:关键点 (kpt)、网格 (mesh) 或密集姿态 (dense); (3)单视图 (sview) 或多视图 (mview);(4)RGB 或 RGBD; 以及(5)图像 (img) 或视频 (vid)。例如, `2d_kpt_sview_rgb_img`, `3d_kpt_sview_rgb_vid`, 等等。
- `{algorithm}`: 算法类型,例如,`associative_embedding`, `deeppose` 等。
- `{dataset}`: 数据集名称,例如, `coco` 等。
- `{backbone}`: 主干网络类型,例如,`res50` (ResNet-50) 等。
- `[model setting]`: 对某些模型的特定设置。
- `[input_size]`: 模型的输入大小。
- `[technique]`: 一些特定的技术,包括损失函数,数据增强,训练技巧等,例如, `wingloss`, `udp`, `fp16` 等.
### 配置系统
- 基于热图的二维自顶向下的人体姿态估计实例
为了帮助用户对完整的配置结构和配置系统中的模块有一个基本的了解,
我们下面对配置文件 'https://github.com/open-mmlab/mmpose/tree/e1ec589884235bee875c89102170439a991f8450/configs/top_down/resnet/coco/res50_coco_256x192.py' 作简要的注释。
有关每个模块中每个参数的更详细用法和替代方法,请参阅 API 文档。
```python
# 运行设置
log_level = 'INFO' # 日志记录级别
load_from = None # 从给定路径加载预训练模型
resume_from = None # 从给定路径恢复模型权重文件,将从保存模型权重文件时的轮次开始继续训练
dist_params = dict(backend='nccl') # 设置分布式训练的参数,也可以设置端口
workflow = [('train', 1)] # 运行程序的工作流。[('train', 1)] 表示只有一个工作流,名为 'train' 的工作流执行一次
checkpoint_config = dict( # 设置模型权重文件钩子的配置,请参阅 https://github.com/open-mmlab/mmcv/blob/master/mmcv/runner/hooks/checkpoint.py 的实现
interval=10) # 保存模型权重文件的间隔
evaluation = dict( # 训练期间评估的配置
interval=10, # 执行评估的间隔
metric='mAP', # 采用的评价指标
key_indicator='AP') # 将 `AP` 设置为关键指标以保存最佳模型权重文件
# 优化器
optimizer = dict(
# 用于构建优化器的配置,支持 (1). PyTorch 中的所有优化器,
# 其参数也与 PyTorch 中的相同. (2). 自定义的优化器
# 它们通过 `constructor` 构建,可参阅 "tutorials/4_new_modules.md"
# 的实现。
type='Adam', # 优化器的类型, 可参阅 https://github.com/open-mmlab/mmcv/blob/master/mmcv/runner/optimizer/default_constructor.py#L13 获取更多细节
lr=5e-4, # 学习率, 参数的详细用法见 PyTorch 文档
)
optimizer_config = dict(grad_clip=None) # 不限制梯度的范围
# 学习率调整策略
lr_config = dict( # 用于注册 LrUpdater 钩子的学习率调度器的配置
policy='step', # 调整策略, 还支持 CosineAnnealing, Cyclic, 等等,请参阅 https://github.com/open-mmlab/mmcv/blob/master/mmcv/runner/hooks/lr_updater.py#L9 获取支持的 LrUpdater 细节
warmup='linear', # 使用的预热类型,它可以是 None (不使用预热), 'constant', 'linear' 或者 'exp'.
warmup_iters=500, # 预热的迭代次数或者轮数
warmup_ratio=0.001, # 预热开始时使用的学习率,等于预热比 (warmup_ratio) * 初始学习率
step=[170, 200]) # 降低学习率的步数 
total_epochs = 210 # 训练模型的总轮数
log_config = dict( # 注册日志记录器钩子的配置
interval=50, # 打印日志的间隔
hooks=[
dict(type='TextLoggerHook'), # 用来记录训练过程的日志记录器
# dict(type='TensorboardLoggerHook') # 也支持 Tensorboard 日志记录器
])
channel_cfg = dict(
num_output_channels=17, # 关键点头部的输出通道数
dataset_joints=17, # 数据集的关节数
dataset_channel=[ # 数据集支持的通道数
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
],
inference_channel=[ # 输出通道数
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
])
# 模型设置
model = dict( # 模型的配置
type='TopDown', # 模型的类型
pretrained='torchvision://resnet50', # 预训练模型的 url / 网址
backbone=dict( # 主干网络的字典
type='ResNet', # 主干网络的名称
depth=50), # ResNet 模型的深度
keypoint_head=dict( # 关键点头部的字典
type='TopdownHeatmapSimpleHead', # 关键点头部的名称
in_channels=2048, # 关键点头部的输入通道数
out_channels=channel_cfg['num_output_channels'], # 关键点头部的输出通道数
loss_keypoint=dict( # 关键点损失函数的字典
type='JointsMSELoss', # 关键点损失函数的名称
use_target_weight=True)), # 在损失计算中是否考虑目标权重
train_cfg=dict(), # 训练超参数的配置
test_cfg=dict( # 测试超参数的配置
flip_test=True, # 推断时是否使用翻转测试
post_process='default', # 使用“默认” (default) 后处理方法。
shift_heatmap=True, # 移动并对齐翻转的热图以获得更高的性能
modulate_kernel=11)) # 用于调制的高斯核大小。仅用于 "post_process='unbiased'"
data_cfg = dict(
image_size=[192, 256], # 模型输入分辨率的大小
heatmap_size=[48, 64], # 输出热图的大小
num_output_channels=channel_cfg['num_output_channels'], # 输出通道数
num_joints=channel_cfg['dataset_joints'], # 关节点数量
dataset_channel=channel_cfg['dataset_channel'], # 数据集支持的通道数
inference_channel=channel_cfg['inference_channel'], # 输出通道数
soft_nms=False, # 推理过程中是否执行 soft_nms
nms_thr=1.0, # 非极大抑制阈值
oks_thr=0.9, # nms 期间 oks(对象关键点相似性)得分阈值
vis_thr=0.2, # 关键点可见性阈值
use_gt_bbox=False, # 测试时是否使用人工标注的边界框
det_bbox_thr=0.0, # 检测到的边界框分数的阈值。当 'use_gt_bbox=True' 时使用
bbox_file='data/coco/person_detection_results/' # 边界框检测文件的路径
'COCO_val2017_detections_AP_H_56_person.json',
)
train_pipeline = [
dict(type='LoadImageFromFile'), # 从文件加载图像
dict(type='TopDownRandomFlip', # 执行随机翻转增强
flip_prob=0.5), # 执行翻转的概率
dict(
type='TopDownHalfBodyTransform', # TopDownHalfBodyTransform 数据增强的配置
num_joints_half_body=8, # 执行半身变换的阈值
prob_half_body=0.3), # 执行翻转的概率
dict(
type='TopDownGetRandomScaleRotation', # TopDownGetRandomScaleRotation 的配置
rot_factor=40, # 旋转到 ``[-2*rot_factor, 2*rot_factor]``.
scale_factor=0.5), # 缩放到 ``[1-scale_factor, 1+scale_factor]``.
dict(type='TopDownAffine', # 对图像进行仿射变换形成输入
use_udp=False), # 不使用无偏数据处理
dict(type='ToTensor'), # 将其他类型转换为张量类型流水线
dict(
type='NormalizeTensor', # 标准化输入张量
mean=[0.485, 0.456, 0.406], # 要标准化的不同通道的平均值
std=[0.229, 0.224, 0.225]), # 要标准化的不同通道的标准差
dict(type='TopDownGenerateTarget', # 生成热图目标。支持不同的编码类型
sigma=2), # 热图高斯的 Sigma
dict(
type='Collect', # 收集决定数据中哪些键应该传递到检测器的流水线
keys=['img', 'target', 'target_weight'], # 输入键
meta_keys=[ # 输入的元键
'image_file', 'joints_3d', 'joints_3d_visible', 'center', 'scale',
'rotation', 'bbox_score', 'flip_pairs'
]),
]
val_pipeline = [
dict(type='LoadImageFromFile'), # 从文件加载图像
dict(type='TopDownAffine'), # 对图像进行仿射变换形成输入
dict(type='ToTensor'), # ToTensor 的配置
dict(
type='NormalizeTensor',
mean=[0.485, 0.456, 0.406], # 要标准化的不同通道的平均值
std=[0.229, 0.224, 0.225]), # 要标准化的不同通道的标准差
dict(
type='Collect', # 收集决定数据中哪些键应该传递到检测器的流水线
keys=['img'], # 输入键
meta_keys=[ # 输入的元键
'image_file', 'center', 'scale', 'rotation', 'bbox_score',
'flip_pairs'
]),
]
test_pipeline = val_pipeline
data_root = 'data/coco' # 数据集的配置
data = dict(
samples_per_gpu=64, # 训练期间每个 GPU 的 Batch size
workers_per_gpu=2, # 每个 GPU 预取数据的 worker 个数
val_dataloader=dict(samples_per_gpu=32), # 验证期间每个 GPU 的 Batch size
test_dataloader=dict(samples_per_gpu=32), # 测试期间每个 GPU 的 Batch size
train=dict( # 训练数据集的配置
type='TopDownCocoDataset', # 数据集的名称
ann_file=f'{data_root}/annotations/person_keypoints_train2017.json', # 标注文件的路径
img_prefix=f'{data_root}/train2017/',
data_cfg=data_cfg,
pipeline=train_pipeline),
val=dict( # 验证数据集的配置
type='TopDownCocoDataset', # 数据集的名称
ann_file=f'{data_root}/annotations/person_keypoints_val2017.json', # 标注文件的路径
img_prefix=f'{data_root}/val2017/',
data_cfg=data_cfg,
pipeline=val_pipeline),
test=dict( # 测试数据集的配置
type='TopDownCocoDataset', # 数据集的名称
ann_file=f'{data_root}/annotations/person_keypoints_val2017.json', # 标注文件的路径
img_prefix=f'{data_root}/val2017/',
data_cfg=data_cfg,
pipeline=val_pipeline),
)
```
## 常见问题
### 在配置中使用中间变量
配置文件中使用了一些中间变量,如 `train_pipeline`/`val_pipeline`/`test_pipeline` 等。
例如,我们首先要定义 `train_pipeline`/`val_pipeline`/`test_pipeline`,然后将它们传递到 `data` 中。
因此,`train_pipeline`/`val_pipeline`/`test_pipeline` 是中间变量。
@@ -0,0 +1,153 @@
# 教程 1:如何微调模型
在 COCO 数据集上进行预训练,然后在其他数据集(如 COCO-WholeBody 数据集)上进行微调,往往可以提升模型的效果。
本教程介绍如何使用[模型库](https://mmpose.readthedocs.io/en/latest/modelzoo.html)中的预训练模型,并在其他数据集上进行微调。
<!-- TOC -->
- [概要](#概要)
- [修改 Head](#修改网络头)
- [修改数据集](#修改数据集)
- [修改训练策略](#修改训练策略)
- [使用预训练模型](#使用预训练模型)
<!-- TOC -->
## 概要
对新数据集上的模型微调需要两个步骤:
1. 支持新数据集。详情参见 [教程 2:如何增加新数据集](2_new_dataset.md)
2. 修改配置文件。这部分将在本教程中做具体讨论。
例如,如果想要在自定义数据集上,微调 COCO 预训练的模型,则需要修改 [配置文件](0_config.md) 中 网络头、数据集、训练策略、预训练模型四个部分。
## 修改网络头
如果自定义数据集的关键点个数,与 COCO 不同,则需要相应修改 `keypoint_head` 中的 `out_channels` 参数。
网络头(head)的最后一层的预训练参数不会被载入,而其他层的参数都会被正常载入。
例如,COCO-WholeBody 拥有 133 个关键点,因此需要把 17 (COCO 数据集的关键点数目) 改为 133。
```python
channel_cfg = dict(
num_output_channels=133, # 从 17 改为 133
dataset_joints=133, # 从 17 改为 133
dataset_channel=[
list(range(133)), # 从 17 改为 133
],
inference_channel=list(range(133))) # 从 17 改为 133
# model settings
model = dict(
type='TopDown',
pretrained='https://download.openmmlab.com/mmpose/'
'pretrain_models/hrnet_w48-8ef0771d.pth',
backbone=dict(
type='HRNet',
in_channels=3,
extra=dict(
stage1=dict(
num_modules=1,
num_branches=1,
block='BOTTLENECK',
num_blocks=(4, ),
num_channels=(64, )),
stage2=dict(
num_modules=1,
num_branches=2,
block='BASIC',
num_blocks=(4, 4),
num_channels=(48, 96)),
stage3=dict(
num_modules=4,
num_branches=3,
block='BASIC',
num_blocks=(4, 4, 4),
num_channels=(48, 96, 192)),
stage4=dict(
num_modules=3,
num_branches=4,
block='BASIC',
num_blocks=(4, 4, 4, 4),
num_channels=(48, 96, 192, 384))),
),
keypoint_head=dict(
type='TopdownHeatmapSimpleHead',
in_channels=48,
out_channels=channel_cfg['num_output_channels'], # 已对应修改
num_deconv_layers=0,
extra=dict(final_conv_kernel=1, ),
loss_keypoint=dict(type='JointsMSELoss', use_target_weight=True)),
train_cfg=dict(),
test_cfg=dict(
flip_test=True,
post_process='unbiased',
shift_heatmap=True,
modulate_kernel=17))
```
其中, `pretrained='https://download.openmmlab.com/mmpose/pretrain_models/hrnet_w48-8ef0771d.pth'` 表示采用 ImageNet 预训练的权重,初始化主干网络(backbone)。
不过,`pretrained` 只会初始化主干网络(backbone),而不会初始化网络头(head)。因此,我们模型微调时的预训练权重一般通过 `load_from` 指定,而不是使用 `pretrained` 指定。
## 支持自己的数据集
MMPose 支持十余种不同的数据集,包括 COCO, COCO-WholeBody, MPII, MPII-TRB 等数据集。
用户可将自定义数据集转换为已有数据集格式,并修改如下字段。
```python
data_root = 'data/coco'
data = dict(
samples_per_gpu=32,
workers_per_gpu=2,
val_dataloader=dict(samples_per_gpu=32),
test_dataloader=dict(samples_per_gpu=32),
train=dict(
type='TopDownCocoWholeBodyDataset', # 对应修改数据集名称
ann_file=f'{data_root}/annotations/coco_wholebody_train_v1.0.json', # 修改数据集标签路径
img_prefix=f'{data_root}/train2017/',
data_cfg=data_cfg,
pipeline=train_pipeline),
val=dict(
type='TopDownCocoWholeBodyDataset', # 对应修改数据集名称
ann_file=f'{data_root}/annotations/coco_wholebody_val_v1.0.json', # 修改数据集标签路径
img_prefix=f'{data_root}/val2017/',
data_cfg=data_cfg,
pipeline=val_pipeline),
test=dict(
type='TopDownCocoWholeBodyDataset', # 对应修改数据集名称
ann_file=f'{data_root}/annotations/coco_wholebody_val_v1.0.json', # 修改数据集标签路径
img_prefix=f'{data_root}/val2017/',
data_cfg=data_cfg,
pipeline=val_pipeline)
)
```
## 修改训练策略
通常情况下,微调模型时设置较小的学习率和训练轮数,即可取得较好效果。
```python
# 优化器
optimizer = dict(
type='Adam',
lr=5e-4, # 可以适当减小
)
optimizer_config = dict(grad_clip=None)
# 学习策略
lr_config = dict(
policy='step',
warmup='linear',
warmup_iters=500,
warmup_ratio=0.001,
step=[170, 200]) # 可以适当减小
total_epochs = 210 # 可以适当减小
```
## 使用预训练模型
网络设置中的 `pretrained`,仅会在主干网络模型上加载预训练参数。若要载入整个网络的预训练参数,需要通过 `load_from` 指定模型文件路径或模型链接。
```python
# 将预训练模型用于整个 HRNet 网络
load_from = 'https://download.openmmlab.com/mmpose/top_down/hrnet/hrnet_w48_coco_384x288_dark-741844ba_20200812.pth' # 模型路径可以在 model zoo 中找到
```
@@ -0,0 +1,316 @@
# 教程 2: 增加新的数据集
## 将数据集转化为COCO格式
我们首先需要将自定义数据集,转换为COCO数据集格式。
COCO数据集格式的json标注文件有以下关键字:
```python
'images': [
{
'file_name': '000000001268.jpg',
'height': 427,
'width': 640,
'id': 1268
},
...
],
'annotations': [
{
'segmentation': [[426.36,
...
424.34,
223.3]],
'keypoints': [0,0,0,
0,0,0,
0,0,0,
427,220,2,
443,222,2,
414,228,2,
449,232,2,
408,248,1,
454,261,2,
0,0,0,
0,0,0,
411,287,2,
431,287,2,
0,0,0,
458,265,2,
0,0,0,
466,300,1],
'num_keypoints': 10,
'area': 3894.5826,
'iscrowd': 0,
'image_id': 1268,
'bbox': [402.34, 205.02, 65.26, 88.45],
'category_id': 1,
'id': 215218
},
...
],
'categories': [
{'id': 1, 'name': 'person'},
]
```
Json文件中必须包含以下三个关键字:
- `images`: 包含图片信息的列表,提供图片的 `file_name`, `height`, `width` 和 `id` 等信息。
- `annotations`: 包含实例标注的列表。
- `categories`: 包含类别名称 ('person') 和对应的 ID (1)。
## 为自定义数据集创建 dataset_info 数据集配置文件
在如下位置,添加一个数据集配置文件。
```
configs/_base_/datasets/custom.py
```
数据集配置文件的样例如下:
`keypoint_info` 包含每个关键点的信息,其中:
1. `name`: 代表关键点的名称。一个数据集的每个关键点,名称必须唯一。
2. `id`: 关键点的标识号。
3. `color`: ([B, G, R]) 用于可视化关键点。
4. `type`: 分为 'upper' 和 'lower' 两种,用于数据增强。
5. `swap`: 表示与当前关键点,“镜像对称”的关键点名称。
`skeleton_info` 包含关键点之间的连接关系,主要用于可视化。
`joint_weights` 可以为不同的关键点设置不同的损失权重,用于训练。
`sigmas` 用于计算 OKS 得分,具体内容请参考 [keypoints-eval](https://cocodataset.org/#keypoints-eval)。
```
dataset_info = dict(
dataset_name='coco',
paper_info=dict(
author='Lin, Tsung-Yi and Maire, Michael and '
'Belongie, Serge and Hays, James and '
'Perona, Pietro and Ramanan, Deva and '
r'Doll{\'a}r, Piotr and Zitnick, C Lawrence',
title='Microsoft coco: Common objects in context',
container='European conference on computer vision',
year='2014',
homepage='http://cocodataset.org/',
),
keypoint_info={
0:
dict(name='nose', id=0, color=[51, 153, 255], type='upper', swap=''),
1:
dict(
name='left_eye',
id=1,
color=[51, 153, 255],
type='upper',
swap='right_eye'),
2:
dict(
name='right_eye',
id=2,
color=[51, 153, 255],
type='upper',
swap='left_eye'),
3:
dict(
name='left_ear',
id=3,
color=[51, 153, 255],
type='upper',
swap='right_ear'),
4:
dict(
name='right_ear',
id=4,
color=[51, 153, 255],
type='upper',
swap='left_ear'),
5:
dict(
name='left_shoulder',
id=5,
color=[0, 255, 0],
type='upper',
swap='right_shoulder'),
6:
dict(
name='right_shoulder',
id=6,
color=[255, 128, 0],
type='upper',
swap='left_shoulder'),
7:
dict(
name='left_elbow',
id=7,
color=[0, 255, 0],
type='upper',
swap='right_elbow'),
8:
dict(
name='right_elbow',
id=8,
color=[255, 128, 0],
type='upper',
swap='left_elbow'),
9:
dict(
name='left_wrist',
id=9,
color=[0, 255, 0],
type='upper',
swap='right_wrist'),
10:
dict(
name='right_wrist',
id=10,
color=[255, 128, 0],
type='upper',
swap='left_wrist'),
11:
dict(
name='left_hip',
id=11,
color=[0, 255, 0],
type='lower',
swap='right_hip'),
12:
dict(
name='right_hip',
id=12,
color=[255, 128, 0],
type='lower',
swap='left_hip'),
13:
dict(
name='left_knee',
id=13,
color=[0, 255, 0],
type='lower',
swap='right_knee'),
14:
dict(
name='right_knee',
id=14,
color=[255, 128, 0],
type='lower',
swap='left_knee'),
15:
dict(
name='left_ankle',
id=15,
color=[0, 255, 0],
type='lower',
swap='right_ankle'),
16:
dict(
name='right_ankle',
id=16,
color=[255, 128, 0],
type='lower',
swap='left_ankle')
},
skeleton_info={
0:
dict(link=('left_ankle', 'left_knee'), id=0, color=[0, 255, 0]),
1:
dict(link=('left_knee', 'left_hip'), id=1, color=[0, 255, 0]),
2:
dict(link=('right_ankle', 'right_knee'), id=2, color=[255, 128, 0]),
3:
dict(link=('right_knee', 'right_hip'), id=3, color=[255, 128, 0]),
4:
dict(link=('left_hip', 'right_hip'), id=4, color=[51, 153, 255]),
5:
dict(link=('left_shoulder', 'left_hip'), id=5, color=[51, 153, 255]),
6:
dict(link=('right_shoulder', 'right_hip'), id=6, color=[51, 153, 255]),
7:
dict(
link=('left_shoulder', 'right_shoulder'),
id=7,
color=[51, 153, 255]),
8:
dict(link=('left_shoulder', 'left_elbow'), id=8, color=[0, 255, 0]),
9:
dict(
link=('right_shoulder', 'right_elbow'), id=9, color=[255, 128, 0]),
10:
dict(link=('left_elbow', 'left_wrist'), id=10, color=[0, 255, 0]),
11:
dict(link=('right_elbow', 'right_wrist'), id=11, color=[255, 128, 0]),
12:
dict(link=('left_eye', 'right_eye'), id=12, color=[51, 153, 255]),
13:
dict(link=('nose', 'left_eye'), id=13, color=[51, 153, 255]),
14:
dict(link=('nose', 'right_eye'), id=14, color=[51, 153, 255]),
15:
dict(link=('left_eye', 'left_ear'), id=15, color=[51, 153, 255]),
16:
dict(link=('right_eye', 'right_ear'), id=16, color=[51, 153, 255]),
17:
dict(link=('left_ear', 'left_shoulder'), id=17, color=[51, 153, 255]),
18:
dict(
link=('right_ear', 'right_shoulder'), id=18, color=[51, 153, 255])
},
joint_weights=[
1., 1., 1., 1., 1., 1., 1., 1.2, 1.2, 1.5, 1.5, 1., 1., 1.2, 1.2, 1.5,
1.5
],
sigmas=[
0.026, 0.025, 0.025, 0.035, 0.035, 0.079, 0.079, 0.072, 0.072, 0.062,
0.062, 0.107, 0.107, 0.087, 0.087, 0.089, 0.089
])
```
## 创建自定义数据集类
1. 首先在 mmpose/datasets/datasets 文件夹创建一个包,比如命名为 custom。
2. 定义数据集类,并且注册这个类。
```
@DATASETS.register_module(name='MyCustomDataset')
class MyCustomDataset(SomeOtherBaseClassAsPerYourNeed):
```
3. 为你的自定义类别创建 `mmpose/datasets/datasets/custom/__init__.py`
4. 更新 `mmpose/datasets/__init__.py`
## 创建和修改训练配置文件
创建和修改训练配置文件,来使用你的自定义数据集。
在 `configs/my_custom_config.py` 中,修改如下几行。
```python
...
# dataset settings
dataset_type = 'MyCustomDataset'
...
data = dict(
samples_per_gpu=2,
workers_per_gpu=2,
train=dict(
type=dataset_type,
ann_file='path/to/your/train/json',
img_prefix='path/to/your/train/img',
...),
val=dict(
type=dataset_type,
ann_file='path/to/your/val/json',
img_prefix='path/to/your/val/img',
...),
test=dict(
type=dataset_type,
ann_file='path/to/your/test/json',
img_prefix='path/to/your/test/img',
...))
...
```
@@ -0,0 +1,151 @@
# 教程 3: 自定义数据前处理流水线
## 设计数据前处理流水线
参照惯例,MMPose 使用 `Dataset` 和 `DataLoader` 实现多进程数据加载。
`Dataset` 返回一个字典,作为模型的输入。
由于姿态估计任务的数据大小不一定相同(图片大小,边界框大小等),MMPose 使用 MMCV 中的 `DataContainer` 收集和分配不同大小的数据。
详情可见[此处](https://github.com/open-mmlab/mmcv/blob/master/mmcv/parallel/data_container.py)。
数据前处理流水线和数据集是相互独立的。
通常,数据集定义如何处理标注文件,而数据前处理流水线将原始数据处理成网络输入。
数据前处理流水线包含一系列操作。
每个操作都输入一个字典(dict),新增/更新/删除相关字段,最终输出更新后的字典作为下一个操作的输入。
数据前处理流水线的操作可以被分类为数据加载、预处理、格式化和生成监督等(后文将详细介绍)。
这里以 Simple Baseline (ResNet50) 的数据前处理流水线为例:
```python
train_pipeline = [
dict(type='LoadImageFromFile'),
dict(type='TopDownRandomFlip', flip_prob=0.5),
dict(type='TopDownHalfBodyTransform', num_joints_half_body=8, prob_half_body=0.3),
dict(type='TopDownGetRandomScaleRotation', rot_factor=40, scale_factor=0.5),
dict(type='TopDownAffine'),
dict(type='ToTensor'),
dict(
type='NormalizeTensor',
mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225]),
dict(type='TopDownGenerateTarget', sigma=2),
dict(
type='Collect',
keys=['img', 'target', 'target_weight'],
meta_keys=[
'image_file', 'joints_3d', 'joints_3d_visible', 'center', 'scale',
'rotation', 'bbox_score', 'flip_pairs'
]),
]
val_pipeline = [
dict(type='LoadImageFromFile'),
dict(type='TopDownAffine'),
dict(type='ToTensor'),
dict(
type='NormalizeTensor',
mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225]),
dict(
type='Collect',
keys=['img'],
meta_keys=[
'image_file', 'center', 'scale', 'rotation', 'bbox_score',
'flip_pairs'
]),
]
```
下面列出每个操作新增/更新/删除的相关字典字段。
### 数据加载
`LoadImageFromFile`
- 新增: img, img_file
### 预处理
`TopDownRandomFlip`
- 更新: img, joints_3d, joints_3d_visible, center
`TopDownHalfBodyTransform`
- 更新: center, scale
`TopDownGetRandomScaleRotation`
- 更新: scale, rotation
`TopDownAffine`
- 更新: img, joints_3d, joints_3d_visible
`NormalizeTensor`
- 更新: img
### 生成监督
`TopDownGenerateTarget`
- 新增: target, target_weight
### 格式化
`ToTensor`
- 更新: 'img'
`Collect`
- 新增: img_meta (其包含的字段由 `meta_keys` 指定)
- 删除: 除了 `keys` 指定以外的所有字段
## 扩展和使用自定义流水线
1. 将一个新的处理流水线操作写入任一文件中,例如 `my_pipeline.py`。它以一个字典作为输入,并返回一个更新后的字典。
```python
from mmpose.datasets import PIPELINES
@PIPELINES.register_module()
class MyTransform:
def __call__(self, results):
results['dummy'] = True
return results
```
1. 导入定义好的新类。
```python
from .my_pipeline import MyTransform
```
1. 在配置文件中使用它。
```python
train_pipeline = [
dict(type='LoadImageFromFile'),
dict(type='TopDownRandomFlip', flip_prob=0.5),
dict(type='TopDownHalfBodyTransform', num_joints_half_body=8, prob_half_body=0.3),
dict(type='TopDownGetRandomScaleRotation', rot_factor=40, scale_factor=0.5),
dict(type='TopDownAffine'),
dict(type='MyTransform'),
dict(type='ToTensor'),
dict(
type='NormalizeTensor',
mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225]),
dict(type='TopDownGenerateTarget', sigma=2),
dict(
type='Collect',
keys=['img', 'target', 'target_weight'],
meta_keys=[
'image_file', 'joints_3d', 'joints_3d_visible', 'center', 'scale',
'rotation', 'bbox_score', 'flip_pairs'
]),
]
```
@@ -0,0 +1,214 @@
# 教程 4: 增加新的模块
## 自定义优化器
在本教程中,我们将介绍如何为项目定制优化器.
假设想要添加一个名为 `MyOptimizer` 的优化器,它有 `a`,`b` 和 `c` 三个参数。
那么首先需要在一个文件中实现该优化器,例如 `mmpose/core/optimizer/my_optimizer.py`:
```python
from mmcv.runner import OPTIMIZERS
from torch.optim import Optimizer
@OPTIMIZERS.register_module()
class MyOptimizer(Optimizer):
def __init__(self, a, b, c)
```
然后需要将其添加到 `mmpose/core/optimizer/__init__.py` 中,从而让注册器可以找到这个新的优化器并添加它:
```python
from .my_optimizer import MyOptimizer
```
之后,可以在配置文件的 `optimizer` 字段中使用 `MyOptimizer`。
在配置中,优化器由 `optimizer` 字段所定义,如下所示:
```python
optimizer = dict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.0001)
```
若要使用自己新定义的优化器,可以将字段修改为:
```python
optimizer = dict(type='MyOptimizer', a=a_value, b=b_value, c=c_value)
```
我们已经支持使用 PyTorch 实现的所有优化器,
只需要更改配置文件的 `optimizer` 字段。
例如:若用户想要使用`ADAM`优化器,只需要做出如下修改,虽然这会造成网络效果下降。
```python
optimizer = dict(type='Adam', lr=0.0003, weight_decay=0.0001)
```
用户可以直接根据 [PyTorch API 文档](https://pytorch.org/docs/stable/optim.html?highlight=optim#module-torch.optim)
对参数进行设置。
## 自定义优化器构造器
某些模型可能对不同层的参数有特定的优化设置,例如 BatchNorm 层的权值衰减。
用户可以通过自定义优化器构造函数来进行这些细粒度的参数调整。
```python
from mmcv.utils import build_from_cfg
from mmcv.runner import OPTIMIZER_BUILDERS, OPTIMIZERS
from mmpose.utils import get_root_logger
from .cocktail_optimizer import CocktailOptimizer
@OPTIMIZER_BUILDERS.register_module()
class CocktailOptimizerConstructor:
def __init__(self, optimizer_cfg, paramwise_cfg=None):
def __call__(self, model):
return my_optimizer
```
## 开发新组件
MMPose 将模型组件分为 3 种基础模型:
- 检测器(detector):整个检测器模型流水线,通常包含一个主干网络(backbone)和关键点头(keypoint_head)。
- 主干网络(backbone):通常为一个用于提取特征的 FCN 网络,例如 ResNet,HRNet。
- 关键点头(keypoint_head):用于姿势估计的组件,通常包括一系列反卷积层。
1. 创建一个新文件 `mmpose/models/backbones/my_model.py`.
```python
import torch.nn as nn
from ..builder import BACKBONES
@BACKBONES.register_module()
class MyModel(nn.Module):
def __init__(self, arg1, arg2):
pass
def forward(self, x): # should return a tuple
pass
def init_weights(self, pretrained=None):
pass
```
2. 在 `mmpose/models/backbones/__init__.py` 中导入新的主干网络.
```python
from .my_model import MyModel
```
3. 创建一个新文件 `mmpose/models/keypoint_heads/my_head.py`.
用户可以通过继承 `nn.Module` 编写一个新的关键点头,
并重写 `init_weights(self)` 和 `forward(self, x)` 方法。
```python
from ..builder import HEADS
@HEADS.register_module()
class MyHead(nn.Module):
def __init__(self, arg1, arg2):
pass
def forward(self, x):
pass
def init_weights(self):
pass
```
4. 在 `mmpose/models/keypoint_heads/__init__.py` 中导入新的关键点头
```python
from .my_head import MyHead
```
5. 在配置文件中使用它。
对于自顶向下的 2D 姿态估计模型,我们将模型类型设置为 `TopDown`。
```python
model = dict(
type='TopDown',
backbone=dict(
type='MyModel',
arg1=xxx,
arg2=xxx),
keypoint_head=dict(
type='MyHead',
arg1=xxx,
arg2=xxx))
```
### 添加新的损失函数
假设用户想要为关键点估计添加一个名为 `MyLoss`的新损失函数。
为了添加一个新的损失函数,用户需要在 `mmpose/models/losses/my_loss.py` 下实现该函数。
其中,装饰器 `weighted_loss` 使损失函数能够为每个元素加权。
```python
import torch
import torch.nn as nn
from mmpose.models import LOSSES
def my_loss(pred, target):
assert pred.size() == target.size() and target.numel() > 0
loss = torch.abs(pred - target)
loss = torch.mean(loss)
return loss
@LOSSES.register_module()
class MyLoss(nn.Module):
def __init__(self, use_target_weight=False):
super(MyLoss, self).__init__()
self.criterion = my_loss()
self.use_target_weight = use_target_weight
def forward(self, output, target, target_weight):
batch_size = output.size(0)
num_joints = output.size(1)
heatmaps_pred = output.reshape(
(batch_size, num_joints, -1)).split(1, 1)
heatmaps_gt = target.reshape((batch_size, num_joints, -1)).split(1, 1)
loss = 0.
for idx in range(num_joints):
heatmap_pred = heatmaps_pred[idx].squeeze(1)
heatmap_gt = heatmaps_gt[idx].squeeze(1)
if self.use_target_weight:
loss += self.criterion(
heatmap_pred * target_weight[:, idx],
heatmap_gt * target_weight[:, idx])
else:
loss += self.criterion(heatmap_pred, heatmap_gt)
return loss / num_joints
```
之后,用户需要把它添加进 `mmpose/models/losses/__init__.py`。
```python
from .my_loss import MyLoss, my_loss
```
若要使用新的损失函数,可以修改模型中的 `loss_keypoint` 字段。
```python
loss_keypoint=dict(type='MyLoss', use_target_weight=False)
```
@@ -0,0 +1,48 @@
# 教程 5:如何导出模型为 onnx 格式
开放式神经网络交换格式(Open Neural Network Exchange,即 [ONNX](https://onnx.ai/))是各种框架共用的一种模型交换格式,AI 开发人员可以方便将模型部署到所需的框架之中。
<!-- TOC -->
- [支持的模型](#支持的模型)
- [如何使用](#如何使用)
- [准备工作](#准备工作)
<!-- TOC -->
## 支持的模型
MMPose 支持将训练好的各种 Pytorch 模型导出为 ONNX 格式。支持的模型包括但不限于:
- ResNet
- HRNet
- HigherHRNet
## 如何使用
用户可以使用这里的 [脚本](/tools/deployment/pytorch2onnx.py) 来导出 ONNX 格式。
### 准备工作
首先,安装 onnx
```shell
pip install onnx onnxruntime
```
MMPose 提供了一个 python 脚本,将 MMPose 训练的 pytorch 模型导出到 ONNX。
```shell
python tools/deployment/pytorch2onnx.py ${CONFIG_FILE} ${CHECKPOINT_FILE} [--shape ${SHAPE}] \
[--verify] [--show] [--output-file ${OUTPUT_FILE}] [--is-localizer] [--opset-version ${VERSION}]
```
可选参数:
- `--shape`: 模型输入张量的形状。对于 2D 关键点检测模型(如 HRNet),输入形状应当为 `$batch $channel $height $width` (例如,`1 3 256 192`);
- `--verify`: 是否对导出模型进行验证,验证项包括是否可运行,数值是否正确等。如果没有手动指定,默认为 `False`。
- `--show`: 是否打印导出模型的结构。如果没有手动指定,默认为 `False`。
- `--output-file`: 导出的 onnx 模型名。如果没有手动指定,默认为 `tmp.onnx`。
- `--opset-version`:决定 onnx 的执行版本,MMPose 推荐用户使用高版本(例如 11 版本)的 onnx 以确保稳定性。如果没有手动指定,默认为 `11`。
如果发现提供的模型权重文件没有被成功导出,或者存在精度损失,可以在本 repo 下提出问题(issue)。
@@ -0,0 +1,3 @@
# 教程 6: 自定义运行时设置
内容建设中……
@@ -0,0 +1,3 @@
# 常用工具
内容建设中……