Spaces:
Sleeping
Sleeping
File size: 3,490 Bytes
da50974 def2892 da50974 def2892 da50974 5eab86a da50974 9dc3e41 def2892 9dc3e41 0045512 9dc3e41 0045512 5eab86a 21518d9 def2892 9dc3e41 def2892 0401c3e def2892 9dc3e41 def2892 da50974 5eab86a 9dc3e41 da50974 def2892 da50974 5eab86a def2892 0045512 da50974 0045512 da50974 def2892 0045512 da50974 def2892 da50974 0045512 def2892 5eab86a def2892 5eab86a def2892 5eab86a def2892 0045512 def2892 da50974 def2892 | 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 | import gradio as gr
import torch
import torch.nn as nn
from torchvision import transforms, models
from PIL import Image
import numpy as np
import pickle
import os
# Model definition
class FoodIngredientClassifier(nn.Module):
def __init__(self, num_classes):
super().__init__()
self.backbone = models.vit_b_16(weights=None)
num_features = self.backbone.heads.head.in_features
self.backbone.heads = nn.Sequential(
nn.Dropout(0.5),
nn.Linear(num_features, 1024),
nn.BatchNorm1d(1024),
nn.ReLU(),
nn.Dropout(0.4),
nn.Linear(1024, 512),
nn.BatchNorm1d(512),
nn.ReLU(),
nn.Dropout(0.3),
nn.Linear(512, num_classes)
)
def forward(self, x):
return self.backbone(x)
# Load model
DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
THRESHOLD = 0.5
def load_model():
checkpoint = torch.load("model.pth", map_location=DEVICE, weights_only=False)
mlb = checkpoint["mlb"]
num_classes = len(mlb.classes_)
model = FoodIngredientClassifier(num_classes)
model.load_state_dict(checkpoint["model_state_dict"])
model.to(DEVICE)
model.eval()
return model, mlb
model, mlb = load_model()
# Transform
transform = transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])
# Inference Function
def predict(image, threshold):
if image is None:
return "Please upload an image."
img = image.convert("RGB")
img_tensor = transform(img).unsqueeze(0).to(DEVICE)
with torch.no_grad():
output = model(img_tensor)
probs = torch.sigmoid(output).cpu().numpy()[0]
pred_indices = np.where(probs > threshold)[0]
if len(pred_indices) == 0:
return "No ingredients detected above the threshold. Try lowering it."
results = sorted(
zip(mlb.classes_[pred_indices], probs[pred_indices]),
key=lambda x: x[1],
reverse=True
)
output_lines = ["### 🍽️ Detected Ingredients\n"]
for ingredient, confidence in results:
bar = "█" * int(confidence * 20)
output_lines.append(f"**{ingredient}** — {confidence:.1%} `{bar}`")
return "\n\n".join(output_lines)
# UI
with gr.Blocks(title="Food Ingredient Detector") as demo:
gr.Markdown("""
# Food Ingredient Detector
Upload a photo of food and the model will identify its ingredients.
Built with a **ViT-B/16** backbone fine-tuned for multi-label ingredient classification.
""")
with gr.Row():
with gr.Column():
image_input = gr.Image(type="pil", label="Upload Food Image")
threshold_slider = gr.Slider(
minimum=0.1, maximum=0.9, value=0.5, step=0.05,
label="Detection Threshold",
info="Lower = more ingredients detected, higher = only confident predictions"
)
predict_btn = gr.Button("Detect Ingredients", variant="primary")
with gr.Column():
output = gr.Markdown(label="Results")
predict_btn.click(
fn=predict,
inputs=[image_input, threshold_slider],
outputs=output
)
gr.Examples(
examples=[], # Add example image paths here if you include sample images
inputs=image_input
)
if __name__ == "__main__":
demo.launch() |