Exemplo n.º 1
0
 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,
     )
Exemplo n.º 2
0
    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
Exemplo n.º 3
0
    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,
        )
Exemplo n.º 4
0
class IGExplainer:
    def __init__(self, model, activation=torch.nn.Softmax(-1)):
        self.device = 'cuda'  #'cuda' if torch.cuda.is_available() else 'cpu'
        self.base_model = model.to(self.device)
        self.base_model.device = self.device
        self.explainer = IntegratedGradients(self.base_model)
        self.activation = activation

    def attribute(self, x, y, retrospective=False):
        #x, y = x.to(self.device), y.to(self.device)
        score = np.zeros(x.shape)
        self.base_model.zero_grad()
        if retrospective:
            score = self.attribute(x, target=y.long(), baselines=(x * 0))
            score = score.detach().cpu().numpy()
        else:
            score = np.zeros(x.shape)
            for t in range(x.shape[-1]):
                x_in = x[:, :, :t + 1]
                pred = self.activation(self.base_model(x_in))
                if type(self.activation).__name__ == type(
                        torch.nn.Softmax(-1)).__name__:
                    target = torch.argmax(pred, -1)
                    imp = self.explainer.attribute(x_in,
                                                   target=target,
                                                   baselines=(x[:, :, :t + 1] *
                                                              0))
                    score[:, :, t] = imp.detach().cpu().numpy()[:, :, -1]
                else:
                    #print(pred)
                    n_labels = pred.shape[1]
                    if n_labels > 1:
                        imp = torch.zeros(list(x_in.shape) + [n_labels])
                        for l in range(n_labels):
                            target = (pred[:, l] > 0.5).float()  #[:,0]
                            imp[:, :, :, l] = self.explainer.attribute(
                                x_in,
                                target=target.long(),
                                baselines=(x_in * 0))
                        score[:, :,
                              t] = (imp.detach().cpu().numpy()).max(3)[:, :,
                                                                       -1]
                    else:
                        #this is for spike with just one label. and we will explain one class
                        target = (pred > 0.5).float()[:, 0]
                        imp = self.explainer.attribute(x_in,
                                                       target=target.long(),
                                                       baselines=(x_in * 0))
                        score[:, :, t] = imp.detach().cpu().numpy()[:, :, -1]
        return score
Exemplo n.º 5
0
    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
Exemplo n.º 6
0
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
Exemplo n.º 7
0
class Explainer():
    def __init__(self,model):
        self.model=model
        self.explain=IntegratedGradients(model)


    def get_attribution_map(self,img,target=None):
        if target is None:
            target=torch.argmax(self.model(img),1)
        baseline_dist = torch.randn_like(img) * 0.001
        thrd=20
        attributions=[]
        if img.size(0) > thrd:
            img=torch.split(img,thrd)
            target=torch.split(target,thrd)
            baseline_dist=torch.split(baseline_dist,thrd)
        else:
            img,target,baseline_dist=[img],[target],[baseline_dist]

        for i,t,b in zip(img,target,baseline_dist):
            temp = self.explain.attribute(i, b, target=t , return_convergence_delta=False)
            attributions.append(temp)

        attributions=torch.cat(tuple(attributions),0)
        return attributions
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 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
Exemplo n.º 10
0
 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
Exemplo n.º 11
0
    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]
Exemplo n.º 12
0
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,
    }
Exemplo n.º 13
0
    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)
