prasanthmj commited on
Commit
6e08ed4
·
verified ·
1 Parent(s): 99857c5

Fix: use @spaces.GPU for ZeroGPU - load models on CPU, move to GPU per-request

Browse files
Files changed (1) hide show
  1. app.py +35 -46
app.py CHANGED
@@ -2,43 +2,36 @@
2
 
3
  import json
4
  import tempfile
5
- from pathlib import Path
6
 
7
  import cv2
8
  import gradio as gr
9
  import numpy as np
 
10
  import torch
11
  from huggingface_hub import hf_hub_download
12
  from transformers import AutoModelForSeq2SeqLM, AutoTokenizer
13
  from ultralytics import YOLO
14
 
15
- # --- Model loading (cached at startup) ---
16
 
17
  YOLO_REPO = "prasanthmj/yolov8-braille"
18
  BYT5_REPO = "prasanthmj/braille-byt5-v3"
19
 
20
- def load_models():
21
- """Download and load both models."""
22
- # YOLOv8 braille detector
23
- weights_path = hf_hub_download(YOLO_REPO, "yolov8_braille.pt")
24
- braille_map_path = hf_hub_download(YOLO_REPO, "braille_map.json")
25
-
26
- yolo_model = YOLO(weights_path)
27
- with open(braille_map_path) as f:
28
- dot_to_unicode = json.load(f)
29
-
30
- # ByT5 Grade 2 interpreter
31
- tokenizer = AutoTokenizer.from_pretrained(BYT5_REPO)
32
- device = "cuda" if torch.cuda.is_available() else "cpu"
33
- byt5_model = AutoModelForSeq2SeqLM.from_pretrained(BYT5_REPO).to(device)
34
- byt5_model.eval()
35
 
36
- return yolo_model, dot_to_unicode, tokenizer, byt5_model, device
 
 
 
 
 
37
 
 
 
 
 
38
 
39
- print("Loading models...")
40
- yolo_model, dot_to_unicode, tokenizer, byt5_model, device = load_models()
41
- print(f"Models loaded. Device: {device}")
42
 
43
  # --- CLAHE Preprocessing ---
44
 
@@ -102,30 +95,9 @@ def detect_braille(image_path: str, confidence: float = 0.15) -> list[list[dict]
102
 
103
  return lines
104
 
105
- # --- Stage 2: ByT5 Interpretation ---
106
-
107
- def interpret_braille(braille_lines: list[str]) -> list[str]:
108
- """Translate braille Unicode lines to English using ByT5."""
109
- results = []
110
- for line in braille_lines:
111
- if not line.strip():
112
- results.append("")
113
- continue
114
-
115
- input_text = f"translate Braille to English: {line}"
116
- inputs = tokenizer(input_text, return_tensors="pt", max_length=1024, truncation=True)
117
- inputs = {k: v.to(device) for k, v in inputs.items()}
118
-
119
- with torch.no_grad():
120
- outputs = byt5_model.generate(**inputs, max_length=512)
121
-
122
- decoded = tokenizer.decode(outputs[0], skip_special_tokens=True)
123
- results.append(decoded)
124
-
125
- return results
126
-
127
- # --- Main pipeline ---
128
 
 
129
  def transcribe(image) -> str:
130
  """Full pipeline: image -> detection -> interpretation -> English text."""
131
  if image is None:
@@ -155,8 +127,25 @@ def transcribe(image) -> str:
155
  total_cells = sum(len(line) for line in lines)
156
  avg_conf = np.mean([cell["confidence"] for line in lines for cell in line])
157
 
158
- # Stage 2: Interpret with ByT5
159
- english_lines = interpret_braille(braille_lines)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
 
161
  # Format output
162
  braille_text = "\n".join(braille_lines)
 
2
 
3
  import json
4
  import tempfile
 
5
 
6
  import cv2
7
  import gradio as gr
8
  import numpy as np
9
+ import spaces
10
  import torch
11
  from huggingface_hub import hf_hub_download
12
  from transformers import AutoModelForSeq2SeqLM, AutoTokenizer
13
  from ultralytics import YOLO
14
 
15
+ # --- Model loading (on CPU at startup, GPU allocated per-request) ---
16
 
17
  YOLO_REPO = "prasanthmj/yolov8-braille"
18
  BYT5_REPO = "prasanthmj/braille-byt5-v3"
19
 
20
+ print("Loading models...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
+ # YOLOv8 braille detector
23
+ weights_path = hf_hub_download(YOLO_REPO, "yolov8_braille.pt")
24
+ braille_map_path = hf_hub_download(YOLO_REPO, "braille_map.json")
25
+ yolo_model = YOLO(weights_path)
26
+ with open(braille_map_path) as f:
27
+ dot_to_unicode = json.load(f)
28
 
29
+ # ByT5 Grade 2 interpreter (load on CPU, moved to GPU per-request)
30
+ tokenizer = AutoTokenizer.from_pretrained(BYT5_REPO)
31
+ byt5_model = AutoModelForSeq2SeqLM.from_pretrained(BYT5_REPO)
32
+ byt5_model.eval()
33
 
34
+ print("Models loaded (CPU). GPU allocated per-request via ZeroGPU.")
 
 
35
 
36
  # --- CLAHE Preprocessing ---
37
 
 
95
 
96
  return lines
97
 
98
+ # --- Main pipeline (GPU allocated here) ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
 
100
+ @spaces.GPU
101
  def transcribe(image) -> str:
102
  """Full pipeline: image -> detection -> interpretation -> English text."""
103
  if image is None:
 
127
  total_cells = sum(len(line) for line in lines)
128
  avg_conf = np.mean([cell["confidence"] for line in lines for cell in line])
129
 
130
+ # Stage 2: Interpret each line with ByT5 on GPU
131
+ device = "cuda" if torch.cuda.is_available() else "cpu"
132
+ byt5_model.to(device)
133
+
134
+ english_lines = []
135
+ for line in braille_lines:
136
+ if not line.strip():
137
+ english_lines.append("")
138
+ continue
139
+
140
+ input_text = f"translate Braille to English: {line}"
141
+ inputs = tokenizer(input_text, return_tensors="pt", max_length=1024, truncation=True)
142
+ inputs = {k: v.to(device) for k, v in inputs.items()}
143
+
144
+ with torch.no_grad():
145
+ outputs = byt5_model.generate(**inputs, max_length=512)
146
+
147
+ decoded = tokenizer.decode(outputs[0], skip_special_tokens=True)
148
+ english_lines.append(decoded)
149
 
150
  # Format output
151
  braille_text = "\n".join(braille_lines)