Instructions to use stabilityai/stable-audio-3-optimized with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Stable Audio 3
How to use stabilityai/stable-audio-3-optimized with Stable Audio 3:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
sm_120 SAME-L: AOT (graph-capturable) engines + tensorRT/README.md
#6
by cortexelus - opened
tensorRT/README.md
CHANGED
|
@@ -0,0 +1,177 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Stable Audio 3 β TensorRT engines
|
| 2 |
+
|
| 3 |
+
Prebuilt TensorRT engines for the Stable Audio 3 stack, organised by CUDA architecture.
|
| 4 |
+
|
| 5 |
+
```
|
| 6 |
+
tensorRT/sm_90/ Hopper β H100, H200
|
| 7 |
+
tensorRT/sm_120/ Blackwell β RTX 5090, RTX PRO 6000, RTX PRO 4500
|
| 8 |
+
```
|
| 9 |
+
|
| 10 |
+
TensorRT engines are **not portable across architectures** β an `sm_90` engine will not
|
| 11 |
+
load on an `sm_120` GPU. They are also tied to the TensorRT version they were built with
|
| 12 |
+
(these were built with **TensorRT 10.15.1.29**). If your GPU or TensorRT version is not
|
| 13 |
+
covered here, build from the ONNX in `onnx/` using the scripts in
|
| 14 |
+
[`optimized/tensorRT/build/`](https://github.com/Stability-AI/stable-audio-3/tree/main/optimized/tensorRT/build).
|
| 15 |
+
|
| 16 |
+
| directory | contents |
|
| 17 |
+
|---|---|
|
| 18 |
+
| `sa3-m/` | medium DiT (the main diffusion transformer) |
|
| 19 |
+
| `sa3-sm-music/`, `sa3-sm-sfx/` | small domain-specialised DiTs |
|
| 20 |
+
| `same-l/`, `same-s/` | autoencoder (SAME) encoder + decoder |
|
| 21 |
+
| `t5gemma/` | text conditioner, plus its tokenizer |
|
| 22 |
+
|
| 23 |
+
---
|
| 24 |
+
|
| 25 |
+
## The SAME-L attention kernel: two implementations
|
| 26 |
+
|
| 27 |
+
The SAME-L encoder and decoder use a custom sliding-window-attention plugin
|
| 28 |
+
(`samel::diff_attn_swa`) for differential attention, which TensorRT has no native op for.
|
| 29 |
+
That plugin ships **two implementations**, and *which one an engine uses is fixed when the
|
| 30 |
+
engine is built* β it is baked into the `.trt` file and cannot be changed at load time.
|
| 31 |
+
|
| 32 |
+
**AOT** (ahead-of-time) compiles a block-tiled tensor-core kernel to PTX and embeds it in
|
| 33 |
+
the engine. No Python runs during inference. **JIT** dispatches a Triton kernel through a
|
| 34 |
+
Python callback on every enqueue β 12 callbacks per decode, one per attention layer.
|
| 35 |
+
|
| 36 |
+
| | AOT | JIT |
|
| 37 |
+
|---|---|---|
|
| 38 |
+
| CUDA-graph capturable | **yes, both architectures** | sm_90 only β **fails on sm_120** |
|
| 39 |
+
| Python / Triton calls per decode | **0** | 12 |
|
| 40 |
+
| Triton needed at inference | no | **yes** |
|
| 41 |
+
| Engine size | +0.1% | baseline |
|
| 42 |
+
|
| 43 |
+
### Which files use which
|
| 44 |
+
|
| 45 |
+
| published engines | kernel | why |
|
| 46 |
+
|---|---|---|
|
| 47 |
+
| `sm_120/same-l/` | **AOT** (block-tiled MMA) | required β the JIT build is not capturable on sm_120 |
|
| 48 |
+
| `sm_90/same-l/` | **JIT** | works, and AOT measured no faster on Hopper, so these were left alone |
|
| 49 |
+
|
| 50 |
+
So on **sm_90 you need Triton installed to run** the `same-l` engines, and on **sm_120 you
|
| 51 |
+
do not**. Both implementations stay registered by the runtime, so either kind of engine
|
| 52 |
+
loads and runs regardless of which GPU you are on.
|
| 53 |
+
|
| 54 |
+
For anything you build yourself, **AOT is the default on every architecture** β it is the
|
| 55 |
+
only correct choice on sm_120, it is at parity on sm_90, and it drops the runtime Triton
|
| 56 |
+
dependency. Rebuilding the `sm_90` engines would therefore give you AOT rather than the
|
| 57 |
+
JIT files published here; that is expected and fine, not a mismatch.
|
| 58 |
+
|
| 59 |
+
### Why JIT breaks on sm_120
|
| 60 |
+
|
| 61 |
+
The runtime captures the whole pipeline into one CUDA graph. A JIT engine cannot be
|
| 62 |
+
captured on sm_120: `enqueueV3` returns `False`, TensorRT logs *"this TRT engine is not
|
| 63 |
+
stream capturable"*, and **the decode stage is silently omitted from the graph** β no
|
| 64 |
+
exception, no non-zero exit.
|
| 65 |
+
|
| 66 |
+
What you get is the pre-capture warm-up decode of zero latents: a constant wash of noise,
|
| 67 |
+
**byte-identical for every prompt and every seed**, with exit code 0. If you ever see
|
| 68 |
+
that, this is the first thing to check. The diagnostic is to render twice with different
|
| 69 |
+
seeds and compare the files β identical bytes mean the decode never ran.
|
| 70 |
+
|
| 71 |
+
The same engine captures without complaint on sm_90, which is why the problem did not
|
| 72 |
+
surface until Blackwell. Re-entering Python inside a captured region was always fragile
|
| 73 |
+
rather than supported, so do not assume a future architecture will tolerate it either.
|
| 74 |
+
|
| 75 |
+
The decode is inside the captured region on the default path: `sa3_trt.py` captures T5 β
|
| 76 |
+
DiT loop β decoder β PCM copy as one graph whenever `--cfg 1.0` and no inpaint/init-audio
|
| 77 |
+
is used, which is the default. `--no-mega-graph` runs eagerly and sidesteps capture
|
| 78 |
+
entirely, so it is a usable workaround on an affected engine β at the cost of the
|
| 79 |
+
graph-replay speedup.
|
| 80 |
+
|
| 81 |
+
> **The `sm_120` SAME-L engines were rebuilt AOT on 2026-07-31.** Anything published
|
| 82 |
+
> before that date was a JIT build and is affected, so if you have an `sm_120` copy cached
|
| 83 |
+
> from earlier, re-pull it. The `sm_90` files are unchanged β JIT captures correctly on
|
| 84 |
+
> Hopper, so they were never affected.
|
| 85 |
+
|
| 86 |
+
### Benchmarks
|
| 87 |
+
|
| 88 |
+
SAME-L decode, milliseconds, median of 7 on an otherwise idle GPU. `L` is the latent
|
| 89 |
+
sequence length β one latent is 4096 samples, so at 44.1 kHz L=1292 is a two-minute
|
| 90 |
+
render and L=4096 is about 6m20s.
|
| 91 |
+
|
| 92 |
+
**sm_120 Β· RTX PRO 4500 Blackwell**
|
| 93 |
+
|
| 94 |
+
| kernel | L=256 | L=1024 | L=1292 | L=2048 | L=4096 |
|
| 95 |
+
|---|---|---|---|---|---|
|
| 96 |
+
| JIT *(not capturable here)* | 55.1 | 227.2 | 289.1 | 457.7 | 920.2 |
|
| 97 |
+
| AOT `ptx` (scalar fallback) | 62.5 | 251.2 | 318.7 | 502.8 | 1008.8 |
|
| 98 |
+
| **AOT `mma` (default)** | 55.4 | **223.6** | **283.7** | **448.4** | **899.3** |
|
| 99 |
+
|
| 100 |
+
**sm_90 Β· H200**
|
| 101 |
+
|
| 102 |
+
| kernel | L=256 | L=1024 | L=1292 | L=2048 | L=4096 |
|
| 103 |
+
|---|---|---|---|---|---|
|
| 104 |
+
| JIT | 12.4 | 47.0 | 61.1 | 98.5 | 194.4 |
|
| 105 |
+
| AOT `ptx` (scalar fallback) | 12.7 | 47.3 | 60.7 | 96.6 | 195.5 |
|
| 106 |
+
| **AOT `mma` (default)** | 12.4 | 48.4 | 62.6 | 100.0 | 196.8 |
|
| 107 |
+
|
| 108 |
+
The default AOT kernel is at parity with JIT on both architectures β within a few percent
|
| 109 |
+
either way, and faster at long sequence lengths on sm_120 β while remaining capturable.
|
| 110 |
+
Accuracy against the FP32 decoder at L=1292: AOT `mma` **51.45 dB** PSNR, JIT 51.43, AOT
|
| 111 |
+
`ptx` 51.11. The default kernel is the most accurate of the three as well as the fastest.
|
| 112 |
+
|
| 113 |
+
Note the ~4.5Γ gap between the two architectures. That is silicon, not a software
|
| 114 |
+
regression β a workstation card against a flagship datacenter part. Measured on these two
|
| 115 |
+
GPUs, the H200 has **5.57Γ** the copy bandwidth (4084 vs 734 GB/s) and 5.08Γ the BF16
|
| 116 |
+
tensor throughput, so a bandwidth-bound decoder landing at 4.5Γ is extracting slightly
|
| 117 |
+
*more* of its silicon on sm_120 than the H200 does of its own.
|
| 118 |
+
|
| 119 |
+
### How the kernels differ
|
| 120 |
+
|
| 121 |
+
The default AOT kernel (`mma`) is block-tiled: 16 queries per block share a 64-wide K/V
|
| 122 |
+
tile in shared memory, and both attention products go through `tl.dot`, which lowers to
|
| 123 |
+
512 Γ `mma.sync.aligned.m16n8k8.row.col.f32.tf32.tf32.f32` β TF32 tensor cores. It is
|
| 124 |
+
written in Triton and compiled ahead of time, so Triton generates the fragment layouts
|
| 125 |
+
rather than us hand-writing them, but the result is a plain PTX blob inside the engine.
|
| 126 |
+
|
| 127 |
+
The fallback AOT kernel (`ptx`) is hand-written scalar FP32: one warp per query, no K/V
|
| 128 |
+
reuse, zero `mma` instructions. It exists only for targets where the block-tiled kernel
|
| 129 |
+
will not build, and costs about 10% on sm_120.
|
| 130 |
+
|
| 131 |
+
TF32 in the two attention products matches what the JIT path already did β it is not a new
|
| 132 |
+
precision loss. The differential subtraction stays in FP32 on FP32 accumulators, so the
|
| 133 |
+
cancellation-sensitive step is untouched.
|
| 134 |
+
|
| 135 |
+
### Building your own
|
| 136 |
+
|
| 137 |
+
```bash
|
| 138 |
+
SA3_SWA_PLUGIN=aot # default β PTX compiled into the engine
|
| 139 |
+
SA3_SWA_PLUGIN=jit # Triton through a Python callback per enqueue
|
| 140 |
+
SA3_SWA_AOT=mma # default AOT kernel β block-tiled, tensor cores
|
| 141 |
+
SA3_SWA_AOT=ptx # fallback AOT kernel β scalar FP32
|
| 142 |
+
```
|
| 143 |
+
|
| 144 |
+
Triton is needed to *build* an AOT engine (it is the code generator) but not to run one.
|
| 145 |
+
|
| 146 |
+
Three gotchas, all of which produce wrong output rather than a build failure:
|
| 147 |
+
|
| 148 |
+
- **Kernel parameter order is inputs β runtime scalars β outputs.** TensorRT's AOT
|
| 149 |
+
launcher passes the `extra` scalars *before* the output pointers. Declaring the output
|
| 150 |
+
ahead of them makes the kernel dereference a sequence length as an address; ours died
|
| 151 |
+
with an illegal memory access until the order was fixed.
|
| 152 |
+
- **`BLOCK_KV` must be β₯ `BLOCK_N + 2*WINDOW`.** Otherwise the K/V tile stops covering
|
| 153 |
+
every position the block's queries can attend to and attention contributions are
|
| 154 |
+
*silently dropped*. `BLOCK_N=32` with `BLOCK_KV=64` needs 66 and is therefore wrong,
|
| 155 |
+
even though it compiles and fits in shared memory.
|
| 156 |
+
- **Shared memory over 48 KB fails at enqueue, not at build.** `BLOCK_N=64` needs 64 KB;
|
| 157 |
+
the engine builds cleanly and then reports *"Failed to enqueue status -1"* and returns
|
| 158 |
+
zeros. `BLOCK_N=16` needs 40 KB, and is faster anyway β with a window of only Β±17, a
|
| 159 |
+
wide K/V tile is mostly masked-out waste.
|
| 160 |
+
|
| 161 |
+
The engine filenames still say `triton_swa` because Triton remains the code generator;
|
| 162 |
+
only the compilation moved ahead of time.
|
| 163 |
+
|
| 164 |
+
---
|
| 165 |
+
|
| 166 |
+
## Other things worth knowing
|
| 167 |
+
|
| 168 |
+
**The medium DiT has three precisions.** `dit_fp16mixed.trt` is the default and the one to
|
| 169 |
+
use: FP16 attention core with FP32 RMSNorm and RoPE islands, ~4.3Γ faster than FP32 with
|
| 170 |
+
no audible quality cost. `dit_fp32.trt` is the reference. `dit_bf16.trt` is kept for
|
| 171 |
+
comparison β earlier builds of it degraded past about two minutes of audio because the
|
| 172 |
+
RoPE angle was computed in BF16, where one ULP exceeds 2Ο at long sequence lengths; the
|
| 173 |
+
published engine has the RoPE table baked in at FP32 precision.
|
| 174 |
+
|
| 175 |
+
**`dit_fp8.trt` is sm_90 only** and must be built weakly-typed; strong typing breaks
|
| 176 |
+
TensorRT's attention fusion. This is the *opposite* of the FP16-mixed rule, which requires
|
| 177 |
+
`STRONGLY_TYPED` or the builder re-casts the FP32 islands.
|
tensorRT/sm_120/same-l/dec_dynamic_triton_swa.trt
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:e7b030cb0cf0fa075caa8c11c81b5e1bc621ddf4dd6e03e84f6c0acc81450d09
|
| 3 |
+
size 1196159668
|
tensorRT/sm_120/same-l/enc_dynamic_triton_swa.trt
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:d48b4210bff72a3d2f41ad0eb5c2741b2be7f82c6e5a8101927e755f728b7b0c
|
| 3 |
+
size 1196143124
|