kikogazda commited on
Commit
2463f57
·
verified ·
1 Parent(s): 00e63d1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +47 -30
app.py CHANGED
@@ -1,50 +1,67 @@
1
  import gradio as gr
2
  import torch
 
3
  from torchvision import models, transforms
4
  from PIL import Image
5
  import scipy.io
6
-
7
- # --- Load class names from cars_meta.mat ---
8
  import numpy as np
9
- meta = scipy.io.loadmat("cars_meta.mat")
10
- class_names = [name[0] for name in meta['class_names'][0]]
11
-
12
- num_classes = len(class_names)
13
-
14
- # --- Load model ---
15
- def load_model():
16
- model = models.resnet50(pretrained=False)
17
- model.fc = torch.nn.Linear(model.fc.in_features, num_classes)
18
- state_dict = torch.load("twin_car_best_model_v2.pth", map_location="cpu")
19
- model.load_state_dict(state_dict)
20
- model.eval()
 
 
 
 
 
 
 
21
  return model
22
 
23
- model = load_model()
 
 
24
 
25
- # --- Image preprocessing ---
26
- transform = transforms.Compose([
27
- transforms.Resize((224, 224)),
 
 
 
28
  transforms.ToTensor(),
29
- # If you normalized during training, add normalization here:
30
- transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
31
  ])
32
 
33
- # --- Prediction ---
34
  def predict(img):
35
- img = transform(img).unsqueeze(0)
 
36
  with torch.no_grad():
37
- logits = model(img)
38
- probs = torch.softmax(logits, dim=1)
39
- top5_prob, top5_catid = torch.topk(probs, 5)
40
- results = {class_names[i]: float(top5_prob[0][idx]) for idx, i in enumerate(top5_catid[0])}
41
  return results
42
 
43
- # --- Gradio interface ---
 
 
 
 
 
44
  gr.Interface(
45
  fn=predict,
46
- inputs=gr.Image(type="pil"),
47
  outputs=gr.Label(num_top_classes=5),
48
- title="TwinCar-196 Fine-Grained Car Classifier",
49
- description="Upload a car image to see the top-5 predicted makes and models."
 
50
  ).launch()
 
1
  import gradio as gr
2
  import torch
3
+ import torch.nn as nn
4
  from torchvision import models, transforms
5
  from PIL import Image
6
  import scipy.io
 
 
7
  import numpy as np
8
+
9
+ # ---- CONFIG ----
10
+ MODEL_PATH = "twin_car_best_model_v2.pth"
11
+ META_PATH = "cars_meta.mat"
12
+ DEVICE = torch.device("cpu")
13
+
14
+ # ---- LOAD CLASS NAMES ----
15
+ meta = scipy.io.loadmat(META_PATH)
16
+ class_names = [x[0] for x in meta['class_names'][0]]
17
+
18
+ # ---- DEFINE MODEL ----
19
+ def get_model(num_classes=196):
20
+ model = models.resnet50(weights=None)
21
+ model.fc = nn.Sequential(
22
+ nn.Linear(model.fc.in_features, 512),
23
+ nn.ReLU(),
24
+ nn.Dropout(0.2),
25
+ nn.Linear(512, num_classes)
26
+ )
27
  return model
28
 
29
+ model = get_model(num_classes=len(class_names))
30
+ model.load_state_dict(torch.load(MODEL_PATH, map_location=DEVICE))
31
+ model.eval()
32
 
33
+ # ---- TRANSFORM ----
34
+ imagenet_mean = [0.485, 0.456, 0.406]
35
+ imagenet_std = [0.229, 0.224, 0.225]
36
+ test_transform = transforms.Compose([
37
+ transforms.Resize(256),
38
+ transforms.CenterCrop(224),
39
  transforms.ToTensor(),
40
+ transforms.Normalize(mean=imagenet_mean, std=imagenet_std)
 
41
  ])
42
 
43
+ # ---- PREDICTION FUNCTION ----
44
  def predict(img):
45
+ img_pil = img.convert("RGB")
46
+ x = test_transform(img_pil).unsqueeze(0)
47
  with torch.no_grad():
48
+ logits = model(x)
49
+ probs = torch.softmax(logits, dim=1).cpu().numpy()[0]
50
+ top5_idx = np.argsort(probs)[-5:][::-1]
51
+ results = {class_names[i]: float(probs[i]) for i in top5_idx}
52
  return results
53
 
54
+ # ---- GRADIO APP ----
55
+ description = (
56
+ "Upload a car image. The model returns top-5 fine-grained make/model predictions "
57
+ "using Stanford Cars 196. <br><br>Model: ResNet-50 + custom head, trained by Kiril Mickovski."
58
+ )
59
+
60
  gr.Interface(
61
  fn=predict,
62
+ inputs=gr.Image(type="pil", label="Upload Car Image"),
63
  outputs=gr.Label(num_top_classes=5),
64
+ title="🚗 TwinCar-196: Stanford Cars Classifier",
65
+ description=description,
66
+ allow_flagging="never"
67
  ).launch()