Spaces:
Runtime error
Runtime error
File size: 3,912 Bytes
58762a0 0e03829 58762a0 0e03829 58762a0 0e03829 58762a0 0e03829 58762a0 0e03829 58762a0 0e03829 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | import numpy as np
import torch
import torch.nn.functional as F
import cv2
from PIL import Image
import tensorflow as tf
class PyTorchGradCAM:
def __init__(self, model, target_layer):
self.model = model
self.feature_maps = None
self.gradients = None
self.forward_hook = target_layer.register_forward_hook(self._save_feature_maps)
self.backward_hook = target_layer.register_full_backward_hook(self._save_gradients)
def _save_feature_maps(self, module, input, output):
self.feature_maps = output.detach()
def _save_gradients(self, module, grad_input, grad_output):
self.gradients = grad_output[0].detach()
def compute(self, tensor):
tensor = tensor.clone().requires_grad_(True)
output = self.model(tensor)
predicted_class = output.argmax(dim=1).item()
self.model.zero_grad()
output[0, predicted_class].backward()
weights = self.gradients.mean(dim=(2, 3), keepdim=True)
cam = (weights * self.feature_maps).sum(dim=1, keepdim=True)
cam = F.relu(cam)
cam = cam.squeeze().cpu().numpy()
cam = (cam - cam.min()) / (cam.max() - cam.min() + 1e-8)
return cam
def remove_hooks(self):
self.forward_hook.remove()
self.backward_hook.remove()
def _overlay_heatmap(original_image, cam):
img_resized = np.array(original_image.convert("RGB").resize((224, 224)))
cam_resized = cv2.resize(cam, (224, 224))
heatmap = cv2.applyColorMap(np.uint8(255 * cam_resized), cv2.COLORMAP_JET)
heatmap = cv2.cvtColor(heatmap, cv2.COLOR_BGR2RGB)
overlay = cv2.addWeighted(img_resized, 0.6, heatmap, 0.4, 0)
return Image.fromarray(overlay)
def gradcam_pytorch(original_image, model, tensor, target_layer):
gc = PyTorchGradCAM(model, target_layer)
try:
cam = gc.compute(tensor)
finally:
gc.remove_hooks()
return _overlay_heatmap(original_image, cam)
def gradcam_keras_manual(original_image, model, array, predicted_class):
img_tensor = tf.cast(array, tf.float32)
# Base model (MobileNetV2) nikalo
base_model = model.layers[0]
# Last conv layer dhundo
last_conv_layer = None
for layer in base_model.layers:
if isinstance(layer, tf.keras.layers.Conv2D):
last_conv_layer = layer
if last_conv_layer is None:
return original_image.resize((224, 224))
# Sirf ek output — last_conv_layer.output ONLY
grad_model = tf.keras.models.Model(
inputs=base_model.input,
outputs=last_conv_layer.output
)
with tf.GradientTape() as tape:
conv_outputs = grad_model(img_tensor, training=False)
tape.watch(conv_outputs)
x = conv_outputs
# base_model baaki layers manually
found = False
for layer in base_model.layers:
if found:
x = layer(x, training=False)
if layer == last_conv_layer:
found = True
# Sequential baaki layers
for layer in model.layers[1:]:
x = layer(x, training=False)
loss = x[:, 0]
grads = tape.gradient(loss, conv_outputs)
pooled_grads = tf.reduce_mean(grads, axis=(0, 1, 2))
conv_out = conv_outputs[0]
cam = conv_out @ pooled_grads[..., tf.newaxis]
cam = tf.squeeze(cam)
cam = tf.maximum(cam, 0) / (tf.math.reduce_max(cam) + 1e-8)
cam = cam.numpy()
return _overlay_heatmap(original_image, cam)
def generate_gradcam_pytorch_resnet(original_image, model, tensor):
return gradcam_pytorch(original_image, model, tensor, model.layer4)
def generate_gradcam_pytorch_mobilenet(original_image, model, tensor):
return gradcam_pytorch(original_image, model, tensor, model.features[-1])
def generate_gradcam_keras(original_image, model, array, predicted_class):
return gradcam_keras_manual(original_image, model, array, predicted_class) |