alphamike's picture
Refactor Gradio app for model selection and checkpoint handling
36fca7c
Raw
History Blame Contribute Delete
4.64 kB
from __future__ import annotations
from pathlib import Path
from typing import Any, Dict
import gradio as gr
import torch
from PIL import Image
from huggingface_hub import hf_hub_download
import sys
from pathlib import Path as _Path
ROOT = _Path(__file__).resolve().parent
SRC_DIR = ROOT / "src"
if str(SRC_DIR) not in sys.path:
sys.path.insert(0, str(SRC_DIR))
from infer.pipeline import LoadedModel, load_checkpoint, predict_image
MODEL_REPO_ID = "alphamike/GraphAttributeLearning_Model"
MODEL_FILENAMES = {
"baseline": "baseline/best.pt",
"gnn1": "gnn1/best.pt",
"gnn2": "gnn2/best.pt",
}
class ModelRegistry:
def __init__(self) -> None:
self._cache: Dict[str, LoadedModel] = {}
def get(self, key: str, path: Path, device: torch.device) -> LoadedModel:
cached = self._cache.get(key)
if cached is not None:
return cached
loaded = load_checkpoint(path, device=device)
self._cache[key] = loaded
return loaded
registry = ModelRegistry()
def infer_gradio(
image: Image.Image,
model_type: str,
checkpoint_path: str,
top_k: int,
threshold: float,
) -> Any:
if image is None:
return [], "No image provided."
# Resolve checkpoint: either use the textbox value as filename within the model repo
# or fall back to the default mapping for the selected model_type.
filename = (checkpoint_path or "").strip() or MODEL_FILENAMES.get(model_type, "")
if not filename:
return [], f"Unknown model_type '{model_type}'."
try:
local_ckpt_path = hf_hub_download(
repo_id=MODEL_REPO_ID,
filename=filename,
repo_type="model",
)
except Exception as exc: # noqa: BLE001
return [], f"Error downloading checkpoint from Hub: {exc}"
path = Path(local_ckpt_path)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
try:
key = f"{model_type}:{path}"
loaded = registry.get(key, path, device)
# Save temp image to disk-agnostic path is unnecessary; use pipeline logic directly.
from infer.pipeline import predict_image as predict_from_loaded
from infer.pipeline import LoadedModel as _LM # type: ignore
assert isinstance(loaded, _LM)
# Wrap PIL image call using temporary in-memory path emulation.
# For simplicity, reuse adapter directly.
result = loaded.adapter.predict(
image=image,
label_vocab=loaded.label_vocab,
top_k=top_k,
threshold=threshold,
)
rows = [
{"label": label, "score": round(score, 4), "positive@thr": label in result.positives}
for label, score in zip(result.labels, result.scores)
]
message = f"Positives (>= {threshold:.2f}): {', '.join(result.positives) if result.positives else 'none'}"
return rows, message
except Exception as exc: # noqa: BLE001
return [], f"Error: {exc}"
with gr.Blocks() as demo:
gr.Markdown(
"# Adjective-Aware Chair Attributes\n"
"Select baseline, GNN 1, or GNN 2, upload an image, and view attribute scores.\n\n"
f"Models are loaded from Hugging Face model repo: `{MODEL_REPO_ID}`."
)
with gr.Row():
with gr.Column(scale=1):
image_input = gr.Image(type="pil", label="Chair image")
model_type = gr.Radio(
choices=["baseline", "gnn1", "gnn2"],
value="baseline",
label="Model type",
)
checkpoint = gr.Textbox(
value=MODEL_FILENAMES["baseline"],
label="Checkpoint filename (within Hub repo)",
)
def _sync_ckpt(choice: str) -> str:
return MODEL_FILENAMES.get(choice, MODEL_FILENAMES["baseline"])
model_type.change(_sync_ckpt, inputs=model_type, outputs=checkpoint)
top_k = gr.Slider(1, 20, value=5, step=1, label="Top-K")
threshold = gr.Slider(0.0, 1.0, value=0.5, step=0.01, label="Threshold")
run_btn = gr.Button("Run inference")
with gr.Column(scale=2):
table = gr.Dataframe(
headers=["label", "score", "positive@thr"],
datatype=["str", "number", "bool"],
label="Attribute scores",
)
message = gr.Markdown()
run_btn.click(
infer_gradio,
inputs=[image_input, model_type, checkpoint, top_k, threshold],
outputs=[table, message],
)
if __name__ == "__main__":
demo.launch()