From b7879b85c8555654d17553e4dbf0c095a2808f8d Mon Sep 17 00:00:00 2001 From: Evgeny Tsykunov Date: Tue, 20 Aug 2024 23:17:13 +0900 Subject: [PATCH] fix bbox bug and tests --- openvino_xai/methods/black_box/aise.py | 13 +++++++-- tests/unit/explanation/test_visualization.py | 29 +++++++++++++++++-- .../black_box/test_black_box_method.py | 15 ++++++++-- 3 files changed, 50 insertions(+), 7 deletions(-) diff --git a/openvino_xai/methods/black_box/aise.py b/openvino_xai/methods/black_box/aise.py index 480d2766..82e7190e 100644 --- a/openvino_xai/methods/black_box/aise.py +++ b/openvino_xai/methods/black_box/aise.py @@ -372,12 +372,15 @@ def generate_saliency_map( # type: ignore saliency_maps = {} for target in target_indices: - self.kernel_params_hist = collections.defaultdict(list) - self.pred_score_hist = collections.defaultdict(list) - self.target_box = boxes[target] self.target_label = labels[target] + if self.target_box[0] == self.target_box[2] or self.target_box[1] == self.target_box[3]: + continue + + self.kernel_params_hist = collections.defaultdict(list) + self.pred_score_hist = collections.defaultdict(list) + self._process_box() saliency_map_per_target = self._run_synchronous_explanation() if scale_output: @@ -427,6 +430,10 @@ def _process_box(self, padding_coef: float = 0.5) -> None: x_to = min(target_box_scaled[2] + box_width * padding_coef, 1.0) y_from = max(target_box_scaled[1] - box_height * padding_coef, 0.0) y_to = min(target_box_scaled[3] + box_height * padding_coef, 1.0) + + if x_from < x_to or y_from < y_to: + raise ValueError("Bounding box data is incorrect.") + self.bounds = Bounds([x_from, y_from], [x_to, y_to]) def _get_loss(self, data_perturbed: np.array) -> float: diff --git a/tests/unit/explanation/test_visualization.py b/tests/unit/explanation/test_visualization.py index 470a27c7..0f3bf6d8 100644 --- a/tests/unit/explanation/test_visualization.py +++ b/tests/unit/explanation/test_visualization.py @@ -4,6 +4,7 @@ import numpy as np import pytest +from openvino_xai.common.parameters import Task from openvino_xai.common.utils import get_min_max, scaling from openvino_xai.explainer.explanation import Explanation from openvino_xai.explainer.visualizer import Visualizer, colormap, overlay, resize @@ -11,6 +12,10 @@ SALIENCY_MAPS = [ (np.random.rand(1, 5, 5) * 255).astype(np.uint8), (np.random.rand(1, 2, 5, 5) * 255).astype(np.uint8), + { + 0: (np.random.rand(5, 5) * 255).astype(np.uint8), + 1: (np.random.rand(5, 5) * 255).astype(np.uint8), + }, ] EXPLAIN_ALL_CLASSES = [ @@ -98,7 +103,7 @@ class TestVisualizer: @pytest.mark.parametrize("colormap", [True, False]) @pytest.mark.parametrize("overlay", [True, False]) @pytest.mark.parametrize("overlay_weight", [0.5, 0.3]) - def test_Visualizer( + def test_visualizer( self, saliency_maps, explain_all_classes, @@ -142,7 +147,7 @@ def test_Visualizer( for map_ in explanation.saliency_map.values(): assert map_.shape[:2] == original_input_image.shape[:2] - if saliency_maps.ndim == 3 and not overlay: + if isinstance(saliency_maps, np.ndarray) and saliency_maps.ndim == 3 and not overlay: explanation = Explanation(saliency_maps, targets=-1) visualizer = Visualizer() explanation_output_size = visualizer( @@ -157,3 +162,23 @@ def test_Visualizer( maps_data = explanation.saliency_map maps_size = explanation_output_size.saliency_map assert np.all(maps_data["per_image_map"] == maps_size["per_image_map"]) + + if isinstance(saliency_maps, dict): + metadata = { + Task.DETECTION: { + 0: ([5, 0, 7, 4], 0.5, 0), + 1: ([2, 5, 9, 7], 0.5, 0), + } + } + explanation = Explanation(saliency_maps, targets=-1, metadata=metadata) + visualizer = Visualizer() + explanation_output_size = visualizer( + explanation=explanation, + original_input_image=original_input_image, + output_size=(20, 20), + scaling=scaling, + resize=resize, + colormap=colormap, + overlay=overlay, + overlay_weight=overlay_weight, + ) diff --git a/tests/unit/methods/black_box/test_black_box_method.py b/tests/unit/methods/black_box/test_black_box_method.py index e7747f11..60374d93 100644 --- a/tests/unit/methods/black_box/test_black_box_method.py +++ b/tests/unit/methods/black_box/test_black_box_method.py @@ -137,12 +137,23 @@ def test_run(self, target_indices, fxt_data_root: Path): assert saliency_map[ref_target].shape == (416, 416) assert (saliency_map[ref_target] >= 0).all() and (saliency_map[ref_target] <= 255).all() - tmp = saliency_map[0] - actual_sal_vals = saliency_map[0][150, 240:250].astype(np.int16) ref_sal_vals = np.array([152, 168, 184, 199, 213, 225, 235, 243, 247, 249], dtype=np.uint8) assert np.all(np.abs(actual_sal_vals - ref_sal_vals) <= 1) + def test_target_none(self, fxt_data_root: Path): + model = self.get_det_model(fxt_data_root) + + aise_method = AISEDetection(model, self.postprocess_det_fn, self.preprocess_det_fn) + saliency_map = aise_method.generate_saliency_map( + data=self.image, + target_indices=None, + preset=Preset.SPEED, + num_iterations_per_kernel=1, + divisors=[5], + ) + assert len(saliency_map) == 56 + def test_preset(self, fxt_data_root: Path): model = self.get_det_model(fxt_data_root) method = AISEDetection(model, self.postprocess_det_fn, self.preprocess_det_fn)