someone-in-the-world Claude Sonnet 5 commited on
Commit
1093d66
·
1 Parent(s): d86fc4a

Revert NF4 quantization: this checkpoint's weights are stored fp8-native

Browse files

Space startup crashed: RuntimeError: Blockwise 4bit quantization only
supports 16/32-bit floats, but got torch.float8_e4m3fn.

The transformer safetensors index reports ~19GB total for a 20B-param
model (~1 byte/param), confirming prithivMLmods/Qwen-Image-Edit-Rapid-
AIO-V23 already ships as fp8, not bf16. bitsandbytes' 4-bit quantizer
requires a 16/32-bit source tensor to quantize from and cannot operate
on fp8-stored weights directly — and since nothing in this vendored
qwenimage code has fp8 compute kernels, the weights still need to be
upcast to bf16 for the forward pass to work at all, which is exactly
what the pre-quantization code already did. So NF4-on-load isn't a
drop-in fix here; doing it properly would mean manually materializing
the model in bf16 first and then hand-converting nn.Linear modules to
Linear4bit, which needs real GPU verification to get right.

Reverting app.py to the pre-quantization state (926cf86) to restore a
working Space. The requirements.txt fix pinning diffusers==0.39.0
(unrelated to quantization — it fixed a real huggingface-hub version
conflict against the transformers==4.57.1 pin) is kept since it's
still correct and needed regardless of the quantization approach.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

Files changed (2) hide show
  1. app.py +21 -33
  2. requirements.txt +0 -1
app.py CHANGED
@@ -72,7 +72,7 @@ print("[startup] TF32 enabled", flush=True)
72
  print("[startup] importing dimensions...", flush=True)
73
  from dimensions import compute_output_dimensions, max_dim_for_mode
74
  print("[startup] importing diffusers...", flush=True)
75
- from diffusers import BitsAndBytesConfig, FlowMatchEulerDiscreteScheduler
76
  print("[startup] importing QwenImageEditPlusPipeline...", flush=True)
77
  from qwenimage.pipeline_qwenimage_edit_plus import QwenImageEditPlusPipeline
78
  print("[startup] importing QwenImageTransformer2DModel...", flush=True)
@@ -97,31 +97,13 @@ def _start_heartbeat(label: str) -> threading.Event:
97
  _t0_load = time.perf_counter()
98
  print("[startup] loading transformer from_pretrained (prithivMLmods/Qwen-Image-Edit-Rapid-AIO-V23)...", flush=True)
99
  _hb = _start_heartbeat("transformer")
100
- # NF4-quantize the transformer (~20B params, ~40GB in bf16) to fit the pipeline
101
- # comfortably inside this Space's 47GB MIG slice. bitsandbytes only quantizes
102
- # on an actual CUDA device (it rejects device_map="cpu"/"disk" for a fresh,
103
- # not-yet-quantized config), so this loads straight onto cuda:0 instead of the
104
- # CPU-first pattern used below for the rest of the pipeline. That pays the
105
- # once-per-boot "ZeroGPU disk packing" cost the CPU-first load was added to
106
- # avoid, but only once at startup rather than never.
107
- _quant_config = BitsAndBytesConfig(
108
- load_in_4bit=True,
109
- bnb_4bit_quant_type="nf4",
110
- bnb_4bit_compute_dtype=dtype,
111
- bnb_4bit_use_double_quant=True,
112
- ) if torch.cuda.is_available() else None
113
  _transformer = QwenImageTransformer2DModel.from_pretrained(
114
  "prithivMLmods/Qwen-Image-Edit-Rapid-AIO-V23",
115
  torch_dtype=dtype,
116
- device_map={"": 0} if _quant_config else "cpu",
117
- quantization_config=_quant_config,
118
  )
119
  _hb.set()
120
  print(f"[startup] transformer loaded in {time.perf_counter()-_t0_load:.1f}s", flush=True)
121
- try:
122
- print(f"[startup] transformer memory footprint: {_transformer.get_memory_footprint()/1024**3:.2f}GB", flush=True)
123
- except Exception as e:
124
- print(f"[startup] transformer memory footprint: unavailable ({e})", flush=True)
125
 
126
  _t1_load = time.perf_counter()
127
  print("[startup] loading pipeline from_pretrained (FireRedTeam/FireRed-Image-Edit-1.1)...", flush=True)
@@ -422,21 +404,27 @@ def _infer_gpu(pil_images, prompt, seed, guidance_scale, steps, width, height, m
422
 
423
  # Each ZeroGPU call runs in a fresh worker (hooks are always unset here),
424
  # so cpu_offload buys no cross-call reuse — it only trades one bulk
425
- # to(device) transfer for several slower hook-managed ones. The
426
- # transformer is now NF4-quantized (~40GB bf16 -> ~11GB), so the full
427
- # pipeline (~25-30GB total) should comfortably fit even on the 47GB
428
- # 2g.48gb MIG slice this Space actually gets always attempt full-GPU
429
- # residency first and only fall back to offload on an actual OOM.
 
 
430
  if getattr(pipe.transformer, "_hf_hook", None) is None:
431
- try:
432
- pipe.to(device)
433
- print(f"[infer] moved full pipe to {device} — t={time.perf_counter()-t0:.1f}s")
434
- except torch.cuda.OutOfMemoryError:
435
- print(f"[infer] OOM moving full pipe to {device}, falling back to cpu offload")
436
- pipe.to("cpu")
437
- torch.cuda.empty_cache()
 
 
 
 
438
  pipe.enable_model_cpu_offload(device=device)
439
- print(f"[infer] enabled cpu offload on {device} (fallback)")
440
  print(f"[infer] {_gpu_mem_str(_cuda_ok)} — t={time.perf_counter()-t0:.1f}s")
441
 
442
  print(f"[infer] {len(pil_images)} image(s) pre-decoded, output={width}x{height}, seed={seed}")
 
72
  print("[startup] importing dimensions...", flush=True)
73
  from dimensions import compute_output_dimensions, max_dim_for_mode
74
  print("[startup] importing diffusers...", flush=True)
75
+ from diffusers import FlowMatchEulerDiscreteScheduler
76
  print("[startup] importing QwenImageEditPlusPipeline...", flush=True)
77
  from qwenimage.pipeline_qwenimage_edit_plus import QwenImageEditPlusPipeline
78
  print("[startup] importing QwenImageTransformer2DModel...", flush=True)
 
97
  _t0_load = time.perf_counter()
98
  print("[startup] loading transformer from_pretrained (prithivMLmods/Qwen-Image-Edit-Rapid-AIO-V23)...", flush=True)
99
  _hb = _start_heartbeat("transformer")
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  _transformer = QwenImageTransformer2DModel.from_pretrained(
101
  "prithivMLmods/Qwen-Image-Edit-Rapid-AIO-V23",
102
  torch_dtype=dtype,
103
+ device_map="cpu",
 
104
  )
105
  _hb.set()
106
  print(f"[startup] transformer loaded in {time.perf_counter()-_t0_load:.1f}s", flush=True)
 
 
 
 
107
 
108
  _t1_load = time.perf_counter()
109
  print("[startup] loading pipeline from_pretrained (FireRedTeam/FireRed-Image-Edit-1.1)...", flush=True)
 
404
 
405
  # Each ZeroGPU call runs in a fresh worker (hooks are always unset here),
406
  # so cpu_offload buys no cross-call reuse — it only trades one bulk
407
+ # to(device) transfer for several slower hook-managed ones. On a
408
+ # generously-sized allocation, move the full ~37GB pipeline to GPU in one
409
+ # shot (fast); but the 47GB 2g.48gb MIG slice this Space actually gets
410
+ # measured a peak of 46.82GB and still OOM'd on that path, wasting ~40s
411
+ # before falling back so only attempt it when there's real headroom
412
+ # above that, otherwise go straight to enable_model_cpu_offload.
413
+ _FAST_PATH_MIN_GB = 60
414
  if getattr(pipe.transformer, "_hf_hook", None) is None:
415
+ if _cuda_ok and p.total_memory / 1024**3 >= _FAST_PATH_MIN_GB:
416
+ try:
417
+ pipe.to(device)
418
+ print(f"[infer] moved full pipe to {device} — t={time.perf_counter()-t0:.1f}s")
419
+ except torch.cuda.OutOfMemoryError:
420
+ print(f"[infer] OOM moving full pipe to {device}, falling back to cpu offload")
421
+ pipe.to("cpu")
422
+ torch.cuda.empty_cache()
423
+ pipe.enable_model_cpu_offload(device=device)
424
+ print(f"[infer] enabled cpu offload on {device} (fallback)")
425
+ else:
426
  pipe.enable_model_cpu_offload(device=device)
427
+ print(f"[infer] enabled cpu offload on {device} (slice too small for fast path)")
428
  print(f"[infer] {_gpu_mem_str(_cuda_ok)} — t={time.perf_counter()-t0:.1f}s")
429
 
430
  print(f"[infer] {len(pil_images)} image(s) pre-decoded, output={width}x{height}, seed={seed}")
requirements.txt CHANGED
@@ -2,7 +2,6 @@ git+https://github.com/huggingface/accelerate.git
2
  diffusers==0.39.0
3
  git+https://github.com/huggingface/peft.git
4
  transformers==4.57.1
5
- bitsandbytes
6
  huggingface_hub
7
  pyarrow
8
  sentencepiece
 
2
  diffusers==0.39.0
3
  git+https://github.com/huggingface/peft.git
4
  transformers==4.57.1
 
5
  huggingface_hub
6
  pyarrow
7
  sentencepiece