Optimizing flux2klein - #458
Conversation
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.
64a64aa to
d78a39e
Compare
3daea67 to
9dbca46
Compare
…weight loading, and end-to-end optimizations - Implemented Flax NNX Transformer architecture (NNXFlux2KleinTransformer2DModel) with support for both 4B (5 double / 20 single layers) and 9B (8 double / 24 single layers) configurations. - Integrated Flax Qwen3 text encoder with 3-layer intermediate hidden states extraction (layers 9, 18, 27) and custom splash/dot-product attention. - Implemented FlaxAutoencoderKL VAE decoder with fused batch normalization unscaling and channel re-layout. - Added fused end-to-end denoising loop scan with Flow Match Euler scheduler. - Added concurrent AOT XLA compilation across Qwen3, Flux transformer, and VAE. - Implemented fast host-memory streaming weight converter for safetensors shards directly into NNX State PyTree. - Optimized splash attention block sizes and Ulysses context parallelism sharding. - Added comprehensive unit tests and end-to-end smoke test suite (generate_flux2klein_smoke_test.py).
9dbca46 to
9162a46
Compare
Building off of PR 456 (so some overlapping code changes)
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