Skip to content

model: add Muse Spark Open (text, vision and audio) - #30616

Merged
ServeurpersoCom merged 9 commits into
ggml-org:masterfrom
ServeurpersoCom:muse-spark-open
Oct 15, 2026
Merged

ServeurpersoCom merged 9 commits into
ggml-org:masterfrom
ServeurpersoCom:muse-spark-open

Conversation

@ServeurpersoCom

Copy link
Copy Markdown
Contributor

Overview

Muse Spark Open is a latent space MoE: the residual stream stays at 8192 while the 256 experts live in 4096, with a projection down and up around them, top-8 sigmoid routing with a correction bias. Attention interleaves three sliding layers at a 2048 window with rope for one global layer without rope, which is where the 1M context comes from, plus a sigmoid output gate and a weightless QK-norm. Residuals are norm preserving, their gate is folded at conversion time.

Vision reuses the Muse Glimmer tower. Audio is a causal convolutional pyramid with no attention and no spectrogram, four stages folding 16, 6, 5 and 4 samples into the channel dim, one embedding per 80 ms of 24 kHz.

The quantizer keeps the latent projections and the attention gate at Q8_0, a little over 1% of the weights, since the whole residual stream passes through them and the low-bit types turned the output into a repeating loop without it.

Additional information

Validated against the transformers reference at cosine 1.000000000 on the text path and 0.999999926 on the audio tower, on the real weights. Tested on a Mac Studio M3 Ultra with Metal and on an RTX PRO 6000: vision on two images, audio on a 17s clip, tool calling, and perplexity on wikitext-2 and on recent llama.cpp sources the weights cannot have seen.

GGUFs: ggml-org/Muse-Spark-Open-816B-A42B-GGUF, Q8_0, Q4_K_S and an imatrix-calibrated Q2_K, with the mmproj in F16 and Q8_0.

Requirements

Muse Spark Open is a latent space MoE: the residual stream stays at 8192
while the 256 experts live in 4096, with a projection down and up around
them, top-8 sigmoid routing with a correction bias. Attention interleaves
three sliding layers at a 2048 window with rope for one global layer
without rope, with a sigmoid output gate and a weightless QK-norm.
Residuals are norm preserving, their gate is folded at conversion time.

Vision reuses the Muse Glimmer tower. Audio is a causal convolutional
pyramid with no attention and no spectrogram, four stages folding 16, 6,
5 and 4 samples into the channel dim, one embedding per 80 ms of 24 kHz.

The quantizer keeps the latent projections and the attention gate at
Q8_0, a little over 1% of the weights, since the whole residual stream
passes through them and the low-bit types turned the output into a
repeating loop. The model saver writes the post norm epsilon, and the
arch is registered in test-llama-archs.

Co-authored-by: Xuan Son Nguyen <son@huggingface.co>
Co-authored-by: Pedro Cuenca <pedro@huggingface.co>
@github-actions github-actions Bot added model Model specific testing Everything test related mtmd Related to multimodal functionality (video/image/audio) conversion labels Oct 15, 2026
Comment thread src/models/muse-spark.cpp Outdated
cb(cur, "result_output", -1);
res->t_logits = cur;

ggml_build_forward_expand(gf, cur);

@ggerganov ggerganov Oct 15, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No longer needed to forward expand

@aldehir aldehir left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the output format significantly different from glimmer that it requires a new parser?

@ServeurpersoCom

Copy link
Copy Markdown
Contributor Author

Is the output format significantly different from glimmer that it requires a new parser?

Yes, Spark adds a third recipient Glimmer does not have: to=commentary, user facing content the model emits mid turn, typically before or between tool calls, terminated by <|eom|>. Glimmer only has to=self for the chain of thought and to=user for the final answer, so its parser treats everything that is not the final message as reasoning. On Spark that would swallow commentary into reasoning_content instead of surfacing it as content.

The two parsers are otherwise close, the diff is about forty lines: the commentary rule, the aside alternation that lets analysis and commentary interleave, and the trigger regex which has to exclude commentary as well. Happy to merge them into one parameterised parser if you prefer that over two files, the rest is identical.

Comment thread conversion/muse_spark.py Outdated
Comment on lines +128 to +130
# The residual gate is norm preserving: the stream is scaled by alpha and
# the branch by beta, with alpha^2 + beta^2 = 1. Both depend on the weight
# alone, so they resolve here and the graph keeps a scale and an add.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix comments please :)

@aldehir

aldehir commented Oct 15, 2026

Copy link
Copy Markdown
Contributor

Ah, looks like it's taking some ideas from gpt-oss.

Happy to merge them into one parameterised parser if you prefer that over two files, the rest is identical.

It's not a big deal, we can keep them separate for now.

danielhanchen added a commit to unslothai/unsloth that referenced this pull request Oct 15, 2026
## Summary

