File size: 7,811 Bytes
f322570 ca77fd5 f322570 5f757e6 f322570 5f757e6 f322570 ca77fd5 f322570 ca77fd5 5bde481 ca77fd5 eca7b02 591d257 4e539c0 9cfa170 4e539c0 d844a2a eca7b02 d844a2a eca7b02 d844a2a eca7b02 f322570 ca77fd5 f322570 d844a2a f322570 d844a2a ca77fd5 d844a2a ca77fd5 d844a2a ca77fd5 eca7b02 ca77fd5 f322570 d844a2a eca7b02 ca77fd5 eca7b02 d844a2a ca77fd5 d844a2a ca77fd5 d844a2a f322570 13685f2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
import torch
import gradio as gr
import torch.nn as nn
import torch.nn.functional as F
import os
from pathlib import Path
from torch.nn import init
import torchvision.transforms as transforms
from PIL import Image
# MobileNetV3 Model Definition (keep this exactly as in your original code)
class hswish(nn.Module):
def forward(self, x):
return x * F.relu6(x + 3) / 6
class hsigmoid(nn.Module):
def forward(self, x):
return F.relu6(x + 3) / 6
class SeModule(nn.Module):
def __init__(self, in_size, reduction=4):
super().__init__()
self.se = nn.Sequential(
nn.AdaptiveAvgPool2d(1),
nn.Conv2d(in_size, in_size//reduction, 1, bias=False),
nn.BatchNorm2d(in_size//reduction),
nn.ReLU(inplace=True),
nn.Conv2d(in_size//reduction, in_size, 1, bias=False),
nn.BatchNorm2d(in_size),
hsigmoid()
)
def forward(self, x):
return x * self.se(x)
class Block(nn.Module):
def __init__(self, kernel_size, in_size, expand_size, out_size, nolinear, semodule, stride):
super().__init__()
self.stride = stride
self.se = semodule
self.conv1 = nn.Conv2d(in_size, expand_size, 1, 1, 0, bias=False)
self.bn1 = nn.BatchNorm2d(expand_size)
self.nolinear1 = nolinear
self.conv2 = nn.Conv2d(expand_size, expand_size, kernel_size, stride, kernel_size//2, groups=expand_size, bias=False)
self.bn2 = nn.BatchNorm2d(expand_size)
self.nolinear2 = nolinear
self.conv3 = nn.Conv2d(expand_size, out_size, 1, 1, 0, bias=False)
self.bn3 = nn.BatchNorm2d(out_size)
self.shortcut = nn.Sequential()
if stride == 1 and in_size != out_size:
self.shortcut = nn.Sequential(
nn.Conv2d(in_size, out_size, 1, 1, 0, bias=False),
nn.BatchNorm2d(out_size),
)
def forward(self, x):
out = self.nolinear1(self.bn1(self.conv1(x)))
out = self.nolinear2(self.bn2(self.conv2(out)))
out = self.bn3(self.conv3(out))
if self.se: out = self.se(out)
return out + self.shortcut(x) if self.stride==1 else out
class MobileNetV3_Small(nn.Module):
def __init__(self, num_classes=30):
super().__init__()
self.conv1 = nn.Conv2d(3, 16, 3, 2, 1, bias=False)
self.bn1 = nn.BatchNorm2d(16)
self.hs1 = hswish()
self.bneck = nn.Sequential(
Block(3, 16, 16, 16, nn.ReLU(), SeModule(16), 2),
Block(3, 16, 72, 24, nn.ReLU(), None, 2),
Block(3, 24, 88, 24, nn.ReLU(), None, 1),
Block(5, 24, 96, 40, hswish(), SeModule(40), 2),
Block(5, 40, 240, 40, hswish(), SeModule(40), 1),
Block(5, 40, 240, 40, hswish(), SeModule(40), 1),
Block(5, 40, 120, 48, hswish(), SeModule(48), 1),
Block(5, 48, 144, 48, hswish(), SeModule(48), 1),
Block(5, 48, 288, 96, hswish(), SeModule(96), 2),
Block(5, 96, 576, 96, hswish(), SeModule(96), 1),
Block(5, 96, 576, 96, hswish(), SeModule(96), 1),
)
self.conv2 = nn.Conv2d(96, 576, 1, 1, 0, bias=False)
self.bn2 = nn.BatchNorm2d(576)
self.hs2 = hswish()
self.linear3 = nn.Linear(576, 1280)
self.bn3 = nn.BatchNorm1d(1280)
self.hs3 = hswish()
self.linear4 = nn.Linear(1280, num_classes)
for m in self.modules():
if isinstance(m, nn.Conv2d):
init.kaiming_normal_(m.weight, mode='fan_out')
if m.bias is not None: init.constant_(m.bias, 0)
elif isinstance(m, nn.BatchNorm2d):
init.constant_(m.weight, 1)
init.constant_(m.bias, 0)
elif isinstance(m, nn.Linear):
init.normal_(m.weight, std=0.001)
if m.bias is not None: init.constant_(m.bias, 0)
def forward(self, x):
x = self.hs1(self.bn1(self.conv1(x)))
x = self.bneck(x)
x = self.hs2(self.bn2(self.conv2(x)))
x = F.avg_pool2d(x, x.size()[2:])
x = x.view(x.size(0), -1)
x = self.hs3(self.bn3(self.linear3(x)))
return self.linear4(x)
# Initialize Model
model = MobileNetV3_Small().cpu()
model.load_state_dict(torch.load("MobileNet3_small_StateDictionary.pth", map_location='cpu'))
model.eval()
# Class Labels
classes = [
'antelope', 'buffalo', 'chimpanzee', 'cow', 'deer', 'dolphin',
'elephant', 'fox', 'giant+panda', 'giraffe', 'gorilla', 'grizzlybear',
'hamster', 'hippopotamus', 'horse', 'humpbackwhale', 'leopard', 'lion',
'moose', 'otter', 'ox', 'pig', 'polarbear', 'rabbit', 'rhinoceros',
'seal', 'sheep', 'squirrel', 'tiger', 'zebra'
]
# Precompute example image paths
example_dir = "examples"
example_images = [os.path.join(example_dir, f) for f in os.listdir(example_dir)
if f.lower().endswith(('.png', '.jpg', '.jpeg', '.webp'))]
# Custom CSS for styling
css = """
.centered-examples {
margin: 0 auto !important;
justify-content: center !important;
gap: 8px !important;
}
.centered-examples .thumb {
height: 100px !important;
width: 100px !important;
object-fit: cover !important;
}
"""
# PREPROCESSING PIPELINE (ADD THIS BACK)
preprocess = transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])
# Precompute example image paths
example_dir = "examples"
example_images = [os.path.join(example_dir, f) for f in os.listdir(example_dir)
if f.lower().endswith(('.png', '.jpg', '.jpeg', '.webp'))]
def predict(img_path):
"""Process single image and return prediction"""
if not img_path:
return "Please select or upload an image first"
try:
image = Image.open(img_path).convert('RGB')
tensor = preprocess(image).unsqueeze(0)
with torch.inference_mode():
outputs = model(tensor)
_, pred = torch.max(outputs, 1)
return classes[pred.item()]
except Exception as e:
return f"Error: {str(e)}"
with gr.Blocks(title="Animal Classifier", css=css) as demo:
gr.Markdown("## 🐾 Animal Classifier")
gr.Markdown("Select an image below or upload your own, then click Classify")
# Store current image path
current_image = gr.State()
with gr.Row():
with gr.Column():
image_preview = gr.Image(label="Selected Image", type="filepath")
upload_btn = gr.UploadButton("Upload Custom Image", file_types=["image"])
classify_btn = gr.Button("Classify 🚀", variant="primary")
result = gr.Textbox(label="Prediction", lines=3)
# Example gallery at bottom
with gr.Row(variant="panel"):
examples_gallery = gr.Gallery(
value=example_images,
label="Example Images (Click to Select)",
columns=7,
height=120,
allow_preview=False,
elem_classes=["centered-examples"]
)
# Handle image selection from examples
def select_example(evt: gr.SelectData):
return example_images[evt.index]
examples_gallery.select(
fn=select_example,
outputs=[image_preview, current_image],
show_progress=False
)
# Handle custom uploads
upload_btn.upload(
fn=lambda file: (file.name, file.name),
inputs=upload_btn,
outputs=[image_preview, current_image]
)
# Handle classification
classify_btn.click(
fn=predict,
inputs=current_image,
outputs=result
)
if __name__ == "__main__":
demo.launch(show_error=True) |