Repository navigation
Conversation
4 of 10 tasks
LuminaAttnProcessor2_0 expanded the (batch, 1, 1, kv_len) bool mask to (batch, heads, q_len, kv_len) before F.scaled_dot_product_attention. SDPA broadcasts the mask, so pass it as is, and say so in the comment above it. Add a test that compares the transformer output with the broadcast mask against SDPA called with the expanded mask, using a padded prompt mask, and checks that the padded text tokens do not change the output. Bit-identical output at 1024x1024 (model card setting). Signed-off-by: Hsu, Chan Fu <ChanFu.Hsu@amd.com>
LuminaPipeline built a 384 x 384 RoPE table on CPU inside the denoising loop on every step, and LuminaPatchEmbed moved the whole table to the device before slicing it to the token grid. Only two tables are used (linear-scaled and NTK-scaled, switched at scaling_watershed), and only the [:height_tokens, :width_tokens] part of each. Build both tables once per call on the latent token grid and move them to the device before the loop; the loop picks one of them as before. In LuminaPatchEmbed, slice freqs_cis to the token grid before .to(device). Add a test that checks the token-grid table equals the slice of the 384 x 384 table, on a square and a non-square grid, and gives the same transformer output, for linear and NTK factors 2.0 and 0.5 and the unscaled table. Bit-identical output at 1024x1024 (model card setting, scaling_factor 1.0, where the two tables are equal). With this and the previous commit, also bit-identical at 512x512 and 768x1024 with scaling_watershed=0.3, where the loop switches from the linear-scaled to the NTK-scaled table. Signed-off-by: Hsu, Chan Fu <ChanFu.Hsu@amd.com>
chsu-amd
marked this pull request as ready for review
November 12, 2026 03:46
This was referenced Nov 12, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Fixes #15251
Related: #13375 (pipeline DtoH syncs), #13401 (pipeline profiling), #13634 (Lumina review, different scope; see self-review notes). Lumina-Next-SFT (
LuminaPipeline+LuminaNextDiT2DModel) repeats avoidable work on every step. This PR removes it in two commits:LuminaAttnProcessor2_0: stop expanding the(batch, 1, 1, kv_len)bool mask to(batch, heads, q_len, kv_len).F.scaled_dot_product_attentionbroadcasts the mask.LuminaPatchEmbed: slicefreqs_cisto the token grid before.to(device).LuminaPipeline: build the linear-scaled and NTK-scaled RoPE tables once per call on the latent token grid and move them to the device before the denoising loop, instead of building a 384 x 384 table on CPU every step and moving all of it. The loop only picks one of the two tables atscaling_watershed, as before.No new branches or flags. Output is bit-identical (0 differing values) at 1024x1024 (card setting) and at 512x512 and 768x1024 with
scaling_watershed=0.3, where the loop switches from the linear-scaled to the NTK-scaled table.LuminaFeedForward(shared with Lumina-Image-2.0) is changed separately (#15252).Full pipeline call, bf16, seconds, main vs this PR:
transformer.compile(fullgraph=True)Alpha-VLLM/Lumina-Next-SFT-diffusers, model card prompt and settings (from_pretrained(torch_dtype=torch.bfloat16).to("cuda"),__call__defaults: 1024x1024, 30 steps, guidance 4.0), CPU generator with a fixed seed. RTX 5090 (Windows), bf16, batch 1, default attention backend (SDPA viaLuminaAttnProcessor2_0), torch 2.14.1+cu130. AMD Radeon AI PRO R9700 (gfx1201): Linux, torch 2.16.0a0+rocm10.3, same settings.Method: installed diffusers 0.42.1, whose touched classes (
LuminaAttnProcessor2_0,LuminaPatchEmbed,LuminaPipeline) equal main 0905b66, with main's and this PR's functions alternated in one process. Each row is one process: 8 pairs (main first in every pair), median per side (mean of the 4th and 5th of 8 sorted times); the change was faster in 8 of 8 pairs in every row. 0 differing output values vs main for seeds 0, 1, 7 and in every pair. 0 graph breaks under compile.A plain timing script (seed 0, one process per checkout) is in #15251: 11.968 -> 10.001 s at the card setting, 0 differing values.
cudaStreamSynchronizecalls per pipeline call on RTX 5090 (eager, torch.profiler) with commit 2: 74 -> 46.Tests
Each commit adds the test for its own change in
tests/models/transformers/test_models_transformer_lumina.py(TestLuminaNextDiTBehavior, padded prompt mask, non-zerogateso the cross-attention and its mask are not hidden):test_attention_mask_broadcast_matches_expanded_maskchecks the transformer output with the broadcast mask against SDPA called with the mask expanded to(batch, heads, q_len, kv_len), bit for bit. It also checks that padded text tokens do not change the output, which fails if the mask is dropped from the SDPA call.test_rotary_table_on_token_grid_matches_384_tablechecks that the table built on the token grid equals the[:tokens, :tokens]slice of the 384 x 384 table, also on a non-square(tokens - 2, tokens)grid, and that the transformer output is the same with either, for linear and NTK factors 2.0 and 0.5 and the unscaled table. Its table asserts fail ifget_2d_rotary_pos_embed_luminareturns a grid table that is not the slice (checked by shifting it one row and one column, and by swapping height and width on the non-square grid).Both new tests check equivalence, so they should also pass on main (not run on main). The new pipeline code runs in the fast
TestLuminaPipelinetests (32x32, where both tables are equal). The pipeline's own height / width order and linear / NTK pick are covered only by the end-to-end runs withscaling_watershed=0.3above (768x1024 is the non-square one).From the checkout root, with that checkout's
srcfirst onPYTHONPATH:No failures on either side. The commit-1 tree alone also passes
TestLuminaNextDiTBehavioron CUDA and CPU.Self-review notes (
self-reviewskill)READY, no blocking issues.
ruff checkandruff format --check(ruff 0.9.10) pass on the changed files.utils/check_copies.pyandutils/check_dummies.pycould not be run cleanly on my Windows host: they fail on unmodified main too, with the same output as on this branch (103 copy inconsistencies in unrelated files such asloaders/lora_pipeline.py, anddummy_bitsandbytes_objects), none in the changed files; no# Copied fromblock covers the changed code. No dead code. Left as is:F.scaled_dot_product_attentionto compute the reference with the expanded mask; the real SDPA still runs.current_timestep[0] < scaling_watershed(device tensor vs float, already on main); not changed here.LuminaAttnProcessor2_0calls SDPA directly instead ofdispatch_attention_fn(lumina model/pipeline review #13634, Issue 6), and self-attention passes an all-ones mask instead ofNone.Before submitting
self-reviewskill on the diff?documentation guidelines, and
here are tips on formatting docstrings. (no user-facing change)
Who can review?
cc @yiyixuxu @dg845