Repository navigation
Conversation
adaln_segmented(x, scale, shift, split, eps, rms_weight, rms_weight_offset) computes norm(x) * (1 + scale[i]) + shift[i] for x [B, L, D], with modulation row i = 0 for the tokens before split and i = 1 from split on, and gated_residual_segmented(residual, x, gate, split) computes residual + x * gate[i] the same way, out of place or (gated_residual_segmented_) in place into residual. This is the reference-token (index_timestep_zero) modulation of Qwen-Image (_modulate / _apply_gate), Krea2 (SingleStreamBlock.forward) and Flux / Flux.2 (apply_mod with modulation_dims), which ComfyUI runs as a norm followed by in-place updates of per-segment slices. The norm is LayerNorm without affine (Qwen-Image, Flux) or, with rms_weight given, the fp32 RMSNorm of Krea2 rounded to x's dtype. scale / shift / gate are [2, B, D] views (or [2, 1, D]), which each model gets from its modulation output without a copy. Public wrappers, torch.ops.comfy_kitchen custom ops with fake impls, and the eager backend as the reference: the Flux / Krea2 op order (the product rounded before the shift is added); Qwen-Image's addcmul rounds once and can differ by one rounding step. Signed-off-by: ChanFu, Hsu <ChanFu.Hsu@amd.com>
One program owns one token row and holds the whole row of D in registers (block_d = next_power_of_2(D), num_warps 8 from block_d 4096 up, else 4), so x is read once: the LayerNorm or RMSNorm statistics, the normalize, the optional RMSNorm weight and the scale / shift row of the token's segment are applied in fp32 and rounded once on the store. The gated residual kernel stores residual + x * gate[i] the same way, into a new tensor or in place into residual. The segment rows are read through their own batch strides, so the [2, B, D] modulation views are not copied. This launch was the fastest or within 3% of the fastest of the configs tried (a two-pass loop over 1024 / 2048-column chunks, num_warps autotuning) at every captured shape on the RTX 5090 and the Radeon 8060S; the gate kernel is not autotuned because autotuning re-runs an in-place launch. The Triton backend takes fp16 / bf16 / fp32 x with modulation of the same dtype, [2, B, D] or [2, 1, D], and D up to 8192; x and residual need unit stride on D and are made contiguous otherwise, except that an in-place residual without it goes to eager. Empty inputs go to eager. Signed-off-by: ChanFu, Hsu <ChanFu.Hsu@amd.com>
Signed-off-by: ChanFu, Hsu <ChanFu.Hsu@amd.com>
…ding in the docstrings The public docstrings said x * gate and the RMSNorm output are rounded to the activation dtype, which is what the eager backend does; the triton backend computes in fp32 and rounds once. State both. Signed-off-by: ChanFu, Hsu <ChanFu.Hsu@amd.com>
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
Tip 🎯 Customize your risk assessments
✅ Automatic approvals, with your rules
|
One op per PR: gated_residual_segmented and gated_residual_segmented_ (public wrappers, eager custom ops and constraints, the Triton kernel, its call rules and the tests) move to a separate PR. adaln_segmented is unchanged. Signed-off-by: ChanFu, Hsu <ChanFu.Hsu@amd.com>
Format the lines this branch adds (new files in full; only the added ranges in files that are not format-clean on main). Signed-off-by: ChanFu, Hsu <ChanFu.Hsu@amd.com>
Comment-only change; the speedups and timings stay in the PR description. Signed-off-by: ChanFu, Hsu <ChanFu.Hsu@amd.com>
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.
Adds
ck.adaln_segmented(x, scale, shift, split, eps=1e-6, rms_weight=None, rms_weight_offset=0.0)for the reference-token (index_timestep_zero) modulation of image-edit DiTs, where the tokens before a split index are modulated with one set of scale / shift rows and the reference-image tokens after it with another. It computesnorm(x) * (1 + scale[i]) + shift[i]for x[B, L, D], withi = 0for tokens[0, split)andi = 1for[split, L). The norm is LayerNorm without affine, or, withrms_weightgiven, an fp32 RMSNorm with weightrms_weight + rms_weight_offsetrounded to x's dtype after the norm (Krea2 stores its RMSNorm scale zero-centered, offset 1.0).scale/shiftare[2, B, D](or[2, 1, D]), any strides on the first two dims, which each model gets from its modulation output as a view: Fluxscale.transpose(0, 1)of[B, 2, D], Qwen-Image and Krea2scale.unflatten(0, (2, -1))of[2B, D].In ComfyUI this runs as a norm followed by in-place updates of per-segment slices, each a separate kernel reading and writing the full activation, before the attention and the MLP of every block of every step:
_modulate(comfy/ldm/qwen_image/model.py):F.layer_norm, thentorch.addcmulper segment andtorch.cat.SingleStreamBlock.forward(comfy/ldm/krea2/model.py): fp32RMSNorm,.to(dtype), thenmul_(1 + scale).add_(shift)per segment.modulated_normwithmodulation_dims(comfy/ldm/flux/layers.py): withmodulation_dimsset,modulated_normskipsck.adalnand runslayer_norm, then*=/+=per segment.The segmented gated residual after the attention / MLP of the same blocks (
gated_residual_segmented) is in a separate PR: #310.t * (1 + scale)rounded to x's dtype before the shift is added); it equals those two paths exactly. Qwen-Image'saddcmulrounds once, so it can differ from eager by one rounding step.block_d = next_power_of_2(D),num_warps8 fromblock_d4096 up, else 4), so x is read once; the norm statistics, the normalize, the optional RMSNorm weight and the scale / shift row of the token's segment are applied in fp32 and rounded once on the store. Segment rows are read through their own batch strides, so the[2, B, D]views are not copied. fp16 / bf16 / fp32 x with modulation of the same dtype and D up to 8192; x needs unit stride on D and is made contiguous otherwise, and empty inputs run eager. This launch was the fastest or within 3% of the fastest of the configs tried (a two-pass loop over 1024 / 2048-column chunks,num_warpsautotuning) at every captured shape on the RTX 5090 and the Radeon 8060S.Speedup over ComfyUI's current path, bf16, per call through the public op (so the op's host-side dispatch is included), at the shapes captured from real runs: Krea2
(1, 8414, 6144)split 4270, Qwen-Image(1, 12336, 3072)split 4096, Flux.2 Klein 9B double / single blocks(1, 12168, 4096)split 4056 and(1, 12680, 4096)split 4568 on the first step,(1, 4056, 4096)/(1, 4568, 4096)after the KV cache step. Times are from the first of two pairs, the speedup is given for both pairs. Every call was served by triton, and at every shape the max and mean error against an fp32 reference are no larger than the current path's:Environment: RTX 5090 on Windows (torch 2.14.1+cu130, triton-windows 3.9.0, Python 3.12.16); Radeon 8060S (RDNA3.5) on Windows (ROCm torch 2.15.0a0+rocm10.1.0a20260907, HIP 7.16, triton-windows 3.8.0, Python 3.12.10).
Tests and benchmarks on 53fe266 on both GPUs (the head 076094d after it only edits comments), with prebuilt extensions copied into the source tree:
test_adaln_segmented.py33,test_backends.py12,test_constraints.py42 passed on the RTX 5090 (CUDA extension from the 0.2.41 wheel); the same on the Radeon 8060S (HIP extension only), excepttest_constraints.py40 passed / 2 skipped (CUDA-only).Not covered yet: end to end in ComfyUI, on either GPU. ComfyUI integration (Qwen-Image, Krea2, Flux / Flux.2 call sites) is a separate PR; ComfyUI keeps comfy-kitchen's triton backend off unless the server is started with
--enable-triton-backend.