Spaces:
Runtime error
Runtime error
moose Claude Opus 4.5 commited on
Commit ·
bca4977
1
Parent(s): 07e1710
Fix device mismatch during AOT compilation warmup
Browse filesMove text encoder offloading inside optimize_pipeline_() to happen
AFTER the warmup pass but BEFORE torch.export. This ensures:
1. Warmup run has all components on GPU (avoids CPU/CUDA mismatch)
2. torch.export has reduced memory (text encoder on CPU)
3. Text encoder returns to GPU after compilation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- app.py +1 -9
- optimization.py +17 -2
app.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
| 1 |
-
import gc
|
| 2 |
import gradio as gr
|
| 3 |
import numpy as np
|
| 4 |
import random
|
|
@@ -123,16 +122,9 @@ pipe.transformer.__class__ = QwenImageTransformer2DModel
|
|
| 123 |
pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
|
| 124 |
|
| 125 |
# --- Ahead-of-time compilation ---
|
| 126 |
-
#
|
| 127 |
-
pipe.text_encoder.to('cpu')
|
| 128 |
-
gc.collect()
|
| 129 |
-
torch.cuda.empty_cache()
|
| 130 |
-
|
| 131 |
optimize_pipeline_(pipe, image=[Image.new("RGB", (1024, 1024)), Image.new("RGB", (1024, 1024))], prompt="prompt")
|
| 132 |
|
| 133 |
-
# Move text encoder back to GPU for inference
|
| 134 |
-
pipe.text_encoder.to(device)
|
| 135 |
-
|
| 136 |
# --- UI Constants and Helpers ---
|
| 137 |
MAX_SEED = np.iinfo(np.int32).max
|
| 138 |
|
|
|
|
|
|
|
| 1 |
import gradio as gr
|
| 2 |
import numpy as np
|
| 3 |
import random
|
|
|
|
| 122 |
pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
|
| 123 |
|
| 124 |
# --- Ahead-of-time compilation ---
|
| 125 |
+
# Note: optimize_pipeline_ handles text encoder offloading internally to save memory during torch.export
|
|
|
|
|
|
|
|
|
|
|
|
|
| 126 |
optimize_pipeline_(pipe, image=[Image.new("RGB", (1024, 1024)), Image.new("RGB", (1024, 1024))], prompt="prompt")
|
| 127 |
|
|
|
|
|
|
|
|
|
|
| 128 |
# --- UI Constants and Helpers ---
|
| 129 |
MAX_SEED = np.iinfo(np.int32).max
|
| 130 |
|
optimization.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
| 1 |
"""
|
|
|
|
| 2 |
"""
|
| 3 |
|
|
|
|
| 4 |
from typing import Any
|
| 5 |
from typing import Callable
|
| 6 |
from typing import ParamSpec
|
|
@@ -50,14 +52,22 @@ def optimize_pipeline_(pipeline: Callable[P, Any], *args: P.args, **kwargs: P.kw
|
|
| 50 |
@spaces.GPU(duration=1500)
|
| 51 |
def compile_transformer():
|
| 52 |
|
|
|
|
| 53 |
with spaces.aoti_capture(pipeline.transformer) as call:
|
| 54 |
pipeline(*args, **kwargs)
|
| 55 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
dynamic_shapes = tree_map(lambda t: None, call.kwargs)
|
| 57 |
dynamic_shapes |= TRANSFORMER_DYNAMIC_SHAPES
|
| 58 |
|
| 59 |
# quantize_(pipeline.transformer, Float8DynamicActivationFloat8WeightConfig())
|
| 60 |
-
|
| 61 |
exported = torch.export.export(
|
| 62 |
mod=pipeline.transformer,
|
| 63 |
args=call.args,
|
|
@@ -65,6 +75,11 @@ def optimize_pipeline_(pipeline: Callable[P, Any], *args: P.args, **kwargs: P.kw
|
|
| 65 |
dynamic_shapes=dynamic_shapes,
|
| 66 |
)
|
| 67 |
|
| 68 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 69 |
|
| 70 |
spaces.aoti_apply(compile_transformer(), pipeline.transformer)
|
|
|
|
| 1 |
"""
|
| 2 |
+
AOT compilation optimization for Qwen-Image-Edit pipeline.
|
| 3 |
"""
|
| 4 |
|
| 5 |
+
import gc
|
| 6 |
from typing import Any
|
| 7 |
from typing import Callable
|
| 8 |
from typing import ParamSpec
|
|
|
|
| 52 |
@spaces.GPU(duration=1500)
|
| 53 |
def compile_transformer():
|
| 54 |
|
| 55 |
+
# Run warmup pass to capture transformer inputs (needs all components on GPU)
|
| 56 |
with spaces.aoti_capture(pipeline.transformer) as call:
|
| 57 |
pipeline(*args, **kwargs)
|
| 58 |
|
| 59 |
+
# Offload text encoder to CPU to free ~16GB during memory-intensive torch.export
|
| 60 |
+
# This happens AFTER warmup but BEFORE export to avoid device mismatch
|
| 61 |
+
text_encoder_device = next(pipeline.text_encoder.parameters()).device
|
| 62 |
+
pipeline.text_encoder.to('cpu')
|
| 63 |
+
gc.collect()
|
| 64 |
+
torch.cuda.empty_cache()
|
| 65 |
+
|
| 66 |
dynamic_shapes = tree_map(lambda t: None, call.kwargs)
|
| 67 |
dynamic_shapes |= TRANSFORMER_DYNAMIC_SHAPES
|
| 68 |
|
| 69 |
# quantize_(pipeline.transformer, Float8DynamicActivationFloat8WeightConfig())
|
| 70 |
+
|
| 71 |
exported = torch.export.export(
|
| 72 |
mod=pipeline.transformer,
|
| 73 |
args=call.args,
|
|
|
|
| 75 |
dynamic_shapes=dynamic_shapes,
|
| 76 |
)
|
| 77 |
|
| 78 |
+
compiled = spaces.aoti_compile(exported, INDUCTOR_CONFIGS)
|
| 79 |
+
|
| 80 |
+
# Move text encoder back to original device
|
| 81 |
+
pipeline.text_encoder.to(text_encoder_device)
|
| 82 |
+
|
| 83 |
+
return compiled
|
| 84 |
|
| 85 |
spaces.aoti_apply(compile_transformer(), pipeline.transformer)
|