Apiarist Dev commited on
Commit
2c5f41c
Β·
1 Parent(s): 3de1e82

wire @spaces.GPU decorator for ZeroGPU; auto cuda/cpu device handling

Browse files
Files changed (1) hide show
  1. app.py +24 -9
app.py CHANGED
@@ -1,9 +1,9 @@
1
  """
2
  Apiarist - Offline AI inspector for honeybee hive frames.
3
 
4
- Day 5: switched from Moondream2 (version-pinning hell) to SmolVLM-500M
5
- (HuggingFace's own model, standard transformers API). Will swap up to
6
- Qwen2.5-VL-7B once GPU access lands.
7
  """
8
 
9
  import gradio as gr
@@ -13,6 +13,16 @@ import re
13
  import torch
14
  from transformers import AutoProcessor, AutoModelForVision2Seq
15
 
 
 
 
 
 
 
 
 
 
 
16
 
17
  MODEL_ID = "HuggingFaceTB/SmolVLM-500M-Instruct"
18
 
@@ -21,14 +31,12 @@ _processor = None
21
 
22
 
23
  def get_model():
 
24
  global _model, _processor
25
  if _model is None:
26
  print(f"Loading {MODEL_ID} ...")
27
  _processor = AutoProcessor.from_pretrained(MODEL_ID)
28
- _model = AutoModelForVision2Seq.from_pretrained(
29
- MODEL_ID,
30
- torch_dtype=torch.float32, # CPU prefers FP32
31
- )
32
  _model.eval()
33
  print("Model loaded.")
34
  return _model, _processor
@@ -93,7 +101,7 @@ def build_narrative(r: dict, raw: str) -> str:
93
  **Notes:** {r['notes']}
94
 
95
  ---
96
- *Powered by SmolVLM-500M β€” lightweight stand-in. Qwen2.5-VL-7B + specialist YOLO detector land once GPU access is granted.*
97
 
98
  <details><summary>Raw model output</summary>
99
 
@@ -104,12 +112,18 @@ def build_narrative(r: dict, raw: str) -> str:
104
  """
105
 
106
 
 
107
  def analyze_frame(image: Image.Image, hive_name: str):
108
  if image is None:
109
  return None, "Upload a frame photo first.", ""
110
 
111
  model, processor = get_model()
112
 
 
 
 
 
 
113
  messages = [
114
  {
115
  "role": "user",
@@ -125,6 +139,7 @@ def analyze_frame(image: Image.Image, hive_name: str):
125
  messages, add_generation_prompt=True
126
  )
127
  inputs = processor(text=prompt, images=[image], return_tensors="pt")
 
128
 
129
  with torch.no_grad():
130
  generated = model.generate(
@@ -218,7 +233,7 @@ with gr.Blocks(title="Apiarist - Hive Frame Inspector") as app:
218
  - 🎯 Fine-tuned for honeybees
219
  - πŸ““ Built in 10 days for the [Build Small Hackathon](https://huggingface.co/build-small-hackathon)
220
 
221
- **Stack**: SmolVLM (placeholder) β†’ Qwen2.5-VL-7B + YOLOv8 (final), Gradio, llama.cpp.
222
  """
223
  )
224
 
 
1
  """
2
  Apiarist - Offline AI inspector for honeybee hive frames.
3
 
4
+ Day 6: SmolVLM-500M + ZeroGPU (free on-demand GPU). The @spaces.GPU
5
+ decorator tells HF to allocate a GPU just for the inference call,
6
+ then release it.
7
  """
8
 
9
  import gradio as gr
 
13
  import torch
14
  from transformers import AutoProcessor, AutoModelForVision2Seq
15
 
16
+ # ZeroGPU integration β€” gracefully degrades to a no-op outside HF Spaces
17
+ try:
18
+ import spaces
19
+
20
+ def gpu(fn):
21
+ return spaces.GPU(duration=60)(fn)
22
+ except ImportError:
23
+ def gpu(fn):
24
+ return fn
25
+
26
 
27
  MODEL_ID = "HuggingFaceTB/SmolVLM-500M-Instruct"
28
 
 
31
 
32
 
33
  def get_model():
34
+ """Lazy-load model on first call. Stays on CPU until moved by analyze_frame."""
35
  global _model, _processor
36
  if _model is None:
37
  print(f"Loading {MODEL_ID} ...")
38
  _processor = AutoProcessor.from_pretrained(MODEL_ID)
39
+ _model = AutoModelForVision2Seq.from_pretrained(MODEL_ID)
 
 
 
40
  _model.eval()
41
  print("Model loaded.")
42
  return _model, _processor
 
101
  **Notes:** {r['notes']}
102
 
103
  ---
104
+ *Powered by SmolVLM-500M on ZeroGPU β€” lightweight stand-in. Qwen2.5-VL-7B + specialist YOLO detector are the planned final stack.*
105
 
106
  <details><summary>Raw model output</summary>
107
 
 
112
  """
113
 
114
 
115
+ @gpu
116
  def analyze_frame(image: Image.Image, hive_name: str):
117
  if image is None:
118
  return None, "Upload a frame photo first.", ""
119
 
120
  model, processor = get_model()
121
 
122
+ # ZeroGPU allocates a GPU only inside this @gpu-decorated call.
123
+ device = "cuda" if torch.cuda.is_available() else "cpu"
124
+ dtype = torch.float16 if device == "cuda" else torch.float32
125
+ model = model.to(device=device, dtype=dtype)
126
+
127
  messages = [
128
  {
129
  "role": "user",
 
139
  messages, add_generation_prompt=True
140
  )
141
  inputs = processor(text=prompt, images=[image], return_tensors="pt")
142
+ inputs = inputs.to(device)
143
 
144
  with torch.no_grad():
145
  generated = model.generate(
 
233
  - 🎯 Fine-tuned for honeybees
234
  - πŸ““ Built in 10 days for the [Build Small Hackathon](https://huggingface.co/build-small-hackathon)
235
 
236
+ **Stack**: SmolVLM-500M on ZeroGPU. Qwen2.5-VL-7B + YOLOv8 are the planned upgrades.
237
  """
238
  )
239