From 9eef9c407af31c47edc346029fac54bb1f97a4aa Mon Sep 17 00:00:00 2001 From: Qiushen Wang Date: Mon, 4 Dec 2023 20:10:52 -0800 Subject: [PATCH 1/4] Prevent none gradient when there is input has not impact to the traget --- alibi/explainers/integrated_gradients.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/alibi/explainers/integrated_gradients.py b/alibi/explainers/integrated_gradients.py index d2726a8ca..a74a0ac2b 100644 --- a/alibi/explainers/integrated_gradients.py +++ b/alibi/explainers/integrated_gradients.py @@ -400,6 +400,10 @@ def _gradients_input(model: Union[tf.keras.models.Model], grads = tape.gradient(preds, x) + # if there are inputs have not impact to the output, the gradient is None, but we need to return a tensor + for idx, grad in enumerate(grads): + if grad is None: + grads[idx] = tf.convert_to_tensor(np.zeros(x[idx].shape), dtype=x[idx].dtype) return grads @@ -497,7 +501,10 @@ def wrapper(*args, **kwargs): grads = tape.gradient(preds, layer.inp) else: grads = tape.gradient(preds, layer.result) - + # if there are inputs have not impact to the output, the gradient is None, but we need to return a tensor + for idx, grad in enumerate(grads): + if grad is None: + grads[idx] = tf.convert_to_tensor(np.zeros(x[idx].shape), dtype=x[idx].dtype) delattr(layer, 'inp') delattr(layer, 'result') layer.call = orig_call From c9f653fdd827a7d940314ae34eeed92ff708848a Mon Sep 17 00:00:00 2001 From: Qiushen Wang Date: Mon, 4 Dec 2023 20:20:50 -0800 Subject: [PATCH 2/4] get shape from x based on x's type --- alibi/explainers/integrated_gradients.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/alibi/explainers/integrated_gradients.py b/alibi/explainers/integrated_gradients.py index a74a0ac2b..a42d9853e 100644 --- a/alibi/explainers/integrated_gradients.py +++ b/alibi/explainers/integrated_gradients.py @@ -401,9 +401,13 @@ def _gradients_input(model: Union[tf.keras.models.Model], grads = tape.gradient(preds, x) # if there are inputs have not impact to the output, the gradient is None, but we need to return a tensor + if isinstance(x, list): + shape = x[0].shape + else: + shape = x.shape for idx, grad in enumerate(grads): if grad is None: - grads[idx] = tf.convert_to_tensor(np.zeros(x[idx].shape), dtype=x[idx].dtype) + grads[idx] = tf.convert_to_tensor(np.zeros(shape), dtype=x[idx].dtype) return grads @@ -502,9 +506,13 @@ def wrapper(*args, **kwargs): else: grads = tape.gradient(preds, layer.result) # if there are inputs have not impact to the output, the gradient is None, but we need to return a tensor + if isinstance(x, list): + shape = x[0].shape + else: + shape = x.shape for idx, grad in enumerate(grads): if grad is None: - grads[idx] = tf.convert_to_tensor(np.zeros(x[idx].shape), dtype=x[idx].dtype) + grads[idx] = tf.convert_to_tensor(np.zeros(shape), dtype=x[idx].dtype) delattr(layer, 'inp') delattr(layer, 'result') layer.call = orig_call From 408f12d2bbf3760fa48d2a17ca8e5d7f5d8feb19 Mon Sep 17 00:00:00 2001 From: Qiushen Wang Date: Tue, 5 Dec 2023 21:26:27 -0800 Subject: [PATCH 3/4] Change to only fix none gradient when x is list --- alibi/explainers/integrated_gradients.py | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/alibi/explainers/integrated_gradients.py b/alibi/explainers/integrated_gradients.py index a42d9853e..61c6eb452 100644 --- a/alibi/explainers/integrated_gradients.py +++ b/alibi/explainers/integrated_gradients.py @@ -402,12 +402,9 @@ def _gradients_input(model: Union[tf.keras.models.Model], # if there are inputs have not impact to the output, the gradient is None, but we need to return a tensor if isinstance(x, list): - shape = x[0].shape - else: - shape = x.shape - for idx, grad in enumerate(grads): - if grad is None: - grads[idx] = tf.convert_to_tensor(np.zeros(shape), dtype=x[idx].dtype) + for idx, grad in enumerate(grads): + if grad is None: + grads[idx] = tf.convert_to_tensor(np.zeros(x[0].shape), dtype=x[idx].dtype) return grads @@ -507,12 +504,9 @@ def wrapper(*args, **kwargs): grads = tape.gradient(preds, layer.result) # if there are inputs have not impact to the output, the gradient is None, but we need to return a tensor if isinstance(x, list): - shape = x[0].shape - else: - shape = x.shape - for idx, grad in enumerate(grads): - if grad is None: - grads[idx] = tf.convert_to_tensor(np.zeros(shape), dtype=x[idx].dtype) + for idx, grad in enumerate(grads): + if grad is None: + grads[idx] = tf.convert_to_tensor(np.zeros(x[0].shape), dtype=x[idx].dtype) delattr(layer, 'inp') delattr(layer, 'result') layer.call = orig_call From 8dd5883427866336d247a14570c488b362644cc1 Mon Sep 17 00:00:00 2001 From: Qiushen Wang Date: Tue, 5 Dec 2023 21:41:05 -0800 Subject: [PATCH 4/4] fix comment and change to use x[idx] instead of x[0] --- alibi/explainers/integrated_gradients.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/alibi/explainers/integrated_gradients.py b/alibi/explainers/integrated_gradients.py index 61c6eb452..96953da7f 100644 --- a/alibi/explainers/integrated_gradients.py +++ b/alibi/explainers/integrated_gradients.py @@ -400,11 +400,11 @@ def _gradients_input(model: Union[tf.keras.models.Model], grads = tape.gradient(preds, x) - # if there are inputs have not impact to the output, the gradient is None, but we need to return a tensor + # If certain inputs don't impact the target, the gradient is None, but we need to return a tensor if isinstance(x, list): for idx, grad in enumerate(grads): if grad is None: - grads[idx] = tf.convert_to_tensor(np.zeros(x[0].shape), dtype=x[idx].dtype) + grads[idx] = tf.convert_to_tensor(np.zeros(x[idx].shape), dtype=x[idx].dtype) return grads @@ -502,11 +502,11 @@ def wrapper(*args, **kwargs): grads = tape.gradient(preds, layer.inp) else: grads = tape.gradient(preds, layer.result) - # if there are inputs have not impact to the output, the gradient is None, but we need to return a tensor + # If certain inputs don't impact the target, the gradient is None, but we need to return a tensor if isinstance(x, list): for idx, grad in enumerate(grads): if grad is None: - grads[idx] = tf.convert_to_tensor(np.zeros(x[0].shape), dtype=x[idx].dtype) + grads[idx] = tf.convert_to_tensor(np.zeros(x[idx].shape), dtype=x[idx].dtype) delattr(layer, 'inp') delattr(layer, 'result') layer.call = orig_call