Meta 推出 Muse Spark Open:开放权重的前沿多模态混合专家模型
英文标题:Welcome Muse Spark Open: open-weight frontier multimodal mixture-of-experts model from Meta
Meta 发布开放权重模型 Muse Spark Open,这是一款总参数量约 8160 亿、每个 token 激活约 420 亿参数的多模态 MoE 模型,支持文本、图像、音频和视频输入,最大上下文窗口达 100 万 token。该模型面向 Agentic Coding 优化,可处理代码库阅读、多文件重构、调试和工具调用等长程开发任务,并可结合截图、语音备忘和录屏理解上下文。模型提供 BF16 与面向 NVIDIA Blackwell GPU 的 NVFP4 检查点,部署时需要 816B 级别的显存容量,但计算速度接近 42B 模型。对开发者而言,Muse Spark Open 通过统一接口提供多模态推理、长上下文和 Agent 工作流能力,并支持 Transformers、llama.cpp、vLLM 与 SGLang 等推理方案。
9.3 KB
9.7 KB
15.6 KB
7.8 KB
8.6 KB
10.5 KB
14.7 KB
4.2 KB
3.9 KB
452.5 KB
160.8 KB
244.7 KB
160.8 KB
200.5 KB
228.5 KB
136.2 KB
90.4 KB
中文
Muse Spark Open 是 Meta 推出的开放权重模型。这款混合专家模型将文本、图像、音频和视频整合到一个约有 8160 亿参数的模型中,每个 token 约激活 420 亿参数,并支持最长 100 万 token 的上下文窗口。它生成文本,为开发者提供统一接口,以便针对不同类型的输入提出问题。
继 Muse Glimmer 之后,Muse Spark Open 在更大的规模上引入了混合专家架构,并成为迄今为止能力最强的美国开放权重模型。
Meta 针对 Agentic Coding 训练了 Muse Spark Open:包括阅读代码库、编写和调试代码以及调用工具。它还可接收图像、音频和视频输入,因此同一模型能够在处理你的代码时读取截图、听取语音备忘录或观看屏幕录制。本篇文章将介绍如何运行和微调该模型,以及我们基于它构建了什么。可在此处找到全部模型。
总体能力与架构
Meta 将 Muse Spark Open 描述为一款针对编程优化的模型,训练数据覆盖多文件重构和长时间调试会话等真实开发者工作流。Muse Spark Open 是一款专注于 Agent 的模型,能够在长任务中规划、行动、观察并自我纠正,其中包括利用图像浏览网页。
| 功能 | Muse Spark Open |
|---|---|
| 模型规模 | 总参数量约 816B;每个 token 激活约 42B 参数 |
| 专家路由 | 每个 MoE 层包含 256 个专家;每个 token 选择 8 个 |
| 输入 | 文本、图像、音频和视频 |
| 输出 | 文本 |
| 上下文窗口 | 最多 1M token |
| 检查点格式 | BF16 和 NVFP4 |
检查点仓库为 Muse-Spark-Open-816B-A42B 和 Muse-Spark-Open-816B-A42B-NVFP4。
Muse Spark Open 是 Muse 系列模型中的全尺寸模型。Meta 于 8 月发布的 Muse Glimmer 是同一系列中的小型稠密模型,适合本地运行。两款模型使用相同的 tokenizer 和词表。聊天模板沿用 Muse Glimmer 模板,并为新模态增加了扩展。在 Muse Spark Open 中,输入嵌入层和输出层是两个独立矩阵,每个矩阵约有 16.6 亿参数。
混合专家
该语言模型有 62 层,隐藏维度为 8192。每层具有 128 个 query heads 和 16 个 key-value heads(分组查询注意力,grouped-query attention)。每个 head 的维度为 64。注意力块包含输出门控和输出归一化层。模型还会对 query 和 key 应用归一化(QK-norm)。每个块通过可学习的残差门控将输入与输出结合,而非简单相加。
Muse Glimmer 在每一层使用一个稠密前馈网络。Muse Spark Open 则以混合专家(MoE)块替代这一稠密网络。每个 MoE 块包含 256 个专家,路由器为每个 token 选择 8 个专家。每个专家都是一个前馈网络,先将维度从 8192 投影至 4096,再投影回 8192,随后对其输出应用独立归一化。专家参数约占模型总参数量的 97%。
每个 token 只运行 8 个专家,因此模型每个 token 的计算量约对应 42B 参数。所有 256 个专家都需保留在内存中,因此部署需要 816B 参数模型级别的内存,但运行速度显著接近 42B 模型。BF16 检查点以 safetensors 格式存储时约为 1.5 TB。NVFP4 检查点以 4 位精度存储参数,精度损失可忽略,专门面向 NVIDIA Blackwell GPU。在 transformers 中,BF16 检查点可通过张量并行(TP=32)运行于 4 个节点、每节点 8 张 H200 GPU;NVFP4 则可运行于单个 B200 节点。如果要部署 Muse Spark Open,请参考下方的 llama.cpp、vLLM 和 SGLang 配方。
感知编码器
与 Muse Glimmer 类似,感知编码器会将图像和视频帧转换为供语言模型使用的 token。该编码器有 18 亿参数、50 层、1536 的隐藏维度和 16 个注意力头。它将每张图像划分为 14×14 的 patch,并生成 4096 维特征。位置信息来自学习式绝对嵌入和 2D RoPE。每层中的前馈网络使用 LayerNorm 和 GELU。每第四层及最后一层使用完整注意力,其余层使用稀疏注意力。
Muse Glimmer 30B 使用了具有相同架构的编码器。该设计遵循 Meta 的 Perception Encoder 工作。视频输入与图像输入经过相同的编码器。
音频编码器
Muse Spark Open 通过其音频编码器接收音频输入。音频 tokenizer 将音频转换为 token,聊天模板使用 <|audio|> token 标记音频位置。该编码器每 80 毫秒输出一个音频 token,即每秒生成 12.5 个 token。例如,对于 10 秒音频,输入音频 token 数量为 125。编码器本身采用卷积金字塔架构,每个阶段由具有不同 patch 大小的 patch embedder,以及两个内核大小为 7、步长为 1 的一维卷积块组成。这些阶段针对 [16, 6, 5, 4] 的 patch 大小重复执行。在最终阶段结束时,时间帧会被送入最后一个由 RMSNorm → 线性投影 → RMSNorm 构成的模块。
长上下文
推理时上下文窗口为 1M token。配置将 max_position_embeddings 设为 1,048,576。这一窗口将图像、视频和音频 token 与文本 token 一同计入。
对于如此规模的模型,分组查询注意力可使 KV cache 保持较小。每个 token 向缓存中增加 2 × 16 heads × 64 dimensions × 62 layers = 126,976 个值。以 BF16 存储时,每个 token 约占 250 KB,完整的 100 万 token 上下文约占 266 GB。
推理支持
Transformers
Muse Spark Open 实现提供 MuseSparkForConditionalGeneration,用于从多模态输入生成文本;还提供 MuseSparkProcessor,用于准备对话输入。该 processor 组合了 tokenizer、图像和视频处理器、音频特征提取器以及聊天模板。
使用 DistributedConfig 配置并行设置。tp_size 是稠密层进行分片的设备数量,ep_size 是专家分布所在的设备数量。
可以按如下方式初始化模型和 processor。
import os
from transformers import AutoModelForMultimodalLM, AutoTokenizer, DistributedConfig
distributed_config = DistributedConfig(
tp_size=int(os.environ["WORLD_SIZE"]),
ep_size=int(os.environ["WORLD_SIZE"]),
)
tokenizer = AutoTokenizer.from_pretrained("meta-models/Muse-Spark-Open-816B-A42B
")
model = AutoModelForMultimodalLM.from_pretrained(
"meta-models/Muse-Spark-Open-816B-A42B",
distributed_config=distributed_config,
)
messages = [
{"role": "user", "content": "Explain in one sentence why the sky is usually blue."},
]
inputs = tokenizer.apply_chat_template(
messages,
reasoning_effort="medium",
add_generation_prompt=True,
tokenize=True,
return_dict=True,
return_tensors="pt",
).to(model.device).to(model.dtype)
input_len = inputs["input_ids"].shape[-1]
outputs = model.generate(**inputs, max_new_tokens=2000)
纯文本推理
准备对话后,将 messages 传给 processor.apply_chat_template,并启用 add_generation_prompt=True、tokenize=True、return_dict=True 和 return_tensors="pt"。将 processor 输出传入 model.generate,并对新生成的 token 进行解码,同时排除输入前缀。processor 提供推理强度控制,将符号级别(low/medium/high/xhigh)映射为模型可接受的整数值(16、64、256、512)。请注意,Muse Spark Open 无法关闭推理;如果希望在解决较简单任务时消耗更少 token,请将模型推理维持在“low”。也可以通过在 system prompt 中加入类似 Reasoning strength: 1 的一行来设定数值化强度。
messages = [
{"role": "system", "content": "You should only answer with a number."},
{"role": "user", "content": "What is 17 * 23?"},
]
inputs = processor.apply_chat_template(
messages,
add_generation_prompt=True,
tokenize=True,
return_dict=True,
return_tensors="pt",
reasoning_effort="high",
).to(model.device).to(model.dtype)
output = model.generate(**inputs, max_new_tokens=2000)
generated_tokens = output[0][inputs["input_ids"].shape[1] :]
print(processor.decode(generated_tokens, skip_special_tokens=False))
图像与文本
Muse Spark Open processor 会将每个图像标记扩展为处理后图像所需数量的 patch token,并在其周围添加图像边界 token。这种扩展可使文本位置与传入模型的视觉特征保持对齐。processor 还支持在单个 prompt 中处理多张图像。
image_url = (
"https://huggingface.co/datasets/merve/vl-test-suite/"
"resolve/main/pills.jpg"
)
messages = [
{
"role": "user",
"content": [
{
"type": "image",
"image": image_url,
},
{
"type": "text",
"text": "Do any of the components in this supplement interact?",
},
],
},
]
inputs = processor.apply_chat_template(
messages,
tokenize=True,
add_generation_prompt=True,
reasoning_effort="medium",
return_dict=True,
return_tensors="pt",
).to(model.device).to(model.dtype)
input_len = inputs["input_ids"].shape[-1]
outputs = model.generate(**inputs, max_new_tokens=2000)
response = processor.decode(outputs[0][input_len:], skip_special_tokens=False)
processor.parse_response(response)
视频推理
视频 prompt 除了视觉内容外,还包含帧时间信息。processor 可处理带有音频的视频(得益于音频编码器,这相比 Muse Glimmer 是一次升级)。processor 会对视频帧和音频进行下采样,以使帧彼此对齐。默认情况下,视频按 2 FPS 采样,最多采集 96 帧。可通过设置视频处理器的 fps 修改此行为:
processor.video_processor.fps = 4.0
一般而言,视频是按时间顺序排列的帧;下采样程度越高,特定事件之间丢失的帧就越多。因此,如果希望生成结果更准确,需要保持较高 fps。不过这存在权衡,因为会需要更多内存,并增加 prefill 延迟。视频帧会与标明时间戳的文本输入交错排列,例如“Time: 3.5s”。若要传入带音频的视频,请向 apply_chat_template 传递 load_audio_from_video=True。
使用 return_metadata=True 准备输入时,请保留视频的元数据,以便 processor 分配正确的帧率。
import torch
messages = [
{
"role": "user",
"content": [
{
"type": "text",
"text": (
"Describe what happens in this video. "
"Use timestamps and include relevant speech or sounds."
),
},
{
"type": "video",
"url": "https://huggingface.co/datasets/merve/vlm_test_images/resolve/main/ramen.mp4"
},
],
}
]
inputs = processor.apply_chat_template(
messages,
add_generation_prompt=True,
tokenize=True,
return_dict=True,
return_tensors="pt",
load_audio_from_video=True,
return_metadata=True,
).to(model.device).to(model.dtype)
with torch.inference_mode():
output_ids = model.generate(
**inputs,
max_new_tokens=256,
do_sample=False,
)
generated_ids = output_ids[:, inputs["input_ids"].shape[1] :]
response = processor.batch_decode(
generated_ids,
skip_special_tokens=True,
)[0]
print(response)
音频推理
Muse Spark Open 的音频塔接收原始波形。processor 期望输入为 24 kHz 单声道音频,并会将波形填充至 1,920 个采样点的倍数,这对应每 80 毫秒一个音频嵌入。直接向 processor 提供其他采样率的音频时,必须先进行重采样。可使用 transformers 的 load_audio 工具完成此操作。load_audio 使用 torchcodec、librosa 或 torchaudio 后端,因此在运行推理前,请确保本地已安装其中之一。
不过,如果只想通过 messages 使用 apply_chat_template,这些操作都会在底层自动处理:
import torch
from transformers import AutoProcessor, AutoModelForMultimodalLM
model_id = "meta-models/Muse-Spark-Open-816B-A42B"
processor = AutoProcessor.from_pretrained(model_id)
model = AutoModelForMultimodalLM.from
English / 原文
Muse Spark Open is an open-weight model from Meta. The mixture of experts model brings text, images, audio, and video into a model with approximately 816 billion parameters, around 42 billion active per token, and a context window of up to one million tokens. It generates text, giving developers a common interface for asking questions about different kinds of input.
Following Muse Glimmer, Muse Spark Open introduces a mixture-of-experts architecture at a much larger scale, and the most capable US open-weights model to date.
Meta trained Muse Spark Open for agentic coding: reading a codebase, writing and debugging code, and calling tools. It also takes images, audio, and video as input, so the same model can read a screenshot, listen to a voice note, or watch a screen recording while it works on your code. This post shows you how to run it, how to fine-tune it, and what we built with it. Find all the models here.
Overall Capabilities and Architecture
Meta describes Muse Spark Open as a coding-optimized model trained on real developer workflows such as multi-file refactors and long debugging sessions. Muse Spark Open is an agentic focused model that plans, acts, observes, and self-corrects over long tasks, including browsing the web with images.
| Feature | Muse Spark Open |
|---|---|
| Model size | ~816B total parameters; ~42B active per token |
| Expert routing | 256 experts per MoE layer; 8 selected per token |
| Inputs | Text, images, audio, and video |
| Output | Text |
| Context window | Up to 1M tokens |
| Checkpoint formats | BF16 and NVFP4 |
The checkpoint repositories are Muse-Spark-Open-816B-A42B and Muse-Spark-Open-816B-A42B-NVFP4.
Muse Spark Open is the full-size model of the Muse series of models. Muse Glimmer, which Meta released in August, is a small dense model from the same series, ideal for running locally. Both models use the same tokenizer and vocabulary. The chat template follows the Muse Glimmer template, with additions for the new modalities. In Muse Spark Open the input embedding and the output layer are separate matrices of about 1.66B parameters each.
Mixture of Experts
The language model has 62 layers and a hidden dimension of 8192. Each layer has 128 query heads and 16 key-value heads (grouped-query attention). Each head has 64 dimensions. The attention block has an output gate and an output normalization layer. The model also applies normalization to the queries and the keys (QK-norm). Each block combines its input and its output through a learned residual gate, not through a plain sum.
Muse Glimmer uses one dense feed-forward network in each layer. Muse Spark Open replaces this dense network with a Mixture-of-Experts (MoE) block. Each MoE block has 256 experts, and a router selects 8 experts for each token. Each expert is a feed-forward network that projects from 8192 to 4096 dimensions and back to 8192, then applies its own normalization to its output. The experts hold ~97% of the total model parameters.
Only 8 experts run per token, so the model computes each token with about 42B parameters. All 256 experts stay in memory, so deployment needs the memory of an 816B-parameter model, but runs at the much faster speed of a 42B model. The BF16 checkpoint is about 1.5 TB in safetensors format. The NVFP4 checkpoint stores the parameters in 4-bit precision with negligible loss in accuracy, specifically for NVIDIA Blackwell GPUs. In transformers, the BF16 checkpoint runs across 4 nodes of 8 H200 GPUs with tensor parallelism (TP=32) and the NVFP4 runs on a single B200 node. If you want to deploy Muse Spark Open, check out the llama.cpp, vLLM, and SGLang recipes below.
Perception Encoder
A perception encoder converts images and video frames into tokens for the language model, just like Muse Glimmer. The encoder has 1.8B parameters, 50 layers, a hidden dimension of 1536, and 16 attention heads. It splits each image into 14×14 patches and produces features with 4096 dimensions. Position information comes from learned absolute embeddings and 2D RoPE. The feed-forward network in each layer uses LayerNorm and GELU. Every fourth layer and the last layer use full attention, and the other layers use sparse attention.
Muse Glimmer 30B uses an encoder with the same architecture. The design follows the Perception Encoder work from Meta. Video input goes through the same encoder as images.
Audio Encoder
Muse Spark Open accepts audio as input through its audio encoder. An audio tokenizer converts the audio into tokens, and the chat template marks the audio position with <|audio|> tokens. The encoder emits one audio token every 80 ms, which yields 12.5 tokens per second. So let’s say, you have an audio of 10 seconds, the number of input audio tokens would be 125. The encoder itself is a convolutional pyramid where each stage consists of a patch embedder of different patch sizes and 2 convolutional blocks of 1d kernels of size 7 with stride of 1. These stages are repeated for patch sizes of [16, 6, 5, 4]. At the end of the final stage, the temporal frames are fed to a final block of RMSNorm → linear projection → RMSNorm.
Long Context
The context window is 1M tokens at inference. The configuration sets max_position_embeddings to 1,048,576. This includes image, video, and audio tokens in the same window as text.
Grouped-query attention keeps the KV cache small for a model of this size. Each token adds 2 × 16 heads × 64 dimensions × 62 layers = 126,976 values to the cache. In BF16, this is about 250 KB per token and about 266 GB for a full 1M-token context.
Inference Support
Transformers
The Muse Spark Open implementation provides MuseSparkForConditionalGeneration for text generation from multimodal inputs and MuseSparkProcessor for preparing conversations. The processor combines the tokenizer, image and video processors, audio feature extractor, and chat template.
Use a DistributedConfig to configure the parallelism settings. tp_size is the number of devices across which the dense layers are sharded, and ep_size is the number of devices across which the experts are distributed.
You can initialize the model and processor as follows.
import os
from transformers import AutoModelForMultimodalLM, AutoTokenizer, DistributedConfig
distributed_config = DistributedConfig(
tp_size=int(os.environ["WORLD_SIZE"]),
ep_size=int(os.environ["WORLD_SIZE"]),
)
tokenizer = AutoTokenizer.from_pretrained("meta-models/Muse-Spark-Open-816B-A42B
")
model = AutoModelForMultimodalLM.from_pretrained(
"meta-models/Muse-Spark-Open-816B-A42B",
distributed_config=distributed_config,
)
messages = [
{"role": "user", "content": "Explain in one sentence why the sky is usually blue."},
]
inputs = tokenizer.apply_chat_template(
messages,
reasoning_effort="medium",
add_generation_prompt=True,
tokenize=True,
return_dict=True,
return_tensors="pt",
).to(model.device).to(model.dtype)
input_len = inputs["input_ids"].shape[-1]
outputs = model.generate(**inputs, max_new_tokens=2000)
Text-only Inference
Prepare the conversation, then pass the messages to processor.apply_chat_template, enabling add_generation_prompt=True, tokenize=True, return_dict=True, and return_tensors="pt". Pass the processor output to model.generate and decode the newly generated tokens, excluding the input prefix. The processor has a lever for the reasoning effort, mapping symbolic levels (low/medium/high/xhigh) to the integers the model itself accepts (16, 64, 256, 512). Note that turning off reasoning is not possible with Muse Spark Open, so keep the model reasoning at “low” if you want to consume less tokens to solve an easier task. You can also set a numeric effort by including a line like Reasoning strength: 1 in the system prompt.
messages = [
{"role": "system", "content": "You should only answer with a number."},
{"role": "user", "content": "What is 17 * 23?"},
]
inputs = processor.apply_chat_template(
messages,
add_generation_prompt=True,
tokenize=True,
return_dict=True,
return_tensors="pt",
reasoning_effort="high",
).to(model.device).to(model.dtype)
output = model.generate(**inputs, max_new_tokens=2000)
generated_tokens = output[0][inputs["input_ids"].shape[1] :]
print(processor.decode(generated_tokens, skip_special_tokens=False))
Images and Text
The Muse Spark Open processor expands each image marker into the number of patch tokens required by the processed image, surrounded by image boundary tokens. This expansion keeps the text positions aligned with the visual features passed to the model. The processor also handles multiple images within a single prompt.
image_url = (
"https://huggingface.co/datasets/merve/vl-test-suite/"
"resolve/main/pills.jpg"
)
messages = [
{
"role": "user",
"content": [
{
"type": "image",
"image": image_url,
},
{
"type": "text",
"text": "Do any of the components in this supplement interact?",
},
],
},
]
inputs = processor.apply_chat_template(
messages,
tokenize=True,
add_generation_prompt=True,
reasoning_effort="medium",
return_dict=True,
return_tensors="pt",
).to(model.device).to(model.dtype)
input_len = inputs["input_ids"].shape[-1]
outputs = model.generate(**inputs, max_new_tokens=2000)
response = processor.decode(outputs[0][input_len:], skip_special_tokens=False)
processor.parse_response(response)
Video Inference
Video prompts include frame timing as well as visual content. The processor handles videos with audios in them (which is an upgrade from Muse Glimmer thanks to the audio encoder). The processor downsamples video frames and audio to align frames together. By default, videos are sampled to 2 FPS, capped at 96 frames. You can modify this by setting the fps of the video processor:
processor.video_processor.fps = 4.0
As a general rule of thumb, videos are frames in temporal sequence, and the more you downsample, the more you will lose frames in between specific events, so you need to keep fps high if you want more accurate generations. However, there’s a trade-off because you will require more memory and increase latency for prefill. The frames are interleaved with text input that states timestamps (e.g. “Time: 3.5s”). To enable passing in videos with audio, pass load_audio_from_video=True to apply_chat_template.
Preserve the video's metadata when preparing inputs with return_metadata=True so the processor can assign the correct framerate.
import torch
messages = [
{
"role": "user",
"content": [
{
"type": "text",
"text": (
"Describe what happens in this video. "
"Use timestamps and include relevant speech or sounds."
),
},
{
"type": "video",
"url": "https://huggingface.co/datasets/merve/vlm_test_images/resolve/main/ramen.mp4"
},
],
}
]
inputs = processor.apply_chat_template(
messages,
add_generation_prompt=True,
tokenize=True,
return_dict=True,
return_tensors="pt",
load_audio_from_video=True,
return_metadata=True,
).to(model.device).to(model.dtype)
with torch.inference_mode():
output_ids = model.generate(
**inputs,
max_new_tokens=256,
do_sample=False,
)
generated_ids = output_ids[:, inputs["input_ids"].shape[1] :]
response = processor.batch_decode(
generated_ids,
skip_special_tokens=True,
)[0]
print(response)
Audio Inference
The Muse Spark Open audio tower consumes a raw waveform. The processor expects mono audio at 24 kHz and pads the waveform to a multiple of 1,920 samples, corresponding to one audio embedding per 80 milliseconds. Audio supplied directly to the processor at another sample rate must first be resampled. You can do this by using the load_audio util of transformers. load_audio uses torchcodec, librosa or torchaudio backends, so make sure to have one of these installed locally before running inference.
If you want to simply use apply_chat_template with messages though, this is all handled for you under the hood:
import torch
from transformers import AutoProcessor, AutoModelForMultimodalLM
model_id = "meta-models/Muse-Spark-Open-816B-A42B"
processor = AutoProcessor.from_pretrained(model_id)
model = AutoModelForMultimodalLM.from_pretrained(model_id).eval()
messages = [
{
"role": "user",
"content": [
{
"type": "audio",
"url": "https://huggingface.co/buckets/huggingface/audio-samples/resolve/bbaudio_question_39.mp3",
},
{
"type": "text",
"text": "Answer the question.",
},
],
}
]
inputs = processor.apply_chat_template(
messages,
add_generation_prompt=True,
tokenize=True,
return_dict=True,
return_tensors="pt",
load_audio_backend="auto",
).to(model.device).to(model.dtype)
with torch.inference_mode():
output_ids = model.generate(
**inputs,
max_new_tokens=128,
do_sample=False,
)
prompt_length = inputs["input_ids"].shape[1]
generated_text = processor.batch_decode(
output_ids[:, prompt_length:],
skip_special_tokens=True,
)
print(generated_text[0])
The processor inserts the matching number of audio tokens between audio boundary markers. It also returns a mask identifying real samples, allowing the model to exclude padded audio embeddings.
Tool Calling
Muse Spark Open can do text-only and multimodal tool calling. You can make the model call tools as follows.
from transformers import AutoProcessor, AutoModelForMultimodalLM
MODEL_ID = "meta-models/Muse-Spark-Open-816B-A42B"
processor = AutoProcessor.from_pretrained(MODEL_ID)
model = AutoModelForMultimodalLM.from_pretrained(
MODEL_ID,
dtype="auto",
device_map="auto"
)
tools = [
{
"type": "function",
"function": {
"name": "weather.get",
"description": "Get the current weather for a city.",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string"},
},
"required": ["city"],
},
},
}
]
messages = [
{
"role": "user",
"content": [
{"type": "image", "image": "https://huggingface.co/datasets/merve/vl-test-suite/resolve/main/SF.png"},
{"type": "text", "text": "I'm going to the city in this picture. What clothes should I wear?"},
],
},
]
inputs = processor.apply_chat_template(
messages,
tools=tools,
tokenize=True,
return_dict=True,
return_tensors="pt",
add_generation_prompt=True,
reasoning_strength="high"
).to(model.device).to(model.dtype)
input_len = inputs["input_ids"].shape[-1]
outputs = model.generate(**inputs)
response = processor.parse_response(
completion,
prefix=inputs["input_ids"][0],
tools=tools,
)
print(response)
Muse Spark Open uses a channel-based chat template (Harmony, first introduced by gpt-oss). Note that you don’t have to know about the internals, but it’s useful to check the channels the model routes to, in case you get low quality outputs. In the input message below:
<|begin_of_text|>
<|start|>system<|message|>
You are a helpful AI assistant.
Knowledge cutoff: 2026-01-04.
Current date: ...
...
<|eot|>
<|start|>user<|message|>...
<|eot|>
<|start|>assistant
<|start|>assistant is intentionally left open, it’s the model that chooses recipient with to= . The model has different recipients, e.g. self asks the model to reason,
to=self<|message|>the model reasons here<|eom|> # reasoning
<|start|>assistant to=user<|message|>final answer<|eot|> # final answer
self is for reasoning, commentary are comments before and between tool calls visible to the end user, user is the final response.
Tool-call routing is parsed as follows (assuming you have passed tools to apply_chat_template:
<|start|>assistant to=weather.get<|message|>
<atem:function_calls>
<atem:invoke name="weather.get">
<atem:parameter name="city">San Francisco</atem:parameter>
</atem:invoke>
</atem:function_calls>
<|eot|>
Llama.cpp
Muse Spark 2-bit running on Llama Server
Muse Spark Open is integrated in llama.cpp and comes in the prebuilt binaries. You can install this with following command:
curl -LsSf https://llama.app/install.sh | sh
You can start the server as follows with quant suffix attached to model ID:
llama serve -hf ggml-org/Muse-Spark-Open-816B-A42B-GGUF:Q2_K
The repository containing quants is here. Once the server has started, you can head to localhost:9931 to chat with the built-in WebUI. From the web UI you can add audio and images for inference and adjust the reasoning lever.
Note that turning off reasoning is not possible with Muse Spark Open, so keep the model reasoning at “low” if you want to consume less tokens to solve an easier task.
We tested quants on Mac M3 Ultra (512GB). An imatrix-calibrated 2-bit quant runs at 18 tokens/s, with plenty of room free for the KV cache (304 GB used by the model).
You can also query the server as follows. Feel free to check out the API reference for multimodality, tool calls and more.
## Text-only inference
curl http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Write a limerick about python exceptions"}
]
}'
## Image-text inference
curl -s http://127.0.0.1:8080/v1/chat/completions \
-H "Content-Type: application/json" -H "Authorization: Bearer <your-key>" \
-d '{"model":"muse-spark-open","messages":[{"role":"user","content":[
{"type":"text","text":"What is in this image?"},
{"type":"image_url","image_url":{"url":"data:image/png;base64,..."}}
]}],"temperature":0}'
## Audio-text inference
curl -s http://127.0.0.1:8080/v1/chat/completions \
-H "Content-Type: application/json" -H "Authorization: Bearer <your-key>" \
-d '{"model":"muse-spark-open","messages":[{"role":"user","content":[
{"type":"text","text":"Transcribe this audio."},
{"type":"input_audio","input_audio":{"data":"data:audio/wav;base64,..."}}
]}],"temperature":0}'
llama.cpp team ships different quantized versions. We have tested Q2_K, Q4_K_S and Q_8 on Apple Silicon chips. You can run each quant by adding the quant id as suffix, llama serve -hf ggml-org/Muse-Spark-Open-816B-A42B:Q2_K.
SGLang
The Muse Spark Open integration for SGLang supports text, image, audio, and video inputs. The NVFP4 reference configuration runs across four GB300 GPUs.
From the SGLang integration environment, download the checkpoint from the Hugging Face Hub and start the server:
export MODEL_ID=meta-models/Muse-Spark-Open-816B-A42B-NVFP4
export CKPT="$(hf download "$MODEL_ID")"
SGLANG_FLASHINFER_NVFP4_PER_TOKEN_ACTIVATION=1 \
uv run sglang_meta serve \
--model-path "$CKPT" \
--served-model-name "$MODEL_ID" \
--quantization modelopt_fp4 \
--moe-runner-backend flashinfer_trtllm \
--tp-size 4 \
--ep-size 4 \
--port 30000
The checkpoint includes the chat template, which we pass explicitly. The launcher configures the Muse reasoning and tool-call parsers.
Send a request through the OpenAI-compatible API:
curl http://localhost:30000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "meta-models/Muse-Spark-Open-816B-A42B-NVFP4",
"messages": [{
"role": "user",
"content": "Explain how a mixture-of-experts model works."
}],
"max_tokens": 2048
}'
The response separates the reasoning trace in reasoning_content from the final answer in content.
vLLM
The Muse Spark Open reference integration for vLLM supports text and image inputs with the NVFP4 checkpoint that require blackwell series GPUs.
After installing the reference plugin and its dependencies, download the checkpoint from the Hugging Face Hub and launch the server:
export MODEL_ID=meta-models/Muse-Spark-Open-816B-A42B-NVFP4
export CKPT="$(hf download "$MODEL_ID")"
VLLM_ALLOW_LONG_MAX_MODEL_LEN=1 \
VLLM_PLUGINS=musespark1x_models,ptq_nvfp4 \
vllm serve "$CKPT" \
--served-model-name "$MODEL_ID" \
--tokenizer-mode musespark1x \
--config-format auto \
--load-format internal_safetensor \
--tensor-parallel-size 4 \
--enable-expert-parallel \
--max-model-len 131072 \
--gpu-memory-utilization 0.92 \
--reasoning-parser musespark1x \
--tool-call-parser musespark1x \
--enable-auto-tool-choice \
--port 8000
This configuration sets a 128K-token serving context. The plugin supplies the model implementation, checkpoint loader, and reasoning and tool-call parsers.
Send a request using the same Hub model ID:
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "meta-models/Muse-Spark-Open-816B-A42B-NVFP4",
"messages": [{
"role": "user",
"content": "Explain how a mixture-of-experts model works."
}],
"max_tokens": 2048
}'
MLX
Muse Spark Open is available in oMLX and mlx-lm today. oQ quants optimized for oMLX are available in 3-bit and 4-bit, ready to use right away.
We tested the oQ3e quant on an M3 Ultra (512 GB). The model takes about 344 GB, leaving room for the KV cache, and runs at about 225 tok/s prefill and 21 tok/s generation with a 1024-token prompt and 128 generated tokens.
Once you download the model through the oMLX interface, you can chat with it in the built-in chat UI. From the chat UI you can add images and adjust the reasoning effort on the fly, from low to xhigh. The model’s reasoning shows up as a collapsible thinking block, separate from the final answer.
Note that it's not possible to turn reasoning off, and the default (Auto) uses xhigh. Set it to “low” if you want to use fewer tokens on easier tasks. 
The language model is also available in this PR of the official mlx-lm repository. You can run it on the same high-quality oQ3e quant like this:
mlx_lm.generate --model mlx-community/Muse-Spark-Open-816B-A42B-oQ3e \
--prompt "Explain convolutional networks like I am 5" \
--max-tokens 5000
This is a big model, even the 3-bit quantization requires more than 256 GB of RAM, as explained above. You can also run distributed inference across multiple computers, please refer to the documentation for details.
Deploying Muse Spark Open with Inference Endpoints
You can deploy Muse Spark Open on Inference Endpoints with a pre-validated SGLang recipe for the NVFP4 variant which runs on either 8 × NVIDIA RTX Pro 6000 98 GB with 131072 context length, or with 8 x NVIDIA H200 141GB if you want 1048576 context length instead.
To deploy, run one command with the Hugging Face CLI:
hf endpoints catalog deploy --repo meta-models/Muse-Spark-Open-816B-A42B-NVFP4 --name muse-spark
Or open endpoints.huggingface.co/new/meta-models/Muse-Spark-Open-816B-A42B-NVFP4 and select Create Endpoint.
The endpoint exposes an OpenAI-compatible API with both Chat Completions API at /v1/chat/completions and Responses API at /v1/responses.
curl "https://<your-endpoint>.endpoints.huggingface.cloud/v1/chat/completions" \
-H "Authorization: Bearer $HF_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"model": "meta-models/Muse-Spark-Open-816B-A42B-NVFP4",
"messages": [{
"role": "user",
"content": [
{"type": "image_url", "image_url": {"url": "https://huggingface.co/datasets/merve/vl-test-suite/resolve/main/pills.jpg"}},
{"type": "text", "text": "Do any of the components in this supplement interact?"}
]
}],
"chat_template_kwargs": {"enable_thinking": false}
}'
Any OpenAI-compatible client works with the same URL and your Hugging Face token as the API key.
Fine-tuning with TRL
You can fine-tune the 816B checkpoint with the TRL SFTTrainer. This section shows how we fine-tuned it with TRL on 8 nodes of 8 H100 GPUs. The recipe trains LoRA adapters on the attention layers. The experts stay frozen. The full script is in the TRL examples.
First, we need to split the model across 64 GPU devices. Given the large size of the model, we need to parallelize it across multiple axes. We shard the model with FSDP and split the experts across GPUs, using DistributedConfig, which tells transformers how to split the model when it loads:
from transformers.distributed import DistributedConfig
distributed_config = DistributedConfig(fsdp_size=64, ep_size=8)
In the snippet above, fsdp_size=64 shards the model across all 64 GPUs with FSDP2, and ep_size=8 splits the 256 experts of each layer into 8 groups. Transformers sends each token to the GPU that holds its expert, so each GPU trains on its own slice of the batch.
Now, we can configure the SFTConfig for our training run. We’ve performed a simple task here to adapt the model’s chat template on an open source dataset, but you could apply it to your own use case.
import torch
from datasets import load_dataset
from peft import LoraConfig
from transformers.distributed import DistributedConfig
from trl import SFTConfig, SFTTrainer
train_dataset = load_dataset("allenai/tulu-3-sft-mixture", split="train[:500000]")
training_args = SFTConfig(
output_dir="muse-spark-lora-sft",
model_init_kwargs={"dtype": torch.bfloat16, "distributed_config": DistributedConfig(fsdp_size=64, ep_size=8)},
per_device_train_batch_size=1,
max_steps=500,
max_length=2048,
packing=True,
save_only_model=True,
logging_steps=1,
report_to="trackio",
)
trainer = SFTTrainer(
model="meta-models/Muse-Spark-Open-816B-A42B",
args=training_args,
train_dataset=train_dataset,
peft_config=LoraConfig(r=16, lora_alpha=32, target_modules=["q_proj", "k_proj", "v_proj", "o_proj"]),
)
trainer.train()
The core parts here are packing=True which joins examples into 2048-token sequences without padding. A block-diagonal mask keeps the examples separate. save_only_model=True saves the adapter and no optimizer state, because the trainer cannot resume a model that was sharded at load time. LoraConfig targets the four attention projections and the 256 experts of each layer stay frozen.
Then we can run this command across each node:
torchrun --nnodes 8 --nproc_per_node 8 --rdzv_backend c10d --rdzv_endpoint "$MASTER_IP:29700" sft_muse_spark_open.py
We trained for 500 steps, which took about 2 hours on 64 H100s, at about 8,000 tokens per second. Mean token accuracy rose from 72% to 84% and the loss fell from 1.26 to 0.57, which signals a good fine-tuning run.
Demos
Muse Spark Open is a coding and agentic model. We wanted to see that for ourselves, so we tried a mixture of multi-modal and agentic tasks that use the model's image and audio inputs. Everything below is something you can run or fork.
3D Asset Generator
We combined 2-bit quantized Muse Spark open (served on llama.cpp) with the Pi coding agent to generate and iteratively improve 3D assets in Three.js. You can find the prompt here, as the model is quantized it requires a bit more steering. We get 18 TPS on llama.cpp on Mac Ultra.
We initially describe the asset, and Pi uses the model to generate Three.js code for the asset, renders the result in a browser, and captures screenshots from multiple angles. It then sends those images back to the same model on llama server for visual feedback. Pi uses that feedback to edit the code and repeats the process.
Browser Interactions with OpenEnv and Hugging Face Sandbox
We tested Spark on computer use tasks and were amazed by the performance, so we have built a lean demo that also serves to teach you how a computer use agent works. You can also further customize this for your needs. This is both an educational example and something you can run in a few lines. You can find it here.
Muse Spark NVFP4 Browser Agent with OpenEnv and HF Sandboxes
Hugging Face Sandboxes are sandboxes built on Hugging Face Jobs for easy code execution. The demo consists of three components:
- Muse Spark Open served with Inference Endpoints,
- OpenEnv wrapping web driver actions with helium and selenium (click, type, scroll etc) defining browser environment’s reset, step, observation, termination interface,
- Chromium web browser
where the remote sandbox contains the environment and the browser as illustrated below.
You can easily try this with a few steps, described in the example. Start Inference Endpoint with Muse Spark Open (NVFP4 works well too!), add your endpoint URL as environmental variable, publish your OpenEnv server in Spaces and also provide that, then you can run the agent loop. Muse Spark Open sees the previous actions, system prompt, url and the screenshot of the browser to take an action, and nothing else (no DOM, no HTML code, nothing) so it’s a truly multimodal browser demo.
Call your Browser
Finally, we wanted to push Spark’s agentic multimodality to the limits, so we set up this space that combines the model’s audio, image, and agentic properties into a browser agent. We give the model a general description of a thing we need and it interacts with the integrated browser to find options on Amazon.
Muse Spark Open takes the voice input and reasons over the type of product that meets the descriptions, searches for it on Amazon, and selects the most appropriate based on criteria.
Wrapping Up
Muse Spark Open is a full-size open-weight model from the Muse series. Start with the BF16 or NVFP4 checkpoint, or try one of the great llama.cpp quants. If you build something with Muse Spark Open, share it, and tell us in the repository’s discussions.






