Skip to content

Add an MLX backend so MOSS-Music runs on Apple Silicon - #3

Open
dthinkr wants to merge 1 commit into
OpenMOSS:mainfrom
dthinkr:feat/mlx-backend
Open

Add an MLX backend so MOSS-Music runs on Apple Silicon#3
dthinkr wants to merge 1 commit into
OpenMOSS:mainfrom
dthinkr:feat/mlx-backend

Conversation

@dthinkr

@dthinkr dthinkr commented Jun 27, 2026

Copy link
Copy Markdown

MOSS-Music doesn't run well on Apple Silicon today. On the PyTorch/MPS path several audio-encoder ops fall back to CPU, so local generation crawls (under 0.3 tokens/sec, and it often just hangs). This PR adds an MLX backend that runs properly: on an M4 it loads in about 1.5 seconds and analyzes a song in roughly 34 seconds, using about 10 GB of memory.

The code lives in a new mlx/ folder, following the same layout as the existing sglang/ backend. It reuses the repo's own audio processor and mlx-lm's Qwen3 implementation, so only the audio-specific parts (the encoder, the adapters, and the audio-to-text fusion) are reimplemented for MLX.

It includes a converter that turns the HuggingFace weights into MLX format with optional 8-bit quantization (the audio encoder is kept at higher precision for quality), generation with both a command-line tool and a Python API (Chinese text streams correctly), and tests that compare the MLX output against the original PyTorch model.

On accuracy, the 8-bit MLX model predicts the same next token as the full-precision reference and the logits line up almost exactly: cosine 0.99999 against fp32, and 5 out of 5 matching top predictions across five mixed-genre clips against the bf16 model. A script in mlx/README.md reproduces these numbers.

A few notes: 8-bit is the tested recipe, while 4-bit and 6-bit run but aren't verified yet; inference handles one audio clip at a time. Also, unrelated to this PR, the repo's pyproject.toml points to a LICENSE file that isn't in the root while the README states Apache-2.0, so it may be worth adding one.

Port MOSS-Music-8B to MLX so it runs efficiently on Apple Silicon, where the
PyTorch/MPS path falls back to CPU and is effectively unusable for local
generation. The audio encoder (chunked conv stem, Whisper layers, DeepStack
taps), the SwiGLU adapters and the audio-to-Qwen3 fusion are reimplemented in
MLX; the Qwen3 decoder is reused from mlx-lm. The repository's own
MossMusicProcessor is reused unchanged for mel features and audio-token
placeholders.

Includes:
- HF to MLX conversion with 8-bit quantization (audio encoder kept bf16)
- KV-cached generation with a UTF-8-safe incremental detokenizer and a CLI
- prefill parity vs the PyTorch reference, decode-path self-consistency tests,
  artifact-free unit tests, and a bf16-vs-8bit eval harness
- an [mlx] optional-dependency group; mlx/ mirrors the sglang/ backend layout

Validation: 8-bit vs fp32 reference prefill argmax identical, logit cos 0.99999;
8-bit vs bf16 over 5 mixed-genre clips argmax 5/5, mean cos 0.99998; ~10.2 GB,
~23 tok/s on an M4 (vs PyTorch/MPS stalling at <0.3 tok/s).
@dthinkr

dthinkr commented Jun 27, 2026

Copy link
Copy Markdown
Author

Quick note on context: I built this because I wanted to run MOSS-Music locally on an Apple Silicon Mac, and it seemed like it might be useful to others, so I'm offering it as a proposal rather than assuming you want it.

It's self-contained in its own mlx/ folder and doesn't touch the core code, so it should be easy to review or to drop. I completely understand if an MLX backend isn't a direction you want to take on, or if you'd prefer a different approach. Happy to change anything or close it.

No rush on a review, take your time. Thanks for the great work on this model.

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