Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -164,47 +164,72 @@ except ImportError:
|
|
| 164 |
except ImportError:
|
| 165 |
QwenDoubleStreamAttnProcessorFA3 = None
|
| 166 |
|
|
|
|
| 167 |
dtype = torch.bfloat16 if torch.cuda.is_available() else torch.float32
|
| 168 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 169 |
|
| 170 |
def _load_pipe_with_version(version: str) -> QwenImageEditPlusPipeline:
|
| 171 |
sub = f"{version}/transformer"
|
| 172 |
print(f"📦 Loading AIO transformer: {AIO_REPO_ID} / {sub}")
|
| 173 |
-
device_map = "cuda" if torch.cuda.is_available() else "cpu"
|
| 174 |
p = QwenImageEditPlusPipeline.from_pretrained(
|
| 175 |
"Qwen/Qwen-Image-Edit-2511",
|
| 176 |
transformer=QwenImageTransformer2DModel.from_pretrained(
|
| 177 |
AIO_REPO_ID,
|
| 178 |
subfolder=sub,
|
| 179 |
torch_dtype=dtype,
|
| 180 |
-
device_map=
|
| 181 |
),
|
| 182 |
torch_dtype=dtype,
|
| 183 |
).to(device)
|
| 184 |
return p
|
| 185 |
|
| 186 |
|
| 187 |
-
|
| 188 |
-
|
| 189 |
-
pipe
|
| 190 |
-
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
|
| 195 |
-
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
|
| 206 |
-
|
| 207 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 208 |
|
| 209 |
MAX_SEED = np.iinfo(np.int32).max
|
| 210 |
|
|
@@ -754,6 +779,12 @@ def infer(
|
|
| 754 |
steps,
|
| 755 |
progress=gr.Progress(track_tqdm=True),
|
| 756 |
):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 757 |
gc.collect()
|
| 758 |
if torch.cuda.is_available():
|
| 759 |
torch.cuda.empty_cache()
|
|
@@ -860,9 +891,20 @@ aio_status_line = (
|
|
| 860 |
f"({AIO_VERSION_SOURCE}; env `AIO_VERSION`={_AIO_ENV_RAW!r})"
|
| 861 |
)
|
| 862 |
|
|
|
|
|
|
|
| 863 |
with gr.Blocks() as demo:
|
| 864 |
with gr.Column(elem_id="col-container"):
|
| 865 |
gr.Markdown("# **Qwen-Image-Edit-2511-LoRAs-Fast**", elem_id="main-title")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 866 |
gr.Markdown(
|
| 867 |
"Perform diverse image edits using specialized "
|
| 868 |
"[LoRA](https://huggingface.co/models?other=base_model:adapter:Qwen/Qwen-Image-Edit-2511) adapters for the "
|
|
|
|
| 164 |
except ImportError:
|
| 165 |
QwenDoubleStreamAttnProcessorFA3 = None
|
| 166 |
|
| 167 |
+
# ── dtype: bfloat16 on GPU (fast), float32 on CPU (fallback) ──────────────
|
| 168 |
dtype = torch.bfloat16 if torch.cuda.is_available() else torch.float32
|
| 169 |
|
| 170 |
+
# ── Lazy pipeline: only load when a GPU is actually present ───────────────
|
| 171 |
+
# Loading a 10 GB model on CPU OOMs free-tier Spaces (16 GB RAM limit).
|
| 172 |
+
# We defer loading to first inference; if no GPU is present the UI still
|
| 173 |
+
# starts and shows a clear warning instead of crashing at startup.
|
| 174 |
+
pipe = None
|
| 175 |
+
_pipe_loaded_version: str | None = None
|
| 176 |
+
|
| 177 |
|
| 178 |
def _load_pipe_with_version(version: str) -> QwenImageEditPlusPipeline:
|
| 179 |
sub = f"{version}/transformer"
|
| 180 |
print(f"📦 Loading AIO transformer: {AIO_REPO_ID} / {sub}")
|
|
|
|
| 181 |
p = QwenImageEditPlusPipeline.from_pretrained(
|
| 182 |
"Qwen/Qwen-Image-Edit-2511",
|
| 183 |
transformer=QwenImageTransformer2DModel.from_pretrained(
|
| 184 |
AIO_REPO_ID,
|
| 185 |
subfolder=sub,
|
| 186 |
torch_dtype=dtype,
|
| 187 |
+
device_map="cuda", # only called when CUDA is confirmed
|
| 188 |
),
|
| 189 |
torch_dtype=dtype,
|
| 190 |
).to(device)
|
| 191 |
return p
|
| 192 |
|
| 193 |
|
| 194 |
+
def _ensure_pipe_loaded() -> None:
|
| 195 |
+
"""Load the pipeline on first call (requires CUDA). Raises if no GPU."""
|
| 196 |
+
global pipe, _pipe_loaded_version, AIO_VERSION, AIO_VERSION_SOURCE
|
| 197 |
+
if pipe is not None:
|
| 198 |
+
return
|
| 199 |
+
if not torch.cuda.is_available():
|
| 200 |
+
raise RuntimeError(
|
| 201 |
+
"No GPU detected. This Space requires a CUDA GPU to run. "
|
| 202 |
+
"Go to Space Settings > Hardware and select a GPU tier (e.g. T4 Medium)."
|
| 203 |
+
)
|
| 204 |
+
try:
|
| 205 |
+
pipe = _load_pipe_with_version(AIO_VERSION)
|
| 206 |
+
_pipe_loaded_version = AIO_VERSION
|
| 207 |
+
except Exception as e:
|
| 208 |
+
print("❌ Failed to load requested AIO_VERSION. Falling back to v19.")
|
| 209 |
+
print(traceback.format_exc())
|
| 210 |
+
AIO_VERSION = DEFAULT_AIO_VERSION
|
| 211 |
+
AIO_VERSION_SOURCE = "fallback_to_v19"
|
| 212 |
+
pipe = _load_pipe_with_version(AIO_VERSION)
|
| 213 |
+
_pipe_loaded_version = AIO_VERSION
|
| 214 |
+
|
| 215 |
+
# Apply FA3 Optimization
|
| 216 |
+
try:
|
| 217 |
+
if QwenDoubleStreamAttnProcessorFA3 is not None:
|
| 218 |
+
pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
|
| 219 |
+
print("Flash Attention 3 Processor set successfully.")
|
| 220 |
+
else:
|
| 221 |
+
print("Warning: QwenDoubleStreamAttnProcessorFA3 not available; skipping.")
|
| 222 |
+
except Exception as e:
|
| 223 |
+
print(f"Warning: Could not set FA3 processor: {e}")
|
| 224 |
+
|
| 225 |
+
|
| 226 |
+
if torch.cuda.is_available():
|
| 227 |
+
# GPU available at startup — load immediately so first request is fast
|
| 228 |
+
_ensure_pipe_loaded()
|
| 229 |
+
else:
|
| 230 |
+
print("⚠️ No GPU at startup — pipeline will NOT be loaded.")
|
| 231 |
+
print(" The UI will start but inference will fail until a GPU is assigned.")
|
| 232 |
+
print(" Fix: Space Settings → Hardware → select a GPU tier.")
|
| 233 |
|
| 234 |
MAX_SEED = np.iinfo(np.int32).max
|
| 235 |
|
|
|
|
| 779 |
steps,
|
| 780 |
progress=gr.Progress(track_tqdm=True),
|
| 781 |
):
|
| 782 |
+
# Ensure pipeline is loaded (raises friendly error if no GPU)
|
| 783 |
+
try:
|
| 784 |
+
_ensure_pipe_loaded()
|
| 785 |
+
except RuntimeError as e:
|
| 786 |
+
raise gr.Error(str(e))
|
| 787 |
+
|
| 788 |
gc.collect()
|
| 789 |
if torch.cuda.is_available():
|
| 790 |
torch.cuda.empty_cache()
|
|
|
|
| 891 |
f"({AIO_VERSION_SOURCE}; env `AIO_VERSION`={_AIO_ENV_RAW!r})"
|
| 892 |
)
|
| 893 |
|
| 894 |
+
NO_GPU_WARNING = not torch.cuda.is_available()
|
| 895 |
+
|
| 896 |
with gr.Blocks() as demo:
|
| 897 |
with gr.Column(elem_id="col-container"):
|
| 898 |
gr.Markdown("# **Qwen-Image-Edit-2511-LoRAs-Fast**", elem_id="main-title")
|
| 899 |
+
if NO_GPU_WARNING:
|
| 900 |
+
gr.Markdown(
|
| 901 |
+
"## ⚠️ No GPU detected — inference is disabled\n\n"
|
| 902 |
+
"This model requires a **CUDA GPU** to run. The app has started, but clicking "
|
| 903 |
+
"**Edit Image** will show an error.\n\n"
|
| 904 |
+
"**Fix:** Go to your Space → ⚙️ **Settings** → **Hardware** → "
|
| 905 |
+
"select **T4 Medium** (or better) → **Save**. The Space will rebuild with a GPU.",
|
| 906 |
+
visible=True,
|
| 907 |
+
)
|
| 908 |
gr.Markdown(
|
| 909 |
"Perform diverse image edits using specialized "
|
| 910 |
"[LoRA](https://huggingface.co/models?other=base_model:adapter:Qwen/Qwen-Image-Edit-2511) adapters for the "
|