Skip to main content
Diffusion transformers and VAEs spend a large share of their non-GEMM time on short elementwise and selection chains — adaLN modulate, residual gating, QK-norm, RoPE, norm epilogues, and MoE routing — each of which can require several kernel launches and HBM round trips in eager PyTorch. SGLang Diffusion replaces these chains with fused kernels under sglang/kernels/ops/diffusion. This page is an inventory: what each kernel fuses, what its numerical contract is, and which models use it. It is not a lever you tune — most of these kernels are on by default and require no flag. The one switch is --quality, described below.

Numerical contracts and quality tiers

Multi-step denoising amplifies a per-step rounding difference into visible quality loss, so “close enough” and “bit-exact” are different products here. The quality switch distinguishes unconditional bit-exact replacements from non-bit-exact eager-chain fusions: Bit-exact — mounted unconditionally. The kernel reproduces every rounding boundary of the eager chain, so torch.equal holds against the reference. Some go quite far to get there: the fused LayerNorm+modulate kernel replicates PyTorch’s vectorized_layer_norm_kernel down to its Welford update order, guarded reciprocal, and warp-fold tree; the fused RMSNorm+scale/shift kernel replicates FlashInfer’s CuTe-DSL RMSNormKernel fragment order and shfl.bfly fold. Because the dispatch they replicate can change underneath them, each one still verifies itself against the live eager chain on first sight and falls back permanently on any mismatch. Not bit-exact — request-gated. These differ from eager only at half-precision rounding-order level, but that is enough to matter, so they are mounted only for quality="extra-high" and quality="high" requests, at batch boundaries, all-or-nothing per transformer. The default quality="lossless" runs the unmodified reference chain. Model/checkpoint-native. Generic close-contract kernels, sparse operators, and FP8/NVFP4 producers can be part of a model implementation or a separately selected deployment path. They are documented in the inventory, but quality does not select or undo those choices. Selection-equivalent routing — enabled unconditionally. LingBot Video’s fused group-limited top-k returns the same selected expert-id set as its guarded CUDA torch.topk(..., sorted=False) reference chain. The order of those ids is not part of either path’s contract. Because the selected experts are unchanged, this path does not depend on the request quality tier.
A plain fp32 single-pass norm fusion looks harmless and is not. On ERNIE-Image it moved the 50-step trajectory to 18.83 dB PSNR, which is what motivated the bit-exact rewrite of that path.
The quality levels are cumulative: If a model has no eligible request-gated fusion, extra-high can execute the same path as lossless. Likewise, high adds only the model-specific high-only paths that the active pipeline implements.
quality is not a master precision switch. A quantized checkpoint, an explicitly selected approximate attention backend, or an independently enabled cache remains active at every quality tier.

Enabling the request-gated set

The server default stays lossless; the OpenAI-compatible endpoints carry it per request. Images:
Video, same field:
The quality field in a video response body is unrelated. It is Sora-compatible response metadata and is always reported as "standard"; it does not reflect the sampling quality the request ran with.
quality participates in the dynamic-batch signature, so mixed-quality traffic is batched separately and the transition happens safely at a batch boundary. Mounting is all-or-nothing: if any marked site on a transformer fails its static guards, no site on that transformer is fused.
Do not combine request-gated DiT fusions with --enable-breakable-cuda-graph. BCG warmup captures the lossless module branches before an extra-high or high request mounts its DiT fusions, so replay would bypass the requested kernels. SGLang rejects this combination for models with eligible DiT quality sites. Models whose request-gated path changes only VAE decode remain allowed because BCG captures the DiT only.
These fusion families mount under both quality="extra-high" and quality="high":

Kernel inventory

45 operators are registered in the kernel registry across 51 implementations (some operators carry several backends). Backends are named by provenance, not device: KDA identifies Kernel Design Agents implementations, JIT compiles under nvcc and hipcc, TRITON identifies Triton sources, CUTE_DSL needs CUTLASS, FLYDSL is ROCm gfx950 only, and AOT comes from the sgl_kernel wheel. Per-operator capability metadata determines which devices can load each implementation.

Normalization

adaLN modulation and gating

temb_table_slices is worth knowing about. The eager (scale_shift_table + temb.float()).chunk(6, dim=2) materializes roughly 8 GB of fp32 at 704p/121f and hands six strided slices downstream, whose .contiguous() calls then copy each one again. The fused kernel produces the six slices in one pass, each naturally contiguous, so the downstream copies become no-ops.

RoPE and QK-norm

Activation

Attention

MoE routing

Data movement

Every kernel here only moves values (plus zero fill, plus at most one same-order add), so each is bitwise identical to the aten chain it replaces.

Quantized layout producers

These kernels preserve the quantized checkpoint path’s selected reference operation. They are not a claim that FP8 or NVFP4 is equivalent to an unquantized BF16 checkpoint.

Coverage by model

Kernels are written against a specific eager chain in a specific model, so coverage is per-model rather than universal.

Inspecting what is registered

Every kernel is described by a KernelSpec in the process-wide registry, so the inventory is queryable without importing any backend:
Registration is metadata only — it imports neither torch nor a backend and triggers no JIT build. To pick a specific implementation of an operator that has several:

Importing the kernels

Runtime code imports from the package, never from a submodule:
Resolution is lazy: the backends have disjoint, heavy dependencies (Triton, CUTLASS/CuTe-DSL, and FlyDSL on ROCm), so an eager re-export would make every one of them an import-time requirement on every platform. Each public kernel is a predicate-plus-kernel pair — call can_use_<op>(...) first and fall back to the reference chain when it returns False; the kernel raises on an unsupported input rather than silently returning None. The package README.md carries a selection matrix for the cases where several kernels look interchangeable and are not. The normalization domain alone holds more than a dozen implementations that differ by numerical contract, activation layout, and backend rather than by speed.

References