From 92de63eed7f866306002a25bfa7308befb4b264a Mon Sep 17 00:00:00 2001 From: Yining Li <liyining0712@gmail.com> Date: Fri, 25 Feb 2022 14:43:16 +0800 Subject: [PATCH] [Docs] Add evaluator docs (#33) * add evaluator docs * resolve comments * resolve comments --- docs/zh_cn/tutorials/evaluator.md | 141 ++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 docs/zh_cn/tutorials/evaluator.md diff --git a/docs/zh_cn/tutorials/evaluator.md b/docs/zh_cn/tutorials/evaluator.md new file mode 100644 index 00000000..abcd6fb9 --- /dev/null +++ b/docs/zh_cn/tutorials/evaluator.md @@ -0,0 +1,141 @@ +# 评测器(Evaluator) + +在模型验è¯å’Œæ¨¡åž‹æµ‹è¯•ä¸ï¼Œé€šå¸¸éœ€è¦å¯¹æ¨¡åž‹ç²¾åº¦åšå®šé‡è¯„测。在 MMEngine ä¸å®žçŽ°äº†[评测器](Todo:evaluator-doc-link)æ¥å®Œæˆè¿™ä¸€åŠŸèƒ½ã€‚评测器å¯ä»¥æ ¹æ®æ¨¡åž‹çš„输入数æ®å’Œé¢„æµ‹ç»“æžœï¼Œè®¡ç®—ç‰¹å®šçš„è¯„æµ‹æŒ‡æ ‡ï¼ˆMetric)。评测器与数æ®é›†ä¹‹é—´ç›¸äº’解耦,这使得用户å¯ä»¥ä»»æ„组åˆæ‰€éœ€çš„测试数æ®å’Œè¯„测器。如 [COCOEvaluator](Todo:coco-evaluator-doc-link) å¯ç”¨äºŽè®¡ç®— COCO æ•°æ®é›†çš„ AP,AR ç‰è¯„æµ‹æŒ‡æ ‡ï¼Œä¹Ÿå¯ç”¨äºŽå…¶ä»–çš„ç›®æ ‡æ£€æµ‹æ•°æ®é›†ä¸Šã€‚ + +## 模型精度评测 + +使用评测器计算模型精度的过程如下图所示。 + +测试数æ®é€šå¸¸ä¼šè¢«åˆ’分为若干批次(batch)。通过一个循环,ä¾æ¬¡å°†æ¯ä¸ªæ‰¹æ¬¡çš„æ•°æ®é€å…¥æ¨¡åž‹ï¼Œå¾—到对应的预测结果,并将预测结果连åŒæ¨¡åž‹çš„输入数æ®ä¸€èµ·é€šè¿‡è¯„测器的 `process()` 方法é€å…¥è¯„测器。当循环结æŸåŽï¼Œå†è°ƒç”¨è¯„测器的 `evaluate()` 方法,å³å¯è®¡ç®—å¾—åˆ°å¯¹åº”çš„è¯„æµ‹æŒ‡æ ‡ã€‚ + +在实际使用ä¸ï¼Œè¿™äº›æ“作å‡ç”±ä»»åŠ¡æ‰§è¡Œå™¨å®Œæˆã€‚用户åªéœ€è¦åœ¨é…置文件ä¸é€‰æ‹©è¦ä½¿ç”¨çš„评测器并é…置相应å‚æ•°å³å¯ã€‚ + +<div align="center"> + <img src="https://user-images.githubusercontent.com/15977946/154652635-f4bda588-9f94-462f-b68f-b900690e6215.png"/> +</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, +) +``` + +### 使用多个评测器 + +评测器支æŒç»„åˆä½¿ç”¨ã€‚用户å¯ä»¥é€šè¿‡é…置多个评测器,在模型验è¯æˆ–模型测试阶段åŒæ—¶è®¡ç®—å¤šä¸ªè¯„æµ‹æŒ‡æ ‡ã€‚ä½¿ç”¨å¤šä¸ªè¯„æµ‹å™¨æ—¶ï¼Œåªéœ€è¦åœ¨é…置文件里将所有评测器的é…置写在一个列表里å³å¯ï¼š + +```python +validation_cfg=dict( + evaluator=[ + dict(type='accuracy', top_k=1), # 使用分类æ£ç¡®çŽ‡è¯„测器 + dict(type='f1_score') # 使用 F1_score 评测器 + ], + main_metric='accuracy' + interval=10, + by_epoch=True, +) +``` + +在使用多个评测器时,å¯èƒ½ä¼šå‡ºçŽ°è¯„æµ‹æŒ‡æ ‡åŒå的情况。比如,在下é¢çš„例åä¸ä½¿ç”¨äº† 2 个å‚æ•°ä¸åŒçš„分类æ£ç¡®çŽ‡è¯„æµ‹å™¨ï¼Œå®ƒä»¬å¯¹åº”çš„è¯„æµ‹æŒ‡æ ‡éƒ½æ˜¯ accuracy。æ¤æ—¶ï¼Œä¸ºäº†é¿å…æ§ä¹‰ï¼Œéœ€è¦ç»™è¯„测器设置 `prefix` å‚数。评测器的 `prefix` ä¼šè‡ªåŠ¨æ·»åŠ åœ¨è¯„æµ‹æŒ‡æ ‡å称的开头,从而使åŒåçš„è¯„æµ‹æŒ‡æ ‡å¯ä»¥åŒºåˆ†ã€‚ + +```python +validation_cfg=dict( + evaluator=[ + dict(type='accuracy', top_k=1, prefix='top1'), + dict(type='accuracy', top_k=5, prefix='top5') + ], + main_metric='top1_accuracy', # å‰ç¼€ 'top1' è¢«è‡ªåŠ¨æ·»åŠ è¿›æŒ‡æ ‡å称ä¸ï¼Œç”¨ä»¥åŒºåˆ†åŒåæŒ‡æ ‡ + interval=10, + by_epoch=True, +) +``` + +## å¢žåŠ è‡ªå®šä¹‰è¯„æµ‹å™¨ + +在 OpenMMLab çš„å„个算法库ä¸ï¼Œå·²ç»å®žçŽ°äº†å¯¹åº”æ–¹å‘的常用评测器。如 MMDetection ä¸æ供了 COCO 评测器,MMClassification ä¸æ供了 accuracyã€f1_score ç‰è¯„测器ç‰ã€‚ + +用户也å¯ä»¥æ ¹æ®è‡ªèº«éœ€æ±‚ï¼Œå¢žåŠ è‡ªå®šä¹‰çš„è¯„æµ‹å™¨ã€‚åœ¨å®žçŽ°è‡ªå®šä¹‰è¯„æµ‹å™¨æ—¶ï¼Œç”¨æˆ·éœ€è¦ç»§æ‰¿ MMEngine ä¸æ供的评测器基类 [BaseEvaluator](Todo:baseevaluator-doc-link),并实现对应的抽象方法。 + +### 评测器基类 + +评测器基类 `BaseEvaluator` 是一个抽象类,具有以下 2 个抽象方法: + +- `process()`: 处ç†æ¯ä¸ªæ‰¹æ¬¡çš„测试数æ®å’Œæ¨¡åž‹é¢„测结果。处ç†ç»“果应å˜æ”¾åœ¨ `self.results` 列表ä¸ï¼Œç”¨äºŽåœ¨å¤„ç†å®Œæ‰€æœ‰æµ‹è¯•æ•°æ®åŽè®¡ç®—è¯„æµ‹æŒ‡æ ‡ã€‚ +- `compute_metrics()`: è®¡ç®—è¯„æµ‹æŒ‡æ ‡ï¼Œå¹¶å°†æ‰€è¯„æµ‹æŒ‡æ ‡å˜æ”¾åœ¨ä¸€ä¸ªå—å…¸ä¸è¿”回。 + +å…¶ä¸ï¼Œ`compute_metrics()` 会在 `evaluate()` 方法ä¸è¢«è°ƒç”¨ï¼›åŽè€…åœ¨è®¡ç®—è¯„æµ‹æŒ‡æ ‡å‰ï¼Œä¼šåœ¨åˆ†å¸ƒå¼æµ‹è¯•æ—¶æ”¶é›†å’Œæ±‡æ€»ä¸åŒ rank çš„ä¸é—´å¤„ç†ç»“果。而 `process()` å’Œ `evaluate()` éƒ½ä¼šç”±ä»»åŠ¡æ‰§è¡Œå™¨è°ƒç”¨ã€‚å› æ¤ï¼Œç”¨æˆ·åªéœ€è¦åœ¨ç»§æ‰¿ `BaseEvaluator` åŽå®žçŽ° `process()` å’Œ `compute_metrics()` 方法å³å¯ã€‚ + +需è¦æ³¨æ„的是,`self.results` ä¸å˜æ”¾çš„具体类型å–å†³äºŽè‡ªå®šä¹‰è¯„æµ‹å™¨ç±»çš„å®žçŽ°ã€‚ä¾‹å¦‚ï¼Œå½“æµ‹è¯•æ ·æœ¬æˆ–æ¨¡åž‹è¾“å‡ºæ•°æ®é‡è¾ƒå¤§ï¼ˆå¦‚è¯ä¹‰åˆ†å‰²ã€å›¾åƒç”Ÿæˆç‰ä»»åŠ¡ï¼‰ï¼Œä¸å®œå…¨éƒ¨å˜æ”¾åœ¨å†…å˜ä¸æ—¶ï¼Œå¯ä»¥åœ¨ `self.results` ä¸å˜æ”¾æ¯ä¸ªæ‰¹æ¬¡è®¡ç®—å¾—åˆ°çš„æŒ‡æ ‡ï¼Œå¹¶åœ¨ `compute_metrics()` ä¸æ±‡æ€»ï¼›æˆ–å°†æ¯ä¸ªæ‰¹æ¬¡çš„ä¸é—´ç»“æžœå˜å‚¨åˆ°ä¸´æ—¶æ–‡ä»¶ä¸ï¼Œå¹¶åœ¨ `self.results` ä¸å˜æ”¾ä¸´æ—¶æ–‡ä»¶è·¯å¾„,最åŽç”± `compute_metrics()` 从文件ä¸è¯»å–æ•°æ®å¹¶è®¡ç®—æŒ‡æ ‡ã€‚ + +### 自定义评测器类 + +我们以实现分类æ£ç¡®çŽ‡ï¼ˆClassification Accuracy)评测器为例,说明实现自定义评测器的方法。 + +首先,自定义评测器类应继承自 `BaseEvaluator`ï¼Œå¹¶åº”åŠ å…¥æ³¨å†Œå™¨ `EVALUATORS` (关于注册器的说明请å‚考[相关文档](docs\zh_cn\tutorials\registry.md))。 + + `process()` 方法有 2 个输入å‚数,分别是测试数æ®æ ·æœ¬`data_samples`和模型预测结果 `predictions`。我们从ä¸åˆ†åˆ«å–å‡ºæ ·æœ¬ç±»åˆ«æ ‡ç¾å’Œåˆ†ç±»é¢„测结果,并å˜æ”¾åœ¨ `self.results` ä¸ã€‚ + +`compute_metrics()`方法有 1 个输入å‚æ•° `results`,里é¢å˜æ”¾äº†æ‰€æœ‰æ‰¹æ¬¡æµ‹è¯•æ•°æ®ç»è¿‡ `process()` 方法处ç†åŽå¾—到的结果。从ä¸å–å‡ºæ ·æœ¬ç±»åˆ«æ ‡ç¾å’Œåˆ†ç±»é¢„测结果,å³å¯è®¡ç®—得到分类æ£ç¡®çŽ‡ `acc`ã€‚æœ€ç»ˆï¼Œå°†è®¡ç®—å¾—åˆ°çš„è¯„æµ‹æŒ‡æ ‡ä»¥å—典的形å¼è¿”回。 + +具体的实现如下: + +```python +from mmengine.evaluator import BaseEvaluator +from mmengine.registry import EVALUATORS + +import numpy as np + +@EVALUATORS.register_module() +class AccuracyEvaluator(BaseEvaluator): + + def process(self, data_samples: Dict, predictions: Dict): + """Process one batch of data and predictions. The processed + Results should be stored in `self.results`, which will be used + to computed the metrics when all batches have been processed. + + Args: + data_samples (dict): The data samples from the dataset. + predictions (dict): The output of the model. + """ + + # å–å‡ºåˆ†ç±»é¢„æµ‹ç»“æžœå’Œç±»åˆ«æ ‡ç¾ + result = dict( + 'pred': predictions.pred_label, + 'gt': data_samples.gt_label + ) + + # å°†å½“å‰ batch 的结果å˜è¿› self.results + self.results.append(result) + + def compute_metrics(self, results: List): + """Compute the metrics from processed results. + + Args: + results (dict): The processed results of each batch. + + Returns: + Dict: The computed metrics. The keys are the names of the metrics, + and the values are corresponding results. + """ + + # æ±‡æ€»æ‰€æœ‰æ ·æœ¬çš„åˆ†ç±»é¢„æµ‹ç»“æžœå’Œç±»åˆ«æ ‡ç¾ + preds = np.concatenate([res['pred'] for res in results]) + gts = np.concatenate([res['gt'] for res in results]) + + # 计算分类æ£ç¡®çŽ‡ + acc = (preds == gts).sum() / preds.size + + # è¿”å›žè¯„æµ‹æŒ‡æ ‡ç»“æžœ + return {'accuracy': acc} + +``` -- GitLab