Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import torch | |
| import torch.nn as nn | |
| import torchvision.transforms as transforms | |
| from PIL import Image | |
| import torch.nn.functional as F | |
| import matplotlib.pyplot as plt | |
| import numpy as np | |
| import os | |
| # ----------------- CLASS LABELS ----------------- | |
| CLASSES = [ | |
| "airplane", "automobile", "bird", "cat", "deer", | |
| "dog", "frog", "horse", "ship", "truck" | |
| ] | |
| # ----------------- CNN MODEL (same as training) ----------------- | |
| class CNN(nn.Module): | |
| def __init__(self): | |
| super().__init__() | |
| self.conv_layer = nn.Sequential( | |
| nn.Conv2d(3, 32, kernel_size=3, padding=1), | |
| nn.ReLU(), | |
| nn.MaxPool2d(2, 2), | |
| nn.Conv2d(32, 64, kernel_size=3, padding=1), | |
| nn.ReLU(), | |
| nn.MaxPool2d(2, 2) | |
| ) | |
| self.fc_layer = nn.Sequential( | |
| nn.Linear(64 * 8 * 8, 256), | |
| nn.ReLU(), | |
| nn.Linear(256, 10) | |
| ) | |
| def forward(self, x): | |
| x = self.conv_layer(x) | |
| x = x.view(x.size(0), -1) | |
| x = self.fc_layer(x) | |
| return x | |
| # ----------------- LOAD TRAINED MODEL ----------------- | |
| model = CNN() | |
| import os | |
| MODEL_PATH = os.path.join(os.getcwd(), "model.pth") | |
| model.load_state_dict(torch.load(MODEL_PATH, map_location=torch.device('cpu'))) | |
| model.eval() | |
| # ----------------- IMAGE TRANSFORMS ----------------- | |
| transform = transforms.Compose([ | |
| transforms.Resize((32, 32)), | |
| transforms.ToTensor(), | |
| transforms.Normalize((0.5,), (0.5,)) | |
| ]) | |
| # ----------------- GRAD CAM UTILS ----------------- | |
| # ----------------- CORRECT GRAD-CAM IMPLEMENTATION ----------------- | |
| # Store activations + gradients | |
| activations = None | |
| gradients = None | |
| # Save forward activations | |
| def save_activation(module, input, output): | |
| global activations | |
| activations = output | |
| # Save backward gradients | |
| def save_gradient(module, grad_input, grad_output): | |
| global gradients | |
| gradients = grad_output[0] | |
| def generate_gradcam(model, image_tensor): | |
| global activations, gradients | |
| # Last conv layer | |
| last_conv_layer = model.conv_layer[3] # Conv2d(32 → 64) | |
| # Hook for forward activations | |
| forward_handle = last_conv_layer.register_forward_hook(save_activation) | |
| # Hook for backward gradients | |
| backward_handle = last_conv_layer.register_backward_hook(save_gradient) | |
| # Forward pass | |
| output = model(image_tensor) | |
| pred_class = output.argmax(dim=1) | |
| # Backward pass | |
| model.zero_grad() | |
| output[0, pred_class].backward() | |
| # Remove hooks | |
| forward_handle.remove() | |
| backward_handle.remove() | |
| # Process gradients + activations | |
| pooled_grads = torch.mean(gradients, dim=[0, 2, 3]) | |
| activation_maps = activations[0] | |
| # Weight channels | |
| for i in range(len(pooled_grads)): | |
| activation_maps[i, :, :] *= pooled_grads[i] | |
| heatmap = torch.mean(activation_maps, dim=0).detach().cpu().numpy() | |
| # Normalize | |
| heatmap = np.maximum(heatmap, 0) | |
| heatmap = heatmap / np.max(heatmap) | |
| return heatmap | |
| def overlay_heatmap(img, heatmap): | |
| heatmap = np.uint8(255 * heatmap) | |
| heatmap = Image.fromarray(heatmap).resize(img.size, Image.BILINEAR) | |
| heatmap = np.array(heatmap) | |
| # Colorize heatmap | |
| heatmap_color = plt.cm.jet(heatmap)[:, :, :3] * 255 | |
| heatmap_color = heatmap_color.astype(np.uint8) | |
| # Overlay with original | |
| img_np = np.array(img) | |
| superimposed = (0.6 * heatmap_color + 0.4 * img_np).astype(np.uint8) | |
| return Image.fromarray(superimposed) | |
| # ----------------- STREAMLIT UI ----------------- | |
| st.title("🖼️ CIFAR-10 Image Classifier (CNN)") | |
| uploaded_image = st.file_uploader("Upload an image", type=["jpg", "jpeg", "png"]) | |
| if uploaded_image: | |
| image = Image.open(uploaded_image).convert("RGB") | |
| st.image(image, caption="Uploaded Image", width=250) | |
| img_tensor = transform(image).unsqueeze(0) | |
| with torch.no_grad(): | |
| outputs = model(img_tensor) | |
| # Apply softmax to get probabilities | |
| probs = F.softmax(outputs, dim=1)[0] | |
| # Get top-3 predictions | |
| top3_prob, top3_idx = torch.topk(probs, 3) | |
| st.write("### 🔍 Top Predictions:") | |
| for i in range(3): | |
| st.write(f"**{CLASSES[top3_idx[i]]}: {top3_prob[i].item()*100:.2f}%**") | |
| # ----------------- BAR CHART ----------------- | |
| st.write("### 📊 Probability Distribution") | |
| fig, ax = plt.subplots() | |
| ax.bar(CLASSES, probs.tolist()) | |
| plt.xticks(rotation=45) | |
| st.pyplot(fig) | |
| # ----------------- GENERATE GRAD-CAM ----------------- | |
| heatmap = generate_gradcam(model, img_tensor) | |
| cam_image = overlay_heatmap(image, heatmap) | |
| st.write("### 🔥 Grad-CAM Heatmap") | |
| st.image(cam_image, caption="Where the model is looking", use_column_width=True) | |