Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import torch | |
| import torch.nn as nn | |
| from torchvision import transforms | |
| from PIL import Image | |
| # --------------------------------------------------------- | |
| # 1. MODEL ARCHITECTURE | |
| # --------------------------------------------------------- | |
| class SimpleCNN(nn.Module): | |
| def __init__(self, num_classes=10): | |
| super(SimpleCNN, self).__init__() | |
| self.conv_block1 = nn.Sequential( | |
| nn.Conv2d(in_channels=3, out_channels=16, kernel_size=3, padding=1), | |
| nn.ReLU(), | |
| nn.MaxPool2d(kernel_size=2, stride=2), | |
| ) | |
| self.conv_block2 = nn.Sequential( | |
| nn.Conv2d(in_channels=16, out_channels=32, kernel_size=3, padding=1), | |
| nn.ReLU(), | |
| nn.MaxPool2d(kernel_size=2, stride=2), | |
| ) | |
| self.classifier = nn.Sequential( | |
| nn.Flatten(), | |
| nn.Linear(in_features=32 * 32 * 32, out_features=128), | |
| nn.ReLU(), | |
| nn.Linear(in_features=128, out_features=num_classes), | |
| ) | |
| def forward(self, x): | |
| x = self.conv_block1(x) | |
| x = self.conv_block2(x) | |
| x = self.classifier(x) | |
| return x | |
| # --------------------------------------------------------- | |
| # 2. SETUP | |
| # --------------------------------------------------------- | |
| # Initialize model | |
| model = SimpleCNN() | |
| # Load weights (Ensure 'fulldigits.pt' is uploaded to Hugging Face Files!) | |
| try: | |
| model.load_state_dict(torch.load("fulldigits.pt", map_location="cpu")) | |
| model.eval() | |
| except FileNotFoundError: | |
| print("Error: 'fulldigits.pt' not found. Please upload your model file.") | |
| # Define transforms | |
| # CRITICAL FIX: Added lambda to force RGB. | |
| # This prevents crashes if someone uploads a Grayscale or RGBA image. | |
| transform = transforms.Compose([ | |
| transforms.Lambda(lambda x: x.convert("RGB")), | |
| transforms.Resize((128, 128)), | |
| transforms.ToTensor(), | |
| transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]), | |
| ]) | |
| # --------------------------------------------------------- | |
| # 3. PREDICTION FUNCTION | |
| # --------------------------------------------------------- | |
| def predict(image): | |
| if image is None: | |
| return None | |
| # Transform image | |
| img_tensor = transform(image).unsqueeze(0) | |
| # Make prediction | |
| with torch.no_grad(): | |
| output = model(img_tensor) | |
| # Get probabilities | |
| probabilities = torch.nn.functional.softmax(output[0], dim=0) | |
| # Return a dictionary for Gradio's Label component | |
| # This creates the nice bar chart effect | |
| return {str(i): float(probabilities[i]) for i in range(10)} | |
| # --------------------------------------------------------- | |
| # 4. GRADIO INTERFACE | |
| # --------------------------------------------------------- | |
| demo = gr.Interface( | |
| fn=predict, | |
| inputs=gr.Image(type="pil", label="Upload Image"), | |
| outputs=gr.Label(num_top_classes=3, label="Predictions"), # Changed to Label for better UI | |
| title="Digit Classification Project", | |
| description="Upload an image to check if it contains a digit (0-9).", | |
| # removed share=True for production deployment | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() |