From 3323faa3fcf7c09fc38f9d552fcc2193cc421284 Mon Sep 17 00:00:00 2001 From: Alexander Riedel <54716527+alexriedel1@users.noreply.github.com> Date: Wed, 16 Mar 2022 19:38:39 +0100 Subject: [PATCH 1/9] calculate feature map shape patchcore --- anomalib/models/patchcore/model.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/anomalib/models/patchcore/model.py b/anomalib/models/patchcore/model.py index d98e062a25..8ffce08a7a 100644 --- a/anomalib/models/patchcore/model.py +++ b/anomalib/models/patchcore/model.py @@ -54,10 +54,10 @@ def compute_anomaly_map(self, patch_scores: torch.Tensor) -> torch.Tensor: Returns: torch.Tensor: Map of the pixel-level anomaly scores """ - # TODO: https://github.com/openvinotoolkit/anomalib/issues/40 - batch_size = len(patch_scores) // (28 * 28) + w, h = feature_map_shape + batch_size = len(patch_scores) // (w * h) - anomaly_map = patch_scores[:, 0].reshape((batch_size, 1, 28, 28)) + anomaly_map = patch_scores[:, 0].reshape((batch_size, 1, w, h)) anomaly_map = F.interpolate(anomaly_map, size=(self.input_size[0], self.input_size[1])) kernel_size = 2 * int(4.0 * self.sigma + 0.5) + 1 @@ -66,7 +66,7 @@ def compute_anomaly_map(self, patch_scores: torch.Tensor) -> torch.Tensor: return anomaly_map @staticmethod - def compute_anomaly_score(patch_scores: torch.Tensor) -> torch.Tensor: + def compute_anomaly_score(patch_scores: torch.Tensor, feature_map_shape: tuple) -> torch.Tensor: """Compute Image-Level Anomaly Score. Args: @@ -99,7 +99,9 @@ def __call__(self, **kwargs: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]: raise ValueError(f"Expected key `patch_scores`. Found {kwargs.keys()}") patch_scores = kwargs["patch_scores"] - anomaly_map = self.compute_anomaly_map(patch_scores) + feature_map_shape = kwargs["feature_map_shape"] + + anomaly_map = self.compute_anomaly_map(patch_scores, feature_map_shape) anomaly_score = self.compute_anomaly_score(patch_scores) return anomaly_map, anomaly_score @@ -163,12 +165,13 @@ def forward(self, input_tensor: Tensor) -> Union[torch.Tensor, Tuple[torch.Tenso embedding = self.tiler.untile(embedding) embedding = self.reshape_embedding(embedding) + feature_map_shape = tuple(embedding.shape[-2:]) if self.training: output = embedding else: patch_scores = self.nearest_neighbors(embedding=embedding, n_neighbors=9) - anomaly_map, anomaly_score = self.anomaly_map_generator(patch_scores=patch_scores) + anomaly_map, anomaly_score = self.anomaly_map_generator(patch_scores=patch_scores, feature_map_shape=feature_map_shape) output = (anomaly_map, anomaly_score) return output From 6a44b8a2ad63be029f9c12b897e5464584053bf1 Mon Sep 17 00:00:00 2001 From: Alexander Riedel <54716527+alexriedel1@users.noreply.github.com> Date: Wed, 16 Mar 2022 19:41:41 +0100 Subject: [PATCH 2/9] passed to wrong function --- anomalib/models/patchcore/model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/anomalib/models/patchcore/model.py b/anomalib/models/patchcore/model.py index 8ffce08a7a..e2e1cad2c3 100644 --- a/anomalib/models/patchcore/model.py +++ b/anomalib/models/patchcore/model.py @@ -46,7 +46,7 @@ def __init__( self.input_size = input_size self.sigma = sigma - def compute_anomaly_map(self, patch_scores: torch.Tensor) -> torch.Tensor: + def compute_anomaly_map(self, patch_scores: torch.Tensor, feature_map_shape: tuple) -> torch.Tensor: """Pixel Level Anomaly Heatmap. Args: @@ -66,7 +66,7 @@ def compute_anomaly_map(self, patch_scores: torch.Tensor) -> torch.Tensor: return anomaly_map @staticmethod - def compute_anomaly_score(patch_scores: torch.Tensor, feature_map_shape: tuple) -> torch.Tensor: + def compute_anomaly_score(patch_scores: torch.Tensor) -> torch.Tensor: """Compute Image-Level Anomaly Score. Args: From c1417678d6806b4e42632a5ec5cf9ca4ead60d6b Mon Sep 17 00:00:00 2001 From: Alexander Riedel <54716527+alexriedel1@users.noreply.github.com> Date: Thu, 17 Mar 2022 08:50:59 +0100 Subject: [PATCH 3/9] unpack values from torch tensor directly --- anomalib/models/patchcore/model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/anomalib/models/patchcore/model.py b/anomalib/models/patchcore/model.py index e2e1cad2c3..59fe497963 100644 --- a/anomalib/models/patchcore/model.py +++ b/anomalib/models/patchcore/model.py @@ -46,7 +46,7 @@ def __init__( self.input_size = input_size self.sigma = sigma - def compute_anomaly_map(self, patch_scores: torch.Tensor, feature_map_shape: tuple) -> torch.Tensor: + def compute_anomaly_map(self, patch_scores: torch.Tensor, feature_map_shape: torch.Tensor) -> torch.Tensor: """Pixel Level Anomaly Heatmap. Args: @@ -165,7 +165,7 @@ def forward(self, input_tensor: Tensor) -> Union[torch.Tensor, Tuple[torch.Tenso embedding = self.tiler.untile(embedding) embedding = self.reshape_embedding(embedding) - feature_map_shape = tuple(embedding.shape[-2:]) + feature_map_shape = embedding.shape[-2:] if self.training: output = embedding From 49a6d671d293931251064b308d37cdc90c6eff24 Mon Sep 17 00:00:00 2001 From: Alexander Riedel <54716527+alexriedel1@users.noreply.github.com> Date: Thu, 17 Mar 2022 16:56:19 +0100 Subject: [PATCH 4/9] get feature map shape before reshaping --- anomalib/models/patchcore/model.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/anomalib/models/patchcore/model.py b/anomalib/models/patchcore/model.py index 59fe497963..12db7344d3 100644 --- a/anomalib/models/patchcore/model.py +++ b/anomalib/models/patchcore/model.py @@ -163,9 +163,10 @@ def forward(self, input_tensor: Tensor) -> Union[torch.Tensor, Tuple[torch.Tenso if self.apply_tiling: embedding = self.tiler.untile(embedding) - - embedding = self.reshape_embedding(embedding) + feature_map_shape = embedding.shape[-2:] + embedding = self.reshape_embedding(embedding) + if self.training: output = embedding From 16d0b39b0cbd32692ab155e5eb235cbff0f1df00 Mon Sep 17 00:00:00 2001 From: Alexander Riedel <54716527+alexriedel1@users.noreply.github.com> Date: Fri, 18 Mar 2022 08:47:40 +0100 Subject: [PATCH 5/9] updating docstrings in patchcore --- anomalib/models/patchcore/model.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/anomalib/models/patchcore/model.py b/anomalib/models/patchcore/model.py index 12db7344d3..dbed91cd2a 100644 --- a/anomalib/models/patchcore/model.py +++ b/anomalib/models/patchcore/model.py @@ -51,6 +51,8 @@ def compute_anomaly_map(self, patch_scores: torch.Tensor, feature_map_shape: tor Args: patch_scores (torch.Tensor): Patch-level anomaly scores + feature_map_shape (torch.Tensor): 2-D feature map shape (width, height) + Returns: torch.Tensor: Map of the pixel-level anomaly scores """ @@ -83,10 +85,11 @@ def __call__(self, **kwargs: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]: """Returns anomaly_map and anomaly_score. Expects `patch_scores` keyword to be passed explicitly + Expects `feature_map_shape` keyword to be passed explicitly Example >>> anomaly_map_generator = AnomalyMapGenerator(input_size=input_size) - >>> map, score = anomaly_map_generator(patch_scores=numpy_array) + >>> map, score = anomaly_map_generator(patch_scores=numpy_array, feature_map_shape=feature_map_shape) Raises: ValueError: If `patch_scores` key is not found @@ -98,6 +101,9 @@ def __call__(self, **kwargs: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]: if "patch_scores" not in kwargs: raise ValueError(f"Expected key `patch_scores`. Found {kwargs.keys()}") + if "feature_map_shape" not in kwargs: + raise ValueError(f"Expected key `feature_map_shape`. Found {kwargs.keys()}") + patch_scores = kwargs["patch_scores"] feature_map_shape = kwargs["feature_map_shape"] From 0292b4f1cd58e3666c09df4f8cd79274ed4de044 Mon Sep 17 00:00:00 2001 From: Alexander Riedel <54716527+alexriedel1@users.noreply.github.com> Date: Fri, 18 Mar 2022 09:09:04 +0100 Subject: [PATCH 6/9] fix line length --- anomalib/models/patchcore/model.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/anomalib/models/patchcore/model.py b/anomalib/models/patchcore/model.py index dbed91cd2a..6660045c52 100644 --- a/anomalib/models/patchcore/model.py +++ b/anomalib/models/patchcore/model.py @@ -178,7 +178,9 @@ def forward(self, input_tensor: Tensor) -> Union[torch.Tensor, Tuple[torch.Tenso output = embedding else: patch_scores = self.nearest_neighbors(embedding=embedding, n_neighbors=9) - anomaly_map, anomaly_score = self.anomaly_map_generator(patch_scores=patch_scores, feature_map_shape=feature_map_shape) + anomaly_map, anomaly_score = self.anomaly_map_generator( + patch_scores=patch_scores, feature_map_shape=feature_map_shape + ) output = (anomaly_map, anomaly_score) return output From fe1fb0f51c70b1feba550fe0891de9c32155dd2f Mon Sep 17 00:00:00 2001 From: Alexander Riedel <54716527+alexriedel1@users.noreply.github.com> Date: Fri, 18 Mar 2022 09:59:57 +0100 Subject: [PATCH 7/9] w, h (too short) -> width, height --- anomalib/models/patchcore/model.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/anomalib/models/patchcore/model.py b/anomalib/models/patchcore/model.py index 6660045c52..0199a08fac 100644 --- a/anomalib/models/patchcore/model.py +++ b/anomalib/models/patchcore/model.py @@ -56,10 +56,10 @@ def compute_anomaly_map(self, patch_scores: torch.Tensor, feature_map_shape: tor Returns: torch.Tensor: Map of the pixel-level anomaly scores """ - w, h = feature_map_shape - batch_size = len(patch_scores) // (w * h) + width, height = feature_map_shape + batch_size = len(patch_scores) // (width * height) - anomaly_map = patch_scores[:, 0].reshape((batch_size, 1, w, h)) + anomaly_map = patch_scores[:, 0].reshape((batch_size, 1, width, height)) anomaly_map = F.interpolate(anomaly_map, size=(self.input_size[0], self.input_size[1])) kernel_size = 2 * int(4.0 * self.sigma + 0.5) + 1 From 01b9b6aae8ae8221183f080f0ee6893fe366240d Mon Sep 17 00:00:00 2001 From: Alexander Riedel <54716527+alexriedel1@users.noreply.github.com> Date: Fri, 18 Mar 2022 10:26:14 +0100 Subject: [PATCH 8/9] typing torch.Size of feature_map_shape --- anomalib/models/patchcore/model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/anomalib/models/patchcore/model.py b/anomalib/models/patchcore/model.py index 0199a08fac..36a89465ab 100644 --- a/anomalib/models/patchcore/model.py +++ b/anomalib/models/patchcore/model.py @@ -46,12 +46,12 @@ def __init__( self.input_size = input_size self.sigma = sigma - def compute_anomaly_map(self, patch_scores: torch.Tensor, feature_map_shape: torch.Tensor) -> torch.Tensor: + def compute_anomaly_map(self, patch_scores: torch.Tensor, feature_map_shape: torch.Size) -> torch.Tensor: """Pixel Level Anomaly Heatmap. Args: patch_scores (torch.Tensor): Patch-level anomaly scores - feature_map_shape (torch.Tensor): 2-D feature map shape (width, height) + feature_map_shape (torch.Size): 2-D feature map shape (width, height) Returns: torch.Tensor: Map of the pixel-level anomaly scores From 0e8a10d1e4f65fef002b0f5205976e60563ec236 Mon Sep 17 00:00:00 2001 From: Alexander Riedel <54716527+alexriedel1@users.noreply.github.com> Date: Fri, 18 Mar 2022 10:57:18 +0100 Subject: [PATCH 9/9] removing trailing whitespaces --- anomalib/models/patchcore/model.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/anomalib/models/patchcore/model.py b/anomalib/models/patchcore/model.py index 36a89465ab..94a78de3ee 100644 --- a/anomalib/models/patchcore/model.py +++ b/anomalib/models/patchcore/model.py @@ -169,10 +169,9 @@ def forward(self, input_tensor: Tensor) -> Union[torch.Tensor, Tuple[torch.Tenso if self.apply_tiling: embedding = self.tiler.untile(embedding) - + feature_map_shape = embedding.shape[-2:] embedding = self.reshape_embedding(embedding) - if self.training: output = embedding