Spaces:
				
			
			
	
			
			
		Build error
		
	
	
	
			
			
	
	
	
	
		
		
		Build error
		
	| import matplotlib.pyplot as plt | |
| import matplotlib.cm as mpl_color_map | |
| import copy | |
| import numpy as np | |
| import torch | |
| import torch.nn.functional as F | |
| from PIL import Image | |
| from modules.guided_backprop import GuidedBackprop | |
| import sys,os | |
| sys.path.append(os.getcwd()) | |
| def apply_colormap_on_image(org_im, activation, colormap_name): | |
| """ | |
| Apply heatmap on image | |
| Args: | |
| org_img (PIL img): Original image | |
| activation_map (numpy arr): Activation map (grayscale) 0-255 | |
| colormap_name (str): Name of the colormap | |
| """ | |
| # Get colormap | |
| color_map = mpl_color_map.get_cmap(colormap_name) | |
| no_trans_heatmap = color_map(activation) | |
| # Change alpha channel in colormap to make sure original image is displayed | |
| heatmap = copy.copy(no_trans_heatmap) | |
| heatmap[:, :, 3] = 0.4 | |
| heatmap = Image.fromarray((heatmap*255).astype(np.uint8)) | |
| no_trans_heatmap = Image.fromarray((no_trans_heatmap*255).astype(np.uint8)) | |
| # Apply heatmap on iamge | |
| org_im = np.uint8(org_im.detach().to("cpu").numpy()[0][0]*255) | |
| org_im = Image.fromarray(org_im) | |
| heatmap_on_image = Image.new("RGBA", org_im.size) | |
| heatmap_on_image = Image.alpha_composite(heatmap_on_image, org_im.convert('RGBA')) | |
| heatmap_on_image = Image.alpha_composite(heatmap_on_image, heatmap) | |
| return no_trans_heatmap, heatmap_on_image | |
| def save_gradient_images(gradient, file_name): | |
| """ | |
| Exports the original gradient image | |
| Args: | |
| gradient (np arr): Numpy array of the gradient with shape (3, 224, 224) | |
| file_name (str): Full filename including directory and png | |
| """ | |
| if not os.path.exists('../results'): | |
| os.makedirs('../results') | |
| # Normalize | |
| gradient = gradient - gradient.min() | |
| gradient /= gradient.max() | |
| # Save image | |
| path_to_file = file_name | |
| # print("gradient save shape: ", gradient.shape) | |
| save_image(gradient, path_to_file) | |
| def format_np_output(np_arr): | |
| """ | |
| This is a (kind of) bandaid fix to streamline saving procedure. | |
| It converts all the outputs to the same format which is 3xWxH | |
| with using sucecssive if clauses. | |
| Args: | |
| im_as_arr (Numpy array): Matrix of shape 1xWxH or WxH or 3xWxH | |
| """ | |
| # Phase/Case 1: The np arr only has 2 dimensions | |
| # Result: Add a dimension at the beginning | |
| if len(np_arr.shape) == 2: | |
| np_arr = np.expand_dims(np_arr, axis=0) | |
| # Phase/Case 2: Np arr has only 1 channel (assuming first dim is channel) | |
| # Result: Repeat first channel and convert 1xWxH to 3xWxH | |
| if np_arr.shape[0] == 1: | |
| np_arr = np.repeat(np_arr, 3, axis=0) | |
| # Phase/Case 3: Np arr is of shape 3xWxH | |
| # Result: Convert it to WxHx3 in order to make it saveable by PIL | |
| if np_arr.shape[0] == 3: | |
| np_arr = np_arr.transpose(1, 2, 0) | |
| # Phase/Case 4: NP arr is normalized between 0-1 | |
| # Result: Multiply with 255 and change type to make it saveable by PIL | |
| if np.max(np_arr) <= 1: | |
| np_arr = (np_arr*255).astype(np.uint8) | |
| return np_arr | |
| def save_image(im, path): | |
| """ | |
| Saves a numpy matrix or PIL image as an image | |
| Args: | |
| im_as_arr (Numpy array): Matrix of shape DxWxH | |
| path (str): Path to the image | |
| """ | |
| if isinstance(im, (np.ndarray, np.generic)): | |
| im = format_np_output(im) | |
| im = Image.fromarray(im) | |
| im.save(path) | |
| def module_output_to_numpy(tensor): | |
| return tensor.data.to('cpu').numpy() | |
| def convert_to_grayscale(im_as_arr): | |
| """ | |
| Converts 3d image to grayscale | |
| Args: | |
| im_as_arr (numpy arr): RGB image with shape (D,W,H) | |
| returns: | |
| grayscale_im (numpy_arr): Grayscale image with shape (1,W,D) | |
| """ | |
| grayscale_im = np.sum(np.abs(im_as_arr), axis=0) | |
| im_max = np.percentile(grayscale_im, 99) | |
| im_min = np.min(grayscale_im) | |
| grayscale_im = (np.clip((grayscale_im - im_min) / (im_max - im_min), 0, 1)) | |
| grayscale_im = np.expand_dims(grayscale_im, axis=0) | |
| return grayscale_im | |
| class SaveOutput: | |
| def __init__(self, totalFeatMaps): | |
| self.layer_outputs = [] | |
| self.grad_outputs = [] | |
| self.first_grads = [] | |
| self.totalFeatMaps = totalFeatMaps | |
| self.feature_ext = None | |
| ### Used on register_forward_hook | |
| ### Output up to totalFeatMaps | |
| def append_layer_out(self, module, input, output): | |
| self.layer_outputs.append(output[0]) ### Appending with earlier index pertaining to earlier layers | |
| ### Used on register_backward_hook | |
| ### Output up to totalFeatMaps | |
| def append_grad_out(self, module, grad_input, grad_output): | |
| self.grad_outputs.append(grad_output[0][0]) ### Appending with last-to-first index pertaining to first-to-last layers | |
| ### Used as guided backprop mask | |
| def append_first_grads(self, module, grad_in, grad_out): | |
| self.first_grads.append(grad_in[0]) | |
| def clear(self): | |
| self.layer_outputs = [] | |
| self.grad_outputs = [] | |
| self.first_grads = [] | |
| def set_feature_ext(self, feature_ext): | |
| self.feature_ext = feature_ext | |
| def getGuidedGradImg(self, layerNum, input_img): | |
| # print("layer outputs shape: ", self.layer_outputs[0].shape) | |
| # print("layer grad_outputs shape: ", self.grad_outputs[0].shape) | |
| conv_output_img = module_output_to_numpy(self.layer_outputs[layerNum]) | |
| grad_output_img = module_output_to_numpy(self.grad_outputs[len(self.grad_outputs)-layerNum-1]) | |
| first_grad_output = self.first_grads[0].data.to('cpu').numpy()[0] | |
| print("conv_output_img output shape: ", conv_output_img.shape) | |
| print("grad_output_img output shape: ", grad_output_img.shape) | |
| print("first_grad_output output shape: ", first_grad_output.shape) | |
| print("target min max: {}, {}".format(conv_output_img.min(), conv_output_img.max())) | |
| print("guided_gradients min max: {}, {}".format(grad_output_img.min(), grad_output_img.max())) | |
| weights = np.mean(grad_output_img, axis=(1, 2)) # Take averages for each gradient | |
| print("weights shape: ", weights.shape) | |
| print("weights min max1: {}, {}".format(weights.min(), weights.max())) | |
| # Create empty numpy array for cam | |
| # conv_output_img = np.clip(conv_output_img, 0, conv_output_img.max()) | |
| cam = np.ones(conv_output_img.shape[1:], dtype=np.float32) | |
| print("cam min max1: {}, {}".format(cam.min(), cam.max())) | |
| # Multiply each weight with its conv output and then, sum | |
| for i, w in enumerate(weights): | |
| cam += w * conv_output_img[i, :, :] | |
| # cam = np.maximum(cam, 0) | |
| print("cam min max2: {}, {}".format(cam.min(), cam.max())) | |
| cam = (cam - np.min(cam)) / (np.max(cam) - np.min(cam)) # Normalize between 0-1 | |
| cam = np.uint8(cam * 255) # Scale between 0-255 to visualize | |
| cam = np.uint8(Image.fromarray(cam).resize((input_img.shape[3], | |
| input_img.shape[2]), Image.ANTIALIAS))/255 | |
| # cam_gb = np.multiply(cam, first_grad_output) | |
| # grayscale_cam_gb = convert_to_grayscale(cam) | |
| return cam | |
| def getGuidedGradTimesImg(self, layerNum, input_img): | |
| grad_output_img = module_output_to_numpy(self.grad_outputs[len(self.grad_outputs)-layerNum-1]) | |
| print("grad_output_img output shape: ", grad_output_img.shape) | |
| grad_times_image = grad_output_img[0]*input_img.detach().to("cpu").numpy()[0] | |
| return grad_times_image | |
| ### target_output -- pass a created output tensor with one hot (1s) already in placed, used for guided gradients (first layer) | |
| def output_feature_maps(self, targetDir, input_img): | |
| # GBP = GuidedBackprop(self.feature_ext, 'resnet34') | |
| # guided_grads = GBP.generate_gradients(input_img, one_hot_output_guided, text_for_pred) | |
| # print("guided_grads shape: ", guided_grads.shape) | |
| for layerNum in range(self.totalFeatMaps): | |
| grad_times_image = self.getGuidedGradTimesImg(layerNum, input_img) | |
| # save_gradient_images(cam_gb, targetDir + 'GGrad_Cam_Layer{}.jpg'.format(layerNum)) | |
| # save_gradient_images(grayscale_cam_gb, targetDir + 'GGrad_Cam_Gray_Layer{}.jpg'.format(layerNum)) | |
| ### Output heatmaps | |
| grayscale_vanilla_grads = convert_to_grayscale(grad_times_image) | |
| save_gradient_images(grayscale_vanilla_grads, targetDir + 'Vanilla_grad_times_image_gray{}.jpg'.format(layerNum)) | |