ChandraPrakashBathula's picture
Create model.py
a36ad62 verified
Raw History Blame Contribute Delete
2.3 kB
from collections import OrderedDict
import torch
import torch.nn as nn
import torch.nn.functional as F
class SceneCNN(nn.Module):
def __init__(self, base=16, num_classes=6, conv_dropout=0.1, fc_dropout=0.4):
super().__init__()
channels = [base, base * 2, base * 4, base * 8]
layers = OrderedDict()
in_ch = 3
for i, out_ch in enumerate(channels, 1):
layers[f"conv{i}a"] = nn.Conv2d(in_ch, out_ch, 3, padding=1, bias=False)
layers[f"bn{i}a"] = nn.BatchNorm2d(out_ch)
layers[f"relu{i}a"] = nn.ReLU()
layers[f"conv{i}b"] = nn.Conv2d(out_ch, out_ch, 3, padding=1, bias=False)
layers[f"bn{i}b"] = nn.BatchNorm2d(out_ch)
layers[f"relu{i}b"] = nn.ReLU()
layers[f"pool{i}"] = nn.MaxPool2d(2)
layers[f"drop{i}"] = nn.Dropout2d(conv_dropout)
in_ch = out_ch
self.features = nn.Sequential(layers)
self.gap = nn.AdaptiveAvgPool2d(1)
self.flatten = nn.Flatten()
self.drop_fc = nn.Dropout(fc_dropout)
self.fc1 = nn.Linear(channels[-1], 128)
self.relu_fc = nn.ReLU()
self.fc2 = nn.Linear(128, num_classes)
def forward(self, x):
x = self.features(x)
x = self.flatten(self.gap(x))
x = self.drop_fc(x)
x = self.relu_fc(self.fc1(x))
return self.fc2(x)
def grad_cam(model, x):
"""x: normalized tensor (3,H,W). Returns (cam HxW in [0,1], softmax probs)."""
model.eval()
store = {}
def hook(_, __, out):
store["act"] = out
out.register_hook(lambda g: store.__setitem__("grad", g))
h = model.features.relu4b.register_forward_hook(hook)
with torch.enable_grad():
logits = model(x.unsqueeze(0))
h.remove()
cls = logits.argmax(1).item()
model.zero_grad()
logits[0, cls].backward()
act, grad = store["act"][0], store["grad"][0]
weights = grad.mean(dim=(1, 2))
cam = F.relu((weights[:, None, None] * act).sum(0))
cam = F.interpolate(cam[None, None], size=x.shape[1:], mode="bilinear", align_corners=False)[0, 0]
cam = (cam - cam.min()) / (cam.max() - cam.min() + 1e-8)
probs = F.softmax(logits, 1)[0]
return cam.detach().numpy(), probs.detach().numpy()