def guided_grad_cam(model, image, results_dir, file_name): guided_gc = GuidedGradCam(model, model.skip_4[0]) # Last Conv Layer attributions = guided_gc.attribute(image) attributions = attributions.squeeze() attributions = attributions.detach().numpy() attributions = nib.Nifti1Image(attributions, affine=np.eye(4)) nib.save(attributions, results_dir + file_name + "-HM.nii")
def compute_guided_gradcam(self, img_path, target): # open image img, transformed_img, input = self.open_image(img_path) # guided grad cam input.requires_grad = True gradcam = GuidedGradCam(self.model, self.layer) attributions_gradcam = gradcam.attribute(input, target) attributions_gradcam = np.transpose( attributions_gradcam.squeeze().cpu().detach().numpy(), (1, 2, 0)) return attributions_gradcam
class GuidedGradCamPublisher: def __init__(self, model, layer, forward_pass_preprocess): from captum.attr import GuidedGradCam self.model = model self.grad_cam = GuidedGradCam(model=model, layer=layer) self.forward_pass_preprocess = forward_pass_preprocess def __call__(self, writer: SummaryWriter, tag, sample, idx): if not isinstance(sample, torch.Tensor): sample = torch.tensor(sample) if sample.shape[-1] == 3: # H, W, C sample = sample.permute(2, 0, 1) X = self.forward_pass_preprocess(sample).unsqueeze(0) device = next(self.model.parameters()).device X = X.to(device) logits = self.model(X) res = self.grad_cam.attribute(X, logits.argmax()) res = res.squeeze().detach().cpu().numpy() res = (res - res.min()) res /= res.max() res = (res * 255).astype(np.uint8) writer.add_image(f"{tag}_gradcam", res, global_step=idx)
def measure_model( model_version, dataset, out_folder, weights_dir, device, method=METHODS["gradcam"], sample_images=50, step=1, ): invTrans = get_inverse_normalization_transformation() data_dir = os.path.join("data") if model_version == "resnet18": model = create_resnet18_model(num_of_classes=NUM_OF_CLASSES[dataset]) elif model_version == "resnet50": model = create_resnet50_model(num_of_classes=NUM_OF_CLASSES[dataset]) elif model_version == "densenet": model = create_densenet121_model( num_of_classes=NUM_OF_CLASSES[dataset]) else: model = create_efficientnetb0_model( num_of_classes=NUM_OF_CLASSES[dataset]) model.load_state_dict(torch.load(weights_dir)) # print(model) model.eval() model.to(device) test_dataset = CustomDataset( dataset=dataset, transformer=get_default_transformation(), data_type="test", root_dir=data_dir, step=step, ) data_loader = torch.utils.data.DataLoader(test_dataset, batch_size=1, shuffle=False, num_workers=4) try: image_ids = random.sample(range(0, test_dataset.__len__()), sample_images) except ValueError: raise ValueError( f"Image sample number ({sample_images}) exceeded dataset size ({test_dataset.__len__()})." ) classes_map = test_dataset.classes_map print(f"Measuring {model_version} on {dataset} dataset, with {method}") print("-" * 10) pbar = tqdm(total=test_dataset.__len__(), desc="Model test completion") multipy_by_inputs = False if method == METHODS["ig"]: attr_method = IntegratedGradients(model) nt_samples = 8 n_perturb_samples = 3 if method == METHODS["saliency"]: attr_method = Saliency(model) nt_samples = 8 n_perturb_samples = 10 if method == METHODS["gradcam"]: if model_version == "efficientnet": attr_method = GuidedGradCam(model, model._conv_stem) elif model_version == "densenet": attr_method = GuidedGradCam(model, model.features.conv0) else: attr_method = GuidedGradCam(model, model.conv1) nt_samples = 8 n_perturb_samples = 10 if method == METHODS["deconv"]: attr_method = Deconvolution(model) nt_samples = 8 n_perturb_samples = 10 if method == METHODS["gradshap"]: attr_method = GradientShap(model) nt_samples = 8 if model_version == "efficientnet": n_perturb_samples = 3 elif model_version == "densenet": n_perturb_samples = 2 else: n_perturb_samples = 10 if method == METHODS["gbp"]: attr_method = GuidedBackprop(model) nt_samples = 8 n_perturb_samples = 10 if method == "lime": attr_method = Lime(model) nt_samples = 8 n_perturb_samples = 10 feature_mask = torch.tensor(lime_mask).to(device) multipy_by_inputs = True if method == METHODS['ig']: nt = attr_method else: nt = NoiseTunnel(attr_method) scores = [] @infidelity_perturb_func_decorator(multipy_by_inputs=multipy_by_inputs) def perturb_fn(inputs): noise = torch.tensor(np.random.normal(0, 0.003, inputs.shape)).float() noise = noise.to(device) return inputs - noise for input, label in data_loader: pbar.update(1) inv_input = invTrans(input) input = input.to(device) input.requires_grad = True output = model(input) output = F.softmax(output, dim=1) prediction_score, pred_label_idx = torch.topk(output, 1) prediction_score = prediction_score.cpu().detach().numpy()[0][0] pred_label_idx.squeeze_() if method == METHODS['gradshap']: baseline = torch.randn(input.shape) baseline = baseline.to(device) if method == "lime": attributions = attr_method.attribute(input, target=1, n_samples=50) elif method == METHODS['ig']: attributions = nt.attribute( input, target=pred_label_idx, n_steps=25, ) elif method == METHODS['gradshap']: attributions = nt.attribute(input, target=pred_label_idx, baselines=baseline) else: attributions = nt.attribute( input, nt_type="smoothgrad", nt_samples=nt_samples, target=pred_label_idx, ) infid = infidelity(model, perturb_fn, input, attributions, target=pred_label_idx) if method == "lime": sens = sensitivity_max( attr_method.attribute, input, target=pred_label_idx, n_perturb_samples=1, n_samples=200, feature_mask=feature_mask, ) elif method == METHODS['ig']: sens = sensitivity_max( nt.attribute, input, target=pred_label_idx, n_perturb_samples=n_perturb_samples, n_steps=25, ) elif method == METHODS['gradshap']: sens = sensitivity_max(nt.attribute, input, target=pred_label_idx, n_perturb_samples=n_perturb_samples, baselines=baseline) else: sens = sensitivity_max( nt.attribute, input, target=pred_label_idx, n_perturb_samples=n_perturb_samples, ) inf_value = infid.cpu().detach().numpy()[0] sens_value = sens.cpu().detach().numpy()[0] if pbar.n in image_ids: attr_data = attributions.squeeze().cpu().detach().numpy() fig, ax = viz.visualize_image_attr_multiple( np.transpose(attr_data, (1, 2, 0)), np.transpose(inv_input.squeeze().cpu().detach().numpy(), (1, 2, 0)), ["original_image", "heat_map"], ["all", "positive"], titles=["original_image", "heat_map"], cmap=default_cmap, show_colorbar=True, use_pyplot=False, fig_size=(8, 6), ) ax[0].set_xlabel( f"Infidelity: {'{0:.6f}'.format(inf_value)}\n Sensitivity: {'{0:.6f}'.format(sens_value)}" ) fig.suptitle( f"True: {classes_map[str(label.numpy()[0])][0]}, Pred: {classes_map[str(pred_label_idx.item())][0]}\nScore: {'{0:.4f}'.format(prediction_score)}", fontsize=16, ) fig.savefig( os.path.join( out_folder, f"{str(pbar.n)}-{classes_map[str(label.numpy()[0])][0]}-{classes_map[str(pred_label_idx.item())][0]}.png", )) plt.close(fig) # if pbar.n > 25: # break scores.append([inf_value, sens_value]) pbar.close() np.savetxt( os.path.join(out_folder, f"{model_version}-{dataset}-{method}.csv"), np.array(scores), delimiter=",", header="infidelity,sensitivity", ) print(f"Artifacts stored at {out_folder}")
def measure_filter_model( model_version, dataset, out_folder, weights_dir, device, method=METHODS["gradcam"], sample_images=50, step=1, use_infidelity=False, use_sensitivity=False, render=False, ids=None, ): invTrans = get_inverse_normalization_transformation() data_dir = os.path.join("data") if model_version == "resnet18": model = create_resnet18_model(num_of_classes=NUM_OF_CLASSES[dataset]) elif model_version == "resnet50": model = create_resnet50_model(num_of_classes=NUM_OF_CLASSES[dataset]) elif model_version == "densenet": model = create_densenet121_model( num_of_classes=NUM_OF_CLASSES[dataset]) else: model = create_efficientnetb0_model( num_of_classes=NUM_OF_CLASSES[dataset]) model.load_state_dict(torch.load(weights_dir)) # print(model) model.eval() model.to(device) test_dataset = CustomDataset( dataset=dataset, transformer=get_default_transformation(), data_type="test", root_dir=data_dir, step=step, add_filters=True, ids=ids, ) data_loader = torch.utils.data.DataLoader(test_dataset, batch_size=1, shuffle=False, num_workers=4) try: image_ids = random.sample(range(0, test_dataset.__len__()), test_dataset.__len__()) except ValueError: raise ValueError( f"Image sample number ({test_dataset.__len__()}) exceeded dataset size ({test_dataset.__len__()})." ) classes_map = test_dataset.classes_map print(f"Measuring {model_version} on {dataset} dataset, with {method}") print("-" * 10) pbar = tqdm(total=test_dataset.__len__(), desc="Model test completion") multipy_by_inputs = False if method == METHODS["ig"]: attr_method = IntegratedGradients(model) nt_samples = 1 n_perturb_samples = 1 if method == METHODS["saliency"]: attr_method = Saliency(model) nt_samples = 8 n_perturb_samples = 2 if method == METHODS["gradcam"]: if model_version == "efficientnet": attr_method = GuidedGradCam(model, model._conv_stem) elif model_version == "densenet": attr_method = GuidedGradCam(model, model.features.conv0) else: attr_method = GuidedGradCam(model, model.conv1) nt_samples = 8 n_perturb_samples = 2 if method == METHODS["deconv"]: attr_method = Deconvolution(model) nt_samples = 8 n_perturb_samples = 2 if method == METHODS["gradshap"]: attr_method = GradientShap(model) nt_samples = 8 n_perturb_samples = 2 if method == METHODS["gbp"]: attr_method = GuidedBackprop(model) nt_samples = 8 n_perturb_samples = 2 if method == "lime": attr_method = Lime(model) nt_samples = 8 n_perturb_samples = 2 feature_mask = torch.tensor(lime_mask).to(device) multipy_by_inputs = True if method == METHODS["ig"]: nt = attr_method else: nt = NoiseTunnel(attr_method) scores = [] @infidelity_perturb_func_decorator(multipy_by_inputs=multipy_by_inputs) def perturb_fn(inputs): noise = torch.tensor(np.random.normal(0, 0.003, inputs.shape)).float() noise = noise.to(device) return inputs - noise OUR_FILTERS = [ "none", "fx_freaky_details 2,10,1,11,0,32,0", "normalize_local 8,10", "fx_boost_chroma 90,0,0", "fx_mighty_details 25,1,25,1,11,0", "sharpen 300", ] idx = 0 filter_count = 0 filter_attrs = {filter_name: [] for filter_name in OUR_FILTERS} predicted_main_class = 0 for input, label in data_loader: pbar.update(1) inv_input = invTrans(input) input = input.to(device) input.requires_grad = True output = model(input) output = F.softmax(output, dim=1) prediction_score, pred_label_idx = torch.topk(output, 1) prediction_score = prediction_score.cpu().detach().numpy()[0][0] pred_label_idx.squeeze_() if OUR_FILTERS[filter_count] == 'none': predicted_main_class = pred_label_idx.item() if method == METHODS["gradshap"]: baseline = torch.randn(input.shape) baseline = baseline.to(device) if method == "lime": attributions = attr_method.attribute(input, target=1, n_samples=50) elif method == METHODS["ig"]: attributions = nt.attribute( input, target=predicted_main_class, n_steps=25, ) elif method == METHODS["gradshap"]: attributions = nt.attribute(input, target=predicted_main_class, baselines=baseline) else: attributions = nt.attribute( input, nt_type="smoothgrad", nt_samples=nt_samples, target=predicted_main_class, ) if use_infidelity: infid = infidelity(model, perturb_fn, input, attributions, target=predicted_main_class) inf_value = infid.cpu().detach().numpy()[0] else: inf_value = 0 if use_sensitivity: if method == "lime": sens = sensitivity_max( attr_method.attribute, input, target=predicted_main_class, n_perturb_samples=1, n_samples=200, feature_mask=feature_mask, ) elif method == METHODS["ig"]: sens = sensitivity_max( nt.attribute, input, target=predicted_main_class, n_perturb_samples=n_perturb_samples, n_steps=25, ) elif method == METHODS["gradshap"]: sens = sensitivity_max( nt.attribute, input, target=predicted_main_class, n_perturb_samples=n_perturb_samples, baselines=baseline, ) else: sens = sensitivity_max( nt.attribute, input, target=predicted_main_class, n_perturb_samples=n_perturb_samples, ) sens_value = sens.cpu().detach().numpy()[0] else: sens_value = 0 # filter_name = test_dataset.data.iloc[pbar.n]["filter"].split(" ")[0] attr_data = attributions.squeeze().cpu().detach().numpy() if render: fig, ax = viz.visualize_image_attr_multiple( np.transpose(attr_data, (1, 2, 0)), np.transpose(inv_input.squeeze().cpu().detach().numpy(), (1, 2, 0)), ["original_image", "heat_map"], ["all", "positive"], titles=["original_image", "heat_map"], cmap=default_cmap, show_colorbar=True, use_pyplot=False, fig_size=(8, 6), ) if use_sensitivity or use_infidelity: ax[0].set_xlabel( f"Infidelity: {'{0:.6f}'.format(inf_value)}\n Sensitivity: {'{0:.6f}'.format(sens_value)}" ) fig.suptitle( f"True: {classes_map[str(label.numpy()[0])][0]}, Pred: {classes_map[str(pred_label_idx.item())][0]}\nScore: {'{0:.4f}'.format(prediction_score)}", fontsize=16, ) fig.savefig( os.path.join( out_folder, f"{str(idx)}-{str(filter_count)}-{str(label.numpy()[0])}-{str(OUR_FILTERS[filter_count])}-{classes_map[str(label.numpy()[0])][0]}-{classes_map[str(pred_label_idx.item())][0]}.png", )) plt.close(fig) # if pbar.n > 25: # break score_for_true_label = output.cpu().detach().numpy( )[0][predicted_main_class] filter_attrs[OUR_FILTERS[filter_count]] = [ np.moveaxis(attr_data, 0, -1), "{0:.8f}".format(score_for_true_label), ] data_range_for_current_set = MAX_ATT_VALUES[model_version][method][ dataset] filter_count += 1 if filter_count >= len(OUR_FILTERS): ssims = [] for rot in OUR_FILTERS: ssims.append("{0:.8f}".format( ssim( filter_attrs["none"][0], filter_attrs[rot][0], win_size=11, data_range=data_range_for_current_set, multichannel=True, ))) ssims.append(filter_attrs[rot][1]) scores.append(ssims) filter_count = 0 predicted_main_class = 0 idx += 1 pbar.close() indexes = [] for filter_name in OUR_FILTERS: indexes.append(str(filter_name) + "-ssim") indexes.append(str(filter_name) + "-score") np.savetxt( os.path.join( out_folder, f"{model_version}-{dataset}-{method}-ssim-with-range.csv"), np.array(scores), delimiter=";", fmt="%s", header=";".join([str(rot) for rot in indexes]), ) print(f"Artifacts stored at {out_folder}")
MODEL_DIR = "/artefact/" if os.path.exists("models/"): MODEL_DIR = "models/" DEVICE = torch.device("cpu") MODEL = CustomSEResNeXt(MODEL_DIR + "pretrained_model.pth", DEVICE) MODEL.load_state_dict(torch.load(MODEL_DIR + "finetuned_model.pth", map_location=DEVICE)) MODEL.eval() GRAD_CAM = GradCam(model=MODEL.model, feature_module=MODEL.model.layer4, target_layer_names=["2"], use_cuda=False) GUIDED_GC = GuidedGradCam(MODEL.model, MODEL.model.layer4) IG = IntegratedGradients(MODEL.model) def process_image(image): """Process image.""" seed_torch(seed=42) proc_image = transforms.Compose([ Rescale(256), RandomCrop(224), ToTensor(), ])(image) proc_image = proc_image.unsqueeze(0).to(DEVICE) return proc_image
# **************************************************************************************** # # Captum model = torchvision.models.squeezenet1_1(pretrained=True) # We don't want to train the model, so tell PyTorch not to compute gradients # with respect to model parameters. for param in model.parameters(): param.requires_grad = False # Convert X and y from numpy arrays to Torch Tensors X_tensor = torch.cat([preprocess(Image.fromarray(x)) for x in X], dim=0) y_tensor = torch.LongTensor(y) # Computing Guided GradCam gc_result = GuidedGradCam(model, model.features[3]) attr_ggc = compute_attributions(gc_result, X_tensor, target=y_tensor) attr_ggc = attr_ggc.abs() attr_ggc, i = torch.max(attr_ggc, dim=1) attr_ggc = attr_ggc.unsqueeze(0) visualize_attr_maps('visualization/Captum_Guided_GradCam.png', X, y, class_names, attr_ggc, ['GuidedGradCam'], lambda attr: attr.detach().numpy()) # # Computing Guided BackProp gbp_result = GuidedBackprop(model) attr_gbp = compute_attributions(gbp_result, X_tensor, target=y_tensor) attr_gbp = attr_gbp.abs() attr_gbp, i = torch.max(attr_gbp, dim=1) attr_gbp = attr_gbp.unsqueeze(0) visualize_attr_maps('visualization/Captum_Guided_BackProp.png', X, y,
def __init__(self, model, layer, forward_pass_preprocess): from captum.attr import GuidedGradCam self.model = model self.grad_cam = GuidedGradCam(model=model, layer=layer) self.forward_pass_preprocess = forward_pass_preprocess
covid_loaders = COVID_Dataset('data/final3_masked', pos_neg_file='data/labels_covid19_posi.tsv', splits=[0.7, 0.15, 0.15], replicate_channel=1, batch_size=1, random_seed=123, input_size=224, mode='ct', num_workers=0) model = DenseNetModel(121, 2) model.model.load_state_dict( torch.load('interpretability/model_best.pth')['state_dict']) model = model.eval() model.model = model.model.to('cuda') gc = GuidedGradCam(model.model, model.model.features.denseblock3) noise_tunnel = NoiseTunnel(gc) for (img, label, sublabel, subject_id, ct_id, slice_id) in tqdm(covid_loaders.test): img = img.to('cuda') output = model.model(img) prediction_score, predicted_label = torch.max(output, 1) attributions_ig_nt = noise_tunnel.attribute(img, nt_samples=10, nt_type='smoothgrad_sq', target=predicted_label, stdevs=0.01) filename = subject_id[0] + '_' + ct_id[0] + '_' + str( slice_id.item()) + '.png' dest = os.path.join('interp_output', subject_id[0], ct_id[0], filename)
def get_attribution(real_img, fake_img, real_class, fake_class, net_module, checkpoint_path, input_shape, channels, methods=["ig", "grads", "gc", "ggc", "dl", "ingrad", "random", "residual"], output_classes=6, downsample_factors=[(2,2), (2,2), (2,2), (2,2)]): imgs = [image_to_tensor(normalize_image(real_img).astype(np.float32)), image_to_tensor(normalize_image(fake_img).astype(np.float32))] classes = [real_class, fake_class] net = init_network(checkpoint_path, input_shape, net_module, channels, output_classes=output_classes,eval_net=True, require_grad=False, downsample_factors=downsample_factors) attrs = [] attrs_names = [] if "residual" in methods: res = np.abs(real_img - fake_img) res = res - np.min(res) attrs.append(torch.tensor(res/np.max(res))) attrs_names.append("residual") if "random" in methods: rand = np.abs(np.random.randn(*np.shape(real_img))) rand = np.abs(scipy.ndimage.filters.gaussian_filter(rand, 4)) rand = rand - np.min(rand) rand = rand/np.max(np.abs(rand)) attrs.append(torch.tensor(rand)) attrs_names.append("random") if "gc" in methods: net.zero_grad() last_conv_layer = [(name,module) for name, module in net.named_modules() if type(module) == torch.nn.Conv2d][-1] layer_name = last_conv_layer[0] layer = last_conv_layer[1] layer_gc = LayerGradCam(net, layer) gc_real = layer_gc.attribute(imgs[0], target=classes[0]) gc_fake = layer_gc.attribute(imgs[1], target=classes[1]) gc_real = project_layer_activations_to_input_rescale(gc_real.cpu().detach().numpy(), (input_shape[0], input_shape[1])) gc_fake = project_layer_activations_to_input_rescale(gc_fake.cpu().detach().numpy(), (input_shape[0], input_shape[1])) attrs.append(torch.tensor(gc_real[0,0,:,:])) attrs_names.append("gc_real") attrs.append(torch.tensor(gc_fake[0,0,:,:])) attrs_names.append("gc_fake") # SCAM gc_diff_0, gc_diff_1 = get_sgc(real_img, fake_img, real_class, fake_class, net_module, checkpoint_path, input_shape, channels, None, output_classes=output_classes, downsample_factors=downsample_factors) attrs.append(gc_diff_0) attrs_names.append("gc_diff_0") attrs.append(gc_diff_1) attrs_names.append("gc_diff_1") if "ggc" in methods: net.zero_grad() last_conv = [module for module in net.modules() if type(module) == torch.nn.Conv2d][-1] guided_gc = GuidedGradCam(net, last_conv) ggc_real = guided_gc.attribute(imgs[0], target=classes[0]) ggc_fake = guided_gc.attribute(imgs[1], target=classes[1]) attrs.append(ggc_real[0,0,:,:]) attrs_names.append("ggc_real") attrs.append(ggc_fake[0,0,:,:]) attrs_names.append("ggc_fake") net.zero_grad() gbp = GuidedBackprop(net) gbp_real = gbp.attribute(imgs[0], target=classes[0]) gbp_fake = gbp.attribute(imgs[1], target=classes[1]) attrs.append(gbp_real[0,0,:,:]) attrs_names.append("gbp_real") attrs.append(gbp_fake[0,0,:,:]) attrs_names.append("gbp_fake") ggc_diff_0 = gbp_real[0,0,:,:] * gc_diff_0 ggc_diff_1 = gbp_fake[0,0,:,:] * gc_diff_1 attrs.append(ggc_diff_0) attrs_names.append("ggc_diff_0") attrs.append(ggc_diff_1) attrs_names.append("ggc_diff_1") # IG if "ig" in methods: baseline = image_to_tensor(np.zeros(input_shape, dtype=np.float32)) net.zero_grad() ig = IntegratedGradients(net) ig_real, delta_real = ig.attribute(imgs[0], baseline, target=classes[0], return_convergence_delta=True) ig_fake, delta_fake = ig.attribute(imgs[1], baseline, target=classes[1], return_convergence_delta=True) ig_diff_0, delta_diff = ig.attribute(imgs[0], imgs[1], target=classes[0], return_convergence_delta=True) ig_diff_1, delta_diff = ig.attribute(imgs[1], imgs[0], target=classes[1], return_convergence_delta=True) attrs.append(ig_real[0,0,:,:]) attrs_names.append("ig_real") attrs.append(ig_fake[0,0,:,:]) attrs_names.append("ig_fake") attrs.append(ig_diff_0[0,0,:,:]) attrs_names.append("ig_diff_0") attrs.append(ig_diff_1[0,0,:,:]) attrs_names.append("ig_diff_1") # DL if "dl" in methods: net.zero_grad() dl = DeepLift(net) dl_real = dl.attribute(imgs[0], target=classes[0]) dl_fake = dl.attribute(imgs[1], target=classes[1]) dl_diff_0 = dl.attribute(imgs[0], baselines=imgs[1], target=classes[0]) dl_diff_1 = dl.attribute(imgs[1], baselines=imgs[0], target=classes[1]) attrs.append(dl_real[0,0,:,:]) attrs_names.append("dl_real") attrs.append(dl_fake[0,0,:,:]) attrs_names.append("dl_fake") attrs.append(dl_diff_0[0,0,:,:]) attrs_names.append("dl_diff_0") attrs.append(dl_diff_1[0,0,:,:]) attrs_names.append("dl_diff_1") # INGRAD if "ingrad" in methods: net.zero_grad() saliency = Saliency(net) grads_real = saliency.attribute(imgs[0], target=classes[0]) grads_fake = saliency.attribute(imgs[1], target=classes[1]) attrs.append(grads_real[0,0,:,:]) attrs_names.append("grads_real") attrs.append(grads_fake[0,0,:,:]) attrs_names.append("grads_fake") net.zero_grad() input_x_gradient = InputXGradient(net) ingrad_real = input_x_gradient.attribute(imgs[0], target=classes[0]) ingrad_fake = input_x_gradient.attribute(imgs[1], target=classes[1]) ingrad_diff_0 = grads_fake * (imgs[0] - imgs[1]) ingrad_diff_1 = grads_real * (imgs[1] - imgs[0]) attrs.append(torch.abs(ingrad_real[0,0,:,:])) attrs_names.append("ingrad_real") attrs.append(torch.abs(ingrad_fake[0,0,:,:])) attrs_names.append("ingrad_fake") attrs.append(torch.abs(ingrad_diff_0[0,0,:,:])) attrs_names.append("ingrad_diff_0") attrs.append(torch.abs(ingrad_diff_1[0,0,:,:])) attrs_names.append("ingrad_diff_1") attrs = [a.detach().cpu().numpy() for a in attrs] attrs_norm = [a/np.max(np.abs(a)) for a in attrs] return attrs_norm, attrs_names
def evaluation_ten_classes(initiate_or_load_model, config_data, singleton_scope=False, reshape_size=None, FIND_OPTIM_BRANCH_MODEL=False, realtime_update=False, ALLOW_ADHOC_NOPTIM=False): from pipeline.training.training_utils import prepare_save_dirs xai_mode = config_data['xai_mode'] MODEL_DIR, INFO_DIR, CACHE_FOLDER_DIR = prepare_save_dirs(config_data) ############################ VERBOSE = 0 ############################ if not FIND_OPTIM_BRANCH_MODEL: print( 'Using the following the model from (only) continuous training for xai evaluation [%s]' % (str(xai_mode))) net, evaluator = initiate_or_load_model(MODEL_DIR, INFO_DIR, config_data, verbose=VERBOSE) else: BRANCH_FOLDER_DIR = MODEL_DIR[:MODEL_DIR.find('.model')] + '.%s' % ( str(config_data['branch_name_label'])) BRANCH_MODEL_DIR = os.path.join( BRANCH_FOLDER_DIR, '%s.%s.model' % (str(config_data['model_name']), str(config_data['branch_name_label']))) # BRANCH_MODEL_DIR = MODEL_DIR[:MODEL_DIR.find('.model')] + '.%s.model'%(str(config_data['branch_name_label'])) if ALLOW_ADHOC_NOPTIM: # this is intended only for debug runs print('<< [EXY1] ALLOWING ADHOC NOPTIM >>') import shutil shutil.copyfile(BRANCH_MODEL_DIR, BRANCH_MODEL_DIR + '.noptim') if os.path.exists(BRANCH_MODEL_DIR + '.optim'): BRANCH_MODEL_DIR = BRANCH_MODEL_DIR + '.optim' print( ' Using the OPTIMIZED branch model for [%s] xai evaluation: %s' % (str(xai_mode), str(BRANCH_MODEL_DIR))) elif os.path.exists(BRANCH_MODEL_DIR + '.noptim'): BRANCH_MODEL_DIR = BRANCH_MODEL_DIR + '.noptim' print( ' Using the partially optimized branch model for [%s] xai evaluation: %s' % (str(xai_mode), str(BRANCH_MODEL_DIR))) else: raise RuntimeError( 'Attempting to find .optim or .noptim model, but not found.') if VERBOSE >= 250: print( ' """You may see a warning by pytorch for ReLu backward hook. It has been fixed externally, so you can ignore it."""' ) net, evaluator = initiate_or_load_model(BRANCH_MODEL_DIR, INFO_DIR, config_data, verbose=VERBOSE) if xai_mode == 'Saliency': attrmodel = Saliency(net) elif xai_mode == 'IntegratedGradients': attrmodel = IntegratedGradients(net) elif xai_mode == 'InputXGradient': attrmodel = InputXGradient(net) elif xai_mode == 'DeepLift': attrmodel = DeepLift(net) elif xai_mode == 'GuidedBackprop': attrmodel = GuidedBackprop(net) elif xai_mode == 'GuidedGradCam': attrmodel = GuidedGradCam(net, net.select_first_layer()) # first layer elif xai_mode == 'Deconvolution': attrmodel = Deconvolution(net) elif xai_mode == 'GradientShap': attrmodel = GradientShap(net) elif xai_mode == 'DeepLiftShap': attrmodel = DeepLiftShap(net) else: raise RuntimeError('No valid attribution selected.') if singleton_scope: # just to observe a single datapoint, mostly for debugging singleton_scope_oberservation(net, attrmodel, config_data, CACHE_FOLDER_DIR) else: aggregate_evaluation(net, attrmodel, config_data, CACHE_FOLDER_DIR, reshape_size=reshape_size, realtime_update=realtime_update, EVALUATE_BRANCH=FIND_OPTIM_BRANCH_MODEL)