File size: 6,046 Bytes
d3dbf03
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# 自定义日志

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

```