From b1cc38bb9f31ef1d2a77dcf4fa5b6bed1fe2373d Mon Sep 17 00:00:00 2001 From: Eugene Liu Date: Fri, 20 Sep 2024 01:54:47 +0100 Subject: [PATCH 1/9] Include Geti arrow dataset subset names (#3962) * restrited number of output masks by tiling * add geti subset name * update num of max pred --- src/otx/core/data/utils/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/otx/core/data/utils/utils.py b/src/otx/core/data/utils/utils.py index 0bdb4a48baa..02fe1136301 100644 --- a/src/otx/core/data/utils/utils.py +++ b/src/otx/core/data/utils/utils.py @@ -276,7 +276,7 @@ def adapt_tile_config(tile_config: TileConfig, dataset: Dataset, task: OTXTaskTy task (Task): task type of the model """ if (train_dataset := dataset.subsets().get("train") or dataset.subsets().get("TRAINING")) is not None: - stat = compute_robust_dataset_statistics(train_dataset, task=task) + stat = compute_robust_dataset_statistics(train_dataset) max_num_objects = round(stat["annotation"]["num_per_image"]["max"]) avg_size = stat["annotation"]["size_of_shape"]["avg"] min_size = stat["annotation"]["size_of_shape"]["robust_min"] From b3792f916fe575eba42a33f4ac4a57a8994bf45a Mon Sep 17 00:00:00 2001 From: Harim Kang Date: Fri, 20 Sep 2024 12:14:49 +0900 Subject: [PATCH 2/9] Add type checker in converter for callable functions (optimizer, scheduler) (#3968) Fix converter callable functions (optimizer, scheduler) From 7e17afacf16c013b038d50a7658d0fe19a3ec4d3 Mon Sep 17 00:00:00 2001 From: Yunchu Lee Date: Fri, 20 Sep 2024 14:45:32 +0900 Subject: [PATCH 3/9] Update for 2.2.0rc2 (#3969) update for 2.2.0rc2 From 50609d257e2209c66010a7ff8ec55711a026e275 Mon Sep 17 00:00:00 2001 From: Eugene Liu Date: Mon, 23 Sep 2024 14:17:25 +0100 Subject: [PATCH 4/9] Fix config converter for tiling (#3973) fix config converter for tiling From 63fa64b7d2933bcace1457c509caae4b9a3ec1bc Mon Sep 17 00:00:00 2001 From: Yunchu Lee Date: Tue, 24 Sep 2024 10:37:12 +0900 Subject: [PATCH 5/9] Update for 2.2.0rc3 (#3975) --- CHANGELOG.md | 2 ++ README.md | 1 + docs/source/guide/release_notes/index.rst | 1 + 3 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 360b39be295..5781746f6a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -95,6 +95,8 @@ All notable changes to this project will be documented in this file. () - Change categories mapping logic () +- Fix config converter for tiling + () ## \[v2.1.0\] diff --git a/README.md b/README.md index f1c3043a6e1..077d7083370 100644 --- a/README.md +++ b/README.md @@ -204,6 +204,7 @@ In addition to the examples above, please refer to the documentation for tutoria - Add num_devices in Engine for multi-gpu training - Add missing tile recipes and various tile recipe changes - Change categories mapping logic +- Fix config converter for tiling ### Known issues diff --git a/docs/source/guide/release_notes/index.rst b/docs/source/guide/release_notes/index.rst index 75070a72926..fbb2ec1e65b 100644 --- a/docs/source/guide/release_notes/index.rst +++ b/docs/source/guide/release_notes/index.rst @@ -46,6 +46,7 @@ Bug fixes - Add num_devices in Engine for multi-gpu training - Add missing tile recipes and various tile recipe changes - Change categories mapping logic +- Fix config converter for tiling v2.1.0 (2024.07) ---------------- From 7462ef8658a3dfa91df36d811c7e11e30f7dbd4f Mon Sep 17 00:00:00 2001 From: Eunwoo Shin Date: Fri, 4 Oct 2024 20:29:08 +0900 Subject: [PATCH 6/9] Change sematic segmentation to consider bbox only annotations. (#3996) * segmentation consider bbox only annotations * add unit test * add unit test * update fixture * use name attribute * revert tox file * update for 2.2.0rc4 --------- Co-authored-by: Yunchu Lee --- CHANGELOG.md | 2 ++ README.md | 1 + docs/source/guide/release_notes/index.rst | 1 + src/otx/core/data/dataset/segmentation.py | 12 +++---- tests/unit/core/data/conftest.py | 11 ++++-- .../core/data/dataset/test_segmentation.py | 36 +++++++++++++++++++ 6 files changed, 55 insertions(+), 8 deletions(-) create mode 100644 tests/unit/core/data/dataset/test_segmentation.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 5781746f6a7..63ac5dac93b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -82,6 +82,8 @@ All notable changes to this project will be documented in this file. () - Add type checker in converter for callable functions (optimizer, scheduler) () +- Change sematic segmentation to consider bbox only annotations + () ### Bug fixes diff --git a/README.md b/README.md index 077d7083370..f42741bb689 100644 --- a/README.md +++ b/README.md @@ -196,6 +196,7 @@ In addition to the examples above, please refer to the documentation for tutoria - Include Geti arrow dataset subset names - Include full image with anno in case there's no tile in tile dataset - Add type checker in converter for callable functions (optimizer, scheduler) +- Change sematic segmentation to consider bbox only annotations ### Bug fixes diff --git a/docs/source/guide/release_notes/index.rst b/docs/source/guide/release_notes/index.rst index fbb2ec1e65b..a0e0954c2a8 100644 --- a/docs/source/guide/release_notes/index.rst +++ b/docs/source/guide/release_notes/index.rst @@ -37,6 +37,7 @@ Enhancements - Include Geti arrow dataset subset names - Include full image with anno in case there's no tile in tile dataset - Add type checker in converter for callable functions (optimizer, scheduler) +- Change sematic segmentation to consider bbox only annotations Bug fixes ^^^^^^^^^ diff --git a/src/otx/core/data/dataset/segmentation.py b/src/otx/core/data/dataset/segmentation.py index ee23be6090e..c0a976b8e40 100644 --- a/src/otx/core/data/dataset/segmentation.py +++ b/src/otx/core/data/dataset/segmentation.py @@ -11,7 +11,7 @@ import cv2 import numpy as np import torch -from datumaro.components.annotation import Ellipse, Image, Mask, Polygon +from datumaro.components.annotation import Bbox, Ellipse, Image, Mask, Polygon, RotatedBbox from torchvision import tv_tensors from otx.core.data.entity.base import ImageInfo @@ -100,11 +100,11 @@ def _extract_class_mask(item: DatasetItem, img_shape: tuple[int, int], ignore_in raise ValueError(msg, ignore_index) # fill mask with background label if we have Polygon/Ellipse annotations - fill_value = 0 if isinstance(item.annotations[0], (Ellipse, Polygon)) else ignore_index + fill_value = 0 if isinstance(item.annotations[0], (Ellipse, Polygon, Bbox, RotatedBbox)) else ignore_index class_mask = np.full(shape=img_shape[:2], fill_value=fill_value, dtype=np.uint8) for mask in sorted( - [ann for ann in item.annotations if isinstance(ann, (Mask, Ellipse, Polygon))], + [ann for ann in item.annotations if isinstance(ann, (Mask, Ellipse, Polygon, Bbox, RotatedBbox))], key=lambda ann: ann.z_order, ): index = mask.label @@ -113,7 +113,7 @@ def _extract_class_mask(item: DatasetItem, img_shape: tuple[int, int], ignore_in msg = "Mask's label index should not be None." raise ValueError(msg) - if isinstance(mask, (Ellipse, Polygon)): + if isinstance(mask, (Ellipse, Polygon, Bbox, RotatedBbox)): polygons = np.asarray(mask.as_polygon(), dtype=np.int32).reshape((-1, 1, 2)) class_index = index + 1 # NOTE: disregard the background index. Objects start from index=1 this_class_mask = cv2.drawContours( @@ -194,8 +194,8 @@ def __init__( @property def has_polygons(self) -> bool: """Check if the dataset has polygons in annotations.""" - ann_types = {str(ann_type).split(".")[-1] for ann_type in self.dm_subset.ann_types()} - if ann_types & {"polygon", "ellipse"}: + # all polygon-like format should be considered as polygons + if {ann_type.name for ann_type in self.dm_subset.ann_types()} & {"polygon", "ellipse", "bbox", "rotated_bbox"}: return True return False diff --git a/tests/unit/core/data/conftest.py b/tests/unit/core/data/conftest.py index 48b0fc54961..665bc5a7471 100644 --- a/tests/unit/core/data/conftest.py +++ b/tests/unit/core/data/conftest.py @@ -10,7 +10,7 @@ import cv2 import numpy as np import pytest -from datumaro.components.annotation import Bbox, Label, LabelCategories, Mask, Polygon +from datumaro.components.annotation import AnnotationType, Bbox, Label, LabelCategories, Mask, Polygon from datumaro.components.dataset import Dataset as DmDataset from datumaro.components.dataset_base import DatasetItem from datumaro.components.media import Image @@ -89,7 +89,7 @@ def fxt_dm_item(request, tmpdir) -> DatasetItem: media=media, annotations=[ Label(label=0), - Bbox(x=0, y=0, w=1, h=1, label=0), + Bbox(x=200, y=200, w=1, h=1, label=0), Mask(label=0, image=np.eye(10, dtype=np.uint8)), Polygon(points=[399.0, 570.0, 397.0, 572.0, 397.0, 573.0, 394.0, 576.0], label=0), ], @@ -133,6 +133,12 @@ def fxt_mock_dm_subset(mocker: MockerFixture, fxt_dm_item: DatasetItem) -> Magic mock_dm_subset.__getitem__.return_value = fxt_dm_item mock_dm_subset.__len__.return_value = 1 mock_dm_subset.categories().__getitem__.return_value = LabelCategories.from_iterable(_LABEL_NAMES) + mock_dm_subset.ann_types.return_value = [ + AnnotationType.label, + AnnotationType.bbox, + AnnotationType.mask, + AnnotationType.polygon, + ] return mock_dm_subset @@ -142,6 +148,7 @@ def fxt_mock_det_dm_subset(mocker: MockerFixture, fxt_dm_item_bbox_only: Dataset mock_dm_subset.__getitem__.return_value = fxt_dm_item_bbox_only mock_dm_subset.__len__.return_value = 1 mock_dm_subset.categories().__getitem__.return_value = LabelCategories.from_iterable(_LABEL_NAMES) + mock_dm_subset.ann_types.return_value = [AnnotationType.bbox] return mock_dm_subset diff --git a/tests/unit/core/data/dataset/test_segmentation.py b/tests/unit/core/data/dataset/test_segmentation.py new file mode 100644 index 00000000000..141dc4bf74b --- /dev/null +++ b/tests/unit/core/data/dataset/test_segmentation.py @@ -0,0 +1,36 @@ +# Copyright (C) 2024 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +"""Unit tests of classification datasets.""" + +from otx.core.data.dataset.segmentation import OTXSegmentationDataset +from otx.core.data.entity.segmentation import SegDataEntity + + +class TestOTXSegmentationDataset: + def test_get_item( + self, + fxt_mock_dm_subset, + ) -> None: + dataset = OTXSegmentationDataset( + dm_subset=fxt_mock_dm_subset, + transforms=[lambda x: x], + mem_cache_img_max_size=None, + max_refetch=3, + ) + assert isinstance(dataset[0], SegDataEntity) + assert "background" in [label_name.lower() for label_name in dataset.label_info.label_names] + + def test_get_item_from_bbox_dataset( + self, + fxt_mock_det_dm_subset, + ) -> None: + dataset = OTXSegmentationDataset( + dm_subset=fxt_mock_det_dm_subset, + transforms=[lambda x: x], + mem_cache_img_max_size=None, + max_refetch=3, + ) + assert isinstance(dataset[0], SegDataEntity) + # OTXSegmentationDataset should add background when getting a dataset which includes only bbox annotations + assert "background" in [label_name.lower() for label_name in dataset.label_info.label_names] From 1392507040a28e130ae8afaacdc811da29c1e651 Mon Sep 17 00:00:00 2001 From: kprokofi Date: Tue, 8 Oct 2024 00:07:48 +0900 Subject: [PATCH 7/9] remove task from adapt_tiling_config --- src/otx/core/data/module.py | 2 +- src/otx/core/data/utils/utils.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/otx/core/data/module.py b/src/otx/core/data/module.py index f9b7cac8fd4..9bdefc6fc7d 100644 --- a/src/otx/core/data/module.py +++ b/src/otx/core/data/module.py @@ -150,7 +150,7 @@ def __init__( # noqa: PLR0913 self.input_size = input_size if self.tile_config.enable_tiler and self.tile_config.enable_adaptive_tiling: - adapt_tile_config(self.tile_config, dataset=dataset, task=self.task) + adapt_tile_config(self.tile_config, dataset=dataset) config_mapping = { self.train_subset.subset_name: self.train_subset, diff --git a/src/otx/core/data/utils/utils.py b/src/otx/core/data/utils/utils.py index 02fe1136301..5e76eb8bd72 100644 --- a/src/otx/core/data/utils/utils.py +++ b/src/otx/core/data/utils/utils.py @@ -264,7 +264,7 @@ def area(x: list[int] | tuple[int, int]) -> int: return image_size # type: ignore[return-value] -def adapt_tile_config(tile_config: TileConfig, dataset: Dataset, task: OTXTaskType) -> None: +def adapt_tile_config(tile_config: TileConfig, dataset: Dataset) -> None: """Config tile parameters. Adapt based on annotation statistics. From 3430156522827e7319d90dab6c8087f4541511f9 Mon Sep 17 00:00:00 2001 From: kprokofi Date: Tue, 8 Oct 2024 00:12:58 +0900 Subject: [PATCH 8/9] revert changes back --- src/otx/core/data/module.py | 2 +- src/otx/core/data/utils/utils.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/otx/core/data/module.py b/src/otx/core/data/module.py index 9bdefc6fc7d..f9b7cac8fd4 100644 --- a/src/otx/core/data/module.py +++ b/src/otx/core/data/module.py @@ -150,7 +150,7 @@ def __init__( # noqa: PLR0913 self.input_size = input_size if self.tile_config.enable_tiler and self.tile_config.enable_adaptive_tiling: - adapt_tile_config(self.tile_config, dataset=dataset) + adapt_tile_config(self.tile_config, dataset=dataset, task=self.task) config_mapping = { self.train_subset.subset_name: self.train_subset, diff --git a/src/otx/core/data/utils/utils.py b/src/otx/core/data/utils/utils.py index 5e76eb8bd72..0bdb4a48baa 100644 --- a/src/otx/core/data/utils/utils.py +++ b/src/otx/core/data/utils/utils.py @@ -264,7 +264,7 @@ def area(x: list[int] | tuple[int, int]) -> int: return image_size # type: ignore[return-value] -def adapt_tile_config(tile_config: TileConfig, dataset: Dataset) -> None: +def adapt_tile_config(tile_config: TileConfig, dataset: Dataset, task: OTXTaskType) -> None: """Config tile parameters. Adapt based on annotation statistics. @@ -276,7 +276,7 @@ def adapt_tile_config(tile_config: TileConfig, dataset: Dataset) -> None: task (Task): task type of the model """ if (train_dataset := dataset.subsets().get("train") or dataset.subsets().get("TRAINING")) is not None: - stat = compute_robust_dataset_statistics(train_dataset) + stat = compute_robust_dataset_statistics(train_dataset, task=task) max_num_objects = round(stat["annotation"]["num_per_image"]["max"]) avg_size = stat["annotation"]["size_of_shape"]["avg"] min_size = stat["annotation"]["size_of_shape"]["robust_min"] From 31823cd4e2477785f4ebf7d0d710d54ed0a491a0 Mon Sep 17 00:00:00 2001 From: kprokofi Date: Tue, 8 Oct 2024 00:18:22 +0900 Subject: [PATCH 9/9] change changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63ac5dac93b..3640f36e4fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ All notable changes to this project will be documented in this file. (https://github.com/openvinotoolkit/training_extensions/pull/3970) - Add tiling for semantic segmentation (https://github.com/openvinotoolkit/training_extensions/pull/3954) +- Add 3D Object Detection task with MonoDETR model + (https://github.com/openvinotoolkit/training_extensions/pull/3979) ### Enhancements