someone-in-the-world Claude Sonnet 4.6 commited on
Commit
6c0477d
·
1 Parent(s): 2668631

Load model on CPU at startup to bypass slow ZeroGPU disk packing

Browse files

spaces 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>

Files changed (4) hide show
  1. app.py +8 -4
  2. requirements.txt +1 -1
  3. static/mode_toggle.js +1 -1
  4. 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="cuda",
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
- ).to(device)
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] {_gpu_mem_str(_cuda_ok)} — t={time.perf_counter()-t0:.1f}s")
 
 
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=20, elem_id="gradio-gpu-duration", elem_classes="hidden-input", container=False)
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==0.50.4
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: 20, high_detail: 40 };
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="20">
124
- <span class="slider-val" id="custom-gpu-duration-val">20</span>
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>