signal-grad-cam 0.1.1__tar.gz → 0.1.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of signal-grad-cam might be problematic. Click here for more details.
- {signal_grad_cam-0.1.1 → signal_grad_cam-0.1.3}/PKG-INFO +1 -1
- {signal_grad_cam-0.1.1 → signal_grad_cam-0.1.3}/setup.py +1 -1
- {signal_grad_cam-0.1.1 → signal_grad_cam-0.1.3}/signal_grad_cam/cam_builder.py +12 -5
- {signal_grad_cam-0.1.1 → signal_grad_cam-0.1.3}/signal_grad_cam/pytorch_cam_builder.py +31 -7
- {signal_grad_cam-0.1.1 → signal_grad_cam-0.1.3}/signal_grad_cam/tensorflow_cam_builder.py +35 -9
- {signal_grad_cam-0.1.1 → signal_grad_cam-0.1.3}/signal_grad_cam.egg-info/PKG-INFO +1 -1
- {signal_grad_cam-0.1.1 → signal_grad_cam-0.1.3}/LICENSE +0 -0
- {signal_grad_cam-0.1.1 → signal_grad_cam-0.1.3}/README.md +0 -0
- {signal_grad_cam-0.1.1 → signal_grad_cam-0.1.3}/pyproject.toml +0 -0
- {signal_grad_cam-0.1.1 → signal_grad_cam-0.1.3}/setup.cfg +0 -0
- {signal_grad_cam-0.1.1 → signal_grad_cam-0.1.3}/signal_grad_cam/__init__.py +0 -0
- {signal_grad_cam-0.1.1 → signal_grad_cam-0.1.3}/signal_grad_cam.egg-info/SOURCES.txt +0 -0
- {signal_grad_cam-0.1.1 → signal_grad_cam-0.1.3}/signal_grad_cam.egg-info/dependency_links.txt +0 -0
- {signal_grad_cam-0.1.1 → signal_grad_cam-0.1.3}/signal_grad_cam.egg-info/not-zip-safe +0 -0
- {signal_grad_cam-0.1.1 → signal_grad_cam-0.1.3}/signal_grad_cam.egg-info/requires.txt +0 -0
- {signal_grad_cam-0.1.1 → signal_grad_cam-0.1.3}/signal_grad_cam.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: signal_grad_cam
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: SignalGrad-CAM aims at generalising Grad-CAM to one-dimensional applications, while enhancing usability and efficiency.
|
|
5
5
|
Home-page: https://github.com/samuelepe11/signal_grad_cam
|
|
6
6
|
Author: Samuele Pe
|
|
@@ -5,7 +5,7 @@ with open("README.md", "r") as f:
|
|
|
5
5
|
|
|
6
6
|
setup(
|
|
7
7
|
name="signal_grad_cam",
|
|
8
|
-
version="0.1.
|
|
8
|
+
version="0.1.3",
|
|
9
9
|
description="SignalGrad-CAM aims at generalising Grad-CAM to one-dimensional applications, while enhancing usability"
|
|
10
10
|
" and efficiency.",
|
|
11
11
|
keywords="XAI, class activation maps, CNN, time series",
|
|
@@ -23,8 +23,8 @@ class CamBuilder:
|
|
|
23
23
|
def __init__(self, model: torch.nn.Module | tf.keras.Model | Any,
|
|
24
24
|
transform_fn: Callable[[np.ndarray, *tuple[Any, ...]], torch.Tensor | tf.Tensor] = None,
|
|
25
25
|
class_names: List[str] = None, time_axs: int = 1, input_transposed: bool = False,
|
|
26
|
-
ignore_channel_dim: bool = False,
|
|
27
|
-
padding_dim: int = None, seed: int = 11):
|
|
26
|
+
ignore_channel_dim: bool = False, is_regression_network: bool = False, model_output_index: int = None,
|
|
27
|
+
extend_search: bool = False, padding_dim: int = None, seed: int = 11):
|
|
28
28
|
"""
|
|
29
29
|
Initializes the CamBuilder class. The constructor also displays, if present and retrievable, the 1D- and
|
|
30
30
|
2D-convolutional layers in the network, as well as the final Sigmoid/Softmax activation. Additionally, the CAM
|
|
@@ -44,6 +44,10 @@ class CamBuilder:
|
|
|
44
44
|
during model inference, either by the model itself or by the preprocessing function.
|
|
45
45
|
:param ignore_channel_dim: (optional, default is False) A boolean indicating whether to ignore the channel
|
|
46
46
|
dimension. This is useful when the model expects inputs without a singleton channel dimension.
|
|
47
|
+
:param is_regression_network: (optional, default is False) A boolean indicating whether the network is designed
|
|
48
|
+
for a regression task. If set to True, the CAM will highlight both positive and negative contributions.
|
|
49
|
+
While negative contributions are typically irrelevant for classification-based saliency maps, they can be
|
|
50
|
+
meaningful in regression settings, as they may represent features that decrease the predicted value.
|
|
47
51
|
:param model_output_index: (optional, default is None) An integer index specifying which of the model's outputs
|
|
48
52
|
represents output scores (or probabilities). If there is only one output, this argument can be ignored.
|
|
49
53
|
:param extend_search: (optional, default is False) A boolean flag indicating whether to deepend the search for
|
|
@@ -67,6 +71,7 @@ class CamBuilder:
|
|
|
67
71
|
self.time_axs = time_axs
|
|
68
72
|
self.input_transposed = input_transposed
|
|
69
73
|
self.ignore_channel_dim = ignore_channel_dim
|
|
74
|
+
self.is_regression_network = is_regression_network
|
|
70
75
|
self.model_output_index = model_output_index
|
|
71
76
|
self.padding_dim = padding_dim
|
|
72
77
|
self.original_dims = []
|
|
@@ -136,7 +141,8 @@ class CamBuilder:
|
|
|
136
141
|
:param results_dir_path: (optional, default is None) A string representing the relative path to the directory
|
|
137
142
|
for storing results. If None, the output will be displayed in a figure.
|
|
138
143
|
:param aspect_factor: (optional, default is 100) A numerical value to set the aspect ratio of the output signal
|
|
139
|
-
one-dimensional CAM.
|
|
144
|
+
one-dimensional CAM. Note that this value should be grater than the length of the input signal considered,
|
|
145
|
+
otherwise it is set to the length of the considered signal.
|
|
140
146
|
:param data_shape_list: (optional, default is None) A list of integer tuples storing the original input sizes,
|
|
141
147
|
used to set the CAM shape after resizing during preprocessing. The expected format is number of rows x
|
|
142
148
|
number of columns.
|
|
@@ -648,7 +654,8 @@ class CamBuilder:
|
|
|
648
654
|
:param dt: (optional, default is 10) A numerical value representing the granularity of the time axis in seconds
|
|
649
655
|
in the output display.
|
|
650
656
|
:param aspect_factor: (optional, default is 100) A numerical value to set the aspect ratio of the output signal
|
|
651
|
-
one-dimensional CAM.
|
|
657
|
+
one-dimensional CAM. Note that this value should be grater than the length of the input signal considered,
|
|
658
|
+
otherwise it is set to the length of the considered signal.
|
|
652
659
|
:param bar_ranges: A tuple containing two np.ndarrays, corresponding to the minimum and maximum importance scores
|
|
653
660
|
per CAM for each item in the input data list, based on a given setting (defined by algorithm, target
|
|
654
661
|
layer, and target class).
|
|
@@ -674,7 +681,7 @@ class CamBuilder:
|
|
|
674
681
|
norm = self.__get_norm(map)
|
|
675
682
|
|
|
676
683
|
if map.shape[1] == 1:
|
|
677
|
-
aspect = int(map.shape[0] / aspect_factor)
|
|
684
|
+
aspect = int(map.shape[0] / aspect_factor) if map.shape[0] <= aspect_factor else 1
|
|
678
685
|
map = np.transpose(map)
|
|
679
686
|
else:
|
|
680
687
|
if is_2d_layer:
|
|
@@ -15,8 +15,8 @@ class TorchCamBuilder(CamBuilder):
|
|
|
15
15
|
|
|
16
16
|
def __init__(self, model: nn.Module | Any, transform_fn: Callable[[np.ndarray, *tuple[Any, ...]], torch.Tensor]
|
|
17
17
|
= None, class_names: List[str] = None, time_axs: int = 1, input_transposed: bool = False,
|
|
18
|
-
ignore_channel_dim: bool = False,
|
|
19
|
-
use_gpu: bool = False, padding_dim: int = None, seed: int = 11):
|
|
18
|
+
ignore_channel_dim: bool = False, is_regression_network: bool = False, model_output_index: int = None,
|
|
19
|
+
extend_search: bool = False, use_gpu: bool = False, padding_dim: int = None, seed: int = 11):
|
|
20
20
|
"""
|
|
21
21
|
Initializes the TorchCamBuilder class. The constructor also displays, if present and retrievable, the 1D- and
|
|
22
22
|
2D-convolutional layers in the network, as well as the final Sigmoid/Softmax activation. Additionally, the CAM
|
|
@@ -36,6 +36,10 @@ class TorchCamBuilder(CamBuilder):
|
|
|
36
36
|
during model inference, either by the model itself or by the preprocessing function.
|
|
37
37
|
:param ignore_channel_dim: (optional, default is False) A boolean indicating whether to ignore the channel
|
|
38
38
|
dimension. This is useful when the model expects inputs without a singleton channel dimension.
|
|
39
|
+
:param is_regression_network: (optional, default is False) A boolean indicating whether the network is designed
|
|
40
|
+
for a regression task. If set to True, the CAM will highlight both positive and negative contributions.
|
|
41
|
+
While negative contributions are typically irrelevant for classification-based saliency maps, they can be
|
|
42
|
+
meaningful in regression settings, as they may represent features that decrease the predicted value.
|
|
39
43
|
:param model_output_index: (optional, default is None) An integer index specifying which of the model's outputs
|
|
40
44
|
represents output scores (or probabilities). If there is only one output, this argument can be ignored.
|
|
41
45
|
:param extend_search: (optional, default is False) A boolean flag indicating whether to deepend the search for
|
|
@@ -52,6 +56,7 @@ class TorchCamBuilder(CamBuilder):
|
|
|
52
56
|
super(TorchCamBuilder, self).__init__(model=model, transform_fn=transform_fn, class_names=class_names,
|
|
53
57
|
time_axs=time_axs, input_transposed=input_transposed,
|
|
54
58
|
ignore_channel_dim=ignore_channel_dim,
|
|
59
|
+
is_regression_network=is_regression_network,
|
|
55
60
|
model_output_index=model_output_index, extend_search=extend_search,
|
|
56
61
|
padding_dim=padding_dim, seed=seed)
|
|
57
62
|
|
|
@@ -180,12 +185,29 @@ class TorchCamBuilder(CamBuilder):
|
|
|
180
185
|
|
|
181
186
|
if softmax_final:
|
|
182
187
|
# Approximate Softmax inversion formula logit = log(prob) + constant, as the constant is negligible
|
|
183
|
-
# during derivation
|
|
184
|
-
target_scores = torch.log(outputs)
|
|
188
|
+
# during derivation. Clamp probabilities before log application to avoid null maps for maximum confidence.
|
|
189
|
+
target_scores = torch.log(torch.clamp(outputs, min=0, max=1 - 1e-6))
|
|
185
190
|
target_probs = outputs
|
|
191
|
+
|
|
192
|
+
# Adjust results for binary network
|
|
193
|
+
if len(outputs.shape) == 1:
|
|
194
|
+
target_scores = torch.stack([-target_scores, target_scores], dim=1)
|
|
195
|
+
target_probs = torch.stack([1 - target_probs, target_probs], dim=1)
|
|
196
|
+
elif len(outputs.shape) == 2 and outputs.shape[1] == 1:
|
|
197
|
+
target_scores = torch.cat([-target_scores, target_scores], dim=1)
|
|
198
|
+
target_probs = torch.cat([1 - target_probs, target_probs], dim=1)
|
|
186
199
|
else:
|
|
200
|
+
if len(outputs.shape) == 1:
|
|
201
|
+
outputs = torch.stack([-outputs, outputs], dim=1)
|
|
202
|
+
elif len(outputs.shape) == 2 and outputs.shape[1] == 1:
|
|
203
|
+
outputs = torch.cat([-outputs, outputs], dim=1)
|
|
187
204
|
target_scores = outputs
|
|
188
|
-
|
|
205
|
+
|
|
206
|
+
if len(outputs.shape) == 2 and outputs.shape[1] > 1:
|
|
207
|
+
target_probs = torch.softmax(target_scores, dim=1)
|
|
208
|
+
else:
|
|
209
|
+
tmp = torch.sigmoid(target_scores[:, 1])
|
|
210
|
+
target_probs = torch.stack([1 - tmp, tmp], dim=1)
|
|
189
211
|
|
|
190
212
|
target_probs = target_probs[:, target_class].cpu().detach().numpy()
|
|
191
213
|
|
|
@@ -229,7 +251,8 @@ class TorchCamBuilder(CamBuilder):
|
|
|
229
251
|
activations[i, :] *= weights[i]
|
|
230
252
|
|
|
231
253
|
cam = torch.sum(activations, dim=0)
|
|
232
|
-
|
|
254
|
+
if not self.is_regression_network:
|
|
255
|
+
cam = torch.relu(cam)
|
|
233
256
|
return cam
|
|
234
257
|
|
|
235
258
|
def _get_hirescam_map(self, is_2d_layer: bool, batch_idx: int) -> torch.Tensor:
|
|
@@ -254,7 +277,8 @@ class TorchCamBuilder(CamBuilder):
|
|
|
254
277
|
activations[i, :] *= gradients[i, :]
|
|
255
278
|
|
|
256
279
|
cam = torch.sum(activations, dim=0)
|
|
257
|
-
|
|
280
|
+
if not self.is_regression_network:
|
|
281
|
+
cam = torch.relu(cam)
|
|
258
282
|
return cam
|
|
259
283
|
|
|
260
284
|
def __get_activation_forward_hook(self, layer: nn.Module, inputs: Tuple[torch.Tensor, ...], outputs: torch.Tensor) \
|
|
@@ -20,8 +20,8 @@ class TfCamBuilder(CamBuilder):
|
|
|
20
20
|
|
|
21
21
|
def __init__(self, model: tf.keras.Model | Any, transform_fn: Callable[[np.ndarray, *tuple[Any, ...]], tf.Tensor]
|
|
22
22
|
= None, class_names: List[str] = None, time_axs: int = 1, input_transposed: bool = False,
|
|
23
|
-
ignore_channel_dim: bool = False,
|
|
24
|
-
padding_dim: int = None, seed: int = 11):
|
|
23
|
+
ignore_channel_dim: bool = False, is_regression_network: bool = False, model_output_index: int = None,
|
|
24
|
+
extend_search: bool = False, padding_dim: int = None, seed: int = 11):
|
|
25
25
|
"""
|
|
26
26
|
Initializes the TfCamBuilder class. The constructor also displays, if present and retrievable, the 1D- and
|
|
27
27
|
2D-convolutional layers in the network, as well as the final Sigmoid/Softmax activation. Additionally, the CAM
|
|
@@ -41,6 +41,10 @@ class TfCamBuilder(CamBuilder):
|
|
|
41
41
|
during model inference, either by the model itself or by the preprocessing function.
|
|
42
42
|
:param ignore_channel_dim: (optional, default is False) A boolean indicating whether to ignore the channel
|
|
43
43
|
dimension. This is useful when the model expects inputs without a singleton channel dimension.
|
|
44
|
+
:param is_regression_network: (optional, default is False) A boolean indicating whether the network is designed
|
|
45
|
+
for a regression task. If set to True, the CAM will highlight both positive and negative contributions.
|
|
46
|
+
While negative contributions are typically irrelevant for classification-based saliency maps, they can be
|
|
47
|
+
meaningful in regression settings, as they may represent features that decrease the predicted value.
|
|
44
48
|
:param model_output_index: (optional, default is None) An integer index specifying which of the model's outputs
|
|
45
49
|
represents output scores (or probabilities). If there is only one output, this argument can be ignored.
|
|
46
50
|
:param extend_search: (optional, default is False) A boolean flag indicating whether to deepend the search for
|
|
@@ -54,7 +58,9 @@ class TfCamBuilder(CamBuilder):
|
|
|
54
58
|
# Initialize attributes
|
|
55
59
|
super(TfCamBuilder, self).__init__(model=model, transform_fn=transform_fn, class_names=class_names,
|
|
56
60
|
time_axs=time_axs, input_transposed=input_transposed,
|
|
57
|
-
ignore_channel_dim=ignore_channel_dim,
|
|
61
|
+
ignore_channel_dim=ignore_channel_dim,
|
|
62
|
+
is_regression_network=is_regression_network,
|
|
63
|
+
model_output_index=model_output_index,
|
|
58
64
|
extend_search=extend_search, padding_dim=padding_dim, seed=seed)
|
|
59
65
|
|
|
60
66
|
# Set seeds
|
|
@@ -189,17 +195,35 @@ class TfCamBuilder(CamBuilder):
|
|
|
189
195
|
|
|
190
196
|
grad_model = keras.models.Model(self.model.inputs, [target_layer.output, self.model.output])
|
|
191
197
|
extra_inputs_list = extra_inputs_list or []
|
|
192
|
-
with tf.GradientTape() as tape:
|
|
198
|
+
with (tf.GradientTape() as tape):
|
|
193
199
|
self.activations, outputs = grad_model([data_batch] + extra_inputs_list)
|
|
194
200
|
|
|
195
201
|
if softmax_final:
|
|
196
202
|
# Approximate Softmax inversion formula logit = log(prob) + constant, as the constant is negligible
|
|
197
|
-
# during derivation
|
|
198
|
-
|
|
203
|
+
# during derivation. Clamp probabilities before log application to avoid null maps for maximum
|
|
204
|
+
# confidence.
|
|
205
|
+
target_scores = tf.math.log(tf.clip_by_value(outputs, 0, 1.0 - 1e-6))
|
|
199
206
|
target_probs = outputs
|
|
207
|
+
|
|
208
|
+
# Adjust results for binary network
|
|
209
|
+
if len(outputs.shape) == 1:
|
|
210
|
+
target_scores = tf.stack([-target_scores, target_scores], axis=1)
|
|
211
|
+
target_probs = tf.stack([1 - target_probs, target_probs], axis=1)
|
|
212
|
+
elif len(outputs.shape) == 2 and outputs.shape[1] == 1:
|
|
213
|
+
target_scores = tf.concat([-target_scores, target_scores], axis=1)
|
|
214
|
+
target_probs = tf.concat([1 - target_probs, target_probs], axis=1)
|
|
200
215
|
else:
|
|
216
|
+
if len(outputs.shape) == 1:
|
|
217
|
+
outputs = tf.stack([-outputs, outputs], axis=1)
|
|
218
|
+
elif len(outputs.shape) == 2 and outputs.shape[1] == 1:
|
|
219
|
+
outputs = tf.concat([-outputs, outputs], axis=1)
|
|
201
220
|
target_scores = outputs
|
|
202
|
-
|
|
221
|
+
|
|
222
|
+
if len(outputs.shape) == 2 and outputs.shape[1] > 1:
|
|
223
|
+
target_probs = tf.nn.softmax(target_scores, axis=1)
|
|
224
|
+
else:
|
|
225
|
+
tmp = tf.math.sigmoid(target_scores[:, 1])
|
|
226
|
+
target_probs = tf.stack([1 - tmp, tmp], axis=1)
|
|
203
227
|
|
|
204
228
|
target_scores = target_scores[:, target_class]
|
|
205
229
|
target_probs = target_probs[:, target_class]
|
|
@@ -243,7 +267,8 @@ class TfCamBuilder(CamBuilder):
|
|
|
243
267
|
activations[:, i] *= weights[i]
|
|
244
268
|
|
|
245
269
|
cam = tf.reduce_sum(tf.convert_to_tensor(activations), axis=-1)
|
|
246
|
-
|
|
270
|
+
if not self.is_regression_network:
|
|
271
|
+
cam = tf.nn.relu(cam)
|
|
247
272
|
return cam
|
|
248
273
|
|
|
249
274
|
def _get_hirecam_map(self, is_2d_layer: bool, batch_idx: int) -> tf.Tensor:
|
|
@@ -268,7 +293,8 @@ class TfCamBuilder(CamBuilder):
|
|
|
268
293
|
activations[:, i] *= gradients[:, i]
|
|
269
294
|
|
|
270
295
|
cam = tf.reduce_sum(tf.convert_to_tensor(activations), axis=-1)
|
|
271
|
-
|
|
296
|
+
if not self.is_regression_network:
|
|
297
|
+
cam = tf.nn.relu(cam)
|
|
272
298
|
return cam
|
|
273
299
|
|
|
274
300
|
@staticmethod
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: signal-grad-cam
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: SignalGrad-CAM aims at generalising Grad-CAM to one-dimensional applications, while enhancing usability and efficiency.
|
|
5
5
|
Home-page: https://github.com/samuelepe11/signal_grad_cam
|
|
6
6
|
Author: Samuele Pe
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{signal_grad_cam-0.1.1 → signal_grad_cam-0.1.3}/signal_grad_cam.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|