Skip to content

Commit 7d3b237

Browse files
authored
Boost segmentation import performance (#1261)
<!-- Contributing guide: https://github.com/openvinotoolkit/datumaro/blob/develop/CONTRIBUTING.md --> ### Summary When analyzing the import performance for `cityscapes` and `kaggle_image_mask`, I have checked that the most bottleneck is `np.unique` for parsing the unique class indices within each mask. Analysis before PR: ![image](https://github.com/openvinotoolkit/datumaro/assets/89109581/3b75783b-c01b-4a99-8319-385abb430ead) Analysis after PR: ![image](https://github.com/openvinotoolkit/datumaro/assets/89109581/6fd0e946-a765-414d-918c-89c798f7eb32) Instead of parsing unique class indices within a mask, I have changed to use all class indices in a dataset. As a result, the performance is 5 times faster. <!-- Resolves #111 and #222. Depends on #1000 (for series of dependent commits). This PR introduces this capability to make the project better in this and that. - Added this feature - Removed that feature - Fixed the problem #1234 --> ### How to test <!-- Describe the testing procedure for reviewers, if changes are not fully covered by unit tests or manual testing can be complicated. --> ### Checklist <!-- Put an 'x' in all the boxes that apply --> - [x] I have added unit tests to cover my changes.​ - [ ] I have added integration tests to cover my changes.​ - [x] I have added the description of my changes into [CHANGELOG](https://github.com/openvinotoolkit/datumaro/blob/develop/CHANGELOG.md).​ - [ ] I have updated the [documentation](https://github.com/openvinotoolkit/datumaro/tree/develop/docs) accordingly ### License - [ ] I submit _my code changes_ under the same [MIT License](https://github.com/openvinotoolkit/datumaro/blob/develop/LICENSE) that covers the project. Feel free to contact the maintainers if that's a concern. - [ ] I have updated the license header for each file (see an example below). ```python # Copyright (C) 2023 Intel Corporation # # SPDX-License-Identifier: MIT ```
1 parent 8e77887 commit 7d3b237

File tree

8 files changed

+74
-153
lines changed

8 files changed

+74
-153
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3535
(<https://github.com/openvinotoolkit/datumaro/pull/1245>)
3636
- Enable image backend and color channel format to be selectable
3737
(<https://github.com/openvinotoolkit/datumaro/pull/1246>)
38+
- Boost up `CityscapesBase` and `KaggleImageMaskBase` by dropping `np.unique`
39+
(<https://github.com/openvinotoolkit/datumaro/pull/1261>)
3840
- Enhance RISE algortihm for explainable AI
3941
(<https://github.com/openvinotoolkit/datumaro/pull/1263>)
4042
- Enhance explore unit test to use real dataset from ImageNet

src/datumaro/plugins/data_formats/cityscapes.py

+21-19
Original file line numberDiff line numberDiff line change
@@ -265,30 +265,35 @@ def _load_items(self):
265265
recursive=True,
266266
)
267267
mask_suffix = CityscapesPath.GT_INSTANCE_MASK_SUFFIX
268+
269+
self._categories = self._load_categories(
270+
self._path, use_train_label_map=mask_suffix is CityscapesPath.LABEL_TRAIN_IDS_SUFFIX
271+
)
272+
273+
label_ids = []
274+
for label_cat in self._categories[AnnotationType.label]:
275+
label_id, _ = self._categories[AnnotationType.label].find(label_cat.name)
276+
if label_id:
277+
label_ids.append(label_id)
278+
268279
for mask_path in masks:
269280
item_id = self._get_id_from_mask_path(mask_path, mask_suffix)
270281

271282
anns = []
272283
instances_mask = load_image(mask_path, dtype=np.int32)
273-
segm_ids = np.unique(instances_mask)
274-
for segm_id in segm_ids:
275-
# either is_crowd or ann_id should be set
276-
if segm_id < 1000:
277-
label_id = segm_id
278-
is_crowd = True
279-
ann_id = None
280-
else:
281-
label_id = segm_id // 1000
282-
is_crowd = False
283-
ann_id = segm_id % 1000
284+
mask_id = 1
285+
for label_id in label_ids:
286+
if label_id not in instances_mask:
287+
continue
288+
binary_mask = self._lazy_extract_mask(instances_mask, label_id)
284289
anns.append(
285290
Mask(
286-
image=self._lazy_extract_mask(instances_mask, segm_id),
291+
id=mask_id,
292+
image=binary_mask,
287293
label=label_id,
288-
id=ann_id,
289-
attributes={"is_crowd": is_crowd},
290294
)
291295
)
296+
mask_id += 1
292297

293298
image = image_path_by_id.pop(item_id, None)
294299
if image:
@@ -303,9 +308,6 @@ def _load_items(self):
303308
id=item_id, subset=self._subset, media=Image.from_file(path=path)
304309
)
305310

306-
self._categories = self._load_categories(
307-
self._path, use_train_label_map=mask_suffix is CityscapesPath.LABEL_TRAIN_IDS_SUFFIX
308-
)
309311
return items
310312

311313
@staticmethod
@@ -429,8 +431,8 @@ def _apply_impl(self):
429431
masks,
430432
instance_ids=[
431433
self._label_id_mapping(m.label)
432-
if m.attributes.get("is_crowd", False)
433-
else self._label_id_mapping(m.label) * 1000 + (m.id or (i + 1))
434+
# if m.attributes.get("is_crowd", False)
435+
# else self._label_id_mapping(m.label) * 1000 + (m.id or (i + 1))
434436
for i, m in enumerate(masks)
435437
],
436438
instance_labels=[self._label_id_mapping(m.label) for m in masks],

src/datumaro/plugins/data_formats/kaggle/base.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ def __init__(
215215
self._path = path
216216
self._mask_path = mask_path
217217

218+
self._label_ids = []
218219
self._categories = self._load_categories(labelmap_file)
219220
self._items = self._load_items()
220221

@@ -241,6 +242,7 @@ def _load_categories(self, label_map_file: Optional[str]):
241242
for label_name, label_color in label_map.items():
242243
label_id = label_categories.find(label_name)[0]
243244
colormap[label_id] = label_color
245+
self._label_ids.append(label_id)
244246

245247
categories[AnnotationType.mask] = MaskCategories(colormap)
246248

@@ -260,8 +262,8 @@ def _lazy_extract_mask(mask, c):
260262
instances_mask = load_image(
261263
osp.join(self._mask_path, mask_name), dtype=np.int32
262264
)
263-
label_ids = np.unique(instances_mask)
264-
for label_id in label_ids:
265+
# label_ids = np.unique(instances_mask)
266+
for label_id in self._label_ids:
265267
anns.append(
266268
Mask(
267269
image=_lazy_extract_mask(instances_mask, label_id),

0 commit comments

Comments
 (0)