def initialize(self, context): super().initialize(context) self.ig = IntegratedGradients(self.model) self.initialized = True properties = context.system_properties if not properties.get("limit_max_image_pixels"): Image.MAX_IMAGE_PIXELS = None
def integrated_gradients(self, dataset, file): self.model.load_state_dict(torch.load(file)) x, y, _ = self._str2dataset(dataset) baselines = np.zeros(x.shape) names = self.input_names for i in range(len(names)): if names[i] == "glucose": mean = np.mean(y) baselines[:, :, i] = mean * np.ones(x.shape[0:2]) # if names[i] == "mets": # baselines[:, :, i] = mean * np.ones(x.shape[0:2]) x = torch.Tensor(x).cuda() x.requires_grad_() baselines = torch.Tensor(baselines).cuda() self.model.train() ig = IntegratedGradients(self.model) attr = [] for i in range(len(x) // 10): attr_i = ig.attribute(x[i * 10:(i + 1) * 10], baselines=baselines[i * 10:(i + 1) * 10], n_steps=50) attr.append(attr_i.cpu().detach().numpy()) attr_i = ig.attribute(x[(i + 1) * 10:len(x)], baselines=baselines[(i + 1) * 10:len(x)], n_steps=50) attr.append(attr_i.cpu().detach().numpy()) attr = np.concatenate(attr, axis=0) return attr
def get_attributions_to_interpret_all_positive_in_test(dataset_dir, pathway_dir, drug_ids_path, outdir, best_model_path, norm, do_layers, batchnorm, num_layers, hidden_gcn, hidden_fc, splits_dir, in_channels, n_classes, feature_names_path, model_type, k_hops, n_steps = 100): model, samples_of_interest, loader, feature_names, device = preparing_data_all_positive_in_test(dataset_dir, pathway_dir, drug_ids_path, outdir, best_model_path, norm, do_layers, batchnorm, num_layers, hidden_gcn, hidden_fc, splits_dir, in_channels, n_classes, feature_names_path, model_type, k_hops) #######Computing attributions # print('OUTDIR', outdir) scaler = MinMaxScaler() model.eval() ig = IntegratedGradients(model) attributions_list = [] for sample in samples_of_interest: sample = sample.to(device) baseline = torch.tensor(0 * sample.x, requires_grad=True) sample.x = torch.tensor(sample.x, requires_grad=True) attributions, delta = ig.attribute(sample.x.view(1, -1, 1), baselines=baseline.view(1, -1, 1), additional_forward_args=(torch.tensor([0], device=device)), target=1, return_convergence_delta=True, internal_batch_size=1, n_steps=n_steps) attributions_list.append(scaler.fit_transform(attributions.detach().cpu().numpy().squeeze().reshape(-1,1)).reshape(1,-1)) # print('IG Attributions:', attributions) # log_handle = open(outdir+'/log_get_attributions_to_interpret.txt', 'w') # scores = model(baseline.view(1, -1, 1), torch.tensor([0], device=device)).detach().cpu().numpy()[0] # log_handle.write('n_steps\t{}\n'.format(n_steps)) # log_handle.write('Baseline score\tDelta\t:{}\t{}\t{}\n'.format(scores[0], scores[1],delta.item())) # log_handle.close() # Creates output dataframe # attributions_list = scaler.fit_transform(np.array(attributions_list).squeeze().reshape(-1,1)).reshape(1,-1) attributions = pd.DataFrame(np.vstack(attributions_list)) attributions.columns = feature_names return attributions
def explain(method, device, model, data): def model_forward(edge_mask, device, data, model): batch = torch.zeros(data.x.shape[0], dtype=int).to(device) out = model(data.x, data.edge_index, batch, edge_mask) return out data = data.to(device) target = data.y.to(device) input_mask = torch.ones(data.edge_index.shape[1]).requires_grad_(True).to(device) if method == 'ig': ig = IntegratedGradients(model_forward) mask = ig.attribute(input_mask, target=target, additional_forward_args=(data,), internal_batch_size=data.edge_index.shape[1]) elif method == 'saliency': saliency = Saliency(model_forward) mask = saliency.attribute(input_mask, target=target, additional_forward_args=(device, data, model)) else: raise Exception('Unknown explanation method') edge_mask = np.abs(mask.cpu().detach().numpy()) if edge_mask.max() > 0: # avoid division by zero edge_mask = edge_mask / edge_mask.max() edge_mask_dict = defaultdict(float) for val, u, v in list(zip(edge_mask, *data.edge_index)): u, v = u.item(), v.item() edge_mask_dict[(u, v)] += val return edge_mask_dict
def _get_attributions(self, enc_data, metric, n_steps, nt_type, baseline_type, strides, sliding_window_shapes): # Get Baseline baseline = self.get_baseline_img(enc_data[0], baseline_type) supported_metrics = {} if metric == 'IG': self._integrated_gradients = self._integrated_gradients if hasattr( self, '_integrated_gradients') else IntegratedGradients( self.model) return self._integrated_gradients.attribute(enc_data[0], baseline, target=enc_data[1], n_steps=200) elif metric == 'NT': self._integrated_gradients = self._integrated_gradients if hasattr( self, '_integrated_gradients') else IntegratedGradients( self.model) self._noise_tunnel = self._noise_tunnel if hasattr( self, '_noise_tunnel') else NoiseTunnel( self._integrated_gradients) return self._noise_tunnel.attribute(enc_data[0].to( self.dls.device), n_samples=1, nt_type=nt_type, target=enc_data[1]) elif metric == 'Occl': self._occlusion = self._occlusion if hasattr( self, '_occlusion') else Occlusion(self.model) return self._occlusion.attribute( enc_data[0].to(self.dls.device), strides=strides, target=enc_data[1], sliding_window_shapes=sliding_window_shapes, baselines=baseline)
def test_basic_infidelity_multiple_with_normalize(self) -> None: input1 = torch.tensor([3.0] * 3) input2 = torch.tensor([1.0] * 3) inputs = (input1, input2) expected = torch.zeros(3) model = BasicModel2() ig = IntegratedGradients(model) attrs = ig.attribute(inputs) scaled_attrs = tuple(attr * 100 for attr in attrs) infid = self.infidelity_assert(model, attrs, inputs, expected, normalize=True) scaled_infid = self.infidelity_assert( model, scaled_attrs, inputs, expected, normalize=True, ) # scaling attr should not change normalized infidelity assertTensorAlmostEqual(self, infid, scaled_infid)
def get_single_experiment_scores(path_to_net, X_input): X_input = torch.from_numpy(X_input) X_input = X_input.float() X_input = X_input.permute(0, 2, 1).contiguous() # --- Preparing the model --- use_gpu = torch.cuda.is_available() CNN = Multiple_Input_Model() if use_gpu: CNN = torch.nn.DataParallel(CNN, device_ids=[0]) X_input = X_input.to(DEVICE_ID) # --- Loading net and getting metrics --- CNN, start_epoch, valid_loss_min = load_net(path_to_net, CNN) CNN.eval() ig = IntegratedGradients(CNN) # ig = DeepLift(CNN) attributions, delta = ig.attribute(X_input, target=1, return_convergence_delta=True) attributions = attributions.cpu().numpy() return attributions
def predict_step(self, batch, batch_idx, dataloader_idx=0): """IG wrapped in predict_step for multi-GPU scaling via Trainer.predict()""" ig = IntegratedGradients(self.predict) attributions, delta = ig.attribute(tuple(batch), method='gausslegendre', return_convergence_delta=True) return attributions, delta
def basic_model_assert( self, model: Module, inputs: TensorOrTupleOfTensorsGeneric, expected: Tensor, n_perturb_samples: int = 10, max_batch_size: int = None, perturb_func: Callable = _local_perturb_func, multiply_by_inputs: bool = False, normalize: bool = False, ) -> Tensor: ig = IntegratedGradients(model) if multiply_by_inputs: attrs = cast( TensorOrTupleOfTensorsGeneric, tuple(attr / input for input, attr in zip(inputs, ig.attribute(inputs))), ) else: attrs = ig.attribute(inputs) return self.infidelity_assert( model, attrs, inputs, expected, n_perturb_samples=n_perturb_samples, max_batch_size=max_batch_size, perturb_func=perturb_func, normalize=normalize, )
def get_token_wise_attributions( fn, model, embedding_outputs, attention_masks, name, position, token_index, n_steps, internal_batch_size=4, method="riemann_right", ): int_grad = IntegratedGradients( fn, multiply_by_inputs=True, ) attributions, approximation_error = int_grad.attribute( embedding_outputs, target=token_index, n_steps=n_steps, method=method, additional_forward_args=(model, attention_masks, name, position), internal_batch_size=internal_batch_size, return_convergence_delta=True, ) return { "attributions": attributions, "delta": approximation_error, }
def PT_IntegratedGradient(model, x, y_onthot, baseline=None, n_steps=50, method='riemann_trapezoid', device='cuda:0', **kwargs): input = torch.tensor(x, requires_grad=True).to(device) model = model.to(device) model.eval() saliency = IntegratedGradients(model) target = torch.tensor(np.argmax(y_onthot, -1)).to(device) if baseline is not None: baseline = torch.tensor(baseline).to(device) # if method == Riemann.trapezoid: # return list(np.linspace(0, 1, n)) # elif method == Riemann.left: # return list(np.linspace(0, 1 - 1 / n, n)) # elif method == Riemann.middle: # return list(np.linspace(1 / (2 * n), 1 - 1 / (2 * n), n)) # elif method == Riemann.right: # return list(np.linspace(1 / n, 1, n)) # Ref: https://github.com/pytorch/captum/blob/master/captum/attr/_utils/approximation_methods.py attribution_map = saliency.attribute(input, target=target, baselines=baseline, n_steps=n_steps, method=method) return attribution_map.detach().cpu().numpy()
def _calculate_attribution( self, net: Module, baselines: Optional[List[Tuple[Tensor, ...]]], data: Tuple[Tensor, ...], additional_forward_args: Optional[Tuple[Tensor, ...]], label: Optional[Union[Tensor]], ) -> Tensor: ig = IntegratedGradients(net) # TODO support multiple baselines baseline = baselines[0] if len(baselines) > 0 else None label = ( None if not self._use_label_for_attr or label is None or label.nelement() == 0 else label ) attr_ig = ig.attribute( data, baselines=baseline, additional_forward_args=additional_forward_args, target=label, n_steps=self._config.steps, ) return attr_ig
def explain_handle(self, model_wraper, text, target=1): # pylint: disable=too-many-locals,unused-argument,arguments-differ """Captum explanations handler. Args: data_preprocess (Torch Tensor): Preprocessed data to be used for captum raw_data (list): The unprocessed data to get target from the request Returns: dict : A dictionary response with the explanations response. """ model_wrapper = AGNewsmodelWrapper(self.model) tokenizer = BertTokenizer(self.vocab_file) model_wrapper.eval() model_wrapper.zero_grad() input_ids = torch.tensor( [tokenizer.encode(self.text, add_special_tokens=True)]) input_embedding_test = model_wrapper.model.bert_model.embeddings( input_ids) preds = model_wrapper(input_embedding_test) out = np.argmax(preds.cpu().detach(), axis=1) out = out.item() ig_1 = IntegratedGradients(model_wrapper) attributions, delta = ig_1.attribute( # pylint: disable=no-member input_embedding_test, n_steps=500, return_convergence_delta=True, target=1, ) tokens = tokenizer.convert_ids_to_tokens(input_ids[0].numpy().tolist()) feature_imp_dict = {} feature_imp_dict["words"] = tokens attributions_sum = self.summarize_attributions(attributions) feature_imp_dict["importances"] = attributions_sum.tolist() feature_imp_dict["delta"] = delta[0].tolist() return [feature_imp_dict]
def basic_model_assert( self, model, inputs, expected, n_perturb_samples=10, max_batch_size=None, perturb_func=_local_perturb_func, local=True, ): ig = IntegratedGradients(model) if local: attrs = tuple(attr / input for input, attr in zip(inputs, ig.attribute(inputs))) else: attrs = ig.attribute(inputs) return self.infidelity_assert( model, attrs, inputs, expected, n_perturb_samples=n_perturb_samples, max_batch_size=max_batch_size, perturb_func=perturb_func, )
def feature_conductance(test_input_tensor): ig = IntegratedGradients(net) test_input_tensor.requires_grad_() attr, _ = ig.attribute(test_input_tensor, target=1, return_convergence_delta=True) attr = attr.detach().numpy() # To understand these attributions, we can first average them across all the inputs # and print and visualize the average attribution for each feature. feature_imp, feature_imp_dict = visualize_importances(feature_names, np.mean(attr, axis=0)) mlflow.log_metrics(feature_imp_dict) mlflow.log_text(str(feature_imp), "feature_imp_summary.txt") fig, (ax1, ax2) = plt.subplots(2, 1) fig.tight_layout(pad=3) ax1.hist(attr[:, 1], 100) ax1.set(title="Distribution of Sibsp Attribution Values") # we can bucket the examples by the value of the sibsp feature and # plot the average attribution for the feature. # In the plot below, the size of the dot is proportional to # the number of examples with that value. bin_means, bin_edges, _ = stats.binned_statistic( test_features[:, 1], attr[:, 1], statistic="mean", bins=6 ) bin_count, _, _ = stats.binned_statistic( test_features[:, 1], attr[:, 1], statistic="count", bins=6 ) bin_width = bin_edges[1] - bin_edges[0] bin_centers = bin_edges[1:] - bin_width / 2 ax2.scatter(bin_centers, bin_means, s=bin_count) ax2.set(xlabel="Average Sibsp Feature Value", ylabel="Average Attribution") mlflow.log_figure(fig, "Average_Sibsp_Feature_Value.png")
def explain_ig(model, x, edge_index, target, include_edges=None): ig = IntegratedGradients(model_forward) input_mask = torch.ones(edge_index.shape[1]).requires_grad_(True).to(device) ig_mask = ig.attribute(input_mask, target=target, additional_forward_args=(model, x, edge_index), internal_batch_size=edge_index.shape[1]) edge_mask = ig_mask.cpu().detach().numpy() return edge_mask
def integrated_gradients(self, xs, labels, baselines): attributor = IntegratedGradients(self) # BS, T, C if baselines is not None and baselines.ndim == 2: baselines = baselines.unsqueeze(0) attributions = attributor.attribute(xs, target=labels, baselines=baselines) attributions = attributions.mean(dim=-1) return attributions
def setup(self, model): #setup a captum wrapper model based on bert self.device = torch.device('cuda:{}'.format( self.opt.gpu_ids[0])) if self.opt.gpu_ids else torch.device( 'cpu') # get device name: CPU or GPU self.bert_model_wrapper = BertModelWrapper(self.opt, model) self.bert_model_wrapper.to(self.device) self.ig = IntegratedGradients(self.bert_model_wrapper) self.isDefined = True
def _compute_attributions( self, single_forward_output: Dict[str, numpy.ndarray], instance: Instance, n_steps: int = 50, ) -> List[List[Attribution]]: """Attributes the prediction to the input. The attributions are calculated by means of the [Integrated Gradients](https://arxiv.org/abs/1703.01365) method. Parameters ---------- single_forward_output Non-batched forward output containing numpy arrays instance The instance containing the input data n_steps The number of steps used when calculating the attribution of each token. Returns ------- attributions A list of list of attributions due to the the ListField level """ # captum needs `torch.Tensor`s and we need a batch dimension (-> unsqueeze) embeddings = torch.from_numpy( single_forward_output["embeddings"]).unsqueeze(0) mask = torch.from_numpy(single_forward_output["mask"]).unsqueeze(0) logits = torch.from_numpy(single_forward_output["logits"]).unsqueeze(0) ig = IntegratedGradients(self._encoder_and_head_forward) attributions, delta = ig.attribute( embeddings, n_steps=n_steps, target=torch.argmax(logits), additional_forward_args=mask, return_convergence_delta=True, ) attributions = attributions.sum(dim=3).squeeze(0) attributions = attributions / torch.norm(attributions) attributions = attributions.detach().numpy() document_tokens = [ cast(TextField, text_field).tokens for text_field in cast( ListField, instance.get(self.forward_arg_name)) ] return [[ Attribution( text=token.text, start=token.idx, end=self._get_token_end(token), field=self.forward_arg_name, attribution=attribution, ) for token, attribution in zip(sentence_tokens, sentence_attributions) ] for sentence_tokens, sentence_attributions in zip( document_tokens, attributions)]
def explain_ig_node(model, x, edge_index, target, include_edges=None): ig = IntegratedGradients(model_forward_node) input_mask = x.clone().requires_grad_(True).to(device) ig_mask = ig.attribute(input_mask, target=target, additional_forward_args=(model, edge_index), internal_batch_size=input_mask.shape[0]) node_attr = ig_mask.cpu().detach().numpy().sum(axis=1) edge_mask = node_attr_to_edge(edge_index, node_attr) return edge_mask
def compute_integrated_gradients(model, preprocessed_image, label, baseline=None): saliency = IntegratedGradients(model).attribute(preprocessed_image, target=label, n_steps=35) grad = saliency.detach().cpu().clone().numpy().squeeze() return grad
def integrated_gradient_differential(net, input, target, adata, n_genes=None, target_class=1, clip="abs", save_name="feature_gradients", ig_pval=0.05, ig_fc=1, method="wilcoxon", batch_size=100): # Caculate integrated gradient ig = IntegratedGradients(net) df_results = {} attr, delta = ig.attribute(input, target=target_class, return_convergence_delta=True, internal_batch_size=batch_size) attr = attr.detach().cpu().numpy() if clip == 'positive': attr = np.clip(attr, a_min=0, a_max=None) elif clip == 'negative': attr = abs(np.clip(attr, a_min=None, a_max=0)) else: attr = abs(attr) igadata = sc.AnnData(attr) igadata.var.index = adata.var.index igadata.obs.index = adata.obs.index igadata.obs['sensitive'] = target igadata.obs['sensitive'] = igadata.obs['sensitive'].astype('category') sc.tl.rank_genes_groups(igadata, 'sensitive', method=method, n_genes=n_genes) for label in [0, 1]: try: df_degs = ut.get_de_dataframe(igadata, label) df_degs = df_degs.loc[(df_degs.pvals_adj < ig_pval) & (df_degs.logfoldchanges >= ig_fc)] df_degs.to_csv("saved/results/DIG_class_" + str(target_class) + "_" + str(label) + save_name + '.csv') df_results[label] = df_degs except: logging.warning("Only one class, no two calsses critical genes") return adata, igadata, list(df_results[0].names), list(df_results[1].names)
class FilterConfig(NamedTuple): attribution_method: str = IntegratedGradients.get_name() attribution_arguments: Dict[str, Any] = { arg: config.value for arg, config in ATTRIBUTION_METHOD_CONFIG[ IntegratedGradients.get_name()].items() } prediction: str = "all" classes: List[str] = [] count: int = 4
class FilterConfig(NamedTuple): attribution_method: str = IntegratedGradients.get_name() # issue with mypy github.com/python/mypy/issues/8376 attribution_arguments: Dict[str, Any] = { arg: config.value # type: ignore for arg, config in ATTRIBUTION_METHOD_CONFIG[ IntegratedGradients.get_name()].params.items() } prediction: str = "all" classes: List[str] = [] num_examples: int = 4
def explain_prediction( self, prediction: Dict[str, numpy.array], instance: Instance, n_steps: int ) -> Dict[str, Any]: """Here, we must apply transformations for manage ListFields tensors shapes""" dataset = Batch([instance]) input_tokens_ids = dataset.as_tensor_dict() ig = IntegratedGradients(self._explain_embeddings) num_wrapping_dims = 1 document_tokens = [ [token.text for token in cast(TextField, text_field).tokens] for text_field in cast(ListField, instance.get(self.forward_arg_name)) ] document_tensors = input_tokens_ids.get(self.forward_arg_name) mask = get_text_field_mask( document_tensors, num_wrapping_dims=num_wrapping_dims ) text_embeddings = self.backbone.embedder.forward( document_tensors, num_wrapping_dims=num_wrapping_dims ) label_id = vocabulary.index_for_label( self.backbone.vocab, prediction.get(self.label_name) ) attributions, delta = ig.attribute( text_embeddings, target=label_id, additional_forward_args=mask, return_convergence_delta=True, n_steps=n_steps, ) attributions = attributions.sum(dim=3).squeeze(0) attributions = attributions / torch.norm(attributions) attributions = attributions.detach().numpy() return { **prediction, "explain": { self.forward_arg_name: [ [ {"token": token, "attribution": attribution} for token, attribution in zip( sentence_tokens, sentence_attribution ) ] for sentence_tokens, sentence_attribution in zip( document_tokens, attributions ) ] }, }
def visualizations(model, smile, feature_list, color_map=plt.cm.bwr): model.eval() adjacency, nodes, edges = smile_to_graph(smile) mols = Chem.MolFromSmiles(smile) ig = IntegratedGradients(model) adjacency, nodes, edges = molgraph_collate_fn( ((adjacency, nodes, edges), )) attr = ig.attribute(nodes, additional_forward_args=(edges, adjacency), target=0) attr1 = torch.squeeze(attr, dim=0) attr2 = attr1.sum(dim=1) vmax = max(attr2.abs().max(), 1e-16) vmin = -vmax node_colors = get_colors(attr1, color_map) node_colors = node_colors[:, :3] fig, ax = plt.subplots(figsize=(6, 1)) fig.subplots_adjust(bottom=0.5) norm = plt.Normalize(vmin, vmax) fig.colorbar(cm.ScalarMappable(norm=norm, cmap=color_map), cax=ax, orientation='horizontal', label='color_bar') b = BytesIO() b.write( moltopng(mols, node_colors=node_colors, edge_colors={}, molSize=(600, 600))) b.seek(0) display(Image.open(b)) b.close() symbols = { i: f'{mols.GetAtomWithIdx(i).GetSymbol()}{i}' for i in range(mols.GetNumAtoms()) } x_pos = (np.arange(len(feature_list))) y_pos = (np.arange(len(list(symbols.values())))) plt.matshow(attr1, cmap=color_map) plt.xticks(x_pos, feature_list, rotation='vertical') plt.yticks(y_pos, list(symbols.values())) plt.show() visualize_importances(list(symbols.values()), attr2)
def compute_integrated_gradients(self, img_path, target): # open image img, transformed_img, input = self.open_image(img_path) integrated_gradients = IntegratedGradients(self.model) attributions_ig = integrated_gradients.attribute(input, target=target, n_steps=200) attributions_ig = np.transpose( attributions_ig.squeeze().cpu().detach().numpy(), (1, 2, 0)) return attributions_ig
def test_classification_infidelity_tpl_target_w_baseline(self) -> None: model = BasicModel_MultiLayer() input = torch.arange(1.0, 13.0).view(4, 3) baseline = torch.ones(4, 3) additional_forward_args = (torch.arange(1, 13).view(4, 3).float(), True) targets: List = [(0, 1, 1), (0, 1, 1), (1, 1, 1), (0, 1, 1)] ig = IntegratedGradients(model) def perturbed_func2(inputs, baselines): return torch.ones(baselines.shape), baselines @infidelity_perturb_func_decorator(True) def perturbed_func3(inputs, baselines): return baselines attr, delta = ig.attribute( input, target=targets, additional_forward_args=additional_forward_args, baselines=baseline, return_convergence_delta=True, ) infid = self.infidelity_assert( model, attr, input, torch.tensor([0.10686, 0.0, 0.0, 0.0]), additional_args=additional_forward_args, baselines=baseline, target=targets, multi_input=False, n_perturb_samples=3, perturb_func=perturbed_func3, ) infid2 = self.infidelity_assert( model, attr, input, torch.tensor([0.10686, 0.0, 0.0, 0.0]), additional_args=additional_forward_args, baselines=baseline, target=targets, multi_input=False, n_perturb_samples=3, perturb_func=perturbed_func2, ) assertTensorAlmostEqual(self, infid, delta * delta) assertTensorAlmostEqual(self, infid, infid2)
def get_integrated_gradients_attribution_with_prediction( model: nn.Module, image: np.ndarray): torch.manual_seed(0) np.random.seed(0) transform_normalize = transforms.Compose([ transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ]) input_tensor = transform_normalize(image) input_tensor = input_tensor.unsqueeze(0) print("Performing forward pass...") model = model.eval() output = model(input_tensor) output = F.softmax(output, dim=1) _, pred_label_idx = torch.topk(output, 1) pred_label_idx.squeeze_() prediction = pred_label_idx.item() print("Generating visualization...") tic = time.time() visualization = IntegratedGradients(model) attributions = visualization.attribute(input_tensor, target=pred_label_idx, n_steps=5) attributions = attributions.squeeze().cpu().detach().numpy() attributions = np.transpose(attributions, (1, 2, 0)) toc = time.time() print("Took %.02fs" % (toc - tic)) custom_cmap = LinearSegmentedColormap.from_list("custom blue", [(0, "#ffffff"), (0.25, "#000000"), (1, "#000000")], N=256) fig, ax = viz.visualize_image_attr( attributions, method="heat_map", sign="positive", cmap=custom_cmap, show_colorbar=True, ) ax.margins(0) fig.tight_layout(pad=0) return fig, prediction
def get_attribution(model, input, target, method, device, saliency_layer='features.norm5', iba_wrapper=None): input = input.to(device) input.requires_grad = True # get attribution if method == "grad_cam": saliency_map = grad_cam(model, input, target, saliency_layer=saliency_layer) elif method == "extremal_perturbation": saliency_map, _ = extremal_perturbation(model, input, target) elif method == 'ib': assert iba_wrapper, "Please give a iba wrapper as function parameter!" saliency_map = iba_wrapper.iba(model, input, target, device) elif method == 'reverse_ib': assert iba_wrapper, "Please give a iba wrapper as function parameter!" saliency_map = iba_wrapper.iba(model, input, target, device, reverse_lambda=True) elif method == "gradient": saliency_map = gradient(model, input, target) elif method == "excitation_backprop": saliency_map = excitation_backprop(model, input, target, saliency_layer=saliency_layer) elif method == "integrated_gradients": ig = IntegratedGradients(model) saliency_map, _ = ig.attribute(input, target=target, return_convergence_delta=True) saliency_map = saliency_map.squeeze().mean(0) # ib heatmap already a numpy array scaled to image size if method != 'ib' and method != 'reverse_ib': saliency_map = saliency_map.detach().cpu().numpy().squeeze() shape = (224, 224) saliency_map = resize(saliency_map, shape, order=1, preserve_range=True) return saliency_map