Skip to content
Snippets Groups Projects
Unverified Commit d2e4c6b6 authored by Yining Li's avatar Yining Li Committed by GitHub
Browse files

[Doc] Update docs of metrics and evaluator (#183)

* update docs of metrics and evaluator

* rename file

* resolve comments
parent 5f8f36e6
No related branches found
No related tags found
No related merge requests found
# 评测器(Evaluator)
# 评测指标(Metric)和评测器(Evaluator)
在模型验证和模型测试中,通常需要对模型精度做定量评测。在 MMEngine 中实现了[评测器](Todo:evaluator-doc-link)来完成这一功能。评测器可以根据模型的输入数据和预测结果,计算特定的评测指标(Metric)。评测器与数据集之间相互解耦,这使得用户可以任意组合所需的测试数据和评测器。如 [COCOEvaluator](Todo:coco-evaluator-doc-link) 可用于计算 COCO 数据集的 AP,AR 等评测指标,也可用于其他的目标检测数据集上。
在模型验证和模型测试中,通常需要对模型精度做定量评测。在 MMEngine 中实现了[评测指标](Todo:metric-doc-link)[评测器](Todo:evaluator-doc-linek)来完成这一功能。
**评测指标** 根据模型的输入数据和预测结果,完成特定指标下模型精度的计算。评测指标与数据集之间相互解耦,这使得用户可以任意组合所需的测试数据和评测指标。如 [COCOMetric](Todo:coco-metric-doc-link) 可用于计算 COCO 数据集的 AP,AR 等评测指标,也可用于其他的目标检测数据集上。
**评测器** 是评测指标的上层模块,通常包含一个或多个评测指标。评测器的作用是在模型评测时完成必要的数据格式转换,并调用评测指标计算模型精度。评测器通常由[执行器](TODO:runner-doc-link)或测试脚本构建,分别用于在线评测和离线评测。
用户通常不需要深入了解或手动修改评测器,因此该文档将重点介绍评测指标的原理和使用方式。
## 模型精度评测
使用评测器计算模型精度的过程如下图所示。
通常,模型精度评测的过程如下图所示。
测试数据通常会被划分为若干批次(batch)。通过一个循环,依次将每个批次的数据送入模型,得到对应的预测结果,并将预测结果连同模型的输入数据一起通过评测器`process()` 方法送入评测器。当循环结束后,调用评测`evaluate()` 方法,可计算得到对应的评测指标
**在线评测**测试数据通常会被划分为若干批次(batch)。通过一个循环,依次将每个批次的数据送入模型,得到对应的预测结果,并将测试数据和模型预测结果送入评测器。评测器会调用评测指标`process()` 方法对数据和预测结果进行处理。当循环结束后,评测器会调用评测指标`evaluate()` 方法,可计算得到对应指标的模型精度
在实际使用中,这些操作均由任务执行器完成。用户只需要在配置文件中选择要使用的评测器并配置相应参数即可
**离线评测**:与在线评测过程类似,区别是直接读取预先保存的模型预测结果来进行评测。评测器提供了 `offline_evaluate` 接口,用于在离线方式下调用评测指标来计算模型精度。为了避免同时处理大量数据导致内存溢出,离线评测时会将测试数据和预测结果分成若干个块(Chunk)进行处理,类似在线评测中的批次
<div align="center">
<img src="https://user-images.githubusercontent.com/15977946/154652635-f4bda588-9f94-462f-b68f-b900690e6215.png"/>
<img src="https://user-images.githubusercontent.com/15977946/163718224-20a4970a-e540-4a3a-8b01-bf0a604c6841.jpg" width="500"/>
</div>
## 在配置文件中配置评测指标
### 在配置文件中配置评测器
在配置文件中配置评测器时,需要指定评测器的类别、参数以及调用方式等。其中,调用方式通常针对模型验证阶段,包括调用评测器的间隔时间单位(epoch 或 iteration)、间隔时间、主要评测指标(即筛选最佳 checkpoint 所依据的指标)等。
例如,用户希望在模型验证时使用 COCO 评测器,每 10 epoch 评测一次,并以 AP 作为主要评测指标,对应的配置文件部分如下:
```python
validation_cfg=dict(
evaluator=dict(type='COCO'), # 使用 COCO 评测器,无参数
main_metric='AP', # 主要评测指标为 AP
interval=10, # 每 10 epoch 评测一次
by_epoch=True,
)
```
### 使用多个评测器
评测器支持组合使用。用户可以通过配置多个评测器,在模型验证或模型测试阶段同时计算多个评测指标。使用多个评测器时,只需要在配置文件里将所有评测器的配置写在一个列表里即可:
在配置文件中可以通过 `val_evaluator``test_evaluator` 2 个字段分别指定模型验证和测试阶段的评测指标。例如,用户在训练分类模型时,希望在模型验证阶段使用分类正确率和 F1 Score 两个评测指标,可以按以下方式配置:
```python
validation_cfg=dict(
evaluator=[
dict(type='Accuracy', top_k=1), # 使用分类正确率评测器
dict(type='F1Score') # 使用 F1_score 评测器
],
main_metric='accuracy',
interval=10,
by_epoch=True,
)
val_evaluator = [
dict(type='Accuracy', top_k=1), # 使用分类正确率评测指标
dict(type='F1Score') # 使用 F1_score 评测指标
]
```
使用多个评测器时,可能出现评测指标同名的情况。比如,在下面的例子中使用了 2 个 `COCOEvaluator` 分别对检测框和关键点的预测结果进行评测,它们的评测指标都包括 `AP``AR` 等。为了避免同名评测指标引发歧义,`Evaluator` 中支持通过 `prefix` 参数为评测指标名增加前缀。通常,一个 `Evaluator` 会有默认的前缀,用户也可以在配置文件中进行指定。
配置中的`val_evaluator` 会被用于构建一个包含多个评测指标的评测器,其中的每个字典对应于一个评测指标的类别和参数。
如果只使用单个评测指标,也可以省略掉配置中的列表,直接指定评测指标参数。例如,在模型测试阶段使用分类正确率评测指标,对应的配置如下:
```python
validation_cfg=dict(
evaluator=[
dict(type='COCO', iou_type='bbox'), # 使用默认前缀 `COCO`
dict(type='COCO', iou_type='keypoints', prefix='COCOKpts') # 自定义前缀 `COCOKpts`
],
# 指定使用前缀为 COCO 的 AP 为主要评测指标
# 在没有重名指标歧义的情况下,此处可以不写前缀,只写评测指标名
main_metric='COCO/AP',
interval=10,
by_epoch=True,
)
test_evaluator = dict(type='Accuracy', top_k=1)
```
## 增加自定义评测
## 增加自定义评测指标
在 OpenMMLab 的各个算法库中,已经实现了对应方向的常用评测。如 MMDetection 中提供了 COCO 评测,MMClassification 中提供了 Accuracy、F1Score 等评测等。
在 OpenMMLab 的各个算法库中,已经实现了对应方向的常用评测指标。如 MMDetection 中提供了 COCO 评测指标,MMClassification 中提供了 Accuracy、F1Score 等评测指标等。
用户也可以根据自身需求,增加自定义的评测。在实现自定义评测器时,用户需要继承 MMEngine 中提供的评测基类 [BaseEvaluator](Todo:baseevaluator-doc-link),并实现对应的抽象方法。
用户也可以增加自定义的评测指标。在实现自定义评测指标时,需要继承 MMEngine 中提供的评测指标基类 [BaseMetric](Todo:basemetric-doc-link),并实现对应的抽象方法。
### 评测基类
### 评测指标基类
评测基类 `BaseEvaluator` 是一个抽象类,具有以下 2 个抽象方法:
评测指标基类 `BaseMetric` 是一个抽象类,具有以下 2 个抽象方法:
- `process()`: 处理每个批次的测试数据和模型预测结果。处理结果应存放在 `self.results` 列表中,用于在处理完所有测试数据后计算评测指标。
- `compute_metrics()`: 计算评测指标,并将所评测指标存放在一个字典中返回。
其中,`compute_metrics()` 会在 `evaluate()` 方法中被调用;后者在计算评测指标前,会在分布式测试时收集和汇总不同 rank 的中间处理结果。`process()``evaluate()` 都会由任务执行器调用。因此,用户只需要在继承 `BaseEvaluator` 后实现 `process()``compute_metrics()` 方法即可。
其中,`compute_metrics()` 会在 `evaluate()` 方法中被调用;后者在计算评测指标前,会在分布式测试时收集和汇总不同 rank 的中间处理结果。
需要注意的是,`self.results` 中存放的具体类型取决于自定义评测器类的实现。例如,当测试样本或模型输出数据量较大(如语义分割、图像生成等任务),不宜全部存放在内存中时,可以在 `self.results` 中存放每个批次计算得到的指标,并在 `compute_metrics()` 中汇总;或将每个批次的中间结果存储到临时文件中,并在 `self.results` 中存放临时文件路径,最后由 `compute_metrics()` 从文件中读取数据并计算指标。
需要注意的是,`self.results` 中存放的具体类型取决于评测指标子类的实现。例如,当测试样本或模型输出数据量较大(如语义分割、图像生成等任务),不宜全部存放在内存中时,可以在 `self.results` 中存放每个批次计算得到的指标,并在 `compute_metrics()` 中汇总;或将每个批次的中间结果存储到临时文件中,并在 `self.results` 中存放临时文件路径,最后由 `compute_metrics()` 从文件中读取数据并计算指标。
### 自定义评测
### 自定义评测指标
我们以实现分类正确率(Classification Accuracy)评测为例,说明实现自定义评测的方法。
我们以实现分类正确率(Classification Accuracy)评测指标为例,说明自定义评测指标的方法。
首先,自定义评测器类应继承自 `BaseEvaluator`,并应加入注册器 `EVALUATORS` (关于注册器的说明请参考[相关文档](docs\zh_cn\tutorials\registry.md))。
首先,评测指标类应继承自 `BaseMetric`,并应加入注册器 `METRICS` (关于注册器的说明请参考[相关文档](docs\zh_cn\tutorials\registry.md))。
`process()` 方法有 2 个输入参数,分别是一个批次的测试数据样本 `data_batch` 和模型预测结果 `predictions`。我们从中分别取出样本类别标签和分类预测结果,并存放在 `self.results` 中。
`compute_metrics()` 方法有 1 个输入参数 `results`,里面存放了所有批次测试数据经过 `process()` 方法处理后得到的结果。从中取出样本类别标签和分类预测结果,即可计算得到分类正确率 `acc`。最终,将计算得到的评测指标以字典的形式返回。
此外,我们建议在子类中为类属性 `default_prefix` 赋值。如果在初始化参数(即 config 中)没有指定 `prefix`,则会自动使用 `default_prefix` 作为评测指标名的前缀。同时,应在 docstring 中说明该评测`default_prefix` 值以及所有的评测指标
此外,我们建议在子类中为类属性 `default_prefix` 赋值。如果在初始化参数(即 config 中)没有指定 `prefix`,则会自动使用 `default_prefix` 作为评测指标名的前缀。同时,应在 docstring 中说明该评测指标类`default_prefix` 值以及所有的返回指标名称
具体的实现如下:
......@@ -100,7 +75,7 @@ from mmengine.registry import METRICS
import numpy as np
@METRICS.register_module()
@METRICS.register_module() # 将 Accuracy 类注册到 METRICS 注册器
class Accuracy(BaseMetric):
""" Accuracy Evaluator
......@@ -110,9 +85,9 @@ class Accuracy(BaseMetric):
- accuracy (float): classification accuracy
"""
default_prefix = 'ACC'
default_prefix = 'ACC' # 设置 default_prefix
def process(self, data_batch: Sequence[Tuple[Any, dict]],
def process(self, data_batch: data_batch: Sequence[dict],
predictions: Sequence[dict]):
"""Process one batch of data and predictions. The processed
Results should be stored in `self.results`, which will be used
......@@ -128,7 +103,7 @@ class Accuracy(BaseMetric):
# 取出分类预测结果和类别标签
result = {
'pred': predictions['pred_label'],
'gt': data_batch['gt_label']
'gt': data_batch['data_sample']['gt_label']
}
# 将当前 batch 的结果存进 self.results
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment