@@ -97,14 +97,65 @@ def transformer_step(t_params, latents, img_ids, prompt_embeds, txt_ids, vec, ti
9797 guidance = guidance ,
9898 )
9999
100- @jax .jit
100+ @jax .jit ( donate_argnums = ( 1 ,))
101101 def vae_decode (v_params , latents_unpatched ):
102102 return self .vae .apply ({"params" : v_params }, latents = latents_unpatched , method = self .vae .decode )
103103
104104 self ._jitted_qwen3_forward = qwen3_forward
105105 self ._jitted_transformer_step = transformer_step
106106 self ._jitted_vae_decode = vae_decode
107107
108+ def compile_aot_async (self , params , vae_params , qwen3_params , batch_size = 1 , height = 1024 , width = 1024 ):
109+ """Triggers AOT compilation for Qwen3, Flux Transformer, and VAE concurrently using ThreadPoolExecutor."""
110+ self ._setup_jit_functions ()
111+ max_logging .log ("🚀 Pre-compiling XLA graphs for Qwen3, Flux Transformer, and VAE concurrently..." )
112+ from concurrent .futures import ThreadPoolExecutor
113+
114+ seq_len_img = (height // 16 ) * (width // 16 )
115+ seq_len_txt = self ._config .max_sequence_length
116+
117+ dummy_ids = jnp .zeros ((batch_size , seq_len_txt ), dtype = jnp .int32 )
118+ dummy_mask = jnp .ones ((batch_size , seq_len_txt ), dtype = jnp .int32 )
119+
120+ dummy_latents = jnp .zeros ((batch_size , seq_len_img , 128 ), dtype = jnp .float32 )
121+ dummy_img_ids = jnp .zeros ((batch_size , seq_len_img , 4 ), dtype = jnp .int32 )
122+ dummy_prompt_embeds = jnp .zeros ((batch_size , seq_len_txt , 12288 ), dtype = jnp .bfloat16 )
123+ dummy_txt_ids = jnp .zeros ((batch_size , seq_len_txt , 4 ), dtype = jnp .float32 )
124+ dummy_t_vec = jnp .zeros ((batch_size ,), dtype = jnp .float32 )
125+
126+ dummy_unpacked_latents = jnp .zeros ((batch_size , 32 , height // 8 , width // 8 ), dtype = jnp .float32 )
127+
128+ def compile_qwen3 ():
129+ t0 = time .perf_counter ()
130+ with self .mesh , nn_partitioning .axis_rules (self ._config .logical_axis_rules ):
131+ self ._jitted_qwen3_forward .lower (qwen3_params , dummy_ids , dummy_mask ).compile ()
132+ max_logging .log (f" -> [AOT COMPILED] Qwen3 Text Encoder in { time .perf_counter () - t0 :.2f} s" )
133+
134+ def compile_transformer ():
135+ t0 = time .perf_counter ()
136+ with self .mesh , nn_partitioning .axis_rules (self ._config .logical_axis_rules ):
137+ self ._jitted_transformer_step .lower (
138+ params , dummy_latents , dummy_img_ids , prompt_embeds = dummy_prompt_embeds , txt_ids = dummy_txt_ids , vec = None , timestep = dummy_t_vec , guidance = None
139+ ).compile ()
140+ max_logging .log (f" -> [AOT COMPILED] Flux Transformer Step in { time .perf_counter () - t0 :.2f} s" )
141+
142+ def compile_vae ():
143+ t0 = time .perf_counter ()
144+ with self .mesh , nn_partitioning .axis_rules (self ._config .logical_axis_rules ):
145+ self ._jitted_vae_decode .lower (vae_params , dummy_unpacked_latents ).compile ()
146+ max_logging .log (f" -> [AOT COMPILED] VAE Decoder in { time .perf_counter () - t0 :.2f} s" )
147+
148+ t_start = time .perf_counter ()
149+ with ThreadPoolExecutor (max_workers = 3 ) as executor :
150+ futures = [
151+ executor .submit (compile_qwen3 ),
152+ executor .submit (compile_transformer ),
153+ executor .submit (compile_vae ),
154+ ]
155+ for future in futures :
156+ future .result ()
157+ max_logging .log (f"⚡ [AOT CONCURRENT COMPILATION COMPLETE] Total AOT compile time: { time .perf_counter () - t_start :.2f} s" )
158+
108159 def _prepare_latents (self , config , batch_size , height , width ):
109160 num_channels_latents = 32
110161 latent_height = height // 8
@@ -147,6 +198,7 @@ def __call__(
147198 use_latents : bool = False ,
148199 latents : Optional [Any ] = None ,
149200 measure_time : bool = False ,
201+ warmup : bool = False ,
150202 output_dir : str = "output/" ,
151203 output_name : str = "flux2klein_generated_image.png" ,
152204 ):
@@ -293,8 +345,9 @@ def put_data_on_devices(x, sharding):
293345 # ---------------------------------------------------------------------
294346 # PHASE B: Denoising Loop (Flux Transformer - Standalone Step JIT)
295347 # ---------------------------------------------------------------------
348+ steps_to_run = 1 if warmup else num_inference_steps
296349 print (
297- f"{ host_prefix } [PHASE B] Running { num_inference_steps } -step E2E Denoising Loop on a batch of { batch_size } images..." ,
350+ f"{ host_prefix } [PHASE B] Running { steps_to_run } -step E2E Denoising Loop on a batch of { batch_size } images (warmup= { warmup } ) ..." ,
298351 flush = True ,
299352 )
300353 t0 = time .perf_counter ()
@@ -303,7 +356,7 @@ def put_data_on_devices(x, sharding):
303356 guidance_vec_val = None
304357 vec_val = None
305358
306- for step_idx in range (num_inference_steps ):
359+ for step_idx in range (steps_to_run ):
307360 timestep = scheduler_state .timesteps [step_idx ]
308361 t_vec = jnp .full ((batch_size ,), timestep / 1000.0 , dtype = latents_jax .dtype )
309362
0 commit comments