Repository navigation
[WS1][Qwen-Image][CUDA] Final AdaLN output (final_adaln_out) - #538
Open
fusheng-ji wants to merge 3 commits into
Open
fusheng-ji wants to merge 3 commits into
fusheng-ji wants to merge 3 commits into
Conversation
Add the Qwen-Image Phase A `adaln_mod_projection` operator (RFC RL-Align#386): per-stream SiLU + Linear 3072->18432 with a fixed-order FP32 forward, compensated input gradients and ascending FP32 Neumaier parameter gradients, plus an independent CPU FP32 reference. Sources live under csrc/cuda/model_specific/qwenimage, rl_engine/backends/cuda/model_specific/qwenimage and rl_engine/reference/model_specific/qwenimage. Register the CUDA and CPU slots (other platforms fail closed), the native bindings, the WS1 operator spec/inputs and the build source, and add tests, evidence runners under benchmarks/models/qwenimage, and the operator page.
Add the Qwen-Image Phase A `final_adaln_out` operator (RFC RL-Align#386): image-stream final modulation, LayerNorm(eps 1e-6) with SiLU + Linear 3072->6144 `(scale, shift)`, reusing the fixed-order projection from `adaln_mod_projection` and adding a fixed-tree FP32 token reduction for the modulation parameter gradients. Register the CUDA and CPU slots (other platforms fail closed), the token-sum binding, the WS1 operator spec/inputs and the build source, and extend the tests, evidence runners and documentation to the final stream.
Accuracy, batch-invariance, workload, parameter-gradient, reuse survey (vLLM, SGLang, Megatron, Liger and flash-attention compositions), timing and regression evidence from a clean checkout of 55f83d2.
fusheng-ji
requested review from
Flink-ddd,
KJLdefeated,
bitborne,
inaniloquentee and
ryankert01
as code owners
October 11, 2026 01:47
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configuration
You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
13 tasks
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
RFC #386 WS1 row
final_adaln_out: the image-stream final modulationnorm_out:Forward and backward are implemented. The later 3072 → 64
proj_outbelongs tolatent_proj_gemmand is not included.adaln_mod_projection's fixed-order CUDA projection and backward ([WS1][Qwen-Image][CUDA] AdaLN modulation projection (adaln_mod_projection) #537) unchanged.aten.native_layer_normandnative_layer_norm_backward), run on FP32 input with a declared execution-dtype store. Both are per-row, so batching does not change them; the BI checks above confirm this.d_scaleandd_shiftare token sums, reduced by a new FP32 kernel (csrc/cuda/model_specific/qwenimage/token_sum.cu) that applies fixed 32-way balanced trees recursively until one value remains. The tree depends only on the sequence length, not on B or batch position.qwenimage_final_adaln_out(CUDA only, no fallback; CPU maps to the reference; ROCm/NPU/MUSA fail closed), plus the WS1 operator spec/inputs, binding, build source anddocs/operators/qwenimage-final-adaln-out.md.benchmarks/models/qwenimage/streams.py), plus two reuse-survey modes for the LayerNorm part: Liger and flash-attention.Placement follows #537:
model_specific/qwenimage/.Prior art & reuse decision
Each candidate composes an existing batch-invariant projection with an existing LayerNorm, and is measured on the full forward and backward path with the checkpoint's
norm_out.linearweights. BI is checked bytewise: a singleton vs every row of B = 64/257/2048, three seeds, dense and boundary batch sweeps, the 4096-sample workload in 5 chunkings, and B = 2 vs B = 1 at S = 31/32/33/4096/6889/6032.F.layer_norm+F.linear(cuBLAS), torch 2.13.0+cu130--mode native --phase bi: 581/816 records failbatch_invariant.py@7797b60GEMM +F.layer_norm--mode vllm_local: 4/816 fail (long sequences)d_weight40,442 elements over tolerance at S=6889CUBLAS_WORKSPACE_CONFIG=:16:8,CUBLASLT_WORKSPACE_SIZE=1batch_invariant_ops.py, sglang 0.5.21batch_invariant_kernels.py@52fbcbcliger_kernel/ops/layer_norm.py, liger-kernel 0.8.4, with the vLLM GEMMd_weight40,459 elements over tolerance at S=6889flash_attn/ops/triton/layer_norm.py@94e22c9(Triton, with backward), with the vLLM GEMMd_weight40,442 elements over tolerance at S=6889flashinfer/norm/__init__.py@34bb66efused_dit_residual_layernorm_scale_shift(+ gated variants)0b55a2f: examples only (e.g.37_gemm_layernorm_gemm_fusion)1d367a4/05bd9cb/b9ecdf5:git grep -iE 'img_mod|txt_mod|AdaLayerNormContinuous|adaln'→ no filesAdaLayerNormContinuousinnormalization.py@d961a38All five batch-invariant compositions also exceed the BF16 tolerance on
d_weight/d_bias:At FP32 B = 2048 they fail by 70–75 elements. In these compositions, the modulation backward and its token sums run through native autograd; this operator accumulates those sums in a fixed FP32 tree and passes every case.
Final stream, forward + backward median ms:
F.layer_normDecision: write our own. No existing implementation is both batch-invariant and within the declared tolerances:
The operator is slower than these candidates at large conditioning batches; the projection reuse question in #537 applies to its projection part as well.
Results
Measured at
55f83d2b9043f41dca84440d9002ca30f5d3fac4. The evidence commit adds onlydocs/usage/evidence/qwenimage-final-adaln-out-b200/.fixed/acceptance.json is qualified with zero failures (all three streams are revalidated at this commit):
Accuracy (strict FP64 acceptance; this operator vs the BI compositions):

Batch invariance:

Performance (all candidates; and this operator vs native PyTorch at B=1):


At B=1, S=6889 (BF16) the operator takes 0.979 ms forward + backward vs 0.802 ms for native PyTorch. Peak memory is 605.5 MiB vs 350.4 MiB, because the operator keeps FP32 normalization state. Environment: B200 (SM100), PyTorch 2.13.0+cu130, CUDA 13.0, driver 580.126.20, TF32 off, no fast-math. Full evidence, pins and reproduction: README.
Status
No known failures at
efeb3b9d57668371a2bb394ae3d49a5c3e794af3. Evidence was produced from a clean checkout of the code commit55f83d2b9043f41dca84440d9002ca30f5d3fac4, which is this PR's parent of the evidence commit. Stacked on #537; review that first.Tests
135 passed, 0 failed, 0 skipped on 2× B200 (log). That is 101 from #537 and 34 added here. The added tests cover:
(scale, shift)order and LayerNorm.Scope / Known limitations
norm_outonly;proj_outbelongs tolatent_proj_gemm. First-order autograd only. Long token counts and large batches are covered separately, not every B×S combination.