Exemplo n.º 14
0
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()
Exemplo n.º 15
0
class IntegradedGradientsCallback(Callback):
    "Captum Callback for Resnet Interpretation"
    def __init__(self):
        pass

    def after_fit(self):
        self.integrated_gradients = IntegratedGradients(self.model)

    def visualize(self, inp_data, n_steps=200, cmap_name='custom blue', colors=None, N=256,
                  methods=None, signs=None, outlier_perc=1):
        if methods is None: methods=['original_image','heat_map']
        if signs is None: signs=["all", "positive"]
        dl = self.dls.test_dl(L(inp_data),with_labels=True, bs=1)
        self.enc_inp,self.enc_preds= dl.one_batch()
        dec_data=dl.decode((self.enc_inp,self.enc_preds))
        self.dec_img,self.dec_pred=dec_data[0][0],dec_data[1][0]
        self.colors = [(0, '#ffffff'),(0.25, '#000000'),(1, '#000000')] if colors is None else colors
        self.attributions_ig = self.integrated_gradients.attribute(self.enc_inp.to(self.dl.device), target=self.enc_preds, n_steps=200)
        default_cmap = LinearSegmentedColormap.from_list(cmap_name,
                                                 self.colors, N=N)
        _ = viz.visualize_image_attr_multiple(np.transpose(self.attributions_ig.squeeze().cpu().detach().numpy(), (1,2,0)),
                             np.transpose(self.dec_img.numpy(), (1,2,0)),
                             methods=methods,
                             cmap=default_cmap,
                             show_colorbar=True,
                             signs=signs,
                             outlier_perc=outlier_perc, titles=[f'Original Image - ({self.dec_pred})', 'IG'])
Exemplo n.º 16
0
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")
Exemplo n.º 17
0
 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
Exemplo n.º 18
0
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
Exemplo n.º 19
0
    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)]
Exemplo n.º 20
0
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)
Exemplo n.º 21
0
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
Exemplo n.º 22
0
    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
                    )
                ]
            },
        }
Exemplo n.º 23
0
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)
Exemplo n.º 24
0
    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
Exemplo n.º 25
0
    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)
Exemplo n.º 26
0
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
Exemplo n.º 28
0
 def interpret(self, data_loader, n_features, n_classes, save_path=None):
     batch = next(iter(data_loader))
     e = batch.edge_index.to(self.device).long()
     def model_forward(input):
         out = self.net(input, e)
         return out
     self.net.eval()
     importances = np.zeros((n_features, n_classes))
     for batch in data_loader:
         input = batch.x.to(self.device)
         target = batch.y.to(self.device)
         ig = IntegratedGradients(model_forward)
         attributions = ig.attribute(input, target=target)
         attributions = attributions.to('cpu').detach().numpy()
         importances[:, target.to('cpu').numpy()] += attributions
     return importances
Exemplo n.º 29
0
class VisionHandler(BaseHandler, ABC):
    """
    Base class for all vision handlers
    """
    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 preprocess(self, data):
        """The preprocess function of MNIST program converts the input data to a float tensor

        Args:
            data (List): Input data from the request is in the form of a Tensor

        Returns:
            list : The preprocess function returns the input image as a list of float tensors.
        """
        images = []

        for row in data:
            # Compat layer: normally the envelope should just return the data
            # directly, but older versions of Torchserve didn't have envelope.
            image = row.get("data") or row.get("body")
            if isinstance(image, str):
                # if the image is a string of bytesarray.
                image = base64.b64decode(image)

            # If the image is sent as bytesarray
            if isinstance(image, (bytearray, bytes)):
                image = Image.open(io.BytesIO(image))
                image = self.image_processing(image)
            else:
                # if the image is a list
                image = torch.FloatTensor(image)

            images.append(image)

        return torch.stack(images).to(self.device)

    def get_insights(self, tensor_data, _, target=0):
        print("input shape", tensor_data.shape)
        return self.ig.attribute(tensor_data, target=target,
                                 n_steps=15).tolist()
Exemplo n.º 30
0
 def explain_handle(self, model_wraper, text, target=1):
     """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.
     """
     vis_data_records_base = []
     model_wrapper = AGNewsmodelWrapper(self.model)
     tokenizer = BertTokenizer(self.VOCAB_FILE)
     model_wrapper.eval()
     model_wrapper.zero_grad()
     encoding = tokenizer.encode_plus(self.text,
                                      return_attention_mask=True,
                                      return_tensors="pt",
                                      add_special_tokens=False)
     input_ids = encoding["input_ids"]
     attention_mask = encoding["attention_mask"]
     input_ids = input_ids.to(self.device)
     attention_mask = attention_mask.to(self.device)
     input_embedding_test = model_wrapper.model.bert_model.embeddings(
         input_ids)
     preds = model_wrapper(input_embedding_test, attention_mask)
     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].cpu().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()
     self.add_attributions_to_visualizer(attributions, tokens,
                                         self.score_func(preds), out, 2, 1,
                                         delta, vis_data_records_base)
     return [feature_imp_dict]