import argparse import cv2 import numpy as np import torch from pytorch_grad_cam import GradCAM, \ ScoreCAM, \ GradCAMPlusPlus, \ AblationCAM, \ XGradCAM, \ EigenCAM, \ EigenGradCAM, \ LayerCAM, \ FullGrad from pytorch_grad_cam import GuidedBackpropReLUModel from pytorch_grad_cam.utils.image import show_cam_on_image, \ preprocess_image from pytorch_grad_cam.ablation_layer import AblationLayerVit def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--device', type=str, default='cpu', help='Torch device to use') parser.add_argument( '--image-path', type=str, default='./examples/both.png', help='Input image path') parser.add_argument('--aug_smooth', action='store_true', help='Apply test time augmentation to smooth the CAM') parser.add_argument( '--eigen_smooth', action='store_true', help='Reduce noise by taking the first principle componenet' 'of cam_weights*activations') parser.add_argument( '--method', type=str, default='gradcam', help='Can be gradcam/gradcam++/scorecam/xgradcam/ablationcam') args = parser.parse_args() if args.device: print(f'Using device "{args.device}" for acceleration') else: print('Using CPU for computation') return args def reshape_transform(tensor, height=14, width=14): result = tensor[:, 1:, :].reshape(tensor.size(0), height, width, tensor.size(2)) # Bring the channels to the first dimension, # like in CNNs. result = result.transpose(2, 3).transpose(1, 2) return result if __name__ == '__main__': """ python vit_gradcam.py --image-path Example usage of using cam-methods on a VIT network. """ args = get_args() methods = \ {"gradcam": GradCAM, "scorecam": ScoreCAM, "gradcam++": GradCAMPlusPlus, "ablationcam": AblationCAM, "xgradcam": XGradCAM, "eigencam": EigenCAM, "eigengradcam": EigenGradCAM, "layercam": LayerCAM, "fullgrad": FullGrad} if args.method not in list(methods.keys()): raise Exception(f"method should be one of {list(methods.keys())}") model = torch.hub.load('facebookresearch/deit:main', 'deit_tiny_patch16_224', pretrained=True).to(torch.device(args.device)).eval() target_layers = [model.blocks[-1].norm1] if args.method not in methods: raise Exception(f"Method {args.method} not implemented") if args.method == "ablationcam": cam = methods[args.method](model=model, target_layers=target_layers, reshape_transform=reshape_transform, ablation_layer=AblationLayerVit()) else: cam = methods[args.method](model=model, target_layers=target_layers, reshape_transform=reshape_transform) rgb_img = cv2.imread(args.image_path, 1)[:, :, ::-1] rgb_img = cv2.resize(rgb_img, (224, 224)) rgb_img = np.float32(rgb_img) / 255 input_tensor = preprocess_image(rgb_img, mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]).to(args.device) # If None, returns the map for the highest scoring category. # Otherwise, targets the requested category. targets = None # AblationCAM and ScoreCAM have batched implementations. # You can override the internal batch size for faster computation. cam.batch_size = 32 grayscale_cam = cam(input_tensor=input_tensor, targets=targets, eigen_smooth=args.eigen_smooth, aug_smooth=args.aug_smooth) # Here grayscale_cam has only one image in the batch grayscale_cam = grayscale_cam[0, :] cam_image = show_cam_on_image(rgb_img, grayscale_cam) cv2.imwrite(f'{args.method}_cam.jpg', cam_image)