-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Doc] Translate some advanced guides (#2499)
- Loading branch information
Showing
4 changed files
with
434 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
# 自定义数据集 | ||
|
||
在本教程中,我们将介绍如何通过在线转换来自定义你的数据集。 | ||
|
||
- [自定义数据集](#自定义数据集) | ||
- [MMAction2 数据集概述](#mmaction2-数据集概述) | ||
- [定制新的数据集](#定制新的数据集) | ||
- [为 PoseDataset 自定义关键点格式](#为-posedataset-自定义关键点格式) | ||
|
||
## MMAction2 数据集概述 | ||
|
||
MMAction2 提供了任务特定的 `Dataset` 类,例如用于动作识别的 `VideoDataset`/`RawframeDataset`,用于时空动作检测的 `AVADataset`,用于基于骨骼的动作识别的`PoseDataset`。这些任务特定的数据集只需要实现 `load_data_list(self)` 来从注释文件生成数据列表。剩下的函数由超类(即 `BaseActionDataset` 和 `BaseDataset`)自动处理。下表显示了模块的继承关系和主要方法。 | ||
|
||
| 类名 | 类方法 | | ||
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| `MMAction2::VideoDataset` | `load_data_list(self)` <br> 从注释文件中构建数据列表。 | | ||
| `MMAction2::BaseActionDataset` | `get_data_info(self, idx)` <br> 给定 `idx`,从数据列表中返回相应的数据样本。 | | ||
| `MMEngine::BaseDataset` | `__getitem__(self, idx)` <br> 给定 `idx`,调用 `get_data_info` 获取数据样本,然后调用 `pipeline` 在 `train_pipeline` 或 `val_pipeline` 中执行数据变换和增强。 | | ||
|
||
## 定制新的数据集类 | ||
|
||
大多数情况下,把你的数据集离线转换成指定格式是首选方法,但 MMAction2 提供了一个方便的过程来创建一个定制的 `Dataset` 类。如前所述,任务特定的数据集只需要实现 `load_data_list(self)` 来从注释文件生成数据列表。请注意,`data_list` 中的元素是包含后续流程中必要字段的 `dict`。 | ||
|
||
以 `VideoDataset` 为例,`train_pipeline`/`val_pipeline` 在 `DecordInit` 中需要 `'filename'`,在 `PackActionInputs` 中需要 `'label'`。因此,`data_list` 中的数据样本必须包含2个字段:`'filename'`和`'label'`。 | ||
请参考[定制数据流水线](customize_pipeline.md)以获取有关 `pipeline` 的更多详细信息。 | ||
|
||
``` | ||
data_list.append(dict(filename=filename, label=label)) | ||
``` | ||
|
||
`AVADataset` 会更加复杂,`data_list` 中的数据样本包含有关视频数据的几个字段。此外,它重写了 `get_data_info(self, idx)` 以转换在时空动作检测数据流水线中需要用的字段。 | ||
|
||
```python | ||
|
||
class AVADataset(BaseActionDataset): | ||
... | ||
|
||
def load_data_list(self) -> List[dict]: | ||
... | ||
video_info = dict( | ||
frame_dir=frame_dir, | ||
video_id=video_id, | ||
timestamp=int(timestamp), | ||
img_key=img_key, | ||
shot_info=shot_info, | ||
fps=self._FPS, | ||
ann=ann) | ||
data_list.append(video_info) | ||
data_list.append(video_info) | ||
return data_list | ||
|
||
def get_data_info(self, idx: int) -> dict: | ||
... | ||
ann = data_info.pop('ann') | ||
data_info['gt_bboxes'] = ann['gt_bboxes'] | ||
data_info['gt_labels'] = ann['gt_labels'] | ||
data_info['entity_ids'] = ann['entity_ids'] | ||
return data_info | ||
``` | ||
|
||
## 为 PoseDataset 自定义关键点格式 | ||
|
||
MMAction2 目前支持三种关键点格式:`coco`,`nturgb+d` 和 `openpose`。如果你使用其中一种格式,你可以简单地在以下模块中指定相应的格式: | ||
|
||
对于图卷积网络,如 AAGCN,STGCN,... | ||
|
||
- `pipeline`:在 `JointToBone` 中的参数 `dataset`。 | ||
- `backbone`:在图卷积网络中的参数 `graph_cfg`。 | ||
|
||
对于 PoseC3D: | ||
|
||
- `pipeline`:在 `Flip` 中,根据关键点的对称关系指定 `left_kp` 和 `right_kp`。 | ||
- `pipeline`:在 `GeneratePoseTarget` 中,如果 `with_limb` 为 `True`,指定`skeletons`,`left_limb`,`right_limb`,如果 `with_kp` 为 `True`,指定`left_kp` 和 `right_kp`。 | ||
|
||
如果使用自定义关键点格式,需要在 `backbone` 和 `pipeline` 中都包含一个新的图布局。这个布局将定义关键点及其连接关系。 | ||
|
||
以 `coco` 数据集为例,我们在 `Graph` 中定义了一个名为 `coco` 的布局。这个布局的 `inward` 连接包括所有节点连接,每个**向心**连接由一个节点元组组成。`coco`的额外设置包括将节点数指定为 `17`,将 `node 0` 设为中心节点。 | ||
|
||
```python | ||
|
||
self.num_node = 17 | ||
self.inward = [(15, 13), (13, 11), (16, 14), (14, 12), (11, 5), | ||
(12, 6), (9, 7), (7, 5), (10, 8), (8, 6), (5, 0), | ||
(6, 0), (1, 0), (3, 1), (2, 0), (4, 2)] | ||
self.center = 0 | ||
``` | ||
|
||
同样,我们在 `JointToBone` 中定义了 `pairs`,添加了一个 bone `(0, 0)` 以使 bone 的数量对齐到 joint。coco数据集的 `pairs` 如下所示,`JointToBone` 中的 `pairs` 的顺序无关紧要。 | ||
|
||
```python | ||
|
||
self.pairs = ((0, 0), (1, 0), (2, 0), (3, 1), (4, 2), | ||
(5, 0), (6, 0), (7, 5), (8, 6), (9, 7), | ||
(10, 8), (11, 0), (12, 0), (13, 11), (14, 12), | ||
(15, 13), (16, 14)) | ||
``` | ||
|
||
要使用你的自定义关键点格式,只需定义上述设置为你的图结构,并在你的配置文件中指定它们,如下所示。在这个例子中,我们将使用 `STGCN`,其中 `n` 表示类别的数量,`custom_dataset` 在 `Graph` 和 `JointToBone` 中定义。 | ||
|
||
```python | ||
model = dict( | ||
type='RecognizerGCN', | ||
backbone=dict( | ||
type='STGCN', graph_cfg=dict(layout='custom_dataset', mode='stgcn_spatial')), | ||
cls_head=dict(type='GCNHead', num_classes=n, in_channels=256)) | ||
|
||
train_pipeline = [ | ||
... | ||
dict(type='GenSkeFeat', dataset='custom_dataset'), | ||
...] | ||
|
||
val_pipeline = [ | ||
... | ||
dict(type='GenSkeFeat', dataset='custom_dataset'), | ||
...] | ||
|
||
test_pipeline = [ | ||
... | ||
dict(type='GenSkeFeat', dataset='custom_dataset'), | ||
...] | ||
|
||
``` | ||
|
||
只需简单地指定自定义布局,你就可以使用你自己的关键点格式进行训练和测试了。通过这种方式,MMAction2 为用户提供了很大的灵活性,允许用户自定义他们的数据集和关键点格式,以满足他们特定的需求。 | ||
|
||
以上就是关于如何自定义你的数据集的一些方法。希望这个教程能帮助你理解MMAction2的数据集结构,并教给你如何根据自己的需求创建新的数据集。虽然这可能需要一些编程知识,但是 MMAction2 试图使这个过程尽可能简单。通过了解这些基本概念,你将能够更好地控制你的数据,从而改进你的模型性能。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
# 自定义日志 | ||
|
||
MMAction2 在运行过程中会产生大量的日志,如损失、迭代时间、学习率等。在这一部分,我们将向你介绍如何输出自定义日志。有关日志系统的更多详细信息,请参考 [MMEngine 教程](https://mmengine.readthedocs.io/zh_CN/latest/advanced_tutorials/logging.html)。 | ||
|
||
- [自定义日志](#自定义日志) | ||
- [灵活的日志系统](#灵活的日志系统) | ||
- [定制日志](#定制日志) | ||
- [导出调试日志](#导出调试日志) | ||
|
||
## 灵活的日志系统 | ||
|
||
默认情况下,MMAction2 的日志系统由 [default_runtime](/configs/_base_/default_runtime.py) 中的 `LogProcessor` 配置: | ||
|
||
```python | ||
log_processor = dict(type='LogProcessor', window_size=20, by_epoch=True) | ||
``` | ||
|
||
默认情况下,`LogProcessor` 捕获 `model.forward` 返回的所有以 `loss` 开头的字段。例如,在以下模型中,`loss1` 和 `loss2` 将在没有任何额外配置的情况下自动记录到日志。 | ||
|
||
```python | ||
from mmengine.model import BaseModel | ||
|
||
class ToyModel(BaseModel): | ||
def __init__(self) -> None: | ||
super().__init__() | ||
self.linear = nn.Linear(1, 1) | ||
|
||
def forward(self, img, label, mode): | ||
feat = self.linear(img) | ||
loss1 = (feat - label).pow(2) | ||
loss2 = (feat - label).abs() | ||
return dict(loss1=loss1, loss2=loss2) | ||
``` | ||
|
||
输出日志遵循以下格式: | ||
|
||
``` | ||
08/21 02:58:41 - mmengine - INFO - Epoch(train) [1][10/25] lr: 1.0000e-02 eta: 0:00:00 time: 0.0019 data_time: 0.0004 loss1: 0.8381 loss2: 0.9007 loss: 1.7388 | ||
08/21 02:58:41 - mmengine - INFO - Epoch(train) [1][20/25] lr: 1.0000e-02 eta: 0:00:00 time: 0.0029 data_time: 0.0010 loss1: 0.1978 loss2: 0.4312 loss: 0.6290 | ||
``` | ||
|
||
`LogProcessor` 将按以下格式输出日志: | ||
|
||
- 日志的前缀: | ||
- epoch 模式(`by_epoch=True`):`Epoch(train) [{current_epoch}/{current_iteration}]/{dataloader_length}` | ||
- iteration 模式(`by_epoch=False`):`Iter(train) [{current_iteration}/{max_iteration}]` | ||
- 学习率 (`lr`):最后一次迭代的学习率。 | ||
- 时间: | ||
- `time`:过去 `window_size` 次迭代的推理平均时间。 | ||
- `data_time`:过去 `window_size` 次迭代的数据加载平均时间。 | ||
- `eta`:完成训练的预计到达时间。 | ||
- 损失:过去 `window_size` 次迭代中模型输出的平均损失。 | ||
|
||
```{warning} | ||
默认情况下,log_processor 输出基于 epoch 的日志(`by_epoch=True`)。要得到与 `train_cfg` 匹配的预期日志,我们应在 `train_cfg` 和 `log_processor` 中设置相同的 `by_epoch` 值。 | ||
``` | ||
|
||
根据以上规则,代码片段将每20次迭代计算 loss1 和 loss2 的平均值。更多类型的统计方法,请参考 [mmengine.runner.LogProcessor](mmengine.runner.LogProcessor)。 | ||
|
||
## 定制日志 | ||
|
||
日志系统不仅可以记录 `loss`,`lr` 等,还可以收集和输出自定义日志。例如,如果我们想要统计中间损失: | ||
|
||
`ToyModel` 在 forward 中计算 `loss_tmp`,但不将其保存到返回字典中。 | ||
|
||
```python | ||
from mmengine.logging import MessageHub | ||
|
||
class ToyModel(BaseModel): | ||
|
||
def __init__(self) -> None: | ||
super().__init__() | ||
self.linear = nn.Linear(1, 1) | ||
|
||
def forward(self, img, label, mode): | ||
feat = self.linear(img) | ||
loss_tmp = (feat - label).abs() | ||
loss = loss_tmp.pow(2) | ||
|
||
message_hub = MessageHub.get_current_instance() | ||
# 在消息中心更新中间的 `loss_tmp` | ||
message_hub.update_scalar('train/loss_tmp', loss_tmp.sum()) | ||
return dict(loss=loss) | ||
``` | ||
|
||
将 `loss_tmp` 添加到配置中: | ||
|
||
```python | ||
log_processor = dict( | ||
type='LogProcessor', | ||
window_size=20, | ||
by_epoch=True, | ||
custom_cfg=[ | ||
# 使用平均值统计 loss_tmp | ||
dict( | ||
data_src='loss_tmp', | ||
window_size=20, | ||
method_name='mean') | ||
]) | ||
``` | ||
|
||
`loss_tmp` 将被添加到输出日志中: | ||
|
||
``` | ||
08/21 03:40:31 - mmengine - INFO - Epoch(train) [1][10/25] lr: 1.0000e-02 eta: 0:00:00 time: 0.0026 data_time: 0.0008 loss_tmp: 0.0097 loss: 0.0000 | ||
08/21 03:40:31 - mmengine - INFO - Epoch(train) [1][20/25] lr: 1.0000e-02 eta: 0:00:00 time: 0.0028 data_time: 0.0013 loss_tmp: 0.0065 loss: 0.0000 | ||
``` | ||
|
||
## 导出调试日志 | ||
|
||
要将调试日志导出到 `work_dir`,你可以在配置文件中设置日志级别如下: | ||
|
||
``` | ||
log_level='DEBUG' | ||
``` | ||
|
||
``` | ||
08/21 18:16:22 - mmengine - DEBUG - Get class `LocalVisBackend` from "vis_backend" registry in "mmengine" | ||
08/21 18:16:22 - mmengine - DEBUG - An `LocalVisBackend` instance is built from registry, its implementation can be found in mmengine.visualization.vis_backend | ||
08/21 18:16:22 - mmengine - DEBUG - Get class `RuntimeInfoHook` from "hook" registry in "mmengine" | ||
08/21 18:16:22 - mmengine - DEBUG - An `RuntimeInfoHook` instance is built from registry, its implementation can be found in mmengine.hooks.runtime_info_hook | ||
08/21 18:16:22 - mmengine - DEBUG - Get class `IterTimerHook` from "hook" registry in "mmengine" | ||
... | ||
``` | ||
|
||
此外,如果你正在使用共享存储训练你的模型,那么在 `debug` 模式下,不同排名的日志将被保存。日志的层级结构如下: | ||
|
||
```text | ||
./tmp | ||
├── tmp.log | ||
├── tmp_rank1.log | ||
├── tmp_rank2.log | ||
├── tmp_rank3.log | ||
├── tmp_rank4.log | ||
├── tmp_rank5.log | ||
├── tmp_rank6.log | ||
└── tmp_rank7.log | ||
... | ||
└── tmp_rank63.log | ||
``` | ||
|
||
在具有独立存储的多台机器上的日志: | ||
|
||
```text | ||
# 设备:0: | ||
work_dir/ | ||
└── exp_name_logs | ||
├── exp_name.log | ||
├── exp_name_rank1.log | ||
├── exp_name_rank2.log | ||
├── exp_name_rank3.log | ||
... | ||
└── exp_name_rank7.log | ||
# 设备:7: | ||
work_dir/ | ||
└── exp_name_logs | ||
├── exp_name_rank56.log | ||
├── exp_name_rank57.log | ||
├── exp_name_rank58.log | ||
... | ||
└── exp_name_rank63.log | ||
``` |
Oops, something went wrong.