Studio support for the Muse Spark Open GGUFs
(`unsloth/Muse-Spark-Open-816B-A42B-GGUF`, llama.cpp arch `muse-spark`,
loaded through the prebuilt llama.cpp that carries
ggml-org/llama.cpp#30616).

- **Sampling defaults.** A new `muse-spark` family uses the model card
settings: temperature 1.0, top_p 1.0, top_k disabled, and min_p 0.0. The
Hugging Face generation_config.json lists top_k 64, but the model card
recommends top_k disabled and its benchmarks use that, so the card wins.
Before this, every Muse Spark id fell through to `default.yaml` (0.7 /
0.95 / min_p 0.01).
- top_k is stored as -1, Studio's "disabled" value. The llama-server
payload sends it as 0, which llama.cpp reads as no top-k cutoff.
- The pattern sits next to `muse-glimmer`, so Glimmer keeps its own 0.95
/ 64.
- **Reasoning effort.** The Muse Spark chat template accepts
`reasoning_effort` low, medium, high or xhigh (default xhigh). Any other
value hits `raise_exception`, and the render fails.
- Before this change, the request builder forwarded the OpenAI `none`
sentinel as-is, and the default-effort path forwarded `none`, `minimal`
and `max`. All of them failed.
- Muse Spark cannot turn reasoning off. So for the `muse-spark`
architecture only, `none` and `minimal` now map to `low` and `max` maps
to `xhigh`. Inkling's numeric mapping and every other architecture are
unchanged.

## Already handled by main (verified, no change needed)

- **Variant menu.** On the real repo listing, the menu shows exactly the
eight quants: UD-IQ1_S, UD-IQ1_M, UD-IQ2_XXS, UD-IQ2_S, UD-IQ3_XXS,
UD-Q2_K_XL, UD-Q3_K_XL and UD-Q4_K_XL.
  - Each quant resolves to shard 1 plus its remaining shards.
- The root `imatrix_unsloth.gguf` is never offered as a variant and
never picked as the model.
- **Reasoning detection.** Detection publishes the four effort levels
and tool support.
- The template opens reasoning with `<|start|>assistant
to=self<|message|>`, so the existing recipient-channel parser handles
the output: `self` is reasoning, `user` is the reply.
- **Memory planner.** Tested on the real UD-IQ1_S metadata (62 blocks:
16 full-attention and 46 sliding-window layers; 163.6 GiB of weights).
The planner fits 134144 tokens of context on a single B200. Larger
context requests and smaller cards spread across 2 or 3 GPUs without
errors.

## Testing

- **New tests:** `tests/test_muse_spark.py`, 38 tests. 12 fail on main
and all pass on this branch.
- Sampling for the repo, repo:quant, cache snapshot, local .gguf and org
variants.
  - The variant menu and shard resolution for every quant.
  - The imatrix exclusion.
  - Reasoning detection.
- Every reasoning kwarg Studio can produce, rendered against the
template's effort handling.
- **Full backend suite** (`studio/backend/tests`, `-n 24`): main vs this
branch comparison of failing test IDs is in progress; I will update
here.
- **Live check:** Studio's planned argv for UD-IQ1_S (`-c 134144`, flash
attention on), run on a ggml-org/llama.cpp#30616 llama-server build on
two B200s.
- Effort high: 511 tokens, reasoning split into `reasoning_content`,
answer `17 x 23 = 391`.
- Effort low: 114 tokens, answer `391`; the system prompt renders
`Reasoning strength: 8.`
- Rendering with `reasoning_effort: "none"` fails with HTTP 500
`Unsupported reasoning_effort`. That is the failure the coercion
prevents.
Comment thread src/llama-quant.cpp Outdated
Comment thread src/llama-graph.cpp Outdated
Comment thread conversion/muse_spark.py Outdated
Comment thread conversion/muse_spark.py Outdated
Comment thread conversion/muse_spark.py Outdated
Comment thread conversion/muse_spark.py Outdated
ServeurpersoCom and others added 6 commits October 15, 2026 20:16
Co-authored-by: Sigbjørn Skjæret <sigbjorn.skjaeret@huggingface.co>
Co-authored-by: Sigbjørn Skjæret <sigbjorn.skjaeret@huggingface.co>
Co-authored-by: Sigbjørn Skjæret <sigbjorn.skjaeret@huggingface.co>
Co-authored-by: Sigbjørn Skjæret <sigbjorn.skjaeret@huggingface.co>
Co-authored-by: Sigbjørn Skjæret <sigbjorn.skjaeret@huggingface.co>
Co-authored-by: Sigbjørn Skjæret <sigbjorn.skjaeret@huggingface.co>
@ngxson

ngxson commented Oct 15, 2026

Copy link
Copy Markdown
Collaborator

most tests are passed, should we merge this now?

@ServeurpersoCom

Copy link
Copy Markdown
Contributor Author

Good to go on my side. The only red is gpu-vulkan-nvidia-cm2, which also fails on master at cd0a5b6 and is unrelated to this PR, nothing here touches Vulkan.

@CISC

CISC commented Oct 16, 2026

Copy link
Copy Markdown
Member

@ServeurpersoCom

Copy link
Copy Markdown
Contributor Author

Randomly failing llama-context tests: https://github.com/ggml-org/llama.cpp/actions/runs/38825598153/job/116732208986#step:7:13016 https://github.com/ggml-org/llama.cpp/actions/runs/38813196242/job/116691279071#step:10:13031

Thanks, that one is mine. muse-spark-moe is the only model failing, on state_load and sometimes cp_h/cp_d, with NMSE 1.17e-05 and 1.15e-05 against the 1.0e-05 threshold, at a different step each run. CPU backend only, nothing GPU in either log. It is a tolerance overshoot rather than a broken restore, most likely top-8 routing flipping an expert on a near tie. I'll fix CI.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

conversion model Model specific mtmd Related to multimodal functionality (video/image/audio) testing Everything test related

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants