Spaces:
Running on Zero
Running on Zero
Commit ·
6c0477d
1
Parent(s): 2668631
Load model on CPU at startup to bypass slow ZeroGPU disk packing
Browse filesspaces 0.51.0 (released 2026-07-10) switched to disk-based tensor
packing (~19s pack + ~19s unpack per inference), breaking the ~7s
inference that worked with spaces 0.50.4's pinned-memory approach.
HuggingFace force-injects spaces==0.51.0 so pinning requirements.txt
doesn't help. Instead:
- Load transformer and pipeline on CPU at startup (ZeroGPU has nothing
to pack since no tensors are on GPU)
- pipe.to(device) inside @spaces.GPU: ~3-4s PCIe transfer vs ~19s disk
- pipe.to("cpu") in finally block so ZeroGPU has nothing to repack
Also reverts bad spaces==0.50.4 pin (build error) and raises GPU
duration defaults to accommodate the explicit model-move time.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- app.py +8 -4
- requirements.txt +1 -1
- static/mode_toggle.js +1 -1
- templates/app.html +2 -2
app.py
CHANGED
|
@@ -70,7 +70,7 @@ _hb = _start_heartbeat("transformer")
|
|
| 70 |
_transformer = QwenImageTransformer2DModel.from_pretrained(
|
| 71 |
"prithivMLmods/Qwen-Image-Edit-Rapid-AIO-V23",
|
| 72 |
torch_dtype=dtype,
|
| 73 |
-
device_map="
|
| 74 |
)
|
| 75 |
_hb.set()
|
| 76 |
print(f"[startup] transformer loaded in {time.perf_counter()-_t0_load:.1f}s", flush=True)
|
|
@@ -82,7 +82,7 @@ pipe = QwenImageEditPlusPipeline.from_pretrained(
|
|
| 82 |
"FireRedTeam/FireRed-Image-Edit-1.1",
|
| 83 |
transformer=_transformer,
|
| 84 |
torch_dtype=dtype,
|
| 85 |
-
)
|
| 86 |
_hb.set()
|
| 87 |
print(f"[startup] pipeline loaded in {time.perf_counter()-_t1_load:.1f}s", flush=True)
|
| 88 |
|
|
@@ -372,7 +372,9 @@ def _infer_gpu(pil_images, prompt, seed, guidance_scale, steps, width, height, m
|
|
| 372 |
print(f"[infer] GPU: {p.name}, total={p.total_memory/1024**3:.1f}GB, cap={p.major}.{p.minor}")
|
| 373 |
torch.cuda.reset_peak_memory_stats()
|
| 374 |
|
| 375 |
-
print(f"[infer] {
|
|
|
|
|
|
|
| 376 |
|
| 377 |
torch.cuda.empty_cache()
|
| 378 |
print(f"[infer] cache cleared — {_gpu_mem_str(_cuda_ok)}")
|
|
@@ -418,6 +420,8 @@ def _infer_gpu(pil_images, prompt, seed, guidance_scale, steps, width, height, m
|
|
| 418 |
timer.print_timings()
|
| 419 |
raise
|
| 420 |
finally:
|
|
|
|
|
|
|
| 421 |
gc.collect()
|
| 422 |
torch.cuda.empty_cache()
|
| 423 |
print(f"[infer] ===== END t={time.perf_counter()-t0:.1f}s =====")
|
|
@@ -432,7 +436,7 @@ with gr.Blocks() as demo:
|
|
| 432 |
guidance_scale = gr.Slider(minimum=1.0, maximum=10.0, step=0.1, value=1.0, elem_id="gradio-guidance", elem_classes="hidden-input", container=False)
|
| 433 |
steps = gr.Slider(minimum=1, maximum=50, step=1, value=4, elem_id="gradio-steps", elem_classes="hidden-input", container=False)
|
| 434 |
mode = gr.Textbox(value="fast", elem_id="gradio-mode", elem_classes="hidden-input", container=False)
|
| 435 |
-
gpu_duration = gr.Slider(minimum=10, maximum=120, step=5, value=
|
| 436 |
result = gr.Image(elem_id="gradio-result", elem_classes="hidden-input", container=False, format="png")
|
| 437 |
|
| 438 |
example_idx = gr.Textbox(value="", elem_id="example-idx-input", elem_classes="hidden-input", container=False)
|
|
|
|
| 70 |
_transformer = QwenImageTransformer2DModel.from_pretrained(
|
| 71 |
"prithivMLmods/Qwen-Image-Edit-Rapid-AIO-V23",
|
| 72 |
torch_dtype=dtype,
|
| 73 |
+
device_map="cpu",
|
| 74 |
)
|
| 75 |
_hb.set()
|
| 76 |
print(f"[startup] transformer loaded in {time.perf_counter()-_t0_load:.1f}s", flush=True)
|
|
|
|
| 82 |
"FireRedTeam/FireRed-Image-Edit-1.1",
|
| 83 |
transformer=_transformer,
|
| 84 |
torch_dtype=dtype,
|
| 85 |
+
)
|
| 86 |
_hb.set()
|
| 87 |
print(f"[startup] pipeline loaded in {time.perf_counter()-_t1_load:.1f}s", flush=True)
|
| 88 |
|
|
|
|
| 372 |
print(f"[infer] GPU: {p.name}, total={p.total_memory/1024**3:.1f}GB, cap={p.major}.{p.minor}")
|
| 373 |
torch.cuda.reset_peak_memory_stats()
|
| 374 |
|
| 375 |
+
print(f"[infer] moving pipe to {device}... — t={time.perf_counter()-t0:.1f}s")
|
| 376 |
+
pipe.to(device)
|
| 377 |
+
print(f"[infer] pipe on {device} — {_gpu_mem_str(_cuda_ok)} — t={time.perf_counter()-t0:.1f}s")
|
| 378 |
|
| 379 |
torch.cuda.empty_cache()
|
| 380 |
print(f"[infer] cache cleared — {_gpu_mem_str(_cuda_ok)}")
|
|
|
|
| 420 |
timer.print_timings()
|
| 421 |
raise
|
| 422 |
finally:
|
| 423 |
+
print(f"[infer] moving pipe to CPU... t={time.perf_counter()-t0:.1f}s")
|
| 424 |
+
pipe.to("cpu")
|
| 425 |
gc.collect()
|
| 426 |
torch.cuda.empty_cache()
|
| 427 |
print(f"[infer] ===== END t={time.perf_counter()-t0:.1f}s =====")
|
|
|
|
| 436 |
guidance_scale = gr.Slider(minimum=1.0, maximum=10.0, step=0.1, value=1.0, elem_id="gradio-guidance", elem_classes="hidden-input", container=False)
|
| 437 |
steps = gr.Slider(minimum=1, maximum=50, step=1, value=4, elem_id="gradio-steps", elem_classes="hidden-input", container=False)
|
| 438 |
mode = gr.Textbox(value="fast", elem_id="gradio-mode", elem_classes="hidden-input", container=False)
|
| 439 |
+
gpu_duration = gr.Slider(minimum=10, maximum=120, step=5, value=30, elem_id="gradio-gpu-duration", elem_classes="hidden-input", container=False)
|
| 440 |
result = gr.Image(elem_id="gradio-result", elem_classes="hidden-input", container=False, format="png")
|
| 441 |
|
| 442 |
example_idx = gr.Textbox(value="", elem_id="example-idx-input", elem_classes="hidden-input", container=False)
|
requirements.txt
CHANGED
|
@@ -7,7 +7,7 @@ pyarrow
|
|
| 7 |
sentencepiece
|
| 8 |
torchvision
|
| 9 |
kernels
|
| 10 |
-
spaces
|
| 11 |
hf_xet
|
| 12 |
gradio
|
| 13 |
pytest
|
|
|
|
| 7 |
sentencepiece
|
| 8 |
torchvision
|
| 9 |
kernels
|
| 10 |
+
spaces
|
| 11 |
hf_xet
|
| 12 |
gradio
|
| 13 |
pytest
|
static/mode_toggle.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
() => {
|
| 2 |
window.__selectedMode = 'fast';
|
| 3 |
-
var MODE_GPU_DURATION = { fast:
|
| 4 |
window.__setMode = function(m) {
|
| 5 |
window.__selectedMode = m;
|
| 6 |
var fast = document.getElementById('mode-btn-fast');
|
|
|
|
| 1 |
() => {
|
| 2 |
window.__selectedMode = 'fast';
|
| 3 |
+
var MODE_GPU_DURATION = { fast: 30, high_detail: 60 };
|
| 4 |
window.__setMode = function(m) {
|
| 5 |
window.__selectedMode = m;
|
| 6 |
var fast = document.getElementById('mode-btn-fast');
|
templates/app.html
CHANGED
|
@@ -120,8 +120,8 @@
|
|
| 120 |
<div class="settings-group-body">
|
| 121 |
<div class="slider-row">
|
| 122 |
<label>GPU Duration (s)</label>
|
| 123 |
-
<input type="range" id="custom-gpu-duration" min="10" max="120" step="5" value="
|
| 124 |
-
<span class="slider-val" id="custom-gpu-duration-val">
|
| 125 |
</div>
|
| 126 |
<div class="slider-row">
|
| 127 |
<label>Seed</label>
|
|
|
|
| 120 |
<div class="settings-group-body">
|
| 121 |
<div class="slider-row">
|
| 122 |
<label>GPU Duration (s)</label>
|
| 123 |
+
<input type="range" id="custom-gpu-duration" min="10" max="120" step="5" value="30">
|
| 124 |
+
<span class="slider-val" id="custom-gpu-duration-val">30</span>
|
| 125 |
</div>
|
| 126 |
<div class="slider-row">
|
| 127 |
<label>Seed</label>
|