Suphawan's picture
Upload app.py
bc10ce2 verified
Raw
History Blame Contribute Delete
3.93 kB
# -*- coding: utf-8 -*-
"""app.ipynb
Automatically generated by Colab.
Original file is located at
https://colab.research.google.com/drive/1pj05m47J2hNpEuUjfEoP7Jk3UaGpUjPE
"""
import gradio as gr
import joblib
import torch
import torch.nn as nn
import numpy as np
from PIL import Image
import torchvision.transforms as T
from torchvision.models import resnet18, ResNet18_Weights
device = "cuda" if torch.cuda.is_available() else "cpu"
cnn = resnet18(weights=ResNet18_Weights.DEFAULT)
cnn.fc = nn.Identity()
cnn.eval().to(device)
for p in cnn.parameters():
p.requires_grad = False
transform = T.Compose([
T.Resize((640, 640)),
T.ToTensor()
])
def extract_feature(image: Image.Image):
img = transform(image).unsqueeze(0).to(device)
with torch.no_grad():
feat = cnn(img).cpu().numpy().flatten()
return feat
MODELS = {
"XGBoost": joblib.load("saved_models/xgb/hier_xgb_bundle.pkl"),
"Logistic": joblib.load("saved_models/logistic/hier_logistic_bundle.pkl"),
"MLP": joblib.load("saved_models/mlp/hier_mlp_bundle.pkl"),
}
def predict_brix(model_name, image, weight, width, height):
if image is None:
return "❌ Please upload an image", {"Low": 0, "Medium": 0, "High": 0}
bundle = MODELS[model_name]
model_A = bundle["model_A"]
model_B = bundle["model_B"]
scaler = bundle["scaler"]
th = bundle["thresholds"]["BEST_TH"]
# ---- Feature extraction ----
feat_img = extract_feature(image)
num = np.array([[weight, width, height]])
num = scaler.transform(num).flatten()
x = np.concatenate([feat_img, num]).reshape(1, -1)
# ---- Stage A ----
p_sweet = model_A.predict_proba(x)[0][1]
probs = {"Low": 0.0, "Medium": 0.0, "High": 0.0}
if p_sweet < (1 - th):
label = "🍈 Low Brix"
probs["Low"] = float(1 - p_sweet)
elif p_sweet > th:
cls = model_B.predict(x)[0] + 1
p2 = model_B.predict_proba(x)[0]
probs["Medium"] = float(p2[0])
probs["High"] = float(p2[1])
label = "🍈 Medium Brix" if cls == 1 else "🍈 High Brix"
else:
label = "⚠️ Abstain (Uncertain)"
return label, probs
with gr.Blocks() as demo:
gr.Markdown(
"""
# 🍈 Melon Brix Classifier
**Hierarchical Classification with Abstention**
CNN Feature Extraction + Tabular Data
เลือกโมเดล → ใส่ข้อมูล → ระบบจะทำนายความหวาน
ถ้าไม่มั่นใจ ระบบจะ *Abstain* แทนการเดา
"""
)
with gr.Tab("🍈 Prediction"): # ✅ แท็บเดียว
with gr.Row():
with gr.Column(scale=1):
model_dd = gr.Dropdown(
["XGBoost", "Logistic", "MLP"],
value="MLP",
label="Select Model"
)
image_in = gr.Image(
type="pil",
image_mode="RGB",
label="Melon Image (.jpg / .png)",
sources=["upload"])
weight_in = gr.Number(label="Weight (kg)", value=1.5)
width_in = gr.Number(label="Width (cm)", value=15.0)
height_in = gr.Number(label="Height (cm)", value=15.0)
btn = gr.Button("🔍 Predict")
with gr.Column(scale=1):
pred_out = gr.Label(label="Prediction")
prob_out = gr.BarPlot(
x=["Low", "Medium", "High"],
y="value",
title="Class Probability",
height=300
)
btn.click(
fn=predict_brix,
inputs=[model_dd, image_in, weight_in, width_in, height_in],
outputs=[pred_out, prob_out]
)
demo.launch()