Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import torch | |
| import torch.nn as nn | |
| import torch.nn.functional as F | |
| from torchvision import transforms | |
| from PIL import Image | |
| import numpy as np | |
| # CIFAR-100 class names | |
| CIFAR100_CLASSES = [ | |
| 'apple', 'aquarium_fish', 'baby', 'bear', 'beaver', 'bed', 'bee', 'beetle', | |
| 'bicycle', 'bottle', 'bowl', 'boy', 'bridge', 'bus', 'butterfly', 'camel', | |
| 'can', 'castle', 'caterpillar', 'cattle', 'chair', 'chimpanzee', 'clock', | |
| 'cloud', 'cockroach', 'couch', 'crab', 'crocodile', 'cup', 'dinosaur', | |
| 'dolphin', 'elephant', 'flatfish', 'forest', 'fox', 'girl', 'hamster', | |
| 'house', 'kangaroo', 'keyboard', 'lamp', 'lawn_mower', 'leopard', 'lion', | |
| 'lizard', 'lobster', 'man', 'maple_tree', 'motorcycle', 'mountain', 'mouse', | |
| 'mushroom', 'oak_tree', 'orange', 'orchid', 'otter', 'palm_tree', 'pear', | |
| 'pickup_truck', 'pine_tree', 'plain', 'plate', 'poppy', 'porcupine', | |
| 'possum', 'rabbit', 'raccoon', 'ray', 'road', 'rocket', 'rose', | |
| 'sea', 'seal', 'shark', 'shrew', 'skunk', 'skyscraper', 'snail', 'snake', | |
| 'spider', 'squirrel', 'streetcar', 'sunflower', 'sweet_pepper', 'table', | |
| 'tank', 'telephone', 'television', 'tiger', 'tractor', 'train', 'trout', | |
| 'tulip', 'turtle', 'wardrobe', 'whale', 'willow_tree', 'wolf', 'woman', 'worm' | |
| ] | |
| # ResNet-18 Architecture | |
| class BasicBlock(nn.Module): | |
| expansion = 1 | |
| def __init__(self, in_planes, planes, stride=1): | |
| super(BasicBlock, self).__init__() | |
| self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False) | |
| self.bn1 = nn.BatchNorm2d(planes) | |
| self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False) | |
| self.bn2 = nn.BatchNorm2d(planes) | |
| self.shortcut = nn.Sequential() | |
| if stride != 1 or in_planes != self.expansion * planes: | |
| self.shortcut = nn.Sequential( | |
| nn.Conv2d(in_planes, self.expansion * planes, kernel_size=1, stride=stride, bias=False), | |
| nn.BatchNorm2d(self.expansion * planes) | |
| ) | |
| def forward(self, x): | |
| out = F.relu(self.bn1(self.conv1(x))) | |
| out = self.bn2(self.conv2(out)) | |
| out += self.shortcut(x) | |
| out = F.relu(out) | |
| return out | |
| class ResNet(nn.Module): | |
| def __init__(self, block, num_blocks, num_classes=100): | |
| super(ResNet, self).__init__() | |
| self.in_planes = 64 # Changed from 32 to 64 | |
| # For CIFAR-100, use kernel_size=3 and stride=1 (not 7 and 2 like ImageNet) | |
| self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False) # Changed from 32 to 64 | |
| self.bn1 = nn.BatchNorm2d(64) # Changed from 32 to 64 | |
| self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=1) # Changed from 32 to 64 | |
| self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2) # Changed from 64 to 128 | |
| self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2) # Changed from 128 to 256 | |
| self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2) # Changed from 256 to 512 | |
| self.linear = nn.Linear(512 * block.expansion, num_classes) # Changed from 256 to 512 | |
| def _make_layer(self, block, planes, num_blocks, stride): | |
| strides = [stride] + [1] * (num_blocks - 1) | |
| layers = [] | |
| for stride in strides: | |
| layers.append(block(self.in_planes, planes, stride)) | |
| self.in_planes = planes * block.expansion | |
| return nn.Sequential(*layers) | |
| def forward(self, x): | |
| out = F.relu(self.bn1(self.conv1(x))) | |
| out = self.layer1(out) | |
| out = self.layer2(out) | |
| out = self.layer3(out) | |
| out = self.layer4(out) | |
| out = F.avg_pool2d(out, 4) | |
| out = out.view(out.size(0), -1) | |
| out = self.linear(out) | |
| return out | |
| # Load model | |
| def load_model(): | |
| device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') | |
| model = ResNet(BasicBlock, [2, 2, 2, 2], num_classes=100) | |
| # Load checkpoint | |
| try: | |
| checkpoint = torch.load('checkpoints/resnet18_best.pth', map_location=device) | |
| model.load_state_dict(checkpoint['model_state_dict']) | |
| print(f"Model loaded successfully! Best accuracy: {checkpoint.get('best_acc', 'N/A')}%") | |
| except Exception as e: | |
| print(f"Error loading model: {e}") | |
| print("Using randomly initialized model (for demo purposes)") | |
| model = model.to(device) | |
| model.eval() | |
| return model, device | |
| # Image preprocessing | |
| def preprocess_image(image): | |
| transform = transforms.Compose([ | |
| transforms.Resize((32, 32)), | |
| transforms.ToTensor(), | |
| transforms.Normalize((0.5071, 0.4867, 0.4408), (0.2675, 0.2565, 0.2761)) | |
| ]) | |
| if image.mode != 'RGB': | |
| image = image.convert('RGB') | |
| img_tensor = transform(image).unsqueeze(0) | |
| return img_tensor | |
| # Prediction function | |
| def predict(image): | |
| if image is None: | |
| return None | |
| # Preprocess | |
| img_tensor = preprocess_image(image) | |
| img_tensor = img_tensor.to(device) | |
| # Predict | |
| with torch.no_grad(): | |
| outputs = model(img_tensor) | |
| probabilities = F.softmax(outputs, dim=1)[0] | |
| # Get top 5 predictions | |
| top5_prob, top5_idx = torch.topk(probabilities, 5) | |
| # Format results | |
| results = {} | |
| for i in range(5): | |
| class_name = CIFAR100_CLASSES[top5_idx[i]] | |
| confidence = top5_prob[i].item() | |
| results[class_name] = float(confidence) | |
| return results | |
| # Initialize model | |
| print("Loading model...") | |
| model, device = load_model() | |
| print("Model loaded!") | |
| # Create Gradio interface | |
| title = "ResNet-18 CIFAR-100 Image Classifier" | |
| description = """ | |
| ## 🎯 ResNet-18 trained on CIFAR-100 Dataset | |
| This model achieves **77.18% test accuracy** on CIFAR-100! | |
| **How to use:** | |
| 1. Upload an image or use one of the examples | |
| 2. The model will classify it into one of 100 categories | |
| 3. See the top 5 predictions with confidence scores | |
| **Note:** This model was trained on 32×32 images from CIFAR-100, so it works best with: | |
| - Small objects | |
| - Centered subjects | |
| - Simple backgrounds | |
| - Animals, vehicles, household items, plants, etc. | |
| **Training Details:** | |
| - Architecture: ResNet-18 (11M parameters) | |
| - Dataset: CIFAR-100 (100 classes) | |
| - Techniques: OneCycleLR, Cutout, Label Smoothing | |
| - Training Time: ~70 minutes on RTX 4070 | |
| """ | |
| article = """ | |
| ### Model Performance | |
| - **Test Accuracy:** 77.18% | |
| - **Train Accuracy:** 98.25% | |
| - **Total Epochs:** 100 | |
| - **Training Time:** ~70 minutes | |
| ### Classes | |
| The model can recognize 100 different classes including: | |
| - **Animals (42 classes):** bear, beaver, bee, beetle, butterfly, camel, cattle, chimpanzee, caterpillar, crab, crocodile, dinosaur, dolphin, elephant, flatfish, fox, hamster, kangaroo, leopard, lion, lizard, lobster, mouse, otter, porcupine, possum, rabbit, raccoon, ray, seal, shark, shrew, skunk, snail, snake, spider, squirrel, tiger, trout, turtle, whale, wolf, worm | |
| - **Vehicles (10 classes):** bicycle, bus, motorcycle, pickup_truck, lawn_mower, rocket, streetcar, tank, tractor, train | |
| - **Household Items (15 classes):** bed, bottle, bowl, can, chair, clock, couch, cup, keyboard, lamp, plate, table, telephone, television, wardrobe | |
| - **People (5 classes):** baby, boy, girl, man, woman | |
| - **Plants:** | |
| - **Flowers (5 classes):** orchid, poppy, rose, sunflower, tulip | |
| - **Trees (5 classes):** maple_tree, oak_tree, palm_tree, pine_tree, willow_tree | |
| - **Food (5 classes):** apple, mushroom, orange, pear, sweet_pepper | |
| - **Nature & Structures (13 classes):** aquarium_fish, bridge, castle, cloud, forest, house, mountain, plain, road, sea, skyscraper | |
| --- | |
| **Repository:** [GitHub](https://github.com/godsofheaven/Resnet-Model-Implementation-for-CIFAR-100-Dataset) | |
| """ | |
| # Create interface | |
| demo = gr.Interface( | |
| fn=predict, | |
| inputs=gr.Image(type="pil", label="Upload Image"), | |
| outputs=gr.Label(num_top_classes=5, label="Predictions"), | |
| title=title, | |
| description=description, | |
| article=article, | |
| examples=[ | |
| # Users can add their own example images | |
| ], | |
| theme=gr.themes.Soft(), | |
| analytics_enabled=False, | |
| ) | |
| # Launch | |
| if __name__ == "__main__": | |
| demo.launch() | |