Repository navigation
Conversation
…T, DAV), music3-generate and --serve The AR LM with its depth decoder in a CUDA-graph frame step (warp-a-row GEMVs at the GB10 read ceiling, SwiGLU fused into gate/up, CFG top-k drawn on the device), int8 weight-only by default (a scale a row; depth decoder a scale a group of 128); the DiT on tuned cuBLASLt fp16 GEMMs with our flash attention; the DAV in fp32 tap SGEMMs. --serve speaks a JSON-lines protocol shared with our Mac MLX engine. Parity vs ComfyUI's native nodes, kernel contract gates 1-4 and gate 5 records, docs/recipes/minimax-music3-cuda.md with the receipts.
|
Thank you @drowzeys! Music 3 on CUDA and Metal is a big piece of work, and your parity receipts against the reference made it much easier to review. We've folded #982 and #987 into one family on the shared core: frames go through the core's frame queue, each lane keeps its own AR state, prompts resume from the core prompt store with both CFG histories, and every load step unwinds only after its GPU work completes. One change: prompt.zig said it follows ComfyUI's prompt.py by hand. ComfyUI is another project's GPL-3.0 code, so we rewrote the prompt builder from its behaviour. It matches yours byte for byte on 2,066 cases. Could you attach the ten prompt cases from your receipts, with ComfyUI's ids, as JSON? They're the last check before the GPU gates. Posted by Ash's AI Assistant Synthena |
Thank you, Ash, for the invitation in #941, and for the CUDA runtime and kernel contract this builds on.
This is the first music model on TensorFold's Zig runtime. MiniMax Music 3 turns a caption and lyrics into a full song with vocals. It now runs end to end on TensorFold's CUDA runtime, with no Python and no PyTorch at run time. It reads Comfy-Org's single-file checkpoints as they are and has its own kernels.
The model has three parts:
On one DGX Spark (GB10), for a 60 s song:
I did not open an issue first, since this came by invitation in #941. Happy to move the gate discussion into one if you prefer. It stands alone on
main: it does not depend on the Drama 3 pull requests.Receipts
All on one GB10 (sm_121, 128 GB), idle, one model process, CUDA 13. The checkpoint is Comfy-Org's MiniMax-Music3 repack (
minimax_music3_text_encoder_pruned_bf16,minimax_music3_dit_fp16,minimax_music3_dav). The baseline and reference is ComfyUI 5a665890's native nodes on the same machine. The full tables and their JSON are indocs/recipes/minimax-music3-cuda.mdanddocs/recipes/minimax-music3-cuda/.Measured ceilings before building
Measured on an idle GB10, with weights rotated through a 2 GB pool so L2 never holds them:
What got there:
griddepcontrol.wait.mma.syncm16n8k16). There is noflex_attention, which gives wrong results on sm_121.Parity against ComfyUI
Same 30 s input (hiphop bench prompt, seed 7), teacher-forced so the rows are comparable:
The draws themselves cannot match (torch's multinomial against our Philox inverse-CDF draw), so a song is not ComfyUI's song for the same seed, only the same model.
Speed and memory
Hiphop bench prompt, seed 7, and the long-pop prompt, seed 5, for the 120 s row. Load (37 s from a cold page cache) is outside "total". Peak machine is MemTotal − MemAvailable sampled twice a second, minus the idle machine.
int8 is the default:
--weights bf16reads the checkpoint's own numbers.Lyric accuracy
Three 45 s songs, each in bf16 and int8, plus ComfyUI's own 60 s song. Transcribed by faster-whisper large-v3-turbo on the CPU and scored against the lyrics by
tools/music3/lyrics_check.py. The score counts the words heard up to the last lyric word heard. The span counts only matched runs of 3 or more words.The int8 long-pop score of 31 is a scoring artefact: a stray "down" matched the bridge's "go down". Its span is 100.
Checks on this branch
Run on a GB10 at this head, against
main6ee828c:zig build test: 86/86 steps; 450/456 tests passed, 6 skipped (libjpeg-turbo absent: JPEG cases).zig build test-cuda-host: 41/41 steps; 856/856 tests passed (main: 852/852).Plain
zig build: succeeded.zig fmt --check zig build.zig: clean.python3 tools/zig/lean_check.py: 517 problems, the same 517 asmain. 0 new findings; the inherited ones are unchanged.Kernel contract (
zig build kernel-contract -Dnvcc=/usr/local/cuda/bin/nvcc) on sm_121:Launch limits (
zig build fatbins kernel-contract-fatbins -Dsm=80,86,89,120,121, thentf-cuda-test kernel-contract-limits zig-out/fatbin):All 55 music3 launches are registered in
registry.zigwith records for sm_80, sm_86, sm_89, sm_120 and sm_121.m3_rmsnorm,m3_gemv_bf16_2,m3_gemv_i8_2andm3_gemv_g8_2go through gates 1–4 (zig/tests/cuda/contract_music3.zig).What it adds
These are new files, plus the minimal wiring: 11 lines in
zig/build/cuda.zig, 1 inzig/src/cuda/kernels.zig, 12 in the contract runner, 55 records inregistry.zig, and 1 row in the recipe index.zig/src/families/music3/(Zig over the CUDA runtime):config.zigholds the shapes, request settings and the reference's schedules.prompt.zigbuilds the caption and lyrics prompt ids through the core tokenizer and the checkpoint's owntokenizer_json.weights.zigreads the three files and quantizes int8 on the GPU at load: body and lm_head one scale a row, the depth decoder one scale a group of 128.ar.zigholds the AR prompt pass (cuBLAS bf16 GEMMs) and the graphed frame step.dit.zigholds the windowed DiT: 689 latent rows every 344, both CFG branches in one forward, on cuBLASLt fp16 GEMMs.dav.zigholds the DAV: fp32, every conv as one SGEMM a tap, with no TF32.engine.zigandgenerate.zigprovide the request, the CLI and--serve.parity.zigandnpy.zigprovide the parity dumps.lt.zigandblas.zigopen cuBLASLt and cuBLAS at run time.wav.zigwrites the WAV.zig/kernels/cuda/music3.cuand its headers (music3_ar.cuh,music3_dit.cuh,music3_dav.cuh,music3_sample.cuh,music3_common.cuh) build one fatbin.zig build music3-generate:--idsfor prompt ids with no GPU;--parity-ar / --parity-probe / --parity-dit / --parity-dav REFagainst a reference dump;--serve 1.tools/music3/(development tools, Python):parity.pybuilds the parity table from REF and MINE, with numpy only.lyrics_check.pymeasures lyric accuracy with Whisper.served_test.pydrives--servethrough the Studio's client.docs/recipes/minimax-music3-cuda.mdis the recipe, with the plan and ceilings written before building, the receipts, and their JSON.How it fits the engine, and how it does not
--serve 1reads one JSON request a line on stdin and answers on stderr, with optional progress lines. It is the same protocol as our Mac MLX engine for this model, so one client drives either. It answers one request at a time.u32token, and the song is finished by a DiT and a waveform decoder. So this runs as its own generator beside the lane engine rather than on the lane core. Moving it there needs the same core changes drama3: Fish Audio Drama 3 text to speech on one CUDA GPU (new family, plain decoding; proposal) #939 lists: a frame position type or a family hook, per-codebook sampling, and an audio output. Plain decoding only; there is no drafter.Licences
The code is written for TensorFold and is Apache-2.0. No ComfyUI source is copied in, and nothing here imports ComfyUI. ComfyUI's implementation (GPL-3) is the reference it was checked against. Some parts were written by hand to behave as ComfyUI does, so the outputs line up, and I am naming them so you can decide:
The reference harness is not included. It is a ComfyUI custom node that records tensors from ComfyUI's own loaders and sampler. The recipe describes what it records and the file layout
parity.pyreads.The model: MiniMax-Music3 is under the MiniMax-Music3 Community License. No weights are included.
music3-generateprints the display notice, and--servereports"license_display":"MiniMax-Music3".Not tested
Next steps, if you want them
music3-mlxon our fork) is a working reference and baseline for it. On an M5 Ultra it does a 60 s song at about real time in int8, with the same parity tables against ComfyUI on MPS. It is Python/MLX, so I have not sent it here: CONTRIBUTING keeps the Python engine frozen at 0.6.6, and the final native request should not need Python.