Skip to content

Flux2klein Onboarding#445

Draft
amepas wants to merge 1 commit into
mainfrom
flux2klein-onboarding-clean
Draft

Flux2klein Onboarding#445
amepas wants to merge 1 commit into
mainfrom
flux2klein-onboarding-clean

Conversation

@amepas

@amepas amepas commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

This branch contains all of the code for onboarding the Flux2.Klein model into this repo. PR contains support for both the 4B and 9B model variants.

Images can be generated with:
python src/maxdiffusion/generate_flux2klein.py src/maxdiffusion/configs/base_flux2klein.yml

For the 9B model, point to the corresponding .yml file
python src/maxdiffusion/generate_flux2klein.py src/maxdiffusion/configs/base_flux2klein_9B.yml

Running this implementation on a v7-1 with FSDP=2 on Batch-size 8 (1024 by 1024) gives the following latency:

  • Model Loading: 546.69s
  • Dry-Run/Compilation: 73.94s
  • Text Embedding (Qwen3): 0.32s
  • Denoising: 2.96s
  • VAE: 0.24s
  • E2E Latency: 3.51s

Some call-outs on the implementation:

  • src/maxdiffusion/generate_flux2klein.py is the main user-facing file for running either the 4B and 9B files. It invokes src/maxdiffusion/pipelines/flux/flux2klein_pipeline.py.
  • src/maxdiffusion/models/flux/transformers/transformer_flux_flax.py is heavily modified to add support for the new variants of the Attention blocks used in the Flux2.Klein models over the older generation of models.
  • We add a custom Jax implementation of the Qwen3 model: src/maxdiffusion/models/qwen3_flax.py
  • We add two sets of tests: a smoke test to check if the implementation has changed in any way, and a e2e parity test that generates images from the Pytorch diffusers library and compares the generated outputs from our new implementation for the 4B and 9B models.

@amepas amepas requested a review from entrpn as a code owner July 14, 2026 06:36
@github-actions

Copy link
Copy Markdown

@amepas amepas force-pushed the flux2klein-onboarding-clean branch from e4e7f55 to 8a38bd9 Compare July 14, 2026 16:17
@amepas amepas force-pushed the flux2klein-onboarding-clean branch 2 times, most recently from b22d0ce to a67c8b7 Compare July 14, 2026 19:02
Comment thread src/maxdiffusion/tests/generate_flux2klein_smoke_test.py
Comment thread src/maxdiffusion/models/qwen3_flax.py Outdated
Comment thread src/maxdiffusion/generate_flux2klein.py Outdated
Comment thread src/maxdiffusion/pipelines/flux/flux2klein_pipeline.py
Comment thread src/maxdiffusion/pipelines/flux/flux2klein_pipeline.py
@amepas amepas force-pushed the flux2klein-onboarding-clean branch 2 times, most recently from 48b898f to 20a03d2 Compare July 14, 2026 22:11
@amepas amepas requested a review from eltsai July 14, 2026 22:11
@amepas amepas force-pushed the flux2klein-onboarding-clean branch 4 times, most recently from 7bcb105 to f446205 Compare July 14, 2026 22:55
@amepas amepas force-pushed the flux2klein-onboarding-clean branch from f446205 to 56e6a4d Compare July 14, 2026 23:03

@eltsai eltsai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still see a few print statement instead of max_logging, but I think it's fine for now, we can send out a small PR for that later. RN let's prioritize merging the model onboarding PR.

I was able to reproduce the same e2e generation time as reported.

@github-actions

Copy link
Copy Markdown

🤖 Hi @eltsai, I've received your request, and I'm working on it now! You can track my progress in the logs for more details.

@github-actions

Copy link
Copy Markdown

🤖 I'm sorry @eltsai, but I was unable to process your request. Please see the logs for more details.

@eltsai

eltsai commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

Seems like the linter test failed because of #443 , but #443 itself passed the linter tests, @syhuang22 is investigating it now

)["params"]


class FlaxSwiGluFeedForward(nn.Module):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New models in maxdiffusion should be using nnx over linen. Is there a reason why linen was used?

interactive: False

# 9B Architecture Dimensions
depth: 24 # num_single_layers

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are these required? They can be retrieved from the huggingface config.

import jax.numpy as jnp
import jax

for k, v in list(d.items()):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should filter out norm layers to keep those calculations in fp32 for numerical stability. For example, see https://github.com/AI-Hypercomputer/maxdiffusion/blob/main/src/maxdiffusion/pipelines/wan/wan_pipeline.py#L95

first_leaf = jax.tree_util.tree_leaves(params)[0]
target_dtype = first_leaf.dtype

def cvt(tensor, transpose=False):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you rename this function to something more clear.

)
del pt_state_dict
gc.collect()
max_logging.log("Weight conversion complete!")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think its best to validate params have been mapped correct. For example something like https://github.com/AI-Hypercomputer/maxdiffusion/blob/main/src/maxdiffusion/models/flux/util.py#L116

max_logging.log(f"Loading VAE weights from: {safetensors_path}")
pt_state_dict = load_file(safetensors_path)

def get_w(key):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you rename the function to something more clear.

)(timesteps_proj.astype(dtype))

if self.guidance_embeds and guidance is not None:
guidance_proj = FlaxTimesteps(dim=256, flip_sin_to_cos=True, freq_shift=0)(guidance)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where is 256 from? any way it can be passed instead of being hardcoded.

@@ -0,0 +1,491 @@
"""

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this model loaded replicated? Can it be sharded?

# ---------------------------------------------------------------------
# PHASE A: Encode Prompt (Qwen3)
# ---------------------------------------------------------------------
print(f"[PHASE A] Encoding {len(prompts)} prompt(s) using JAX Qwen3 on TPU...")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for print statements, please use max_logging instead.

@entrpn entrpn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

left some comments + please change all print statements to max_logging instead.

@amepas amepas marked this pull request as draft July 15, 2026 03:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants