Spaces:
Running
Running
changes to gradcam
Browse files- app.py +0 -1
- inference.py +29 -12
app.py
CHANGED
|
@@ -51,7 +51,6 @@ def root():
|
|
| 51 |
</html>
|
| 52 |
"""
|
| 53 |
|
| 54 |
-
|
| 55 |
@app.get("/health")
|
| 56 |
def health():
|
| 57 |
return {"status": "ok", "device": DEVICE, "model": "DenseNet121-CBAM"}
|
|
|
|
| 51 |
</html>
|
| 52 |
"""
|
| 53 |
|
|
|
|
| 54 |
@app.get("/health")
|
| 55 |
def health():
|
| 56 |
return {"status": "ok", "device": DEVICE, "model": "DenseNet121-CBAM"}
|
inference.py
CHANGED
|
@@ -97,17 +97,17 @@ class GradCAMPlusPlus:
|
|
| 97 |
for name, module in self.model.named_modules():
|
| 98 |
if name == target_layer_name:
|
| 99 |
self.hooks.append(module.register_forward_hook(forward_hook))
|
| 100 |
-
self.hooks.append(module.
|
| 101 |
return
|
| 102 |
raise ValueError(f"Layer '{target_layer_name}' not found in model")
|
| 103 |
|
| 104 |
def generate_cam(self, input_tensor, class_idx=None):
|
| 105 |
self.model.eval()
|
| 106 |
-
input_tensor = input_tensor.clone().detach().requires_grad_(True)
|
| 107 |
|
| 108 |
for param in self.model.parameters():
|
| 109 |
param.requires_grad = True
|
| 110 |
|
|
|
|
| 111 |
output = self.model(input_tensor)
|
| 112 |
|
| 113 |
if class_idx is None:
|
|
@@ -117,18 +117,34 @@ class GradCAMPlusPlus:
|
|
| 117 |
self.model.zero_grad()
|
| 118 |
target_score.backward(retain_graph=True)
|
| 119 |
|
| 120 |
-
grads = self.gradients
|
| 121 |
-
acts = self.activations
|
|
|
|
|
|
|
| 122 |
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
alpha_denom = torch.where(alpha_denom != 0.0, alpha_denom, torch.ones_like(alpha_denom))
|
| 127 |
-
alpha = alpha_num.div(alpha_denom + 1e-7)
|
| 128 |
-
weights = alpha.mul(torch.relu(grads).view(1, grads.size(1), -1).sum(dim=-1))
|
| 129 |
|
| 130 |
-
|
| 131 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 132 |
cam = (cam - cam.min()) / (cam.max() - cam.min() + 1e-8)
|
| 133 |
return cam
|
| 134 |
|
|
@@ -137,6 +153,7 @@ class GradCAMPlusPlus:
|
|
| 137 |
hook.remove()
|
| 138 |
|
| 139 |
|
|
|
|
| 140 |
# βββ Preprocessing βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 141 |
|
| 142 |
def get_transform(image_size=512):
|
|
|
|
| 97 |
for name, module in self.model.named_modules():
|
| 98 |
if name == target_layer_name:
|
| 99 |
self.hooks.append(module.register_forward_hook(forward_hook))
|
| 100 |
+
self.hooks.append(module.register_full_backward_hook(backward_hook))
|
| 101 |
return
|
| 102 |
raise ValueError(f"Layer '{target_layer_name}' not found in model")
|
| 103 |
|
| 104 |
def generate_cam(self, input_tensor, class_idx=None):
|
| 105 |
self.model.eval()
|
|
|
|
| 106 |
|
| 107 |
for param in self.model.parameters():
|
| 108 |
param.requires_grad = True
|
| 109 |
|
| 110 |
+
input_tensor = input_tensor.clone().detach().requires_grad_(True)
|
| 111 |
output = self.model(input_tensor)
|
| 112 |
|
| 113 |
if class_idx is None:
|
|
|
|
| 117 |
self.model.zero_grad()
|
| 118 |
target_score.backward(retain_graph=True)
|
| 119 |
|
| 120 |
+
grads = self.gradients # [1, C, H, W]
|
| 121 |
+
acts = self.activations # [1, C, H, W]
|
| 122 |
+
|
| 123 |
+
B, C, H, W = grads.shape
|
| 124 |
|
| 125 |
+
# ββ GradCAM++ alpha computation (all ops stay in [B, C, H, W]) ββ
|
| 126 |
+
grads_sq = grads.pow(2) # [1, C, H, W]
|
| 127 |
+
grads_cub = grads.pow(3) # [1, C, H, W]
|
|
|
|
|
|
|
|
|
|
| 128 |
|
| 129 |
+
# sum over spatial dims H,W β [1, C, 1, 1] then broadcast back
|
| 130 |
+
spatial_sum = (acts * grads_cub).sum(dim=[2, 3], keepdim=True) # [1, C, 1, 1]
|
| 131 |
+
|
| 132 |
+
alpha_denom = 2.0 * grads_sq + spatial_sum # [1, C, H, W]
|
| 133 |
+
alpha_denom = torch.where(
|
| 134 |
+
alpha_denom != 0.0,
|
| 135 |
+
alpha_denom,
|
| 136 |
+
torch.ones_like(alpha_denom)
|
| 137 |
+
)
|
| 138 |
+
alpha = grads_sq / (alpha_denom + 1e-7) # [1, C, H, W]
|
| 139 |
+
|
| 140 |
+
# weights: alpha * ReLU(grads), summed over H,W β [1, C, 1, 1]
|
| 141 |
+
weights = (alpha * torch.relu(grads)).sum(dim=[2, 3], keepdim=True) # [1, C, 1, 1]
|
| 142 |
+
|
| 143 |
+
# CAM: weighted sum of activations β [1, 1, H, W]
|
| 144 |
+
cam = (weights * acts).sum(dim=1, keepdim=True) # [1, 1, H, W]
|
| 145 |
+
cam = torch.relu(cam)
|
| 146 |
+
|
| 147 |
+
cam = cam.squeeze().cpu().detach().numpy() # [H, W]
|
| 148 |
cam = (cam - cam.min()) / (cam.max() - cam.min() + 1e-8)
|
| 149 |
return cam
|
| 150 |
|
|
|
|
| 153 |
hook.remove()
|
| 154 |
|
| 155 |
|
| 156 |
+
|
| 157 |
# βββ Preprocessing βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 158 |
|
| 159 |
def get_transform(image_size=512):
|