[Diffusion] Add cumulative extra-high quality tier (#37422)

This commit is contained in:
Xiaoyu Zhang
2026-09-02 10:26:13 +08:00
committed by GitHub
parent 26f760d5c0
commit 1aa8299d1d
34 changed files with 449 additions and 215 deletions
@@ -84,7 +84,7 @@ Send this MessagePack map immediately after the WebSocket opens.
| `num_inference_steps` | integer | No | Denoising steps per chunk. LingBot defaults to `4` when omitted. | | `num_inference_steps` | integer | No | Denoising steps per chunk. LingBot defaults to `4` when omitted. |
| `guidance_scale` | number | No | Classifier-free guidance scale. Realtime LingBot commonly uses `1`. | | `guidance_scale` | number | No | Classifier-free guidance scale. Realtime LingBot commonly uses `1`. |
| `negative_prompt` | string | No | Negative prompt passed to the diffusion pipeline. | | `negative_prompt` | string | No | Negative prompt passed to the diffusion pipeline. |
| `quality` | `"lossless"`, `"high"` | No | `lossless` keeps FP32 VAE decode. `high` uses the validated BF16 decode path for lower per-chunk latency. | | `quality` | `"lossless"`, `"extra-high"`, `"high"` | No | `lossless` keeps FP32 VAE decode. `extra-high` keeps FP32 decode and enables only any eligible request-gated kernel fusions. `high` includes those fusions and uses the validated BF16 decode path for lower per-chunk latency. |
| `max_chunks` | integer | No | Stop after this many chunks. Omit for a continuous session. | | `max_chunks` | integer | No | Stop after this many chunks. Omit for a continuous session. |
| `realtime_causal_sink_size` | integer | No | Number of sink frames/tokens retained in the causal attention window. | | `realtime_causal_sink_size` | integer | No | Number of sink frames/tokens retained in the causal attention window. |
| `realtime_causal_kv_cache_num_frames` | integer | No | Number of recent frames retained in the causal KV cache window. | | `realtime_causal_kv_cache_num_frames` | integer | No | Number of recent frames retained in the causal KV cache window. |
@@ -79,7 +79,7 @@ Send this MessagePack map immediately after the WebSocket opens.
| `num_inference_steps` | integer | No | Denoising steps per chunk. LingBot defaults to `4` when omitted. | | `num_inference_steps` | integer | No | Denoising steps per chunk. LingBot defaults to `4` when omitted. |
| `guidance_scale` | number | No | Classifier-free guidance scale. Realtime LingBot commonly uses `1`. | | `guidance_scale` | number | No | Classifier-free guidance scale. Realtime LingBot commonly uses `1`. |
| `negative_prompt` | string | No | Negative prompt passed to the diffusion pipeline. | | `negative_prompt` | string | No | Negative prompt passed to the diffusion pipeline. |
| `quality` | `"lossless"`, `"high"` | No | `lossless` keeps FP32 VAE decode. `high` uses the validated BF16 decode path for lower per-chunk latency. | | `quality` | `"lossless"`, `"extra-high"`, `"high"` | No | `lossless` keeps FP32 VAE decode. `extra-high` keeps FP32 decode and enables only any eligible request-gated kernel fusions. `high` includes those fusions and uses the validated BF16 decode path for lower per-chunk latency. |
| `max_chunks` | integer | No | Stop after this many chunks. Omit for a continuous session. | | `max_chunks` | integer | No | Stop after this many chunks. Omit for a continuous session. |
| `realtime_causal_sink_size` | integer | No | Number of sink frames/tokens retained in the causal attention window. | | `realtime_causal_sink_size` | integer | No | Number of sink frames/tokens retained in the causal attention window. |
| `realtime_causal_kv_cache_num_frames` | integer | No | Number of recent frames retained in the causal KV cache window. | | `realtime_causal_kv_cache_num_frames` | integer | No | Number of recent frames retained in the causal KV cache window. |
+25 -6
View File
@@ -673,17 +673,22 @@ done
### Choose the quality level ### Choose the quality level
`quality` is a request-scoped sampling parameter with two validated levels: `quality` is a cumulative request-scoped optimization parameter with three
levels:
- `"lossless"` (default): the exact reference path. Output is bit-exact - `"lossless"` (default): the exact reference path. Output is bit-exact
against the reference implementation and the CI ground truth. against the reference implementation and the CI ground truth.
- `"extra-high"`: includes the global fusion-only tier but does not enable
Cache-DiT or another approximate optimization. MiniMax-H3 currently has no
request-gated fusion site, so its denoise path is the same as `lossless`.
- `"high"`: the audited accelerated path. Quality is guaranteed (the audited - `"high"`: the audited accelerated path. Quality is guaranteed (the audited
Cache-DiT configuration measures SSIM 0.931 / PSNR 28.16 dB against Cache-DiT configuration measures SSIM 0.931 / PSNR 28.16 dB against
`lossless`), but output is no longer bit-identical to the reference. `lossless`), but output is no longer bit-identical to the reference.
One resident server serves both levels; a `quality: "high"` request mounts One resident server serves all three levels; a `quality: "high"` request
its audited Cache-DiT policy at the batch boundary, and a later mounts its audited Cache-DiT policy at the batch boundary, and a later
`quality: "lossless"` request removes the hooks before denoising. `quality: "lossless"` or `quality: "extra-high"` request removes the hooks
before denoising.
Start the validated server once: Start the validated server once:
@@ -720,6 +725,19 @@ omitting the field is equivalent.
</Tab> </Tab>
<Tab title="extra-high">
The global fusion-only tier. It does not enable MiniMax-H3 Cache-DiT and
currently follows the same H3 denoise path as `lossless`.
```json Request field
{
"quality": "extra-high"
}
```
</Tab>
<Tab title="high"> <Tab title="high">
The audited accelerated path. Use it when you can trade bit-exactness for The audited accelerated path. Use it when you can trade bit-exactness for
@@ -740,6 +758,7 @@ The measured trade-off is:
| `quality` | Mean <br />inference <br />latency | Speedup | SSIM vs <br />lossless | PSNR vs <br />lossless | Expected <br />trade-off | | `quality` | Mean <br />inference <br />latency | Speedup | SSIM vs <br />lossless | PSNR vs <br />lossless | Expected <br />trade-off |
| --- | ---: | ---: | ---: | ---: | --- | | --- | ---: | ---: | ---: | ---: | --- |
| `lossless` | 75.10 s | 1.00× | 1.000 | exact | Native reference path | | `lossless` | 75.10 s | 1.00× | 1.000 | exact | Native reference path |
| `extra-high` | Not separately measured | — | Same H3 denoise path | Same H3 denoise path | Fusion-only tier; no H3-specific request-gated site yet |
| `high` | 53.70 s | 1.40× | 0.931 | 28.16 dB | Smallest same-seed visual change | | `high` | 53.70 s | 1.40× | 0.931 | 28.16 dB | Smallest same-seed visual change |
These numbers use 1344×768, 124-frame, 24 fps T2VA with 50 inference steps, These numbers use 1344×768, 124-frame, 24 fps T2VA with 50 inference steps,
@@ -766,8 +785,8 @@ name, for example `sglang generate --quality high`.
For manually tuned Cache-DiT experiments outside that validated path, omit For manually tuned Cache-DiT experiments outside that validated path, omit
the request `quality` field and set `--enable-cache-dit` or the the request `quality` field and set `--enable-cache-dit` or the
process-wide `SGLANG_CACHE_DIT_*` defaults. An explicit `quality` process-wide `SGLANG_CACHE_DIT_*` defaults. Any explicit `quality`, including
(including `"lossless"`) takes H3 off the generic Cache-DiT path. The `"lossless"` and `"extra-high"`, takes H3 off the generic Cache-DiT path. The
24 GB layerwise recipe above can use the same switch; skipped blocks are 24 GB layerwise recipe above can use the same switch; skipped blocks are
not streamed. not streamed.
+12 -12
View File
@@ -64,7 +64,7 @@ sglang serve \
--port 30010 --port 30010
``` ```
For request and response examples, see [OpenAI-Compatible API](./openai_api). For request and response examples, see [OpenAI-Compatible API](/docs/sglang-diffusion/api/openai_api).
<Tip> <Tip>
Use `sglang generate --help` and `sglang serve --help` for the full argument list. The CLI help output is the source of truth for exhaustive flags. Use `sglang generate --help` and `sglang serve --help` for the full argument list. The CLI help output is the source of truth for exhaustive flags.
@@ -97,16 +97,16 @@ Use `sglang generate --help` and `sglang serve --help` for the full argument lis
- `--warmup-mode {off|request|server}`: control startup warmup for `sglang serve`; `off` skips warmup, `request` primes the request path, and `server` runs a full synthetic server warmup before serving traffic - `--warmup-mode {off|request|server}`: control startup warmup for `sglang serve`; `off` skips warmup, `request` primes the request path, and `server` runs a full synthetic server warmup before serving traffic
- `--enable-torch-compile {true|false}`: compile native diffusion hot paths. When no warmup mode is configured, this also enables server warmup so first real requests do not pay compile latency. - `--enable-torch-compile {true|false}`: compile native diffusion hot paths. When no warmup mode is configured, this also enables server warmup so first real requests do not pay compile latency.
- `--offload-during-compile {true|false}`: when compile warmup is active, temporarily layerwise-offload DiT weights and move resident non-DiT components off-device so `max-autotune` fits on tighter-memory GPUs; the configured serving residency is restored before real traffic. Skipped under existing layerwise offload, Cache-DiT, or FSDP. - `--offload-during-compile {true|false}`: when compile warmup is active, temporarily layerwise-offload DiT weights and move resident non-DiT components off-device so `max-autotune` fits on tighter-memory GPUs; the configured serving residency is restored before real traffic. Skipped under existing layerwise offload, Cache-DiT, or FSDP.
- `--enable-breakable-cuda-graph {true|false}`: capture supported DiT forwards as breakable CUDA graph segments to reduce launch overhead. Requires `--warmup-resolutions` for every served resolution because each resolution is captured separately. A `quality=high` request is rejected when it would mount request-scoped DiT fusions that were not present during lossless graph capture; VAE-only high-quality paths remain compatible. - `--enable-breakable-cuda-graph {true|false}`: capture supported DiT forwards as breakable CUDA graph segments to reduce launch overhead. Requires `--warmup-resolutions` for every served resolution because each resolution is captured separately. An `extra-high` or `high` request is rejected when it would mount request-scoped DiT fusions that were not present during lossless graph capture; VAE-only request-gated paths remain compatible.
- `--bcg-text-buckets {N...}`: prompt-length padding buckets for breakable CUDA graph capture/replay reuse. - `--bcg-text-buckets {N...}`: prompt-length padding buckets for breakable CUDA graph capture/replay reuse.
- `--attention-backend {BACKEND}`: attention backend for native SGLang and diffusers pipelines - `--attention-backend {BACKEND}`: attention backend for native SGLang and diffusers pipelines
- `--component-attention-backends {MAP}`: per-component attention backend overrides, for example `text_encoder=torch_sdpa,transformer=fa` - `--component-attention-backends {MAP}`: per-component attention backend overrides, for example `text_encoder=torch_sdpa,transformer=fa`
- `--attention-backend-config {CONFIG}`: attention backend configuration - `--attention-backend-config {CONFIG}`: attention backend configuration
- `--srt-encoder-url {HTTPADDRESS}`: address of SGLang srt server with AR model for GLM-Image like models. See [Models with AR Stage](../models_with_ar). - `--srt-encoder-url {HTTPADDRESS}`: address of SGLang srt server with AR model for GLM-Image like models. See [Models with AR Stage](/docs/sglang-diffusion/models_with_ar).
- `--srt-encoder-timeout {SECONDS}`: Timeout in seconds for HTTP requests to the SGLang encoder server - `--srt-encoder-timeout {SECONDS}`: Timeout in seconds for HTTP requests to the SGLang encoder server
- `--srt-encoder-connection-timeout {SECONDS}`: TCP connection timeout in seconds for SGLang encoder server - `--srt-encoder-connection-timeout {SECONDS}`: TCP connection timeout in seconds for SGLang encoder server
- `--scheduler-rpc-timeout {SECONDS}`: optional end-to-end deadline for an internal scheduler RPC, including scheduler queue time. It is unset by default so valid long-running and queued video jobs are not failed by the transport layer. Set it only when the deployment requires a bounded request deadline; caller cancellation and server shutdown remain effective without it. - `--scheduler-rpc-timeout {SECONDS}`: optional end-to-end deadline for an internal scheduler RPC, including scheduler queue time. It is unset by default so valid long-running and queued video jobs are not failed by the transport layer. Set it only when the deployment requires a bounded request deadline; caller cancellation and server shutdown remain effective without it.
- `--pe-server-url {HTTPADDRESS}`: url of SGLang server hosting the PE model (e.g., for ERNIE-Image). See [Models with Prompt Enhancement](../models_with_pe). - `--pe-server-url {HTTPADDRESS}`: url of SGLang server hosting the PE model (e.g., for ERNIE-Image). See [Models with Prompt Enhancement](/docs/sglang-diffusion/models_with_pe).
### Sampling and output ### Sampling and output
@@ -114,11 +114,11 @@ Use `sglang generate --help` and `sglang serve --help` for the full argument lis
- `--image-path {PATH} [{PATH} ...]`: input image(s) for image-to-video or image-to-image generation - `--image-path {PATH} [{PATH} ...]`: input image(s) for image-to-video or image-to-image generation
- `--num-inference-steps {STEPS}` and `--seed {SEED}` - `--num-inference-steps {STEPS}` and `--seed {SEED}`
- `--num-outputs-per-prompt {N}` / `--num-outputs {N}`: generate multiple outputs for each prompt. A scalar seed expands as `seed + output_index`. - `--num-outputs-per-prompt {N}` / `--num-outputs {N}`: generate multiple outputs for each prompt. A scalar seed expands as `seed + output_index`.
- `--quality {lossless,high}`: request-level quality. `lossless` (default) keeps the exact reference path, bit-exact against the reference implementation; `high` opts into the model-owned validated accelerated path, whose quality stays guaranteed but is not bit-exact. Support and validated deployment constraints are model-specific. - `--quality {lossless,extra-high,high}`: cumulative request-level optimization tier. `lossless` (default) keeps the selected deployment's reference path and all unconditional bit-exact replacements. `extra-high` adds only request-gated DiT/VAE kernel fusions; the tier does not itself enable sparse, caching, or other approximate paths. `high` includes the complete `extra-high` set and may also enable model-owned approximate optimizations. Separately configured quantization, attention, or caching options still apply. Support and validation constraints are model-specific.
- `--height {HEIGHT}`, `--width {WIDTH}`, `--num-frames {N}`, `--fps {FPS}` - `--height {HEIGHT}`, `--width {WIDTH}`, `--num-frames {N}`, `--fps {FPS}`
- `--output-path {PATH}`, `--output-file-name {NAME}`, `--save-output`, `--return-frames` - `--output-path {PATH}`, `--output-file-name {NAME}`, `--save-output`, `--return-frames`
For frame interpolation and upscaling, see [Post-Processing](./post_processing). For frame interpolation and upscaling, see [Post-Processing](/docs/sglang-diffusion/api/post_processing).
### Quantization ### Quantization
@@ -162,7 +162,7 @@ The same contract applies to every weighted component: path routing is generic,
while quantized materialization is capability-based. Native auxiliary loaders while quantized materialization is capability-based. Native auxiliary loaders
whose current materializer expects plain state dicts reject unsupported whose current materializer expects plain state dicts reject unsupported
quantization metadata before model construction. See quantization metadata before model construction. See
[Quantized Component Repositories](../quantization#quantized-component-repositories) [Quantized Component Repositories](/docs/sglang-diffusion/quantization#quantized-component-repositories)
for the current component matrix. A model cookbook is the source of truth for for the current component matrix. A model cookbook is the source of truth for
published, model-specific checkpoint examples; for example, all H3 sources and published, model-specific checkpoint examples; for example, all H3 sources and
their exact overlays are kept in one their exact overlays are kept in one
@@ -191,8 +191,8 @@ For supported realtime causal video models, `--kv-cache-quant {off|int4|int2}`
compresses completed KV-cache chunks independently of transformer weight compresses completed KV-cache chunks independently of transformer weight
quantization. It is lossy and disabled by default. quantization. It is lossy and disabled by default.
See [Realtime and Causal Video Models](../realtime_models) for the runtime and See [Realtime and Causal Video Models](/docs/sglang-diffusion/realtime_models) for the runtime and
model scope, and [Quantization](../quantization) for supported quantization model scope, and [Quantization](/docs/sglang-diffusion/quantization) for supported quantization
families and examples. families and examples.
### Request logging ### Request logging
@@ -263,7 +263,7 @@ sglang generate \
HTTP server-only arguments are ignored by `sglang generate`. HTTP server-only arguments are ignored by `sglang generate`.
</Note> </Note>
For supported native pipelines, set `SGLANG_CACHE_DIT_ENABLED=true` to enable Cache-DiT. It can run with DiT layerwise offload; it cannot run with FSDP. For the diffusers backend, use `--backend diffusers --cache-dit-config ...`. See [Cache-DiT](../cache_dit). For supported native pipelines, set `SGLANG_CACHE_DIT_ENABLED=true` to enable Cache-DiT. It can run with DiT layerwise offload; it cannot run with FSDP. For the diffusers backend, use `--backend diffusers --cache-dit-config ...`. See [Cache-DiT](/docs/sglang-diffusion/cache_dit).
For supported image pipelines, breakable CUDA graph can be enabled with `--enable-breakable-cuda-graph`, but you must declare every served resolution in `--warmup-resolutions` so warmup captures matching graph signatures. For supported image pipelines, breakable CUDA graph can be enabled with `--enable-breakable-cuda-graph`, but you must declare every served resolution in `--warmup-resolutions` so warmup captures matching graph signatures.
@@ -394,7 +394,7 @@ export SGLANG_S3_SECRET_ACCESS_KEY=your-secret-key
export SGLANG_S3_ENDPOINT_URL=https://minio.example.com export SGLANG_S3_ENDPOINT_URL=https://minio.example.com
``` ```
See [Environment Variables](../environment_variables) for the full set of storage options. See [Environment Variables](/docs/sglang-diffusion/environment_variables) for the full set of storage options.
## Component Path Overrides ## Component Path Overrides
@@ -416,7 +416,7 @@ selected loader must support that serialized format. Native plain-state loaders
fail closed; library-managed components inherit the corresponding Transformers fail closed; library-managed components inherit the corresponding Transformers
or Diffusers support. The transformer-specific `--quantization` flag does not or Diffusers support. The transformer-specific `--quantization` flag does not
select the format of component checkpoints; their own metadata does. See select the format of component checkpoints; their own metadata does. See
[Quantized Component Repositories](../quantization#quantized-component-repositories). [Quantized Component Repositories](/docs/sglang-diffusion/quantization#quantized-component-repositories).
## Component Attention Backend Overrides ## Component Attention Backend Overrides
@@ -129,7 +129,7 @@ The server implements an OpenAI-compatible Images API under the `/v1/images` nam
#### Request quality #### Request quality
`quality` selects a model-owned sampling level when that model advertises one: use `lossless` for the reference path or `high` for a validated accelerated path. Omit it (or send OpenAI's default `auto`) to keep the runtime default. It is distinct from `output_quality`, which controls only output-file compression. The same extension is accepted by image edits and video requests. `quality` selects a cumulative request-level optimization tier: `lossless` keeps the selected deployment's reference path and all unconditional bit-exact replacements; `extra-high` additionally enables only request-gated DiT/VAE kernel fusions; `high` includes the full `extra-high` set and may also enable model-owned sparse, caching, lower-precision, or other approximate paths. The tier does not override separately configured quantization, attention, or caching options. Omit it (or send OpenAI's default `auto`) to keep the `lossless` runtime default. It is distinct from `output_quality`, which controls only output-file compression. The same extension is accepted by image edits and video requests.
**Python Example (b64_json response):** **Python Example (b64_json response):**
+58 -23
View File
@@ -8,22 +8,38 @@ Diffusion transformers and VAEs spend a large share of their non-GEMM time on sh
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. 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.
## Two numerical contracts ## 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. Every kernel in the package falls into one of two classes. 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. **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="high"` requests, at batch boundaries, all-or-nothing per transformer. The default `quality="lossless"` runs the unmodified reference chain. **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.
<Note> <Note>
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 at `quality=high`, which is what motivated the bit-exact rewrite of that path. 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.
</Note>
The quality levels are cumulative:
| `quality` | Included optimization set |
| --- | --- |
| `lossless` | The selected deployment's reference path plus every unconditional bit-exact replacement |
| `extra-high` | Everything in `lossless`, plus request-gated DiT and VAE kernel fusions; this level does not itself enable sparse, caching, or another approximate path |
| `high` | Everything in `extra-high`, plus any model-owned high-only optimization, such as an audited Cache-DiT policy or lower-precision VAE decode |
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.
<Note>
`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.
</Note> </Note>
## Enabling the request-gated set ## Enabling the request-gated set
```bash ```bash
sglang generate --model-path MODEL_PATH --prompt "..." --quality high sglang generate --model-path MODEL_PATH --prompt "..." --quality extra-high
``` ```
The server default stays `lossless`; the OpenAI-compatible endpoints carry it per request. Images: The server default stays `lossless`; the OpenAI-compatible endpoints carry it per request. Images:
@@ -31,7 +47,7 @@ The server default stays `lossless`; the OpenAI-compatible endpoints carry it pe
```bash ```bash
curl -X POST http://${HOST}:${PORT}/v1/images/generations \ curl -X POST http://${HOST}:${PORT}/v1/images/generations \
-H 'Content-Type: application/json' \ -H 'Content-Type: application/json' \
-d '{"model": "MODEL_PATH", "prompt": "...", "quality": "high"}' -d '{"model": "MODEL_PATH", "prompt": "...", "quality": "extra-high"}'
``` ```
Video, same field: Video, same field:
@@ -39,7 +55,7 @@ Video, same field:
```bash ```bash
curl -X POST http://${HOST}:${PORT}/v1/videos \ curl -X POST http://${HOST}:${PORT}/v1/videos \
-H 'Content-Type: application/json' \ -H 'Content-Type: application/json' \
-d '{"model": "MODEL_PATH", "prompt": "...", "quality": "high"}' -d '{"model": "MODEL_PATH", "prompt": "...", "quality": "extra-high"}'
``` ```
<Warning> <Warning>
@@ -50,28 +66,33 @@ The `quality` field in a **video response** body is unrelated. It is Sora-compat
<Warning> <Warning>
Do not combine request-gated DiT fusions with `--enable-breakable-cuda-graph`. Do not combine request-gated DiT fusions with `--enable-breakable-cuda-graph`.
BCG warmup captures the lossless module branches before a high-quality request BCG warmup captures the lossless module branches before an `extra-high` or
mounts its DiT fusions, so replay would bypass the requested kernels. SGLang `high` request mounts its DiT fusions, so replay would bypass the requested
rejects this combination for models with eligible DiT quality sites. Models kernels. SGLang rejects this combination for models with eligible DiT quality
whose high-quality path changes only VAE decode remain allowed because BCG sites. Models whose request-gated path changes only VAE decode remain allowed
captures the DiT only. because BCG captures the DiT only.
</Warning> </Warning>
These fusion families mount under `quality="high"`: These fusion families mount under both `quality="extra-high"` and
`quality="high"`:
| Fusion | What it folds | | Fusion | What it folds |
| --- | --- | | --- | --- |
| Linear + tanh-GELU | Bias-add and GELU into the GEMM epilogue (cublasLt), removing the `[tokens, 4*dim]` intermediate round trip | | Linear + tanh-GELU | Bias-add and GELU into the GEMM epilogue (cublasLt), removing the `[tokens, 4*dim]` intermediate round trip |
| Wan NVFP4 linear + GELU | Bias-add and GELU fused into Wan's NVFP4 FFN projection output |
| Qwen-Image added-QKV | Added Q/K/V projections fused into joint-buffer production |
| LayerNorm + modulate | `layer_norm(x, weight=(1 + scale), bias=shift)` in place of affine-free LN plus a separate modulate | | LayerNorm + modulate | `layer_norm(x, weight=(1 + scale), bias=shift)` in place of affine-free LN plus a separate modulate |
| LTX-2 RMSNorm + modulate | `rms_norm(x) * (1 + scale) + shift` in one launch | | LTX-2 RMSNorm + modulate | `rms_norm(x) * (1 + scale) + shift` in one launch |
| Gate RMSNorm (BF16-native) | `RMSNorm + tanh + mul + add` in one pass | | Gate RMSNorm (BF16-native) | `RMSNorm + tanh + mul + add` in one pass |
| HunyuanVideo strided QK RMSNorm | Per-head QK RMSNorm over the packed QKV layout | | HunyuanVideo strided QK RMSNorm | Per-head QK RMSNorm over the packed QKV layout |
| LingBot Video fused RMSNorm | Replaces the handwritten cast, square, mean, rsqrt, and multiply chain with existing Triton RMSNorm kernels | | LingBot Video fused RMSNorm | Replaces the handwritten cast, square, mean, rsqrt, and multiply chain with existing Triton RMSNorm kernels |
| SANA-Video BF16-input linear attention | Keeps the first linear-attention GEMM's inputs in BF16 with FP32 accumulation/output; the second GEMM remains FP32 | | SANA-Video BF16-input linear attention | Keeps the first linear-attention GEMM's inputs in BF16 with FP32 accumulation/output; the second GEMM remains FP32 |
| FLUX-family VAE fast paths | Channels-last decode, GroupNorm(+SiLU), upsample, and attention replacements for FLUX.2 and AutoencoderKL-based FLUX.1, Z-Image, and SD3 pipelines |
| Wan VAE RMSNorm + SiLU | Replaces the channel-first RMSNorm/SiLU chain while keeping the decode in `channels_last_3d` |
## Kernel inventory ## Kernel inventory
34 operators are registered in the kernel registry across 38 implementations (some operators carry several backends). Backends are named by provenance, not device: `JIT` compiles under nvcc *and* hipcc, `TRITON` runs on CUDA and ROCm, `CUTE_DSL` needs CUTLASS, `FLYDSL` is ROCm gfx950 only, `AOT` comes from the `sgl_kernel` wheel. 43 operators are registered in the kernel registry across 47 implementations (some operators carry several backends). Backends are named by provenance, not device: `JIT` compiles under nvcc *and* hipcc, `TRITON` runs on CUDA and ROCm, `CUTE_DSL` needs CUTLASS, `FLYDSL` is ROCm gfx950 only, `AOT` comes from the `sgl_kernel` wheel.
### Normalization ### Normalization
@@ -79,6 +100,7 @@ These fusion families mount under `quality="high"`:
| --- | --- | --- | --- | | --- | --- | --- | --- |
| `rmsnorm_scale_shift` | Triton | bit-exact | RMSNorm + `* (1 + scale) + shift` (4 kernels) | | `rmsnorm_scale_shift` | Triton | bit-exact | RMSNorm + `* (1 + scale) + shift` (4 kernels) |
| `scale_residual_norm_scale_shift` | Triton / CuTe-DSL / FlyDSL | bit-exact (Triton) | the above plus the preceding `residual + gate * update` | | `scale_residual_norm_scale_shift` | Triton / CuTe-DSL / FlyDSL | bit-exact (Triton) | the above plus the preceding `residual + gate * update` |
| `scale_residual_norm_scale_shift_nvfp4` | JIT CUDA | matches the selected NVFP4 producer contract | Qwen residual LayerNorm/modulation + FC1 NVFP4 quantization |
| `layernorm_modulate` | Triton | bit-exact | affine-free LayerNorm + adaLN modulate | | `layernorm_modulate` | Triton | bit-exact | affine-free LayerNorm + adaLN modulate |
| `qk_head_layernorm` | Triton | bit-exact | per-head LayerNorm on q/k | | `qk_head_layernorm` | Triton | bit-exact | per-head LayerNorm on q/k |
| `qk_rmsnorm_native` | Triton | bit-exact | Z-Image per-head QK RMSNorm | | `qk_rmsnorm_native` | Triton | bit-exact | Z-Image per-head QK RMSNorm |
@@ -107,8 +129,11 @@ These fusion families mount under `quality="high"`:
| Operator | Backend | Contract | Replaces | | Operator | Backend | Contract | Replaces |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| `fused_inplace_qknorm_rope` | JIT CUDA | one bf16 rounding step vs the split baseline; exact with `round_norm_before_rope=True` | separate QK-norm kernel + RoPE | | `fused_inplace_qknorm_rope` | JIT CUDA | one bf16 rounding step vs the split baseline; exact with `round_norm_before_rope=True` | separate QK-norm kernel + RoPE |
| `flux2_qkv_epilogue` | JIT CUDA | bit-exact against its selected BF16 reference chain | FLUX.2 QK RMSNorm + RoPE + joint text/image QKV packing |
| `qwen_qkv_epilogue` | JIT CUDA | bit-exact against its selected BF16 reference chain | Qwen-Image QK RMSNorm + RoPE + joint QKV writes on SM100+ |
| `rope_rotate_half` | Triton | bit-exact | `chunk` → `cat(-x2, x1)` → two muls + add → `cat(tail)`, about 7 kernels per projection | | `rope_rotate_half` | Triton | bit-exact | `chunk` → `cat(-x2, x1)` → two muls + add → `cat(tail)`, about 7 kernels per projection |
| `interleaved_rope_fp64` | JIT CUDA | bit-exact | paired SANA-Video Q/K RoPE with fp64 tables, about 14 eager kernels | | `interleaved_rope_fp64` | JIT CUDA | bit-exact | paired SANA-Video Q/K RoPE with fp64 tables, about 14 eager kernels |
| `helios_qk_rope` | JIT CUDA | bit-exact | paired in-place Helios Q/K RoPE with transposed frequency layout |
| `ltx2_qknorm_split_rope` | JIT CUDA | close (validated on B200) | LTX-2 QK-norm + split RoPE | | `ltx2_qknorm_split_rope` | JIT CUDA | close (validated on B200) | LTX-2 QK-norm + split RoPE |
| `ltx25_decoder_rope` | JIT CUDA | bit-exact | paired LTX-2.5 decoder 3D RoPE from cached compact axis tables | | `ltx25_decoder_rope` | JIT CUDA | bit-exact | paired LTX-2.5 decoder 3D RoPE from cached compact axis tables |
| `hunyuan_qkv_rope_pack` | Triton | bit-exact | QKV pack and RoPE in one pass | | `hunyuan_qkv_rope_pack` | Triton | bit-exact | QKV pack and RoPE in one pass |
@@ -137,10 +162,20 @@ Every kernel here only moves values (plus zero fill, plus at most one same-order
| `usp_merge_heads` | JIT CUDA | USP all-to-all output head merge (`permute` + `contiguous`) | | `usp_merge_heads` | JIT CUDA | USP all-to-all output head merge (`permute` + `contiguous`) |
| `pack_qkv_destination_major` | Triton | Ulysses destination-major QKV pack | | `pack_qkv_destination_major` | Triton | Ulysses destination-major QKV pack |
| `varlen_pack_qkv`, `varlen_scatter_to_padded` | Triton | varlen gather/scatter around the masked attention path | | `varlen_pack_qkv`, `varlen_scatter_to_padded` | Triton | varlen gather/scatter around the masked attention path |
| `varlen_pack_segmented_qkv` | Triton | varlen gather from a virtual prefix/main Q/K/V sequence |
| `causal_conv3d_cat_pad` | JIT CUDA / Triton | causal Conv3d `cat` + `pad` | | `causal_conv3d_cat_pad` | JIT CUDA / Triton | causal Conv3d `cat` + `pad` |
| `cat_pad_channels_last_3d` | Triton | Wan causal VAE `cat + F.pad + contiguous` (three passes plus cache bookkeeping) in one pass | | `cat_pad_channels_last_3d` | Triton | Wan causal VAE `cat + F.pad + contiguous` (three passes plus cache bookkeeping) in one pass |
| `dup_up3d_add` | Triton | `repeat_interleave + permute().contiguous() + add` | | `dup_up3d_add` | Triton | `repeat_interleave + permute().contiguous() + add` |
### 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.
| Operator | Backend | Replaces |
| --- | --- | --- |
| `flux2_token_cat_fp8` | Triton | FLUX.2 single-block attention/MLP concatenation plus static FP8 quantization |
| `flux2_token_cat_nvfp4` | JIT CUDA | FLUX.2 single-block attention/MLP concatenation plus NVFP4 quantization |
## Coverage by model ## Coverage by model
Kernels are written against a specific eager chain in a specific model, so coverage is per-model rather than universal. Kernels are written against a specific eager chain in a specific model, so coverage is per-model rather than universal.
@@ -148,18 +183,18 @@ Kernels are written against a specific eager chain in a specific model, so cover
| Model | Fused paths | | Model | Fused paths |
| --- | --- | | --- | --- |
| FLUX.1 | LN+modulate, modulate, residual-gate add, linear+GELU | | FLUX.1 | LN+modulate, modulate, residual-gate add, linear+GELU |
| FLUX.2 | LN+modulate, packed SwiGLU, residual-gate add | | FLUX.2 | LN+modulate, packed SwiGLU, gated residual/norm, residual-gate add, QK RMSNorm+RoPE+joint QKV packing, FP8/NVFP4 token-cat producers |
| Qwen-Image | linear+GELU, select-0/1 LN modulation | | Qwen-Image | linear+GELU, select-0/1 LN modulation, added-QKV fusion, QK RMSNorm+RoPE+joint QKV writes, residual norm/modulate+NVFP4 producer |
| GLM-Image | LN+modulate, per-head qk LN, residual-gate add, linear+GELU | | GLM-Image | LN+modulate, per-head qk LN, residual-gate add, linear+GELU |
| ERNIE-Image | RMSNorm+scale/shift, residual-gated variant, rotate-half RoPE, residual-gate add | | ERNIE-Image | RMSNorm+scale/shift, residual-gated variant, rotate-half RoPE, residual-gate add |
| Z-Image | BF16-native RMSNorm scale / tanh-residual, per-head QK RMSNorm | | Z-Image | BF16-native RMSNorm scale / tanh-residual, per-head QK RMSNorm |
| Ideogram 4 | gate RMSNorm, SwiGLU, rotate-half RoPE, modulate, residual-gate add | | Ideogram 4 | gate RMSNorm, SwiGLU, rotate-half RoPE, modulate, residual-gate add |
| LTX-2 | QK-norm + split RoPE, ada-values split, RMSNorm+modulate, modulate, residual-gate add, linear+GELU | | LTX-2 | QK-norm + split RoPE, ada-values split, RMSNorm+modulate, modulate, residual-gate add, linear+GELU |
| LTX-2.5 decoder | paired 3D RoPE with shared axis-table cache | | LTX-2.5 decoder | paired 3D RoPE with shared axis-table cache |
| HunyuanVideo | QKV+RoPE pack, strided QK RMSNorm, linear+GELU | | HunyuanVideo / Helios | QKV+RoPE pack, strided QK RMSNorm, linear+GELU; Helios also has paired in-place Q/K RoPE |
| LingBot Video MoE | Fused RMSNorm at `quality=high` | | LingBot Video MoE | Fused RMSNorm at `quality=extra-high` or `quality=high` |
| Sana | LN+modulate, GLUMB bias+SiLU / bias+GLU, residual-gate add | | Sana | LN+modulate, GLUMB bias+SiLU / bias+GLU, residual-gate add |
| SANA-Video | Packed QKV/KV; paired fp64 interleaved RoPE; LN+modulate, GLUMB bias+SiLU / bias+GLU, and residual-gate add during BCG; BF16-input linear attention at `quality=high` | | SANA-Video | Packed QKV/KV; paired fp64 interleaved RoPE; LN+modulate, GLUMB bias+SiLU / bias+GLU, and residual-gate add during BCG; BF16-input linear attention at `quality=extra-high` or `quality=high` |
| Sana-WM | bidirectional gated delta-net, fused QK inverse-RMS | | Sana-WM | bidirectional gated delta-net, fused QK inverse-RMS |
| Wan | temb table slices; VAE cat+pad and DupUp3D add, `channels_last_3d` RMSNorm+SiLU | | Wan | temb table slices; VAE cat+pad and DupUp3D add, `channels_last_3d` RMSNorm+SiLU |
| Cosmos3 / Krea2 / MiniMax-H3 | QK-norm + RoPE (Krea2 also CuTe-DSL norm+scale/shift; MiniMax-H3 also indexed modulation) | | Cosmos3 / Krea2 / MiniMax-H3 | QK-norm + RoPE (Krea2 also CuTe-DSL norm+scale/shift; MiniMax-H3 also indexed modulation) |
@@ -201,9 +236,9 @@ The package `README.md` carries a selection matrix for the cases where several k
## References ## References
- [Performance Optimization](./performance-optimization) - [Performance Optimization](/docs/sglang-diffusion/performance-optimization)
- [Attention Backends](./attention_backends) - [Attention Backends](/docs/sglang-diffusion/attention_backends)
- [Quantization](./quantization) - [Quantization](/docs/sglang-diffusion/quantization)
- [Profiling](./profiling) - [Profiling](/docs/sglang-diffusion/profiling)
- [`sglang/kernels/ops/diffusion`](https://github.com/sgl-project/sglang/tree/main/python/sglang/kernels/ops/diffusion) — source and selection matrix - [`sglang/kernels/ops/diffusion`](https://github.com/sgl-project/sglang/tree/main/python/sglang/kernels/ops/diffusion) — source and selection matrix
- [RFC #29630](https://github.com/sgl-project/sglang/issues/29630) — the unified `sglang.kernels` namespace - [RFC #29630](https://github.com/sgl-project/sglang/issues/29630) — the unified `sglang.kernels` namespace
@@ -12,11 +12,28 @@ The docs use "output-preserving" instead of promising bit-exact "lossless" becau
## Start Here ## Start Here
1. Pick a serving or generation mode from [Deployment and Performance Modes](./deployment_cookbook). `--performance-mode auto` is the default; use `speed` when the model fits in GPU memory and latency matters most, `memory` when GPU memory is the bottleneck, and `manual` when every performance flag should be explicit. 1. Pick a serving or generation mode from [Deployment and Performance Modes](/docs/sglang-diffusion/deployment_cookbook). `--performance-mode auto` is the default; use `speed` when the model fits in GPU memory and latency matters most, `memory` when GPU memory is the bottleneck, and `manual` when every performance flag should be explicit.
2. Choose the right attention backend from [Attention Backends](./attention_backends). 2. Choose the right attention backend from [Attention Backends](/docs/sglang-diffusion/attention_backends).
3. Use [Sequence Parallelism](./ring_sp_performance) only when the model and video shape benefit from sequence splitting. 3. Use [Sequence Parallelism](/docs/sglang-diffusion/ring_sp_performance) only when the model and video shape benefit from sequence splitting.
4. Use [Inference Batching](./dynamic_batching) for concurrent compatible requests during serving. 4. Use [Inference Batching](/docs/sglang-diffusion/dynamic_batching) for concurrent compatible requests during serving.
5. Use [Profiling](./profiling) before changing several levers at once. 5. Use [Profiling](/docs/sglang-diffusion/profiling) before changing several levers at once.
## Choose a request quality tier
`--quality` is cumulative: a broader tier never drops an optimization from a
stricter tier.
| Tier | Optimization boundary |
| --- | --- |
| `lossless` (default) | The selected deployment's reference execution plus all unconditional bit-exact replacements |
| `extra-high` | Everything in `lossless`, plus only request-gated DiT/VAE kernel fusions; the tier does not itself enable sparse, caching, or other approximate paths |
| `high` | Everything in `extra-high`, plus model-owned high-only paths such as an audited Cache-DiT policy or lower-precision VAE decode |
Use `extra-high` when you want to isolate fusion wins from approximate
acceleration. A tier may be a no-op when the active model has no eligible path.
Separately configured quantization, attention, or caching options still apply.
See [Fused Kernels](/docs/sglang-diffusion/fused_kernels) for the current
request-gated families and their numerical contracts.
## Output-Preserving / Lossless-Style Levers ## Output-Preserving / Lossless-Style Levers
@@ -39,42 +56,42 @@ These settings should preserve model behavior while changing residency, parallel
<tr> <tr>
<td style={{padding: "9px 12px", fontWeight: 500}}><code>--performance-mode</code></td> <td style={{padding: "9px 12px", fontWeight: 500}}><code>--performance-mode</code></td>
<td style={{padding: "9px 12px"}}>You want a safe preset for speed or memory without overriding explicit flags.</td> <td style={{padding: "9px 12px"}}>You want a safe preset for speed or memory without overriding explicit flags.</td>
<td style={{padding: "9px 12px"}}><a href="./deployment_cookbook">Deployment and Performance Modes</a></td> <td style={{padding: "9px 12px"}}><a href="/docs/sglang-diffusion/deployment_cookbook">Deployment and Performance Modes</a></td>
</tr> </tr>
<tr> <tr>
<td style={{padding: "9px 12px", fontWeight: 500}}>Breakable CUDA graph</td> <td style={{padding: "9px 12px", fontWeight: 500}}>Breakable CUDA graph</td>
<td style={{padding: "9px 12px"}}>A supported pipeline serves a fixed set of shapes and eager execution is launch-bound.</td> <td style={{padding: "9px 12px"}}>A supported pipeline serves a fixed set of shapes and eager execution is launch-bound.</td>
<td style={{padding: "9px 12px"}}><a href="./api/cli">CLI reference</a></td> <td style={{padding: "9px 12px"}}><a href="/docs/sglang-diffusion/api/cli">CLI reference</a></td>
</tr> </tr>
<tr> <tr>
<td style={{padding: "9px 12px", fontWeight: 500}}>Offload, FSDP, CFG parallelism</td> <td style={{padding: "9px 12px", fontWeight: 500}}>Offload, FSDP, CFG parallelism</td>
<td style={{padding: "9px 12px"}}>GPU memory, multi-GPU residency, or CFG branch splitting is the main bottleneck.</td> <td style={{padding: "9px 12px"}}>GPU memory, multi-GPU residency, or CFG branch splitting is the main bottleneck.</td>
<td style={{padding: "9px 12px"}}><a href="./deployment_cookbook">Deployment and Performance Modes</a></td> <td style={{padding: "9px 12px"}}><a href="/docs/sglang-diffusion/deployment_cookbook">Deployment and Performance Modes</a></td>
</tr> </tr>
<tr> <tr>
<td style={{padding: "9px 12px", fontWeight: 500}}>Sequence parallelism</td> <td style={{padding: "9px 12px", fontWeight: 500}}>Sequence parallelism</td>
<td style={{padding: "9px 12px"}}>Long image/video sequences need sequence-level parallelism.</td> <td style={{padding: "9px 12px"}}>Long image/video sequences need sequence-level parallelism.</td>
<td style={{padding: "9px 12px"}}><a href="./ring_sp_performance">Sequence Parallelism</a></td> <td style={{padding: "9px 12px"}}><a href="/docs/sglang-diffusion/ring_sp_performance">Sequence Parallelism</a></td>
</tr> </tr>
<tr> <tr>
<td style={{padding: "9px 12px", fontWeight: 500}}><code>--encoder-parallel</code></td> <td style={{padding: "9px 12px", fontWeight: 500}}><code>--encoder-parallel</code></td>
<td style={{padding: "9px 12px"}}>Text/image encoding is a visible share of the request and the DiT replica sits idle during it.</td> <td style={{padding: "9px 12px"}}>Text/image encoding is a visible share of the request and the DiT replica sits idle during it.</td>
<td style={{padding: "9px 12px"}}><a href="./encoder_parallel">Encoder Parallelism</a></td> <td style={{padding: "9px 12px"}}><a href="/docs/sglang-diffusion/encoder_parallel">Encoder Parallelism</a></td>
</tr> </tr>
<tr> <tr>
<td style={{padding: "9px 12px", fontWeight: 500}}>Attention backend</td> <td style={{padding: "9px 12px", fontWeight: 500}}>Attention backend</td>
<td style={{padding: "9px 12px"}}>Kernel choice dominates DiT latency or memory.</td> <td style={{padding: "9px 12px"}}>Kernel choice dominates DiT latency or memory.</td>
<td style={{padding: "9px 12px"}}><a href="./attention_backends">Attention Backends</a></td> <td style={{padding: "9px 12px"}}><a href="/docs/sglang-diffusion/attention_backends">Attention Backends</a></td>
</tr> </tr>
<tr> <tr>
<td style={{padding: "9px 12px", fontWeight: 500}}>Fused kernels</td> <td style={{padding: "9px 12px", fontWeight: 500}}>Fused kernels</td>
<td style={{padding: "9px 12px"}}>You want to know which elementwise chains are already fused, or to opt into the request-gated set.</td> <td style={{padding: "9px 12px"}}>You want to know which elementwise chains are already fused, or to opt into the request-gated set.</td>
<td style={{padding: "9px 12px"}}><a href="./fused_kernels">Fused Kernels</a></td> <td style={{padding: "9px 12px"}}><a href="/docs/sglang-diffusion/fused_kernels">Fused Kernels</a></td>
</tr> </tr>
<tr> <tr>
<td style={{padding: "9px 12px", fontWeight: 500}}>Dynamic batching</td> <td style={{padding: "9px 12px", fontWeight: 500}}>Dynamic batching</td>
<td style={{padding: "9px 12px"}}>Serving many compatible requests concurrently.</td> <td style={{padding: "9px 12px"}}>Serving many compatible requests concurrently.</td>
<td style={{padding: "9px 12px"}}><a href="./dynamic_batching">Inference Batching</a></td> <td style={{padding: "9px 12px"}}><a href="/docs/sglang-diffusion/dynamic_batching">Inference Batching</a></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
@@ -100,22 +117,22 @@ These techniques can change the denoising path, numerical representation, or gen
<tr> <tr>
<td style={{padding: "9px 12px", fontWeight: 500}}>Cache-DiT</td> <td style={{padding: "9px 12px", fontWeight: 500}}>Cache-DiT</td>
<td style={{padding: "9px 12px"}}>Skips selected DiT block or step computation based on cache decisions.</td> <td style={{padding: "9px 12px"}}>Skips selected DiT block or step computation based on cache decisions.</td>
<td style={{padding: "9px 12px"}}><a href="./cache_dit">Cache-DiT</a></td> <td style={{padding: "9px 12px"}}><a href="/docs/sglang-diffusion/cache_dit">Cache-DiT</a></td>
</tr> </tr>
<tr> <tr>
<td style={{padding: "9px 12px", fontWeight: 500}}>TeaCache</td> <td style={{padding: "9px 12px", fontWeight: 500}}>TeaCache</td>
<td style={{padding: "9px 12px"}}>Reuses residuals when consecutive denoising steps are similar enough.</td> <td style={{padding: "9px 12px"}}>Reuses residuals when consecutive denoising steps are similar enough.</td>
<td style={{padding: "9px 12px"}}><a href="./teacache">TeaCache</a></td> <td style={{padding: "9px 12px"}}><a href="/docs/sglang-diffusion/teacache">TeaCache</a></td>
</tr> </tr>
<tr> <tr>
<td style={{padding: "9px 12px", fontWeight: 500}}>Progressive resolution</td> <td style={{padding: "9px 12px", fontWeight: 500}}>Progressive resolution</td>
<td style={{padding: "9px 12px"}}>Runs early denoising at lower latent resolution for supported pipelines.</td> <td style={{padding: "9px 12px"}}>Runs early denoising at lower latent resolution for supported pipelines.</td>
<td style={{padding: "9px 12px"}}><a href="./progressive_resolution">Progressive Resolution Generation</a></td> <td style={{padding: "9px 12px"}}><a href="/docs/sglang-diffusion/progressive_resolution">Progressive Resolution Generation</a></td>
</tr> </tr>
<tr> <tr>
<td style={{padding: "9px 12px", fontWeight: 500}}>Quantization</td> <td style={{padding: "9px 12px", fontWeight: 500}}>Quantization</td>
<td style={{padding: "9px 12px"}}>Uses lower-precision transformer weights or activations.</td> <td style={{padding: "9px 12px"}}>Uses lower-precision transformer weights or activations.</td>
<td style={{padding: "9px 12px"}}><a href="./quantization">Quantization</a></td> <td style={{padding: "9px 12px"}}><a href="/docs/sglang-diffusion/quantization">Quantization</a></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
@@ -124,20 +141,21 @@ These techniques can change the denoising path, numerical representation, or gen
1. Establish a baseline with the target model, resolution, frame count, step count, and GPU type. 1. Establish a baseline with the target model, resolution, frame count, step count, and GPU type.
2. Select `--performance-mode` and explicit residency or parallelism flags. 2. Select `--performance-mode` and explicit residency or parallelism flags.
3. Compare breakable CUDA graph against eager execution for supported fixed-shape pipelines. Pass every served resolution to `--warmup-resolutions` and confirm capture in the server log. 3. Compare `quality=lossless` with `quality=extra-high` to isolate the request-gated fusion set.
4. Tune attention backend and batching for the deployment pattern. 4. Compare breakable CUDA graph against eager execution for supported fixed-shape pipelines. Pass every served resolution to `--warmup-resolutions` and confirm capture in the server log. Models with request-gated DiT fusions cannot combine those fusions with a graph captured from the lossless branches.
5. Profile if the bottleneck is unclear. 5. Tune attention backend and batching for the deployment pattern.
6. Add caching, progressive resolution, or quantization only after comparing output quality against your acceptance target. 6. Profile if the bottleneck is unclear.
7. Add `quality=high`, caching, progressive resolution, or quantization only after comparing output quality against your acceptance target.
## Diagnostics ## Diagnostics
[Profiling](./profiling) is not an optimization technique by itself. It belongs in the performance workflow because it tells you which stage, kernel, or denoising step is worth optimizing before you change multiple levers. [Profiling](/docs/sglang-diffusion/profiling) is not an optimization technique by itself. It belongs in the performance workflow because it tells you which stage, kernel, or denoising step is worth optimizing before you change multiple levers.
## References ## References
- [Deployment and Performance Modes](./deployment_cookbook) - [Deployment and Performance Modes](/docs/sglang-diffusion/deployment_cookbook)
- [Attention Backends](./attention_backends) - [Attention Backends](/docs/sglang-diffusion/attention_backends)
- [Fused Kernels](./fused_kernels) - [Fused Kernels](/docs/sglang-diffusion/fused_kernels)
- [Sequence Parallelism](./ring_sp_performance) - [Sequence Parallelism](/docs/sglang-diffusion/ring_sp_performance)
- [Caching Strategies](./caching-acceleration) - [Caching Strategies](/docs/sglang-diffusion/caching-acceleration)
- [Profiling](./profiling) - [Profiling](/docs/sglang-diffusion/profiling)
@@ -486,7 +486,7 @@ return {
title: "Quality", title: "Quality",
scope: "request", scope: "request",
docsHref: "/docs/sglang-diffusion/cache_dit", docsHref: "/docs/sglang-diffusion/cache_dit",
description: "Reference execution or the audited Cache-DiT acceleration preset.", description: "Cumulative reference, fusion-only, or audited Cache-DiT execution.",
quality: "Sampling policy", quality: "Sampling policy",
learnMore: "#choose-the-quality-level", learnMore: "#choose-the-quality-level",
default: "lossless", default: "lossless",
@@ -497,6 +497,11 @@ return {
recommended: true, recommended: true,
description: "Reference-exact denoising without Cache-DiT approximation.", description: "Reference-exact denoising without Cache-DiT approximation.",
}, },
{
id: "extra-high",
label: "Extra high",
description: "Includes fusion-only request paths but not Cache-DiT; MiniMax-H3 currently follows its lossless denoise path at this tier.",
},
{ {
id: "high", id: "high",
label: "Audited high", label: "Audited high",
@@ -669,7 +674,7 @@ return {
|| (s.execution === "bcg" && ["b200", "h200"].includes(s.hw) && s.weights === "ref2va"); || (s.execution === "bcg" && ["b200", "h200"].includes(s.hw) && s.weights === "ref2va");
const serveVerified = topologyVerified && encoderVerified && attentionVerified const serveVerified = topologyVerified && encoderVerified && attentionVerified
&& precisionVerified && executionVerified; && precisionVerified && executionVerified;
const requestVerified = topologyVerified && (s.quality === "lossless" const requestVerified = topologyVerified && (["lossless", "extra-high"].includes(s.quality)
|| (s.quality === "high" && highAudited && s.execution === "eager")); || (s.quality === "high" && highAudited && s.execution === "eager"));
const topologyParts = []; const topologyParts = [];
+23 -10
View File
@@ -45,7 +45,7 @@ ext/ JIT C++/CUDA extensions (Hunyuan3D raster/inpaint) — NOT kernels
../../kda_kernels/ agent-generated implementations and their JIT CUDA sources ../../kda_kernels/ agent-generated implementations and their JIT CUDA sources
``` ```
## The two numerical contracts ## Numerical contracts and quality policy
**Bit-exact (`torch.equal` vs the eager chain) → mounted unconditionally.** **Bit-exact (`torch.equal` vs the eager chain) → mounted unconditionally.**
These kernels reproduce every aten rounding boundary, sometimes down to the These kernels reproduce every aten rounding boundary, sometimes down to the
@@ -59,11 +59,18 @@ themselves against the live eager chain on first sight via
dispatch they replicate can change under them. dispatch they replicate can change under them.
**Not bit-exact → quality-gated.** Mounted onto marked `nn.Module` sites only **Not bit-exact → quality-gated.** Mounted onto marked `nn.Module` sites only
for `quality="high"` requests, at batch boundaries, all-or-nothing per for `quality="extra-high"` and `quality="high"` requests, at batch boundaries,
transformer (`sites/quality_gate.py`). A plain fp32 single-pass norm fusion all-or-nothing per transformer (`sites/quality_gate.py`). `extra-high` adds
looks harmless and is not: on ERNIE-Image it moved the 50-step trajectory to only these request-gated DiT/VAE fusions; `high` is cumulative and may also
PSNR 18.83 dB at `quality=high`, which is what motivated the bit-exact enable model-owned approximate paths such as Cache-DiT or a lower-precision
rewrite. decode. A plain fp32 single-pass norm fusion looks harmless and is not: on
ERNIE-Image it moved the 50-step trajectory to PSNR 18.83 dB, which is what
motivated the bit-exact rewrite.
**Model/checkpoint-native.** Generic close-contract kernels, sparse operators,
and FP8/NVFP4 producers can belong to the selected model or deployment path.
The request `quality` tier neither selects nor disables those independent
choices.
SANA-Video's quality-gated linear-attention site keeps BF16 inputs for the SANA-Video's quality-gated linear-attention site keeps BF16 inputs for the
first GEMM while requesting FP32 accumulation/output, then runs the second first GEMM while requesting FP32 accumulation/output, then runs the second
@@ -98,6 +105,7 @@ Several norms look interchangeable and are not. Start here.
| `fused_layernorm_modulate` | Triton | bit-exact vs aten `vectorized_layer_norm` | bf16, `N % 4 == 0`, 16B-aligned | | `fused_layernorm_modulate` | Triton | bit-exact vs aten `vectorized_layer_norm` | bf16, `N % 4 == 0`, 16B-aligned |
| `fused_norm_scale_shift` / `fused_scale_residual_norm_scale_shift` | CuTe-DSL | fp32 statistics, close | fp16/bf16/fp32, LN or RMS, many broadcast modes | | `fused_norm_scale_shift` / `fused_scale_residual_norm_scale_shift` | CuTe-DSL | fp32 statistics, close | fp16/bf16/fp32, LN or RMS, many broadcast modes |
| `flydsl_norm_scale_shift` / `flydsl_fused_residual_norm_scale_shift` | FlyDSL | close | **ROCm gfx950 only** | | `flydsl_norm_scale_shift` / `flydsl_fused_residual_norm_scale_shift` | FlyDSL | close | **ROCm gfx950 only** |
| `try_fused_scale_residual_norm_scale_shift_nvfp4` | JIT CUDA | matches the selected NVFP4 producer contract | Qwen residual LayerNorm/modulation + FC1 NVFP4 quantization |
| `fuse_layernorm_scale_shift_gate_select01_kernel` | Triton | close | per-token select between two modulation rows (Qwen-Image) | | `fuse_layernorm_scale_shift_gate_select01_kernel` | Triton | close | per-token select between two modulation rows (Qwen-Image) |
| `norm_infer` / `rms_norm_fn` | Triton (+torch/NPU/MPS fallbacks) | close | the generic entry point; use when nothing above fits | | `norm_infer` / `rms_norm_fn` | Triton (+torch/NPU/MPS fallbacks) | close | the generic entry point; use when nothing above fits |
@@ -131,6 +139,8 @@ tensor copy per residual site.
|---|---|---| |---|---|---|
| `fused_inplace_qknorm_rope` | JIT CUDA | one bf16 rounding step vs split baseline; `round_norm_before_rope=True` makes it exact; supports compact and full-width NeoX/interleaved caches | | `fused_inplace_qknorm_rope` | JIT CUDA | one bf16 rounding step vs split baseline; `round_norm_before_rope=True` makes it exact; supports compact and full-width NeoX/interleaved caches |
| `fused_qknorm_rope_pack_kv` | JIT CUDA | as above, also packs prefix K/V | | `fused_qknorm_rope_pack_kv` | JIT CUDA | as above, also packs prefix K/V |
| `try_fused_flux2_qkv_epilogue` | JIT CUDA | bit-exact vs the selected BF16 chain | FLUX.2 QK RMSNorm + RoPE + joint QKV packing |
| `try_fused_qwen_qkv_epilogue` | JIT CUDA | bit-exact vs the selected BF16 chain | Qwen-Image QK RMSNorm + RoPE + joint QKV writes; SM100+ |
| `fused_rope_rotate_half_bitexact` | Triton | bit-exact (elementwise only) | | `fused_rope_rotate_half_bitexact` | Triton | bit-exact (elementwise only) |
| `fused_interleaved_rope_fp64` | JIT CUDA | bit-exact vs paired SANA-Video fp64 RoPE | | `fused_interleaved_rope_fp64` | JIT CUDA | bit-exact vs paired SANA-Video fp64 RoPE |
| `fused_inplace_helios_qk_rope` | JIT CUDA | bit-exact paired in-place RoPE for Helios' transposed frequency layout | | `fused_inplace_helios_qk_rope` | JIT CUDA | bit-exact paired in-place RoPE for Helios' transposed frequency layout |
@@ -139,13 +149,16 @@ tensor copy per residual site.
| `apply_rotary_embedding` | Triton (+fallbacks) | close; the generic entry point | | `apply_rotary_embedding` | Triton (+fallbacks) | close; the generic entry point |
| `hunyuan_qkv_rope_pack` | Triton | bit-exact; packs QKV and applies RoPE in one pass | | `hunyuan_qkv_rope_pack` | Triton | bit-exact; packs QKV and applies RoPE in one pass |
### Data movement (all bit-exact by construction) ### Data movement and quantized layout producers
`usp_merge_heads`, `pack_qkv_destination_major`, `fused_pack_qkv`, `usp_merge_heads`, `pack_qkv_destination_major`, `fused_pack_qkv`,
`fused_pack_segmented_qkv`, `fused_scatter_to_padded`, `fused_pack_segmented_qkv`, `fused_scatter_to_padded`,
`fused_causal_conv3d_cat_pad_cuda`, `fused_causal_conv3d_cat_pad_cuda`,
`cat_pad_channels_last_3d`, `dup_up3d_add`, `fused_temb_table_slices`, `cat_pad_channels_last_3d`, `dup_up3d_add`, `fused_temb_table_slices`,
`ltx2_ada_values9`. and `ltx2_ada_values9` are bit-exact data movement or same-order arithmetic.
`try_flux2_token_cat_fp8` and `try_flux2_token_cat_nvfp4` fuse branch
concatenation directly into the quantized representation selected by the
FLUX.2 checkpoint path.
`fused_temb_table_slices` is worth knowing about: the eager `fused_temb_table_slices` is worth knowing about: the eager
`(table + temb.float()).chunk(6, dim=2)` materializes ~8 GB of fp32 at `(table + temb.float()).chunk(6, dim=2)` materializes ~8 GB of fp32 at
@@ -172,7 +185,7 @@ inspecting model modules is its whole job.
3. Give it a `can_use_*` predicate; raise, don't return `None`. 3. Give it a `can_use_*` predicate; raise, don't return `None`.
4. State the numerical contract in the module docstring, including which 4. State the numerical contract in the module docstring, including which
shapes it was verified on. shapes it was verified on.
5. If it is not bit-exact, gate it through `sites/`. Do not mount it by 5. If it is not bit-exact, gate it through `sites/`. It must mount for both
default. `extra-high` and `high`, never for the default `lossless` path.
6. Test it in the domain suite (`test/registered/kernels/ops/diffusion/`), and 6. Test it in the domain suite (`test/registered/kernels/ops/diffusion/`), and
the model wiring in `test_model_fast_paths.py`. the model wiring in `test_model_fast_paths.py`.
@@ -656,15 +656,17 @@ BCG validation must prove all of the following:
For a non-bit-exact optimization, integrate through the request-scoped site For a non-bit-exact optimization, integrate through the request-scoped site
framework under `sglang.kernels.ops.diffusion.sites`. Mark sites during model framework under `sglang.kernels.ops.diffusion.sites`. Mark sites during model
construction and let `QualityGatedFusion` mount them only for construction and let `QualityGatedFusion` mount them for both
`quality="high"`; `quality="lossless"` must keep the original code path. `quality="extra-high"` and `quality="high"`; `quality="lossless"` must keep
the original code path. A high-only sparse, caching, or other approximate
path must remain outside this fusion gate.
Eligibility must be all-or-nothing for coupled sites and fail closed on dtype, Eligibility must be all-or-nothing for coupled sites and fail closed on dtype,
shape, layout, backend, BCG, or compile incompatibility. Add clean site-level shape, layout, backend, BCG, or compile incompatibility. Add clean site-level
guard/parity tests and a model wiring test instead of embedding request-policy guard/parity tests and a model wiring test instead of embedding request-policy
branches throughout the DiT. branches throughout the DiT.
Finally, use the benchmark/profile skill's `--quality-bcg-matrix` to run Finally, use the benchmark/profile skill's `--quality-bcg-matrix` to run
same-GPU ABBA pairs for Eager/BCG at lossless/high. Report denoise and saved same-GPU ABBA pairs for Eager/BCG at lossless/extra-high/high. Report denoise and saved
request e2e separately, require at least 1.5% repeated mean e2e improvement for request e2e separately, require at least 1.5% repeated mean e2e improvement for
an optimization PR, attach profile and generated-media A/B evidence, then an optimization PR, attach profile and generated-media A/B evidence, then
delete the task-owned checkpoint cache and verify zero residual weight files delete the task-owned checkpoint cache and verify zero residual weight files
@@ -9,7 +9,7 @@ Use this skill when measuring denoise performance, finding the slow op, checking
This skill is diagnosis-first. It owns: This skill is diagnosis-first. It owns:
- checked-in denoise benchmark presets - checked-in denoise benchmark presets
- same-GPU quality/BCG applicability checks with repeated lossless and high rows - same-GPU quality/BCG applicability checks with repeated lossless, extra-high, and high rows
- perf dump collection and before/after comparison - perf dump collection and before/after comparison
- `torch.profiler` trace capture and quick hotspot ranking - `torch.profiler` trace capture and quick hotspot ranking
- mapping hot kernels back to known fast paths and fusion families - mapping hot kernels back to known fast paths and fusion families
@@ -65,7 +65,7 @@ Always rule out these existing families first:
- Z-Image bf16-native Triton RMSNorm scale/tanh-residual modulation - Z-Image bf16-native Triton RMSNorm scale/tanh-residual modulation
- SANA packed self-attention Q/K/V and cross-attention K/V GEMMs - SANA packed self-attention Q/K/V and cross-attention K/V GEMMs
- SANA-Video's packed projections and request-scoped BF16-input linear - SANA-Video's packed projections and request-scoped BF16-input linear
attention at `quality=high`; keep the second attention GEMM in FP32 and attention at `quality=extra-high` or `quality=high`; keep the second attention GEMM in FP32 and
compare against `quality=lossless` before changing its precision further compare against `quality=lossless` before changing its precision further
- SANA-Video reuse of SANA's bit-exact bias/activation, residual-gate, and - SANA-Video reuse of SANA's bit-exact bias/activation, residual-gate, and
LayerNorm-modulation fast paths before adding video-only kernels LayerNorm-modulation fast paths before adding video-only kernels
@@ -73,7 +73,7 @@ Always rule out these existing families first:
USP relayout, and batched TP AdaLN collectives USP relayout, and batched TP AdaLN collectives
- bit-exact diffusion adaLN modulation and fused LayerNorm + modulation for - bit-exact diffusion adaLN modulation and fused LayerNorm + modulation for
FLUX.1, GLM-Image, and SANA FLUX.1, GLM-Image, and SANA
- request-scoped `quality=high` DiT and VAE fast paths - request-scoped DiT and VAE fast paths at `quality=extra-high` or `quality=high`
- Wan causal-VAE cache/padding and DupUp3D data-movement fusions - Wan causal-VAE cache/padding and DupUp3D data-movement fusions
- fused diffusion `QK norm + RoPE` - fused diffusion `QK norm + RoPE`
- LTX2 split RoPE - LTX2 split RoPE
@@ -94,9 +94,9 @@ controlled comparator, never for the eager ground truth. The legacy
`--no-torch-compile` spelling remains accepted but is redundant. `--no-torch-compile` spelling remains accepted but is redundant.
For kernel/BCG discovery, run `--quality-bcg-matrix`. It executes Eager/BCG as For kernel/BCG discovery, run `--quality-bcg-matrix`. It executes Eager/BCG as
A-B-B-A at `lossless`, then repeats the pair at `high`, on one locked GPU set A-B-B-A at `lossless`, then repeats the pair at `extra-high` and `high`, on
and one isolated checkpoint cache. The high+BCG rows are applicability checks, one locked GPU set and one isolated checkpoint cache. The extra-high/high+BCG
not presumed-valid performance cells. A BCG row is invalid unless the log rows are applicability checks, not presumed-valid performance cells. A BCG row is invalid unless the log
contains `[Diffusion BCG] captured` and contains no support-disable, contains `[Diffusion BCG] captured` and contains no support-disable,
capture-failure, serving-signature-miss, or late quality-fusion marker. In capture-failure, serving-signature-miss, or late quality-fusion marker. In
particular, a request-scoped DiT fusion mounted after lossless warmup capture particular, a request-scoped DiT fusion mounted after lossless warmup capture
@@ -120,7 +120,7 @@ its normal cleanup finally block without modifying the seed cache.
Keep prompt, negative prompt, seed, shape, steps, guidance, dtype, topology, Keep prompt, negative prompt, seed, shape, steps, guidance, dtype, topology,
and residency fixed. Lossless comparisons require byte-identical artifacts. and residency fixed. Lossless comparisons require byte-identical artifacts.
For `quality=high`, report aggregate and worst-frame SSIM/PSNR; the repository For `quality=extra-high` and `quality=high`, report aggregate and worst-frame SSIM/PSNR; the repository
defaults are 0.95/28 dB for images and 0.92/24 dB for video unless the model's defaults are 0.95/28 dB for images and 0.92/24 dB for video unless the model's
checked-in consistency metadata defines a different threshold. A performance checked-in consistency metadata defines a different threshold. A performance
PR needs repeated saved-request e2e improvement of at least 1.5%, a PR needs repeated saved-request e2e improvement of at least 1.5%, a
@@ -139,9 +139,9 @@ The helper defaults to eager. Add `--torch-compile` only for a labeled compile
control. `--no-torch-compile` remains accepted for compatibility but is no control. `--no-torch-compile` remains accepted for compatibility but is no
longer required. longer required.
Run one explicit quality or BCG comparator with `--quality lossless|high` and Run one explicit quality or BCG comparator with `--quality {lossless,extra-high,high}` and
`--breakable-cuda-graph`. BCG and `torch.compile` are intentionally mutually `--breakable-cuda-graph`. BCG and `torch.compile` are intentionally mutually
exclusive in this helper. A high+BCG command is only a compatibility probe: exclusive in this helper. An extra-high/high+BCG command is only a compatibility probe:
it is invalid if request-scoped DiT fusions mount after the lossless warmup it is invalid if request-scoped DiT fusions mount after the lossless warmup
graphs were captured. When a preset has explicit width and height, the helper graphs were captured. When a preset has explicit width and height, the helper
declares that same `--warmup-resolutions` value automatically. Video presets declares that same `--warmup-resolutions` value automatically. Video presets
@@ -150,21 +150,22 @@ with an explicit frame count also declare the matching `--warmup-num-frames`:
```bash ```bash
PYTHONPATH=python python3 "$BENCH_PY" \ PYTHONPATH=python python3 "$BENCH_PY" \
--model longcat-image \ --model longcat-image \
--quality high \ --quality extra-high \
--breakable-cuda-graph \ --breakable-cuda-graph \
--label bcg-high \ --label bcg-extra-high \
--output-dir "${BENCH_DIR}" --output-dir "${BENCH_DIR}"
``` ```
For optimization discovery, use the full repeated matrix. It runs For optimization discovery, use the full repeated matrix. It runs
Eager/BCG/BCG/Eager at `lossless`, then the same sequence at `high`, while Eager/BCG/BCG/Eager at `lossless`, then the same sequence at `extra-high` and
holding one GPU set and one isolated checkpoint cache. The high+BCG cells test `high`, while holding one GPU set and one isolated checkpoint cache. The
extra-high/high+BCG cells test
whether the combination is actually supported; do not average them when the whether the combination is actually supported; do not average them when the
runtime rejects the combination or the helper detects a late quality-fusion runtime rejects the combination or the helper detects a late quality-fusion
mount. The helper hashes every generated image, video, audio, or 3D mesh mount. The helper hashes every generated image, video, audio, or 3D mesh
artifact. It first requires the two Eager rows at each quality to agree, then artifact. It first requires the two Eager rows at each quality to agree, then
rejects any BCG row whose hash differs from that Eager reference. Cleanup occurs rejects any BCG row whose hash differs from that Eager reference. Cleanup occurs
only after all eight runs, including on failure or interruption: only after all twelve runs, including on failure or interruption:
```bash ```bash
MODEL_CACHE_ROOT=/path/to/task-owned/model-caches MODEL_CACHE_ROOT=/path/to/task-owned/model-caches
@@ -181,7 +182,7 @@ Before starting, confirm the chosen GPU set has no foreign process and remains
unchanged through every run boundary. The helper rejects a BCG row unless its unchanged through every run boundary. The helper rejects a BCG row unless its
log contains `[Diffusion BCG] captured` and contains none of: support-gate log contains `[Diffusion BCG] captured` and contains none of: support-gate
disable, capture failure, `serving signature MISSED`, a message that no graph disable, capture failure, `serving signature MISSED`, a message that no graph
will be captured, or a request-scoped high-quality DiT fusion mounted after will be captured, or a request-scoped quality-gated DiT fusion mounted after
capture. Do not average rejected rows with valid results. capture. Do not average rejected rows with valid results.
BCG signatures include more than width and height. The helper maps an explicit BCG signatures include more than width and height. The helper maps an explicit
@@ -319,13 +320,13 @@ Use the preset categories this way:
| `qwen-edit-base` | `Qwen/Qwen-Image-Edit` | No | Covers the original native `QwenImageEditPipelineConfig`, which is distinct from the 2509/2511 edit-plus paths; public SGLang edit fixture, 1024x1024. | | `qwen-edit-base` | `Qwen/Qwen-Image-Edit` | No | Covers the original native `QwenImageEditPipelineConfig`, which is distinct from the 2509/2511 edit-plus paths; public SGLang edit fixture, 1024x1024. |
| `qwen-image-layered` | `Qwen/Qwen-Image-Layered` | No | Native layered-image path using the same public reference image and four-frame request as the GPU server case, at the registered 640x640 canvas. | | `qwen-image-layered` | `Qwen/Qwen-Image-Layered` | No | Native layered-image path using the same public reference image and four-frame request as the GPU server case, at the registered 640x640 canvas. |
| `stable-diffusion-3.5-medium` | `stabilityai/stable-diffusion-3.5-medium-diffusers` | No | Representative native `StableDiffusion3PipelineConfig` path at 1024x1024. The repository is gated, so export `HF_TOKEN`; an unauthenticated run is a recorded access blocker, not model evidence. | | `stable-diffusion-3.5-medium` | `stabilityai/stable-diffusion-3.5-medium-diffusers` | No | Representative native `StableDiffusion3PipelineConfig` path at 1024x1024. The repository is gated, so export `HF_TOKEN`; an unauthenticated run is a recorded access blocker, not model evidence. |
| `sana-video` | `Efficient-Large-Model/SANA-Video_2B_480p_diffusers` | No | CI-sized T2V baseline: 832x480, 17 frames, 8 steps, guidance 6.0. The BCG comparator declares the same 17-frame warmup shape. Compare `quality=lossless` and `quality=high`; high enables the BF16-input first linear-attention GEMM while retaining FP32 output and the FP32 second GEMM. | | `sana-video` | `Efficient-Large-Model/SANA-Video_2B_480p_diffusers` | No | CI-sized T2V baseline: 832x480, 17 frames, 8 steps, guidance 6.0. The BCG comparator declares the same 17-frame warmup shape. Compare all three tiers; `extra-high` and `high` enable the BF16-input first linear-attention GEMM while retaining FP32 output and the FP32 second GEMM. |
| `sana-wm-bidirectional` | `Efficient-Large-Model/SANA-WM_bidirectional` | No | Dense two-stage TI2V baseline at the native 1280x704 shape, 49 frames, 16 fps, 20 steps, guidance 4.5, and a 48-frame forward/left action program. Uses the shared cat fixture. | | `sana-wm-bidirectional` | `Efficient-Large-Model/SANA-WM_bidirectional` | No | Dense two-stage TI2V baseline at the native 1280x704 shape, 49 frames, 16 fps, 20 steps, guidance 4.5, and a 48-frame forward/left action program. Uses the shared cat fixture. |
| `sana-wm-streaming` | `Efficient-Large-Model/SANA-WM_streaming` | No | Matching offline chunk-causal two-stage baseline with the streaming DiT and chunked refiner enabled; uses the same shape, fixture, seed, and camera action for comparison. | | `sana-wm-streaming` | `Efficient-Large-Model/SANA-WM_streaming` | No | Matching offline chunk-causal two-stage baseline with the streaming DiT and chunked refiner enabled; uses the same shape, fixture, seed, and camera action for comparison. |
| `lingbot-video-moe` | `robbyant/lingbot-video-moe-30b-a3b` | No | One-GPU eager baseline using the CI structured-JSON caption, 384x640, 17 frames, 12 steps, and text-encoder CPU offload. | | `lingbot-video-moe` | `robbyant/lingbot-video-moe-30b-a3b` | No | One-GPU eager baseline using the CI structured-JSON caption, 384x640, 17 frames, 12 steps, and text-encoder CPU offload. |
| `lingbot-world` | `robbyant/lingbot-world-fast-diffusers` | No | One-H200 offline single-chunk profile for the registered causal DMD path: 832x480x9, four steps, guidance 1.0, the shared image fixture, and forward-camera actions for all nine frames. Keep stateful websocket latency as a separate metric. | | `lingbot-world` | `robbyant/lingbot-world-fast-diffusers` | No | One-H200 offline single-chunk profile for the registered causal DMD path: 832x480x9, four steps, guidance 1.0, the shared image fixture, and forward-camera actions for all nine frames. Keep stateful websocket latency as a separate metric. |
| `lingbot-world-v2` | `robbyant/lingbot-world-v2-14b-causal-fast-diffusers` | No | Matching controlled single-chunk profile for the separately registered v2 checkpoint. The fixed shape, action program, and schedule make v1/v2 hotspot comparisons reproducible without presenting one-chunk e2e as stateful realtime latency. | | `lingbot-world-v2` | `robbyant/lingbot-world-v2-14b-causal-fast-diffusers` | No | Matching controlled single-chunk profile for the separately registered v2 checkpoint. The fixed shape, action program, and schedule make v1/v2 hotspot comparisons reproducible without presenting one-chunk e2e as stateful realtime latency. |
| `fastwan21-t2v-1.3b` | `FastVideo/FastWan2.1-T2V-1.3B-Diffusers` | No | One-GPU 832x480, 61-frame, 3-step DMD baseline. The preset pins manual mode with a resident DiT so lossless/high comparisons do not measure an offload-policy change. | | `fastwan21-t2v-1.3b` | `FastVideo/FastWan2.1-T2V-1.3B-Diffusers` | No | One-GPU 832x480, 61-frame, 3-step DMD baseline. The preset pins manual mode with a resident DiT so lossless/extra-high/high comparisons do not measure an offload-policy change. |
| `wan21-t2v-1.3b` | `Wan-AI/Wan2.1-T2V-1.3B-Diffusers` | No | Registered one-GPU 832x480, 81-frame Wan2.1 baseline at 50 steps and guidance 3.0. Keep it separate from FastWan and TurboWan because the longer schedule changes the end-to-end weight of VAE optimizations. | | `wan21-t2v-1.3b` | `Wan-AI/Wan2.1-T2V-1.3B-Diffusers` | No | Registered one-GPU 832x480, 81-frame Wan2.1 baseline at 50 steps and guidance 3.0. Keep it separate from FastWan and TurboWan because the longer schedule changes the end-to-end weight of VAE optimizations. |
| `wan21-t2v-14b` | `Wan-AI/Wan2.1-T2V-14B-Diffusers` | No | Cookbook-aligned four-GPU CFG/Ulysses baseline at 832x480, 81 frames, 50 steps, and guidance 5.0. Text encoding stays CPU-offloaded as in the documented deployment command. | | `wan21-t2v-14b` | `Wan-AI/Wan2.1-T2V-14B-Diffusers` | No | Cookbook-aligned four-GPU CFG/Ulysses baseline at 832x480, 81 frames, 50 steps, and guidance 5.0. Text encoding stays CPU-offloaded as in the documented deployment command. |
| `wan21-i2v-14b-480p` | `Wan-AI/Wan2.1-I2V-14B-480P-Diffusers` | No | Four-GPU CFG/Ulysses image-conditioned baseline at 832x480, 81 frames, 50 steps, and guidance 5.0. Uses the shared cat fixture and its motion prompt. | | `wan21-i2v-14b-480p` | `Wan-AI/Wan2.1-I2V-14B-480P-Diffusers` | No | Four-GPU CFG/Ulysses image-conditioned baseline at 832x480, 81 frames, 50 steps, and guidance 5.0. Uses the shared cat fixture and its motion prompt. |
@@ -668,7 +669,8 @@ some generation failures are reported through the response payload without a
nonzero process exit. nonzero process exit.
For `quality=lossless`, compare saved artifact hashes and require byte equality For `quality=lossless`, compare saved artifact hashes and require byte equality
for a claimed lossless fast path or BCG change. For `quality=high`, keep the for a claimed lossless fast path or BCG change. For `quality=extra-high` and
`quality=high`, keep the
lossless artifact as ground truth and report both aggregate and worst-frame lossless artifact as ground truth and report both aggregate and worst-frame
SSIM/PSNR. Repository defaults are SSIM 0.95 / PSNR 28 dB for images and SSIM SSIM/PSNR. Repository defaults are SSIM 0.95 / PSNR 28 dB for images and SSIM
0.92 / PSNR 24 dB for videos; checked-in model/hardware consistency metadata 0.92 / PSNR 24 dB for videos; checked-in model/hardware consistency metadata
@@ -788,7 +790,7 @@ the known mainline families.
| `to_q -> to_k -> to_v` on NVFP4 or Nunchaku FLUX-family checkpoints | Treat as a packed-QKV fast-path miss or checkpoint-format mismatch | | `to_q -> to_k -> to_v` on NVFP4 or Nunchaku FLUX-family checkpoints | Treat as a packed-QKV fast-path miss or checkpoint-format mismatch |
| `rmsnorm_scale` or `rmsnorm_tanh_residual` missing on Z-Image | Check the bf16-native Triton eligibility guards before proposing a new fusion | | `rmsnorm_scale` or `rmsnorm_tanh_residual` missing on Z-Image | Check the bf16-native Triton eligibility guards before proposing a new fusion |
| FLUX.1, GLM-Image, or SANA shows separate LayerNorm plus adaLN elementwise kernels | Check the bit-exact `modulate_scale_shift` and `fused_layernorm_modulate` guards/self-test before proposing another norm fusion | | FLUX.1, GLM-Image, or SANA shows separate LayerNorm plus adaLN elementwise kernels | Check the bit-exact `modulate_scale_shift` and `fused_layernorm_modulate` guards/self-test before proposing another norm fusion |
| `quality=high` shows the same FLUX/GLM DiT or FLUX-family/Wan VAE chain as `lossless` | Check whether the request-scoped quality gate mounted and whether every site passed its all-or-nothing compatibility checks | | `quality=extra-high` or `quality=high` shows the same FLUX/GLM DiT or FLUX-family/Wan VAE chain as `lossless` | Check whether the request-scoped quality gate mounted and whether every site passed its all-or-nothing compatibility checks |
| LTX-2 split RoPE appears as a long PyTorch elementwise chain | Check the `apply_ltx2_split_rotary_emb` Triton path and its shape guards | | LTX-2 split RoPE appears as a long PyTorch elementwise chain | Check the `apply_ltx2_split_rotary_emb` Triton path and its shape guards |
| Wan decode is dominated by causal `cat + pad + contiguous`, feature-cache copies, or `repeat_interleave + permute + add` | Check the bit-exact Wan causal-cache and DupUp3D data-movement kernels before writing a new decoder kernel | | Wan decode is dominated by causal `cat + pad + contiguous`, feature-cache copies, or `repeat_interleave + permute + add` | Check the bit-exact Wan causal-cache and DupUp3D data-movement kernels before writing a new decoder kernel |
| masked attention spends time packing/unpacking Q/K/V | Check whether fused varlen USP pack/scatter should have engaged | | masked attention spends time packing/unpacking Q/K/V | Check whether fused varlen USP pack/scatter should have engaged |
@@ -826,7 +828,7 @@ This skill intentionally stops here. It tells you whether you are looking at:
- [ ] `compare_perf.py` table generated - [ ] `compare_perf.py` table generated
- [ ] one representative `torch.profiler` trace saved - [ ] one representative `torch.profiler` trace saved
- [ ] hotspot classified against `existing-fast-paths.md` - [ ] hotspot classified against `existing-fast-paths.md`
- [ ] lossless artifact hash is exact; high-quality aggregate and worst-frame SSIM/PSNR pass the checked-in threshold - [ ] lossless artifact hash is exact; extra-high/high aggregate and worst-frame SSIM/PSNR pass the checked-in threshold
- [ ] reference image or start/middle/end video contact sheet checked visually - [ ] reference image or start/middle/end video contact sheet checked visually
- [ ] any PR claim has repeated saved-request e2e improvement >= 1.5% - [ ] any PR claim has repeated saved-request e2e improvement >= 1.5%
- [ ] task-owned checkpoint cache cleaned and ledger shows zero residual weight files - [ ] task-owned checkpoint cache cleaned and ledger shows zero residual weight files
@@ -114,17 +114,20 @@ framework-specific optimization workflow.
check dtype, alignment, shape, BCG/compile context, and the one-time equality check dtype, alignment, shape, BCG/compile context, and the one-time equality
self-test before proposing another fusion. self-test before proposing another fusion.
4. Request-scoped `quality=high` fusion gates 4. Request-scoped fusion gates at `quality=extra-high` or `quality=high`
- Locations: `quality_gate.py`, `fused_ln_modulate.py`, `denoising.py`, - Locations: `quality_gate.py`, `fused_ln_modulate.py`, `denoising.py`,
`decoding.py`, `fast_path_gate.py`, `flux2_vae_cuda_opt.py`, and `decoding.py`, `fast_path_gate.py`, `flux2_vae_cuda_opt.py`, and
`wan_vae_cuda_opt.py`. `wan_vae_cuda_opt.py`.
- Behavior: `quality="lossless"` is the default exact reference path. - Behavior: `quality="lossless"` is the default exact reference path.
`quality="high"` may mount model-owned, validated but non-bit-exact DiT `quality="extra-high"` and `quality="high"` mount the same validated but
fusions and decode-scoped VAE rewrites. Mounting is all-or-nothing per non-bit-exact DiT fusions and decode-scoped VAE rewrites. `high` is
cumulative and may additionally enable model-owned approximate paths.
Mounting is all-or-nothing per
transformer/fusion family; VAE gates reset after every decode. transformer/fusion family; VAE gates reset after every decode.
- Current families include FLUX affine-folded LN+modulate / fused GELU sites, - Current families include FLUX affine-folded LN+modulate / fused GELU sites,
GLM/Qwen/Hunyuan/LTX fused GELU sites, LTX RMSNorm+modulate, Hunyuan QK Wan cublasLt/NVFP4 GELU, Qwen added-QKV, GLM/Qwen/Hunyuan/LTX fused GELU,
RMSNorm, Ideogram gated RMSNorm, SANA-Video linear attention, generic KL VAE LTX RMSNorm+modulate, Hunyuan QK RMSNorm, Ideogram gated RMSNorm,
LingBot RMSNorm, SANA-Video linear attention, generic KL VAE
decoder rewrites used by FLUX.1/FLUX.2/Z-Image/SD3, and Wan VAE decoder rewrites used by FLUX.1/FLUX.2/Z-Image/SD3, and Wan VAE
RMSNorm+SiLU. RMSNorm+SiLU.
- Do not confuse request `--quality` with `--output-quality`, which controls - Do not confuse request `--quality` with `--output-quality`, which controls
@@ -218,7 +221,7 @@ framework-specific optimization workflow.
one channels-last-3D pass, and fuse `main + DupUp3D(src)` without one channels-last-3D pass, and fuse `main + DupUp3D(src)` without
materializing `repeat_interleave + permute().contiguous()` intermediates. materializing `repeat_interleave + permute().contiguous()` intermediates.
- Numerical contract: these are bit-exact data-movement / same-order-add - Numerical contract: these are bit-exact data-movement / same-order-add
replacements and run independently of the `quality=high` Wan RMSNorm+SiLU replacements and run independently of the request-gated Wan RMSNorm+SiLU
path. Unsupported layouts or padding fall back to the aten chain. path. Unsupported layouts or padding fall back to the aten chain.
- Validation: `test/registered/kernels/ops/diffusion/test_wan_causal_cache.py`. - Validation: `test/registered/kernels/ops/diffusion/test_wan_causal_cache.py`.
@@ -328,16 +331,16 @@ framework-specific optimization workflow.
**Request-Scoped DiT Fusions with Breakable CUDA Graphs** **Request-Scoped DiT Fusions with Breakable CUDA Graphs**
- `quality=high` DiT sites are mounted at a request boundary. BCG warmup uses - DiT sites at `quality=extra-high` or `quality=high` are mounted at a request boundary. BCG warmup uses
the model's lossless sampling default unless a quality-aware graph variant the model's lossless sampling default unless a quality-aware graph variant
was captured explicitly. was captured explicitly.
- A graph captured before the high-quality mount retains the lossless module - A graph captured before the request-quality mount retains the lossless module
branches. Replaying it after the mount silently bypasses the requested high branches. Replaying it after the mount silently bypasses the requested fused
kernels even when the tensor signature matches. kernels even when the tensor signature matches.
- Workflow rule: a high+BCG cell is valid only when the model has no - Workflow rule: an extra-high/high+BCG cell is valid only when the model has no
request-scoped DiT quality sites, or when logs prove those sites were mounted request-scoped DiT quality sites, or when logs prove those sites were mounted
before the matching graph capture. A mount after `[Diffusion BCG] captured` before the matching graph capture. A mount after `[Diffusion BCG] captured`
invalidates the row; do not use its latency or output as high-quality invalidates the row; do not use its latency or output as request-quality
evidence. evidence.
**Recent Model Audit Boundaries** **Recent Model Audit Boundaries**
@@ -363,10 +366,10 @@ framework-specific optimization workflow.
- LingBot Video MoE's router implements sigmoid+bias grouped top-k in - LingBot Video MoE's router implements sigmoid+bias grouped top-k in
`multimodal_gen/runtime/layers/moe.py`. Check parameter and output-order `multimodal_gen/runtime/layers/moe.py`. Check parameter and output-order
compatibility with `srt/layers/moe/topk.py::biased_grouped_topk` before compatibility with `srt/layers/moe/topk.py::biased_grouped_topk` before
writing a new router kernel. Its released eager path still expands RMSNorm writing a new router kernel. Current main mounts fused Triton RMSNorm row
into `pow/mean/rsqrt` chains. #35969 is a measured `quality=high` candidate kernels by weight dtype and hidden size for `quality=extra-high` and
that dispatches existing Triton row kernels by weight dtype and hidden size; `quality=high`; check the quality-site guards before treating an expanded
it is not current-main behavior until the PR merges. `pow/mean/rsqrt` chain as a new opportunity.
- LTX-2.5 reuses the mature LTX-2 DiT paths. Treat the optional diffusion - LTX-2.5 reuses the mature LTX-2 DiT paths. Treat the optional diffusion
decoder separately: confirm NATTEN `na3d` is active, then inspect its decoder separately: confirm NATTEN `na3d` is active, then inspect its
per-block 3D RoPE construction and split QKV/SwiGLU projections. per-block 3D RoPE construction and split QKV/SwiGLU projections.
@@ -379,7 +382,7 @@ framework-specific optimization workflow.
- AdaLN modulation: `LayerNormScaleShift`, `RMSNormScaleShift`, `ScaleResidual*` in `layernorm.py`. - AdaLN modulation: `LayerNormScaleShift`, `RMSNormScaleShift`, `ScaleResidual*` in `layernorm.py`.
- Bit-exact adaLN modulation / LayerNorm folding: `modulate_scale_shift` and - Bit-exact adaLN modulation / LayerNorm folding: `modulate_scale_shift` and
`fused_layernorm_modulate` through `flux.py`, `glm_image.py`, and `sana.py`. `fused_layernorm_modulate` through `flux.py`, `glm_image.py`, and `sana.py`.
- Request-scoped high-quality acceleration: `QualityGatedFusion` in - Request-scoped extra-high/high acceleration: `QualityGatedFusion` in
`quality_gate.py`, `_maybe_toggle_quality_fusions` in `denoising.py`, and `quality_gate.py`, `_maybe_toggle_quality_fusions` in `denoising.py`, and
`use_vae_fast_path` in `decoding.py`. `use_vae_fast_path` in `decoding.py`.
- Bit-exact first-sight verify/disable: `BitExactFusionGate` in - Bit-exact first-sight verify/disable: `BitExactFusionGate` in
@@ -394,7 +397,7 @@ framework-specific optimization workflow.
- QK norm: `apply_qk_norm` used in `flux.py`, `flux_2.py`, `qwen_image.py`, `zimage.py`, `wanvideo.py`, `ltx_2.py`, `hunyuanvideo.py`. - QK norm: `apply_qk_norm` used in `flux.py`, `flux_2.py`, `qwen_image.py`, `zimage.py`, `wanvideo.py`, `ltx_2.py`, `hunyuanvideo.py`.
- QK norm + RoPE: `apply_qk_norm_rope` in `layernorm.py`; use this path when the model wants fused attention prep instead of separate QK norm and RoPE calls. - QK norm + RoPE: `apply_qk_norm_rope` in `layernorm.py`; use this path when the model wants fused attention prep instead of separate QK norm and RoPE calls.
- LTX2 split RoPE: `apply_ltx2_split_rotary_emb` in `ltx_2.py`. - LTX2 split RoPE: `apply_ltx2_split_rotary_emb` in `ltx_2.py`.
- LTX2 RMSNorm+modulate and FFN GELU epilogue under `quality="high"`: - LTX2 RMSNorm+modulate and FFN GELU epilogue under `quality="extra-high"` and `quality="high"`:
`mark_ltx2_rms_norm_modulate_site` / `fused_ltx2_rms_norm_modulate` in `mark_ltx2_rms_norm_modulate_site` / `fused_ltx2_rms_norm_modulate` in
`kernels/ops/diffusion/sites/ltx2_rmsnorm_modulate_site.py` (mount-based `kernels/ops/diffusion/sites/ltx2_rmsnorm_modulate_site.py` (mount-based
`QualityGatedFusion`, not a first-sight `BitExactFusionGate` — the fused `QualityGatedFusion`, not a first-sight `BitExactFusionGate` — the fused
@@ -468,8 +471,9 @@ relying on any file path, flag, or claim about whether the work has merged.
- #34584 Wan TI2V modulation/RoPE; #34616 FLUX2; #34617 Hunyuan; - #34584 Wan TI2V modulation/RoPE; #34616 FLUX2; #34617 Hunyuan;
#34619 GLM; #34620 ERNIE; #34928 SANA; #34932 Cosmos3; #35728 #34619 GLM; #34620 ERNIE; #34928 SANA; #34932 Cosmos3; #35728
SANA-Video linear attention. SANA-Video linear attention.
- #35961 SANA-Video lossless shared-kernel reuse and #35969 LingBot - SANA-Video shared-kernel reuse and LingBot request-gated RMSNorm are now
`quality=high` RMSNorm are open candidates, not current-main fast paths. current-main fast paths; verify the source tree before treating their
historical PRs as open work.
- VAE and decode-side acceleration: - VAE and decode-side acceleration:
- #22531 LTX2 parallel VAE support and #20927 batched tiled VAE decode (draft). - #22531 LTX2 parallel VAE support and #20927 batched tiled VAE decode (draft).
- Attention, communication, and runtime scheduling: - Attention, communication, and runtime scheduling:
@@ -492,7 +496,7 @@ relying on any file path, flag, or claim about whether the work has merged.
**Constraints and Fallbacks** **Constraints and Fallbacks**
- `scale_shift` Triton requires CUDA + contiguous `x`. NPU swaps to native. - `scale_shift` Triton requires CUDA + contiguous `x`. NPU swaps to native.
- Bit-exact BF16 LayerNorm+modulate requires the guarded aten-compatible shape - Bit-exact BF16 LayerNorm+modulate requires the guarded aten-compatible shape
and a successful live equality check; `quality=high` affine folding is a and a successful live equality check; request-gated affine folding is a
separate non-bit-exact path. separate non-bit-exact path.
- CuTe DSL fused norms require `D % 256 == 0` and `D <= 8192`. - CuTe DSL fused norms require `D % 256 == 0` and `D <= 8192`.
- Triton norm kernels error on feature size >= 64KB. - Triton norm kernels error on feature size >= 64KB.
@@ -16,8 +16,9 @@ Usage:
# Opt in to a compile control (presets are eager by default) # Opt in to a compile control (presets are eager by default)
python3 python/sglang/multimodal_gen/.claude/skills/sglang-diffusion-benchmark-profile/scripts/bench_diffusion_denoise.py --model flux --torch-compile python3 python/sglang/multimodal_gen/.claude/skills/sglang-diffusion-benchmark-profile/scripts/bench_diffusion_denoise.py --model flux --torch-compile
# Check Eager/BCG at lossless/high on one GPU set; high+BCG is invalid when # Check Eager/BCG at every request quality on one GPU set; extra-high/high
# request-scoped DiT fusions mount only after lossless graph capture. # + BCG are invalid when request-scoped DiT fusions mount only after the
# lossless graph capture.
python3 python/sglang/multimodal_gen/.claude/skills/sglang-diffusion-benchmark-profile/scripts/bench_diffusion_denoise.py --model sana-video --quality-bcg-matrix --model-cache-root /task/model-caches --cleanup-model-cache python3 python/sglang/multimodal_gen/.claude/skills/sglang-diffusion-benchmark-profile/scripts/bench_diffusion_denoise.py --model sana-video --quality-bcg-matrix --model-cache-root /task/model-caches --cleanup-model-cache
# Clean an isolated model cache even if the run fails or is interrupted # Clean an isolated model cache even if the run fails or is interrupted
@@ -80,14 +81,14 @@ DIFFUSERS_FALLBACK_SIGNALS = (
"using diffusers backend", "using diffusers backend",
"loaded diffusers pipeline", "loaded diffusers pipeline",
) )
BENCHMARK_QUALITY_LEVELS = ("lossless", "high") BENCHMARK_QUALITY_LEVELS = ("lossless", "extra-high", "high")
BCG_CAPTURE_SIGNAL = "[diffusion bcg] captured" BCG_CAPTURE_SIGNAL = "[diffusion bcg] captured"
BCG_INVALID_SIGNALS = ( BCG_INVALID_SIGNALS = (
"[diffusion bcg] capture failed", "[diffusion bcg] capture failed",
"[diffusion bcg] disabled", "[diffusion bcg] disabled",
"[diffusion bcg] serving signature missed", "[diffusion bcg] serving signature missed",
"no graph will be captured", "no graph will be captured",
"quality='high' cannot be used with breakable cuda graphs", "cannot be used with breakable cuda graphs",
) )
BCG_LATE_QUALITY_FUSION_SIGNAL = "quality fusion mounted after BCG capture" BCG_LATE_QUALITY_FUSION_SIGNAL = "quality fusion mounted after BCG capture"
QUALITY_BCG_ABBA_MATRIX = ( QUALITY_BCG_ABBA_MATRIX = (
@@ -95,6 +96,10 @@ QUALITY_BCG_ABBA_MATRIX = (
("bcg-lossless-a", "lossless", True), ("bcg-lossless-a", "lossless", True),
("bcg-lossless-b", "lossless", True), ("bcg-lossless-b", "lossless", True),
("eager-lossless-b", "lossless", False), ("eager-lossless-b", "lossless", False),
("eager-extra-high-a", "extra-high", False),
("bcg-extra-high-a", "extra-high", True),
("bcg-extra-high-b", "extra-high", True),
("eager-extra-high-b", "extra-high", False),
("eager-high-a", "high", False), ("eager-high-a", "high", False),
("bcg-high-a", "high", True), ("bcg-high-a", "high", True),
("bcg-high-b", "high", True), ("bcg-high-b", "high", True),
@@ -1838,11 +1843,11 @@ def _run_benchmark_once_impl(
if BCG_CAPTURE_SIGNAL in lower_line: if BCG_CAPTURE_SIGNAL in lower_line:
bcg_capture_detected = True bcg_capture_detected = True
if ( if (
quality == "high" quality in {"extra-high", "high"}
and breakable_cuda_graph and breakable_cuda_graph
and bcg_capture_detected and bcg_capture_detected
and "mounted " in lower_line and "mounted " in lower_line
and "for quality=high" in lower_line and f"for quality={quality}" in lower_line
): ):
bcg_invalid_signals.add(BCG_LATE_QUALITY_FUSION_SIGNAL) bcg_invalid_signals.add(BCG_LATE_QUALITY_FUSION_SIGNAL)
bcg_invalid_signals.update( bcg_invalid_signals.update(
@@ -2256,7 +2261,8 @@ def main():
"--quality-bcg-matrix", "--quality-bcg-matrix",
action="store_true", action="store_true",
help=( help=(
"Run lossless/high Eager-vs-BCG as two ABBA pairs on one GPU set " "Run lossless/extra-high/high Eager-vs-BCG as three ABBA pairs "
"on one GPU set "
"and one task-owned model cache." "and one task-owned model cache."
), ),
) )
@@ -62,7 +62,7 @@ These options **trade output quality** for speed or VRAM savings. Results will d
| Option | CLI Flag / Env Var | What It Does | Speedup | Quality Impact / Limitations | | Option | CLI Flag / Env Var | What It Does | Speedup | Quality Impact / Limitations |
|---|---|---|---|---| |---|---|---|---|---|
| **Request Quality Fast Paths** | `--quality high` (`lossless` is default) | Mounts model-owned accelerated DiT/VAE paths that are validated for high quality but are not bit-exact to the reference path. | Model- and shape-specific | Support is per model and may be a no-op. Keep `--quality lossless` as the A/B ground truth. Report aggregate and worst-frame SSIM/PSNR; defaults are 0.95/28 dB for images and 0.92/24 dB for video unless checked-in model metadata overrides them. Do not confuse this with `--output-quality`, which controls file compression. | | **Request Quality Fast Paths** | `--quality {extra-high,high}` (`lossless` is default) | `extra-high` mounts only request-gated DiT/VAE fusions. `high` includes that complete set and may add model-owned approximate paths such as Cache-DiT or lower-precision decode. | Model- and shape-specific | Support is per model and may be a no-op. Keep `--quality lossless` as the A/B ground truth, then compare `extra-high` before `high` to isolate fusion wins. Report aggregate and worst-frame SSIM/PSNR for every non-bit-exact path; defaults are 0.95/28 dB for images and 0.92/24 dB for video unless checked-in model metadata overrides them. Do not confuse this with `--output-quality`, which controls file compression. |
| **Approximate Attention** | Server-wide: `--attention-backend sage_attn` / `sage_attn_3` / `sliding_tile_attn` / `video_sparse_attn` / `sparse_video_gen_2_attn` / `vmoba_attn` / `sla_attn` / `sage_sla_attn`. Per-request (dense drop-ins only): `--attention-backend-override sage_attn` sampling param / API `extra_body` — valid values `fa`, `torch_sdpa`, `sage_attn`, `sage_attn_3`; rejected (with a log) under BCG, torch.compile, sparse server backends, or a non-ring-capable target with ring parallelism. | Replaces exact attention with approximate or sparse variants. `sage_attn`: INT8/FP8 quantized Q·K; `sliding_tile_attn`: spatial-temporal tile skipping; others: model-specific sparse patterns. | ~1.5–2x on attention (varies by backend) | Quality degradation varies by backend and model. `sage_attn` is the most general; sparse backends (`sliding_tile_attn`, `video_sparse_attn`, etc.) are video-model-specific, may require config files (e.g. `--mask-strategy-file-path` for STA), and are server-level only. Requires corresponding packages installed. | | **Approximate Attention** | Server-wide: `--attention-backend sage_attn` / `sage_attn_3` / `sliding_tile_attn` / `video_sparse_attn` / `sparse_video_gen_2_attn` / `vmoba_attn` / `sla_attn` / `sage_sla_attn`. Per-request (dense drop-ins only): `--attention-backend-override sage_attn` sampling param / API `extra_body` — valid values `fa`, `torch_sdpa`, `sage_attn`, `sage_attn_3`; rejected (with a log) under BCG, torch.compile, sparse server backends, or a non-ring-capable target with ring parallelism. | Replaces exact attention with approximate or sparse variants. `sage_attn`: INT8/FP8 quantized Q·K; `sliding_tile_attn`: spatial-temporal tile skipping; others: model-specific sparse patterns. | ~1.5–2x on attention (varies by backend) | Quality degradation varies by backend and model. `sage_attn` is the most general; sparse backends (`sliding_tile_attn`, `video_sparse_attn`, etc.) are video-model-specific, may require config files (e.g. `--mask-strategy-file-path` for STA), and are server-level only. Requires corresponding packages installed. |
| **Cache-DiT** | Native: per-request `--enable-cache-dit true\|false` + `--cache-dit-params <json>` (sampling params; also via API `extra_body`). `SGLANG_CACHE_DIT_ENABLED` / `SGLANG_CACHE_DIT_*` env vars are the server-wide defaults for requests that leave them unset. Diffusers backend: `--backend diffusers --cache-dit-config <yaml-or-json>` | Caches intermediate residuals across denoising steps and skips redundant computations via DBCache, TaylorSeer, and optional SCM. | ~1.5-2x on supported models | Quality depends on cache policy. Compatible with `--dit-layerwise-offload`: skipped blocks are not streamed, and the first layer after a skip may sync-load. Models that touch every layer before the block loop (for example a full-stack AdaLN prepass) must keep that prepass off while caching. Do not pass `--cache-dit-config` for native SGLang tuning unless you are intentionally using the diffusers backend flow. | | **Cache-DiT** | Native: per-request `--enable-cache-dit true\|false` + `--cache-dit-params <json>` (sampling params; also via API `extra_body`). `SGLANG_CACHE_DIT_ENABLED` / `SGLANG_CACHE_DIT_*` env vars are the server-wide defaults for requests that leave them unset. Diffusers backend: `--backend diffusers --cache-dit-config <yaml-or-json>` | Caches intermediate residuals across denoising steps and skips redundant computations via DBCache, TaylorSeer, and optional SCM. | ~1.5-2x on supported models | Quality depends on cache policy. Compatible with `--dit-layerwise-offload`: skipped blocks are not streamed, and the first layer after a skip may sync-load. Models that touch every layer before the block loop (for example a full-stack AdaLN prepass) must keep that prepass off while caching. Do not pass `--cache-dit-config` for native SGLang tuning unless you are intentionally using the diffusers backend flow. |
| **CFG Gating** | Per-request `--cfg-gate-step 0.5` (sampling param; also via API `extra_body`). `SGLANG_DIFFUSION_CFG_GATE_STEP` is the server-wide default (1.0 = off). | After the given fraction of denoising steps, reuses the cached cond-uncond residual instead of running the unconditional branch each step. | Up to ~2x on the gated tail of CFG models (skips one of two branches) | Lossy; no-op without classifier-free guidance or with `--enable-cfg-parallel`. Lower fractions gate earlier and drift more. | | **CFG Gating** | Per-request `--cfg-gate-step 0.5` (sampling param; also via API `extra_body`). `SGLANG_DIFFUSION_CFG_GATE_STEP` is the server-wide default (1.0 = off). | After the given fraction of denoising steps, reuses the cached cond-uncond residual instead of running the unconditional branch each step. | Up to ~2x on the gated tail of CFG models (skips one of two branches) | Lossy; no-op without classifier-free guidance or with `--enable-cfg-parallel`. Lower fractions gate earlier and drift more. |
@@ -252,7 +252,7 @@ For video, also match the captured frame and conditioning shape; `WxH` alone
does not prove replay. does not prove replay.
For a repeated discovery sweep, use the benchmark/profile helper. This runs For a repeated discovery sweep, use the benchmark/profile helper. This runs
lossless and high-quality Eager/BCG ABBA pairs on one GPU set, then deletes the lossless, extra-high, and high Eager/BCG ABBA pairs on one GPU set, then deletes the
model group cache once: model group cache once:
```bash ```bash
@@ -262,20 +262,25 @@ python3 python/sglang/multimodal_gen/.claude/skills/sglang-diffusion-benchmark-p
--cleanup-model-cache --cleanup-model-cache
``` ```
### Compare request-scoped high-quality fast paths ### Compare cumulative request-quality fast paths
```bash ```bash
sglang generate --model-path <MODEL> \ sglang generate --model-path <MODEL> \
--quality lossless --prompt "..." --seed 42 \ --quality lossless --prompt "..." --seed 42 \
--perf-dump-path baseline.json --save-output --perf-dump-path baseline.json --save-output
sglang generate --model-path <MODEL> \
--quality extra-high --prompt "..." --seed 42 \
--perf-dump-path quality-extra-high.json --save-output
sglang generate --model-path <MODEL> \ sglang generate --model-path <MODEL> \
--quality high --prompt "..." --seed 42 \ --quality high --prompt "..." --seed 42 \
--perf-dump-path quality-high.json --save-output --perf-dump-path quality-high.json --save-output
``` ```
Keep every other flag fixed and compare the generated artifact as well as the Keep every other flag fixed and compare the generated artifact as well as the
perf dumps. If the model has no registered quality-gated sites, `high` may be a perf dumps. `high` must retain every fusion observed under `extra-high`. If the
model has no registered request-gated or high-only sites, either tier may be a
no-op. no-op.
### Image-edit baselines: JoyAI and FireRed ### Image-edit baselines: JoyAI and FireRed
@@ -384,7 +389,7 @@ Use these as first commands to benchmark, not as universal winners.
| Z-Image / Z-Image-Turbo | 1024x1024, runtime-default steps/guidance, 1 GPU | `--enable-torch-compile --warmup-mode request` | Keep base Z-Image separate from Turbo: base uses 50-step CFG defaults, Turbo uses 9-step zero-CFG defaults. Mainline has bf16-native Triton RMSNorm scale and tanh-residual fusions. | | Z-Image / Z-Image-Turbo | 1024x1024, runtime-default steps/guidance, 1 GPU | `--enable-torch-compile --warmup-mode request` | Keep base Z-Image separate from Turbo: base uses 50-step CFG defaults, Turbo uses 9-step zero-CFG defaults. Mainline has bf16-native Triton RMSNorm scale and tanh-residual fusions. |
| Wan2.2 A14B T2V/I2V | 1280x720, 81 frames | Nightly: `--num-gpus 4 --enable-cfg-parallel --ulysses-degree 2 --text-encoder-cpu-offload --pin-cpu-memory` | For lowest latency, also benchmark pure Ulysses on the same GPUs. | | Wan2.2 A14B T2V/I2V | 1280x720, 81 frames | Nightly: `--num-gpus 4 --enable-cfg-parallel --ulysses-degree 2 --text-encoder-cpu-offload --pin-cpu-memory` | For lowest latency, also benchmark pure Ulysses on the same GPUs. |
| Wan2.2 TI2V 5B | 1280x720, 81 frames, 1 GPU | `--enable-torch-compile --warmup-mode request` | Keep the input image and motion prompt fixed when comparing sparse attention or Cache-DiT. | | Wan2.2 TI2V 5B | 1280x720, 81 frames, 1 GPU | `--enable-torch-compile --warmup-mode request` | Keep the input image and motion prompt fixed when comparing sparse attention or Cache-DiT. |
| Wan2.1 / FastWan / TurboWan variants | 480p or 720p video, family defaults | Compare `--quality lossless` with `--quality high`, then try `--enable-torch-compile --warmup-mode request`; add `--ulysses-degree` / CFG parallel only after measuring | `quality=high` mounts the Wan FFN cublasLt GELU epilogue and the Wan VAE RMSNorm+SiLU fast path when their guards pass; validate video quality against lossless. Current registry includes Wan2.1, FastWan2.1, FastWan2.2 TI2V, TurboWan2.1, TurboWan2.2 I2V, and Wan2.1-Fun InP. Use the compatibility matrix and benchmark presets before choosing topology. | | Wan2.1 / FastWan / TurboWan variants | 480p or 720p video, family defaults | Compare `--quality lossless`, `--quality extra-high`, and `--quality high`, then try `--enable-torch-compile --warmup-mode request`; add `--ulysses-degree` / CFG parallel only after measuring | `extra-high` and `high` mount the Wan FFN cublasLt/NVFP4 GELU epilogues and the Wan VAE RMSNorm+SiLU fast path when their guards pass; validate video quality against lossless. Current registry includes Wan2.1, FastWan2.1, FastWan2.2 TI2V, TurboWan2.1, TurboWan2.2 I2V, and Wan2.1-Fun InP. Use the compatibility matrix and benchmark presets before choosing topology. |
| Cosmos3 Nano / Super | T2I: 1024x1024 with `--num-frames 1`; T2V/I2V: 480p/720p video | Start with `--performance-mode auto --warmup-mode request`; use `SGLANG_DISABLE_COSMOS3_GUARDRAILS=1` only for benchmark isolation, and compare compile separately | One checkpoint serves T2I/T2V/I2V. Mode is request-driven: `num_frames == 1` means T2I, `--image-path` means I2V. On GPUs with at least 120 GiB available, auto mode keeps the Cosmos3 DiT and VAE resident for every checkpoint in the family; a 1xH200 832x480x9f, 4-step eager ABBA reduced e2e from 1.576 to 0.428 seconds with exact output parity. Cosmos3 runs one DiT per pipeline, so component offload above that threshold only buys a DiT copy out to host memory and back per request -- it cost Cosmos3-Super 720p 81f T2V ~4s of ~115s on 2xH200. | | Cosmos3 Nano / Super | T2I: 1024x1024 with `--num-frames 1`; T2V/I2V: 480p/720p video | Start with `--performance-mode auto --warmup-mode request`; use `SGLANG_DISABLE_COSMOS3_GUARDRAILS=1` only for benchmark isolation, and compare compile separately | One checkpoint serves T2I/T2V/I2V. Mode is request-driven: `num_frames == 1` means T2I, `--image-path` means I2V. On GPUs with at least 120 GiB available, auto mode keeps the Cosmos3 DiT and VAE resident for every checkpoint in the family; a 1xH200 832x480x9f, 4-step eager ABBA reduced e2e from 1.576 to 0.428 seconds with exact output parity. Cosmos3 runs one DiT per pipeline, so component offload above that threshold only buys a DiT copy out to host memory and back per request -- it cost Cosmos3-Super 720p 81f T2V ~4s of ~115s on 2xH200. |
| Cosmos3 Edge / distilled Super | Edge T2I: 640x640, 35 steps, 1 GPU; distilled Super T2I: 640x640, fixed 4-step schedule, 4 GPUs | Start eager with `--performance-mode manual`; use `SGLANG_DISABLE_COSMOS3_GUARDRAILS=1` only for benchmark isolation | Edge is trained for 256p/480p shapes. Distilled checkpoints own their sigma schedule and force guidance 1.0; do not override steps or flow shift. Do not retry the closed experimental Cosmos BCG path without a new lifecycle design. | | Cosmos3 Edge / distilled Super | Edge T2I: 640x640, 35 steps, 1 GPU; distilled Super T2I: 640x640, fixed 4-step schedule, 4 GPUs | Start eager with `--performance-mode manual`; use `SGLANG_DISABLE_COSMOS3_GUARDRAILS=1` only for benchmark isolation | Edge is trained for 256p/480p shapes. Distilled checkpoints own their sigma schedule and force guidance 1.0; do not override steps or flow shift. Do not retry the closed experimental Cosmos BCG path without a new lifecycle design. |
| Ideogram 4 FP8/NVFP4 | 1024x1024, native preset defaults | `--enable-torch-compile --warmup-mode request` | Do not set `--num-inference-steps` or `--guidance-scale` directly unless you also update the Ideogram preset; sampling params derive them from `preset`. | | Ideogram 4 FP8/NVFP4 | 1024x1024, native preset defaults | `--enable-torch-compile --warmup-mode request` | Do not set `--num-inference-steps` or `--guidance-scale` directly unless you also update the Ideogram preset; sampling params derive them from `preset`. |
@@ -397,7 +402,7 @@ Use these as first commands to benchmark, not as universal winners.
| JoyAI-Image-Edit | 1024-class TI2I, 40 steps, guidance 4.0 | `--backend=sglang --num-gpus 2 --enable-cfg-parallel --ulysses-degree 1 --enable-torch-compile --warmup-mode request --dit-layerwise-offload false --dit-cpu-offload false` | Newly supported image-edit path. Keep the input image, prompt, seed, and output size fixed; 2-GPU CFG parallel is the validated H100 starting point. | | JoyAI-Image-Edit | 1024-class TI2I, 40 steps, guidance 4.0 | `--backend=sglang --num-gpus 2 --enable-cfg-parallel --ulysses-degree 1 --enable-torch-compile --warmup-mode request --dit-layerwise-offload false --dit-cpu-offload false` | Newly supported image-edit path. Keep the input image, prompt, seed, and output size fixed; 2-GPU CFG parallel is the validated H100 starting point. |
| FireRed-Image-Edit 1.0 / 1.1 | 1024x1024 image edit, 40 steps, guidance 4.0 | `--backend=sglang --num-gpus 2 --enable-cfg-parallel --ulysses-degree 1 --enable-torch-compile --warmup-mode request --dit-layerwise-offload false --dit-cpu-offload false` | Uses the native `QwenImageEditPlusPipeline` path. 2-GPU CFG parallel is the validated H100 starting point; benchmark 1.0 and 1.1 separately because checkpoint differences can change denoise latency. | | FireRed-Image-Edit 1.0 / 1.1 | 1024x1024 image edit, 40 steps, guidance 4.0 | `--backend=sglang --num-gpus 2 --enable-cfg-parallel --ulysses-degree 1 --enable-torch-compile --warmup-mode request --dit-layerwise-offload false --dit-cpu-offload false` | Uses the native `QwenImageEditPlusPipeline` path. 2-GPU CFG parallel is the validated H100 starting point; benchmark 1.0 and 1.1 separately because checkpoint differences can change denoise latency. |
| Hunyuan3D-2 shape | Shape generation, 50 steps, guidance 5.0 | `--backend=sglang --enable-torch-compile --warmup-mode request --dit-layerwise-offload false --dit-cpu-offload false` | Focus on `Hunyuan3DShapeDenoisingStage`; keep mesh export/paint timings separate from denoise. | | Hunyuan3D-2 shape | Shape generation, 50 steps, guidance 5.0 | `--backend=sglang --enable-torch-compile --warmup-mode request --dit-layerwise-offload false --dit-cpu-offload false` | Focus on `Hunyuan3DShapeDenoisingStage`; keep mesh export/paint timings separate from denoise. |
| LingBot Video MoE 30B | 384x640, 17 frames, 12 steps for the current GPU case | `--model-path robbyant/lingbot-video-moe-30b-a3b --text-encoder-cpu-offload` | Native T2V path. Prompts are structured JSON captions, not raw free text; keep that contract when comparing latency or quality. Main still expands RMSNorm into PyTorch reduction chains; #35969 is an open `quality=high` Triton-dispatch candidate, not a current-main option until merged. | | LingBot Video MoE 30B | 384x640, 17 frames, 12 steps for the current GPU case | `--model-path robbyant/lingbot-video-moe-30b-a3b --text-encoder-cpu-offload` | Native T2V path. Prompts are structured JSON captions, not raw free text; keep that contract when comparing latency or quality. Current main can mount the fused Triton RMSNorm path at `quality=extra-high` or `quality=high`; keep `lossless` as the reference. |
| MOVA / Helios / LingBot World | Use the benchmark/profile presets or server test cases first | `--enable-torch-compile --warmup-mode request`; pin offload and topology flags explicitly | These video/realtime families have model-specific stages and condition handling. For LingBot World causal serving, keep `--kv-cache-quant off` as the exact cache baseline before testing INT4/INT2. | | MOVA / Helios / LingBot World | Use the benchmark/profile presets or server test cases first | `--enable-torch-compile --warmup-mode request`; pin offload and topology flags explicitly | These video/realtime families have model-specific stages and condition handling. For LingBot World causal serving, keep `--kv-cache-quant off` as the exact cache baseline before testing INT4/INT2. |
## Historical PR Watchlist ## Historical PR Watchlist
@@ -99,7 +99,8 @@ class SGLDiffusionServerAPI:
seed: Random seed for reproducible generation seed: Random seed for reproducible generation
enable_teacache: Enable TEA cache acceleration enable_teacache: Enable TEA cache acceleration
response_format: Response format ("b64_json" or "url") response_format: Response format ("b64_json" or "url")
quality: Image quality ("auto", "standard", "hd") - only for generation quality: Request optimization tier ("auto", "lossless",
"extra-high", "high") - only for generation
style: Image style ("vivid" or "natural") - only for generation style: Image style ("vivid" or "natural") - only for generation
background: Background type ("auto", "transparent", "opaque") background: Background type ("auto", "transparent", "opaque")
output_format: Output format ("png", "jpeg", "webp") output_format: Output format ("png", "jpeg", "webp")
@@ -51,10 +51,17 @@ def generate_request_id() -> str:
return str(uuid.uuid4()) return str(uuid.uuid4())
# Validated request-level quality levels. "lossless" is the exact reference # Validated request-level quality levels, ordered from the strictest numerical
# path (bit-exact against the CI golden outputs); "high" opts into validated # contract to the broadest optimization set. "lossless" keeps the exact
# accelerated paths whose quality is guaranteed but not bit-exact. # reference path; "extra-high" adds only request-gated kernel fusions; "high"
QUALITY_LEVELS: tuple[str, ...] = ("lossless", "high") # is cumulative and may also enable model-owned approximate optimizations.
QUALITY_LEVELS: tuple[str, ...] = ("lossless", "extra-high", "high")
KERNEL_FUSION_QUALITY_LEVELS = frozenset({"extra-high", "high"})
def quality_allows_kernel_fusions(quality: str) -> bool:
"""Return whether a quality level includes request-gated kernel fusions."""
return quality in KERNEL_FUSION_QUALITY_LEVELS
def _sanitize_filename(name: str, replacement: str = "_", max_length: int = 150) -> str: def _sanitize_filename(name: str, replacement: str = "_", max_length: int = 150) -> str:
@@ -141,15 +148,15 @@ class SamplingParams:
# - "lossless" (default): the exact reference path. Output is expected to # - "lossless" (default): the exact reference path. Output is expected to
# be bit-identical to the HF reference implementation and to pass the # be bit-identical to the HF reference implementation and to pass the
# CI golden/ground-truth comparisons. # CI golden/ground-truth comparisons.
# - "high": opt into validated accelerated paths. Quality stays # - "extra-high": add only validated kernel fusions. These may change
# guaranteed (the intent is to back every such path with mathematical # half-precision rounding order, so output is not bit-exact versus the
# acceptance thresholds, e.g. PSNR > 25 against the reference), but # reference, but this tier does not itself enable sparse or approximate
# the output is no longer bit-exact versus the HF reference or the CI # optimizations.
# ground truth. # - "high": include every "extra-high" fusion and allow model-owned
# approximate optimizations such as sparse computation or feature
# caching. These paths require model-specific quality validation.
# #
# Models that support "high" must validate the deployment and workload # It intentionally participates in the dynamic-batch signature.
# explicitly. It intentionally participates in the dynamic-batch
# signature.
quality: str = "lossless" quality: str = "lossless"
# Frame interpolation # Frame interpolation
@@ -1120,10 +1127,12 @@ class SamplingParams:
help=( help=(
"Request-level quality: 'lossless' (default) keeps the exact " "Request-level quality: 'lossless' (default) keeps the exact "
"reference path, bit-exact against the reference " "reference path, bit-exact against the reference "
"implementation; 'high' opts into the model-owned validated " "implementation; 'extra-high' adds only request-gated kernel "
"accelerated path, whose quality stays guaranteed but is not " "fusions and does not itself enable sparse or approximate "
"bit-exact. Support and validated deployment constraints are " "optimization; 'high' includes every extra-high fusion and "
"model-specific." "may also enable "
"model-owned approximate paths. Support and validated "
"deployment constraints are model-specific."
), ),
) )
add_argument( add_argument(
@@ -169,10 +169,11 @@ def _flux_norm_modulate(
"""``norm(x) * (1 + scale) + shift`` for the FLUX adaLN sites. """``norm(x) * (1 + scale) + shift`` for the FLUX adaLN sites.
Priority: (1) the bit-exact single-kernel LN+modulate -- lossless, so it Priority: (1) the bit-exact single-kernel LN+modulate -- lossless, so it
needs no quality gate and also supersedes the ``quality="high"`` affine needs no quality gate and also supersedes the request-gated affine
fold wherever it verifies; (2) when the site is mounted fold wherever it verifies; (2) when the site is mounted
(``quality="high"``) and the bit-exact kernel is unavailable, the (``quality="extra-high"`` or ``"high"``) and the bit-exact kernel is
modulate folded into the LN affine (one aten kernel; not bit-exact); unavailable, the modulate folded into the LN affine (one aten kernel; not
bit-exact);
(3) affine-free LayerNorm + the bit-exact fused modulate. (3) affine-free LayerNorm + the bit-exact fused modulate.
""" """
out = _flux_fused_ln_modulate(norm, x, scale, shift) out = _flux_fused_ln_modulate(norm, x, scale, shift)
@@ -387,7 +388,7 @@ class FluxGELU(nn.Module):
prefix=f"{prefix}.proj" if prefix else "proj", prefix=f"{prefix}.proj" if prefix else "proj",
) )
self.gelu = nn.GELU(approximate="tanh") self.gelu = nn.GELU(approximate="tanh")
# quality="high" fusion site: up-proj GEMM + tanh-GELU in the cublasLt # extra-high/high fusion site: up-proj GEMM + tanh-GELU in the cublasLt
# epilogue. Off by default; mounted per batch by the denoising stage. # epilogue. Off by default; mounted per batch by the denoising stage.
mark_fused_gelu_site(self, "proj") mark_fused_gelu_site(self, "proj")
@@ -407,7 +408,7 @@ class FluxFusedGELUProj(nn.Module):
``approximate="tanh"`` that keeps the ``net.0.proj`` parameter path. The ``approximate="tanh"`` that keeps the ``net.0.proj`` parameter path. The
default path is the bit-exact reference (plain Linear + tanh-GELU); the default path is the bit-exact reference (plain Linear + tanh-GELU); the
cublasLt GELU epilogue is mounted per batch by the denoising stage for cublasLt GELU epilogue is mounted per batch by the denoising stage for
quality="high" requests only. requests with ``quality="extra-high"`` or ``quality="high"`` only.
""" """
def __init__(self, proj: nn.Linear): def __init__(self, proj: nn.Linear):
@@ -790,7 +791,7 @@ class FluxSingleTransformerBlock(nn.Module):
prefix=f"{prefix}.proj_mlp" if prefix else "proj_mlp", prefix=f"{prefix}.proj_mlp" if prefix else "proj_mlp",
) )
self.act_mlp = nn.GELU(approximate="tanh") self.act_mlp = nn.GELU(approximate="tanh")
# quality="high" fusion site: proj_mlp GEMM + tanh-GELU in the # extra-high/high fusion site: proj_mlp GEMM + tanh-GELU in the
# cublasLt epilogue (mounted per batch by the denoising stage). # cublasLt epilogue (mounted per batch by the denoising stage).
mark_fused_gelu_site(self, "proj_mlp") mark_fused_gelu_site(self, "proj_mlp")
proj_out_cls = ( proj_out_cls = (
@@ -954,7 +955,7 @@ class FluxTransformerBlock(nn.Module):
self.norm2 = LayerNorm(dim, eps=1e-6, elementwise_affine=False) self.norm2 = LayerNorm(dim, eps=1e-6, elementwise_affine=False)
self.norm2_context = LayerNorm(dim, eps=1e-6, elementwise_affine=False) self.norm2_context = LayerNorm(dim, eps=1e-6, elementwise_affine=False)
# quality="high" site: the norm2/norm2_context modulate folds into the # extra-high/high site: norm2/norm2_context modulate folds into the
# LN affine when mounted. # LN affine when mounted.
mark_fused_ln_modulate_site(self) mark_fused_ln_modulate_site(self)
@@ -1009,7 +1010,7 @@ class FluxTransformerBlock(nn.Module):
activation_fn="gelu-approximate", activation_fn="gelu-approximate",
) )
# Re-home each FF's tanh-GELU up-projection onto a marked # Re-home each FF's tanh-GELU up-projection onto a marked
# quality="high" fusion site (bit-exact reference by default). # extra-high/high fusion site (bit-exact reference by default).
self.ff.net[0] = FluxFusedGELUProj(self.ff.net[0].proj) self.ff.net[0] = FluxFusedGELUProj(self.ff.net[0].proj)
self.ff_context.net[0] = FluxFusedGELUProj(self.ff_context.net[0].proj) self.ff_context.net[0] = FluxFusedGELUProj(self.ff_context.net[0].proj)
@@ -447,7 +447,7 @@ class GlmImageGELU(nn.Module):
quant_config=quant_config, quant_config=quant_config,
prefix=f"{prefix}.proj" if prefix else "proj", prefix=f"{prefix}.proj" if prefix else "proj",
) )
# quality="high" fusion site: up-proj GEMM + tanh-GELU in the cublasLt # extra-high/high fusion site: up-proj GEMM + tanh-GELU in cublasLt
# epilogue. Off by default; mounted per batch by the denoising stage. # epilogue. Off by default; mounted per batch by the denoising stage.
mark_fused_gelu_site(self, "proj") mark_fused_gelu_site(self, "proj")
@@ -421,7 +421,7 @@ def _norm_scale(
norm: Ideogram4RMSNorm, norm: Ideogram4RMSNorm,
enable_fused: bool, enable_fused: bool,
) -> torch.Tensor: ) -> torch.Tensor:
"""``RMSNorm(x) * (1 + scale)``, fused for ``quality="high"`` batches.""" """``RMSNorm(x) * (1 + scale)``, fused at extra-high or high quality."""
if enable_fused: if enable_fused:
y = fused_rmsnorm_scale( y = fused_rmsnorm_scale(
x, x,
@@ -455,7 +455,7 @@ def _gate_residual(
norm: Ideogram4RMSNorm, norm: Ideogram4RMSNorm,
enable_fused: bool, enable_fused: bool,
) -> torch.Tensor: ) -> torch.Tensor:
"""``residual + tanh(gate) * RMSNorm(x)``, fused for ``quality="high"``.""" """``residual + tanh(gate) * RMSNorm(x)``, fused at extra-high or high."""
if enable_fused: if enable_fused:
y = fused_rmsnorm_tanh_residual( y = fused_rmsnorm_tanh_residual(
x, x,
@@ -511,7 +511,7 @@ class Ideogram4TransformerBlock(nn.Module):
self.ffn_norm1 = Ideogram4RMSNorm(hidden_size, eps=norm_eps) self.ffn_norm1 = Ideogram4RMSNorm(hidden_size, eps=norm_eps)
self.attention_norm2 = Ideogram4RMSNorm(hidden_size, eps=norm_eps) self.attention_norm2 = Ideogram4RMSNorm(hidden_size, eps=norm_eps)
self.ffn_norm2 = Ideogram4RMSNorm(hidden_size, eps=norm_eps) self.ffn_norm2 = Ideogram4RMSNorm(hidden_size, eps=norm_eps)
# quality="high" fusion sites: each RMSNorm modulate/gate chain # extra-high/high fusion sites: each RMSNorm modulate/gate chain
# collapses into one Triton kernel (Z-Image bf16-native suite). Off by # collapses into one Triton kernel (Z-Image bf16-native suite). Off by
# default (bit-exact reference path); mounted per batch by the # default (bit-exact reference path); mounted per batch by the
# denoising stage. # denoising stage.
@@ -222,7 +222,7 @@ class _LongCatFFN(nn.Module):
] ]
) )
self.act = nn.GELU(approximate="tanh") self.act = nn.GELU(approximate="tanh")
# quality="high" site: up-proj GEMM + tanh-GELU cublasLt epilogue. Off by # extra-high/high site: up-proj GEMM + tanh-GELU epilogue. Off by
# default; the denoising stage mounts it per batch. The ModuleDict holds # default; the denoising stage mounts it per batch. The ModuleDict holds
# `proj` in _modules, so getattr resolves it for the fusion helper. # `proj` in _modules, so getattr resolves it for the fusion helper.
mark_fused_gelu_site(self.net[0], "proj") mark_fused_gelu_site(self.net[0], "proj")
@@ -511,7 +511,7 @@ class _SingleTransformerBlock(nn.Module):
prefix=f"{prefix}.proj_mlp", prefix=f"{prefix}.proj_mlp",
) )
self.act_mlp = nn.GELU(approximate="tanh") self.act_mlp = nn.GELU(approximate="tanh")
# quality="high" site: proj_mlp GEMM + tanh-GELU cublasLt epilogue, # extra-high/high site: proj_mlp GEMM + tanh-GELU epilogue,
# mounted per batch by the denoising stage; off (bit-exact) by default. # mounted per batch by the denoising stage; off (bit-exact) by default.
mark_fused_gelu_site(self, "proj_mlp") mark_fused_gelu_site(self, "proj_mlp")
# proj_out: RowParallelLinear reduces sharded [attn | mlp] concat via # proj_out: RowParallelLinear reduces sharded [attn | mlp] concat via
@@ -198,7 +198,7 @@ def _ltx2_rms_norm_modulate(
"""``rms_norm(x) * (1 + scale) + shift`` for the LTX-2 adaLN sites. """``rms_norm(x) * (1 + scale) + shift`` for the LTX-2 adaLN sites.
Folds the weightless RMSNorm and the modulate into one kernel when the Folds the weightless RMSNorm and the modulate into one kernel when the
``quality="high"`` fusion is mounted on ``block`` and the per-call guard request-gated fusion is mounted on ``block`` and the per-call guard
passes; otherwise the verbatim eager reference chain (the ``lossless`` passes; otherwise the verbatim eager reference chain (the ``lossless``
default). The fused kernel is not bit-exact (<=1 bf16 ULP) so it is gated default). The fused kernel is not bit-exact (<=1 bf16 ULP) so it is gated
on the request-scoped mount rather than a runtime self-check. on the request-scoped mount rather than a runtime self-check.
@@ -824,7 +824,7 @@ class QwenImageCrossAttention(nn.Module):
) )
if self._unquantized_added_qkv_is_packed: if self._unquantized_added_qkv_is_packed:
# Packing changes BF16 GEMM reduction association. Keep it # Packing changes BF16 GEMM reduction association. Keep it
# off for lossless requests and mount it for quality=high. # off for lossless and mount it at extra-high or high.
mark_qwen_image_added_qkv_site(self) mark_qwen_image_added_qkv_site(self)
else: else:
self.add_q_proj = ColumnParallelLinear( self.add_q_proj = ColumnParallelLinear(
@@ -1171,7 +1171,7 @@ class QwenImageGELU(nn.Module):
quant_config=quant_config, quant_config=quant_config,
prefix=f"{prefix}.proj", prefix=f"{prefix}.proj",
) )
# quality="high" fusion site: up-proj GEMM + tanh-GELU in the cublasLt # Extra-high-or-higher fusion site: up-proj GEMM + tanh-GELU in cublasLt
# epilogue. Off by default; mounted per batch by the denoising stage. # epilogue. Off by default; mounted per batch by the denoising stage.
mark_fused_gelu_site(self, "proj") mark_fused_gelu_site(self, "proj")
@@ -8,8 +8,9 @@ decoder module family (``ResnetBlock2D`` GroupNorm+SiLU chains,
All rewrites are mathematically exact re-associations of the original All rewrites are mathematically exact re-associations of the original
operators. Wrappers are installed once at VAE load and dispatch on a operators. Wrappers are installed once at VAE load and dispatch on a
decode-scoped :class:`VaeFastPathGate`: ``quality == "high"`` runs the fast decode-scoped :class:`VaeFastPathGate`: ``quality="extra-high"`` and
paths, the ``"lossless"`` default runs the original module path bit-for-bit. ``quality="high"`` run the fast paths, while the ``"lossless"`` default runs
the original module path bit-for-bit.
- channels_last: run the decoder in NHWC so cuDNN convs skip the transpose - channels_last: run the decoder in NHWC so cuDNN convs skip the transpose
kernels; parameter layout is swapped at decode entry to match the gate. kernels; parameter layout is swapped at decode entry to match the gate.
@@ -3,10 +3,10 @@
Fuses every decoder ``WanRMS_norm -> SiLU`` chain into one Triton kernel on Fuses every decoder ``WanRMS_norm -> SiLU`` chain into one Triton kernel on
the channels_last_3d layout. Wrappers are installed once at VAE load and the channels_last_3d layout. Wrappers are installed once at VAE load and
dispatch on a decode-scoped :class:`VaeFastPathGate`: ``quality == "high"`` dispatch on a decode-scoped :class:`VaeFastPathGate`: ``quality="extra-high"``
runs the fused kernel (not bitwise-identical to aten, hence gated), the and ``quality="high"`` run the fused kernel (not bitwise-identical to aten,
``"lossless"`` default runs the original module path bit-for-bit. Install is hence gated), while the ``"lossless"`` default runs the original module path
all-or-nothing and fail-closed. bit-for-bit. Install is all-or-nothing and fail-closed.
""" """
import torch import torch
@@ -10,6 +10,9 @@ import weakref
import torch import torch
import torch.nn as nn import torch.nn as nn
from sglang.multimodal_gen.configs.sample.sampling_params import (
quality_allows_kernel_fusions,
)
from sglang.multimodal_gen.runtime.distributed import ( from sglang.multimodal_gen.runtime.distributed import (
get_decode_parallel_world_size, get_decode_parallel_world_size,
get_local_torch_device, get_local_torch_device,
@@ -333,7 +336,10 @@ class DecodingStage(PipelineStage):
assert vae is not None assert vae is not None
self.vae = vae self.vae = vae
with use_vae_fast_path(vae, batch.sampling_params.quality == "high"): with use_vae_fast_path(
vae,
quality_allows_kernel_fusions(batch.sampling_params.quality),
):
frames = self.decode(batch.latents, server_args, vae_dtype=vae_dtype) frames = self.decode(batch.latents, server_args, vae_dtype=vae_dtype)
# decode trajectory latents if needed # decode trajectory latents if needed
@@ -49,6 +49,9 @@ from sglang.multimodal_gen.configs.pipeline_configs.flux import (
FluxPipelineConfig, FluxPipelineConfig,
) )
from sglang.multimodal_gen.configs.pipeline_configs.zimage import ZImagePipelineConfig from sglang.multimodal_gen.configs.pipeline_configs.zimage import ZImagePipelineConfig
from sglang.multimodal_gen.configs.sample.sampling_params import (
quality_allows_kernel_fusions,
)
from sglang.multimodal_gen.runtime.breakable_cuda_graph import ( from sglang.multimodal_gen.runtime.breakable_cuda_graph import (
prompt_padding as bcg_utils, prompt_padding as bcg_utils,
) )
@@ -326,7 +329,7 @@ class DenoisingStage(PipelineStage, RolloutDenoisingMixin):
self._cache_dit_request_overrides: dict[str, Any] = {} self._cache_dit_request_overrides: dict[str, Any] = {}
# Overrides key the mounted hooks were built from; None when unmounted. # Overrides key the mounted hooks were built from; None when unmounted.
self._cache_dit_active_key: tuple | None = None self._cache_dit_active_key: tuple | None = None
# Whether request-scoped quality="high" fusions are currently mounted. # Whether request-scoped extra-high-or-higher fusions are mounted.
self._quality_fusions_mounted = False self._quality_fusions_mounted = False
self._torch_compile_registry = CompiledModuleRegistry() self._torch_compile_registry = CompiledModuleRegistry()
# Breakable CUDA graph runners, one per transformer module (lazy). # Breakable CUDA graph runners, one per transformer module (lazy).
@@ -666,17 +669,18 @@ class DenoisingStage(PipelineStage, RolloutDenoisingMixin):
return stage_backend return stage_backend
def _maybe_toggle_quality_fusions(self, batch: Req) -> None: def _maybe_toggle_quality_fusions(self, batch: Req) -> None:
"""Mount/unmount the ``quality="high"`` fusions for this batch. """Mount/unmount request-gated kernel fusions for this batch.
These fusions are numerically equivalent only at half-precision These fusions are numerically equivalent only at half-precision
rounding level (not bit-exact), so they are mounted for rounding level (not bit-exact), so they are mounted for both
``quality="high"`` requests and unmounted otherwise. The ``quality="extra-high"`` and ``quality="high"``. The ``"lossless"``
``"lossless"`` default runs the reference path bit-for-bit. ``quality`` default runs the reference path bit-for-bit. ``quality`` participates
participates in the dynamic-batch signature, making this transition in the dynamic-batch signature, making this transition safe at the
safe at the batch boundary. Mounting is all-or-nothing per transformer batch boundary. Mounting is all-or-nothing per transformer and fusion
and fusion family; models without marked sites are no-ops. family; models without marked sites are no-ops.
""" """
want = getattr(batch.sampling_params, "quality", "lossless") == "high" quality = getattr(batch.sampling_params, "quality", "lossless")
want = quality_allows_kernel_fusions(quality)
if want == self._quality_fusions_mounted: if want == self._quality_fusions_mounted:
return return
mounted_fusions: set[str] = set() mounted_fusions: set[str] = set()
@@ -694,7 +698,7 @@ class DenoisingStage(PipelineStage, RolloutDenoisingMixin):
unmount(transformer) unmount(transformer)
descriptions = ", ".join(sorted(mounted_fusions)) descriptions = ", ".join(sorted(mounted_fusions))
raise ValueError( raise ValueError(
"quality='high' cannot be used with breakable CUDA graphs for " f"quality={quality!r} cannot be used with breakable CUDA graphs for "
f"this model because its request-scoped DiT fusions " f"this model because its request-scoped DiT fusions "
f"({descriptions}) do not match the lossless warmup graphs. " f"({descriptions}) do not match the lossless warmup graphs. "
"Disable breakable CUDA graphs or use quality='lossless'." "Disable breakable CUDA graphs or use quality='lossless'."
@@ -702,7 +706,7 @@ class DenoisingStage(PipelineStage, RolloutDenoisingMixin):
self._quality_fusions_mounted = want self._quality_fusions_mounted = want
for description in sorted(mounted_fusions): for description in sorted(mounted_fusions):
logger.info("Mounted %s for quality=high", description) logger.info("Mounted %s for quality=%s", description, quality)
def _cache_dit_dual_model_name(self) -> str: def _cache_dit_dual_model_name(self) -> str:
return "wan2.2" return "wan2.2"
@@ -685,8 +685,8 @@ class CudaPlatformBase(Platform):
"""Install the quality-gated FLUX.2 / AutoencoderKL / Wan VAE decoder """Install the quality-gated FLUX.2 / AutoencoderKL / Wan VAE decoder
fast paths. fast paths.
Requests with quality == "high" run the fast paths; the "lossless" Requests with quality="extra-high" or "high" run the fast paths; the
default runs the original module path bit-for-bit. See "lossless" default runs the original module path bit-for-bit. See
flux2_vae_cuda_opt and wan_vae_cuda_opt for details. flux2_vae_cuda_opt and wan_vae_cuda_opt for details.
""" """
try: try:
@@ -70,7 +70,9 @@ class TestQualityFusionBCGCompatibility(unittest.TestCase):
def _batch(quality: str): def _batch(quality: str):
return SimpleNamespace(sampling_params=SimpleNamespace(quality=quality)) return SimpleNamespace(sampling_params=SimpleNamespace(quality=quality))
def test_rejects_high_when_dit_fusion_would_replace_captured_graph(self): def test_rejects_fusion_levels_when_they_would_replace_captured_graph(self):
for quality in ("extra-high", "high"):
with self.subTest(quality=quality):
unmounted = [] unmounted = []
handlers = ( handlers = (
( (
@@ -80,9 +82,11 @@ class TestQualityFusionBCGCompatibility(unittest.TestCase):
), ),
) )
with patch.object(denoising_module, "_QUALITY_FUSION_HANDLERS", handlers): with patch.object(
denoising_module, "_QUALITY_FUSION_HANDLERS", handlers
):
with self.assertRaisesRegex(ValueError, "lossless warmup graphs"): with self.assertRaisesRegex(ValueError, "lossless warmup graphs"):
self.stage._maybe_toggle_quality_fusions(self._batch("high")) self.stage._maybe_toggle_quality_fusions(self._batch(quality))
self.assertEqual(unmounted, [self.stage.transformer]) self.assertEqual(unmounted, [self.stage.transformer])
self.assertFalse(self.stage._quality_fusions_mounted) self.assertFalse(self.stage._quality_fusions_mounted)
@@ -95,6 +99,21 @@ class TestQualityFusionBCGCompatibility(unittest.TestCase):
self.assertTrue(self.stage._quality_fusions_mounted) self.assertTrue(self.stage._quality_fusions_mounted)
def test_high_keeps_extra_high_fusions_mounted(self):
self.stage.server_args.enable_breakable_cuda_graph = False
mounted = []
handlers = (
("test fusion", lambda _: mounted.append(True) or True, lambda _: None),
)
with patch.object(denoising_module, "_QUALITY_FUSION_HANDLERS", handlers):
self.stage._maybe_toggle_quality_fusions(self._batch("extra-high"))
self.assertTrue(self.stage._quality_fusions_mounted)
self.stage._maybe_toggle_quality_fusions(self._batch("high"))
self.assertEqual(mounted, [True])
self.assertTrue(self.stage._quality_fusions_mounted)
def _fake_cache_dit_batch(*, is_warmup: bool) -> SimpleNamespace: def _fake_cache_dit_batch(*, is_warmup: bool) -> SimpleNamespace:
return SimpleNamespace( return SimpleNamespace(
@@ -257,6 +257,12 @@ class TestDiffusionBenchmarkSkill(unittest.TestCase):
self.assertIn("--quality=high", high_cmd) self.assertIn("--quality=high", high_cmd)
self.assertNotIn("--enable-breakable-cuda-graph", high_cmd) self.assertNotIn("--enable-breakable-cuda-graph", high_cmd)
extra_high_cmd = module.build_sglang_cmd(
"longcat-image", quality="extra-high"
)
self.assertIn("--quality=extra-high", extra_high_cmd)
self.assertNotIn("--enable-breakable-cuda-graph", extra_high_cmd)
bcg_cmd = module.build_sglang_cmd( bcg_cmd = module.build_sglang_cmd(
"longcat-image", "longcat-image",
breakable_cuda_graph=True, breakable_cuda_graph=True,
@@ -538,6 +544,37 @@ class TestDiffusionBenchmarkSkill(unittest.TestCase):
[module.BCG_LATE_QUALITY_FUSION_SIGNAL], [module.BCG_LATE_QUALITY_FUSION_SIGNAL],
) )
def test_extra_high_bcg_rejects_quality_fusion_mounted_after_capture(self):
with tempfile.TemporaryDirectory() as tmpdir:
temp_root = Path(tmpdir)
module = _load_benchmark_module(temp_root)
output_dir = temp_root / "outputs"
output_dir.mkdir()
with patch.object(module.subprocess, "Popen") as popen:
popen.return_value.stdout = iter(
(
"[Diffusion BCG] captured 3 segment(s)\n",
"Mounted Qwen fused added-QKV for quality=extra-high\n",
)
)
popen.return_value.wait.return_value = 0
result = module._run_benchmark_once_impl(
"longcat-image",
"bcg-extra-high",
output_dir,
warmup=False,
quality="extra-high",
breakable_cuda_graph=True,
cuda_visible_devices="0",
)
self.assertTrue(result["error"])
self.assertEqual(
result["bcg_invalid_signals"],
[module.BCG_LATE_QUALITY_FUSION_SIGNAL],
)
def test_quality_bcg_matrix_reuses_one_gpu_set_and_cleans_once(self): def test_quality_bcg_matrix_reuses_one_gpu_set_and_cleans_once(self):
with tempfile.TemporaryDirectory() as tmpdir: with tempfile.TemporaryDirectory() as tmpdir:
temp_root = Path(tmpdir) temp_root = Path(tmpdir)
@@ -564,7 +601,7 @@ class TestDiffusionBenchmarkSkill(unittest.TestCase):
cleanup_model_cache=True, cleanup_model_cache=True,
) )
self.assertEqual(len(results), 8) self.assertEqual(len(results), 12)
self.assertEqual( self.assertEqual(
[ [
(call[2]["quality"], call[2]["breakable_cuda_graph"]) (call[2]["quality"], call[2]["breakable_cuda_graph"])
@@ -23,6 +23,7 @@ from sglang.multimodal_gen.runtime.managers.memory_managers.component_residency
LAYERWISE_OFFLOAD, LAYERWISE_OFFLOAD,
RESIDENT, RESIDENT,
) )
from sglang.multimodal_gen.runtime.pipelines_core.stages.denoising import DenoisingStage
from sglang.multimodal_gen.runtime.pipelines_core.stages.model_specific_stages.minimax_h3.release_metadata import ( from sglang.multimodal_gen.runtime.pipelines_core.stages.model_specific_stages.minimax_h3.release_metadata import (
MiniMaxH3PartitionAdmissionStage, MiniMaxH3PartitionAdmissionStage,
MiniMaxH3ReleaseMetadata, MiniMaxH3ReleaseMetadata,
@@ -351,6 +352,31 @@ def test_high_quality_request_warns_when_bcg_suppresses_cache_dit():
) )
def test_extra_high_quality_does_not_enable_h3_cache_dit():
stage = MiniMaxH3DenoisingStage.__new__(MiniMaxH3DenoisingStage)
stage.server_args = SimpleNamespace(enable_breakable_cuda_graph=False)
stage._cache_dit_enabled = False
stage._minimax_h3_cache_mode = None
stage._minimax_h3_quality = "lossless"
batch = SimpleNamespace(
sampling_params=SimpleNamespace(
quality="extra-high",
_explicit_fields={"quality"},
enable_cache_dit=None,
cache_dit_params=None,
)
)
# Even a server-wide generic Cache-DiT default must not turn an explicit
# fusion-only quality tier into an approximate H3 request.
with patch.object(DenoisingStage, "_cache_dit_requested", return_value=True):
stage._maybe_enable_cache_dit(50, batch)
assert stage._minimax_h3_quality == "extra-high"
assert stage._minimax_h3_cache_mode is None
assert not stage._cache_dit_enabled
def test_quality_admission_fails_closed_outside_validated_request(): def test_quality_admission_fails_closed_outside_validated_request():
metadata = MiniMaxH3ReleaseMetadata.from_model_index( metadata = MiniMaxH3ReleaseMetadata.from_model_index(
{ {
@@ -405,6 +431,9 @@ def test_quality_admission_fails_closed_outside_validated_request():
server_args.attention_backend = "sage_attn" server_args.attention_backend = "sage_attn"
assert stage.forward(batch, server_args) is batch assert stage.forward(batch, server_args) is batch
batch.sampling_params.quality = "extra-high"
assert stage.forward(batch, server_args) is batch
batch.sampling_params.quality = "ultra" batch.sampling_params.quality = "ultra"
server_args.attention_backend = None server_args.attention_backend = None
with pytest.raises(ValueError, match="quality must be one of"): with pytest.raises(ValueError, match="quality must be one of"):
@@ -58,6 +58,7 @@ def test_runtime_sampling_quality_preserves_the_openai_default():
assert _runtime_sampling_quality(None) is None assert _runtime_sampling_quality(None) is None
assert _runtime_sampling_quality("auto") is None assert _runtime_sampling_quality("auto") is None
assert _runtime_sampling_quality("lossless") == "lossless" assert _runtime_sampling_quality("lossless") == "lossless"
assert _runtime_sampling_quality("extra-high") == "extra-high"
assert _runtime_sampling_quality("high") == "high" assert _runtime_sampling_quality("high") == "high"
@@ -149,6 +149,13 @@ class TestDiffusionPrecisionConsistency(unittest.TestCase):
), ),
torch.bfloat16, torch.bfloat16,
) )
self.assertEqual(
resolve_decode_precision(
self._server_args(vae_decode_precision_high="bf16"),
quality="extra-high",
),
torch.float16,
)
self.assertEqual( self.assertEqual(
resolve_decode_precision( resolve_decode_precision(
self._server_args(vae_decode_precision_high="bf16"), self._server_args(vae_decode_precision_high="bf16"),
@@ -26,8 +26,10 @@ from sglang.multimodal_gen.configs.sample.glmimage import (
) )
from sglang.multimodal_gen.configs.sample.qwenimage import QwenImageSamplingParams from sglang.multimodal_gen.configs.sample.qwenimage import QwenImageSamplingParams
from sglang.multimodal_gen.configs.sample.sampling_params import ( from sglang.multimodal_gen.configs.sample.sampling_params import (
QUALITY_LEVELS,
SamplingParams, SamplingParams,
_json_safe, _json_safe,
quality_allows_kernel_fusions,
) )
from sglang.multimodal_gen.configs.sample.spectrum import SpectrumParams from sglang.multimodal_gen.configs.sample.spectrum import SpectrumParams
from sglang.multimodal_gen.configs.sample.teacache import TeaCacheParams from sglang.multimodal_gen.configs.sample.teacache import TeaCacheParams
@@ -52,9 +54,15 @@ class TestSamplingParamsValidate(unittest.TestCase):
def test_quality_defaults_to_lossless(self): def test_quality_defaults_to_lossless(self):
self.assertEqual(SamplingParams().quality, "lossless") self.assertEqual(SamplingParams().quality, "lossless")
def test_quality_accepts_the_two_validated_levels(self): def test_quality_levels_are_cumulative(self):
self.assertEqual(SamplingParams(quality="lossless").quality, "lossless") self.assertEqual(QUALITY_LEVELS, ("lossless", "extra-high", "high"))
self.assertEqual(SamplingParams(quality="high").quality, "high") for quality in QUALITY_LEVELS:
with self.subTest(quality=quality):
self.assertEqual(SamplingParams(quality=quality).quality, quality)
self.assertFalse(quality_allows_kernel_fusions("lossless"))
self.assertTrue(quality_allows_kernel_fusions("extra-high"))
self.assertTrue(quality_allows_kernel_fusions("high"))
def test_quality_rejects_invalid_values(self): def test_quality_rejects_invalid_values(self):
for bad in ("ultra", "draft", "fast", "", True, 1): for bad in ("ultra", "draft", "fast", "", True, 1):
@@ -338,8 +346,10 @@ class TestSamplingParamsCliArgs(unittest.TestCase):
def test_quality_is_request_scoped_cli_arg(self): def test_quality_is_request_scoped_cli_arg(self):
self.assertNotIn("quality", self._parse_cli_kwargs([])) self.assertNotIn("quality", self._parse_cli_kwargs([]))
for quality in ("extra-high", "high"):
with self.subTest(quality=quality):
self.assertEqual( self.assertEqual(
self._parse_cli_kwargs(["--quality", "high"])["quality"], "high" self._parse_cli_kwargs(["--quality", quality])["quality"], quality
) )
def test_get_cli_args_maps_spectrum_prefixed_flags(self): def test_get_cli_args_maps_spectrum_prefixed_flags(self):