Optimizing flux2klein - #458
Conversation
…st weight loading and concurrent AOT compilation
There was a problem hiding this comment.
Code Review
This pull request introduces a unified end-to-end inference pipeline for Flux.2-klein models (4B and 9B) on JAX+TPU, including configurations, entry point scripts, and optimizations such as concurrent AOT compilation and memory-efficient resizing. Feedback on the changes highlights several critical issues: several duplicate files were added in incorrect directories and should be removed; Qwen3 attention needs to correctly handle causal and padding masks when using non-dot_product kernels; step_index should not be a static argument in the scheduler to avoid JIT recompilation; potential index errors when text_encoder_max_layer is less than 27 should be addressed; and fractional per_device_batch_size in the smoke test should be fixed to prevent JAX sharding errors.
…s and architectural audit fixes - Recovered 290.55 ms Flux denoising loop scan latency using custom 2D Ring Ulysses attention (ulysses_ring_custom_fixed_m) and optimal 4608x1024 Flash block sizes. - Formulated 4-step generation pass into fused jax.lax.scan loop with uniform full-warmup execution. - Eliminated redundant Host-to-Device placement overhead, pre-staged mesh timesteps, and implemented dynamic step indexing in FlowMatchScheduler. - Optimized Qwen3 text encoder with early layer 27 exit, inside-JIT formatting, cached tokenizers, dot_product backend isolation, and upfront max_layer validation. - Implemented direct 4D spatial channel vectorized VAE decoding and fast on-TPU uint8 image save matching SGLang specs. - Restored isolated component XProf profiling and cleaned up redundant codebase duplicate files.
64a64aa to
d78a39e
Compare
| attention_sharding_uniform: True | ||
|
|
||
| flash_block_sizes: {} | ||
| block_q: 0 |
There was a problem hiding this comment.
maybe set these variable using some runnable values (like the optimal ones you found)
Building off of PR 456 (hence 2 commits listed here).
Summary
This PR improves inference speeds for Flux2 Klein Models. ~2.58x overall speedup compared to the original implementation and outperform the standard SGLang GB200 baseline.
Performance Benchmarks
1131.20 ms/img765.28 ms/img563.90 ms/img406.40 ms/img438.00 ms/img329.77 ms/img--
Optimizations
1. Tokenizer Caching Outside Warmup & Inference Loops
Instantiated and cached
self.tokenizeronce inFlaxFlux2KleinPipeline.__init__. String inputs are tokenized directly into contiguous PyTorch/NumPy arrays prior to device placement.2. Early-Stopping Qwen3 Text Encoder Execution at Layer 27 (
max_layer_to_run=27)Standard Qwen3 contains 28+ layers, but Flux.2-Klein only extracts cross-attention text embedding representations from intermediate layers 9, 18, and 27. Running layers 28+ performed pure wasted matrix multiplication compute.
3. Dedicated
dot_productAttention Backend for Qwen3 (Backend Isolation)Passing shared global attention arguments into both Qwen3 and Flux caused Qwen3 to attempt loading ring Ulysses Splash kernels (
ulysses_ring_custom), which are slow on the short 512-token text prompts.4. Fusing 4 Denoising Steps into
jax.lax.scan(_jitted_fused_denoise_loop)Switching from a standard for loop to compile as a single graph.
5. Internal Denoising Loop Optimizations
put_data_on_devicesinside Denoising Loop (~4.2 ms saved)scheduler_state.timestepsandscheduler_state.sigmassharding onto the device mesh outside the iterative loop.step_index: Optional[int] = Noneinscheduling_flow_match_flax.pyso the denoising loop passes the exact loop index directly (step_idx) to avoid_find_timestep_idsearches (jnp.argmin(jnp.abs(...))) during every step.6. Optimal Configuration Settings:
attention="ulysses_ring_custom_fixed_m":ici_context_parallelism=2&ulysses_shards=2ulysses_attention_chunks=1: Single-chunk ring stream execution.flash_block_sizes='{"block_q": 4608, "block_kv": 1024, "block_kv_compute": 1024}'.7. Image Saving (
uint8) Matching SGLang implementationImplemented vector clamping and conversion directly on TPU arrays to
uint8([0, 255]) before copying buffers to CPU for PNG encoding.8. 4D Spatial Vectorization in VAE Decoding (
_jitted_vae_decode)The VAE decoder previously packed and flattened latents into intermediate 3D spaces, requiring multiple transpose and reshape operations. Refactored
_jitted_vae_decode(donate_argnums=(1,)) to operate directly on 4D spatial tensors(batch_size, 32, height // 8, width // 8)using direct 4D convolution blocks.Correctness
All smoke tests pass