Skip to content

cpu-amx: torch-free C++ AMX CPU runtime for Stable Audio 3 medium - #105

Open
Cortexelus wants to merge 7 commits into
mainfrom
cpu-amx-release
Open

Cortexelus wants to merge 7 commits into
mainfrom
cpu-amx-release

Conversation

@Cortexelus

@Cortexelus Cortexelus commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator

Adds optimized/cpu-amx — build sources, runtime, CLI and gradio for running Stable Audio 3
medium entirely on CPU via AOT C++ AMX engines (Intel AMX / AVX-512) plus numpy. No torch, MLX,
TFLite or stable-audio-tools at runtime.

prompt -> T5Gemma (C++ AMX) -> numpy conditioner -> DiT pingpong (int8 or bf16 C++ AMX)
       -> SAME-S / SAME-L decoder (C++ AMX, bf16 or int8) -> WAV
audio-to-audio / inpaint: C++ AMX SAME-{S,L} encoder init-encode

Why now

The engine binaries have been published at stabilityai/stable-audio-3-optimized/cpu-amx/ (39
files) since August; the code that builds and loads them was on this branch but never merged.

Contents

scripts/ CLI (sa3_cpu_amx.py), gradio, pipeline, ctypes backends, HF weight fetch, self-test
build/ C++ engine sources + weight dumpers — DiT, SAME-S/L (bf16 + int8), T5Gemma
assets/ SentencePiece tokenizer + conditioner weights (4.9 MB, required at runtime)
sa3, sa3-gradio entry-point wrappers

scripts/weights.py downloads the published binaries on first use into $SA3_CPUAMX_HOME
(default ~/.cache/stable-audio-3/cpu-amx).

Relocatable

Engine paths resolve from $SA3_CPUAMX_HOME at load time in both the Python loader and the
C++ engines, so nothing absolute is compiled in.

⚠️ Binaries published before the last commit here were linked with an absolute prefix baked in;
they need a rebuild from build/ to be portable.

Verified

End to end on Sapphire Rapids via ./sa3: 8.0 s of audio in 17.8 s wall (0.45× realtime at 4
steps), peak RSS 1.77 GB, non-silent 44.1 kHz stereo. 15/15 Python files compile, 5/5 shell
scripts parse, all modules import, 10/10 engine directories resolve.

Not yet included

  • Limiter. The TensorRT and TFLite decoders bake a limiter into the decode graph; cpu-amx
    does not, so output can hard-clip — a smoke render peaked at 32767/32767. Parity with the
    other backends is still to do.
  • LoRA / DoRA. No adapter support in this runtime yet (TensorRT and TFLite both have it).

Commits

1-5 (Aug): initial release, <model>_<precision> HF filenames, int8 encoders +
--decoder-precision, bf16 DiT tier + gradio quant dropdowns, multi-threaded DiT for both
precisions.
6: merge current main.
7: make the tree relocatable and strip local paths — 88 lines of a private directory layout
across 32 files, plus a .gitignore collision that was silently excluding all 21 engine sources
from the commit, and a dead torch encoder that contradicted the torch-free runtime.

🤖 Generated with Claude Code

Cortexelus and others added 7 commits August 2, 2026 03:34
CPU-native SA3-medium inference on Intel AMX Xeon — the whole pipeline on
torch-free C++ engines (T5Gemma -> DiT int8 -> SAME-S/L decoder, + SAME-S/L
encoder for audio-to-audio/inpaint). MLX-parity CLI + gradio, full feature
parity (CFG, negative prompt, APG, inpainting, audio-to-audio).

Compiled .so's + weight blobs (6.5 GB) live on HF
(stabilityai/stable-audio-3-optimized/cpu-amx); scripts/weights.py pulls each
engine on first use. Includes build tooling (build/), tests (tests/), and
docs (README/BUILD/TESTING/LESSONS).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…it_medium_int8, same_*_encoder_bf16); update weights.py to match

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…-precision int8

The int8 SAME-S/L encoders (SmoothQuant+GPTQ, real-audio calib; ear-cleared,
round-trip-transparent vs bf16) are now on HF. weights.py pulls them; CppEncoder
routes a2a/inpaint init-encode to the int8 encoder when --decoder-precision int8,
matching the decoder. Verified end-to-end (a2a int8 → valid audio).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nt dropdowns

- backends.load_dit(precision, threads): routes the int8 (shipped, 1-thread) or
  bf16 (near-lossless fp32 RoPE/RMSNorm islands, ~59/54 dB, runs at --threads) DiT core.
- CLI --dit-precision {int8,bf16} (default int8); full feature parity across
  text-to-audio / CFG+neg+APG / audio-to-audio / inpainting, both precisions.
- gradio: "DiT quantization" + "Decoder quantization" dropdowns, threaded into the CLI.
- weights.py: dit_bf16 group (dit_medium_bf16.so + core_bf16 + pin_fp32 + bf16 flash,
  reuses the shared AOT kernels tarball) pulled from HF cpu-amx/.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…er pinned to 1)

The int8 DiT was pinned to 1 thread (DIT_THREADS=1), so --threads=16 never reached it
— a full 380s song took 676s (0.56x RT), ~664s of it DiT sampling at 1902 ms/step.
Stress-tested int8 at 16 threads (bit-identical + finite over 48 forwards @ L=172/1356/4160,
one length/process): no heap-race, deterministic. Now both precisions honor --threads
(default 16) → int8 DiT ~7.6x faster (1902 -> ~250 ms/step). Pass --threads 1 to restore.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Everything resolved from a hardcoded /weka2/... prefix, so the engines only
loaded on the machine they were built on and the published tree leaked a
private directory layout (88 such lines across 32 files).

Paths now come from $SA3_CPUAMX_HOME (default ~/.cache/stable-audio-3/cpu-amx)
in BOTH halves:
  * scripts/backends.py derives every DIR_* from the base weights.py uses, so
    the loader and the downloader can no longer disagree;
  * the seven C++ engines read the same variable via getenv() instead of
    baking WBASE / AOT / COREBASE / FLASH_SO_DIR in at link time;
  * build.sh takes $ONEDNN_HOME, the weight dumpers take $SA3_REPO,
    compile_isa_all.py takes $SA3_TRITON_CPU.
NOTE: engines published before this need a rebuild from build/ to be portable.

Also:
  * weights.py places the DiT files in dit_medium_cpu_amx/ with every other
    engine, instead of a tritoncpu_sa3/ tree outside the layout.
  * Remove the torch fp32 AEEncoder / load_ae_encoder_torch. Nothing called it
    (a2a and inpaint use the C++ AMX encoders through load_encoder), and it
    pulled in torch + stable_audio_tools + an unpublished loader, contradicting
    the torch-free runtime. requirements.txt claimed torch was required for
    --init-audio; it is not.
  * .gitignore: the repo-root `build/` rule was silently excluding all 21
    engine sources — a PR would have shipped the runtime with no way to rebuild
    anything. Re-included, with bytecode still ignored.
  * Drop tests/, TESTING.md, LESSONS.md: dev material, and every test hardcodes
    a local ground-truth path.

Verified after the change: 15/15 python files compile, 5/5 shell scripts parse,
all modules import, 10/10 engine dirs resolve, and ./sa3 renders 8.0 s of audio
in 17.8 s wall (0.45x realtime, 4 steps) to a non-silent 44.1 kHz stereo WAV.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Cortexelus Cortexelus changed the title cpu-amx: torch-free C++ AMX CPU runtime for SA3 medium cpu-amx: torch-free C++ AMX CPU runtime for Stable Audio 3 medium Sep 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant