Conn Finnegan commited on
Commit
17cba64
·
verified ·
1 Parent(s): 1e04ed9

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +44 -47
app.py CHANGED
@@ -1,7 +1,7 @@
1
  import gradio as gr
2
  import torch
 
3
  from torchvision import models, transforms
4
- from torch.nn import functional as F
5
  from PIL import Image
6
  import numpy as np
7
  import cv2
@@ -14,82 +14,79 @@ model.eval()
14
 
15
  classes = ['benign', 'malignant']
16
 
17
- # Preprocessing
18
  transform = transforms.Compose([
19
  transforms.Resize((224, 224)),
20
  transforms.ToTensor()
21
  ])
22
 
23
- # Grad-CAM setup
24
- final_conv_layer = model.layer3[1].conv2 # Adjust if using a different architecture
25
- gradients = []
26
 
27
- def save_gradient(module, grad_input, grad_output):
28
- gradients.append(grad_output[0])
 
29
 
30
- final_conv_layer.register_forward_hook(save_gradient)
 
 
31
 
32
- def generate_gradcam(input_tensor, pred_class):
 
 
 
 
 
 
 
 
33
  model.zero_grad()
34
  output = model(input_tensor)
35
- class_score = output[0, pred_class]
36
  class_score.backward()
37
 
38
- grads_val = gradients[-1].detach().numpy()[0]
39
- activations = final_conv_layer_output.detach().numpy()[0]
40
-
41
- weights = np.mean(grads_val, axis=(1, 2))
42
- cam = np.zeros(activations.shape[1:], dtype=np.float32)
43
-
44
- for i, w in enumerate(weights):
45
- cam += w * activations[i]
46
-
47
  cam = np.maximum(cam, 0)
48
  cam = cv2.resize(cam, (224, 224))
49
- cam = cam - np.min(cam)
50
- cam = cam / np.max(cam)
51
-
52
  return cam
53
 
54
- # Hook to get activations
55
- def get_activations(module, input, output):
56
- global final_conv_layer_output
57
- final_conv_layer_output = output
 
58
 
59
- final_conv_layer.register_forward_hook(get_activations)
 
60
 
61
- # Main prediction and Grad-CAM overlay function
62
- def predict(img):
63
- gradients.clear()
64
- img_rgb = img.convert("RGB")
65
- input_tensor = transform(img_rgb).unsqueeze(0)
66
-
67
- with torch.no_grad():
68
- output = model(input_tensor)
69
- probs = F.softmax(output[0], dim=0)
70
- pred_class = torch.argmax(probs).item()
71
 
72
- # Grad-CAM
73
  cam = generate_gradcam(input_tensor, pred_class)
74
 
75
- # Convert CAM to heatmap
76
- heatmap = (cam * 255).astype(np.uint8)
77
  heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)
78
 
79
- # Overlay heatmap on image
80
- img_np = np.array(img_rgb.resize((224, 224)))
81
  overlay = cv2.addWeighted(img_np, 0.6, heatmap, 0.4, 0)
82
-
83
- # Convert back to PIL
84
  overlay_img = Image.fromarray(cv2.cvtColor(overlay, cv2.COLOR_BGR2RGB))
85
 
86
  return {classes[i]: float(probs[i]) for i in range(2)}, overlay_img
87
 
88
- # UI
89
- title = "🧠 Lumen: Skin Cancer Classifier with Grad-CAM"
90
  description = """
91
  Upload a dermoscopic image of a mole or lesion. The model will classify it as <b>benign</b> or <b>malignant</b> and show a heatmap of what it focused on.<br><br>
92
- <b>Disclaimer:</b> This tool is for educational use only.
93
  """
94
 
95
  demo = gr.Interface(
 
1
  import gradio as gr
2
  import torch
3
+ import torch.nn.functional as F
4
  from torchvision import models, transforms
 
5
  from PIL import Image
6
  import numpy as np
7
  import cv2
 
14
 
15
  classes = ['benign', 'malignant']
16
 
17
+ # Transform
18
  transform = transforms.Compose([
19
  transforms.Resize((224, 224)),
20
  transforms.ToTensor()
21
  ])
22
 
23
+ # Target layer for Grad-CAM
24
+ target_layer = model.layer3[1].conv2
 
25
 
26
+ # Store activations & gradients
27
+ activations = None
28
+ gradients = None
29
 
30
+ def forward_hook(module, input, output):
31
+ global activations
32
+ activations = output.detach()
33
 
34
+ def backward_hook(module, grad_input, grad_output):
35
+ global gradients
36
+ gradients = grad_output[0].detach()
37
+
38
+ target_layer.register_forward_hook(forward_hook)
39
+ target_layer.register_backward_hook(backward_hook)
40
+
41
+ # Grad-CAM function
42
+ def generate_gradcam(input_tensor, class_idx):
43
  model.zero_grad()
44
  output = model(input_tensor)
45
+ class_score = output[0, class_idx]
46
  class_score.backward()
47
 
48
+ pooled_gradients = torch.mean(gradients, dim=[0, 2, 3]) # [C]
49
+ weighted_activations = activations[0] * pooled_gradients[:, None, None] # [C, H, W]
50
+ cam = torch.sum(weighted_activations, dim=0).cpu().numpy()
51
+
52
+ # Normalize and resize
 
 
 
 
53
  cam = np.maximum(cam, 0)
54
  cam = cv2.resize(cam, (224, 224))
55
+ cam -= cam.min()
56
+ cam /= cam.max()
 
57
  return cam
58
 
59
+ # Full pipeline
60
+ def predict(img):
61
+ global activations, gradients
62
+ activations = None
63
+ gradients = None
64
 
65
+ img = img.convert("RGB")
66
+ input_tensor = transform(img).unsqueeze(0)
67
 
68
+ output = model(input_tensor)
69
+ probs = F.softmax(output[0], dim=0)
70
+ pred_class = torch.argmax(probs).item()
 
 
 
 
 
 
 
71
 
 
72
  cam = generate_gradcam(input_tensor, pred_class)
73
 
74
+ # Convert to heatmap
75
+ heatmap = np.uint8(255 * cam)
76
  heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)
77
 
78
+ # Overlay
79
+ img_np = np.array(img.resize((224, 224)))
80
  overlay = cv2.addWeighted(img_np, 0.6, heatmap, 0.4, 0)
 
 
81
  overlay_img = Image.fromarray(cv2.cvtColor(overlay, cv2.COLOR_BGR2RGB))
82
 
83
  return {classes[i]: float(probs[i]) for i in range(2)}, overlay_img
84
 
85
+ # Gradio interface
86
+ title = "🧠 Lumen: Skin Cancer Classifier + Grad-CAM"
87
  description = """
88
  Upload a dermoscopic image of a mole or lesion. The model will classify it as <b>benign</b> or <b>malignant</b> and show a heatmap of what it focused on.<br><br>
89
+ <b>Disclaimer:</b> For educational use only.
90
  """
91
 
92
  demo = gr.Interface(