moose Claude Opus 4.5 commited on
Commit
bca4977
·
1 Parent(s): 07e1710

Fix device mismatch during AOT compilation warmup

Browse files

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

Files changed (2) hide show
  1. app.py +1 -9
  2. 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
- # Temporarily offload text encoder to CPU to free ~16GB during memory-intensive torch.export
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
- return spaces.aoti_compile(exported, INDUCTOR_CONFIGS)
 
 
 
 
 
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)