Spaces:
Running on Zero
Running on Zero
Keep CPU inference safe across ZeroGPU forks and size GPU requests per task
Browse files- app.py +6 -2
- pixtext_ocr.py +2 -1
- space.py +17 -3
app.py
CHANGED
|
@@ -212,7 +212,9 @@ def detect(session, jid, request: DetectRequest):
|
|
| 212 |
import torch
|
| 213 |
from pixtext_ocr import detect_words
|
| 214 |
|
| 215 |
-
|
|
|
|
|
|
|
| 216 |
root = ocr_root(jid)
|
| 217 |
update_job(jid, message="Detecting words and reading text", progress=0.3)
|
| 218 |
with Image.open(session["directory"] / "source.png") as image:
|
|
@@ -229,7 +231,9 @@ def refine(session, jid, request: RefineRequest, progress_report=None):
|
|
| 229 |
|
| 230 |
if not torch.cuda.is_available():
|
| 231 |
raise RuntimeError("Refinement needs a CUDA GPU. Detection and box editing are ready to use.")
|
| 232 |
-
|
|
|
|
|
|
|
| 233 |
if os.environ.get("PIXTEXT_GPU_MEMORY_FRACTION"):
|
| 234 |
torch.cuda.set_per_process_memory_fraction(float(os.environ["PIXTEXT_GPU_MEMORY_FRACTION"]))
|
| 235 |
if PIPELINE_VARIANT != request.variant:
|
|
|
|
| 212 |
import torch
|
| 213 |
from pixtext_ocr import detect_words
|
| 214 |
|
| 215 |
+
threads = int(os.environ.get("PIXTEXT_CPU_THREADS", "4"))
|
| 216 |
+
if torch.get_num_threads() != threads:
|
| 217 |
+
torch.set_num_threads(threads)
|
| 218 |
root = ocr_root(jid)
|
| 219 |
update_job(jid, message="Detecting words and reading text", progress=0.3)
|
| 220 |
with Image.open(session["directory"] / "source.png") as image:
|
|
|
|
| 231 |
|
| 232 |
if not torch.cuda.is_available():
|
| 233 |
raise RuntimeError("Refinement needs a CUDA GPU. Detection and box editing are ready to use.")
|
| 234 |
+
threads = int(os.environ.get("PIXTEXT_CPU_THREADS", "4"))
|
| 235 |
+
if torch.get_num_threads() != threads:
|
| 236 |
+
torch.set_num_threads(threads)
|
| 237 |
if os.environ.get("PIXTEXT_GPU_MEMORY_FRACTION"):
|
| 238 |
torch.cuda.set_per_process_memory_fraction(float(os.environ["PIXTEXT_GPU_MEMORY_FRACTION"]))
|
| 239 |
if PIPELINE_VARIANT != request.variant:
|
pixtext_ocr.py
CHANGED
|
@@ -8,6 +8,7 @@ from __future__ import annotations
|
|
| 8 |
import hashlib
|
| 9 |
import json
|
| 10 |
import math
|
|
|
|
| 11 |
from functools import lru_cache
|
| 12 |
from pathlib import Path
|
| 13 |
|
|
@@ -82,7 +83,7 @@ class WordOCR:
|
|
| 82 |
)
|
| 83 |
self.detector.eval()
|
| 84 |
options = ort.SessionOptions()
|
| 85 |
-
options.intra_op_num_threads = 4
|
| 86 |
options.inter_op_num_threads = 1
|
| 87 |
self.recognizer = ort.InferenceSession(
|
| 88 |
str(rec_path), sess_options=options, providers=["CPUExecutionProvider"]
|
|
|
|
| 8 |
import hashlib
|
| 9 |
import json
|
| 10 |
import math
|
| 11 |
+
import os
|
| 12 |
from functools import lru_cache
|
| 13 |
from pathlib import Path
|
| 14 |
|
|
|
|
| 83 |
)
|
| 84 |
self.detector.eval()
|
| 85 |
options = ort.SessionOptions()
|
| 86 |
+
options.intra_op_num_threads = int(os.environ.get("PIXTEXT_CPU_THREADS", "4"))
|
| 87 |
options.inter_op_num_threads = 1
|
| 88 |
self.recognizer = ort.InferenceSession(
|
| 89 |
str(rec_path), sess_options=options, providers=["CPUExecutionProvider"]
|
space.py
CHANGED
|
@@ -3,6 +3,9 @@
|
|
| 3 |
import os
|
| 4 |
|
| 5 |
os.environ["PIXTEXT_GRADIO"] = "1"
|
|
|
|
|
|
|
|
|
|
| 6 |
os.environ.setdefault("HF_HUB_DISABLE_TELEMETRY", "1")
|
| 7 |
|
| 8 |
# Import before torch so ZeroGPU can enable its CUDA staging mode.
|
|
@@ -26,7 +29,7 @@ def load_models():
|
|
| 26 |
from pixtext import PixTextPipeline
|
| 27 |
from huggingface_hub import snapshot_download
|
| 28 |
|
| 29 |
-
torch.set_num_threads(
|
| 30 |
if not torch.cuda.is_available() and not spaces.config.Config.zero_gpu:
|
| 31 |
return {}
|
| 32 |
pipelines = {}
|
|
@@ -47,8 +50,16 @@ def load_models():
|
|
| 47 |
PIPELINES = load_models()
|
| 48 |
|
| 49 |
|
| 50 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
def gpu_refine(directory: str, size: list[int], jid: str, payload: str):
|
|
|
|
| 52 |
started = time.perf_counter()
|
| 53 |
request = studio.RefineRequest.model_validate_json(payload)
|
| 54 |
studio.PIPELINE = PIPELINES.get(request.variant)
|
|
@@ -56,10 +67,13 @@ def gpu_refine(directory: str, size: list[int], jid: str, payload: str):
|
|
| 56 |
progress = gr.Progress()
|
| 57 |
|
| 58 |
def report(**values):
|
| 59 |
-
|
|
|
|
|
|
|
| 60 |
|
| 61 |
result = studio.refine({"directory": Path(directory), "size": size}, jid, request, report)
|
| 62 |
result["elapsed"] = round(time.perf_counter() - started, 2)
|
|
|
|
| 63 |
return result
|
| 64 |
|
| 65 |
|
|
|
|
| 3 |
import os
|
| 4 |
|
| 5 |
os.environ["PIXTEXT_GRADIO"] = "1"
|
| 6 |
+
os.environ.setdefault("PIXTEXT_CPU_THREADS", "1")
|
| 7 |
+
os.environ.setdefault("OMP_NUM_THREADS", "1")
|
| 8 |
+
os.environ.setdefault("OPENBLAS_NUM_THREADS", "1")
|
| 9 |
os.environ.setdefault("HF_HUB_DISABLE_TELEMETRY", "1")
|
| 10 |
|
| 11 |
# Import before torch so ZeroGPU can enable its CUDA staging mode.
|
|
|
|
| 29 |
from pixtext import PixTextPipeline
|
| 30 |
from huggingface_hub import snapshot_download
|
| 31 |
|
| 32 |
+
torch.set_num_threads(int(os.environ["PIXTEXT_CPU_THREADS"]))
|
| 33 |
if not torch.cuda.is_available() and not spaces.config.Config.zero_gpu:
|
| 34 |
return {}
|
| 35 |
pipelines = {}
|
|
|
|
| 50 |
PIPELINES = load_models()
|
| 51 |
|
| 52 |
|
| 53 |
+
def estimate_duration(directory: str, size: list[int], jid: str, payload: str):
|
| 54 |
+
import math
|
| 55 |
+
request = json.loads(payload)
|
| 56 |
+
count = sum(row.get("enabled", True) for row in request["regions"])
|
| 57 |
+
return max(20, min(90, 10 + math.ceil(request["steps"] * max(1, count / 8))))
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
@spaces.GPU(duration=estimate_duration)
|
| 61 |
def gpu_refine(directory: str, size: list[int], jid: str, payload: str):
|
| 62 |
+
print("PixText GPU worker: starting", flush=True)
|
| 63 |
started = time.perf_counter()
|
| 64 |
request = studio.RefineRequest.model_validate_json(payload)
|
| 65 |
studio.PIPELINE = PIPELINES.get(request.variant)
|
|
|
|
| 67 |
progress = gr.Progress()
|
| 68 |
|
| 69 |
def report(**values):
|
| 70 |
+
message = values.get("message", "Refining")
|
| 71 |
+
print("PixText GPU:", message, flush=True)
|
| 72 |
+
progress(values.get("progress", 0), desc=message)
|
| 73 |
|
| 74 |
result = studio.refine({"directory": Path(directory), "size": size}, jid, request, report)
|
| 75 |
result["elapsed"] = round(time.perf_counter() - started, 2)
|
| 76 |
+
print("PixText GPU worker: complete", result["elapsed"], flush=True)
|
| 77 |
return result
|
| 78 |
|
| 79 |
|