diff --git a/src/otx/data/dataset/tile.py b/src/otx/data/dataset/tile.py index 778b7de6b3..b4a4fce242 100644 --- a/src/otx/data/dataset/tile.py +++ b/src/otx/data/dataset/tile.py @@ -408,6 +408,15 @@ def __init__(self, dataset: OTXDataset, tile_config: TileConfig) -> None: with_full_img=tile_config.with_full_img, ) dm_dataset = dm_dataset.filter("/item/annotation", filter_annotations=True, remove_empty=True) + + if len(dm_dataset) == 0: + msg = ( + f"Tiled dataset is empty. This is likely because the tile_size ({tile_config.tile_size}) " + f"is too small, causing all annotations to be discarded. " + f"**Try increasing the tile_size.**" + ) + raise ValueError(msg) + # Include original dataset for training dm_dataset.update(dataset.dm_subset) dataset.dm_subset = dm_dataset diff --git a/tests/unit/backend/native/utils/test_tile.py b/tests/unit/backend/native/utils/test_tile.py index a6d6163278..098b607df6 100644 --- a/tests/unit/backend/native/utils/test_tile.py +++ b/tests/unit/backend/native/utils/test_tile.py @@ -1,4 +1,4 @@ -# Copyright (C) 2024 Intel Corporation +# Copyright (C) 2024-2025 Intel Corporation # SPDX-License-Identifier: Apache-2.0 # @@ -7,12 +7,15 @@ from unittest.mock import MagicMock import numpy as np +import pytest from datumaro import Image from datumaro.plugins.tiling.util import xywh_to_x1y1x2y2 from model_api.models import Model from model_api.tilers import Tiler -from otx.data.dataset.tile import OTXTileTransform +from otx.config.data import TileConfig +from otx.data.dataset.base import OTXDataset +from otx.data.dataset.tile import OTXTileTrainDataset, OTXTileTransform def test_tile_transform_consistency(mocker): @@ -45,3 +48,67 @@ def test_tile_transform_consistency(mocker): assert len(dm_rois) == len(ov_tiler_rois) for dm_roi in dm_rois: assert list(dm_roi) in ov_tiler_rois + + +def test_empty_tiled_dataset_raises_value_error(): + """Test that OTXTileTrainDataset raises ValueError when tiled dataset is empty.""" + # Create a mock dataset with empty dm_subset after tiling + mock_dataset = MagicMock(spec=OTXDataset) + mock_dm_subset = MagicMock() + + # Mock the transform method to return an empty dataset + empty_dm_subset = MagicMock() + empty_dm_subset.__len__.return_value = 0 + empty_dm_subset.filter.return_value = empty_dm_subset + + mock_dm_subset.transform.return_value = empty_dm_subset + mock_dataset.dm_subset = mock_dm_subset + + # Create tile config with small tile size to trigger the empty dataset scenario + tile_config = TileConfig( + enable_tiler=True, + tile_size=(10, 10), # Very small tile size + overlap=0.1, + with_full_img=False, + ) + + # Test that ValueError is raised with the expected message + expected_msg = ( + "Tiled dataset is empty. This is likely because the tile_size \\(\\(10, 10\\)\\) " + "is too small, causing all annotations to be discarded. " + "\\*\\*Try increasing the tile_size\\.\\*\\*" + ) + with pytest.raises(ValueError, match=expected_msg): + OTXTileTrainDataset(dataset=mock_dataset, tile_config=tile_config) + + +def test_empty_tiled_dataset_raises_value_error_different_tile_size(): + """Test that OTXTileTrainDataset raises ValueError with different tile size in message.""" + # Create a mock dataset with empty dm_subset after tiling + mock_dataset = MagicMock(spec=OTXDataset) + mock_dm_subset = MagicMock() + + # Mock the transform method to return an empty dataset + empty_dm_subset = MagicMock() + empty_dm_subset.__len__.return_value = 0 + empty_dm_subset.filter.return_value = empty_dm_subset + + mock_dm_subset.transform.return_value = empty_dm_subset + mock_dataset.dm_subset = mock_dm_subset + + # Create tile config with different tile size + tile_config = TileConfig( + enable_tiler=True, + tile_size=(50, 50), # Different tile size + overlap=0.2, + with_full_img=True, + ) + + # Test that ValueError is raised with the expected message containing the tile size + expected_msg = ( + "Tiled dataset is empty. This is likely because the tile_size \\(\\(50, 50\\)\\) " + "is too small, causing all annotations to be discarded. " + "\\*\\*Try increasing the tile_size\\.\\*\\*" + ) + with pytest.raises(ValueError, match=expected_msg): + OTXTileTrainDataset(dataset=mock_dataset, tile_config=tile_config)