Commit 5b3e36dc authored by Sugon_ldc's avatar Sugon_ldc
Browse files

add model TSM

parents
Pipeline #315 failed with stages
in 0 seconds
mmaction.apis
-------------
.. automodule:: mmaction.apis
:members:
mmaction.core
-------------
optimizer
^^^^^^^^^
.. automodule:: mmaction.core.optimizer
:members:
evaluation
^^^^^^^^^^
.. automodule:: mmaction.core.evaluation
:members:
scheduler
^^
.. automodule:: mmaction.core.scheduler
:members:
mmaction.localization
---------------------
localization
^^^^^^^^^^^^
.. automodule:: mmaction.localization
:members:
mmaction.models
---------------
models
^^^^^^
.. automodule:: mmaction.models
:members:
recognizers
^^^^^^^^^^^
.. automodule:: mmaction.models.recognizers
:members:
localizers
^^^^^^^^^^
.. automodule:: mmaction.models.localizers
:members:
common
^^^^^^
.. automodule:: mmaction.models.common
:members:
backbones
^^^^^^^^^
.. automodule:: mmaction.models.backbones
:members:
heads
^^^^^
.. automodule:: mmaction.models.heads
:members:
necks
^^^^^
.. automodule:: mmaction.models.necks
:members:
losses
^^^^^^
.. automodule:: mmaction.models.losses
:members:
mmaction.datasets
-----------------
datasets
^^^^^^^^
.. automodule:: mmaction.datasets
:members:
pipelines
^^^^^^^^^
.. automodule:: mmaction.datasets.pipelines
:members:
samplers
^^^^^^^^
.. automodule:: mmaction.datasets.samplers
:members:
mmaction.utils
--------------
.. automodule:: mmaction.utils
:members:
mmaction.localization
---------------------
.. automodule:: mmaction.localization
:members:
# 基准测试
这里将 MMAction2 与其他流行的代码框架和官方开源代码的速度性能进行对比
## 配置
### 硬件环境
- 8 NVIDIA Tesla V100 (32G) GPUs
- Intel(R) Xeon(R) Gold 6146 CPU @ 3.20GHz
### 软件环境
- Python 3.7
- PyTorch 1.4
- CUDA 10.1
- CUDNN 7.6.03
- NCCL 2.4.08
### 评测指标
这里测量的时间是一轮训练迭代的平均时间,包括数据处理和模型训练。
训练速度以 s/iter 为单位,其值越低越好。注意,这里跳过了前 50 个迭代时间,因为它们可能包含设备的预热时间。
### 比较规则
这里以一轮训练迭代时间为基准,使用了相同的数据和模型设置对 MMAction2 和其他的视频理解工具箱进行比较。参与评测的其他代码库包括
- MMAction: commit id [7f3490d](https://github.com/open-mmlab/mmaction/tree/7f3490d3db6a67fe7b87bfef238b757403b670e3)(1/5/2020)
- Temporal-Shift-Module: commit id [8d53d6f](https://github.com/mit-han-lab/temporal-shift-module/tree/8d53d6fda40bea2f1b37a6095279c4b454d672bd)(5/5/2020)
- PySlowFast: commit id [8299c98](https://github.com/facebookresearch/SlowFast/tree/8299c9862f83a067fa7114ce98120ae1568a83ec)(7/7/2020)
- BSN(boundary sensitive network): commit id [f13707f](https://github.com/wzmsltw/BSN-boundary-sensitive-network/tree/f13707fbc362486e93178c39f9c4d398afe2cb2f)(12/12/2018)
- BMN(boundary matching network): commit id [45d0514](https://github.com/JJBOY/BMN-Boundary-Matching-Network/tree/45d05146822b85ca672b65f3d030509583d0135a)(17/10/2019)
为了公平比较,这里基于相同的硬件环境和数据进行对比实验。
使用的视频帧数据集是通过 [数据准备工具](/tools/data/kinetics/README.md) 生成的,
使用的视频数据集是通过 [该脚本](/tools/data/resize_videos.py) 生成的,以快速解码为特点的,"短边 256,密集关键帧编码“的视频数据集。
正如以下表格所示,在对比正常的短边 256 视频时,可以观察到速度上的显著提升,尤其是在采样特别稀疏的情况下,如 [TSN](/configs/recognition/tsn/tsn_r50_video_320p_1x1x3_100e_kinetics400_rgb.py)
## 主要结果
### 行为识别器
| 模型 | 输入 | IO 后端 | 批大小 x GPU 数量 | MMAction2 (s/iter) | GPU 显存占用 (GB) | MMAction (s/iter) | GPU 显存占用 (GB) | Temporal-Shift-Module (s/iter) | GPU 显存占用 (GB) | PySlowFast (s/iter) | GPU 显存占用 (GB) |
| :------------------------------------------------------------------------------------------ | :----------------------: | :-------: | :---------------: | :-------------------------------------------------------------------------------------------------------------------------: | :---------------: | :------------------------------------------------------------------------------------------------------------------: | :---------------: | :-------------------------------------------------------------------------------------------------------------------------------: | :---------------: | :--------------------------------------------------------------------------------------------------------------------: | :---------------: |
| [TSN](/configs/recognition/tsn/tsn_r50_1x1x3_100e_kinetics400_rgb.py) | 256p rawframes | Memcached | 32x8 | **[0.32](https://download.openmmlab.com/mmaction/benchmark/recognition/mmaction2/tsn_256p_rawframes_memcahed_32x8.zip)** | 8.1 | [0.38](https://download.openmmlab.com/mmaction/benchmark/recognition/mmaction/tsn_256p_rawframes_memcached_32x8.zip) | 8.1 | [0.42](https://download.openmmlab.com/mmaction/benchmark/recognition/temporal_shift_module/tsn_256p_rawframes_memcached_32x8.zip) | 10.5 | x | x |
| [TSN](/configs/recognition/tsn/tsn_r50_1x1x3_100e_kinetics400_rgb.py) | 256p videos | Disk | 32x8 | **[1.42](https://download.openmmlab.com/mmaction/benchmark/recognition/mmaction2/tsn_256p_videos_disk_32x8.zip)** | 8.1 | x | x | x | x | TODO | TODO |
| [TSN](/configs/recognition/tsn/tsn_r50_1x1x3_100e_kinetics400_rgb.py) | 256p dense-encoded video | Disk | 32x8 | **[0.61](https://download.openmmlab.com/mmaction/benchmark/recognition/mmaction2/tsn_256p_fast_videos_disk_32x8.zip)** | 8.1 | x | x | x | x | TODO | TODO |
| [I3D heavy](/configs/recognition/i3d/i3d_r50_video_heavy_8x8x1_100e_kinetics400_rgb.py) | 256p videos | Disk | 8x8 | **[0.34](https://download.openmmlab.com/mmaction/benchmark/recognition/mmaction2/i3d_heavy_256p_videos_disk_8x8.zip)** | 4.6 | x | x | x | x | [0.44](https://download.openmmlab.com/mmaction/benchmark/recognition/pyslowfast/pysf_i3d_r50_8x8_video.log) | 4.6 |
| [I3D heavy](/configs/recognition/i3d/i3d_r50_video_heavy_8x8x1_100e_kinetics400_rgb.py) | 256p dense-encoded video | Disk | 8x8 | **[0.35](https://download.openmmlab.com/mmaction/benchmark/recognition/mmaction2/i3d_heavy_256p_fast_videos_disk_8x8.zip)** | 4.6 | x | x | x | x | [0.36](https://download.openmmlab.com/mmaction/benchmark/recognition/pyslowfast/pysf_i3d_r50_8x8_fast_video.log) | 4.6 |
| [I3D](/configs/recognition/i3d/i3d_r50_32x2x1_100e_kinetics400_rgb.py) | 256p rawframes | Memcached | 8x8 | **[0.43](https://download.openmmlab.com/mmaction/benchmark/recognition/mmaction2/i3d_256p_rawframes_memcahed_8x8.zip)** | 5.0 | [0.56](https://download.openmmlab.com/mmaction/benchmark/recognition/mmaction/i3d_256p_rawframes_memcached_8x8.zip) | 5.0 | x | x | x | x |
| [TSM](/configs/recognition/tsm/tsm_r50_1x1x8_50e_kinetics400_rgb.py) | 256p rawframes | Memcached | 8x8 | **[0.31](https://download.openmmlab.com/mmaction/benchmark/recognition/mmaction2/tsm_256p_rawframes_memcahed_8x8.zip)** | 6.9 | x | x | [0.41](https://download.openmmlab.com/mmaction/benchmark/recognition/temporal_shift_module/tsm_256p_rawframes_memcached_8x8.zip) | 9.1 | x | x |
| [Slowonly](/configs/recognition/slowonly/slowonly_r50_video_4x16x1_256e_kinetics400_rgb.py) | 256p videos | Disk | 8x8 | **[0.32](https://download.openmmlab.com/mmaction/benchmark/recognition/mmaction2/slowonly_256p_videos_disk_8x8.zip)** | 3.1 | TODO | TODO | x | x | [0.34](https://download.openmmlab.com/mmaction/benchmark/recognition/pyslowfast/pysf_slowonly_r50_4x16_video.log) | 3.4 |
| [Slowonly](/configs/recognition/slowonly/slowonly_r50_video_4x16x1_256e_kinetics400_rgb.py) | 256p dense-encoded video | Disk | 8x8 | **[0.25](https://download.openmmlab.com/mmaction/benchmark/recognition/mmaction2/slowonly_256p_fast_videos_disk_8x8.zip)** | 3.1 | TODO | TODO | x | x | [0.28](https://download.openmmlab.com/mmaction/benchmark/recognition/pyslowfast/pysf_slowonly_r50_4x16_fast_video.log) | 3.4 |
| [Slowfast](/configs/recognition/slowfast/slowfast_r50_video_4x16x1_256e_kinetics400_rgb.py) | 256p videos | Disk | 8x8 | **[0.69](https://download.openmmlab.com/mmaction/benchmark/recognition/mmaction2/slowfast_256p_videos_disk_8x8.zip)** | 6.1 | x | x | x | x | [1.04](https://download.openmmlab.com/mmaction/benchmark/recognition/pyslowfast/pysf_slowfast_r50_4x16_video.log) | 7.0 |
| [Slowfast](/configs/recognition/slowfast/slowfast_r50_video_4x16x1_256e_kinetics400_rgb.py) | 256p dense-encoded video | Disk | 8x8 | **[0.68](https://download.openmmlab.com/mmaction/benchmark/recognition/mmaction2/slowfast_256p_fast_videos_disk_8x8.zip)** | 6.1 | x | x | x | x | [0.96](https://download.openmmlab.com/mmaction/benchmark/recognition/pyslowfast/pysf_slowfast_r50_4x16_fast_video.log) | 7.0 |
| [R(2+1)D](/configs/recognition/r2plus1d/r2plus1d_r34_video_8x8x1_180e_kinetics400_rgb.py) | 256p videos | Disk | 8x8 | **[0.45](https://download.openmmlab.com/mmaction/benchmark/recognition/mmaction2/r2plus1d_256p_videos_disk_8x8.zip)** | 5.1 | x | x | x | x | x | x |
| [R(2+1)D](/configs/recognition/r2plus1d/r2plus1d_r34_video_8x8x1_180e_kinetics400_rgb.py) | 256p dense-encoded video | Disk | 8x8 | **[0.44](https://download.openmmlab.com/mmaction/benchmark/recognition/mmaction2/r2plus1d_256p_fast_videos_disk_8x8.zip)** | 5.1 | x | x | x | x | x | x |
### 时序动作检测器
| Model | MMAction2 (s/iter) | BSN(boundary sensitive network) (s/iter) | BMN(boundary matching network) (s/iter) |
| :------------------------------------------------------------------------------------------------------------------ | :-----------------------: | :--------------------------------------: | :-------------------------------------: |
| BSN ([TEM + PEM + PGM](/configs/localization/bsn)) | **0.074(TEM)+0.040(PEM)** | 0.101(TEM)+0.040(PEM) | x |
| BMN ([bmn_400x100_2x8_9e_activitynet_feature](/configs/localization/bmn/bmn_400x100_2x8_9e_activitynet_feature.py)) | **3.27** | x | 3.30 |
## 比较细节
### TSN
- **MMAction2**
```shell
# 处理视频帧
bash tools/slurm_train.sh ${PARTATION_NAME} benchmark_tsn configs/recognition/tsn/tsn_r50_1x1x3_100e_kinetics400_rgb.py --work-dir work_dirs/benchmark_tsn_rawframes
# 处理视频
bash tools/slurm_train.sh ${PARTATION_NAME} benchmark_tsn configs/recognition/tsn/tsn_r50_video_1x1x3_100e_kinetics400_rgb.py --work-dir work_dirs/benchmark_tsn_video
```
- **MMAction**
```shell
python -u tools/train_recognizer.py configs/TSN/tsn_kinetics400_2d_rgb_r50_seg3_f1s1.py
```
- **Temporal-Shift-Module**
```shell
python main.py kinetics RGB --arch resnet50 --num_segments 3 --gd 20 --lr 0.02 --wd 1e-4 --lr_steps 20 40 --epochs 1 --batch-size 256 -j 32 --dropout 0.5 --consensus_type=avg --eval-freq=10 --npb --print-freq 1
```
### I3D
- **MMAction2**
```shell
# 处理视频帧
bash tools/slurm_train.sh ${PARTATION_NAME} benchmark_i3d configs/recognition/i3d/i3d_r50_32x2x1_100e_kinetics400_rgb.py --work-dir work_dirs/benchmark_i3d_rawframes
# 处理视频
bash tools/slurm_train.sh ${PARTATION_NAME} benchmark_i3d configs/recognition/i3d/i3d_r50_video_heavy_8x8x1_100e_kinetics400_rgb.py --work-dir work_dirs/benchmark_i3d_video
```
- **MMAction**
```shell
python -u tools/train_recognizer.py configs/I3D_RGB/i3d_kinetics400_3d_rgb_r50_c3d_inflate3x1x1_seg1_f32s2.py
```
- **PySlowFast**
```shell
python tools/run_net.py --cfg configs/Kinetics/I3D_8x8_R50.yaml DATA.PATH_TO_DATA_DIR ${DATA_ROOT} NUM_GPUS 8 TRAIN.BATCH_SIZE 64 TRAIN.AUTO_RESUME False LOG_PERIOD 1 SOLVER.MAX_EPOCH 1 > pysf_i3d_r50_8x8_video.log
```
可以通过编写一个简单的脚本对日志文件的 'time_diff' 域进行解析,以复现对应的结果。
### SlowFast
- **MMAction2**
```shell
bash tools/slurm_train.sh ${PARTATION_NAME} benchmark_slowfast configs/recognition/slowfast/slowfast_r50_video_4x16x1_256e_kinetics400_rgb.py --work-dir work_dirs/benchmark_slowfast_video
```
- **MMAction**
```shell
python tools/run_net.py --cfg configs/Kinetics/SLOWFAST_4x16_R50.yaml DATA.PATH_TO_DATA_DIR ${DATA_ROOT} NUM_GPUS 8 TRAIN.BATCH_SIZE 64 TRAIN.AUTO_RESUME False LOG_PERIOD 1 SOLVER.MAX_EPOCH 1 > pysf_slowfast_r50_4x16_video.log
```
可以通过编写一个简单的脚本对日志文件的 'time_diff' 域进行解析,以复现对应的结果。
### SlowOnly
- **MMAction2**
```shell
bash tools/slurm_train.sh ${PARTATION_NAME} benchmark_slowonly configs/recognition/slowonly/slowonly_r50_video_4x16x1_256e_kinetics400_rgb.py --work-dir work_dirs/benchmark_slowonly_video
```
- **PySlowFast**
```shell
python tools/run_net.py --cfg configs/Kinetics/SLOW_4x16_R50.yaml DATA.PATH_TO_DATA_DIR ${DATA_ROOT} NUM_GPUS 8 TRAIN.BATCH_SIZE 64 TRAIN.AUTO_RESUME False LOG_PERIOD 1 SOLVER.MAX_EPOCH 1 > pysf_slowonly_r50_4x16_video.log
```
可以通过编写一个简单的脚本对日志文件的 'time_diff' 域进行解析,以复现对应的结果。
### R2plus1D
- **MMAction2**
```shell
bash tools/slurm_train.sh ${PARTATION_NAME} benchmark_r2plus1d configs/recognition/r2plus1d/r2plus1d_r34_video_8x8x1_180e_kinetics400_rgb.py --work-dir work_dirs/benchmark_r2plus1d_video
```
# 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 = 'MMAction2'
copyright = '2020, OpenMMLab'
author = 'MMAction2 Authors'
version_file = '../../mmaction/version.py'
def get_version():
with open(version_file, 'r') as f:
exec(compile(f.read(), version_file, 'exec'))
return locals()['__version__']
# The full version, including alpha/beta/rc tags
release = get_version()
# -- General configuration ---------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc', 'sphinx.ext.napoleon', 'sphinx.ext.viewcode',
'sphinx_markdown_tables', 'sphinx_copybutton', 'myst_parser'
]
# numpy and torch are required
autodoc_mock_imports = ['mmaction.version', 'PIL']
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 = {
# 'logo_url': 'https://mmocr.readthedocs.io/en/latest/',
'menu': [
{
'name':
'教程',
'url':
'https://colab.research.google.com/github/'
'open-mmlab/mmaction2/blob/master/demo/'
'mmaction2_tutorial_zh-CN.ipynb'
},
{
'name': 'GitHub',
'url': 'https://github.com/open-mmlab/mmaction2'
},
{
'name':
'上游代码库',
'children': [
{
'name': 'MMCV',
'url': 'https://github.com/open-mmlab/mmcv',
'description': '计算机视觉基础库'
},
{
'name': 'MMClassification',
'url': 'https://github.com/open-mmlab/mmclassification',
'description': '图像分类代码库'
},
{
'name': 'MMDetection',
'url': 'https://github.com/open-mmlab/mmdetection',
'description': '物体检测代码库'
},
]
},
],
# Specify the language of shared menu
'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".
html_static_path = ['_static']
html_css_files = ['css/readthedocs.css']
myst_enable_extensions = ['colon_fence']
myst_heading_anchors = 3
language = 'zh_CN'
master_doc = 'index'
def builder_inited_handler(app):
subprocess.run(['./merge_docs.sh'])
subprocess.run(['./stat.py'])
def setup(app):
app.connect('builder-inited', builder_inited_handler)
# 准备数据
本文为 MMAction2 的数据准备提供一些指南。
<!-- TOC -->
- [准备数据](#准备数据)
- [视频格式数据的一些注意事项](#视频格式数据的一些注意事项)
- [获取数据](#获取数据)
- [准备视频](#准备视频)
- [提取帧](#提取帧)
- [denseflow 的替代项](#denseflow-的替代项)
- [生成文件列表](#生成文件列表)
- [准备音频](#准备音频)
<!-- TOC -->
## 视频格式数据的一些注意事项
MMAction2 支持两种数据类型:原始帧和视频。前者在过去的项目中经常出现,如 TSN。
如果能把原始帧存储在固态硬盘上,处理帧格式的数据是非常快的,但对于大规模的数据集来说,原始帧需要占据大量的磁盘空间。
(举例来说,最新版本的 [Kinetics](https://www.deepmind.com/open-source/kinetics) 有 650K 个视频,其所有原始帧需要占据几个 TB 的磁盘空间。)
视频格式的数据能够节省很多空间,但在运行模型时,必须进行视频解码,算力开销很大。
为了加速视频解码,MMAction2 支持了若干种高效的视频加载库,如 [decord](https://github.com/zhreshold/decord), [PyAV](https://github.com/PyAV-Org/PyAV) 等。
## 获取数据
本文介绍如何构建自定义数据集。
与上述数据集相似,推荐用户把数据放在 `$MMACTION2/data/$DATASET` 中。
### 准备视频
请参照官网或官方脚本准备视频。
注意,应该按照下面两种方法之一来组织视频数据文件夹结构:
(1) 形如 `${CLASS_NAME}/${VIDEO_ID}` 的两级文件目录结构,这种结构推荐在动作识别数据集中使用(如 UCF101 和 Kinetics)
(2) 单级文件目录结构,这种结构推荐在动作检测数据集或者多标签数据集中使用(如 THUMOS14)
### 提取帧
若想同时提取帧和光流,可以使用 OpenMMLab 准备的 [denseflow](https://github.com/open-mmlab/denseflow) 工具。
因为不同的帧提取工具可能产生不同数量的帧,建议使用同一工具来提取 RGB 帧和光流,以避免它们的数量不同。
```shell
python build_rawframes.py ${SRC_FOLDER} ${OUT_FOLDER} [--task ${TASK}] [--level ${LEVEL}] \
[--num-worker ${NUM_WORKER}] [--flow-type ${FLOW_TYPE}] [--out-format ${OUT_FORMAT}] \
[--ext ${EXT}] [--new-width ${NEW_WIDTH}] [--new-height ${NEW_HEIGHT}] [--new-short ${NEW_SHORT}] \
[--resume] [--use-opencv] [--mixed-ext]
```
- `SRC_FOLDER`: 视频源文件夹
- `OUT_FOLDER`: 存储提取出的帧和光流的根文件夹
- `TASK`: 提取任务,说明提取帧,光流,还是都提取,选项为 `rgb`, `flow`, `both`
- `LEVEL`: 目录层级。1 指单级文件目录,2 指两级文件目录
- `NUM_WORKER`: 提取原始帧的线程数
- `FLOW_TYPE`: 提取的光流类型,如 `None`, `tvl1`, `warp_tvl1`, `farn`, `brox`
- `OUT_FORMAT`: 提取帧的输出文件类型,如 `jpg`, `h5`, `png`
- `EXT`: 视频文件后缀名,如 `avi`, `mp4`
- `NEW_WIDTH`: 调整尺寸后,输出图像的宽
- `NEW_HEIGHT`: 调整尺寸后,输出图像的高
- `NEW_SHORT`: 等比例缩放图片后,输出图像的短边长
- `--resume`: 是否接续之前的光流提取任务,还是覆盖之前的输出结果重新提取
- `--use-opencv`: 是否使用 OpenCV 提取 RGB 帧
- `--mixed-ext`: 说明是否处理不同文件类型的视频文件
根据实际经验,推荐设置为:
1.`$OUT_FOLDER` 设置为固态硬盘上的文件夹。
2. 软连接 `$OUT_FOLDER``$MMACTION2/data/$DATASET/rawframes`
3. 使用 `new-short` 而不是 `new-width``new-height` 来调整图像尺寸
```shell
ln -s ${YOUR_FOLDER} $MMACTION2/data/$DATASET/rawframes
```
#### denseflow 的替代项
如果用户因依赖要求(如 Nvidia 显卡驱动版本),无法安装 [denseflow](https://github.com/open-mmlab/denseflow)
或者只需要一些关于光流提取的快速演示,可用 Python 脚本 `tools/misc/flow_extraction.py` 替代 denseflow。
这个脚本可用于一个或多个视频提取 RGB 帧和光流。注意,由于该脚本时在 CPU 上运行光流算法,其速度比 denseflow 慢很多。
```shell
python tools/misc/flow_extraction.py --input ${INPUT} [--prefix ${PREFIX}] [--dest ${DEST}] [--rgb-tmpl ${RGB_TMPL}] \
[--flow-tmpl ${FLOW_TMPL}] [--start-idx ${START_IDX}] [--method ${METHOD}] [--bound ${BOUND}] [--save-rgb]
```
- `INPUT`: 用于提取帧的视频,可以是单个视频或一个视频列表,视频列表应该是一个 txt 文件,并且只包含视频文件名,不包含目录
- `PREFIX`: 输入视频的前缀,当输入是一个视频列表时使用
- `DEST`: 保存提取出的帧的位置
- `RGB_TMPL`: RGB 帧的文件名格式
- `FLOW_TMPL`: 光流的文件名格式
- `START_IDX`: 提取帧的开始索引
- `METHOD`: 用于生成光流的方法
- `BOUND`: 光流的最大值
- `SAVE_RGB`: 同时保存提取的 RGB 帧
### 生成文件列表
MMAction2 提供了便利的脚本用于生成文件列表。在完成视频下载(或更进一步完成视频抽帧)后,用户可以使用如下的脚本生成文件列表。
```shell
cd $MMACTION2
python tools/data/build_file_list.py ${DATASET} ${SRC_FOLDER} [--rgb-prefix ${RGB_PREFIX}] \
[--flow-x-prefix ${FLOW_X_PREFIX}] [--flow-y-prefix ${FLOW_Y_PREFIX}] [--num-split ${NUM_SPLIT}] \
[--subset ${SUBSET}] [--level ${LEVEL}] [--format ${FORMAT}] [--out-root-path ${OUT_ROOT_PATH}] \
[--seed ${SEED}] [--shuffle]
```
- `DATASET`: 所要准备的数据集,例如:`ucf101` , `kinetics400` , `thumos14` , `sthv1` , `sthv2` 等。
- `SRC_FOLDER`: 存放对应格式的数据的目录:
- 如目录为 "$MMACTION2/data/$DATASET/rawframes",则需设置 `--format rawframes`
- 如目录为 "$MMACTION2/data/$DATASET/videos",则需设置 `--format videos`
- `RGB_PREFIX`: RGB 帧的文件前缀。
- `FLOW_X_PREFIX`: 光流 x 分量帧的文件前缀。
- `FLOW_Y_PREFIX`: 光流 y 分量帧的文件前缀。
- `NUM_SPLIT`: 数据集总共的划分个数。
- `SUBSET`: 需要生成文件列表的子集名称。可选项为 `train`, `val`, `test`
- `LEVEL`: 目录级别数量,1 表示一级目录(数据集中所有视频或帧文件夹位于同一目录), 2 表示二级目录(数据集中所有视频或帧文件夹按类别存放于各子目录)。
- `FORMAT`: 需要生成文件列表的源数据格式。可选项为 `rawframes`, `videos`
- `OUT_ROOT_PATH`: 生成文件的根目录。
- `SEED`: 随机种子。
- `--shuffle`: 是否打乱生成的文件列表。
至此为止,用户可参考 [基础教程](getting_started.md) 来进行模型的训练及测试。
### 准备音频
MMAction2 还提供如下脚本来提取音频的波形并生成梅尔频谱。
```shell
cd $MMACTION2
python tools/data/extract_audio.py ${ROOT} ${DST_ROOT} [--ext ${EXT}] [--num-workers ${N_WORKERS}] \
[--level ${LEVEL}]
```
- `ROOT`: 视频的根目录。
- `DST_ROOT`: 存放生成音频的根目录。
- `EXT`: 视频的后缀名,如 `mp4`
- `N_WORKERS`: 使用的进程数量。
成功提取出音频后,用户可参照 [配置文件](/configs/recognition_audio/resnet/tsn_r50_64x1x1_100e_kinetics400_audio.py) 在线解码并生成梅尔频谱。如果音频文件的目录结构与帧文件夹一致,用户可以直接使用帧数据所用的标注文件作为音频数据的标注文件。在线解码的缺陷在于速度较慢,因此,MMAction2 也提供如下脚本用于离线地生成梅尔频谱。
```shell
cd $MMACTION2
python tools/data/build_audio_features.py ${AUDIO_HOME_PATH} ${SPECTROGRAM_SAVE_PATH} [--level ${LEVEL}] \
[--ext $EXT] [--num-workers $N_WORKERS] [--part $PART]
```
- `AUDIO_HOME_PATH`: 音频文件的根目录。
- `SPECTROGRAM_SAVE_PATH`: 存放生成音频特征的根目录。
- `EXT`: 音频的后缀名,如 `m4a`
- `N_WORKERS`: 使用的进程数量。
- `PART`: 将完整的解码任务分为几部分并执行其中一份。如 `2/5` 表示将所有待解码数据分成 5 份,并对其中的第 2 份进行解码。这一选项在用户有多台机器时发挥作用。
梅尔频谱特征所对应的标注文件与帧文件夹一致,用户可以直接复制 `dataset_[train/val]_list_rawframes.txt` 并将其重命名为 `dataset_[train/val]_list_audio_feature.txt`
# Demo 示例
## 目录
- [Demo 示例](#demo-示例)
- [目录](#目录)
- [预测视频的动作标签](#预测视频的动作标签)
- [预测视频的时空检测结果](#预测视频的时空检测结果)
- [可视化输入视频的 GradCAM](#可视化输入视频的-gradcam)
- [使用网络摄像头的实时动作识别](#使用网络摄像头的实时动作识别)
- [滑动窗口预测长视频中不同动作类别](#滑动窗口预测长视频中不同动作类别)
- [基于网络摄像头的实时时空动作检测](#基于网络摄像头的实时时空动作检测)
- [基于人体姿态预测动作标签](#基于人体姿态预测动作标签)
- [视频结构化预测](#视频结构化预测)
- [基于音频的动作识别](#基于音频的动作识别)
## 预测视频的动作标签
MMAction2 提供如下脚本以预测视频的动作标签。为得到 \[0, 1\] 间的动作分值,请确保在配置文件中设定 `model['test_cfg'] = dict(average_clips='prob')`
```shell
python demo/demo.py ${CONFIG_FILE} ${CHECKPOINT_FILE} ${VIDEO_FILE} {LABEL_FILE} [--use-frames] \
[--device ${DEVICE_TYPE}] [--fps {FPS}] [--font-scale {FONT_SCALE}] [--font-color {FONT_COLOR}] \
[--target-resolution ${TARGET_RESOLUTION}] [--resize-algorithm {RESIZE_ALGORITHM}] [--out-filename {OUT_FILE}]
```
可选参数:
- `--use-frames`: 如指定,代表使用帧目录作为输入;否则代表使用视频作为输入。
- `DEVICE_TYPE`: 指定脚本运行设备,支持 cuda 设备(如 `cuda:0`)或 cpu(`cpu`)。默认为 `cuda:0`
- `FPS`: 使用帧目录作为输入时,代表输入的帧率。默认为 30。
- `FONT_SCALE`: 输出视频上的字体缩放比例。默认为 0.5。
- `FONT_COLOR`: 输出视频上的字体颜色,默认为白色( `white`)。
- `TARGET_RESOLUTION`: 输出视频的分辨率,如未指定,使用输入视频的分辨率。
- `RESIZE_ALGORITHM`: 缩放视频时使用的插值方法,默认为 `bicubic`
- `OUT_FILE`: 输出视频的路径,如未指定,则不会生成输出视频。
示例:
以下示例假设用户的当前目录为 `$MMACTION2`,并已经将所需的模型权重文件下载至目录 `checkpoints/` 下,用户也可以使用所提供的 URL 来直接加载模型权重,文件将会被默认下载至 `$HOME/.cache/torch/checkpoints`
1. 在 cuda 设备上,使用 TSN 模型进行视频识别:
```shell
# demo.mp4 及 label_map_k400.txt 均来自 Kinetics-400 数据集
python demo/demo.py configs/recognition/tsn/tsn_r50_video_inference_1x1x3_100e_kinetics400_rgb.py \
checkpoints/tsn_r50_1x1x3_100e_kinetics400_rgb_20200614-e508be42.pth \
demo/demo.mp4 tools/data/kinetics/label_map_k400.txt
```
2. 在 cuda 设备上,使用 TSN 模型进行视频识别,并利用 URL 加载模型权重文件:
```shell
# demo.mp4 及 label_map_k400.txt 均来自 Kinetics-400 数据集
python demo/demo.py configs/recognition/tsn/tsn_r50_video_inference_1x1x3_100e_kinetics400_rgb.py \
https://download.openmmlab.com/mmaction/recognition/tsn/tsn_r50_1x1x3_100e_kinetics400_rgb/tsn_r50_1x1x3_100e_kinetics400_rgb_20200614-e508be42.pth \
demo/demo.mp4 tools/data/kinetics/label_map_k400.txt
```
3. 在 CPU 上,使用 TSN 模型进行视频识别,输入为视频抽好的帧:
```shell
python demo/demo.py configs/recognition/tsn/tsn_r50_inference_1x1x3_100e_kinetics400_rgb.py \
checkpoints/tsn_r50_1x1x3_100e_kinetics400_rgb_20200614-e508be42.pth \
PATH_TO_FRAMES/ LABEL_FILE --use-frames --device cpu
```
4. 使用 TSN 模型进行视频识别,输出 MP4 格式的识别结果:
```shell
# demo.mp4 及 label_map_k400.txt 均来自 Kinetics-400 数据集
python demo/demo.py configs/recognition/tsn/tsn_r50_video_inference_1x1x3_100e_kinetics400_rgb.py \
checkpoints/tsn_r50_1x1x3_100e_kinetics400_rgb_20200614-e508be42.pth \
demo/demo.mp4 tools/data/kinetics/label_map_k400.txt --out-filename demo/demo_out.mp4
```
5. 使用 TSN 模型进行视频识别,输入为视频抽好的帧,将识别结果存为 GIF 格式:
```shell
python demo/demo.py configs/recognition/tsn/tsn_r50_inference_1x1x3_100e_kinetics400_rgb.py \
checkpoints/tsn_r50_1x1x3_100e_kinetics400_rgb_20200614-e508be42.pth \
PATH_TO_FRAMES/ LABEL_FILE --use-frames --out-filename demo/demo_out.gif
```
6. 使用 TSN 模型进行视频识别,输出 MP4 格式的识别结果,并指定输出视频分辨率及缩放视频时使用的插值方法:
```shell
# demo.mp4 及 label_map_k400.txt 均来自 Kinetics-400 数据集
python demo/demo.py configs/recognition/tsn/tsn_r50_video_inference_1x1x3_100e_kinetics400_rgb.py \
checkpoints/tsn_r50_1x1x3_100e_kinetics400_rgb_20200614-e508be42.pth \
demo/demo.mp4 tools/data/kinetics/label_map_k400.txt --target-resolution 340 256 --resize-algorithm bilinear \
--out-filename demo/demo_out.mp4
```
```shell
# demo.mp4 及 label_map_k400.txt 均来自 Kinetics-400 数据集
# 若 TARGET_RESOLUTION 的任一维度被设置为 -1,视频帧缩放时将保持长宽比
# 如设定 --target-resolution 为 170 -1,原先长宽为 (340, 256) 的视频帧将被缩放至 (170, 128)
python demo/demo.py configs/recognition/tsn/tsn_r50_video_inference_1x1x3_100e_kinetics400_rgb.py \
checkpoints/tsn_r50_1x1x3_100e_kinetics400_rgb_20200614-e508be42.pth \
demo/demo.mp4 tools/data/kinetics/label_map_k400.txt --target-resolution 170 -1 --resize-algorithm bilinear \
--out-filename demo/demo_out.mp4
```
7. 使用 TSN 模型进行视频识别,输出 MP4 格式的识别结果,指定输出视频中使用红色文字,字体大小为 10 像素:
```shell
# demo.mp4 及 label_map_k400.txt 均来自 Kinetics-400 数据集
python demo/demo.py configs/recognition/tsn/tsn_r50_video_inference_1x1x3_100e_kinetics400_rgb.py \
checkpoints/tsn_r50_1x1x3_100e_kinetics400_rgb_20200614-e508be42.pth \
demo/demo.mp4 tools/data/kinetics/label_map_k400.txt --font-size 10 --font-color red \
--out-filename demo/demo_out.mp4
```
8. 使用 TSN 模型进行视频识别,输入为视频抽好的帧,将识别结果存为 MP4 格式,帧率设置为 24fps:
```shell
python demo/demo.py configs/recognition/tsn/tsn_r50_inference_1x1x3_100e_kinetics400_rgb.py \
checkpoints/tsn_r50_1x1x3_100e_kinetics400_rgb_20200614-e508be42.pth \
PATH_TO_FRAMES/ LABEL_FILE --use-frames --fps 24 --out-filename demo/demo_out.gif
```
## 预测视频的时空检测结果
MMAction2 提供如下脚本以预测视频的时空检测结果。
```shell
python demo/demo_spatiotemporal_det.py --video ${VIDEO_FILE} \
[--config ${SPATIOTEMPORAL_ACTION_DETECTION_CONFIG_FILE}] \
[--checkpoint ${SPATIOTEMPORAL_ACTION_DETECTION_CHECKPOINT}] \
[--det-config ${HUMAN_DETECTION_CONFIG_FILE}] \
[--det-checkpoint ${HUMAN_DETECTION_CHECKPOINT}] \
[--det-score-thr ${HUMAN_DETECTION_SCORE_THRESHOLD}] \
[--action-score-thr ${ACTION_DETECTION_SCORE_THRESHOLD}] \
[--label-map ${LABEL_MAP}] \
[--device ${DEVICE}] \
[--out-filename ${OUTPUT_FILENAME}] \
[--predict-stepsize ${PREDICT_STEPSIZE}] \
[--output-stepsize ${OUTPUT_STEPSIZE}] \
[--output-fps ${OUTPUT_FPS}]
```
可选参数:
- `SPATIOTEMPORAL_ACTION_DETECTION_CONFIG_FILE`: 时空检测配置文件路径。
- `SPATIOTEMPORAL_ACTION_DETECTION_CHECKPOINT`: 时空检测模型权重文件路径。
- `HUMAN_DETECTION_CONFIG_FILE`: 人体检测配置文件路径。
- `HUMAN_DETECTION_CHECKPOINT`: 人体检测模型权重文件路径。
- `HUMAN_DETECTION_SCORE_THRE`: 人体检测分数阈值,默认为 0.9。
- `ACTION_DETECTION_SCORE_THRESHOLD`: 动作检测分数阈值,默认为 0.5。
- `LABEL_MAP`: 所使用的标签映射文件,默认为 `tools/data/ava/label_map.txt`
- `DEVICE`: 指定脚本运行设备,支持 cuda 设备(如 `cuda:0`)或 cpu(`cpu`)。默认为 `cuda:0`
- `OUTPUT_FILENAME`: 输出视频的路径,默认为 `demo/stdet_demo.mp4`
- `PREDICT_STEPSIZE`: 每 N 帧进行一次预测(以节约计算资源),默认值为 8。
- `OUTPUT_STEPSIZE`: 对于输入视频的每 N 帧,输出 1 帧至输出视频中, 默认值为 4,注意需满足 `PREDICT_STEPSIZE % OUTPUT_STEPSIZE == 0`
- `OUTPUT_FPS`: 输出视频的帧率,默认值为 6。
示例:
以下示例假设用户的当前目录为 `$MMACTION2`,并已经将所需的模型权重文件下载至目录 `checkpoints/` 下,用户也可以使用所提供的 URL 来直接加载模型权重,文件将会被默认下载至 `$HOME/.cache/torch/checkpoints`
1. 使用 Faster RCNN 作为人体检测器,SlowOnly-8x8-R101 作为动作检测器。每 8 帧进行一次预测,原视频中每 4 帧输出 1 帧至输出视频中,设置输出视频的帧率为 6。
```shell
python demo/demo_spatiotemporal_det.py --video demo/demo.mp4 \
--config configs/detection/ava/slowonly_omnisource_pretrained_r101_8x8x1_20e_ava_rgb.py \
--checkpoint https://download.openmmlab.com/mmaction/detection/ava/slowonly_omnisource_pretrained_r101_8x8x1_20e_ava_rgb/slowonly_omnisource_pretrained_r101_8x8x1_20e_ava_rgb_20201217-16378594.pth \
--det-config demo/faster_rcnn_r50_fpn_2x_coco.py \
--det-checkpoint http://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_2x_coco/faster_rcnn_r50_fpn_2x_coco_bbox_mAP-0.384_20200504_210434-a5d8aa15.pth \
--det-score-thr 0.9 \
--action-score-thr 0.5 \
--label-map tools/data/ava/label_map.txt \
--predict-stepsize 8 \
--output-stepsize 4 \
--output-fps 6
```
## 可视化输入视频的 GradCAM
MMAction2 提供如下脚本以可视化输入视频的 GradCAM。
```shell
python demo/demo_gradcam.py ${CONFIG_FILE} ${CHECKPOINT_FILE} ${VIDEO_FILE} [--use-frames] \
[--device ${DEVICE_TYPE}] [--target-layer-name ${TARGET_LAYER_NAME}] [--fps {FPS}] \
[--target-resolution ${TARGET_RESOLUTION}] [--resize-algorithm {RESIZE_ALGORITHM}] [--out-filename {OUT_FILE}]
```
可选参数:
- `--use-frames`: 如指定,代表使用帧目录作为输入;否则代表使用视频作为输入。
- `DEVICE_TYPE`: 指定脚本运行设备,支持 cuda 设备(如 `cuda:0`)或 cpu(`cpu`)。默认为 `cuda:0`
- `TARGET_LAYER_NAME`: 需要生成 GradCAM 可视化的网络层名称。
- `FPS`: 使用帧目录作为输入时,代表输入的帧率。默认为 30。
- `TARGET_RESOLUTION`: 输出视频的分辨率,如未指定,使用输入视频的分辨率。
- `RESIZE_ALGORITHM`: 缩放视频时使用的插值方法,默认为 `bilinear`
- `OUT_FILE`: 输出视频的路径,如未指定,则不会生成输出视频。
示例:
以下示例假设用户的当前目录为 `$MMACTION2`,并已经将所需的模型权重文件下载至目录 `checkpoints/` 下,用户也可以使用所提供的 URL 来直接加载模型权重,文件将会被默认下载至 `$HOME/.cache/torch/checkpoints`
1. 对于 I3D 模型进行 GradCAM 的可视化,使用视频作为输入,并输出一帧率为 10 的 GIF 文件:
```shell
python demo/demo_gradcam.py configs/recognition/i3d/i3d_r50_video_inference_32x2x1_100e_kinetics400_rgb.py \
checkpoints/i3d_r50_video_32x2x1_100e_kinetics400_rgb_20200826-e31c6f52.pth demo/demo.mp4 \
--target-layer-name backbone/layer4/1/relu --fps 10 \
--out-filename demo/demo_gradcam.gif
```
2. 对于 I3D 模型进行 GradCAM 的可视化,使用视频作为输入,并输出一 GIF 文件,此示例利用 URL 加载模型权重文件:
```shell
python demo/demo_gradcam.py configs/recognition/tsm/tsm_r50_video_inference_1x1x8_100e_kinetics400_rgb.py \
https://download.openmmlab.com/mmaction/recognition/tsm/tsm_r50_video_1x1x8_100e_kinetics400_rgb/tsm_r50_video_1x1x8_100e_kinetics400_rgb_20200702-a77f4328.pth \
demo/demo.mp4 --target-layer-name backbone/layer4/1/relu --out-filename demo/demo_gradcam_tsm.gif
```
## 使用网络摄像头的实时动作识别
MMAction2 提供如下脚本来进行使用网络摄像头的实时动作识别。为得到 \[0, 1\] 间的动作分值,请确保在配置文件中设定 `model['test_cfg'] = dict(average_clips='prob')`
```shell
python demo/webcam_demo.py ${CONFIG_FILE} ${CHECKPOINT_FILE} ${LABEL_FILE} \
[--device ${DEVICE_TYPE}] [--camera-id ${CAMERA_ID}] [--threshold ${THRESHOLD}] \
[--average-size ${AVERAGE_SIZE}] [--drawing-fps ${DRAWING_FPS}] [--inference-fps ${INFERENCE_FPS}]
```
可选参数:
- `DEVICE_TYPE`: 指定脚本运行设备,支持 cuda 设备(如 `cuda:0`)或 cpu(`cpu`)。默认为 `cuda:0`
- `CAMERA_ID`: 摄像头设备的 ID,默认为 0。
- `THRESHOLD`: 动作识别的分数阈值,只有分数大于阈值的动作类型会被显示,默认为 0。
- `AVERAGE_SIZE`: 使用最近 N 个片段的平均结果作为预测,默认为 1。
- `DRAWING_FPS`: 可视化结果时的最高帧率,默认为 20。
- `INFERENCE_FPS`: 进行推理时的最高帧率,默认为 4。
**注**: 若用户的硬件配置足够,可增大可视化帧率和推理帧率以带来更好体验。
示例:
以下示例假设用户的当前目录为 `$MMACTION2`,并已经将所需的模型权重文件下载至目录 `checkpoints/` 下,用户也可以使用所提供的 URL 来直接加载模型权重,文件将会被默认下载至 `$HOME/.cache/torch/checkpoints`
1. 使用 TSN 模型进行利用网络摄像头的实时动作识别,平均最近 5 个片段结果作为预测,输出大于阈值 0.2 的动作类别:
```shell
python demo/webcam_demo.py configs/recognition/tsn/tsn_r50_video_inference_1x1x3_100e_kinetics400_rgb.py \
checkpoints/tsn_r50_1x1x3_100e_kinetics400_rgb_20200614-e508be42.pth tools/data/kinetics/label_map_k400.txt --average-size 5 \
--threshold 0.2 --device cpu
```
2. 使用 TSN 模型在 CPU 上进行利用网络摄像头的实时动作识别,平均最近 5 个片段结果作为预测,输出大于阈值 0.2 的动作类别,此示例利用 URL 加载模型权重文件:
```shell
python demo/webcam_demo.py configs/recognition/tsn/tsn_r50_video_inference_1x1x3_100e_kinetics400_rgb.py \
https://download.openmmlab.com/mmaction/recognition/tsn/tsn_r50_1x1x3_100e_kinetics400_rgb/tsn_r50_1x1x3_100e_kinetics400_rgb_20200614-e508be42.pth \
tools/data/kinetics/label_map_k400.txt --average-size 5 --threshold 0.2 --device cpu
```
3. 使用 I3D 模型在 GPU 上进行利用网络摄像头的实时动作识别,平均最近 5 个片段结果作为预测,输出大于阈值 0.2 的动作类别:
```shell
python demo/webcam_demo.py configs/recognition/i3d/i3d_r50_video_inference_32x2x1_100e_kinetics400_rgb.py \
checkpoints/i3d_r50_32x2x1_100e_kinetics400_rgb_20200614-c25ef9a4.pth tools/data/kinetics/label_map_k400.txt \
--average-size 5 --threshold 0.2
```
**注:** 考虑到用户所使用的推理设备具有性能差异,可进行如下改动在用户设备上取得更好效果:
1). 更改配置文件中的 `test_pipeline``SampleFrames` 步骤 (特别是 `clip_len``num_clips`)。
2). 更改配置文件中的 `test_pipeline` 下的裁剪方式类型(可选项含:`TenCrop`, `ThreeCrop`, `CenterCrop`)。
3). 调低 `AVERAGE_SIZE` 以加快推理。
## 滑动窗口预测长视频中不同动作类别
MMAction2 提供如下脚本来预测长视频中的不同动作类别。为得到 \[0, 1\] 间的动作分值,请确保在配置文件中设定 `model['test_cfg'] = dict(average_clips='prob')`
```shell
python demo/long_video_demo.py ${CONFIG_FILE} ${CHECKPOINT_FILE} ${VIDEO_FILE} ${LABEL_FILE} \
${OUT_FILE} [--input-step ${INPUT_STEP}] [--device ${DEVICE_TYPE}] [--threshold ${THRESHOLD}]
```
可选参数:
- `OUT_FILE`: 输出视频的路径。
- `INPUT_STEP`: 在视频中的每 N 帧中选取一帧作为输入,默认为 1。
- `DEVICE_TYPE`: 指定脚本运行设备,支持 cuda 设备(如 `cuda:0`)或 cpu(`cpu`)。默认为 `cuda:0`
- `THRESHOLD`: 动作识别的分数阈值,只有分数大于阈值的动作类型会被显示,默认为 0.01。
- `STRIDE`: 默认情况下,脚本为每帧给出单独预测,较为耗时。可以设定 `STRIDE` 参数进行加速,此时脚本将会为每 `STRIDE x sample_length` 帧做一次预测(`sample_length` 指模型采帧时的时间窗大小,等于 `clip_len x frame_interval`)。例如,若 sample_length 为 64 帧且 `STRIDE` 设定为 0.5,模型将每 32 帧做一次预测。若 `STRIDE` 设为 0,模型将为每帧做一次预测。`STRIDE` 的理想取值为 (0, 1\] 间,若大于 1,脚本亦可正常执行。`STRIDE` 默认值为 0。
示例:
以下示例假设用户的当前目录为 `$MMACTION2`,并已经将所需的模型权重文件下载至目录 `checkpoints/` 下,用户也可以使用所提供的 URL 来直接加载模型权重,文件将会被默认下载至 `$HOME/.cache/torch/checkpoints`
1. 利用 TSN 模型在 CPU 上预测长视频中的不同动作类别,设置 `INPUT_STEP` 为 3(即每 3 帧随机选取 1 帧作为输入),输出分值大于 0.2 的动作类别:
```shell
python demo/long_video_demo.py configs/recognition/tsn/tsn_r50_video_inference_1x1x3_100e_kinetics400_rgb.py \
checkpoints/tsn_r50_1x1x3_100e_kinetics400_rgb_20200614-e508be42.pth PATH_TO_LONG_VIDEO tools/data/kinetics/label_map_k400.txt PATH_TO_SAVED_VIDEO \
--input-step 3 --device cpu --threshold 0.2
```
2. 利用 TSN 模型在 CPU 上预测长视频中的不同动作类别,设置 `INPUT_STEP` 为 3,输出分值大于 0.2 的动作类别,此示例利用 URL 加载模型权重文件:
```shell
python demo/long_video_demo.py configs/recognition/tsn/tsn_r50_video_inference_1x1x3_100e_kinetics400_rgb.py \
https://download.openmmlab.com/mmaction/recognition/tsn/tsn_r50_1x1x3_100e_kinetics400_rgb/tsn_r50_1x1x3_100e_kinetics400_rgb_20200614-e508be42.pth \
PATH_TO_LONG_VIDEO tools/data/kinetics/label_map_k400.txt PATH_TO_SAVED_VIDEO --input-step 3 --device cpu --threshold 0.2
```
3. 利用 TSN 模型在 CPU 上预测网络长视频(利用 URL 读取)中的不同动作类别,设置 `INPUT_STEP` 为 3,输出分值大于 0.2 的动作类别,此示例利用 URL 加载模型权重文件:
```shell
python demo/long_video_demo.py configs/recognition/tsn/tsn_r50_video_inference_1x1x3_100e_kinetics400_rgb.py \
https://download.openmmlab.com/mmaction/recognition/tsn/tsn_r50_1x1x3_100e_kinetics400_rgb/tsn_r50_1x1x3_100e_kinetics400_rgb_20200614-e508be42.pth \
https://www.learningcontainer.com/wp-content/uploads/2020/05/sample-mp4-file.mp4 \
tools/data/kinetics/label_map_k400.txt PATH_TO_SAVED_VIDEO --input-step 3 --device cpu --threshold 0.2
```
4. 利用 I3D 模型在 GPU 上预测长视频中的不同动作类别,设置 `INPUT_STEP` 为 3,动作识别的分数阈值为 0.01:
```shell
python demo/long_video_demo.py configs/recognition/i3d/i3d_r50_video_inference_32x2x1_100e_kinetics400_rgb.py \
checkpoints/i3d_r50_256p_32x2x1_100e_kinetics400_rgb_20200801-7d9f44de.pth PATH_TO_LONG_VIDEO tools/data/kinetics/label_map_k400.txt PATH_TO_SAVED_VIDEO \
```
## 基于网络摄像头的实时时空动作检测
MMAction2 提供本脚本实现基于网络摄像头的实时时空动作检测。
```shell
python demo/webcam_demo_spatiotemporal_det.py \
[--config ${SPATIOTEMPORAL_ACTION_DETECTION_CONFIG_FILE}] \
[--checkpoint ${SPATIOTEMPORAL_ACTION_DETECTION_CHECKPOINT}] \
[--action-score-thr ${ACTION_DETECTION_SCORE_THRESHOLD}] \
[--det-config ${HUMAN_DETECTION_CONFIG_FILE}] \
[--det-checkpoint ${HUMAN_DETECTION_CHECKPOINT}] \
[--det-score-thr ${HUMAN_DETECTION_SCORE_THRESHOLD}] \
[--input-video] ${INPUT_VIDEO} \
[--label-map ${LABEL_MAP}] \
[--device ${DEVICE}] \
[--output-fps ${OUTPUT_FPS}] \
[--out-filename ${OUTPUT_FILENAME}] \
[--show] \
[--display-height] ${DISPLAY_HEIGHT} \
[--display-width] ${DISPLAY_WIDTH} \
[--predict-stepsize ${PREDICT_STEPSIZE}] \
[--clip-vis-length] ${CLIP_VIS_LENGTH}
```
可选参数:
- `SPATIOTEMPORAL_ACTION_DETECTION_CONFIG_FILE`: 时空检测配置文件路径。
- `SPATIOTEMPORAL_ACTION_DETECTION_CHECKPOINT`: 时空检测模型权重文件路径。
- `ACTION_DETECTION_SCORE_THRESHOLD`: 动作检测分数阈值,默认为 0.4。
- `HUMAN_DETECTION_CONFIG_FILE`: 人体检测配置文件路径。
- `HUMAN_DETECTION_CHECKPOINT`: 人体检测模型权重文件路径。
- `HUMAN_DETECTION_SCORE_THRE`: 人体检测分数阈值,默认为 0.9。
- `INPUT_VIDEO`: 网络摄像头编号或本地视频文件路径,默认为 `0`
- `LABEL_MAP`: 所使用的标签映射文件,默认为 `tools/data/ava/label_map.txt`
- `DEVICE`: 指定脚本运行设备,支持 cuda 设备(如 `cuda:0`)或 cpu(`cpu`),默认为 `cuda:0`
- `OUTPUT_FPS`: 输出视频的帧率,默认为 15。
- `OUTPUT_FILENAME`: 输出视频的路径,默认为 `None`
- `--show`: 是否通过 `cv2.imshow` 展示预测结果。
- `DISPLAY_HEIGHT`: 输出结果图像高度,默认为 0。
- `DISPLAY_WIDTH`: 输出结果图像宽度,默认为 0。若 `DISPLAY_HEIGHT <= 0 and DISPLAY_WIDTH <= 0`,则表示输出图像形状与输入视频形状相同。
- `PREDICT_STEPSIZE`: 每 N 帧进行一次预测(以控制计算资源),默认为 8。
- `CLIP_VIS_LENGTH`: 预测结果可视化持续帧数,即每次预测结果将可视化到 `CLIP_VIS_LENGTH` 帧中,默认为 8。
小技巧:
- 如何设置 `--output-fps` 的数值?
- `--output-fps` 建议设置为视频读取线程的帧率。
- 视频读取线程帧率已通过日志输出,格式为 `DEBUG:__main__:Read Thread: {duration} ms, {fps} fps`
- 如何设置 `--predict-stepsize` 的数值?
- 该参数选择与模型选型有关。
- 模型输入构建时间(视频读取线程)应大于等于模型推理时间(主线程)。
- 模型输入构建时间与模型推理时间均已通过日志输出。
- `--predict-stepsize` 数值越大,模型输入构建时间越长。
- 可降低 `--predict-stepsize` 数值增加模型推理频率,从而充分利用计算资源。
示例:
以下示例假设用户的当前目录为 $MMACTION2,并已经将所需的模型权重文件下载至目录 checkpoints/ 下,用户也可以使用所提供的 URL 来直接加载模型权重,文件将会被默认下载至 $HOME/.cache/torch/checkpoints。
1. 使用 Faster RCNN 作为人体检测器,SlowOnly-8x8-R101 作为动作检测器,每 8 帧进行一次预测,设置输出视频的帧率为 20,并通过 `cv2.imshow` 展示预测结果。
```shell
python demo/webcam_demo_spatiotemporal_det.py \
--input-video 0 \
--config configs/detection/ava/slowonly_omnisource_pretrained_r101_8x8x1_20e_ava_rgb.py \
--checkpoint https://download.openmmlab.com/mmaction/detection/ava/slowonly_omnisource_pretrained_r101_8x8x1_20e_ava_rgb/slowonly_omnisource_pretrained_r101_8x8x1_20e_ava_rgb_20201217-16378594.pth \
--det-config demo/faster_rcnn_r50_fpn_2x_coco.py \
--det-checkpoint http://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_2x_coco/faster_rcnn_r50_fpn_2x_coco_bbox_mAP-0.384_20200504_210434-a5d8aa15.pth \
--det-score-thr 0.9 \
--action-score-thr 0.5 \
--label-map tools/data/ava/label_map.txt \
--predict-stepsize 40 \
--output-fps 20 \
--show
```
## 基于人体姿态预测动作标签
MMAction2 提供本脚本实现基于人体姿态的动作标签预测。
```shell
python demo/demo_skeleton.py ${VIDEO_FILE} ${OUT_FILENAME} \
[--config ${SKELETON_BASED_ACTION_RECOGNITION_CONFIG_FILE}] \
[--checkpoint ${SKELETON_BASED_ACTION_RECOGNITION_CHECKPOINT}] \
[--det-config ${HUMAN_DETECTION_CONFIG_FILE}] \
[--det-checkpoint ${HUMAN_DETECTION_CHECKPOINT}] \
[--det-score-thr ${HUMAN_DETECTION_SCORE_THRESHOLD}] \
[--pose-config ${HUMAN_POSE_ESTIMATION_CONFIG_FILE}] \
[--pose-checkpoint ${HUMAN_POSE_ESTIMATION_CHECKPOINT}] \
[--label-map ${LABEL_MAP}] \
[--device ${DEVICE}] \
[--short-side] ${SHORT_SIDE}
```
可选参数:
- `SKELETON_BASED_ACTION_RECOGNITION_CONFIG_FILE`: 基于人体姿态的动作识别模型配置文件路径。
- `SKELETON_BASED_ACTION_RECOGNITION_CHECKPOINT`: 基于人体姿态的动作识别模型权重文件路径。
- `HUMAN_DETECTION_CONFIG_FILE`: 人体检测配置文件路径。
- `HUMAN_DETECTION_CHECKPOINT`: 人体检测模型权重文件路径。
- `HUMAN_DETECTION_SCORE_THRE`: 人体检测分数阈值,默认为 0.9。
- `HUMAN_POSE_ESTIMATION_CONFIG_FILE`: 人体姿态估计模型配置文件路径 (需在 COCO-keypoint 数据集上训练)。
- `HUMAN_POSE_ESTIMATION_CHECKPOINT`: 人体姿态估计模型权重文件路径 (需在 COCO-keypoint 数据集上训练).
- `LABEL_MAP`: 所使用的标签映射文件,默认为 `tools/data/skeleton/label_map_ntu120.txt`
- `DEVICE`: 指定脚本运行设备,支持 cuda 设备(如 `cuda:0`)或 cpu(`cpu`),默认为 `cuda:0`
- `SHORT_SIDE`: 视频抽帧时使用的短边长度,默认为 480。
示例:
以下示例假设用户的当前目录为 $MMACTION2。
1. 使用 Faster RCNN 作为人体检测器,HRNetw32 作为人体姿态估计模型,PoseC3D-NTURGB+D-120-Xsub-keypoint 作为基于人体姿态的动作识别模型。
```shell
python demo/demo_skeleton.py demo/ntu_sample.avi demo/skeleton_demo.mp4 \
--config configs/skeleton/posec3d/slowonly_r50_u48_240e_ntu120_xsub_keypoint.py \
--checkpoint https://download.openmmlab.com/mmaction/skeleton/posec3d/slowonly_r50_u48_240e_ntu120_xsub_keypoint/slowonly_r50_u48_240e_ntu120_xsub_keypoint-6736b03f.pth \
--det-config demo/faster_rcnn_r50_fpn_2x_coco.py \
--det-checkpoint http://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_2x_coco/faster_rcnn_r50_fpn_2x_coco_bbox_mAP-0.384_20200504_210434-a5d8aa15.pth \
--det-score-thr 0.9 \
--pose-config demo/hrnet_w32_coco_256x192.py \
--pose-checkpoint https://download.openmmlab.com/mmpose/top_down/hrnet/hrnet_w32_coco_256x192-c78dce93_20200708.pth \
--label-map tools/data/skeleton/label_map_ntu120.txt
```
2. 使用 Faster RCNN 作为人体检测器,HRNetw32 作为人体姿态估计模型,STGCN-NTURGB+D-60-Xsub-keypoint 作为基于人体姿态的动作识别模型。
```shell
python demo/demo_skeleton.py demo/ntu_sample.avi demo/skeleton_demo.mp4 \
--config configs/skeleton/stgcn/stgcn_80e_ntu60_xsub_keypoint.py \
--checkpoint https://download.openmmlab.com/mmaction/skeleton/stgcn/stgcn_80e_ntu60_xsub_keypoint/stgcn_80e_ntu60_xsub_keypoint-e7bb9653.pth \
--det-config demo/faster_rcnn_r50_fpn_2x_coco.py \
--det-checkpoint http://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_2x_coco/faster_rcnn_r50_fpn_2x_coco_bbox_mAP-0.384_20200504_210434-a5d8aa15.pth \
--det-score-thr 0.9 \
--pose-config demo/hrnet_w32_coco_256x192.py \
--pose-checkpoint https://download.openmmlab.com/mmpose/top_down/hrnet/hrnet_w32_coco_256x192-c78dce93_20200708.pth \
--label-map tools/data/skeleton/label_map_ntu120.txt
```
## 视频结构化预测
MMAction2 提供本脚本实现基于人体姿态和RGB的视频结构化预测。
```shell
python demo/demo_video_structuralize.py
[--rgb-stdet-config ${RGB_BASED_SPATIO_TEMPORAL_ACTION_DETECTION_CONFIG_FILE}] \
[--rgb-stdet-checkpoint ${RGB_BASED_SPATIO_TEMPORAL_ACTION_DETECTION_CHECKPOINT}] \
[--skeleton-stdet-checkpoint ${SKELETON_BASED_SPATIO_TEMPORAL_ACTION_DETECTION_CHECKPOINT}] \
[--det-config ${HUMAN_DETECTION_CONFIG_FILE}] \
[--det-checkpoint ${HUMAN_DETECTION_CHECKPOINT}] \
[--pose-config ${HUMAN_POSE_ESTIMATION_CONFIG_FILE}] \
[--pose-checkpoint ${HUMAN_POSE_ESTIMATION_CHECKPOINT}] \
[--skeleton-config ${SKELETON_BASED_ACTION_RECOGNITION_CONFIG_FILE}] \
[--skeleton-checkpoint ${SKELETON_BASED_ACTION_RECOGNITION_CHECKPOINT}] \
[--rgb-config ${RGB_BASED_ACTION_RECOGNITION_CONFIG_FILE}] \
[--rgb-checkpoint ${RGB_BASED_ACTION_RECOGNITION_CHECKPOINT}] \
[--use-skeleton-stdet ${USE_SKELETON_BASED_SPATIO_TEMPORAL_DETECTION_METHOD}] \
[--use-skeleton-recog ${USE_SKELETON_BASED_ACTION_RECOGNITION_METHOD}] \
[--det-score-thr ${HUMAN_DETECTION_SCORE_THRE}] \
[--action-score-thr ${ACTION_DETECTION_SCORE_THRE}] \
[--video ${VIDEO_FILE}] \
[--label-map-stdet ${LABEL_MAP_FOR_SPATIO_TEMPORAL_ACTION_DETECTION}] \
[--device ${DEVICE}] \
[--out-filename ${OUTPUT_FILENAME}] \
[--predict-stepsize ${PREDICT_STEPSIZE}] \
[--output-stepsize ${OUTPU_STEPSIZE}] \
[--output-fps ${OUTPUT_FPS}] \
[--cfg-options]
```
可选参数:
- `RGB_BASED_SPATIO_TEMPORAL_ACTION_DETECTION_CONFIG_FILE`: 基于 RGB 的时空检测配置文件路径。
- `RGB_BASED_SPATIO_TEMPORAL_ACTION_DETECTION_CHECKPOINT`: 基于 RGB 的时空检测模型权重文件路径。
- `SKELETON_BASED_SPATIO_TEMPORAL_ACTION_DETECTION_CHECKPOINT`: 基于人体姿态的时空检测模型权重文件路径。
- `HUMAN_DETECTION_CONFIG_FILE`: 人体检测配置文件路径。
- `HUMAN_DETECTION_CHECKPOINT`: The human detection checkpoint URL.
- `HUMAN_POSE_ESTIMATION_CONFIG_FILE`: 人体姿态估计模型配置文件路径 (需在 COCO-keypoint 数据集上训练)。
- `HUMAN_POSE_ESTIMATION_CHECKPOINT`: 人体姿态估计模型权重文件路径 (需在 COCO-keypoint 数据集上训练)。
- `SKELETON_BASED_ACTION_RECOGNITION_CONFIG_FILE`: 基于人体姿态的动作识别模型配置文件路径。
- `SKELETON_BASED_ACTION_RECOGNITION_CHECKPOINT`: 基于人体姿态的动作识别模型权重文件路径。
- `RGB_BASED_ACTION_RECOGNITION_CONFIG_FILE`: 基于 RGB 的行为识别配置文件路径。
- `RGB_BASED_ACTION_RECOGNITION_CHECKPOINT`: 基于 RGB 的行为识别模型权重文件路径。
- `USE_SKELETON_BASED_SPATIO_TEMPORAL_DETECTION_METHOD`: 使用基于人体姿态的时空检测方法。
- `USE_SKELETON_BASED_ACTION_RECOGNITION_METHOD`: 使用基于人体姿态的行为识别方法。
- `HUMAN_DETECTION_SCORE_THRE`: 人体检测分数阈值,默认为 0.9。
- `ACTION_DETECTION_SCORE_THRE`: 动作检测分数阈值,默认为 0.5。
- `LABEL_MAP_FOR_SPATIO_TEMPORAL_ACTION_DETECTION`: 时空动作检测所使用的标签映射文件,默认为: `tools/data/ava/label_map.txt`
- `LABEL_MAP`: 行为识别所使用的标签映射文件, 默认为: `tools/data/kinetics/label_map_k400.txt`
- `DEVICE`: 指定脚本运行设备,支持 cuda 设备(如 `cuda:0`)或 cpu(`cpu`),默认为 `cuda:0`
- `OUTPUT_FILENAME`: 输出视频的路径,默认为 `demo/test_stdet_recognition_output.mp4`
- `PREDICT_STEPSIZE`: 每 N 帧进行一次预测(以节约计算资源),默认值为 8。
- `OUTPUT_STEPSIZE`: 对于输入视频的每 N 帧,输出 1 帧至输出视频中, 默认值为 1,注意需满足 `PREDICT_STEPSIZE % OUTPUT_STEPSIZE == 0`
- `OUTPUT_FPS`: 输出视频的帧率,默认为 24。
示例:
以下示例假设用户的当前目录为 $MMACTION2。
1. 使用 Faster RCNN 作为人体检测器,HRNetw32 作为人体姿态估计模型,PoseC3D 作为基于人体姿态的动作识别模型和时空动作检测器。每 8 帧进行一次预测,原视频中每 1 帧输出 1 帧至输出视频中,设置输出视频的帧率为 24。
```shell
python demo/demo_video_structuralize.py
--skeleton-stdet-checkpoint https://download.openmmlab.com/mmaction/skeleton/posec3d/posec3d_ava.pth \
--det-config demo/faster_rcnn_r50_fpn_2x_coco.py \
--det-checkpoint http://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_2x_coco/faster_rcnn_r50_fpn_2x_coco_bbox_mAP-0.384_20200504_210434-a5d8aa15.pth \
--pose-config demo/hrnet_w32_coco_256x192.py
--pose-checkpoint https://download.openmmlab.com/mmpose/top_down/hrnet/
hrnet_w32_coco_256x192-c78dce93_20200708.pth \
--skeleton-config configs/skeleton/posec3d/slowonly_r50_u48_240e_ntu120_xsub_keypoint.py \
--skeleton-checkpoint https://download.openmmlab.com/mmaction/skeleton/posec3d/
posec3d_k400.pth \
--use-skeleton-stdet \
--use-skeleton-recog \
--label-map-stdet tools/data/ava/label_map.txt \
--label-map tools/data/kinetics/label_map_k400.txt
```
2. 使用 Faster RCNN 作为人体检测器,TSN-R50-1x1x3 作为动作识别模型, SlowOnly-8x8-R101 作为时空动检测器。每 8 帧进行一次预测,原视频中每 1 帧输出 1 帧至输出视频中,设置输出视频的帧率为 24。
```shell
python demo/demo_video_structuralize.py
--rgb-stdet-config configs/detection/ava/slowonly_omnisource_pretrained_r101_8x8x1_20e_ava_rgb.py \
--rgb-stdet-checkpoint https://download.openmmlab.com/mmaction/detection/ava/slowonly_omnisource_pretrained_r101_8x8x1_20e_ava_rgb/slowonly_omnisource_pretrained_r101_8x8x1_20e_ava_rgb_20201217-16378594.pth \
--det-config demo/faster_rcnn_r50_fpn_2x_coco.py \
--det-checkpoint http://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_2x_coco/faster_rcnn_r50_fpn_2x_coco_bbox_mAP-0.384_20200504_210434-a5d8aa15.pth \
--rgb-config configs/recognition/tsn/
tsn_r50_video_inference_1x1x3_100e_kinetics400_rgb.py \
--rgb-checkpoint https://download.openmmlab.com/mmaction/recognition/
tsn/tsn_r50_1x1x3_100e_kinetics400_rgb/
tsn_r50_1x1x3_100e_kinetics400_rgb_20200614-e508be42.pth \
--label-map-stdet tools/data/ava/label_map.txt \
--label-map tools/data/kinetics/label_map_k400.txt
```
3. 使用 Faster RCNN 作为人体检测器,HRNetw32 作为人体姿态估计模型,PoseC3D 作为基于人体姿态的动作识别模型, SlowOnly-8x8-R101 作为时空动作检测器。每 8 帧进行一次预测,原视频中每 1 帧输出 1 帧至输出视频中,设置输出视频的帧率为 24。
```shell
python demo/demo_video_structuralize.py
--rgb-stdet-config configs/detection/ava/slowonly_omnisource_pretrained_r101_8x8x1_20e_ava_rgb.py \
--rgb-stdet-checkpoint https://download.openmmlab.com/mmaction/detection/ava/slowonly_omnisource_pretrained_r101_8x8x1_20e_ava_rgb/slowonly_omnisource_pretrained_r101_8x8x1_20e_ava_rgb_20201217-16378594.pth \
--det-config demo/faster_rcnn_r50_fpn_2x_coco.py \
--det-checkpoint http://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_2x_coco/faster_rcnn_r50_fpn_2x_coco_bbox_mAP-0.384_20200504_210434-a5d8aa15.pth \
--pose-config demo/hrnet_w32_coco_256x192.py
--pose-checkpoint https://download.openmmlab.com/mmpose/top_down/hrnet/
hrnet_w32_coco_256x192-c78dce93_20200708.pth \
--skeleton-config configs/skeleton/posec3d/slowonly_r50_u48_240e_ntu120_xsub_keypoint.py \
--skeleton-checkpoint https://download.openmmlab.com/mmaction/skeleton/posec3d/
posec3d_k400.pth \
--use-skeleton-recog \
--label-map-stdet tools/data/ava/label_map.txt \
--label-map tools/data/kinetics/label_map_k400.txt
```
4. 使用 Faster RCNN 作为人体检测器,HRNetw32 作为人体姿态估计模型,TSN-R50-1x1x3 作为动作识别模型, PoseC3D 作为基于人体姿态的时空动作检测器。每 8 帧进行一次预测,原视频中每 1 帧输出 1 帧至输出视频中,设置输出视频的帧率为 24。
```shell
python demo/demo_video_structuralize.py
--skeleton-stdet-checkpoint https://download.openmmlab.com/mmaction/skeleton/posec3d/posec3d_ava.pth \
--det-config demo/faster_rcnn_r50_fpn_2x_coco.py \
--det-checkpoint http://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_2x_coco/faster_rcnn_r50_fpn_2x_coco_bbox_mAP-0.384_20200504_210434-a5d8aa15.pth \
--pose-config demo/hrnet_w32_coco_256x192.py
--pose-checkpoint https://download.openmmlab.com/mmpose/top_down/hrnet/
hrnet_w32_coco_256x192-c78dce93_20200708.pth \
--skeleton-config configs/skeleton/posec3d/slowonly_r50_u48_240e_ntu120_xsub_keypoint.py \
--rgb-config configs/recognition/tsn/
tsn_r50_video_inference_1x1x3_100e_kinetics400_rgb.py \
--rgb-checkpoint https://download.openmmlab.com/mmaction/recognition/
tsn/tsn_r50_1x1x3_100e_kinetics400_rgb/
tsn_r50_1x1x3_100e_kinetics400_rgb_20200614-e508be42.pth \
--use-skeleton-stdet \
--label-map-stdet tools/data/ava/label_map.txt \
--label-map tools/data/kinetics/label_map_k400.txt
```
## 基于音频的动作识别
本脚本可用于进行基于音频特征的动作识别。
脚本 `extract_audio.py` 可被用于从视频中提取音频,脚本 `build_audio_features.py` 可被用于基于音频文件提取音频特征。
```shell
python demo/demo_audio.py ${CONFIG_FILE} ${CHECKPOINT_FILE} ${AUDIO_FILE} {LABEL_FILE} [--device ${DEVICE}]
```
可选参数:
- `DEVICE`: 指定脚本运行设备,支持 cuda 设备(如 `cuda:0`)或 cpu(`cpu`),默认为 `cuda:0`
示例:
以下示例假设用户的当前目录为 $MMACTION2。
1. 在 GPU 上,使用 TSN 模型进行基于音频特征的动作识别。
```shell
python demo/demo_audio.py \
configs/recognition_audio/resnet/tsn_r18_64x1x1_100e_kinetics400_audio_feature.py \
https://download.openmmlab.com/mmaction/recognition/audio_recognition/tsn_r18_64x1x1_100e_kinetics400_audio_feature/tsn_r18_64x1x1_100e_kinetics400_audio_feature_20201012-bf34df6c.pth \
audio_feature.npy label_map_k400.txt
```
# 常见问题解答
本文这里列出了用户们遇到的一些常见问题,及相应的解决方案。
如果您发现了任何社区中经常出现的问题,也有了相应的解决方案,欢迎充实本文档来帮助他人。
如果本文档不包括您的问题,欢迎使用提供的 [模板](/.github/ISSUE_TEMPLATE/error-report.md) 创建问题,还请确保您在模板中填写了所有必需的信息。
## 安装
- **"No module named 'mmcv.ops'"; "No module named 'mmcv.\_ext'"**
1. 使用 `pip uninstall mmcv` 卸载环境中已安装的 `mmcv`
2. 遵循 [MMCV 安装文档](https://mmcv.readthedocs.io/en/latest/#installation) 来安装 `mmcv-full`
- **"OSError: MoviePy Error: creation of None failed because of the following error"**
参照 [MMAction2 安装文档](https://github.com/open-mmlab/mmaction2/blob/master/docs/zh_cn/install.md#安装依赖包)
1. 对于 Windows 用户,[ImageMagick](https://www.imagemagick.org/script/index.php) 不再被 MoviePy 自动检测,
需要获取名为 `magick` 的 ImageMagick 二进制包的路径,来修改 `moviepy/config_defaults.py` 文件中的 `IMAGEMAGICK_BINARY`,如 `IMAGEMAGICK_BINARY = "C:\\Program Files\\ImageMagick_VERSION\\magick.exe"`
2. 对于 Linux 用户,如果 ImageMagick 没有被 moviepy 检测,需要注释掉 `/etc/ImageMagick-6/policy.xml` 文件中的 `<policy domain="path" rights="none" pattern="@*" />`,即改为 `<!-- <policy domain="path" rights="none" pattern="@*" /> -->`
- **"Please install XXCODEBASE to use XXX"**
如得到报错消息 "Please install XXCODEBASE to use XXX",代表 MMAction2 无法从 XXCODEBASE 中 import XXX。用户可以执行对应 import 语句定位原因。
一个可能的原因是,对于部分 OpenMMLAB 中的代码库,需先安装 mmcv-full 后再进行安装。
## 数据
- **FileNotFound 如 `No such file or directory: xxx/xxx/img_00300.jpg`**
在 MMAction2 中,对于帧数据集,`start_index` 的默认值为 1,而对于视频数据集, `start_index` 的默认值为 0。
如果 FileNotFound 错误发生于视频的第一帧或最后一帧,则需根据视频首帧(即 `xxx_00000.jpg``xxx_00001.jpg`)的偏移量,修改配置文件中数据处理流水线的 `start_index` 值。
- **如何处理数据集中传入视频的尺寸?是把所有视频调整为固定尺寸,如 “340x256”,还是把所有视频的短边调整成相同的长度(256像素或320像素)?**
从基准测试来看,总体来说,后者(把所有视频的短边调整成相同的长度)效果更好,所以“调整尺寸为短边256像素”被设置为默认的数据处理方式。用户可以在 [TSN 数据基准测试](https://github.com/open-mmlab/mmaction2/tree/master/configs/recognition/tsn)[SlowOnly 数据基准测试](https://github.com/open-mmlab/mmaction2/tree/master/configs/recognition/tsn) 中查看相关的基准测试结果。
- **输入数据格式(视频或帧)与数据流水线不匹配,导致异常,如 `KeyError: 'total_frames'`**
对于视频和帧,我们都有相应的流水线来处理。
**对于视频**,应该在处理时首先对其进行解码。可选的解码方式,有 `DecordInit & DecordDecode`, `OpenCVInit & OpenCVDecode`, `PyAVInit & PyAVDecode` 等等。可以参照 [这个例子](https://github.com/open-mmlab/mmaction2/blob/023777cfd26bb175f85d78c455f6869673e0aa09/configs/recognition/slowfast/slowfast_r50_video_4x16x1_256e_kinetics400_rgb.py#L47-L49)
**对于帧**,已经事先在本地对其解码,所以使用 `RawFrameDecode` 对帧处理即可。可以参照 [这个例子](https://github.com/open-mmlab/mmaction2/blob/023777cfd26bb175f85d78c455f6869673e0aa09/configs/recognition/slowfast/slowfast_r50_8x8x1_256e_kinetics400_rgb.py#L49)
`KeyError: 'total_frames'` 是因为错误地使用了 `RawFrameDecode` 来处理视频。当输入是视频的时候,程序是无法事先得到 `total_frame` 的。
## 训练
- **如何使用训练过的识别器作为主干网络的预训练模型?**
参照 [使用预训练模型](https://github.com/open-mmlab/mmaction2/blob/master/docs/zh_cn/tutorials/2_finetune.md#修改训练策略)
如果想对整个网络使用预训练模型,可以在配置文件中,将 `load_from` 设置为预训练模型的链接。
如果只想对主干网络使用预训练模型,可以在配置文件中,将主干网络 `backbone` 中的 `pretrained` 设置为预训练模型的地址或链接。
在训练时,预训练模型中无法与主干网络对应的参数会被忽略。
- **如何实时绘制训练集和验证集的准确率/损失函数曲线图?**
使用 `log_config` 中的 `TensorboardLoggerHook`,如:
```python
log_config=dict(
interval=20,
hooks=[
dict(type='TensorboardLoggerHook')
]
)
```
可以参照 [教程1:如何编写配置文件](tutorials/1_config.md)[教程7:如何自定义模型运行参数](tutorials/7_customize_runtime.md#log-config),和 [这个例子](https://github.com/open-mmlab/mmaction2/blob/master/configs/recognition/tsm/tsm_r50_1x1x8_50e_kinetics400_rgb.py#L118) 了解更多相关内容。
- **在 batchnorm.py 中抛出错误: Expected more than 1 value per channel when training**
BatchNorm 层要求批大小(batch size)大于 1。构建数据集时, 若 `drop_last` 被设为 `False`,有时每个轮次的最后一个批次的批大小可能为 1,进而在训练时抛出错误,可以设置 `drop_last=True` 来避免该错误,如:
```python
train_dataloader=dict(drop_last=True)
```
- **微调模型参数时,如何冻结主干网络中的部分参数?**
可以参照 [`def _freeze_stages()`](https://github.com/open-mmlab/mmaction2/blob/0149a0e8c1e0380955db61680c0006626fd008e9/mmaction/models/backbones/x3d.py#L458)[`frozen_stages`](https://github.com/open-mmlab/mmaction2/blob/0149a0e8c1e0380955db61680c0006626fd008e9/mmaction/models/backbones/x3d.py#L183-L184)。在分布式训练和测试时,还须设置 `find_unused_parameters = True`
实际上,除了少数模型,如 C3D 等,用户都能通过设置 `frozen_stages` 来冻结模型参数,因为大多数主干网络继承自 `ResNet``ResNet3D`,而这两个模型都支持 `_freeze_stages()` 方法。
- **如何在配置文件中设置 `load_from` 参数以进行模型微调?**
MMAction2 在 `configs/_base_/default_runtime.py` 文件中将 `load_from=None` 设为默认。由于配置文件的可继承性,用户可直接在下游配置文件中设置 `load_from` 的值来进行更改。
## 测试
- **如何将预测分值用 softmax 归一化到 \[0, 1\] 区间内?**
可以通过设置 `model['test_cfg'] = dict(average_clips='prob')` 来实现。
- **如果模型太大,连一个测试样例都没法放进显存,怎么办?**
默认情况下,3D 模型是以 `10 clips x 3 crops` 的设置进行测试的,也即采样 10 个帧片段,每帧裁剪出 3 个图像块,总计有 30 个视图。
对于特别大的模型,GPU 显存可能连一个视频都放不下。对于这种情况,您可以在配置文件的 `model['test_cfg']` 中设置 `max_testing_views=n`
如此设置,在模型推理过程中,一个批只会使用 n 个视图,以节省显存。
- **如何保存测试结果?**
测试时,用户可在运行指令中设置可选项 `--out xxx.json/pkl/yaml` 来输出结果文件,以供后续检查。输出的测试结果顺序和测试集顺序保持一致。
除此之外,MMAction2 也在 [`tools/analysis/eval_metric.py`](/tools/analysis/eval_metric.py) 中提供了分析工具,用于结果文件的模型评估。
## 部署
- **为什么由 MMAction2 转换的 ONNX 模型在转换到其他框架(如 TensorRT)时会抛出错误?**
目前只能确保 MMAction2 中的模型与 ONNX 兼容。但是,ONNX 中的某些算子可能不受其他框架支持,例如 [这个问题](https://github.com/open-mmlab/mmaction2/issues/414) 中的 TensorRT。当这种情况发生时,如果 `pytorch2onnx.py` 没有出现问题,转换过去的 ONNX 模型也通过了数值检验,可以提 issue 让社区提供帮助。
# 特征提取
MMAction2 为特征提取提供了便捷使用的脚本。
## 片段级特征提取
片段级特征提取是从长度一般为几秒到几十秒不等的剪辑片段中提取深度特征。从每个片段中提取的特征是一个 n 维向量。当进行多视图特征提取时,例如 n 个片段 × m 种裁剪,提取的特征将会是 n\*m 个视图的平均值。
在应用片段级特征提取之前,用户需要准备一个视频列表包含所有想要进行特征提取的视频。例如,由 UCF101 中视频组成的视频列表如下:
```
ApplyEyeMakeup/v_ApplyEyeMakeup_g01_c01.avi
ApplyEyeMakeup/v_ApplyEyeMakeup_g01_c02.avi
ApplyEyeMakeup/v_ApplyEyeMakeup_g01_c03.avi
ApplyEyeMakeup/v_ApplyEyeMakeup_g01_c04.avi
ApplyEyeMakeup/v_ApplyEyeMakeup_g01_c05.avi
...
YoYo/v_YoYo_g25_c01.avi
YoYo/v_YoYo_g25_c02.avi
YoYo/v_YoYo_g25_c03.avi
YoYo/v_YoYo_g25_c04.avi
YoYo/v_YoYo_g25_c05.avi
```
假设 UCF101 中的视频所在目录为 `data/ucf101/videos`,视频列表的文件名为 `ucf101.txt`,使用 TSN(Kinetics-400 预训练)从 UCF101 中提取片段级特征,用户可以使用脚本如下:
```shell
python tools/misc/clip_feature_extraction.py \
configs/recognition/tsn/tsn_r50_clip_feature_extraction_1x1x3_rgb.py \
https://download.openmmlab.com/mmaction/recognition/tsn/tsn_r50_320p_1x1x3_100e_kinetics400_rgb/tsn_r50_320p_1x1x3_100e_kinetics400_rgb_20200702-cc665e2a.pth \
--video-list ucf101.txt \
--video-root data/ucf101/videos \
--out ucf101_feature.pkl
```
被提取的特征存储于 `ucf101_feature.pkl`
用户也可以使用分布式片段级特征提取。以下是使用拥有 8 gpus 的计算节点的示例。
```shell
bash tools/misc/dist_clip_feature_extraction.sh \
configs/recognition/tsn/tsn_r50_clip_feature_extraction_1x1x3_rgb.py \
https://download.openmmlab.com/mmaction/recognition/tsn/tsn_r50_320p_1x1x3_100e_kinetics400_rgb/tsn_r50_320p_1x1x3_100e_kinetics400_rgb_20200702-cc665e2a.pth \
8 \
--video-list ucf101.txt \
--video-root data/ucf101/videos \
--out ucf101_feature.pkl
```
使用 SlowOnly(Kinetics-400 预训练)从 UCF101 中提取片段级特征,用户可以使用脚本如下:
```shell
python tools/misc/clip_feature_extraction.py \
configs/recognition/slowonly/slowonly_r50_clip_feature_extraction_4x16x1_rgb.py \
https://download.openmmlab.com/mmaction/recognition/slowonly/slowonly_r50_video_320p_4x16x1_256e_kinetics400_rgb/slowonly_r50_video_320p_4x16x1_256e_kinetics400_rgb_20201014-c9cdc656.pth \
--video-list ucf101.txt \
--video-root data/ucf101/videos \
--out ucf101_feature.pkl
```
这两个配置文件展示了用于特征提取的最小配置。用户也可以使用其他存在的配置文件进行特征提取,只要注意使用视频数据进行训练和测试,而不是原始帧数据。
```shell
python tools/misc/clip_feature_extraction.py \
configs/recognition/slowonly/slowonly_r50_video_4x16x1_256e_kinetics400_rgb.py \
https://download.openmmlab.com/mmaction/recognition/slowonly/slowonly_r50_video_320p_4x16x1_256e_kinetics400_rgb/slowonly_r50_video_320p_4x16x1_256e_kinetics400_rgb_20201014-c9cdc656.pth \
--video-list ucf101.txt \
--video-root data/ucf101/videos \
--out ucf101_feature.pkl
```
# 基础教程
本文档提供 MMAction2 相关用法的基本教程。对于安装说明,请参阅 [安装指南](install.md)
<!-- TOC -->
- [基础教程](#基础教程)
- [数据集](#数据集)
- [使用预训练模型进行推理](#使用预训练模型进行推理)
- [测试某个数据集](#测试某个数据集)
- [使用高级 API 对视频和帧文件夹进行测试](#使用高级-api-对视频和帧文件夹进行测试)
- [如何建立模型](#如何建立模型)
- [使用基本组件建立模型](#使用基本组件建立模型)
- [构建新模型](#构建新模型)
- [如何训练模型](#如何训练模型)
- [推理流水线](#推理流水线)
- [训练配置](#训练配置)
- [使用单个 GPU 进行训练](#使用单个-gpu-进行训练)
- [使用多个 GPU 进行训练](#使用多个-gpu-进行训练)
- [使用多台机器进行训练](#使用多台机器进行训练)
- [使用单台机器启动多个任务](#使用单台机器启动多个任务)
- [详细教程](#详细教程)
<!-- TOC -->
## 数据集
MMAction2 建议用户将数据集根目录链接到 `$MMACTION2/data` 下。
如果用户的文件夹结构与默认结构不同,则需要在配置文件中进行对应路径的修改。
```
mmaction2
├── mmaction
├── tools
├── configs
├── data
│ ├── kinetics400
│ │ ├── rawframes_train
│ │ ├── rawframes_val
│ │ ├── kinetics_train_list.txt
│ │ ├── kinetics_val_list.txt
│ ├── ucf101
│ │ ├── rawframes_train
│ │ ├── rawframes_val
│ │ ├── ucf101_train_list.txt
│ │ ├── ucf101_val_list.txt
│ ├── ...
```
请参阅 [数据集准备](data_preparation.md) 获取数据集准备的相关信息。
对于用户自定义数据集的准备,请参阅 [教程 3:如何增加新数据集](tutorials/3_new_dataset.md)
## 使用预训练模型进行推理
MMAction2 提供了一些脚本用于测试数据集(如 Kinetics-400,Something-Something V1&V2,(Multi-)Moments in Time,等),
并提供了一些高级 API,以便更好地兼容其他项目。
MMAction2 支持仅使用 CPU 进行测试。然而,这样做的速度**非常慢**,用户应仅使用其作为无 GPU 机器上的 debug 手段。
如需使用 CPU 进行测试,用户需要首先使用命令 `export CUDA_VISIBLE_DEVICES=-1` 禁用机器上的 GPU (如有),然后使用命令 `python tools/test.py {OTHER_ARGS}` 直接调用测试脚本。
### 测试某个数据集
- [x] 支持单 GPU
- [x] 支持单节点,多 GPU
- [x] 支持多节点
用户可使用以下命令进行数据集测试
```shell
# 单 GPU 测试
python tools/test.py ${CONFIG_FILE} ${CHECKPOINT_FILE} [--out ${RESULT_FILE}] [--eval ${EVAL_METRICS}] \
[--gpu-collect] [--tmpdir ${TMPDIR}] [--options ${OPTIONS}] [--average-clips ${AVG_TYPE}] \
[--launcher ${JOB_LAUNCHER}] [--local_rank ${LOCAL_RANK}] [--onnx] [--tensorrt]
# 多 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}]
```
可选参数:
- `RESULT_FILE`:输出结果文件名。如果没有被指定,则不会保存测试结果。
- `EVAL_METRICS`:测试指标。其可选值与对应数据集相关,如 `top_k_accuracy``mean_class_accuracy` 适用于所有动作识别数据集,`mmit_mean_average_precision` 适用于 Multi-Moments in Time 数据集,`mean_average_precision` 适用于 Multi-Moments in Time 和单类 HVU 数据集,`AR@AN` 适用于 ActivityNet 数据集等。
- `--gpu-collect`:如果被指定,动作识别结果将会通过 GPU 通信进行收集。否则,它将被存储到不同 GPU 上的 `TMPDIR` 文件夹中,并在 rank 0 的进程中被收集。
- `TMPDIR`:用于存储不同进程收集的结果文件的临时文件夹。该变量仅当 `--gpu-collect` 没有被指定时有效。
- `OPTIONS`:用于验证过程的自定义选项。其可选值与对应数据集的 `evaluate` 函数变量有关。
- `AVG_TYPE`:用于平均测试片段结果的选项。如果被设置为 `prob`,则会在平均测试片段结果之前施加 softmax 函数。否则,会直接进行平均。
- `JOB_LAUNCHER`:分布式任务初始化启动器选项。可选值有 `none``pytorch``slurm``mpi`。特别地,如果被设置为 `none`, 则会以非分布式模式进行测试。
- `LOCAL_RANK`:本地 rank 的 ID。如果没有被指定,则会被设置为 0。
- `--onnx`: 如果指定,将通过 onnx 模型推理获取预测结果,输入参数 `CHECKPOINT_FILE` 应为 onnx 模型文件。Onnx 模型文件由 `/tools/deployment/pytorch2onnx.py` 脚本导出。目前,不支持多 GPU 测试以及动态张量形状(Dynamic shape)。请注意,数据集输出与模型输入张量的形状应保持一致。同时,不建议使用测试时数据增强,如 `ThreeCrop``TenCrop``twice_sample` 等。
- `--tensorrt`: 如果指定,将通过 TensorRT 模型推理获取预测结果,输入参数 `CHECKPOINT_FILE` 应为 TensorRT 模型文件。TensorRT 模型文件由导出的 onnx 模型以及 TensorRT 官方模型转换工具生成。目前,不支持多 GPU 测试以及动态张量形状(Dynamic shape)。请注意,数据集输出与模型输入张量的形状应保持一致。同时,不建议使用测试时数据增强,如 `ThreeCrop``TenCrop``twice_sample` 等。
例子:
假定用户将下载的模型权重文件放置在 `checkpoints/` 目录下。
1. 在 Kinetics-400 数据集下测试 TSN (不存储测试结果为文件),并验证 `top-k accuracy``mean class accuracy` 指标
```shell
python tools/test.py configs/recognition/tsn/tsn_r50_1x1x3_100e_kinetics400_rgb.py \
checkpoints/SOME_CHECKPOINT.pth \
--eval top_k_accuracy mean_class_accuracy
```
2. 使用 8 块 GPU 在 Something-Something V1 下测试 TSN,并验证 `top-k accuracy` 指标
```shell
./tools/dist_test.sh configs/recognition/tsn/tsn_r50_1x1x8_50e_sthv1_rgb.py \
checkpoints/SOME_CHECKPOINT.pth \
8 --out results.pkl --eval top_k_accuracy
```
3. 在 slurm 分布式环境中测试 TSN 在 Kinetics-400 数据集下的 `top-k accuracy` 指标
```shell
python tools/test.py configs/recognition/tsn/tsn_r50_1x1x3_100e_kinetics400_rgb.py \
checkpoints/SOME_CHECKPOINT.pth \
--launcher slurm --eval top_k_accuracy
```
4. 在 Something-Something V1 下测试 onnx 格式的 TSN 模型,并验证 `top-k accuracy` 指标
```shell
python tools/test.py configs/recognition/tsn/tsn_r50_1x1x3_100e_kinetics400_rgb.py \
checkpoints/SOME_CHECKPOINT.onnx \
--eval top_k_accuracy --onnx
```
### 使用高级 API 对视频和帧文件夹进行测试
这里举例说明如何构建模型并测试给定视频
```python
import torch
from mmaction.apis import init_recognizer, inference_recognizer
config_file = 'configs/recognition/tsn/tsn_r50_video_inference_1x1x3_100e_kinetics400_rgb.py'
# 从模型库中下载检测点,并把它放到 `checkpoints/` 文件夹下
checkpoint_file = 'checkpoints/tsn_r50_1x1x3_100e_kinetics400_rgb_20200614-e508be42.pth'
# 指定设备
device = 'cuda:0' # or 'cpu'
device = torch.device(device)
# 根据配置文件和检查点来建立模型
model = init_recognizer(config_file, checkpoint_file, device=device)
# 测试单个视频并显示其结果
video = 'demo/demo.mp4'
labels = 'tools/data/kinetics/label_map_k400.txt'
results = inference_recognizer(model, video)
# 显示结果
labels = open('tools/data/kinetics/label_map_k400.txt').readlines()
labels = [x.strip() for x in labels]
results = [(labels[k[0]], k[1]) for k in results]
print(f'The top-5 labels with corresponding scores are:')
for result in results:
print(f'{result[0]}: ', result[1])
```
这里举例说明如何构建模型并测试给定帧文件夹
```python
import torch
from mmaction.apis import init_recognizer, inference_recognizer
config_file = 'configs/recognition/tsn/tsn_r50_inference_1x1x3_100e_kinetics400_rgb.py'
# 从模型库中下载检测点,并把它放到 `checkpoints/` 文件夹下
checkpoint_file = 'checkpoints/tsn_r50_1x1x3_100e_kinetics400_rgb_20200614-e508be42.pth'
# 指定设备
device = 'cuda:0' # or 'cpu'
device = torch.device(device)
# 根据配置文件和检查点来建立模型
model = init_recognizer(config_file, checkpoint_file, device=device)
# 测试单个视频的帧文件夹并显示其结果
video = 'SOME_DIR_PATH/'
labels = 'tools/data/kinetics/label_map_k400.txt'
results = inference_recognizer(model, video)
# 显示结果
labels = open('tools/data/kinetics/label_map_k400.txt').readlines()
labels = [x.strip() for x in labels]
results = [(labels[k[0]], k[1]) for k in results]
print(f'The top-5 labels with corresponding scores are:')
for result in results:
print(f'{result[0]}: ', result[1])
```
这里举例说明如何构建模型并通过 url 测试给定视频
```python
import torch
from mmaction.apis import init_recognizer, inference_recognizer
config_file = 'configs/recognition/tsn/tsn_r50_video_inference_1x1x3_100e_kinetics400_rgb.py'
# 从模型库中下载检测点,并把它放到 `checkpoints/` 文件夹下
checkpoint_file = 'checkpoints/tsn_r50_1x1x3_100e_kinetics400_rgb_20200614-e508be42.pth'
# 指定设备
device = 'cuda:0' # or 'cpu'
device = torch.device(device)
# 根据配置文件和检查点来建立模型
model = init_recognizer(config_file, checkpoint_file, device=device)
# 测试单个视频的 url 并显示其结果
video = 'https://www.learningcontainer.com/wp-content/uploads/2020/05/sample-mp4-file.mp4'
labels = 'tools/data/kinetics/label_map_k400.txt'
results = inference_recognizer(model, video)
# 显示结果
labels = open('tools/data/kinetics/label_map_k400.txt').readlines()
labels = [x.strip() for x in labels]
results = [(labels[k[0]], k[1]) for k in results]
print(f'The top-5 labels with corresponding scores are:')
for result in results:
print(f'{result[0]}: ', result[1])
```
**注意**:MMAction2 在默认提供的推理配置文件(inference configs)中定义 `data_prefix` 变量,并将其设置为 None 作为默认值。
如果 `data_prefix` 不为 None,则要获取的视频文件(或帧文件夹)的路径将为 `data_prefix/video`
在这里,`video` 是上述脚本中的同名变量。可以在 `rawframe_dataset.py` 文件和 `video_dataset.py` 文件中找到此详细信息。例如,
- 当视频(帧文件夹)路径为 `SOME_DIR_PATH/VIDEO.mp4``SOME_DIR_PATH/VIDEO_NAME/img_xxxxx.jpg`),并且配置文件中的 `data_prefix` 为 None,则 `video` 变量应为 `SOME_DIR_PATH/VIDEO.mp4``SOME_DIR_PATH/VIDEO_NAME`)。
- 当视频(帧文件夹)路径为 `SOME_DIR_PATH/VIDEO.mp4``SOME_DIR_PATH/VIDEO_NAME/img_xxxxx.jpg`),并且配置文件中的 `data_prefix``SOME_DIR_PATH`,则 `video` 变量应为 `VIDEO.mp4``VIDEO_NAME`)。
- 当帧文件夹路径为 `VIDEO_NAME/img_xxxxx.jpg`,并且配置文件中的 `data_prefix` 为 None,则 `video` 变量应为 `VIDEO_NAME`
- 当传递参数为视频 url 而非本地路径,则需使用 OpenCV 作为视频解码后端。
[demo/demo.ipynb](/demo/demo.ipynb) 中有提供相应的 notebook 演示文件。
## 如何建立模型
### 使用基本组件建立模型
MMAction2 将模型组件分为 4 种基础模型:
- 识别器(recognizer):整个识别器模型管道,通常包含一个主干网络(backbone)和分类头(cls_head)。
- 主干网络(backbone):通常为一个用于提取特征的 FCN 网络,例如 ResNet,BNInception。
- 分类头(cls_head):用于分类任务的组件,通常包括一个带有池化层的 FC 层。
- 时序检测器(localizer):用于时序检测的模型,目前有的检测器包含 BSN,BMN,SSN。
用户可参照给出的配置文件里的基础模型搭建流水线(如 `Recognizer2D`
如果想创建一些新的组件,如 [TSM: Temporal Shift Module for Efficient Video Understanding](https://arxiv.org/abs/1811.08383) 中的 temporal shift backbone 结构,则需:
1. 创建 `mmaction/models/backbones/resnet_tsm.py` 文件
```python
from ..builder import BACKBONES
from .resnet import ResNet
@BACKBONES.register_module()
class ResNetTSM(ResNet):
def __init__(self,
depth,
num_segments=8,
is_shift=True,
shift_div=8,
shift_place='blockres',
temporal_pool=False,
**kwargs):
pass
def forward(self, x):
# implementation is ignored
pass
```
2.`mmaction/models/backbones/__init__.py` 中导入模型
```python
from .resnet_tsm import ResNetTSM
```
3. 修改模型文件
```python
backbone=dict(
type='ResNet',
pretrained='torchvision://resnet50',
depth=50,
norm_eval=False)
```
修改为
```python
backbone=dict(
type='ResNetTSM',
pretrained='torchvision://resnet50',
depth=50,
norm_eval=False,
shift_div=8)
```
### 构建新模型
要编写一个新的动作识别器流水线,用户需要继承 `BaseRecognizer`,其定义了如下抽象方法
- `forward_train()`: 训练模式下的前向方法
- `forward_test()`: 测试模式下的前向方法
具体可参照 [Recognizer2D](/mmaction/models/recognizers/recognizer2d.py)[Recognizer3D](/mmaction/models/recognizers/recognizer3d.py)
## 如何训练模型
### 推理流水线
MMAction2 使用 `MMDistributedDataParallel` 进行分布式训练,使用 `MMDataParallel` 进行非分布式训练。
对于单机多卡与多台机器的情况,MMAction2 使用分布式训练。假设服务器有 8 块 GPU,则会启动 8 个进程,并且每台 GPU 对应一个进程。
每个进程拥有一个独立的模型,以及对应的数据加载器和优化器。
模型参数同步只发生于最开始。之后,每经过一次前向与后向计算,所有 GPU 中梯度都执行一次 allreduce 操作,而后优化器将更新模型参数。
由于梯度执行了 allreduce 操作,因此不同 GPU 中模型参数将保持一致。
### 训练配置
所有的输出(日志文件和模型权重文件)会被将保存到工作目录下。工作目录通过配置文件中的参数 `work_dir` 指定。
默认情况下,MMAction2 在每个周期后会在验证集上评估模型,可以通过在训练配置中修改 `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。
MMAction2 支持仅使用 CPU 进行训练。然而,这样做的速度**非常慢**,用户应仅使用其作为无 GPU 机器上的 debug 手段。
如需使用 CPU 进行训练,用户需要首先使用命令 `export CUDA_VISIBLE_DEVICES=-1` 禁用机器上的 GPU (如有),然后使用命令 `python tools/train.py {OTHER_ARGS}` 直接调用训练脚本。
### 使用单个 GPU 进行训练
```shell
python tools/train.py ${CONFIG_FILE} [optional arguments]
```
如果用户想在命令中指定工作目录,则需要增加参数 `--work-dir ${YOUR_WORK_DIR}`
### 使用多个 GPU 进行训练
```shell
./tools/dist_train.sh ${CONFIG_FILE} ${GPU_NUM} [optional arguments]
```
可选参数为:
- `--validate` (**强烈建议**):在训练期间每 k 个周期进行一次验证(默认值为 5,可通过修改每个配置文件中的 `evaluation` 字典变量的 `interval` 值进行改变)。
- `--test-last`:在训练结束后使用最后一个检查点的参数进行测试,将测试结果存储在 `${WORK_DIR}/last_pred.pkl` 中。
- `--test-best`:在训练结束后使用效果最好的检查点的参数进行测试,将测试结果存储在 `${WORK_DIR}/best_pred.pkl` 中。
- `--work-dir ${WORK_DIR}`:覆盖配置文件中指定的工作目录。
- `--resume-from ${CHECKPOINT_FILE}`:从以前的模型权重文件恢复训练。
- `--gpus ${GPU_NUM}`:使用的 GPU 数量,仅适用于非分布式训练。
- `--gpu-ids ${GPU_IDS}`:使用的 GPU ID,仅适用于非分布式训练。
- `--seed ${SEED}`:设置 python,numpy 和 pytorch 里的种子 ID,已用于生成随机数。
- `--deterministic`:如果被指定,程序将设置 CUDNN 后端的确定化选项。
- `JOB_LAUNCHER`:分布式任务初始化启动器选项。可选值有 `none``pytorch``slurm``mpi`。特别地,如果被设置为 `none`, 则会以非分布式模式进行测试。
- `LOCAL_RANK`:本地 rank 的 ID。如果没有被指定,则会被设置为 0。
`resume-from``load-from` 的不同点:
`resume-from` 加载模型参数和优化器状态,并且保留检查点所在的周期数,常被用于恢复意外被中断的训练。
`load-from` 只加载模型参数,但周期数从 0 开始计数,常被用于微调模型。
这里提供一个使用 8 块 GPU 加载 TSN 模型权重文件的例子。
```shell
./tools/dist_train.sh configs/recognition/tsn/tsn_r50_1x1x3_100e_kinetics400_rgb.py 8 --resume-from work_dirs/tsn_r50_1x1x3_100e_kinetics400_rgb/latest.pth
```
### 使用多台机器进行训练
如果用户在 [slurm](https://slurm.schedmd.com/) 集群上运行 MMAction2,可使用 `slurm_train.sh` 脚本。(该脚本也支持单台机器上进行训练)
```shell
[GPUS=${GPUS}] ./tools/slurm_train.sh ${PARTITION} ${JOB_NAME} ${CONFIG_FILE} [--work-dir ${WORK_DIR}]
```
这里给出一个在 slurm 集群上的 dev 分区使用 16 块 GPU 训练 TSN 的例子。(使用 `GPUS_PER_NODE=8` 参数来指定一个有 8 块 GPUS 的 slurm 集群节点)
```shell
GPUS=16 ./tools/slurm_train.sh dev tsn_r50_k400 configs/recognition/tsn/tsn_r50_1x1x3_100e_kinetics400_rgb.py --work-dir work_dirs/tsn_r50_1x1x3_100e_kinetics400_rgb
```
用户可以查看 [slurm_train.sh](/tools/slurm_train.sh) 文件来检查完整的参数和环境变量。
如果您想使用由 ethernet 连接起来的多台机器, 您可以使用以下命令:
在第一台机器上:
```shell
NNODES=2 NODE_RANK=0 PORT=$MASTER_PORT MASTER_ADDR=$MASTER_ADDR sh tools/dist_train.sh $CONFIG $GPUS
```
在第二台机器上:
```shell
NNODES=2 NODE_RANK=1 PORT=$MASTER_PORT MASTER_ADDR=$MASTER_ADDR sh tools/dist_train.sh $CONFIG $GPUS
```
但是,如果您不使用高速网路连接这几台机器的话,训练将会非常慢。
### 使用单台机器启动多个任务
如果用使用单台机器启动多个任务,如在有 8 块 GPU 的单台机器上启动 2 个需要 4 块 GPU 的训练任务,则需要为每个任务指定不同端口,以避免通信冲突。
如果用户使用 `dist_train.sh` 脚本启动训练任务,则可以通过以下命令指定端口
```shell
CUDA_VISIBLE_DEVICES=0,1,2,3 PORT=29500 ./tools/dist_train.sh ${CONFIG_FILE} 4
CUDA_VISIBLE_DEVICES=4,5,6,7 PORT=29501 ./tools/dist_train.sh ${CONFIG_FILE} 4
```
如果用户在 slurm 集群下启动多个训练任务,则需要修改配置文件(通常是配置文件的倒数第 6 行)中的 `dist_params` 变量,以设置不同的通信端口。
`config1.py` 中,
```python
dist_params = dict(backend='nccl', port=29500)
```
`config2.py` 中,
```python
dist_params = dict(backend='nccl', port=29501)
```
之后便可启动两个任务,分别对应 `config1.py``config2.py`
```shell
CUDA_VISIBLE_DEVICES=0,1,2,3 GPUS=4 ./tools/slurm_train.sh ${PARTITION} ${JOB_NAME} config1.py [--work-dir ${WORK_DIR}]
CUDA_VISIBLE_DEVICES=4,5,6,7 GPUS=4 ./tools/slurm_train.sh ${PARTITION} ${JOB_NAME} config2.py [--work-dir ${WORK_DIR}]
```
## 详细教程
目前, MMAction2 提供以下几种更详细的教程:
- [如何编写配置文件](tutorials/1_config.md)
- [如何微调模型](tutorials/2_finetune.md)
- [如何增加新数据集](tutorials/3_new_dataset.md)
- [如何设计数据处理流程](tutorials/4_data_pipeline.md)
- [如何增加新模块](tutorials/5_new_modules.md)
- [如何导出模型为 onnx 格式](tutorials/6_export_model.md)
- [如何自定义模型运行参数](tutorials/7_customize_runtime.md)
欢迎来到 MMAction2 的中文文档!
=====================================
您可以在页面左下角切换中英文文档。
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
.. toctree::
:maxdepth: 2
:caption: 数据集
datasets.md
data_preparation.md
supported_datasets.md
.. toctree::
:maxdepth: 2
:caption: 模型库
modelzoo.md
recognition_models.md
localization_models.md
detection_models.md
skeleton_models.md
.. toctree::
:maxdepth: 2
:caption: 教程
tutorials/1_config.md
tutorials/2_finetune.md
tutorials/3_new_dataset.md
tutorials/4_data_pipeline.md
tutorials/5_new_modules.md
tutorials/6_export_model.md
tutorials/7_customize_runtime.md
.. toctree::
:maxdepth: 2
:caption: 实用工具和脚本
useful_tools.md
.. toctree::
:maxdepth: 2
:caption: 记录
changelog.md
faq.md
.. toctree::
:caption: API 参考文档
api.rst
.. toctree::
:caption: 语言切换
switch_language.md
索引和表格
==================
* :ref:`genindex`
* :ref:`search`
# 安装
本文档提供了安装 MMAction2 的相关步骤。
<!-- TOC -->
- [安装](#安装)
- [安装依赖包](#安装依赖包)
- [准备环境](#准备环境)
- [MMAction2 的安装步骤](#mmaction2-的安装步骤)
- [CPU 环境下的安装步骤](#cpu-环境下的安装步骤)
- [利用 Docker 镜像安装 MMAction2](#利用-docker-镜像安装-mmaction2)
- [源码安装 MMAction2](#源码安装-mmaction2)
- [在多个 MMAction2 版本下进行开发](#在多个-mmaction2-版本下进行开发)
- [安装验证](#安装验证)
<!-- 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) 1.1.1+
- Numpy
- ffmpeg (4.2 版本最佳)
- [decord](https://github.com/dmlc/decord) (可选项, 0.4.1+):使用 `pip install decord==0.4.1` 命令安装其 CPU 版本,GPU 版本需从源码进行编译。
- [PyAV](https://github.com/mikeboers/PyAV) (可选项)`conda install av -c conda-forge -y`
- [PyTurboJPEG](https://github.com/lilohuang/PyTurboJPEG) (可选项)`pip install PyTurboJPEG`
- [denseflow](https://github.com/open-mmlab/denseflow) (可选项):可参考 [这里](https://github.com/innerlee/setup) 获取简便安装步骤。
- [moviepy](https://zulko.github.io/moviepy/) (可选项)`pip install moviepy`. 官方安装步骤可参考 [这里](https://zulko.github.io/moviepy/install.html)**特别地**,如果安装过程碰到 [这个问题](https://github.com/Zulko/moviepy/issues/693),可参考:
1. 对于 Windows 用户, [ImageMagick](https://www.imagemagick.org/script/index.php) 将不会被 MoviePy 自动检测到,用户需要对 `moviepy/config_defaults.py` 文件进行修改,以提供 ImageMagick 的二进制文件(即,`magick`)的路径,如 `IMAGEMAGICK_BINARY = "C:\\Program Files\\ImageMagick_VERSION\\magick.exe"`
2. 对于 Linux 用户, 如果 [ImageMagick](https://www.imagemagick.org/script/index.php) 没有被 `moviepy` 检测到,用于需要对 `/etc/ImageMagick-6/policy.xml` 文件进行修改,把文件中的 `<policy domain="path" rights="none" pattern="@*" />` 代码行修改为 `<!-- <policy domain="path" rights="none" pattern="@*" /> -->`
- [Pillow-SIMD](https://docs.fast.ai/performance.html#pillow-simd) (可选项):可使用如下脚本进行安装:
```shell
conda uninstall -y --force pillow pil jpeg libtiff libjpeg-turbo
pip uninstall -y pillow pil jpeg libtiff libjpeg-turbo
conda install -yc conda-forge libjpeg-turbo
CFLAGS="${CFLAGS} -mavx2" pip install --upgrade --no-cache-dir --force-reinstall --no-binary :all: --compile pillow-simd
conda install -y jpeg libtiff
```
**注意**:用户需要首先运行 `pip uninstall mmcv` 命令,以确保 mmcv 被成功安装。
如果 mmcv 和 mmcv-full 同时被安装, 会报 `ModuleNotFoundError` 的错误。
## 准备环境
a. 创建并激活 conda 虚拟环境,如:
```shell
conda create -n open-mmlab python=3.7 -y
conda activate open-mmlab
```
b. 根据 [官方文档](https://pytorch.org/) 进行 PyTorch 和 torchvision 的安装,如:
```shell
conda install pytorch torchvision -c pytorch
```
**注**:确保 CUDA 的编译版本和 CUDA 的运行版本相匹配。
用户可以参照 [PyTorch 官网](https://pytorch.org/) 对预编译包所支持的 CUDA 版本进行核对。
`例 1`:如果用户的 `/usr/local/cuda` 文件夹下已安装 CUDA 10.1 版本,并且想要安装 PyTorch 1.5 版本,
则需要安装 CUDA 10.1 下预编译的 PyTorch。
```shell
conda install pytorch cudatoolkit=10.1 torchvision -c pytorch
```
`例 2`:如果用户的 `/usr/local/cuda` 文件夹下已安装 CUDA 9.2 版本,并且想要安装 PyTorch 1.3.1 版本,
则需要安装 CUDA 9.2 下预编译的 PyTorch。
```shell
conda install pytorch=1.3.1 cudatoolkit=9.2 torchvision=0.4.2 -c pytorch
```
如果 PyTorch 是由源码进行编译安装(而非直接下载预编译好的安装包),则可以使用更多的 CUDA 版本(如 9.0 版本)。
## MMAction2 的安装步骤
这里推荐用户使用 [MIM](https://github.com/open-mmlab/mim) 安装 MMAction2。
```shell
pip install git+https://github.com/open-mmlab/mim.git
mim install mmaction2 -f https://github.com/open-mmlab/mmaction2.git
```
MIM 可以自动安装 OpenMMLab 项目及其依赖。
或者,用户也可以通过以下步骤手动安装 MMAction2。
a. 安装 mmcv-full,我们推荐您安装以下预构建包:
```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.10.0/index.html
```
PyTorch 在 1.x.0 和 1.x.1 之间通常是兼容的,故 mmcv-full 只提供 1.x.0 的编译包。如果你的 PyTorch 版本是 1.x.1,你可以放心地安装在 1.x.0 版本编译的 mmcv-full。
```
# 我们可以忽略 PyTorch 的小版本号
pip install mmcv-full -f https://download.openmmlab.com/mmcv/dist/cu102/torch1.10/index.html
```
可查阅 [这里](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 ..
```
或者直接运行脚本:
```shell
pip install mmcv-full
```
**注意**:如果 mmcv 已经被安装,用户需要使用 `pip uninstall mmcv` 命令进行卸载。如果 mmcv 和 mmcv-full 同时被安装, 会报 `ModuleNotFoundError` 的错误。
b. 克隆 MMAction2 库。
```shell
git clone https://github.com/open-mmlab/mmaction2.git
cd mmaction2
```
c. 安装依赖包和 MMAction2。
```shell
pip install -r requirements/build.txt
pip install -v -e . # or "python setup.py develop"
```
如果是在 macOS 环境安装 MMAction2,则需使用如下命令:
```shell
CC=clang CXX=clang++ CFLAGS='-stdlib=libc++' pip install -e .
```
d. 安装 mmdetection 以支持时空检测任务。
如果用户不想做时空检测相关任务,这部分步骤可以选择跳过。
可参考 [这里](https://github.com/open-mmlab/mmdetection#installation) 进行 mmdetection 的安装。
注意:
1. 在步骤 b 中,git commit 的 id 将会被写到版本号中,如 0.6.0+2e7045c。这个版本号也会被保存到训练好的模型中。
这里推荐用户每次在步骤 b 中对本地代码和 github 上的源码进行同步。如果 C++/CUDA 代码被修改,就必须进行这一步骤。
2. 根据上述步骤,MMAction2 就会以 `dev` 模式被安装,任何本地的代码修改都会立刻生效,不需要再重新安装一遍(除非用户提交了 commits,并且想更新版本号)。
3. 如果用户想使用 `opencv-python-headless` 而不是 `opencv-python`,可再安装 MMCV 前安装 `opencv-python-headless`
4. 如果用户想使用 `PyAV`,可以通过 `conda install av -c conda-forge -y` 进行安装。
5. 一些依赖包是可选的。运行 `python setup.py develop` 将只会安装运行代码所需的最小要求依赖包。
要想使用一些可选的依赖包,如 `decord`,用户需要通过 `pip install -r requirements/optional.txt` 进行安装,
或者通过调用 `pip`(如 `pip install -v -e .[optional]`,这里的 `[optional]` 可替换为 `all``tests``build``optional`) 指定安装对应的依赖包,如 `pip install -v -e .[tests,build]`
## CPU 环境下的安装步骤
MMAction2 可以在只有 CPU 的环境下安装(即无法使用 GPU 的环境)。
在 CPU 模式下,用户可以运行 `demo/demo.py` 的代码。
## 利用 Docker 镜像安装 MMAction2
MMAction2 提供一个 [Dockerfile](/docker/Dockerfile) 用户创建 docker 镜像。
```shell
# 创建拥有 PyTorch 1.6.0, CUDA 10.1, CUDNN 7 配置的 docker 镜像.
docker build -f ./docker/Dockerfile --rm -t mmaction2 .
```
**注意**:用户需要确保已经安装了 [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}:/mmaction2/data mmaction2
```
## 源码安装 MMAction2
这里提供了 conda 下安装 MMAction2 并链接数据集路径的完整脚本(假设 Kinetics-400 数据的路径在 $KINETICS400_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 或 mmcv-full,这里以 mmcv 为例
pip install mmcv
# 安装 mmaction2
git clone https://github.com/open-mmlab/mmaction2.git
cd mmaction2
pip install -r requirements/build.txt
python setup.py develop
mkdir data
ln -s $KINETICS400_ROOT data
```
## 在多个 MMAction2 版本下进行开发
MMAction2 的训练和测试脚本已经修改了 `PYTHONPATH` 变量,以确保其能够运行当前目录下的 MMAction2。
如果想要运行环境下默认的 MMAction2,用户需要在训练和测试脚本中去除这一行:
```shell
PYTHONPATH="$(dirname $0)/..":$PYTHONPATH
```
## 安装验证
为了验证 MMAction2 和所需的依赖包是否已经安装成功,
用户可以运行以下的 python 代码,以测试其是否能成功地初始化动作识别器,并进行演示视频的推理:
```python
import torch
from mmaction.apis import init_recognizer, inference_recognizer
config_file = 'configs/recognition/tsn/tsn_r50_video_inference_1x1x3_100e_kinetics400_rgb.py'
device = 'cuda:0' # 或 'cpu'
device = torch.device(device)
model = init_recognizer(config_file, device=device)
# 进行演示视频的推理
inference_recognizer(model, 'demo/demo.mp4')
```
@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
#!/usr/bin/env bash
# gather models
cat ../../configs/localization/*/README_zh-CN.md | sed "s/md#测/html#测/g" | sed "s/md#训/html#训/g" | sed "s/#/#&/" | sed '1i\# 时序动作检测模型' | sed 's/](\/docs\/zh_CN\//](/g' | sed 's=](/=](https://github.com/open-mmlab/mmaction2/tree/master/=g' | sed "s/getting_started.html##/getting_started.html#/g" > localization_models.md
cat ../../configs/recognition/*/README_zh-CN.md | sed "s/md#测/html#t测/g" | sed "s/md#训/html#训/g" | sed "s/#/#&/" | sed '1i\# 动作识别模型' | sed 's/](\/docs\/zh_CN\//](/g' | sed 's=](/=](https://github.com/open-mmlab/mmaction2/tree/master/=g'| sed "s/getting_started.html##/getting_started.html#/g" > recognition_models.md
cat ../../configs/recognition_audio/*/README_zh-CN.md | sed "s/md#测/html#测/g" | sed "s/md#训/html#训/g" | sed "s/#/#&/" | sed 's/](\/docs\/zh_CN\//](/g' | sed 's=](/=](https://github.com/open-mmlab/mmaction2/tree/master/=g'| sed "s/getting_started.html##/getting_started.html#/g" >> recognition_models.md
cat ../../configs/detection/*/README_zh-CN.md | sed "s/md#测/html#测/g" | sed "s/md#训/html#训/g" | sed "s/#/#&/" | sed '1i\# 时空动作检测模型' | sed 's/](\/docs\/zh_CN\//](/g' | sed 's=](/=](https://github.com/open-mmlab/mmaction2/tree/master/=g'| sed "s/getting_started.html##/getting_started.html#/g" > detection_models.md
cat ../../configs/skeleton/*/README_zh-CN.md | sed "s/md#测/html#测/g" | sed "s/md#训/html#训/g" | sed "s/#/#&/" | sed '1i\# 骨骼动作识别模型' | sed 's/](\/docs\/zh_CN\//](/g' | sed 's=](/=](https://github.com/open-mmlab/mmaction2/tree/master/=g'| sed "s/getting_started.html##/getting_started.html#/g" > skeleton_models.md
# gather datasets
cat ../../tools/data/*/README_zh-CN.md | sed 's/# 准备/# /g' | sed 's/#/#&/' > prepare_data.md
sed -i 's/(\/tools\/data\/activitynet\/README_zh-CN.md/(#activitynet/g' supported_datasets.md
sed -i 's/(\/tools\/data\/kinetics\/README_zh-CN.md/(#kinetics-400600700/g' supported_datasets.md
sed -i 's/(\/tools\/data\/mit\/README_zh-CN.md/(#moments-in-time/g' supported_datasets.md
sed -i 's/(\/tools\/data\/mmit\/README_zh-CN.md/(#multi-moments-in-time/g' supported_datasets.md
sed -i 's/(\/tools\/data\/sthv1\/README_zh-CN.md/(#something-something-v1/g' supported_datasets.md
sed -i 's/(\/tools\/data\/sthv2\/README_zh-CN.md/(#something-something-v2/g' supported_datasets.md
sed -i 's/(\/tools\/data\/thumos14\/README_zh-CN.md/(#thumos14/g' supported_datasets.md
sed -i 's/(\/tools\/data\/ucf101\/README_zh-CN.md/(#ucf-101/g' supported_datasets.md
sed -i 's/(\/tools\/data\/ucf101_24\/README_zh-CN.md/(#ucf101-24/g' supported_datasets.md
sed -i 's/(\/tools\/data\/jhmdb\/README_zh-CN.md/(#jhmdb/g' supported_datasets.md
sed -i 's/(\/tools\/data\/hvu\/README_zh-CN.md/(#hvu/g' supported_datasets.md
sed -i 's/(\/tools\/data\/hmdb51\/README_zh-CN.md/(#hmdb51/g' supported_datasets.md
sed -i 's/(\/tools\/data\/jester\/README_zh-CN.md/(#jester/g' supported_datasets.md
sed -i 's/(\/tools\/data\/ava\/README_zh-CN.md/(#ava/g' supported_datasets.md
sed -i 's/(\/tools\/data\/gym\/README_zh-CN.md/(#gym/g' supported_datasets.md
sed -i 's/(\/tools\/data\/omnisource\/README_zh-CN.md/(#omnisource/g' supported_datasets.md
sed -i 's/(\/tools\/data\/diving48\/README_zh-CN.md/(#diving48/g' supported_datasets.md
sed -i 's/(\/tools\/data\/skeleton\/README_zh-CN.md/(#骨架数据集/g' supported_datasets.md
cat prepare_data.md >> supported_datasets.md
sed -i 's/](\/docs\/zh_CN\//](/g' supported_datasets.md
sed -i 's=](/=](https://github.com/open-mmlab/mmaction2/tree/master/=g' supported_datasets.md
sed -i "s/md###t/html#t/g" demo.md
sed -i 's=](/=](https://github.com/open-mmlab/mmaction2/tree/master/=g' demo.md
sed -i 's=](/=](https://github.com/open-mmlab/mmaction2/tree/master/=g' benchmark.md
sed -i 's=](/=](https://github.com/open-mmlab/mmaction2/tree/master/=g' getting_started.md
sed -i 's=](/=](https://github.com/open-mmlab/mmaction2/tree/master/=g' install.md
sed -i 's/](\/docs\/zh_CN\//](/g' ./tutorials/*.md
sed -i 's=](/=](https://github.com/open-mmlab/mmaction2/tree/master/=g' ./tutorials/*.md
#!/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('*_models.md'))
stats = []
for f in files:
with open(f, 'r') as content_file:
content = content_file.read()
# title
title = content.split('\n')[0].replace('#', '')
# skip IMAGE and ABSTRACT tags
content = [
x for x in content.split('\n')
if 'IMAGE' not in x and 'ABSTRACT' not in x
]
content = '\n'.join(content)
# 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)
q = p.replace('\\', '\\\\').replace('?', '\\?')
paperlinks[p] = ' '.join(
(f'[->]({splitext(basename(f))[0]}.html#{anchor(paperlink)})'
for paperlink in re.findall(
rf'\btitle\s*=\s*{{\s*{q}\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 'mmaction' 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])
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 = ['supported_datasets.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)
q = p.replace('\\', '\\\\').replace('?', '\\?')
paperlinks[p] = ', '.join(
(f'[{p.strip()} ->]({splitext(basename(f))[0]}.html#{anchor(p)})'
for p in re.findall(
rf'\btitle\s*=\s*{{\s*{q}\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))
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)
# 支持的数据集
- 支持的动作识别数据集:
- [UCF101](/tools/data/ucf101/README_zh-CN.md) \[ [主页](https://www.crcv.ucf.edu/research/data-sets/ucf101/) \].
- [HMDB51](/tools/data/hmdb51/README_zh-CN.md) \[ [主页](https://serre-lab.clps.brown.edu/resource/hmdb-a-large-human-motion-database/) \].
- [Kinetics-\[400/600/700\]](/tools/data/kinetics/README_zh-CN.md) \[ [主页](https://deepmind.com/research/open-source/kinetics) \]
- [Something-Something V1](/tools/data/sthv1/README_zh-CN.md) \[ [主页](https://20bn.com/datasets/something-something/v1) \]
- [Something-Something V2](/tools/data/sthv2/README_zh-CN.md) \[ [主页](https://20bn.com/datasets/something-something) \]
- [Moments in Time](/tools/data/mit/README_zh-CN.md) \[ [主页](http://moments.csail.mit.edu/) \]
- [Multi-Moments in Time](/tools/data/mmit/README_zh-CN.md) \[ [主页](http://moments.csail.mit.edu/challenge_iccv_2019.html) \]
- [HVU](/tools/data/hvu/README_zh-CN.md) \[ [主页](https://github.com/holistic-video-understanding/HVU-Dataset) \]
- [Jester](/tools/data/jester/README_zh-CN.md) \[ [主页](https://developer.qualcomm.com/software/ai-datasets/jester) \]
- [GYM](/tools/data/gym/README_zh-CN.md) \[ [主页](https://sdolivia.github.io/FineGym/) \]
- [ActivityNet](/tools/data/activitynet/README_zh-CN.md) \[ [主页](http://activity-net.org/) \]
- 支持的时序动作检测数据集:
- [ActivityNet](/tools/data/activitynet/README_zh-CN.md) \[ [主页](http://activity-net.org/) \]
- [THUMOS14](/tools/data/thumos14/README_zh-CN.md) \[ [主页](https://www.crcv.ucf.edu/THUMOS14/download.html) \]
- 支持的时空动作检测数据集:
- [AVA](/tools/data/ava/README_zh-CN.md) \[ [主页](https://research.google.com/ava/index.html) \]
- [UCF101-24](/tools/data/ucf101_24/README_zh-CN.md) \[ [主页](http://www.thumos.info/download.html) \]
- [JHMDB](/tools/data/jhmdb/README_zh-CN.md) \[ [主页](http://jhmdb.is.tue.mpg.de/) \]
- 基于人体骨架的动作识别数据集:
- [PoseC3D Skeleton Dataset](/tools/data/skeleton/README_zh-CN.md) \[ [主页](https://kennymckormick.github.io/posec3d/) \]
MMAction2 目前支持的数据集如上所列。
MMAction2 在 `$MMACTION2/tools/data/` 路径下提供数据集准备脚本。
每个数据集的详细准备教程也在 [Readthedocs](https://mmaction2.readthedocs.io/zh_CN/latest/supported_datasets.html) 中给出。
## <a href='https://mmaction2.readthedocs.io/en/latest/'>English</a>
## <a href='https://mmaction2.readthedocs.io/zh_CN/latest/'>简体中文</a>
# 教程 1:如何编写配置文件
MMAction2 使用 python 文件作为配置文件。其配置文件系统的设计将模块化与继承整合进来,方便用户进行各种实验。
MMAction2 提供的所有配置文件都放置在 `$MMAction2/configs` 文件夹下,用户可以通过运行命令
`python tools/analysis/print_config.py /PATH/TO/CONFIG` 来查看完整的配置信息,从而方便检查所对应的配置文件。
<!-- TOC -->
- [教程 1:如何编写配置文件](#教程-1如何编写配置文件)
- [通过命令行参数修改配置信息](#通过命令行参数修改配置信息)
- [配置文件结构](#配置文件结构)
- [配置文件命名规则](#配置文件命名规则)
- [时序动作检测的配置文件系统](#时序动作检测的配置文件系统)
- [动作识别的配置文件系统](#动作识别的配置文件系统)
- [时空动作检测的配置文件系统](#时空动作检测的配置文件系统)
- [常见问题](#常见问题)
- [配置文件中的中间变量](#配置文件中的中间变量)
<!-- TOC -->
## 通过命令行参数修改配置信息
当用户使用脚本 "tools/train.py" 或者 "tools/test.py" 提交任务时,可以通过指定 `--cfg-options` 参数来直接修改所使用的配置文件内容。
- 更新配置文件内的字典
用户可以按照原始配置中的字典键顺序来指定配置文件的设置。
例如,`--cfg-options model.backbone.norm_eval=False` 会改变 `train` 模式下模型主干网络 backbone 中所有的 BN 模块。
- 更新配置文件内列表的键
配置文件中,存在一些由字典组成的列表。例如,训练数据前处理流水线 data.train.pipeline 就是 python 列表。
如,`[dict(type='SampleFrames'), ...]`。如果用户想更改其中的 `'SampleFrames'``'DenseSampleFrames'`
可以指定 `--cfg-options data.train.pipeline.0.type=DenseSampleFrames`
- 更新列表/元组的值。
当配置文件中需要更新的是一个列表或者元组,例如,配置文件通常会设置 `workflow=[('train', 1)]`,用户如果想更改,
需要指定 `--cfg-options workflow="[(train,1),(val,1)]"`。注意这里的引号 " 对于列表/元组数据类型的修改是必要的,
并且 **不允许** 引号内所指定的值的书写存在空格。
## 配置文件结构
`config/_base_` 文件夹下存在 3 种基本组件类型: 模型(model), 训练策略(schedule), 运行时的默认设置(default_runtime)。
许多方法都可以方便地通过组合这些组件进行实现,如 TSN,I3D,SlowOnly 等。
其中,通过 `_base_` 下组件来构建的配置被称为 _原始配置_(_primitive_)。
对于在同一文件夹下的所有配置文件,MMAction2 推荐只存在 **一个** 对应的 _原始配置_ 文件。
所有其他的配置文件都应该继承 _原始配置_ 文件,这样就能保证配置文件的最大继承深度为 3。
为了方便理解,MMAction2 推荐用户继承现有方法的配置文件。
例如,如需修改 TSN 的配置文件,用户应先通过 `_base_ = '../tsn/tsn_r50_1x1x3_100e_kinetics400_rgb.py'` 继承 TSN 配置文件的基本结构,
并修改其中必要的内容以完成继承。
如果用户想实现一个独立于任何一个现有的方法结构的新方法,则需要像 `configs/recognition`, `configs/detection` 等一样,在 `configs/TASK` 中建立新的文件夹。
更多详细内容,请参考 [mmcv](https://mmcv.readthedocs.io/en/latest/understand_mmcv/config.html)
## 配置文件命名规则
MMAction2 按照以下风格进行配置文件命名,代码库的贡献者需要遵循相同的命名规则。
```
{model}_[model setting]_{backbone}_[misc]_{data setting}_[gpu x batch_per_gpu]_{schedule}_{dataset}_{modality}
```
其中,`{xxx}` 表示必要的命名域,`[yyy]` 表示可选的命名域。
- `{model}`:模型类型,如 `tsn``i3d` 等。
- `[model setting]`:一些模型上的特殊设置。
- `{backbone}`:主干网络类型,如 `r50`(ResNet-50)等。
- `[misc]`:模型的额外设置或插件,如 `dense``320p``video`等。
- `{data setting}`:采帧数据格式,形如 `{clip_len}x{frame_interval}x{num_clips}`
- `[gpu x batch_per_gpu]`:GPU 数量以及每个 GPU 上的采样。
- `{schedule}`:训练策略设置,如 `20e` 表示 20 个周期(epoch)。
- `{dataset}`:数据集名,如 `kinetics400``mmit`等。
- `{modality}`:帧的模态,如 `rgb`, `flow`等。
### 时序动作检测的配置文件系统
MMAction2 将模块化设计整合到配置文件系统中,以便于执行各种不同的实验。
- 以 BMN 为例
为了帮助用户理解 MMAction2 的配置文件结构,以及时序动作检测系统中的一些模块,这里以 BMN 为例,给出其配置文件的注释。
对于每个模块的详细用法以及对应参数的选择,请参照 [API 文档](https://mmaction2.readthedocs.io/en/latest/api.html)
```python
# 模型设置
model = dict( # 模型的配置
type='BMN', # 时序动作检测器的类型
temporal_dim=100, # 每个视频中所选择的帧数量
boundary_ratio=0.5, # 视频边界的决策几率
num_samples=32, # 每个候选的采样数
num_samples_per_bin=3, # 每个样本的直方图采样数
feat_dim=400, # 特征维度
soft_nms_alpha=0.4, # soft-NMS 的 alpha 值
soft_nms_low_threshold=0.5, # soft-NMS 的下界
soft_nms_high_threshold=0.9, # soft-NMS 的上界
post_process_top_k=100) # 后处理得到的最好的 K 个 proposal
# 模型训练和测试的设置
train_cfg = None # 训练 BMN 的超参配置
test_cfg = dict(average_clips='score') # 测试 BMN 的超参配置
# 数据集设置
dataset_type = 'ActivityNetDataset' # 训练,验证,测试的数据集类型
data_root = 'data/activitynet_feature_cuhk/csv_mean_100/' # 训练集的根目录
data_root_val = 'data/activitynet_feature_cuhk/csv_mean_100/' # 验证集和测试集的根目录
ann_file_train = 'data/ActivityNet/anet_anno_train.json' # 训练集的标注文件
ann_file_val = 'data/ActivityNet/anet_anno_val.json' # 验证集的标注文件
ann_file_test = 'data/ActivityNet/anet_anno_test.json' # 测试集的标注文件
train_pipeline = [ # 训练数据前处理流水线步骤组成的列表
dict(type='LoadLocalizationFeature'), # 加载时序动作检测特征
dict(type='GenerateLocalizationLabels'), # 生成时序动作检测标签
dict( # Collect 类的配置
type='Collect', # Collect 类决定哪些键会被传递到时序检测器中
keys=['raw_feature', 'gt_bbox'], # 输入的键
meta_name='video_meta', # 元名称
meta_keys=['video_name']), # 输入的元键
dict( # ToTensor 类的配置
type='ToTensor', # ToTensor 类将其他类型转化为 Tensor 类型
keys=['raw_feature']), # 将被从其他类型转化为 Tensor 类型的特征
dict( # ToDataContainer 类的配置
type='ToDataContainer', # 将一些信息转入到 ToDataContainer 中
fields=[dict(key='gt_bbox', stack=False, cpu_only=True)]) # 携带额外键和属性的信息域
]
val_pipeline = [ # 验证数据前处理流水线步骤组成的列表
dict(type='LoadLocalizationFeature'), # 加载时序动作检测特征
dict(type='GenerateLocalizationLabels'), # 生成时序动作检测标签
dict( # Collect 类的配置
type='Collect', # Collect 类决定哪些键会被传递到时序检测器中
keys=['raw_feature', 'gt_bbox'], # 输入的键
meta_name='video_meta', # 元名称
meta_keys=[
'video_name', 'duration_second', 'duration_frame', 'annotations',
'feature_frame'
]), # 输入的元键
dict( # ToTensor 类的配置
type='ToTensor', # ToTensor 类将其他类型转化为 Tensor 类型
keys=['raw_feature']), # 将被从其他类型转化为 Tensor 类型的特征
dict( # ToDataContainer 类的配置
type='ToDataContainer', # 将一些信息转入到 ToDataContainer 中
fields=[dict(key='gt_bbox', stack=False, cpu_only=True)]) # 携带额外键和属性的信息域
]
test_pipeline = [ # 测试数据前处理流水线步骤组成的列表
dict(type='LoadLocalizationFeature'), # 加载时序动作检测特征
dict( # Collect 类的配置
type='Collect', # Collect 类决定哪些键会被传递到时序检测器中
keys=['raw_feature'], # 输入的键
meta_name='video_meta', # 元名称
meta_keys=[
'video_name', 'duration_second', 'duration_frame', 'annotations',
'feature_frame'
]), # 输入的元键
dict( # ToTensor 类的配置
type='ToTensor', # ToTensor 类将其他类型转化为 Tensor 类型
keys=['raw_feature']), # 将被从其他类型转化为 Tensor 类型的特征
]
data = dict( # 数据的配置
videos_per_gpu=8, # 单个 GPU 的批大小
workers_per_gpu=8, # 单个 GPU 的 dataloader 的进程
train_dataloader=dict( # 训练过程 dataloader 的额外设置
drop_last=True), # 在训练过程中是否丢弃最后一个批次
val_dataloader=dict( # 验证过程 dataloader 的额外设置
videos_per_gpu=1), # 单个 GPU 的批大小
test_dataloader=dict( # 测试过程 dataloader 的额外设置
videos_per_gpu=2), # 单个 GPU 的批大小
test=dict( # 测试数据集的设置
type=dataset_type,
ann_file=ann_file_test,
pipeline=test_pipeline,
data_prefix=data_root_val),
val=dict( # 验证数据集的设置
type=dataset_type,
ann_file=ann_file_val,
pipeline=val_pipeline,
data_prefix=data_root_val),
train=dict( # 训练数据集的设置
type=dataset_type,
ann_file=ann_file_train,
pipeline=train_pipeline,
data_prefix=data_root))
# 优化器设置
optimizer = dict(
# 构建优化器的设置,支持:
# (1) 所有 PyTorch 原生的优化器,这些优化器的参数和 PyTorch 对应的一致;
# (2) 自定义的优化器,这些优化器在 `constructor` 的基础上构建。
# 更多细节可参考 "tutorials/5_new_modules.md" 部分
type='Adam', # 优化器类型, 参考 https://github.com/open-mmlab/mmcv/blob/master/mmcv/runner/optimizer/default_constructor.py#L13 for more details
lr=0.001, # 学习率, 参数的细节使用可参考 PyTorch 的对应文档
weight_decay=0.0001) # Adam 优化器的权重衰减
optimizer_config = dict( # 用于构建优化器钩子的设置
grad_clip=None) # 大部分的方法不使用梯度裁剪
# 学习策略设置
lr_config = dict( # 用于注册学习率调整钩子的设置
policy='step', # 调整器策略, 支持 CosineAnnealing,Cyclic等方法。更多细节可参考 https://github.com/open-mmlab/mmcv/blob/master/mmcv/runner/hooks/lr_updater.py#L9
step=7) # 学习率衰减步长
total_epochs = 9 # 训练模型的总周期数
checkpoint_config = dict( # 模型权重文件钩子设置,更多细节可参考 https://github.com/open-mmlab/mmcv/blob/master/mmcv/runner/hooks/checkpoint.py
interval=1) # 模型权重文件保存间隔
evaluation = dict( # 训练期间做验证的设置
interval=1, # 执行验证的间隔
metrics=['AR@AN']) # 验证方法
log_config = dict( # 注册日志钩子的设置
interval=50, # 打印日志间隔
hooks=[ # 训练期间执行的钩子
dict(type='TextLoggerHook'), # 记录训练过程信息的日志
# dict(type='TensorboardLoggerHook'), # 同时支持 Tensorboard 日志
])
# 运行设置
dist_params = dict(backend='nccl') # 建立分布式训练的设置(端口号,多 GPU 通信框架等)
log_level = 'INFO' # 日志等级
work_dir = './work_dirs/bmn_400x100_2x8_9e_activitynet_feature/' # 记录当前实验日志和模型权重文件的文件夹
load_from = None # 从给定路径加载模型作为预训练模型. 这个选项不会用于断点恢复训练
resume_from = None # 加载给定路径的模型权重文件作为断点续连的模型, 训练将从该时间点保存的周期点继续进行
workflow = [('train', 1)] # runner 的执行流. [('train', 1)] 代表只有一个执行流,并且这个名为 train 的执行流只执行一次
output_config = dict( # 时序检测器输出设置
out=f'{work_dir}/results.json', # 输出文件路径
output_format='json') # 输出文件格式
```
### 动作识别的配置文件系统
MMAction2 将模块化设计整合到配置文件系统中,以便执行各类不同实验。
- 以 TSN 为例
为了帮助用户理解 MMAction2 的配置文件结构,以及动作识别系统中的一些模块,这里以 TSN 为例,给出其配置文件的注释。
对于每个模块的详细用法以及对应参数的选择,请参照 [API 文档](https://mmaction2.readthedocs.io/en/latest/api.html)
```python
# 模型设置
model = dict( # 模型的配置
type='Recognizer2D', # 动作识别器的类型
backbone=dict( # Backbone 字典设置
type='ResNet', # Backbone 名
pretrained='torchvision://resnet50', # 预训练模型的 url 或文件位置
depth=50, # ResNet 模型深度
norm_eval=False), # 训练时是否设置 BN 层为验证模式
cls_head=dict( # 分类器字典设置
type='TSNHead', # 分类器名
num_classes=400, # 分类类别数量
in_channels=2048, # 分类器里输入通道数
spatial_type='avg', # 空间维度的池化种类
consensus=dict(type='AvgConsensus', dim=1), # consensus 模块设置
dropout_ratio=0.4, # dropout 层概率
init_std=0.01), # 线性层初始化 std 值
# 模型训练和测试的设置
train_cfg=None, # 训练 TSN 的超参配置
test_cfg=dict(average_clips=None)) # 测试 TSN 的超参配置
# 数据集设置
dataset_type = 'RawframeDataset' # 训练,验证,测试的数据集类型
data_root = 'data/kinetics400/rawframes_train/' # 训练集的根目录
data_root_val = 'data/kinetics400/rawframes_val/' # 验证集,测试集的根目录
ann_file_train = 'data/kinetics400/kinetics400_train_list_rawframes.txt' # 训练集的标注文件
ann_file_val = 'data/kinetics400/kinetics400_val_list_rawframes.txt' # 验证集的标注文件
ann_file_test = 'data/kinetics400/kinetics400_val_list_rawframes.txt' # 测试集的标注文件
img_norm_cfg = dict( # 图像正则化参数设置
mean=[123.675, 116.28, 103.53], # 图像正则化平均值
std=[58.395, 57.12, 57.375], # 图像正则化方差
to_bgr=False) # 是否将通道数从 RGB 转为 BGR
train_pipeline = [ # 训练数据前处理流水线步骤组成的列表
dict( # SampleFrames 类的配置
type='SampleFrames', # 选定采样哪些视频帧
clip_len=1, # 每个输出视频片段的帧
frame_interval=1, # 所采相邻帧的时序间隔
num_clips=3), # 所采帧片段的数量
dict( # RawFrameDecode 类的配置
type='RawFrameDecode'), # 给定帧序列,加载对应帧,解码对应帧
dict( # Resize 类的配置
type='Resize', # 调整图片尺寸
scale=(-1, 256)), # 调整比例
dict( # MultiScaleCrop 类的配置
type='MultiScaleCrop', # 多尺寸裁剪,随机从一系列给定尺寸中选择一个比例尺寸进行裁剪
input_size=224, # 网络输入
scales=(1, 0.875, 0.75, 0.66), # 长宽比例选择范围
random_crop=False, # 是否进行随机裁剪
max_wh_scale_gap=1), # 长宽最大比例间隔
dict( # Resize 类的配置
type='Resize', # 调整图片尺寸
scale=(224, 224), # 调整比例
keep_ratio=False), # 是否保持长宽比
dict( # Flip 类的配置
type='Flip', # 图片翻转
flip_ratio=0.5), # 执行翻转几率
dict( # Normalize 类的配置
type='Normalize', # 图片正则化
**img_norm_cfg), # 图片正则化参数
dict( # FormatShape 类的配置
type='FormatShape', # 将图片格式转变为给定的输入格式
input_format='NCHW'), # 最终的图片组成格式
dict( # Collect 类的配置
type='Collect', # Collect 类决定哪些键会被传递到行为识别器中
keys=['imgs', 'label'], # 输入的键
meta_keys=[]), # 输入的元键
dict( # ToTensor 类的配置
type='ToTensor', # ToTensor 类将其他类型转化为 Tensor 类型
keys=['imgs', 'label']) # 将被从其他类型转化为 Tensor 类型的特征
]
val_pipeline = [ # 验证数据前处理流水线步骤组成的列表
dict( # SampleFrames 类的配置
type='SampleFrames', # 选定采样哪些视频帧
clip_len=1, # 每个输出视频片段的帧
frame_interval=1, # 所采相邻帧的时序间隔
num_clips=3, # 所采帧片段的数量
test_mode=True), # 是否设置为测试模式采帧
dict( # RawFrameDecode 类的配置
type='RawFrameDecode'), # 给定帧序列,加载对应帧,解码对应帧
dict( # Resize 类的配置
type='Resize', # 调整图片尺寸
scale=(-1, 256)), # 调整比例
dict( # CenterCrop 类的配置
type='CenterCrop', # 中心裁剪
crop_size=224), # 裁剪部分的尺寸
dict( # Flip 类的配置
type='Flip', # 图片翻转
flip_ratio=0), # 翻转几率
dict( # Normalize 类的配置
type='Normalize', # 图片正则化
**img_norm_cfg), # 图片正则化参数
dict( # FormatShape 类的配置
type='FormatShape', # 将图片格式转变为给定的输入格式
input_format='NCHW'), # 最终的图片组成格式
dict( # Collect 类的配置
type='Collect', # Collect 类决定哪些键会被传递到行为识别器中
keys=['imgs', 'label'], # 输入的键
meta_keys=[]), # 输入的元键
dict( # ToTensor 类的配置
type='ToTensor', # ToTensor 类将其他类型转化为 Tensor 类型
keys=['imgs']) # 将被从其他类型转化为 Tensor 类型的特征
]
test_pipeline = [ # 测试数据前处理流水线步骤组成的列表
dict( # SampleFrames 类的配置
type='SampleFrames', # 选定采样哪些视频帧
clip_len=1, # 每个输出视频片段的帧
frame_interval=1, # 所采相邻帧的时序间隔
num_clips=25, # 所采帧片段的数量
test_mode=True), # 是否设置为测试模式采帧
dict( # RawFrameDecode 类的配置
type='RawFrameDecode'), # 给定帧序列,加载对应帧,解码对应帧
dict( # Resize 类的配置
type='Resize', # 调整图片尺寸
scale=(-1, 256)), # 调整比例
dict( # TenCrop 类的配置
type='TenCrop', # 裁剪 10 个区域
crop_size=224), # 裁剪部分的尺寸
dict( # Flip 类的配置
type='Flip', # 图片翻转
flip_ratio=0), # 执行翻转几率
dict( # Normalize 类的配置
type='Normalize', # 图片正则化
**img_norm_cfg), # 图片正则化参数
dict( # FormatShape 类的配置
type='FormatShape', # 将图片格式转变为给定的输入格式
input_format='NCHW'), # 最终的图片组成格式
dict( # Collect 类的配置
type='Collect', # Collect 类决定哪些键会被传递到行为识别器中
keys=['imgs', 'label'], # 输入的键
meta_keys=[]), # 输入的元键
dict( # ToTensor 类的配置
type='ToTensor', # ToTensor 类将其他类型转化为 Tensor 类型
keys=['imgs']) # 将被从其他类型转化为 Tensor 类型的特征
]
data = dict( # 数据的配置
videos_per_gpu=32, # 单个 GPU 的批大小
workers_per_gpu=2, # 单个 GPU 的 dataloader 的进程
train_dataloader=dict( # 训练过程 dataloader 的额外设置
drop_last=True), # 在训练过程中是否丢弃最后一个批次
val_dataloader=dict( # 验证过程 dataloader 的额外设置
videos_per_gpu=1), # 单个 GPU 的批大小
test_dataloader=dict( # 测试过程 dataloader 的额外设置
videos_per_gpu=2), # 单个 GPU 的批大小
train=dict( # 训练数据集的设置
type=dataset_type,
ann_file=ann_file_train,
data_prefix=data_root,
pipeline=train_pipeline),
val=dict( # 验证数据集的设置
type=dataset_type,
ann_file=ann_file_val,
data_prefix=data_root_val,
pipeline=val_pipeline),
test=dict( # 测试数据集的设置
type=dataset_type,
ann_file=ann_file_test,
data_prefix=data_root_val,
pipeline=test_pipeline))
# 优化器设置
optimizer = dict(
# 构建优化器的设置,支持:
# (1) 所有 PyTorch 原生的优化器,这些优化器的参数和 PyTorch 对应的一致;
# (2) 自定义的优化器,这些优化器在 `constructor` 的基础上构建。
# 更多细节可参考 "tutorials/5_new_modules.md" 部分
type='SGD', # 优化器类型, 参考 https://github.com/open-mmlab/mmcv/blob/master/mmcv/runner/optimizer/default_constructor.py#L13
lr=0.01, # 学习率, 参数的细节使用可参考 PyTorch 的对应文档
momentum=0.9, # 动量大小
weight_decay=0.0001) # SGD 优化器权重衰减
optimizer_config = dict( # 用于构建优化器钩子的设置
grad_clip=dict(max_norm=40, norm_type=2)) # 使用梯度裁剪
# 学习策略设置
lr_config = dict( # 用于注册学习率调整钩子的设置
policy='step', # 调整器策略, 支持 CosineAnnealing,Cyclic等方法。更多细节可参考 https://github.com/open-mmlab/mmcv/blob/master/mmcv/runner/hooks/lr_updater.py#L9
step=[40, 80]) # 学习率衰减步长
total_epochs = 100 # 训练模型的总周期数
checkpoint_config = dict( # 模型权重钩子设置,更多细节可参考 https://github.com/open-mmlab/mmcv/blob/master/mmcv/runner/hooks/checkpoint.py
interval=5) # 模型权重文件保存间隔
evaluation = dict( # 训练期间做验证的设置
interval=5, # 执行验证的间隔
metrics=['top_k_accuracy', 'mean_class_accuracy'], # 验证方法
save_best='top_k_accuracy') # 设置 `top_k_accuracy` 作为指示器,用于存储最好的模型权重文件
log_config = dict( # 注册日志钩子的设置
interval=20, # 打印日志间隔
hooks=[ # 训练期间执行的钩子
dict(type='TextLoggerHook'), # 记录训练过程信息的日志
# dict(type='TensorboardLoggerHook'), # 同时支持 Tensorboard 日志
])
# 运行设置
dist_params = dict(backend='nccl') # 建立分布式训练的设置,其中端口号也可以设置
log_level = 'INFO' # 日志等级
work_dir = './work_dirs/tsn_r50_1x1x3_100e_kinetics400_rgb/' # 记录当前实验日志和模型权重文件的文件夹
load_from = None # 从给定路径加载模型作为预训练模型. 这个选项不会用于断点恢复训练
resume_from = None # 加载给定路径的模型权重文件作为断点续连的模型, 训练将从该时间点保存的周期点继续进行
workflow = [('train', 1)] # runner 的执行流. [('train', 1)] 代表只有一个执行流,并且这个名为 train 的执行流只执行一次
```
### 时空动作检测的配置文件系统
MMAction2 将模块化设计整合到配置文件系统中,以便于执行各种不同的实验。
- 以 FastRCNN 为例
为了帮助用户理解 MMAction2 的完整配置文件结构,以及时空检测系统中的一些模块,这里以 FastRCNN 为例,给出其配置文件的注释。
对于每个模块的详细用法以及对应参数的选择,请参照 [API 文档](https://mmaction2.readthedocs.io/en/latest/api.html)
```python
# 模型设置
model = dict( # 模型的配置
type='FastRCNN', # 时空检测器类型
backbone=dict( # Backbone 字典设置
type='ResNet3dSlowOnly', # Backbone 名
depth=50, # ResNet 模型深度
pretrained=None, # 预训练模型的 url 或文件位置
pretrained2d=False, # 预训练模型是否为 2D 模型
lateral=False, # backbone 是否有侧连接
num_stages=4, # ResNet 模型阶数
conv1_kernel=(1, 7, 7), # Conv1 卷积核尺寸
conv1_stride_t=1, # Conv1 时序步长
pool1_stride_t=1, # Pool1 时序步长
spatial_strides=(1, 2, 2, 1)), # 每个 ResNet 阶的空间步长
roi_head=dict( # roi_head 字典设置
type='AVARoIHead', # roi_head 名
bbox_roi_extractor=dict( # bbox_roi_extractor 字典设置
type='SingleRoIExtractor3D', # bbox_roi_extractor 名
roi_layer_type='RoIAlign', # RoI op 类型
output_size=8, # RoI op 输出特征尺寸
with_temporal_pool=True), # 时序维度是否要经过池化
bbox_head=dict( # bbox_head 字典设置
type='BBoxHeadAVA', # bbox_head 名
in_channels=2048, # 输入特征通道数
num_classes=81, # 动作类别数 + 1(背景)
multilabel=True, # 数据集是否多标签
dropout_ratio=0.5)), # dropout 比率
# 模型训练和测试的设置
train_cfg=dict( # 训练 FastRCNN 的超参配置
rcnn=dict( # rcnn 训练字典设置
assigner=dict( # assigner 字典设置
type='MaxIoUAssignerAVA', # assigner 名
pos_iou_thr=0.9, # 正样本 IoU 阈值, > pos_iou_thr -> positive
neg_iou_thr=0.9, # 负样本 IoU 阈值, < neg_iou_thr -> negative
min_pos_iou=0.9), # 正样本最小可接受 IoU
sampler=dict( # sample 字典设置
type='RandomSampler', # sampler 名
num=32, # sampler 批大小
pos_fraction=1, # sampler 正样本边界框比率
neg_pos_ub=-1, # 负样本数转正样本数的比率上界
add_gt_as_proposals=True), # 是否添加 ground truth 为候选
pos_weight=1.0, # 正样本 loss 权重
debug=False)), # 是否为 debug 模式
test_cfg=dict( # 测试 FastRCNN 的超参设置
rcnn=dict( # rcnn 测试字典设置
action_thr=0.002))) # 某行为的阈值
# 数据集设置
dataset_type = 'AVADataset' # 训练,验证,测试的数据集类型
data_root = 'data/ava/rawframes' # 训练集的根目录
anno_root = 'data/ava/annotations' # 标注文件目录
ann_file_train = f'{anno_root}/ava_train_v2.1.csv' # 训练集的标注文件
ann_file_val = f'{anno_root}/ava_val_v2.1.csv' # 验证集的标注文件
exclude_file_train = f'{anno_root}/ava_train_excluded_timestamps_v2.1.csv' # 训练除外数据集文件路径
exclude_file_val = f'{anno_root}/ava_val_excluded_timestamps_v2.1.csv' # 验证除外数据集文件路径
label_file = f'{anno_root}/ava_action_list_v2.1_for_activitynet_2018.pbtxt' # 标签文件路径
proposal_file_train = f'{anno_root}/ava_dense_proposals_train.FAIR.recall_93.9.pkl' # 训练样本检测候选框的文件路径
proposal_file_val = f'{anno_root}/ava_dense_proposals_val.FAIR.recall_93.9.pkl' # 验证样本检测候选框的文件路径
img_norm_cfg = dict( # 图像正则化参数设置
mean=[123.675, 116.28, 103.53], # 图像正则化平均值
std=[58.395, 57.12, 57.375], # 图像正则化方差
to_bgr=False) # 是否将通道数从 RGB 转为 BGR
train_pipeline = [ # 训练数据前处理流水线步骤组成的列表
dict( # SampleFrames 类的配置
type='AVASampleFrames', # 选定采样哪些视频帧
clip_len=4, # 每个输出视频片段的帧
frame_interval=16), # 所采相邻帧的时序间隔
dict( # RawFrameDecode 类的配置
type='RawFrameDecode'), # 给定帧序列,加载对应帧,解码对应帧
dict( # RandomRescale 类的配置
type='RandomRescale', # 给定一个范围,进行随机短边缩放
scale_range=(256, 320)), # RandomRescale 的短边缩放范围
dict( # RandomCrop 类的配置
type='RandomCrop', # 给定一个尺寸进行随机裁剪
size=256), # 裁剪尺寸
dict( # Flip 类的配置
type='Flip', # 图片翻转
flip_ratio=0.5), # 执行翻转几率
dict( # Normalize 类的配置
type='Normalize', # 图片正则化
**img_norm_cfg), # 图片正则化参数
dict( # FormatShape 类的配置
type='FormatShape', # 将图片格式转变为给定的输入格式
input_format='NCTHW', # 最终的图片组成格式
collapse=True), # 去掉 N 梯度当 N == 1
dict( # Rename 类的配置
type='Rename', # 重命名 key 名
mapping=dict(imgs='img')), # 改名映射字典
dict( # ToTensor 类的配置
type='ToTensor', # ToTensor 类将其他类型转化为 Tensor 类型
keys=['img', 'proposals', 'gt_bboxes', 'gt_labels']), # 将被从其他类型转化为 Tensor 类型的特征
dict( # ToDataContainer 类的配置
type='ToDataContainer', # 将一些信息转入到 ToDataContainer 中
fields=[ # 转化为 Datacontainer 的域
dict( # 域字典
key=['proposals', 'gt_bboxes', 'gt_labels'], # 将转化为 DataContainer 的键
stack=False)]), # 是否要堆列这些 tensor
dict( # Collect 类的配置
type='Collect', # Collect 类决定哪些键会被传递到时空检测器中
keys=['img', 'proposals', 'gt_bboxes', 'gt_labels'], # 输入的键
meta_keys=['scores', 'entity_ids']), # 输入的元键
]
val_pipeline = [ # 验证数据前处理流水线步骤组成的列表
dict( # SampleFrames 类的配置
type='AVASampleFrames', # 选定采样哪些视频帧
clip_len=4, # 每个输出视频片段的帧
frame_interval=16), # 所采相邻帧的时序间隔
dict( # RawFrameDecode 类的配置
type='RawFrameDecode'), # 给定帧序列,加载对应帧,解码对应帧
dict( # Resize 类的配置
type='Resize', # 调整图片尺寸
scale=(-1, 256)), # 调整比例
dict( # Normalize 类的配置
type='Normalize', # 图片正则化
**img_norm_cfg), # 图片正则化参数
dict( # FormatShape 类的配置
type='FormatShape', # 将图片格式转变为给定的输入格式
input_format='NCTHW', # 最终的图片组成格式
collapse=True), # 去掉 N 梯度当 N == 1
dict( # Rename 类的配置
type='Rename', # 重命名 key 名
mapping=dict(imgs='img')), # 改名映射字典
dict( # ToTensor 类的配置
type='ToTensor', # ToTensor 类将其他类型转化为 Tensor 类型
keys=['img', 'proposals']), # 将被从其他类型转化为 Tensor 类型的特征
dict( # ToDataContainer 类的配置
type='ToDataContainer', # 将一些信息转入到 ToDataContainer 中
fields=[ # 转化为 Datacontainer 的域
dict( # 域字典
key=['proposals'], # 将转化为 DataContainer 的键
stack=False)]), # 是否要堆列这些 tensor
dict( # Collect 类的配置
type='Collect', # Collect 类决定哪些键会被传递到时空检测器中
keys=['img', 'proposals'], # 输入的键
meta_keys=['scores', 'entity_ids'], # 输入的元键
nested=True) # 是否将数据包装为嵌套列表
]
data = dict( # 数据的配置
videos_per_gpu=16, # 单个 GPU 的批大小
workers_per_gpu=2, # 单个 GPU 的 dataloader 的进程
val_dataloader=dict( # 验证过程 dataloader 的额外设置
videos_per_gpu=1), # 单个 GPU 的批大小
train=dict( # 训练数据集的设置
type=dataset_type,
ann_file=ann_file_train,
exclude_file=exclude_file_train,
pipeline=train_pipeline,
label_file=label_file,
proposal_file=proposal_file_train,
person_det_score_thr=0.9,
data_prefix=data_root),
val=dict( # 验证数据集的设置
type=dataset_type,
ann_file=ann_file_val,
exclude_file=exclude_file_val,
pipeline=val_pipeline,
label_file=label_file,
proposal_file=proposal_file_val,
person_det_score_thr=0.9,
data_prefix=data_root))
data['test'] = data['val'] # 将验证数据集设置复制到测试数据集设置
# 优化器设置
optimizer = dict(
# 构建优化器的设置,支持:
# (1) 所有 PyTorch 原生的优化器,这些优化器的参数和 PyTorch 对应的一致;
# (2) 自定义的优化器,这些优化器在 `constructor` 的基础上构建。
# 更多细节可参考 "tutorials/5_new_modules.md" 部分
type='SGD', # 优化器类型, 参考 https://github.com/open-mmlab/mmcv/blob/master/mmcv/runner/optimizer/default_constructor.py#L13
lr=0.2, # 学习率, 参数的细节使用可参考 PyTorch 的对应文档
momentum=0.9, # 动量大小
weight_decay=0.00001) # SGD 优化器权重衰减
optimizer_config = dict( # 用于构建优化器钩子的设置
grad_clip=dict(max_norm=40, norm_type=2)) # 使用梯度裁剪
lr_config = dict( # 用于注册学习率调整钩子的设置
policy='step', # 调整器策略, 支持 CosineAnnealing,Cyclic等方法。更多细节可参考 https://github.com/open-mmlab/mmcv/blob/master/mmcv/runner/hooks/lr_updater.py#L9
step=[40, 80], # 学习率衰减步长
warmup='linear', # Warmup 策略
warmup_by_epoch=True, # Warmup 单位为 epoch 还是 iteration
warmup_iters=5, # warmup 数
warmup_ratio=0.1) # 初始学习率为 warmup_ratio * lr
total_epochs = 20 # 训练模型的总周期数
checkpoint_config = dict( # 模型权重文件钩子设置,更多细节可参考 https://github.com/open-mmlab/mmcv/blob/master/mmcv/runner/hooks/checkpoint.py
interval=1) # 模型权重文件保存间隔
workflow = [('train', 1)] # runner 的执行流. [('train', 1)] 代表只有一个执行流,并且这个名为 train 的执行流只执行一次
evaluation = dict( # 训练期间做验证的设置
interval=1, save_best='mAP@0.5IOU') # 执行验证的间隔,以及设置 `mAP@0.5IOU` 作为指示器,用于存储最好的模型权重文件
log_config = dict( # 注册日志钩子的设置
interval=20, # 打印日志间隔
hooks=[ # 训练期间执行的钩子
dict(type='TextLoggerHook'), # 记录训练过程信息的日志
])
# 运行设置
dist_params = dict(backend='nccl') # 建立分布式训练的设置,其中端口号也可以设置
log_level = 'INFO' # 日志等级
work_dir = ('./work_dirs/ava/' # 记录当前实验日志和模型权重文件的文件夹
'slowonly_kinetics_pretrained_r50_4x16x1_20e_ava_rgb')
load_from = ('https://download.openmmlab.com/mmaction/recognition/slowonly/' # 从给定路径加载模型作为预训练模型. 这个选项不会用于断点恢复训练
'slowonly_r50_4x16x1_256e_kinetics400_rgb/'
'slowonly_r50_4x16x1_256e_kinetics400_rgb_20200704-a69556c6.pth')
resume_from = None # 加载给定路径的模型权重文件作为断点续连的模型, 训练将从该时间点保存的周期点继续进行
```
## 常见问题
### 配置文件中的中间变量
配置文件中会用到一些中间变量,如 `train_pipeline`/`val_pipeline`/`test_pipeline`, `ann_file_train`/`ann_file_val`/`ann_file_test`, `img_norm_cfg` 等。
例如,首先定义中间变量 `train_pipeline`/`val_pipeline`/`test_pipeline`,再将上述变量传递到 `data`。因此,`train_pipeline`/`val_pipeline`/`test_pipeline` 为中间变量
这里也定义了 `ann_file_train`/`ann_file_val`/`ann_file_test``data_root`/`data_root_val` 为数据处理流程提供一些基本信息。
此外,使用 `img_norm_cfg` 作为中间变量,构建一些数组增强组件。
```python
...
dataset_type = 'RawframeDataset'
data_root = 'data/kinetics400/rawframes_train'
data_root_val = 'data/kinetics400/rawframes_val'
ann_file_train = 'data/kinetics400/kinetics400_train_list_rawframes.txt'
ann_file_val = 'data/kinetics400/kinetics400_val_list_rawframes.txt'
ann_file_test = 'data/kinetics400/kinetics400_val_list_rawframes.txt'
img_norm_cfg = dict(
mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_bgr=False)
train_pipeline = [
dict(type='SampleFrames', clip_len=32, frame_interval=2, num_clips=1),
dict(type='RawFrameDecode'),
dict(type='Resize', scale=(-1, 256)),
dict(
type='MultiScaleCrop',
input_size=224,
scales=(1, 0.8),
random_crop=False,
max_wh_scale_gap=0),
dict(type='Resize', scale=(224, 224), keep_ratio=False),
dict(type='Flip', flip_ratio=0.5),
dict(type='Normalize', **img_norm_cfg),
dict(type='FormatShape', input_format='NCTHW'),
dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]),
dict(type='ToTensor', keys=['imgs', 'label'])
]
val_pipeline = [
dict(
type='SampleFrames',
clip_len=32,
frame_interval=2,
num_clips=1,
test_mode=True),
dict(type='RawFrameDecode'),
dict(type='Resize', scale=(-1, 256)),
dict(type='CenterCrop', crop_size=224),
dict(type='Normalize', **img_norm_cfg),
dict(type='FormatShape', input_format='NCTHW'),
dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]),
dict(type='ToTensor', keys=['imgs'])
]
test_pipeline = [
dict(
type='SampleFrames',
clip_len=32,
frame_interval=2,
num_clips=10,
test_mode=True),
dict(type='RawFrameDecode'),
dict(type='Resize', scale=(-1, 256)),
dict(type='ThreeCrop', crop_size=256),
dict(type='Normalize', **img_norm_cfg),
dict(type='FormatShape', input_format='NCTHW'),
dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]),
dict(type='ToTensor', keys=['imgs'])
]
data = dict(
videos_per_gpu=8,
workers_per_gpu=2,
train=dict(
type=dataset_type,
ann_file=ann_file_train,
data_prefix=data_root,
pipeline=train_pipeline),
val=dict(
type=dataset_type,
ann_file=ann_file_val,
data_prefix=data_root_val,
pipeline=val_pipeline),
test=dict(
type=dataset_type,
ann_file=ann_file_val,
data_prefix=data_root_val,
pipeline=test_pipeline))
```
# 教程 2:如何微调模型
本教程介绍如何使用预训练模型在其他数据集上进行微调。
<!-- TOC -->
- [教程 2:如何微调模型](#教程-2如何微调模型)
- [概要](#概要)
- [修改 Head](#修改-head)
- [修改数据集](#修改数据集)
- [修改训练策略](#修改训练策略)
- [使用预训练模型](#使用预训练模型)
<!-- TOC -->
## 概要
对新数据集上的模型进行微调需要进行两个步骤:
1. 增加对新数据集的支持。详情请见 [教程 3:如何增加新数据集](3_new_dataset.md)
2. 修改配置文件。这部分将在本教程中做具体讨论。
例如,如果用户想要微调 Kinetics-400 数据集的预训练模型到另一个数据集上,如 UCF101,则需要注意 [配置文件](1_config.md) 中 Head、数据集、训练策略、预训练模型四个部分,下面分别介绍。
## 修改 Head
`cls_head` 中的 `num_classes` 参数需改为新数据集中的类别数。
预训练模型中,除了最后一层外的权重都会被重新利用,因此这个改动是安全的。
例如,UCF101 拥有 101 类行为,因此需要把 400 (Kinetics-400 的类别数) 改为 101。
```python
model = dict(
type='Recognizer2D',
backbone=dict(
type='ResNet',
pretrained='torchvision://resnet50',
depth=50,
norm_eval=False),
cls_head=dict(
type='TSNHead',
num_classes=101, # 从 400 改为 101
in_channels=2048,
spatial_type='avg',
consensus=dict(type='AvgConsensus', dim=1),
dropout_ratio=0.4,
init_std=0.01),
train_cfg=None,
test_cfg=dict(average_clips=None))
```
其中, `pretrained='torchvision://resnet50'` 表示通过 ImageNet 预训练权重初始化 backbone。
然而,模型微调时的预训练权重一般通过 `load_from`(而不是 `pretrained`)指定。
## 修改数据集
MMAction2 支持 UCF101, Kinetics-400, Moments in Time, Multi-Moments in Time, THUMOS14,
Something-Something V1&V2, ActivityNet 等数据集。
用户可将自建数据集转换已有数据集格式。
对动作识别任务来讲,MMAction2 提供了 `RawframeDataset``VideoDataset` 等通用的数据集读取类,数据集格式相对简单。
`UCF101``RawframeDataset` 为例,
```python
# 数据集设置
dataset_type = 'RawframeDataset'
data_root = 'data/ucf101/rawframes_train/'
data_root_val = 'data/ucf101/rawframes_val/'
ann_file_train = 'data/ucf101/ucf101_train_list.txt'
ann_file_val = 'data/ucf101/ucf101_val_list.txt'
ann_file_test = 'data/ucf101/ucf101_val_list.txt'
```
## 修改训练策略
通常情况下,设置较小的学习率,微调模型少量训练批次,即可取得较好效果。
```python
# 优化器
optimizer = dict(type='SGD', lr=0.005, momentum=0.9, weight_decay=0.0001) # 从 0.01 改为 0.005
optimizer_config = dict(grad_clip=dict(max_norm=40, norm_type=2))
# 学习策略
lr_config = dict(policy='step', step=[20, 40]) # step 与 total_epoch 相适应
total_epochs = 50 # 从 100 改为 50
checkpoint_config = dict(interval=5)
```
## 使用预训练模型
若要将预训练模型用于整个网络(主干网络设置中的 `pretrained`,仅会在主干网络模型上加载预训练参数),可通过 `load_from` 指定模型文件路径或模型链接,实现预训练权重导入。
MMAction2 在 `configs/_base_/default_runtime.py` 文件中将 `load_from=None` 设为默认。由于配置文件的可继承性,用户可直接在下游配置文件中设置 `load_from` 的值来进行更改。
```python
# 将预训练模型用于整个 TSN 网络
load_from = 'https://open-mmlab.s3.ap-northeast-2.amazonaws.com/mmaction/mmaction-v1/recognition/tsn_r50_1x1x3_100e_kinetics400_rgb/tsn_r50_1x1x3_100e_kinetics400_rgb_20200614-e508be42.pth' # 模型路径可以在 model zoo 中找到
```
# 教程 3:如何增加新数据集
在本教程中,我们将介绍一些有关如何按已支持的数据格式进行数据组织,和组合已有数据集来自定义数据集的方法。
<!-- TOC -->
- [教程 3:如何增加新数据集](#教程-3如何增加新数据集)
- [通过重组数据来自定义数据集](#通过重组数据来自定义数据集)
- [将数据集重新组织为现有格式](#将数据集重新组织为现有格式)
- [自定义数据集的示例](#自定义数据集的示例)
- [通过组合已有数据集来自定义数据集](#通过组合已有数据集来自定义数据集)
- [重复数据集](#重复数据集)
<!-- TOC -->
## 通过重组数据来自定义数据集
### 将数据集重新组织为现有格式
最简单的方法是将数据集转换为现有的数据集格式(RawframeDataset 或 VideoDataset)。
有三种标注文件:
- 帧标注(rawframe annotation)
帧数据集(rawframe dataset)标注文件由多行文本组成,每行代表一个样本,每个样本分为三个部分,分别是 `帧(相对)文件夹`(rawframe directory of relative path),
`总帧数`(total frames)以及 `标签`(label),通过空格进行划分
示例如下:
```
some/directory-1 163 1
some/directory-2 122 1
some/directory-3 258 2
some/directory-4 234 2
some/directory-5 295 3
some/directory-6 121 3
```
- 视频标注(video annotation)
视频数据集(video dataset)标注文件由多行文本组成,每行代表一个样本,每个样本分为两个部分,分别是 `文件(相对)路径`(filepath of relative path)
`标签`(label),通过空格进行划分
示例如下:
```
some/path/000.mp4 1
some/path/001.mp4 1
some/path/002.mp4 2
some/path/003.mp4 2
some/path/004.mp4 3
some/path/005.mp4 3
```
- ActivityNet 标注
ActivityNet 数据集的标注文件是一个 json 文件。每个键是一个视频名,其对应的值是这个视频的元数据和注释。
示例如下:
```
{
"video1": {
"duration_second": 211.53,
"duration_frame": 6337,
"annotations": [
{
"segment": [
30.025882995319815,
205.2318595943838
],
"label": "Rock climbing"
}
],
"feature_frame": 6336,
"fps": 30.0,
"rfps": 29.9579255898
},
"video2": {
"duration_second": 26.75,
"duration_frame": 647,
"annotations": [
{
"segment": [
2.578755070202808,
24.914101404056165
],
"label": "Drinking beer"
}
],
"feature_frame": 624,
"fps": 24.0,
"rfps": 24.1869158879
}
}
```
有两种使用自定义数据集的方法:
- 在线转换
用户可以通过继承 [BaseDataset](/mmaction/datasets/base.py) 基类编写一个新的数据集类,并重写三个抽象类方法:
`load_annotations(self)``evaluate(self, results, metrics, logger)``dump_results(self, results, out)`
[RawframeDataset](/mmaction/datasets/rawframe_dataset.py)[VideoDataset](/mmaction/datasets/video_dataset.py)[ActivityNetDataset](/mmaction/datasets/activitynet_dataset.py)
- 本地转换
用户可以转换标注文件格式为上述期望的格式,并将其存储为 pickle 或 json 文件,然后便可以应用于 `RawframeDataset``VideoDataset``ActivityNetDataset` 中。
数据预处理后,用户需要进一步修改配置文件以使用数据集。 这里展示了以帧形式使用自定义数据集的例子:
`configs/task/method/my_custom_config.py` 下:
```python
...
# 数据集设定
dataset_type = 'RawframeDataset'
data_root = 'path/to/your/root'
data_root_val = 'path/to/your/root_val'
ann_file_train = 'data/custom/custom_train_list.txt'
ann_file_val = 'data/custom/custom_val_list.txt'
ann_file_test = 'data/custom/custom_val_list.txt'
...
data = dict(
videos_per_gpu=32,
workers_per_gpu=2,
train=dict(
type=dataset_type,
ann_file=ann_file_train,
...),
val=dict(
type=dataset_type,
ann_file=ann_file_val,
...),
test=dict(
type=dataset_type,
ann_file=ann_file_test,
...))
...
```
### 自定义数据集的示例
假设注释在文本文件中以新格式显示,并且图像文件名具有类似 “img_00005.jpg” 的模板。
那么视频注释将以以下形式存储在文本文件 `annotation.txt` 中。
```
#文件夹,总帧数,类别
D32_1gwq35E,299,66
-G-5CJ0JkKY,249,254
T4h1bvOd9DA,299,33
4uZ27ivBl00,299,341
0LfESFkfBSw,249,186
-YIsNpBEx6c,299,169
```
`mmaction/datasets/my_dataset.py` 中创建新数据集加载数据
```python
import copy
import os.path as osp
import mmcv
from .base import BaseDataset
from .builder import DATASETS
@DATASETS.register_module()
class MyDataset(BaseDataset):
def __init__(self,
ann_file,
pipeline,
data_prefix=None,
test_mode=False,
filename_tmpl='img_{:05}.jpg'):
super(MyDataset, self).__init__(ann_file, pipeline, test_mode)
self.filename_tmpl = filename_tmpl
def load_annotations(self):
video_infos = []
with open(self.ann_file, 'r') as fin:
for line in fin:
if line.startswith("directory"):
continue
frame_dir, total_frames, label = line.split(',')
if self.data_prefix is not None:
frame_dir = osp.join(self.data_prefix, frame_dir)
video_infos.append(
dict(
frame_dir=frame_dir,
total_frames=int(total_frames),
label=int(label)))
return video_infos
def prepare_train_frames(self, idx):
results = copy.deepcopy(self.video_infos[idx])
results['filename_tmpl'] = self.filename_tmpl
return self.pipeline(results)
def prepare_test_frames(self, idx):
results = copy.deepcopy(self.video_infos[idx])
results['filename_tmpl'] = self.filename_tmpl
return self.pipeline(results)
def evaluate(self,
results,
metrics='top_k_accuracy',
topk=(1, 5),
logger=None):
pass
```
然后在配置文件中,用户可通过如下修改来使用 `MyDataset`
```python
dataset_A_train = dict(
type='MyDataset',
ann_file=ann_file_train,
pipeline=train_pipeline
)
```
## 通过组合已有数据集来自定义数据集
MMAction2 还支持组合已有数据集以进行训练。 目前,它支持重复数据集(repeat dataset)。
### 重复数据集
MMAction2 使用 “RepeatDataset” 作为包装器来重复数据集。例如,假设原始数据集为 “Dataset_A”,
为了重复此数据集,可设置配置如下:
```python
dataset_A_train = dict(
type='RepeatDataset',
times=N,
dataset=dict( # 这是 Dataset_A 的原始配置
type='Dataset_A',
...
pipeline=train_pipeline
)
)
```
# 教程 4:如何设计数据处理流程
在本教程中,我们将介绍一些有关数据前处理流水线设计的方法,以及如何为项目自定义和扩展自己的数据流水线。
<!-- TOC -->
- [教程 4:如何设计数据处理流程](#教程-4如何设计数据处理流程)
- [数据前处理流水线设计](#数据前处理流水线设计)
- [数据加载](#数据加载)
- [数据预处理](#数据预处理)
- [数据格式化](#数据格式化)
- [扩展和使用自定义流水线](#扩展和使用自定义流水线)
<!-- TOC -->
## 数据前处理流水线设计
按照惯例,MMAction2 使用 `Dataset``DataLoader` 实现多进程数据加载。 `Dataset` 返回一个字典,作为模型的输入。
由于动作识别和时序动作检测的数据大小不一定相同(图片大小,边界框大小等),MMAction2 使用 MMCV 中的 `DataContainer` 收集和分配不同大小的数据,
详情可见 [这里](https://github.com/open-mmlab/mmcv/blob/master/mmcv/parallel/data_container.py)
“数据前处理流水线” 和 “数据集构建” 是相互解耦的。通常,“数据集构建” 定义如何处理标注文件,“数据前处理流水线” 定义数据加载、预处理、格式化等功能(后文将详细介绍)。
数据前处理流水线由一系列相互解耦的操作组成。每个操作都输入一个字典(dict),新增/更新/删除相关字段,最终输出该字典,作为下一个操作的输入。
我们在下图中展示了一个典型的流水线。 蓝色块是流水线操作。
随着流水线的深入,每个操作都可以向结果字典添加新键(标记为绿色)或更新现有键(标记为橙色)。
![流水线](https://github.com/open-mmlab/mmaction2/raw/master/resources/data_pipeline.png)
这些操作分为数据加载,数据预处理和数据格式化。
这里以 TSN 的数据前处理流水线为例:
```python
img_norm_cfg = dict(
mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_bgr=False)
train_pipeline = [
dict(type='SampleFrames', clip_len=1, frame_interval=1, num_clips=3),
dict(type='RawFrameDecode', io_backend='disk'),
dict(type='Resize', scale=(-1, 256)),
dict(
type='MultiScaleCrop',
input_size=224,
scales=(1, 0.875, 0.75, 0.66),
random_crop=False,
max_wh_scale_gap=1),
dict(type='Resize', scale=(224, 224), keep_ratio=False),
dict(type='Flip', flip_ratio=0.5),
dict(type='Normalize', **img_norm_cfg),
dict(type='FormatShape', input_format='NCHW'),
dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]),
dict(type='ToTensor', keys=['imgs', 'label'])
]
val_pipeline = [
dict(
type='SampleFrames',
clip_len=1,
frame_interval=1,
num_clips=3,
test_mode=True),
dict(type='RawFrameDecode', io_backend='disk'),
dict(type='Resize', scale=(-1, 256)),
dict(type='CenterCrop', crop_size=224),
dict(type='Normalize', **img_norm_cfg),
dict(type='FormatShape', input_format='NCHW'),
dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]),
dict(type='ToTensor', keys=['imgs'])
]
test_pipeline = [
dict(
type='SampleFrames',
clip_len=1,
frame_interval=1,
num_clips=25,
test_mode=True),
dict(type='RawFrameDecode', io_backend='disk'),
dict(type='Resize', scale=(-1, 256)),
dict(type='TenCrop', crop_size=224),
dict(type='Normalize', **img_norm_cfg),
dict(type='FormatShape', input_format='NCHW'),
dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]),
dict(type='ToTensor', keys=['imgs'])
]
```
MMAction2 也支持一些 lazy 操作符。
Lazy 操作记录如何处理数据,但是它会推迟对原始数据的处理,直到进入 Fuse 阶段。
具体而言,lazy 操作符避免了对原始数据的频繁读取和修改操作,只在最后的 Fuse 阶段中对原始数据进行了一次处理,从而加快了数据预处理速度,因此,推荐用户使用本功能。
这是使用 lazy 运算符的数据前处理流水线的例子:
```python
train_pipeline = [
dict(type='SampleFrames', clip_len=32, frame_interval=2, num_clips=1),
dict(type='RawFrameDecode', decoding_backend='turbojpeg'),
# 以下三个 lazy 操作符仅处理帧的 bbox 而不修改原始数据。
dict(type='Resize', scale=(-1, 256), lazy=True),
dict(
type='MultiScaleCrop',
input_size=224,
scales=(1, 0.8),
random_crop=False,
max_wh_scale_gap=0,
lazy=True),
dict(type='Resize', scale=(224, 224), keep_ratio=False, lazy=True),
# lazy 操作符 “Flip” 仅记录是否应该翻转框架和翻转方向。
dict(type='Flip', flip_ratio=0.5, lazy=True),
# 在 Fuse 阶段处理一次原始数据
dict(type='Fuse'),
dict(type='Normalize', **img_norm_cfg),
dict(type='FormatShape', input_format='NCTHW'),
dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]),
dict(type='ToTensor', keys=['imgs', 'label'])
]
```
本节将所有操作分为数据加载、数据预处理、数据格式化三类,列出每个操作 新增/更新/删除 的相关字典字段,其中 `*` 代表所对应的键值不一定会被影响。
### 数据加载
`SampleFrames`
- 新增: frame_inds, clip_len, frame_interval, num_clips, \*total_frames
`DenseSampleFrames`
- 新增: frame_inds, clip_len, frame_interval, num_clips, \*total_frames
`PyAVDecode`
- 新增: imgs, original_shape
- 更新: \*frame_inds
`DecordDecode`
- 新增: imgs, original_shape
- 更新: \*frame_inds
`OpenCVDecode`
- 新增: imgs, original_shape
- 更新: \*frame_inds
`RawFrameDecode`
- 新增: imgs, original_shape
- 更新: \*frame_inds
### 数据预处理
`RandomCrop`
- 新增: crop_bbox, img_shape
- 更新: imgs
`RandomResizedCrop`
- 新增: crop_bbox, img_shape
- 更新: imgs
`MultiScaleCrop`
- 新增: crop_bbox, img_shape, scales
- 更新: imgs
`Resize`
- 新增: img_shape, keep_ratio, scale_factor
- 更新: imgs
`Flip`
- 新增: flip, flip_direction
- 更新: imgs, label
`Normalize`
- 新增: img_norm_cfg
- 更新: imgs
`CenterCrop`
- 新增: crop_bbox, img_shape
- 更新: imgs
`ThreeCrop`
- 新增: crop_bbox, img_shape
- 更新: imgs
`TenCrop`
- 新增: crop_bbox, img_shape
- 更新: imgs
### 数据格式化
`ToTensor`
- 更新: specified by `keys`.
`ImageToTensor`
- 更新: specified by `keys`.
`Transpose`
- 更新: specified by `keys`.
`Collect`
- 新增: img_metas (所有需要的图像元数据,会被在此阶段整合进 `meta_keys` 键值中)
- 删除: 所有没有被整合进 `keys` 的键值
**值得注意的是**,第一个键,通常是 `imgs`,会作为主键用来计算批大小。
`FormatShape`
- 新增: input_shape
- 更新: imgs
## 扩展和使用自定义流水线
1. 在任何文件写入一个新的处理流水线,如 `my_pipeline.py`。它以一个字典作为输入并返回一个字典
```python
from mmaction.datasets import PIPELINES
@PIPELINES.register_module()
class MyTransform:
def __call__(self, results):
results['key'] = value
return results
```
2. 导入新类
```python
from .my_pipeline import MyTransform
```
3. 在配置文件使用它
```python
img_norm_cfg = dict(
mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True)
train_pipeline = [
dict(type='DenseSampleFrames', clip_len=8, frame_interval=8, num_clips=1),
dict(type='RawFrameDecode', io_backend='disk'),
dict(type='MyTransform'), # 使用自定义流水线操作
dict(type='Normalize', **img_norm_cfg),
dict(type='FormatShape', input_format='NCTHW'),
dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]),
dict(type='ToTensor', keys=['imgs', 'label'])
]
```
# 教程 5:如何添加新模块
在本教程中,我们将介绍一些有关如何为该项目定制优化器,开发新组件,以及添加新的学习率调整器(更新器)的方法。
<!-- TOC -->
- [教程 5:如何添加新模块](#教程-5如何添加新模块)
- [自定义优化器](#自定义优化器)
- [自定义优化器构造器](#自定义优化器构造器)
- [开发新组件](#开发新组件)
- [添加新的 backbones](#添加新的-backbones)
- [添加新的 heads](#添加新的-heads)
- [添加新的 loss function](#添加新的-loss-function)
- [添加新的学习率调节器(更新器)](#添加新的学习率调节器更新器)
<!-- TOC -->
## 自定义优化器
[CopyOfSGD](/mmaction/core/optimizer/copy_of_sgd.py) 是自定义优化器的一个例子,写在 `mmaction/core/optimizer/copy_of_sgd.py` 文件中。
更一般地,可以根据如下方法自定义优化器。
假设添加的优化器名为 `MyOptimizer`,它有 `a``b``c` 三个参数。
用户需要首先实现一个新的优化器文件,如 `mmaction/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):
```
然后添加这个模块到 `mmaction/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)
```
用户可以直接根据 [PyTorch API 文档](https://pytorch.org/docs/stable/optim.html?highlight=optim#module-torch.optim) 对参数进行直接设置。
## 自定义优化器构造器
某些模型可能对不同层的参数有特定的优化设置,例如 BatchNorm 层的梯度衰减。
用户可以通过自定义优化器构造函数来进行那些细粒度的参数调整。
用户可以编写一个基于 [DefaultOptimizerConstructor](https://github.com/open-mmlab/mmcv/blob/master/mmcv/runner/optimizer/default_constructor.py) 的新的优化器构造器,
并且重写 `add_params(self, params, module)` 方法。
一个自定义优化器构造器的例子是 [TSMOptimizerConstructor](/mmaction/core/optimizer/tsm_optimizer_constructor.py)
更具体地,可以如下定义定制的优化器构造器。
`mmaction/core/optimizer/my_optimizer_constructor.py`
```python
from mmcv.runner import OPTIMIZER_BUILDERS, DefaultOptimizerConstructor
@OPTIMIZER_BUILDERS.register_module()
class MyOptimizerConstructor(DefaultOptimizerConstructor):
```
`mmaction/core/optimizer/__init__.py`
```python
from .my_optimizer_constructor import MyOptimizerConstructor
```
之后便可在配置文件的 `optimizer` 域中使用 `MyOptimizerConstructor`
```python
# 优化器
optimizer = dict(
type='SGD',
constructor='MyOptimizerConstructor',
paramwise_cfg=dict(fc_lr5=True),
lr=0.02,
momentum=0.9,
weight_decay=0.0001)
```
## 开发新组件
MMAction2 将模型组件分为 4 种基础模型:
- 识别器(recognizer):整个识别器模型流水线,通常包含一个主干网络(backbone)和分类头(cls_head)。
- 主干网络(backbone):通常为一个用于提取特征的 FCN 网络,例如 ResNet,BNInception。
- 分类头(cls_head):用于分类任务的组件,通常包括一个带有池化层的 FC 层。
- 时序检测器(localizer):用于时序检测的模型,目前有的检测器包含 BSN,BMN,SSN。
### 添加新的 backbones
这里以 TSN 为例,说明如何开发新的组件。
1. 创建新文件 `mmaction/models/backbones/resnet.py`
```python
import torch.nn as nn
from ..builder import BACKBONES
@BACKBONES.register_module()
class ResNet(nn.Module):
def __init__(self, arg1, arg2):
pass
def forward(self, x): # 应该返回一个元组
pass
def init_weights(self, pretrained=None):
pass
```
2.`mmaction/models/backbones/__init__.py` 中导入模型
```python
from .resnet import ResNet
```
3. 在配置文件中使用它
```python
model = dict(
...
backbone=dict(
type='ResNet',
arg1=xxx,
arg2=xxx),
)
```
### 添加新的 heads
这里以 TSNHead 为例,说明如何开发新的 head
1. 创建新文件 `mmaction/models/heads/tsn_head.py`
可以通过继承 [BaseHead](/mmaction/models/heads/base.py) 编写一个新的分类头,
并重写 `init_weights(self)``forward(self, x)` 方法
```python
from ..builder import HEADS
from .base import BaseHead
@HEADS.register_module()
class TSNHead(BaseHead):
def __init__(self, arg1, arg2):
pass
def forward(self, x):
pass
def init_weights(self):
pass
```
2.`mmaction/models/heads/__init__.py` 中导入模型
```python
from .tsn_head import TSNHead
```
3. 在配置文件中使用它
```python
model = dict(
...
cls_head=dict(
type='TSNHead',
num_classes=400,
in_channels=2048,
arg1=xxx,
arg2=xxx),
```
### 添加新的 loss function
假设用户想添加新的 loss 为 `MyLoss`。为了添加一个新的损失函数,需要在 `mmaction/models/losses/my_loss.py` 下进行实现。
```python
import torch
import torch.nn as nn
from ..builder import LOSSES
def my_loss(pred, target):
assert pred.size() == target.size() and target.numel() > 0
loss = torch.abs(pred - target)
return loss
@LOSSES.register_module()
class MyLoss(nn.Module):
def forward(self, pred, target):
loss = my_loss(pred, target)
return loss
```
之后,用户需要把它添加进 `mmaction/models/losses/__init__.py`
```python
from .my_loss import MyLoss, my_loss
```
为了使用它,需要修改 `loss_xxx` 域。由于 MyLoss 用户识别任务,可以把它作为边界框损失 `loss_bbox`
```python
loss_bbox=dict(type='MyLoss'))
```
### 添加新的学习率调节器(更新器)
构造学习率更新器(即 PyTorch 中的 "scheduler")的默认方法是修改配置,例如:
```python
...
lr_config = dict(policy='step', step=[20, 40])
...
```
[`train.py`](/mmaction/apis/train.py) 的 api 中,它会在以下位置注册用于学习率更新的钩子:
```python
...
runner.register_training_hooks(
cfg.lr_config,
optimizer_config,
cfg.checkpoint_config,
cfg.log_config,
cfg.get('momentum_config', None))
...
```
到目前位置,所有支持的更新器可参考 [mmcv](https://github.com/open-mmlab/mmcv/blob/master/mmcv/runner/hooks/lr_updater.py)
但如果用户想自定义学习率更新器,则需要遵循以下步骤:
1. 首先,在 `$MMAction2/mmaction/core/scheduler` 编写自定义的学习率更新钩子(LrUpdaterHook)。以下片段是自定义学习率更新器的例子,它使用基于特定比率的学习率 `lrs`,并在每个 `steps` 处进行学习率衰减。以下代码段是自定义学习率更新器的例子:
```python
# 在此注册
@HOOKS.register_module()
class RelativeStepLrUpdaterHook(LrUpdaterHook):
# 该类应当继承于 mmcv.LrUpdaterHook
def __init__(self, steps, lrs, **kwargs):
super().__init__(**kwargs)
assert len(steps) == (len(lrs))
self.steps = steps
self.lrs = lrs
def get_lr(self, runner, base_lr):
# 仅需要重写该函数
# 该函数在每个训练周期之前被调用, 并返回特定的学习率.
progress = runner.epoch if self.by_epoch else runner.iter
for i in range(len(self.steps)):
if progress < self.steps[i]:
return self.lrs[i]
```
2. 修改配置
在配置文件下替换原先的 `lr_config` 变量
```python
lr_config = dict(policy='RelativeStep', steps=[20, 40, 60], lrs=[0.1, 0.01, 0.001])
```
更多例子可参考 [mmcv](https://github.com/open-mmlab/mmcv/blob/master/mmcv/runner/hooks/lr_updater.py)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment