ProfRom commited on
Commit
a69f876
·
verified ·
1 Parent(s): 9d8c958

Zhao - Final submission

Browse files
Files changed (1) hide show
  1. app.py +90 -92
app.py CHANGED
@@ -1,98 +1,96 @@
1
- import torch
2
- import gradio as gr
3
- from PIL import Image
4
- from transformers import (
5
- BlipProcessor,
6
- BlipForConditionalGeneration,
7
- pipeline
8
- )
9
-
10
- # Select device
11
- device = "cuda" if torch.cuda.is_available() else "cpu"
12
- torch_dtype = torch.float16 if torch.cuda.is_available() else torch.float32
13
-
14
- # Load BLIP captioning model directly
15
- processor = BlipProcessor.from_pretrained("Salesforce/blip-image-captioning-base")
16
- caption_model = BlipForConditionalGeneration.from_pretrained(
17
- "Salesforce/blip-image-captioning-base",
18
- torch_dtype=torch_dtype
19
- ).to(device)
20
-
21
- # Load image classification model
22
- classifier = pipeline(
23
- task="image-classification",
24
- model="google/vit-base-patch16-224",
25
- device=0 if torch.cuda.is_available() else -1
26
- )
27
 
28
- print("Models loaded successfully.")
29
-
30
- def generate_caption(image):
31
- inputs = processor(images=image, return_tensors="pt").to(device, torch_dtype)
32
- output = caption_model.generate(**inputs, max_new_tokens=30)
33
- caption = processor.decode(output[0], skip_special_tokens=True)
34
- return caption
35
-
36
- def build_summary(caption: str, label: str) -> str:
37
- caption = caption.strip() if caption else "No caption available"
38
- label = label.strip() if label else "unknown object"
39
-
40
- return (
41
- f"The captioning model describes the image as: {caption}. "
42
- f"The image classification model identifies the main subject as: {label}. "
43
- f"Taken together, the image appears to focus on this subject or scene."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  )
 
45
 
46
- def analyze_image(image):
47
- try:
48
- if image is None:
49
- return (
50
- "Please upload an image.",
51
- "No classification available.",
52
- "Please upload an image first."
53
- )
54
 
55
- image = image.convert("RGB")
56
-
57
- # Captioning
58
- caption = generate_caption(image)
59
- print("CAPTION RESULT:", caption)
60
-
61
- # Classification
62
- class_result = classifier(image)
63
- print("CLASSIFICATION RESULT:", class_result)
64
-
65
- if isinstance(class_result, list) and len(class_result) > 0:
66
- top_label = class_result[0].get("label", "Unknown")
67
- top_score = class_result[0].get("score", 0.0)
68
- classification_text = f"{top_label} (confidence: {top_score:.4f})"
69
- else:
70
- top_label = "Unknown"
71
- classification_text = "No classification generated."
72
-
73
- summary = build_summary(caption, top_label)
74
-
75
- return caption, classification_text, summary
76
-
77
- except Exception as e:
78
- print("ERROR:", str(e))
79
- error_text = f"Error: {str(e)}"
80
- return error_text, error_text, error_text
81
-
82
- demo = gr.Interface(
83
- fn=analyze_image,
84
- inputs=gr.Image(type="pil", label="Upload an Image"),
85
- outputs=[
86
- gr.Textbox(label="Generated Caption"),
87
- gr.Textbox(label="Top Classification"),
88
- gr.Textbox(label="Combined Summary", lines=4)
89
- ],
90
- title="Image Captioning, Classification, and Summary App",
91
- description=(
92
- "Upload an image to generate an automatic caption, predict the main image class, "
93
- "and produce a short combined summary."
94
- ),
95
- )
96
 
97
  if __name__ == "__main__":
98
- demo.launch()
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import random
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
 
