From a3b8d4ea56968021c48447105483c863faac4f57 Mon Sep 17 00:00:00 2001 From: Tao Gong <gongtao950513@gmail.com> Date: Fri, 22 Apr 2022 13:51:57 +0800 Subject: [PATCH] Refactor docs of basedataset (#175) * refactor docs of basedataset * fix ci * fix comments * fix comments * fix comments * fix comments * fix comments * set default value of ann_file to '' * fix comments --- docs/zh_cn/tutorials/basedataset.md | 104 ++++++++++++------- mmengine/dataset/base_dataset.py | 36 +++---- tests/data/annotations/dummy_annotation.json | 4 +- tests/test_data/test_base_dataset.py | 5 + 4 files changed, 93 insertions(+), 56 deletions(-) diff --git a/docs/zh_cn/tutorials/basedataset.md b/docs/zh_cn/tutorials/basedataset.md index f0532c3e..d7c723a3 100644 --- a/docs/zh_cn/tutorials/basedataset.md +++ b/docs/zh_cn/tutorials/basedataset.md @@ -6,25 +6,25 @@ å› æ¤ **MMEngine** 实现了一个数æ®é›†åŸºç±»ï¼ˆBaseDataset)并定义了一些基本接å£ï¼Œä¸”基于这套接å£å®žçŽ°äº†ä¸€äº›æ•°æ®é›†åŒ…装(DatasetWrapper)。OpenMMLab 算法库ä¸çš„大部分数æ®é›†éƒ½ä¼šæ»¡è¶³è¿™å¥—æ•°æ®é›†åŸºç±»å®šä¹‰çš„接å£ï¼Œå¹¶ä½¿ç”¨ç»Ÿä¸€çš„æ•°æ®é›†åŒ…装。 -æ•°æ®é›†åŸºç±»çš„åŸºæœ¬åŠŸèƒ½æ˜¯åŠ è½½æ•°æ®é›†ä¿¡æ¯ï¼Œè¿™é‡Œæˆ‘们将数æ®é›†ä¿¡æ¯åˆ†æˆä¸¤ç±»ï¼Œä¸€ç§æ˜¯å…ƒä¿¡æ¯ (meta information),代表数æ®é›†è‡ªèº«ç›¸å…³çš„ä¿¡æ¯ï¼Œæœ‰æ—¶éœ€è¦è¢«æ¨¡åž‹æˆ–其他外部组件获å–,比如在图åƒåˆ†ç±»ä»»åŠ¡ä¸ï¼Œæ•°æ®é›†çš„元信æ¯ä¸€èˆ¬åŒ…å«ç±»åˆ«ä¿¡æ¯ `classes`ï¼Œå› ä¸ºåˆ†ç±»æ¨¡åž‹ `model` 一般需è¦è®°å½•æ•°æ®é›†çš„类别信æ¯ï¼›å¦ä¸€ç§ä¸ºæ•°æ®ä¿¡æ¯ (data information),在数æ®ä¿¡æ¯ä¸ï¼Œå®šä¹‰äº†å…·ä½“æ ·æœ¬çš„æ–‡ä»¶è·¯å¾„ã€å¯¹åº”æ ‡ç¾ç‰çš„ä¿¡æ¯ã€‚除æ¤ä¹‹å¤–,数æ®é›†åŸºç±»çš„å¦ä¸€ä¸ªåŠŸèƒ½ä¸ºå°†æ•°æ®é€å…¥æ•°æ®æµæ°´çº¿ï¼ˆdata pipeline)ä¸ï¼Œè¿›è¡Œæ•°æ®é¢„处ç†ã€‚ +æ•°æ®é›†åŸºç±»çš„åŸºæœ¬åŠŸèƒ½æ˜¯åŠ è½½æ•°æ®é›†ä¿¡æ¯ï¼Œè¿™é‡Œæˆ‘们将数æ®é›†ä¿¡æ¯åˆ†æˆä¸¤ç±»ï¼Œä¸€ç§æ˜¯å…ƒä¿¡æ¯ (meta information),代表数æ®é›†è‡ªèº«ç›¸å…³çš„ä¿¡æ¯ï¼Œæœ‰æ—¶éœ€è¦è¢«æ¨¡åž‹æˆ–其他外部组件获å–,比如在图åƒåˆ†ç±»ä»»åŠ¡ä¸ï¼Œæ•°æ®é›†çš„元信æ¯ä¸€èˆ¬åŒ…å«ç±»åˆ«ä¿¡æ¯ `classes`ï¼Œå› ä¸ºåˆ†ç±»æ¨¡åž‹ `model` 一般需è¦è®°å½•æ•°æ®é›†çš„类别信æ¯ï¼›å¦ä¸€ç§ä¸ºæ•°æ®ä¿¡æ¯ (data information),在数æ®ä¿¡æ¯ä¸ï¼Œå®šä¹‰äº†å…·ä½“æ ·æœ¬çš„æ–‡ä»¶è·¯å¾„ã€å¯¹åº”æ ‡ç¾ç‰çš„ä¿¡æ¯ã€‚除æ¤ä¹‹å¤–,数æ®é›†åŸºç±»çš„å¦ä¸€ä¸ªåŠŸèƒ½ä¸ºä¸æ–地将数æ®é€å…¥æ•°æ®æµæ°´çº¿ï¼ˆdata pipeline)ä¸ï¼Œè¿›è¡Œæ•°æ®é¢„处ç†ã€‚ ### æ•°æ®æ ‡æ³¨æ–‡ä»¶è§„范 -为了统一ä¸åŒä»»åŠ¡çš„æ•°æ®é›†æŽ¥å£ï¼Œä¾¿äºŽå¤šä»»åŠ¡çš„算法模型è®ç»ƒï¼ŒOpenMMLab 制定了 **OpenMMLab 2.0 æ•°æ®é›†æ ¼å¼è§„范**, æ•°æ®é›†æ ‡æ³¨æ–‡ä»¶éœ€ç¬¦åˆè¯¥è§„范,数æ®é›†åŸºç±»åŸºäºŽè¯¥è§„范去读å–与解æžæ•°æ®æ ‡æ³¨æ–‡ä»¶ã€‚如果用户æ供的数æ®æ ‡æ³¨æ–‡ä»¶ä¸ç¬¦åˆè§„å®šæ ¼å¼ï¼Œç”¨æˆ·åº”è¯¥å°†å…¶è½¬åŒ–ä¸ºè§„å®šæ ¼å¼æ‰èƒ½ä½¿ç”¨ OpenMMLab 的算法库基于该数æ®æ ‡æ³¨æ–‡ä»¶è¿›è¡Œç®—法è®ç»ƒå’Œæµ‹è¯•ã€‚ +为了统一ä¸åŒä»»åŠ¡çš„æ•°æ®é›†æŽ¥å£ï¼Œä¾¿äºŽå¤šä»»åŠ¡çš„算法模型è®ç»ƒï¼ŒOpenMMLab 制定了 **OpenMMLab 2.0 æ•°æ®é›†æ ¼å¼è§„范**, æ•°æ®é›†æ ‡æ³¨æ–‡ä»¶éœ€ç¬¦åˆè¯¥è§„范,数æ®é›†åŸºç±»åŸºäºŽè¯¥è§„范去读å–与解æžæ•°æ®æ ‡æ³¨æ–‡ä»¶ã€‚如果用户æ供的数æ®æ ‡æ³¨æ–‡ä»¶ä¸ç¬¦åˆè§„å®šæ ¼å¼ï¼Œç”¨æˆ·å¯ä»¥é€‰æ‹©å°†å…¶è½¬åŒ–ä¸ºè§„å®šæ ¼å¼ï¼Œå¹¶ä½¿ç”¨ OpenMMLab 的算法库基于该数æ®æ ‡æ³¨æ–‡ä»¶è¿›è¡Œç®—法è®ç»ƒå’Œæµ‹è¯•ã€‚ -OpenMMLab 2.0 æ•°æ®é›†æ ¼å¼è§„èŒƒè§„å®šï¼Œæ ‡æ³¨æ–‡ä»¶å¿…é¡»ä¸º `json` 或 `yaml`,`yml` 或 `pickle`,`pkl` æ ¼å¼ï¼›æ ‡æ³¨æ–‡ä»¶ä¸å˜å‚¨çš„å—å…¸å¿…é¡»åŒ…å« `metadata` å’Œ `data_infos` 两个å—æ®µã€‚å…¶ä¸ `metadata` 是一个å—典,里é¢åŒ…å«æ•°æ®é›†çš„元信æ¯ï¼›`data_infos` 是一个列表,列表ä¸æ¯ä¸ªå…ƒç´ 是一个å—典,该å—典定义了一个原始数æ®ï¼ˆraw data),æ¯ä¸ªåŽŸå§‹æ•°æ®åŒ…å«ä¸€ä¸ªæˆ–若干个è®ç»ƒ/æµ‹è¯•æ ·æœ¬ã€‚ +OpenMMLab 2.0 æ•°æ®é›†æ ¼å¼è§„èŒƒè§„å®šï¼Œæ ‡æ³¨æ–‡ä»¶å¿…é¡»ä¸º `json` 或 `yaml`,`yml` 或 `pickle`,`pkl` æ ¼å¼ï¼›æ ‡æ³¨æ–‡ä»¶ä¸å˜å‚¨çš„å—å…¸å¿…é¡»åŒ…å« `metainfo` å’Œ `data_list` 两个å—æ®µã€‚å…¶ä¸ `metainfo` 是一个å—典,里é¢åŒ…å«æ•°æ®é›†çš„元信æ¯ï¼›`data_list` 是一个列表,列表ä¸æ¯ä¸ªå…ƒç´ 是一个å—典,该å—典定义了一个原始数æ®ï¼ˆraw data),æ¯ä¸ªåŽŸå§‹æ•°æ®åŒ…å«ä¸€ä¸ªæˆ–若干个è®ç»ƒ/æµ‹è¯•æ ·æœ¬ã€‚ 以下是一个 JSON æ ‡æ³¨æ–‡ä»¶çš„ä¾‹å(该例åä¸æ¯ä¸ªåŽŸå§‹æ•°æ®åªåŒ…å«ä¸€ä¸ªè®ç»ƒ/æµ‹è¯•æ ·æœ¬ï¼‰: ```json { - 'metadata': + 'metainfo': { 'classes': ('cat', 'dog'), ... }, - 'data_infos': + 'data_list': [ { 'img_path': "xxx/xxx_0.jpg", @@ -55,45 +55,59 @@ data ### æ•°æ®é›†åŸºç±»çš„åˆå§‹åŒ–æµç¨‹ -æ•°æ®é›†åŸºç±»çš„åˆå§‹åŒ–æµç¨‹å¦‚下: +æ•°æ®é›†åŸºç±»çš„åˆå§‹åŒ–æµç¨‹å¦‚下图所示: -1. 获å–æ•°æ®é›†çš„元信æ¯ï¼Œå…ƒä¿¡æ¯æœ‰ä¸‰ç§æ¥æºï¼Œä¼˜å…ˆçº§ä»Žé«˜åˆ°ä½Žä¸ºï¼š + -- `__init__()` 方法ä¸ç”¨æˆ·ä¼ 入的 `meta` å—å…¸ï¼›æ”¹åŠ¨é¢‘çŽ‡æœ€é«˜ï¼Œå› ä¸ºç”¨æˆ·å¯ä»¥åœ¨å®žä¾‹åŒ–æ•°æ®é›†æ—¶ï¼Œä¼ 入该å‚æ•°ï¼› +1. `load metainfo`:获å–æ•°æ®é›†çš„元信æ¯ï¼Œå…ƒä¿¡æ¯æœ‰ä¸‰ç§æ¥æºï¼Œä¼˜å…ˆçº§ä»Žé«˜åˆ°ä½Žä¸ºï¼š -- 类属性 `BaseDataset.META` å—典;改动频率ä¸ç‰ï¼Œå› 为用户å¯ä»¥æ”¹åŠ¨è‡ªå®šä¹‰æ•°æ®é›†ç±»ä¸çš„类属性 `BaseDataset.META`ï¼› +- `__init__()` 方法ä¸ç”¨æˆ·ä¼ 入的 `metainfo` å—å…¸ï¼›æ”¹åŠ¨é¢‘çŽ‡æœ€é«˜ï¼Œå› ä¸ºç”¨æˆ·å¯ä»¥åœ¨å®žä¾‹åŒ–æ•°æ®é›†æ—¶ï¼Œä¼ 入该å‚æ•°ï¼› -- æ ‡æ³¨æ–‡ä»¶ä¸åŒ…å«çš„ `metadata` å—å…¸ï¼›æ”¹åŠ¨é¢‘çŽ‡æœ€ä½Žï¼Œå› ä¸ºæ ‡æ³¨æ–‡ä»¶ä¸€èˆ¬ä¸åšæ”¹åŠ¨ã€‚ +- 类属性 `BaseDataset.METAINFO` å—典;改动频率ä¸ç‰ï¼Œå› 为用户å¯ä»¥æ”¹åŠ¨è‡ªå®šä¹‰æ•°æ®é›†ç±»ä¸çš„类属性 `BaseDataset.METAINFO`ï¼› + +- æ ‡æ³¨æ–‡ä»¶ä¸åŒ…å«çš„ `metainfo` å—å…¸ï¼›æ”¹åŠ¨é¢‘çŽ‡æœ€ä½Žï¼Œå› ä¸ºæ ‡æ³¨æ–‡ä»¶ä¸€èˆ¬ä¸åšæ”¹åŠ¨ã€‚ 如果三ç§æ¥æºä¸æœ‰ç›¸åŒçš„å—段,优先级最高的æ¥æºå†³å®šè¯¥å—段的值; -2. 构建数æ®æµæ°´çº¿ï¼ˆdata pipeline),用于数æ®é¢„处ç†ä¸Žæ•°æ®å‡†å¤‡ï¼› +2. `join path`:处ç†æ•°æ®ä¸Žæ ‡æ³¨æ–‡ä»¶çš„路径; + +3. `build pipeline`:构建数æ®æµæ°´çº¿ï¼ˆdata pipeline),用于数æ®é¢„处ç†ä¸Žæ•°æ®å‡†å¤‡ï¼› -3. 读å–与解æžæ»¡è¶³ OpenMMLab 2.0 æ•°æ®é›†æ ¼å¼è§„èŒƒçš„æ ‡æ³¨æ–‡ä»¶ï¼Œè¯¥æ¥éª¤ä¸ä¼šæœ‰ `parse_annotations()` 方法,该方法负责解æžæ ‡æ³¨æ–‡ä»¶é‡Œçš„æ¯ä¸ªåŽŸå§‹æ•°æ®ï¼› +4. `full init`:完全åˆå§‹åŒ–æ•°æ®é›†ç±»ï¼Œè¯¥æ¥éª¤ä¸»è¦åŒ…å«ä»¥ä¸‹æ“作: -4. è¿‡æ»¤æ— ç”¨æ•°æ®ï¼Œæ¯”如ä¸åŒ…å«æ ‡æ³¨çš„æ ·æœ¬ç‰ï¼› +- `load data list`:读å–与解æžæ»¡è¶³ OpenMMLab 2.0 æ•°æ®é›†æ ¼å¼è§„èŒƒçš„æ ‡æ³¨æ–‡ä»¶ï¼Œè¯¥æ¥éª¤ä¸ä¼šè°ƒç”¨ `parse_data_info()` 方法,该方法负责解æžæ ‡æ³¨æ–‡ä»¶é‡Œçš„æ¯ä¸ªåŽŸå§‹æ•°æ®ï¼› -5. é‡‡æ ·æ•°æ®ï¼Œæ¯”如åªå–å‰ 10 ä¸ªæ ·æœ¬å‚与è®ç»ƒ/测试; +- `filter data` (å¯é€‰)ï¼šæ ¹æ® `filter_cfg` è¿‡æ»¤æ— ç”¨æ•°æ®ï¼Œæ¯”如ä¸åŒ…å«æ ‡æ³¨çš„æ ·æœ¬ç‰ï¼›é»˜è®¤ä¸åšè¿‡æ»¤æ“作,下游åç±»å¯ä»¥æŒ‰è‡ªèº«æ‰€éœ€å¯¹å…¶è¿›è¡Œé‡å†™ï¼› -6. åºåˆ—åŒ–å…¨éƒ¨æ ·æœ¬ï¼Œä»¥è¾¾åˆ°èŠ‚çœå†…å˜çš„效果,详情请å‚考[节çœå†…å˜](#节çœå†…å˜)。 +- `get subset` (å¯é€‰)ï¼šæ ¹æ®ç»™å®šçš„ç´¢å¼•æˆ–æ•´æ•°å€¼é‡‡æ ·æ•°æ®ï¼Œæ¯”如åªå–å‰ 10 ä¸ªæ ·æœ¬å‚与è®ç»ƒ/测试;默认ä¸é‡‡æ ·æ•°æ®ï¼Œå³ä½¿ç”¨å…¨éƒ¨æ•°æ®æ ·æœ¬ï¼› -æ•°æ®é›†åŸºç±»ä¸åŒ…å«çš„ `parse_annotations()` æ–¹æ³•ç”¨äºŽå°†æ ‡æ³¨æ–‡ä»¶é‡Œçš„ä¸€ä¸ªåŽŸå§‹æ•°æ®å¤„ç†æˆä¸€ä¸ªæˆ–若干个è®ç»ƒ/æµ‹è¯•æ ·æœ¬çš„æ–¹æ³•ã€‚å› æ¤å¯¹äºŽè‡ªå®šä¹‰æ•°æ®é›†ç±»ï¼Œç”¨æˆ·éœ€è¦å®žçŽ° `parse_annotations()` 方法。 +- `serialize data` (å¯é€‰):åºåˆ—åŒ–å…¨éƒ¨æ ·æœ¬ï¼Œä»¥è¾¾åˆ°èŠ‚çœå†…å˜çš„效果,详情请å‚考[节çœå†…å˜](#节çœå†…å˜);默认æ“作为åºåˆ—åŒ–å…¨éƒ¨æ ·æœ¬ã€‚ + +æ•°æ®é›†åŸºç±»ä¸åŒ…å«çš„ `parse_data_info()` æ–¹æ³•ç”¨äºŽå°†æ ‡æ³¨æ–‡ä»¶é‡Œçš„ä¸€ä¸ªåŽŸå§‹æ•°æ®å¤„ç†æˆä¸€ä¸ªæˆ–若干个è®ç»ƒ/æµ‹è¯•æ ·æœ¬çš„æ–¹æ³•ã€‚å› æ¤å¯¹äºŽè‡ªå®šä¹‰æ•°æ®é›†ç±»ï¼Œç”¨æˆ·éœ€è¦å®žçŽ° `parse_data_info()` 方法。 ### æ•°æ®é›†åŸºç±»æä¾›çš„æŽ¥å£ ä¸Ž `torch.utils.data.Dataset` 类似,数æ®é›†åˆå§‹åŒ–åŽï¼Œæ”¯æŒ `__getitem__` 方法,用æ¥ç´¢å¼•æ•°æ®ï¼Œä»¥åŠ `__len__` æ“作获å–æ•°æ®é›†å¤§å°ï¼Œé™¤æ¤ä¹‹å¤–,OpenMMLab çš„æ•°æ®é›†åŸºç±»ä¸»è¦æ供了以下接å£æ¥è®¿é—®å…·ä½“ä¿¡æ¯ï¼š -- `meta` 返回元信æ¯ï¼Œè¿”回值为å—å…¸ +- `metainfo`:返回元信æ¯ï¼Œè¿”回值为å—å…¸ + +- `get_data_info(idx)`:返回指定 `idx` çš„æ ·æœ¬å…¨é‡ä¿¡æ¯ï¼Œè¿”回值为å—å…¸ -- `get_data_info(idx)` 返回指定 `idx` çš„æ ·æœ¬å…¨é‡ä¿¡æ¯ï¼Œè¿”回值为å—å…¸ +- `__getitem__(idx)`:返回指定 `idx` çš„æ ·æœ¬ç»è¿‡ pipeline 之åŽçš„结果(也就是é€å…¥æ¨¡åž‹çš„æ•°æ®ï¼‰ï¼Œè¿”回值为å—å…¸ -- `__getitem__(idx)` :返回指定 `idx` çš„æ ·æœ¬ç»è¿‡ pipeline 之åŽçš„结果(也就是é€å…¥æ¨¡åž‹çš„æ•°æ®ï¼‰ï¼Œè¿”回值为å—å…¸ +- `__len__()`:返回数æ®é›†é•¿åº¦ï¼Œè¿”回值为整数型 -- `__len__()` 返回数æ®é›†é•¿åº¦ï¼Œè¿”回值为整数型 +- `get_subset_(indices)`ï¼šæ ¹æ® `indices` 以 inplace çš„æ–¹å¼**修改原数æ®é›†ç±»**。如果 `indices` 为 `int`,则原数æ®é›†ç±»åªåŒ…å«å‰è‹¥å¹²ä¸ªæ•°æ®æ ·æœ¬ï¼›å¦‚æžœ `indices` 为 `Sequence[int]`,则原数æ®é›†ç±»åŒ…å«æ ¹æ® `Sequence[int]` 指定的数æ®æ ·æœ¬ã€‚ + +- `get_subset(indices)`ï¼šæ ¹æ® `indices` 以**éž** inplace çš„æ–¹å¼**返回åæ•°æ®é›†ç±»**,å³é‡æ–°å¤åˆ¶ä¸€ä»½åæ•°æ®é›†ã€‚如果 `indices` 为 `int`,则返回的åæ•°æ®é›†ç±»åªåŒ…å«å‰è‹¥å¹²ä¸ªæ•°æ®æ ·æœ¬ï¼›å¦‚æžœ `indices` 为 `Sequence[int]`,则返回的åæ•°æ®é›†ç±»åŒ…å«æ ¹æ® `Sequence[int]` 指定的数æ®æ ·æœ¬ã€‚ ## 使用数æ®é›†åŸºç±»è‡ªå®šä¹‰æ•°æ®é›†ç±» -在了解了数æ®é›†åŸºç±»çš„åˆå§‹åŒ–æµç¨‹ä¸Žæ供的接å£ä¹‹åŽï¼Œå°±å¯ä»¥åŸºäºŽæ•°æ®é›†åŸºç±»è‡ªå®šä¹‰æ•°æ®é›†ç±»ï¼Œå¦‚上所述,对于满足 OpenMMLab 2.0 æ•°æ®é›†æ ¼å¼è§„èŒƒçš„æ ‡æ³¨æ–‡ä»¶ï¼Œç”¨æˆ·å¯ä»¥é‡è½½ `parse_annotations()`æ¥åŠ è½½æ ‡ç¾ã€‚以下是一个使用数æ®é›†åŸºç±»æ¥å®žçŽ°æŸä¸€å…·ä½“æ•°æ®é›†çš„例å。 +在了解了数æ®é›†åŸºç±»çš„åˆå§‹åŒ–æµç¨‹ä¸Žæ供的接å£ä¹‹åŽï¼Œå°±å¯ä»¥åŸºäºŽæ•°æ®é›†åŸºç±»è‡ªå®šä¹‰æ•°æ®é›†ç±»ã€‚ + +### 对于满足 OpenMMLab 2.0 æ•°æ®é›†æ ¼å¼è§„èŒƒçš„æ ‡æ³¨æ–‡ä»¶ + +如上所述,对于满足 OpenMMLab 2.0 æ•°æ®é›†æ ¼å¼è§„èŒƒçš„æ ‡æ³¨æ–‡ä»¶ï¼Œç”¨æˆ·å¯ä»¥é‡è½½ `parse_data_info()` æ¥åŠ è½½æ ‡ç¾ã€‚以下是一个使用数æ®é›†åŸºç±»æ¥å®žçŽ°æŸä¸€å…·ä½“æ•°æ®é›†çš„例å。 ```python import os.path as osp @@ -103,13 +117,13 @@ from mmengine.data import BaseDataset class ToyDataset(BaseDataset): - # 以上é¢æ ‡æ³¨æ–‡ä»¶ä¸ºä¾‹ï¼Œåœ¨è¿™é‡Œ raw_data_info 代表 `data_infos` 对应列表里的æŸä¸ªå—典: + # 以上é¢æ ‡æ³¨æ–‡ä»¶ä¸ºä¾‹ï¼Œåœ¨è¿™é‡Œ raw_data_info 代表 `data_list` 对应列表里的æŸä¸ªå—典: # { # 'img_path': "xxx/xxx_0.jpg", # 'img_label': 0, # ... # } - def parse_annotations(self, raw_data_info): + def parse_data_info(self, raw_data_info): data_info = raw_data_info img_prefix = self.data_prefix.get('img', None) if img_prefix is not None: @@ -119,7 +133,7 @@ class ToyDataset(BaseDataset): ``` -### 使用自定义数æ®é›†ç±» +#### 使用自定义数æ®é›†ç±» 在定义了数æ®é›†ç±»åŽï¼Œå°±å¯ä»¥é€šè¿‡å¦‚下é…置实例化 `ToyDataset`: @@ -155,13 +169,23 @@ len(toy_dataset) toy_dataset[0] # dict(img=xxx, label=0) + +# `get_subset` 接å£ä¸å¯¹åŽŸæ•°æ®é›†ç±»åšä¿®æ”¹ï¼Œå³å®Œå…¨å¤åˆ¶ä¸€ä»½æ–°çš„ +sub_toy_dataset = toy_dataset.get_subset(1) +len(toy_dataset), len(sub_toy_dataset) +# 2, 1 + +# `get_subset_` 接å£ä¼šå¯¹åŽŸæ•°æ®é›†ç±»åšä¿®æ”¹ï¼Œå³ inplace çš„æ–¹å¼ +toy_dataset.get_subset_(1) +len(toy_dataset) +# 1 ``` ç»è¿‡ä»¥ä¸Šæ¥éª¤ï¼Œå¯ä»¥äº†è§£åŸºäºŽæ•°æ®é›†åŸºç±»å¦‚何自定义新的数æ®é›†ç±»ï¼Œä»¥åŠå¦‚何使用自定义数æ®é›†ç±»ã€‚ -### 自定义视频的数æ®é›†ç±» +#### 自定义视频的数æ®é›†ç±» -在上é¢çš„例åä¸ï¼Œæ ‡æ³¨æ–‡ä»¶çš„æ¯ä¸ªåŽŸå§‹æ•°æ®åªåŒ…å«ä¸€ä¸ªè®ç»ƒ/æµ‹è¯•æ ·æœ¬ï¼ˆé€šå¸¸æ˜¯å›¾åƒé¢†åŸŸï¼‰ã€‚如果æ¯ä¸ªåŽŸå§‹æ•°æ®åŒ…å«è‹¥å¹²ä¸ªè®ç»ƒ/æµ‹è¯•æ ·æœ¬ï¼ˆé€šå¸¸æ˜¯è§†é¢‘é¢†åŸŸï¼‰ï¼Œåˆ™åªéœ€ä¿è¯ `parse_annotations()` 的返回值为 `list[dict]` å³å¯ï¼š +在上é¢çš„例åä¸ï¼Œæ ‡æ³¨æ–‡ä»¶çš„æ¯ä¸ªåŽŸå§‹æ•°æ®åªåŒ…å«ä¸€ä¸ªè®ç»ƒ/æµ‹è¯•æ ·æœ¬ï¼ˆé€šå¸¸æ˜¯å›¾åƒé¢†åŸŸï¼‰ã€‚如果æ¯ä¸ªåŽŸå§‹æ•°æ®åŒ…å«è‹¥å¹²ä¸ªè®ç»ƒ/æµ‹è¯•æ ·æœ¬ï¼ˆé€šå¸¸æ˜¯è§†é¢‘é¢†åŸŸï¼‰ï¼Œåˆ™åªéœ€ä¿è¯ `parse_data_info()` 的返回值为 `list[dict]` å³å¯ï¼š ```python from mmengine.data import BaseDataset @@ -170,8 +194,8 @@ from mmengine.data import BaseDataset class ToyVideoDataset(BaseDataset): # raw_data_info ä»ä¸ºä¸€ä¸ªå—典,但它包å«äº†å¤šä¸ªæ ·æœ¬ - def parse_annotations(self, raw_data_info): - data_infos = [] + def parse_data_info(self, raw_data_info): + data_list = [] ... @@ -181,14 +205,22 @@ class ToyVideoDataset(BaseDataset): ... - data_infos.append(data_info) + data_list.append(data_info) - return data_infos + return data_list ``` `ToyVideoDataset` 使用方法与 `ToyDataset` 类似,在æ¤ä¸åšèµ˜è¿°ã€‚ +### 对于ä¸æ»¡è¶³ OpenMMLab 2.0 æ•°æ®é›†æ ¼å¼è§„èŒƒçš„æ ‡æ³¨æ–‡ä»¶ + +对于ä¸æ»¡è¶³ OpenMMLab 2.0 æ•°æ®é›†æ ¼å¼è§„èŒƒçš„æ ‡æ³¨æ–‡ä»¶ï¼Œæœ‰ä¸¤ç§æ–¹å¼æ¥ä½¿ç”¨æ•°æ®é›†åŸºç±»ï¼š + +1. å°†ä¸æ»¡è¶³è§„èŒƒçš„æ ‡æ³¨æ–‡ä»¶è½¬æ¢æˆæ»¡è¶³è§„èŒƒçš„æ ‡æ³¨æ–‡ä»¶ï¼Œå†é€šè¿‡ä¸Šè¿°æ–¹å¼ä½¿ç”¨æ•°æ®é›†åŸºç±»ã€‚ + +2. 实现一个新的数æ®é›†ç±»ï¼Œç»§æ‰¿è‡ªæ•°æ®é›†åŸºç±»ï¼Œå¹¶ä¸”é‡è½½æ•°æ®é›†åŸºç±»çš„ `load_data_list(self, ann_file):` 函数,处ç†ä¸æ»¡è¶³è§„èŒƒçš„æ ‡æ³¨æ–‡ä»¶ï¼Œå¹¶ä¿è¯è¿”回值为 `list[dict]`,其ä¸æ¯ä¸ª `dict` 代表一个数æ®æ ·æœ¬ã€‚ + ## æ•°æ®é›†åŸºç±»çš„其它特性 æ•°æ®é›†åŸºç±»è¿˜åŒ…å«ä»¥ä¸‹ç‰¹æ€§ï¼š @@ -213,9 +245,9 @@ toy_dataset = ToyDataset( lazy_init=True) ``` -当 `lazy_init=True` 时,`ToyDataset` çš„åˆå§‹åŒ–方法åªæ‰§è¡Œäº†[æ•°æ®é›†åŸºç±»çš„åˆå§‹åŒ–æµç¨‹](#æ•°æ®é›†åŸºç±»çš„åˆå§‹åŒ–æµç¨‹)ä¸çš„ 1ã€2 æ¥éª¤ï¼Œæ¤æ—¶ `toy_dataset` 并未被完全åˆå§‹åŒ–ï¼Œå› ä¸º `toy_dataset` 并ä¸ä¼šè¯»å–与解æžæ ‡æ³¨æ–‡ä»¶ï¼Œåªä¼šè®¾ç½®æ•°æ®é›†ç±»çš„元信æ¯ï¼ˆ`meta`)。 +当 `lazy_init=True` 时,`ToyDataset` çš„åˆå§‹åŒ–方法åªæ‰§è¡Œäº†[æ•°æ®é›†åŸºç±»çš„åˆå§‹åŒ–æµç¨‹](#æ•°æ®é›†åŸºç±»çš„åˆå§‹åŒ–æµç¨‹)ä¸çš„ 1ã€2ã€3 æ¥éª¤ï¼Œæ¤æ—¶ `toy_dataset` 并未被完全åˆå§‹åŒ–ï¼Œå› ä¸º `toy_dataset` 并ä¸ä¼šè¯»å–与解æžæ ‡æ³¨æ–‡ä»¶ï¼Œåªä¼šè®¾ç½®æ•°æ®é›†ç±»çš„元信æ¯ï¼ˆ`metainfo`)。 -自然的,如果之åŽéœ€è¦è®¿é—®å…·ä½“çš„æ•°æ®ä¿¡æ¯ï¼Œå¯ä»¥æ‰‹åŠ¨è°ƒç”¨ `toy_dataset.full_init()` 接å£æ¥æ‰§è¡Œå®Œæ•´çš„åˆå§‹åŒ–过程,在这个过程ä¸æ•°æ®æ ‡æ³¨æ–‡ä»¶å°†è¢«è¯»å–与解æžã€‚调用 `get_data_info(idx)`, `__len__()`, `__getitem__()` 接å£ä¹Ÿä¼šè‡ªåŠ¨åœ°è°ƒç”¨ `full_init()` 接å£æ¥æ‰§è¡Œå®Œæ•´çš„åˆå§‹åŒ–过程(仅在第一次调用时,之åŽè°ƒç”¨ä¸ä¼šé‡å¤åœ°è°ƒç”¨ `full_init()` 接å£ï¼‰ï¼š +自然的,如果之åŽéœ€è¦è®¿é—®å…·ä½“çš„æ•°æ®ä¿¡æ¯ï¼Œå¯ä»¥æ‰‹åŠ¨è°ƒç”¨ `toy_dataset.full_init()` 接å£æ¥æ‰§è¡Œå®Œæ•´çš„åˆå§‹åŒ–过程,在这个过程ä¸æ•°æ®æ ‡æ³¨æ–‡ä»¶å°†è¢«è¯»å–与解æžã€‚调用 `get_data_info(idx)`, `__len__()`, `__getitem__(idx)`,`get_subset_(indices)`, `get_subset(indices)` 接å£ä¹Ÿä¼šè‡ªåŠ¨åœ°è°ƒç”¨ `full_init()` 接å£æ¥æ‰§è¡Œå®Œæ•´çš„åˆå§‹åŒ–过程(仅在第一次调用时,之åŽè°ƒç”¨ä¸ä¼šé‡å¤åœ°è°ƒç”¨ `full_init()` 接å£ï¼‰ï¼š ```python # 完整åˆå§‹åŒ– @@ -234,9 +266,9 @@ toy_dataset[0] # dict(img=xxx, label=0) ### 节çœå†…å˜ -在具体的读å–æ•°æ®è¿‡ç¨‹ä¸ï¼Œæ•°æ®åŠ 载器(dataloader)通常会起多个 worker æ¥é¢„å–æ•°æ®ï¼Œå¤šä¸ª worker 都拥有完整的数æ®é›†ç±»å¤‡ä»½ï¼Œå› æ¤å†…å˜ä¸ä¼šå˜åœ¨å¤šä»½ç›¸åŒçš„ `data_infos`,为了节çœè¿™éƒ¨åˆ†å†…å˜æ¶ˆè€—,数æ®é›†åŸºç±»å¯ä»¥æå‰å°† `data_infos` åºåˆ—化å˜å…¥å†…å˜ä¸ï¼Œä½¿å¾—多个 worker å¯ä»¥å…±äº«åŒä¸€ä»½ `data_infos`,以达到节çœå†…å˜çš„目的。 +在具体的读å–æ•°æ®è¿‡ç¨‹ä¸ï¼Œæ•°æ®åŠ 载器(dataloader)通常会起多个 worker æ¥é¢„å–æ•°æ®ï¼Œå¤šä¸ª worker 都拥有完整的数æ®é›†ç±»å¤‡ä»½ï¼Œå› æ¤å†…å˜ä¸ä¼šå˜åœ¨å¤šä»½ç›¸åŒçš„ `data_list`,为了节çœè¿™éƒ¨åˆ†å†…å˜æ¶ˆè€—,数æ®é›†åŸºç±»å¯ä»¥æå‰å°† `data_list` åºåˆ—化å˜å…¥å†…å˜ä¸ï¼Œä½¿å¾—多个 worker å¯ä»¥å…±äº«åŒä¸€ä»½ `data_list`,以达到节çœå†…å˜çš„目的。 -æ•°æ®é›†åŸºç±»é»˜è®¤æ˜¯å°† `data_infos` åºåˆ—化å˜å…¥å†…å˜ï¼Œä¹Ÿå¯ä»¥é€šè¿‡ `serialize_data` å˜é‡ï¼ˆé»˜è®¤ä¸º `True`)æ¥æŽ§åˆ¶æ˜¯å¦æå‰å°† `data_infos` åºåˆ—化å˜å…¥å†…å˜ä¸ï¼š +æ•°æ®é›†åŸºç±»é»˜è®¤æ˜¯å°† `data_list` åºåˆ—化å˜å…¥å†…å˜ï¼Œä¹Ÿå¯ä»¥é€šè¿‡ `serialize_data` å˜é‡ï¼ˆé»˜è®¤ä¸º `True`)æ¥æŽ§åˆ¶æ˜¯å¦æå‰å°† `data_list` åºåˆ—化å˜å…¥å†…å˜ä¸ï¼š ```python pipeline = [ @@ -254,7 +286,7 @@ toy_dataset = ToyDataset( serialize_data=False) ``` -上é¢ä¾‹åä¸ä¼šæå‰å°† `data_infos` åºåˆ—化å˜å…¥å†…å˜ä¸ï¼Œå› æ¤ä¸å»ºè®®åœ¨ä½¿ç”¨æ•°æ®åŠ 载器开多个 worker åŠ è½½æ•°æ®çš„情况下,使用这ç§æ–¹å¼å®žä¾‹åŒ–æ•°æ®é›†ç±»ã€‚ +上é¢ä¾‹åä¸ä¼šæå‰å°† `data_list` åºåˆ—化å˜å…¥å†…å˜ä¸ï¼Œå› æ¤ä¸å»ºè®®åœ¨ä½¿ç”¨æ•°æ®åŠ 载器开多个 worker åŠ è½½æ•°æ®çš„情况下,使用这ç§æ–¹å¼å®žä¾‹åŒ–æ•°æ®é›†ç±»ã€‚ ## æ•°æ®é›†åŸºç±»åŒ…装 @@ -329,7 +361,7 @@ from mmengine.data import BaseDataset, ClassBalancedDataset class ToyDataset(BaseDataset): - def parse_annotations(self, raw_data_info): + def parse_data_info(self, raw_data_info): data_info = raw_data_info img_prefix = self.data_prefix.get('img', None) if img_prefix is not None: diff --git a/mmengine/dataset/base_dataset.py b/mmengine/dataset/base_dataset.py index 17f707d3..d8f0f3d5 100644 --- a/mmengine/dataset/base_dataset.py +++ b/mmengine/dataset/base_dataset.py @@ -118,12 +118,12 @@ class BaseDataset(Dataset): .. code-block:: none { - "metadata": + "metainfo": { "dataset_type": "test_dataset", "task_name": "test_task" }, - "data_infos": + "data_list": [ { "img_path": "test_img.jpg", @@ -149,7 +149,7 @@ class BaseDataset(Dataset): } Args: - ann_file (str): Annotation file path. + ann_file (str): Annotation file path. Defaults to ''. metainfo (dict, optional): Meta information for dataset, such as class information. Defaults to None. data_root (str, optional): The root directory for ``data_prefix`` and @@ -208,7 +208,7 @@ class BaseDataset(Dataset): _fully_initialized: bool = False def __init__(self, - ann_file: str, + ann_file: str = '', metainfo: Optional[dict] = None, data_root: Optional[str] = None, data_prefix: dict = dict(img=None, ann=None), @@ -232,7 +232,7 @@ class BaseDataset(Dataset): self.data_bytes: np.ndarray # Set meta information. - self._metainfo = self._get_meta_info(copy.deepcopy(metainfo)) + self._metainfo = self._load_metainfo(copy.deepcopy(metainfo)) # Join paths. if self.data_root is not None: @@ -429,21 +429,21 @@ class BaseDataset(Dataset): if not isinstance(annotations, dict): raise TypeError(f'The annotations loaded from annotation file ' f'should be a dict, but got {type(annotations)}!') - if 'data_infos' not in annotations or 'metadata' not in annotations: - raise ValueError('Annotation must have data_infos and metadata ' + if 'data_list' not in annotations or 'metainfo' not in annotations: + raise ValueError('Annotation must have data_list and metainfo ' 'keys') - meta_data = annotations['metadata'] - raw_data_infos = annotations['data_infos'] + metainfo = annotations['metainfo'] + raw_data_list = annotations['data_list'] # Meta information load from annotation file will not influence the # existed meta information load from `BaseDataset.METAINFO` and # `metainfo` arguments defined in constructor. - for k, v in meta_data.items(): + for k, v in metainfo.items(): self._metainfo.setdefault(k, v) # load and parse data_infos. data_list = [] - for raw_data_info in raw_data_infos: + for raw_data_info in raw_data_list: # parse raw data information to target format data_info = self.parse_data_info(raw_data_info) if isinstance(data_info, dict): @@ -467,11 +467,11 @@ class BaseDataset(Dataset): return data_list @classmethod - def _get_meta_info(cls, in_metainfo: dict = None) -> dict: + def _load_metainfo(cls, metainfo: dict = None) -> dict: """Collect meta information from the dictionary of meta. Args: - in_metainfo (dict): Meta information dict. If ``in_metainfo`` + metainfo (dict): Meta information dict. If ``metainfo`` contains existed filename, it will be parsed by ``list_from_file``. @@ -480,15 +480,15 @@ class BaseDataset(Dataset): """ # `cls.METAINFO` will be overwritten by in_meta cls_metainfo = copy.deepcopy(cls.METAINFO) - if in_metainfo is None: + if metainfo is None: return cls_metainfo - if not isinstance(in_metainfo, dict): + if not isinstance(metainfo, dict): raise TypeError( - f'in_metainfo should be a dict, but got {type(in_metainfo)}') + f'metainfo should be a dict, but got {type(metainfo)}') - for k, v in in_metainfo.items(): + for k, v in metainfo.items(): if isinstance(v, str) and osp.isfile(v): - # if filename in in_metainfo, this key will be further parsed. + # if filename in metainfo, this key will be further parsed. # nested filename will be ignored. cls_metainfo[k] = list_from_file(v) else: diff --git a/tests/data/annotations/dummy_annotation.json b/tests/data/annotations/dummy_annotation.json index 5fac907e..87d6f51a 100644 --- a/tests/data/annotations/dummy_annotation.json +++ b/tests/data/annotations/dummy_annotation.json @@ -1,11 +1,11 @@ { - "metadata": + "metainfo": { "dataset_type": "test_dataset", "task_name": "test_task", "empty_list": [] }, - "data_infos": + "data_list": [ { "img_path": "test_img.jpg", diff --git a/tests/test_data/test_base_dataset.py b/tests/test_data/test_base_dataset.py index 3dbbd919..2488144f 100644 --- a/tests/test_data/test_base_dataset.py +++ b/tests/test_data/test_base_dataset.py @@ -87,6 +87,11 @@ class TestBaseDataset: data_root=osp.join(osp.dirname(__file__), '../data/'), data_prefix=dict(img='imgs'), ann_file='annotations/not_existed_annotation.json') + # Use the default value of ann_file, i.e., '' + with pytest.raises(FileNotFoundError): + self.dataset_type( + data_root=osp.join(osp.dirname(__file__), '../data/'), + data_prefix=dict(img='imgs')) # test the instantiation of self.base_dataset when the ann_file is # wrong -- GitLab