MiniMax Music 3 is an open-weight music generation model that runs on a single RTX 5090 and produces 44.1 kHz stereo songs with vocals. We spent five days with it, starting the day it was published — when it had 25 downloads.
This is not a Suno comparison. We did not run one, and nothing below benchmarks against it. The question here is narrower and more practical: can you generate songs on hardware you own, what does it cost in VRAM and time, and what breaks along the way. If you are self-hosting because of cost, privacy, or because you want the seeds and settings on your own disk, this is what the week looked like.
Everything with a number attached was measured on one machine. Where we made a claim and later withdrew it, it says so — the withdrawn ones were the expensive part of the week.
What it is, and why the shape decides everything else
It ships through diffusers, which suggests a diffusion model. It is not one. It is hierarchical autoregressive with a diffusion renderer bolted to the end:
| Stage | Size | Job |
|---|---|---|
| Global LLM | 8B, initialised from Qwen3-8B | predicts RVQ codebook 1, frame by frame — the long-range structure |
| Local LLM | 0.6B | the remaining seven acoustic codebooks within each frame |
| Flow Matching | 2.4B | consumes the fused hidden states of both LLMs |
| Flow-VAE decoder | 123M | → 44.1 kHz stereo |
The tokenizer is eight layers of residual vector quantisation — one semantic codebook of 16,384 entries and seven acoustic ones of 1,024. One detail is worth holding onto: inference never touches the discrete tokenizer decoder. Synthesis runs off the continuous hidden states, so the codebooks exist for training and nothing else.
That division is not trivia. It predicts the behaviour of every knob you will reach for:
- the autoregressive stage decides what gets sung — the words, the melody, the structure, and how long the piece runs
- flow matching only renders it
So a steps slider changes fidelity and can never change a note, while the two autoregressive sampling constants re-roll the entire composition. We confirmed both by experiment before understanding the mechanism, and the mechanism then explained why the experiments came out as they did.
Getting it running
The repo is 57 GB and you need about 27. It ships two parallel weight sets, one for SGLang and one for diffusers. Pulling only the diffusers path halves the download:
hf download MiniMaxAI/MiniMax-Music3 \
--include "language_model/*" "transformer/*" "condition_encoder/*" \
"rvq_depth_decoder/*" "vocoder/*" "scheduler/*" "tokenizer/*"
hf download MiniMaxAI/MiniMax-Music3 modular_model_index.json config.json
Two traps on the way in, each costing a debugging round:
hf download REPO --include A B Ctreats the patterns as positional filenames and warnsIgnoring --include. It downloaded the right subset anyway but silently droppedmodular_model_index.json, which is the one file the modular pipeline actually reads. Check the snapshot rather than trusting the exit code.torchaudiomust be pinned to match torch. Installing it unpinned pulled 2.11 against torch 2.9.1, and the failure surfaced asCould not load this library: _torchaudio.abi3.sowhile importing the Music3 vocoder — an ABI mismatch wearing the costume of a missing dependency.
Diffusers support landed on 2026-08-13 at 23:47 UTC, hours after we installed from the commit — so pinning was belt-and-braces rather than necessity. Pin anyway: the repo moved once during the five days we watched it.
Six things the model card gets wrong
Every one confirmed by running it:
- Output is 44.1 kHz, not the documented 32 kHz. The card says 32 twice.
- The card's own snippet crashes.
audio.T.float().cpu().numpy()assumes a torch tensor; this build hands back numpy. - Lyrics are mandatory. There is no empty-string instrumental mode — the encoder raises. An instrumental is expressed as
[instrumental]or a skeleton of section tags. - The 5,000-token cap is on the assembled prompt — description plus lyrics plus special tokens — not on the description alone.
- Text sharing a line with a section tag is silently dropped.
[verse] Morning lightloses the lyric and keeps the tag. Markdown-wrapped**[chorus]**is not recognised at all and gets sung aloud. - The licence is not Creative Commons, despite the CC badge. It is the MiniMax Community Licence: display "MiniMax-Music3" in a commercial product's UI, and get written authorisation above $20M/yr revenue.
The card also lists no supported languages, which matters more than it looks. More on that below.
What it costs, measured
peak VRAM 23.3 GB of a 32 GB card
model load 7–12 s
output ~1.95 MB/min MP3 at 265–268 kbps VBR
At 23.3 GB peak this needs a 24 GB card at absolute minimum, and 24 GB would be uncomfortably tight — see Will This LLM Fit My GPU? for why headroom matters more than the raw figure suggests. A 32 GB card is the comfortable floor.
A correction, because we published the wrong model of this
An earlier version of this article gave a tidy formula:
render ≈ audio_seconds × (0.56 + 0.014 × steps) ← wrong
It is wrong, and the way it is wrong is instructive. Every point in the step ladder it was fitted to was the same 65.4-second song. A fit over a single duration cannot separate a fixed cost from a per-second one — so the per-job overhead (spawning the child, importing torch and diffusers, loading 23 GB of weights, encoding the output) was quietly folded into a coefficient that then pretends to scale with length. And calling 0.56 "the autoregressive pass" compounded it: that number is the AR stage plus the fixed cost, wearing one label.
The symptom was visible in renders we already had:
| Audio | Wall clock | Ratio |
|---|---|---|
| 65.4 s (steps 30) | 65.2 s | 1.00× |
| 24.2 s | 31.9 s | 1.32× |
| 21.7 s | 28.1 s | 1.29× |
A cost that scaled purely with length would hold that ratio constant. It does not — short renders are proportionally worse, exactly as a fixed overhead being amortised over less audio would predict.
What we can still say: the per-step slope re-derives cleanly at 0.01435 seconds per step per second of audio, and steps genuinely only scale the flow-matching half. What we cannot say is how large the fixed cost is, because we never varied duration and steps independently. The structural flaw in the old fit is certain; the exact magnitude of its error is not, and we are not going to invent one.
That gap is the whole argument for recording every render parameter beside the output. This is precisely the measurement that would have survived had the sidecar existed three days earlier.
Judged by ear on a ladder where the composition was held constant, fidelity improves monotonically with steps and flattens after 30–50. What does not change is diction: the words are already clear at 10 steps, exactly as the architecture predicts, because the AR stage has already decided them.
The five behaviours that actually decide your results
1. Length comes from the material, not from the slider
The model paces a piece against what it is handed. All measured against the requested length:
| Input | Asked | Got |
|---|---|---|
| ~30 lines of lyrics | 165 s | 165.2 s |
| 3 lines of lyrics | 120 s | 68.6 s |
bare [instrumental] |
140 s | 31–65 s |
| 7-tag skeleton | 140 s | 65.5 s |
| 16-tag skeleton | 140 s | 140.2 s |
About 5.5 seconds per lyric line, and 9 seconds per section tag for an instrumental. Give it enough material and it lands exactly on the mark; give it four lines and it will finish early no matter what you ask for.
This is the single most useful thing to know before you start, because most disappointing results are a full-length request stretched over a thin lyric.
2. audio_duration is conditioning, not a trim
A 20-second render correlates 0.167 with the first 20 seconds of the 90-second render at the same seed. It is a different composition, not an excerpt.
This killed a feature. A "preview" button that rendered 30 seconds cheaply looked obvious, and could never have previewed the actual song. What works instead is previewing at the target length and the lowest quality — steps leaves the composition alone, so a draft render really is the same song, roughly rendered.
3. Contradictory conditioning is expensive
A description asking for vocals while the piece was marked instrumental produced 14.2 seconds against a 2:00 request. Removing that one sentence took it to 25.6 s; giving it a proper tag skeleton took it to 140 s.
The model does not error, warn, or degrade gracefully. It writes something short and confident.
4. Two of the important knobs are hardcoded upstream
_AR_CFG_SCALE (1.5) and _AR_SAMPLING_TOP_K (50) are module constants with no pipeline input. They govern the stage that decides what gets sung. They can be reached only by rebinding the module globals — which does work, because they are read inside the generation loop at call time.
5. It is deterministic within a session
Identical parameters rendered twice produced byte-identical files. Within a session, a seed is a real seed. Across restarts we saw one divergence we could not account for, so cross-restart reproduction deserves suspicion.
Two controlled tests, and one retraction
The retraction first, because it is the most useful thing here. An early ad-hoc pair showed top-k 50 → 33.4 s against top-k 8 → 56.7 s, and we read it as "tighter sampling makes the model work through the lyrics." A proper sweep — two one-dimensional arms crossing at the defaults, one variable at a time — does not reproduce it: at seed 1234 the two settings give 65.4 s and 66.6 s. The original pair came from a different process and was confounded.
What the sweep did establish is more useful: changing top-k or AR CFG re-rolls the entire composition. The token stream diverges from the first frame, so eight clips at eight settings are eight different songs, not eight renders of one. With n=1 per setting, take-to-take variance swamps any parameter effect and nothing can be attributed. The listener's verdict — "this mostly depends on the seed" — was right, and the mechanism is that those parameters are a seed change.
The test that worked held the composition constant and varied only the caption. Four seeds, paired, a one-liner against MiniMax's documented three-heading Structured Caption. The structured form gave clearly better vocal diction at no cost to the music, consistently across seeds. That is a real finding because the pairing made it one.
It does not sing Serbian
The tokenizer round-trips Serbian losslessly in both Latin and Cyrillic, with no unknown tokens, at about 2.3× the tokens per character of English. Nothing looks wrong at any point you can inspect. The output is confident, fluent-sounding audio with wrong pronunciation.
The card lists no languages, so this is neither documented nor contradicted. If you work in a language other than English, test pronunciation before building anything on it — the failure is silent, and everything upstream of it looks healthy.
Advice, in the order it would have saved us time
- Write the lyrics first, then set the length to match. Roughly 5.5 s a line.
- Never shorten by lowering duration. That composes a different song. Cut the lyrics instead.
- Iterate at the target length and the lowest quality. Same composition, rougher timbre, 30% faster. Then re-render the keeper at higher steps with the same seed.
- Use the Structured Caption format — Global Metadata / Vocal Details / Arrangement. It is documented, it is what their own reference example uses, and it beat a one-liner in a paired test.
- Say "clear diction, words out front in the mix" in the caption. It is the one phrasing that reliably helped.
- Keep tags on their own line, and strip markdown. Both failure modes are silent.
- Do not fight the model with the AR knobs. They re-roll the song rather than refining it. If diction is poor, write more lyrics.
- Pin the model revision. The repo moved once in the five days we watched it. That particular move was harmless — all 21 weight files resolved to identical blobs, and only a root
config.jsonthis pipeline never reads had changed — but a future one would silently break every seed you have recorded. - Record everything a track was made from. Seed alone is not reproducible: quality, guidance, the AR constants and the exact words all matter. A JSON sidecar per song costs nothing and turns "I liked that one" into something you can rebuild.
- On a shared card, load per job and let the process die. After a CUDA OOM, dropping every reference and calling
empty_cache()still left 20.8 GB held — the traceback kept tensors alive. Only the process exiting returned it.
Making it coexist with everything else on the card
23.3 GB does not fit twice on a 32 GB card, and CUDA memory is not shareable between processes. So the architecture that works is one service owning the weights, loading them in a child process per song, and handing the card back when that child exits. Idle cost: zero.
That is what lets a music model live alongside the chat and vision models that otherwise occupy the same GPU — the same constraint we hit running Muse Glimmer and Qwen3.8 on one card, where two 30B models also could not be resident together.
What went wrong, since that is the part nobody writes down
A missing return in a poll loop wrote 193 copies of one song, one every three seconds, 154 MB, until the server was restarted. The save path set the job's status to done and fell back into while True, and the cancel function refused to touch anything not marked running — so the one escape hatch trusted the field the bug had already corrupted. Twenty-one tests covered every pure function and none of the control flow.
A destructive HTTP endpoint fired on an empty POST. Checking whether the route existed ran it, twice, each time stopping a model somebody was using. It now requires an explicit confirmation flag and otherwise reports what it would have done.
Two error messages sent us to the wrong machine. A 404 reported as "the desktop is not answering" had us checking a box that was awake and replying. Making it say "the service is out of date, restart it" found the next instance of the same fault in seconds.
The pattern in all three: the happy path was right and the reporting was wrong. Which is the same lesson as the sweep — the parts were fine, the seams were not, and only the seams were untested.
Related reading
- Qwen3.8-27B vs Muse Glimmer 30B: Same 10/10, One Is 10× Faster — two more models competing for the same 32 GB
- How to Run Meta Muse Glimmer 30B on an RTX 5090 — the text-model equivalent of this write-up
- Will This LLM Fit My GPU? VRAM Requirements for Every Model Size — the arithmetic behind the 23.3 GB figure
- AI Workstation Comparison: RTX 5090 vs GB10 (HP ZGX) — choosing the card underneath