Repository navigation
[diffusion] Ideogram 4: fuse RMSNorm modulate/gate chains via the Z-Image Triton suite behind quality=high (H200 e2e -2.9%/-3.4%) - #33822
Merged
Conversation
…iton suite behind quality=high (H200 1024^2 e2e: FAST_20 8.482 -> 8.239 s, INSTANT_8 3.488 -> 3.371 s) Ideogram 4's transformer block is form-identical to Z-Image's modulate/gate structure (adaptation-matrix audit @ 407a65d): per block, two `x + tanh(gate) * RMSNorm(out)` gate chains and two `RMSNorm(x) * (1 + scale)` modulate chains, x 34 blocks x 20 (V4_FAST) / 8 (V4_INSTANT) steps. The in-tree Z-Image Triton kernels (`zimage_rmsnorm_tanh_residual` / `zimage_rmsnorm_scale`) fuse each chain into one kernel; no new kernels. Z-Image mounts them unconditionally because they bit-match its native-bf16 reference RMSNorm. Ideogram's reference norm is F.rms_norm (fp32 internal statistics), so the fused path is close but not bit-exact (probed max abs diff 0.0625 at real shapes). Following the fused_linear_gelu precedent (sgl-project#33536), a mount/unmount site protocol gates the fusion to quality="high" batches; the "lossless" default keeps the reference chain byte-for-byte (full-image md5 identical to main for both presets). - kernels/ops/diffusion/fused_gate_rmsnorm.py: mark/mount/unmount site protocol + thin wrappers around the Z-Image kernels (all-or-nothing static guards: bf16 1-D norm weight, hidden <= 8192, Triton available). - dits/ideogram.py: the four per-block chains route through _norm_scale / _gate_residual helpers -- fused when mounted, torch.compiler.is_compiling() escape hatch, per-call fallback; reference expressions unchanged (operator-level torch.equal + e2e md5 vs main). - stages/denoising.py: _maybe_toggle_fused_gelu generalized to _maybe_toggle_quality_fusions; same batch-boundary toggle now handles both quality=high fusion families. H200, cocktailpeanut/ideogram-4-fp8 (byte-identical ungated mirror of the gated ideogram-ai/ideogram-4-fp8), 1024x1024, seed 42, 10 runs drop-first median (sgl-project#33451 protocol): - V4_FAST_20: e2e 8.482 -> 8.239 s (-2.9%), denoise 8259 -> 7977 ms (-3.4%) - V4_INSTANT_8: e2e 3.488 -> 3.371 s (-3.4%), denoise 3243 -> 3118 ms (-3.9%) - quality=high vs lossless PSNR 37.9-58.1 dB, SSIM >= 0.998 (2 prompts x 2 presets) - kernel microbench: gate chain 3.1-3.3x, modulate chain 2.0-2.3x Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
BBuf
requested review from
AgainstEntropy,
HaiShaw,
mickqian,
ping1jing2,
yichiche and
yingluosanqian
as code owners
August 6, 2026 06:01
Collaborator
Author
|
/rerun-failed-ci |
Collaborator
Author
saturn-acc
pushed a commit
to saturn-acc/sglang
that referenced
this pull request
Aug 16, 2026
…mage Triton suite behind quality=high (H200 e2e -2.9%/-3.4%) (sgl-project#33822) Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Atituiset
pushed a commit
to Atituiset/sglang
that referenced
this pull request
Sep 10, 2026
…mage Triton suite behind quality=high (H200 e2e -2.9%/-3.4%) (sgl-project#33822) Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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.
Reuses the Z-Image bf16-native norm kernels already in-tree (
kernels/ops/diffusion/triton/zimage_native_norm.py) — no new kernels; adds the mount/unmount site protocol for them (same shape as #33536'sfused_linear_gelu). 4 files, +283/−28.Motivation
The adaptation-matrix audit (main @ 407a65d) flagged Ideogram 4's transformer block as form-identical to Z-Image's modulate/gate structure, for which a fused Triton suite already ships on Z-Image's default path:
x + tanh(gate) * RMSNorm(out)— 2 sites/block x 34 blocks = 68 sites/step; eager = tanh + RMSNorm + mul + add over the[tokens, 4608]stream.RMSNorm(x) * (1 + scale)— 2 sites/block x 34 blocks; eager = RMSNorm + add + mul.At V4_FAST_20 (guidance 1.0, single forward per step) that is 1,360 gate + 1,360 modulate eager chains per 1024x1024 image; V4_INSTANT_8 has 544 + 544.
zimage_rmsnorm_tanh_residual/zimage_rmsnorm_scalefuse each chain into one kernel.Why quality=high and not the lossless default
Z-Image mounts these kernels unconditionally because they reproduce its own native-bf16 reference RMSNorm by design. Ideogram's reference norm is
F.rms_norm(fp32 internal statistics), so on Ideogram the fused path is close but not bit-exact — probed at real shapes ([1, 4096..4736, 4608], bf16): max abs diff 0.0625, i.e. bf16 rounding of the norm statistics. Following the #33536 precedent (and the same disposition as the FLUX.1 GELU gate in #33819), the sites are mounted only forquality="high"requests; the"lossless"default runs the unmodified reference chain byte-for-byte (md5 proof below).Modifications
kernels/ops/diffusion/fused_gate_rmsnorm.py(new) — mount/unmount site protocol for the existing Z-Image Triton kernels, mirroringfused_linear_gelu:mark_fused_gate_rmsnorm_site(module, norm_attrs), all-or-nothingmount_fused_gate_rmsnormwith static guards (bf16 1-D norm weight, hidden <= 8192 kernel limit, Triton available),unmount_...resets to the bit-exact reference. Thinfused_rmsnorm_scale/fused_rmsnorm_tanh_residualwrappers re-export the kernels, which keep their own runtime shape/stride/dtype guards and returnNoneto fall back per call.runtime/models/dits/ideogram.py— the four per-block chains route through_norm_scale/_gate_residualhelpers: fused when the site is mounted,torch.compiler.is_compiling()escape hatch (compiled graphs never bake in the Triton path), eager fallback otherwise. The reference expressions are unchanged from main (verifiedtorch.equalat operator level and md5-identical e2e). The kernels consume the raw adaln.chunk()slices directly (strided-gate support is native), so no extra copies.runtime/pipelines_core/stages/denoising.py—_maybe_toggle_fused_gelugeneralized to_maybe_toggle_quality_fusions: the same batch-boundary toggle now mounts/unmounts both quality=high fusion families (cublasLt linear+GELU and gate-RMSNorm). Models without marked sites are no-ops, exactly as before; log-confirmed on Ideogram:Mounted fused gate RMSNorm (Z-Image Triton suite) for quality=high.Speed Tests (H200)
cocktailpeanut/ideogram-4-fp8— byte-layout-identical ungated mirror ofideogram-ai/ideogram-4-fp8(official repo and bothfal/ideogram-v4-*distilled repos are HF-gated) — 1024x1024, fixed prompt,seed=42, guidance 1.0 presets (single DiT forward per step). Client wall-clock in one warmed process, 10 consecutive generations, first dropped, median of 9 (#33451/#33536/#33734 protocol), single H200 (CUDA_VISIBLE_DEVICES=7).main @ 604d356 single-shot sanity anchors agree with the lossless arm within noise (FAST_20 8.548 s / denoise 8219 ms; INSTANT_8 3.498 s / denoise 3224 ms), as they must — the lossless path is byte-identical (below).
Attribution closes against kernel microbenchmarks at the real shapes (bf16, 200 iters after warmup, H200):
Summed over sites: ~223 us/block x 34 blocks ≈ 7.6 ms/step ≈ 152 ms per FAST_20 image from the four chains alone; measured denoise delta is 282 ms (the fused calls also drop the standalone per-block
tanhlaunches and their sync/launch overhead at 2.4 it/s). Per-step saving is preset-independent (~14 ms/step), so the few-step INSTANT preset shows the larger relative win.Benchmark configuration
All arms above run the default eager configuration (
performance_mode=auto; every archived server log showsenable_torch_compile: false, regional_compile: false) — i.e. the default production path for this model. Runs with--enable-torch-compileare unaffected: the fused helpers step aside viatorch.compiler.is_compiling()and the reference chain runs under Inductor.Benchmark driver (local mode, one warmed process; 10 sequential requests, first dropped, median of 9):
Accuracy Tests
torch.equal, real shapesTruea742d0b0...FAST_20 p0 on both)quality=high vs lossless, same seed, full-image:
All comfortably above the quality="high" bar (PSNR > 25); the typography prompt — Ideogram's signature use case — is essentially indistinguishable.
Side-by-side samples (lossless left, quality=high right, FAST_20):
fox photo

typography poster

Unit tests (new
test_fused_gate_rmsnorm.py,base-b-kernel-unit, mirrorstest_fused_linear_gelu.py): fused vsF.rms_normreference at the Ideogram hidden size incl. adaln-strided chunk gates; mount all-or-nothing guard (one fp32 site rejects the whole model); unmount restores the reference. Existingtest_zimage_native_norm.pyuntouched and passing (8/8 across both files on H200).🤖 Generated with Claude Code
CI States
Latest PR Test (Base): ❌ Run #31075920352
Latest PR Test (Extra): ❌ Run #31075922438