4
+ import gradio as gr
5
+ import torch
6
+ from datasets import load_dataset
7
+ from transformers import BlipForQuestionAnswering, BlipProcessor
8
+
9
+ # Always use BlipProcessor + BlipForQuestionAnswering directly.
10
+ # The Transformers pipeline API for BLIP-VQA changed between v4 and v5 and can echo
11
+ # the question instead of returning the answer. Direct model calls are stable across versions.
12
+ MODEL_ID = "Salesforce/blip-vqa-base"
13
+
14
+ _device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
15
+ _processor = BlipProcessor.from_pretrained(MODEL_ID)
16
+ _model = BlipForQuestionAnswering.from_pretrained(MODEL_ID).to(_device)
17
+ _model.eval()
18
+
19
+
20
+ def run_vqa(image, question: str) -> str:
21
+ inputs = _processor(images=image, text=question, return_tensors="pt").to(_device)
22
+ with torch.no_grad():
23
+ out = _model.generate(**inputs, max_new_tokens=32)
24
+ return _processor.decode(out[0], skip_special_tokens=True).strip()
25
+
26
+ FOOD101_ID = "ethz/food101"
27
+ DEFAULT_VQA_QUESTION = "What kind of food is in this image?"
28
+
29
+
30
+ def answer_question(image, question):
31
+ if not question:
32
+ return "Please type a question about the image."
33
+ if image is None:
34
+ return "Please upload an image (or use Load random sample) before clicking Answer."
35
+ return run_vqa(image, question)
36
+
37
+
38
+ def load_food101_sample(cache: dict | None):
39
+ """
40
+ Pull one random example from Hugging Face Datasets (Food-101).
41
+ Dataset card: https://huggingface.co/datasets/ethz/food101
42
+ """
43
+ if cache is None:
44
+ cache = {"ds": load_dataset(FOOD101_ID, split="validation")}
45
+ ds = cache["ds"]
46
+ i = random.randint(0, len(ds) - 1)
47
+ ex = ds[i]
48
+ names = ds.features["label"].names
49
+ gold = names[ex["label"]]
50
+ note = (
51
+ f"Loaded from Hugging Face Datasets `{FOOD101_ID}` "
52
+ f"(split `validation`, index {i}). Reference label: `{gold}`."
53
  )
54
+ return ex["image"], DEFAULT_VQA_QUESTION, cache, note
55
 
 
 
 
 
 
 
 
 
56
 
57
+ with gr.Blocks() as demo:
58
+ ds_cache = gr.State(None)
59
+ gr.Markdown(
60
+ "## BLIP Visual Question Answering\n"
61
+ "Gradio app for [Hugging Face Spaces](https://huggingface.co/docs/hub/spaces). "
62
+ "Upload your own image **or** load a sample image from "
63
+ f"[Hugging Face Datasets — `{FOOD101_ID}`](https://huggingface.co/datasets/ethz/food101)."
64
+ )
65
+ dataset_note = gr.Markdown("")
66
+ with gr.Row():
67
+ image_in = gr.Image(type="pil", label="Image")
68
+ question_in = gr.Textbox(
69
+ label="Question",
70
+ placeholder="e.g. What is the weather in this image?",
71
+ )
72
+ answer_out = gr.Textbox(label="Answer")
73
+ with gr.Row():
74
+ submit_btn = gr.Button("Answer", variant="primary")
75
+ sample_btn = gr.Button(f"Load random sample ({FOOD101_ID})")
76
+
77
+ submit_btn.click(answer_question, [image_in, question_in], [answer_out])
78
+ sample_btn.click(
79
+ load_food101_sample,
80
+ [ds_cache],
81
+ [image_in, question_in, ds_cache, dataset_note],
82
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
 
84
  if __name__ == "__main__":
85
+ # Hugging Face Spaces sets PORT; bind 0.0.0.0 so the Space proxy can reach the app.
86
+ # Locally: open http://127.0.0.1:<PORT> (default PORT 7860 if unset).
87
+ _port = int(os.environ.get("PORT", "7860"))
88
+ # Queue mode is recommended for Spaces and tends to play nicer with Gradio’s async stack.
89
+ demo.queue()
90
+ demo.launch(
91
+ server_name="0.0.0.0",
92
+ server_port=_port,
93
+ # Space URL is already public; share=True would add a separate *.gradio.live tunnel (not needed).
94
+ share=False,
95
+ show_error=True,
96
+ )