Text Generation
Transformers
Safetensors
k2_horizon
vllm
compressed-tensors
nvfp4
fp8
mixed-precision
quantized
Mixture of Experts
mova
k2-horizon
reasoning
tool-calling
blackwell
conversational
custom_code
Instructions to use primitive-ai/K2-Horizon-MoVA-36B-A4B-mixed-NVFP4-FP8 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use primitive-ai/K2-Horizon-MoVA-36B-A4B-mixed-NVFP4-FP8 with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="primitive-ai/K2-Horizon-MoVA-36B-A4B-mixed-NVFP4-FP8", trust_remote_code=True) messages = [ {"role": "user", "content": "Who are you?"}, ] pipe(messages)# Load model directly from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained("primitive-ai/K2-Horizon-MoVA-36B-A4B-mixed-NVFP4-FP8", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use primitive-ai/K2-Horizon-MoVA-36B-A4B-mixed-NVFP4-FP8 with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "primitive-ai/K2-Horizon-MoVA-36B-A4B-mixed-NVFP4-FP8" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "primitive-ai/K2-Horizon-MoVA-36B-A4B-mixed-NVFP4-FP8", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/primitive-ai/K2-Horizon-MoVA-36B-A4B-mixed-NVFP4-FP8
- SGLang
How to use primitive-ai/K2-Horizon-MoVA-36B-A4B-mixed-NVFP4-FP8 with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "primitive-ai/K2-Horizon-MoVA-36B-A4B-mixed-NVFP4-FP8" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "primitive-ai/K2-Horizon-MoVA-36B-A4B-mixed-NVFP4-FP8", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "primitive-ai/K2-Horizon-MoVA-36B-A4B-mixed-NVFP4-FP8" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "primitive-ai/K2-Horizon-MoVA-36B-A4B-mixed-NVFP4-FP8", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }' - Docker Model Runner
How to use primitive-ai/K2-Horizon-MoVA-36B-A4B-mixed-NVFP4-FP8 with Docker Model Runner:
docker model run hf.co/primitive-ai/K2-Horizon-MoVA-36B-A4B-mixed-NVFP4-FP8
Card: report call/abstain in the headline, fix the MoVA restack figure (15.1 GB, not 7.55), one decimal throughout, pin the serve image
Browse files
README.md
CHANGED
|
@@ -29,12 +29,13 @@ thumbnail: https://huggingface.co/primitive-ai/K2-Horizon-MoVA-36B-A4B-mixed-NVF
|
|
| 29 |
<img src="https://img.shields.io/badge/vs%20BF16-1.7×%20smaller-F98424?style=flat-square" alt="1.7x smaller than BF16">
|
| 30 |
<img src="https://img.shields.io/badge/vs%20official%20FP8-8%25%20smaller-F98424?style=flat-square" alt="8 percent smaller than the official FP8">
|
| 31 |
<img src="https://img.shields.io/badge/knowledge-level%20with%20BF16%20%26%20FP8-3DD13D?style=flat-square" alt="knowledge level with BF16 and FP8">
|
| 32 |
-
<img src="https://img.shields.io/badge/
|
|
|
|
| 33 |
<img src="https://img.shields.io/badge/requires-Blackwell-lightgrey?style=flat-square" alt="requires Blackwell">
|
| 34 |
<a href="https://primitive.com"><img src="https://img.shields.io/badge/web-primitive.com-lightgrey?style=flat-square" alt="primitive.com"></a>
|
| 35 |
</p>
|
| 36 |
|
| 37 |
-
<h3 align="center">8% smaller than the official FP8, level on knowledge, 1.4 behind on
|
| 38 |
|
| 39 |
<p align="center">
|
| 40 |
Mixed-precision quantization of <a href="https://huggingface.co/IFM/K2-Horizon-MoVA-36B-A4B">IFM/K2-Horizon-MoVA-36B-A4B</a> to
|
|
@@ -42,11 +43,11 @@ Mixed-precision quantization of <a href="https://huggingface.co/IFM/K2-Horizon-M
|
|
| 42 |
15 of the 45 sparse layers carry NVFP4 experts; the other 30 carry FP8 with block scales.
|
| 43 |
</p>
|
| 44 |
|
| 45 |
-
> **This is the
|
| 46 |
> [pure NVFP4 build](https://huggingface.co/primitive-ai/K2-Horizon-MoVA-36B-A4B-NVFP4) at
|
| 47 |
> 36.74 GB that is 7.74 GB smaller, 1.21× faster at concurrency 32, and **the only one of the two
|
| 48 |
-
> that runs on Ampere**. Take this one if tool calling matters most; take that one for
|
| 49 |
-
>
|
| 50 |
|
| 51 |
---
|
| 52 |
|
|
@@ -54,21 +55,19 @@ Mixed-precision quantization of <a href="https://huggingface.co/IFM/K2-Horizon-M
|
|
| 54 |
|
| 55 |
* 🗜️ **8% smaller than IFM's own FP8, 1.7× smaller than BF16.** 44.48 GB against 48.36 GB and
|
| 56 |
74.89 GB.
|
| 57 |
-
* 🎯 **Knowledge is level with both references.** 87.
|
| 58 |
-
85.
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
layers from group-wise 4-bit to FP8 with `[128,128]` block scales is worth about a point of tool
|
| 65 |
-
calling; every build we measured between 36.74 GB and 48.39 GB otherwise lands in the same band.
|
| 66 |
* 🖥️ **One card, no tensor parallelism.** Both official recipes use TP=2; this fits TP=1 with
|
| 67 |
231,488 tokens of KV at 32K context.
|
| 68 |
* ⚠️ **Blackwell.** Two thirds of the expert layers carry FP8 block scales and sm_80 has no FP8
|
| 69 |
-
tensor cores, so we neither built nor tested this one for Ampere. The pure NVFP4 build is
|
| 70 |
-
|
| 71 |
-
* 🔧 **`
|
| 72 |
|
| 73 |
---
|
| 74 |
|
|
@@ -79,17 +78,22 @@ K2-Horizon support merged into vLLM `main` on 3 September 2026
|
|
| 79 |
0.28.0 predates it. Use a `main`/nightly build:
|
| 80 |
|
| 81 |
```bash
|
|
|
|
|
|
|
|
|
|
| 82 |
docker run --gpus all --ipc=host -p 8000:8000 -v $PWD:/models \
|
| 83 |
-
vllm/vllm-openai:nightly \
|
| 84 |
--model /models/K2-Horizon-MoVA-36B-A4B-mixed-NVFP4-FP8 \
|
| 85 |
--trust-remote-code --max-model-len 32768 \
|
| 86 |
--gpu-memory-utilization 0.92 \
|
| 87 |
--reasoning-parser k2_horizon
|
| 88 |
```
|
| 89 |
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
7.06× concurrency**
|
|
|
|
|
|
|
| 93 |
|
| 94 |
**Reasoning effort is a server-level choice on this architecture, not a per-request one.** The
|
| 95 |
template emits a different tag pair per effort and `K2HorizonReasoningParser` picks one pair once
|
|
@@ -121,10 +125,10 @@ the runs counted in the `runs k/a` column.
|
|
| 121 |
|
| 122 |
| build | size | knowledge | call | abstain | tool calling | runs k/a | finished | out/answer |
|
| 123 |
|---|---|---|---|---|---|---|---|---|
|
| 124 |
-
| [IFM BF16](https://huggingface.co/IFM/K2-Horizon-MoVA-36B-A4B) | 74.89 GB | 85.
|
| 125 |
-
| [IFM FP8](https://huggingface.co/IFM/K2-Horizon-MoVA-36B-A4B-FP8) | 48.36 GB | 86.
|
| 126 |
-
| **this repo** | **44.48 GB** | 87.
|
| 127 |
-
| [our pure NVFP4](https://huggingface.co/primitive-ai/K2-Horizon-MoVA-36B-A4B-NVFP4) | 36.74 GB | 86.
|
| 128 |
|
| 129 |
`call` is accuracy on the 160 tool-calling items that require a call; `abstain` is the 40 whose
|
| 130 |
correct action is to call **nothing**; `tool calling` is the two pooled as 200. We report the halves
|
|
@@ -132,22 +136,19 @@ separately because pooling hides which one moved. `runs k/a` is the number of kn
|
|
| 132 |
runs behind each row. `finished` is the share of the 1,170 knowledge items that answered inside the
|
| 133 |
token budget; `out/answer` is mean output tokens.
|
| 134 |
|
| 135 |
-
**Knowledge is one group.** This build's 87.
|
| 136 |
-
separate from anything: against the official FP8 it is t = +0.
|
| 137 |
-
means span 1.4 points, which is inside a single checkpoint's own repeat spread. Don't rank on this
|
| 138 |
column.
|
| 139 |
|
| 140 |
-
**Tool calling: 1.
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
and abstention is untouched.
|
| 146 |
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
residual is argument accuracy.
|
| 151 |
|
| 152 |
<details>
|
| 153 |
<summary>Per-benchmark detail, both suites</summary>
|
|
@@ -175,7 +176,7 @@ Pooled over every run behind the row, so a cell rests on `runs × items`. `when2
|
|
| 175 |
40 abstention items; the other four tool-calling benchmarks supply the 160 call items.
|
| 176 |
|
| 177 |
**Where the tool-calling difference sits.** xlam/APIGen is 40.2 here against the official FP8's
|
| 178 |
-
44.8
|
| 179 |
build gives up 7.0 points on the same benchmark, so this build recovers about a third of that loss.
|
| 180 |
xlam items carry the longest argument lists in the suite.
|
| 181 |
|
|
@@ -183,20 +184,19 @@ xlam items carry the longest argument lists in the suite.
|
|
| 183 |
|
| 184 |
> **The noise floor, and why the run counts are in the table.** Every build compared here has at
|
| 185 |
> least six agentic runs, the one exception being the BF16 reference at three. It needs to be six.
|
| 186 |
-
> The official FP8's tool-calling figure read 72.
|
| 187 |
-
>
|
| 188 |
-
>
|
| 189 |
-
>
|
| 190 |
-
> that. We publish ties as ties.
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
|
| 195 |
-
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
|
| 199 |
-
most of the time, occasional long chains — and quantization did not cause it.
|
| 200 |
|
| 201 |
---
|
| 202 |
|
|
@@ -205,7 +205,8 @@ most of the time, occasional long chains — and quantization did not cause it.
|
|
| 205 |
Cache-free, 8,192 tokens in and 512 out, one RTX PRO 6000 Blackwell, same nightly and same serve
|
| 206 |
flags as the accuracy rows. Prefix caching is disabled and every measurement runs on its own seed,
|
| 207 |
so no row is reading a cache the previous one filled. These come from one sitting and drift a few
|
| 208 |
-
percent between sittings, so read them as a bracket
|
|
|
|
| 209 |
|
| 210 |
| build | tok/s @ conc 1 | TPOT @ conc 1 | tok/s @ conc 32 | TPOT @ conc 32 | median TTFT @ conc 32 |
|
| 211 |
|---|---|---|---|---|---|
|
|
@@ -213,17 +214,17 @@ percent between sittings, so read them as a bracket rather than to the decimal.
|
|
| 213 |
| **this repo** | 29.99 | 32.56 ms | 248.4 | 89.5 ms | 3.59 s |
|
| 214 |
| [our pure NVFP4](https://huggingface.co/primitive-ai/K2-Horizon-MoVA-36B-A4B-NVFP4) | **30.45** | **32.10 ms** | **301.5** | 93.1 ms | **1.54 s** |
|
| 215 |
|
| 216 |
-
**Quantizing this model buys
|
| 217 |
-
0.
|
| 218 |
-
|
| 219 |
-
|
| 220 |
-
|
| 221 |
-
|
| 222 |
-
|
| 223 |
|
| 224 |
-
This build sits between the two on
|
| 225 |
-
|
| 226 |
-
|
| 227 |
|
| 228 |
---
|
| 229 |
|
|
@@ -232,21 +233,20 @@ this one at concurrency 32 and reaches first token in 1.54 s against 3.59 s.
|
|
| 232 |
| | **this repo** | [pure NVFP4](https://huggingface.co/primitive-ai/K2-Horizon-MoVA-36B-A4B-NVFP4) |
|
| 233 |
|---|---|---|
|
| 234 |
| size | 44.48 GB | **36.74 GB** |
|
| 235 |
-
| knowledge | 87.
|
| 236 |
-
| call | **73.
|
| 237 |
-
| abstain | 58.
|
| 238 |
-
| tool calling, pooled | 70.
|
| 239 |
| tok/s @ conc 32 | 248.4 | **301.5** |
|
| 240 |
| median TTFT @ conc 32 | 3.59 s | **1.54 s** |
|
| 241 |
| Blackwell | yes | yes |
|
| 242 |
| **Ampere (A100)** | **no** | **yes** |
|
| 243 |
|
| 244 |
-
This build spends 7.74 GB, +21%, and call accuracy is the one axis that pays it back: +1.
|
| 245 |
-
t = +2.
|
| 246 |
-
(t = +0.
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
half of the suite resolves on its own.
|
| 250 |
|
| 251 |
**On Ampere.** We have not tested this build on an A100 and do not expect FP8 block scales to load
|
| 252 |
on sm_80, which has no FP8 tensor cores. The pure NVFP4 build does run there through Marlin
|
|
@@ -262,7 +262,7 @@ different `temperature`, or whether the model was allowed to reason at all. So e
|
|
| 262 |
table, on this card and on our other cards, comes from the one fixed protocol described above — the
|
| 263 |
same 1,370 items, auto-scored, no LLM judge.
|
| 264 |
|
| 265 |
-
| model | shape | size | overall | knowledge | call | abstain | finished | out |
|
| 266 |
|---|---|---|---|---|---|---|---|---|
|
| 267 |
| [Laguna-XS-2.1](https://huggingface.co/primitive-ai/Laguna-XS-2.1-mixed-NVFP4-MXFP8) | 31 B MoE | 19.3 GiB | 81.7 | 83.8 | 68.4 | 73.5 | 98.9% | 1097 |
|
| 268 |
| [Nemotron-3.5-Lightning-30B-A3B](https://huggingface.co/primitive-ai/Nemotron-3.5-Lightning-30B-A3B-mixed-INT4-INT8) | 30 B MoE+Mamba | 19.2 GiB | 87.1 | 87.9 | 85.4 | 70.5 | 97.9% | 1429 |
|
|
@@ -270,17 +270,17 @@ same 1,370 items, auto-scored, no LLM judge.
|
|
| 270 |
| [Muse-Glimmer-30B](https://huggingface.co/primitive-ai/Muse-Glimmer-30B-mixed-NVFP4) | 30 B MoE | 20.4 GiB | 86.6 | 88.8 | 78.6 | 54.5 | 99.7% | 800 |
|
| 271 |
| [Qwen3.8-27B](https://huggingface.co/primitive-ai/Qwen3.8-27B-mixed-NVFP4-FP8) | 27 B dense | 20.7 GiB | 88.8 | 90.4 | 85.5 | 54.5 | 99.7% | 651 |
|
| 272 |
| [Granite-4.2-30B](https://huggingface.co/primitive-ai/granite-4.2-30b-mixed-NVFP4-FP8) | 30 B dense | 18.1 GB | 85.5 | 86.2 | 85.8 | 60.8 | 98.5% | 1502 |
|
| 273 |
-
| [K2-Horizon-MoVA-36B-A4B NVFP4](https://huggingface.co/primitive-ai/K2-Horizon-MoVA-36B-A4B-NVFP4) | 37 B MoE+MoVA, 4 B active | 36.
|
| 274 |
-
| **K2-Horizon-MoVA-36B-A4B mixed** (this repo) | 37 B MoE+MoVA, 4 B active | **44.
|
| 275 |
| [Laguna-S-2.1](https://huggingface.co/primitive-ai/Laguna-S-2.1-mixed-NVFP4-MXFP8) | 110 B MoE | 64.0 GiB | 84.3 | 87.1 | 64.6 | 81.0 | 97.3% | 995 |
|
| 276 |
| [Qwen3.8-Flash-Next](https://huggingface.co/primitive-ai/Qwen3.8-Flash-Next-mixed-NVFP4-FP8) | 180 B MoE, 6 B active | 183.7 GB | 90.3 | 92.2 | 84.8 | 56.7 | 99.5% | 686 |
|
| 277 |
|
| 278 |
`overall` pools the two suites as 1,370 items, weighted 85.4% knowledge and 14.6% tool calling by
|
| 279 |
item count. **Read it with `finished`**: `overall` scores an answer that overran the token budget as
|
| 280 |
wrong, but it cannot tell you whether the model needed the room or failed to stop — `finished` and
|
| 281 |
-
`out` separate those, and this model's 96.3% is among the lowest `finished` in the table
|
| 282 |
-
reasons in long chains. A gap under **1.0** in `overall` is a tie. Sizes are as each card
|
| 283 |
-
them, which mixes GB and GiB
|
| 284 |
|
| 285 |
---
|
| 286 |
|
|
@@ -290,24 +290,26 @@ The model is 37.4 B parameters in five very unequal pieces:
|
|
| 290 |
|
| 291 |
| | params | share |
|
| 292 |
|---|---|---|
|
| 293 |
-
| routed MoE experts, 45 layers × 100 × 3 × 2560×768 | 26.54 B |
|
| 294 |
| MoVA value-experts, 45 layers × 64 × 2560×1024 | 7.55 B | 20.2% |
|
| 295 |
| attention `qk_proj` / `o_proj` / `gate_proj` | 1.61 B | 4.3% |
|
| 296 |
| `embed_tokens` + `lm_head`, untied, vocab 250624 | 1.28 B | 3.4% |
|
| 297 |
| shared experts + the three dense MLP layers | 0.41 B | 1.1% |
|
| 298 |
|
|
|
|
|
|
|
| 299 |
| tensors | count | format |
|
| 300 |
|---|---|---|
|
| 301 |
| routed experts on 30 of the 45 sparse layers | 9,000 | FP8 E4M3, block scales `[128,128]` |
|
| 302 |
| routed experts on the other 15 sparse layers | 4,500 | NVFP4, group 16 |
|
| 303 |
| MoVA `v_experts` and `v_router`; `qk_proj`/`o_proj`/`gate_proj`; `mlp.gate`; shared experts; dense layers 0–2; `lm_head`; embeddings; norms | 3,408 | BF16 |
|
| 304 |
|
| 305 |
-
`compressed-tensors`, top-level format `mixed-precision`, two config groups. The NVFP4 group is
|
| 306 |
-
|
| 307 |
-
|
| 308 |
|
| 309 |
-
**The second-largest block
|
| 310 |
-
|
| 311 |
|
| 312 |
```python
|
| 313 |
w1 = torch.stack([expert.weight for expert in self.v_experts], dim=0).contiguous()
|
|
@@ -318,17 +320,16 @@ It stacks the raw `.weight` of all 64 value-experts and hands `fused_mova_impl`
|
|
| 318 |
quantized `Linear` carries `weight_packed` plus scales and no `weight`, so a quantized v_expert
|
| 319 |
either fails at load or feeds packed bytes to a kernel that reads them as bfloat16. IFM's own FP8
|
| 320 |
ignores all 2,880 of them for the same reason. That is 20% of the model pinned to BF16 in any build,
|
| 321 |
-
which is why lower precision buys less here than the parameter count suggests
|
| 322 |
-
|
|
|
|
| 323 |
|
| 324 |
-
|
| 325 |
-
to share one scheme. And a layer's experts are quantized as a unit: vLLM's fused MoE
|
| 326 |
-
scheme across an expert's `gate`/`up`/`down`, so the mixture here is per layer, never
|
| 327 |
-
projection.
|
| 328 |
|
| 329 |
-
|
| 330 |
-
servable `compressed-tensors` checkpoint must declare its targets in `config.json`, so which modules
|
| 331 |
-
sit in which format is visible there by necessity.
|
| 332 |
|
| 333 |
## Attribution
|
| 334 |
|
|
@@ -337,8 +338,9 @@ sit in which format is visible there by necessity.
|
|
| 337 |
- Calibration: 496 conversations at seqlen 2048, used to observe activation scales.
|
| 338 |
- The checkpoint carries IFM's `modeling_k2_horizon.py` and `configuration_k2_horizon.py`
|
| 339 |
unchanged, so `--trust-remote-code` works for tooling that wants the reference implementation.
|
| 340 |
-
- Audited before publication: every fused NVFP4 group shares one `weight_global_scale`,
|
| 341 |
-
|
|
|
|
| 342 |
|
| 343 |
---
|
| 344 |
|
|
|
|
| 29 |
<img src="https://img.shields.io/badge/vs%20BF16-1.7×%20smaller-F98424?style=flat-square" alt="1.7x smaller than BF16">
|
| 30 |
<img src="https://img.shields.io/badge/vs%20official%20FP8-8%25%20smaller-F98424?style=flat-square" alt="8 percent smaller than the official FP8">
|
| 31 |
<img src="https://img.shields.io/badge/knowledge-level%20with%20BF16%20%26%20FP8-3DD13D?style=flat-square" alt="knowledge level with BF16 and FP8">
|
| 32 |
+
<img src="https://img.shields.io/badge/call%20accuracy-1.4%20below%20FP8-lightgrey?style=flat-square" alt="call accuracy 1.4 below the official FP8">
|
| 33 |
+
<img src="https://img.shields.io/badge/vs%20our%20NVFP4-%2B1.7%20call%20accuracy-F98424?style=flat-square" alt="plus 1.7 call accuracy versus our pure NVFP4 build">
|
| 34 |
<img src="https://img.shields.io/badge/requires-Blackwell-lightgrey?style=flat-square" alt="requires Blackwell">
|
| 35 |
<a href="https://primitive.com"><img src="https://img.shields.io/badge/web-primitive.com-lightgrey?style=flat-square" alt="primitive.com"></a>
|
| 36 |
</p>
|
| 37 |
|
| 38 |
+
<h3 align="center">8% smaller than the official FP8, level on knowledge, 1.4 behind on call accuracy.</h3>
|
| 39 |
|
| 40 |
<p align="center">
|
| 41 |
Mixed-precision quantization of <a href="https://huggingface.co/IFM/K2-Horizon-MoVA-36B-A4B">IFM/K2-Horizon-MoVA-36B-A4B</a> to
|
|
|
|
| 43 |
15 of the 45 sparse layers carry NVFP4 experts; the other 30 carry FP8 with block scales.
|
| 44 |
</p>
|
| 45 |
|
| 46 |
+
> **This is the better of our two builds on call accuracy, and it needs Blackwell.** There is also a
|
| 47 |
> [pure NVFP4 build](https://huggingface.co/primitive-ai/K2-Horizon-MoVA-36B-A4B-NVFP4) at
|
| 48 |
> 36.74 GB that is 7.74 GB smaller, 1.21× faster at concurrency 32, and **the only one of the two
|
| 49 |
+
> that runs on Ampere**. Take this one if tool calling matters most; take that one for pre-Blackwell
|
| 50 |
+
> hardware, the smallest footprint, or throughput under load.
|
| 51 |
|
| 52 |
---
|
| 53 |
|
|
|
|
| 55 |
|
| 56 |
* 🗜️ **8% smaller than IFM's own FP8, 1.7× smaller than BF16.** 44.48 GB against 48.36 GB and
|
| 57 |
74.89 GB.
|
| 58 |
+
* 🎯 **Knowledge is level with both references.** 87.3 against the official FP8's 86.8 and BF16's
|
| 59 |
+
85.9 over 1,170 items. It is the highest number in that column and it is still a tie.
|
| 60 |
+
* 🧭 **The better of our two builds on tool calls.** 73.5 on call accuracy against the pure NVFP4
|
| 61 |
+
build's 71.8, for 7.74 GB more — the one axis that separates the two (t = +2.4). Against the
|
| 62 |
+
official FP8 the gap is 1.4 and neither half of the suite separates on its own.
|
| 63 |
+
* 🧠 **Block scales, not bit width, are what moved tool calling here.** Two thirds of the expert
|
| 64 |
+
layers carry FP8 with `[128,128]` block scales rather than group-wise 4-bit.
|
|
|
|
|
|
|
| 65 |
* 🖥️ **One card, no tensor parallelism.** Both official recipes use TP=2; this fits TP=1 with
|
| 66 |
231,488 tokens of KV at 32K context.
|
| 67 |
* ⚠️ **Blackwell.** Two thirds of the expert layers carry FP8 block scales and sm_80 has no FP8
|
| 68 |
+
tensor cores, so we neither built nor tested this one for Ampere. The pure NVFP4 build is verified
|
| 69 |
+
there.
|
| 70 |
+
* 🔧 **Serves on stock vLLM `main`, no patches and no custom kernels.** Plain `compressed-tensors`.
|
| 71 |
|
| 72 |
---
|
| 73 |
|
|
|
|
| 78 |
0.28.0 predates it. Use a `main`/nightly build:
|
| 79 |
|
| 80 |
```bash
|
| 81 |
+
hf download primitive-ai/K2-Horizon-MoVA-36B-A4B-mixed-NVFP4-FP8 \
|
| 82 |
+
--local-dir ./K2-Horizon-MoVA-36B-A4B-mixed-NVFP4-FP8
|
| 83 |
+
|
| 84 |
docker run --gpus all --ipc=host -p 8000:8000 -v $PWD:/models \
|
| 85 |
+
vllm/vllm-openai:nightly-8a728663c1c3eeace834a95f5654fa653cc1998c \
|
| 86 |
--model /models/K2-Horizon-MoVA-36B-A4B-mixed-NVFP4-FP8 \
|
| 87 |
--trust-remote-code --max-model-len 32768 \
|
| 88 |
--gpu-memory-utilization 0.92 \
|
| 89 |
--reasoning-parser k2_horizon
|
| 90 |
```
|
| 91 |
|
| 92 |
+
That image tag is the nightly every number on this page was measured on (vllm
|
| 93 |
+
`0.28.1rc1.dev388`). On one RTX PRO 6000 Blackwell it leaves 43.02 GiB resident for weights and
|
| 94 |
+
42.39 GiB for KV — **231,488 tokens at 32K context, 7.06× concurrency**. Expect a slow first boot:
|
| 95 |
+
engine init takes 198 s, of which 90 s is `torch.compile`, because the FP8 block-scale path compiles
|
| 96 |
+
more kernels than a pure NVFP4 one (97 s and 3 s respectively for our other build).
|
| 97 |
|
| 98 |
**Reasoning effort is a server-level choice on this architecture, not a per-request one.** The
|
| 99 |
template emits a different tag pair per effort and `K2HorizonReasoningParser` picks one pair once
|
|
|
|
| 125 |
|
| 126 |
| build | size | knowledge | call | abstain | tool calling | runs k/a | finished | out/answer |
|
| 127 |
|---|---|---|---|---|---|---|---|---|
|
| 128 |
+
| [IFM BF16](https://huggingface.co/IFM/K2-Horizon-MoVA-36B-A4B) | 74.89 GB | 85.9 ±0.7 | 74.6 ±1.3 | 60.8 ±2.9 | 71.8 ±1.0 | 2/3 | 95.8% | 1206 |
|
| 129 |
+
| [IFM FP8](https://huggingface.co/IFM/K2-Horizon-MoVA-36B-A4B-FP8) | 48.36 GB | 86.8 ±0.5 | 74.9 ±1.5 | 60.4 ±2.9 | 72.0 ±0.8 | 2/6 | 96.1% | 1176 |
|
| 130 |
+
| **this repo** | **44.48 GB** | 87.3 ±1.0 | 73.5 ±1.7 | 58.9 ±3.1 | 70.6 ±1.4 | 2/9 | 96.3% | 1118 |
|
| 131 |
+
| [our pure NVFP4](https://huggingface.co/primitive-ai/K2-Horizon-MoVA-36B-A4B-NVFP4) | 36.74 GB | 86.5 ±0.5 | 71.8 ±1.0 | 60.4 ±3.7 | 69.5 ±1.4 | 2/6 | 95.6% | 1234 |
|
| 132 |
|
| 133 |
`call` is accuracy on the 160 tool-calling items that require a call; `abstain` is the 40 whose
|
| 134 |
correct action is to call **nothing**; `tool calling` is the two pooled as 200. We report the halves
|
|
|
|
| 136 |
runs behind each row. `finished` is the share of the 1,170 knowledge items that answered inside the
|
| 137 |
token budget; `out/answer` is mean output tokens.
|
| 138 |
|
| 139 |
+
**Knowledge is one group.** This build's 87.3 is the highest number in the column and it does not
|
| 140 |
+
separate from anything: against the official FP8 it is t = +0.6, at n=2 per side. Don't rank on this
|
|
|
|
| 141 |
column.
|
| 142 |
|
| 143 |
+
**Tool calling: where the 1.4 sits.** The pooled 200-item number separates from the official FP8
|
| 144 |
+
(t = −2.6 over nine runs here and six there), but neither half does on its own: `call` is 1.4 low at
|
| 145 |
+
t = −1.7 and `abstain` is 1.5 low at t = −1.0. So the loss is small, real in aggregate, and spread
|
| 146 |
+
across both halves of the suite rather than concentrated in one. Our pure NVFP4 build behaves
|
| 147 |
+
differently — there the loss is 3.1 on `call` alone (t = −4.2) and abstention is untouched.
|
|
|
|
| 148 |
|
| 149 |
+
It is not a formatting failure. Unparsed replies run at 14 per 1,800 here (0.78%) against 13 per
|
| 150 |
+
1,200 for the official FP8 (1.08%) and 6 per 600 for BF16 (1.00%) — cleaner than either IFM build,
|
| 151 |
+
and our pure NVFP4 build is cleaner still at 0.75%. Thinking fired on 99–100% of items in every row.
|
|
|
|
| 152 |
|
| 153 |
<details>
|
| 154 |
<summary>Per-benchmark detail, both suites</summary>
|
|
|
|
| 176 |
40 abstention items; the other four tool-calling benchmarks supply the 160 call items.
|
| 177 |
|
| 178 |
**Where the tool-calling difference sits.** xlam/APIGen is 40.2 here against the official FP8's
|
| 179 |
+
44.8, 4.6 points on 45 items and this build's largest gap against that reference. The pure NVFP4
|
| 180 |
build gives up 7.0 points on the same benchmark, so this build recovers about a third of that loss.
|
| 181 |
xlam items carry the longest argument lists in the suite.
|
| 182 |
|
|
|
|
| 184 |
|
| 185 |
> **The noise floor, and why the run counts are in the table.** Every build compared here has at
|
| 186 |
> least six agentic runs, the one exception being the BF16 reference at three. It needs to be six.
|
| 187 |
+
> The official FP8's tool-calling figure read 72.7 ±0.3 after three runs and 72.0 ±0.8 after six;
|
| 188 |
+
> this build's read 70.3 ±1.6 after three and 70.6 ±1.4 after nine. On the 1,170-item knowledge
|
| 189 |
+
> suite, repeat runs of a single checkpoint span up to 1.9 points, so **treat a knowledge gap of a
|
| 190 |
+
> point or so as unresolved.** The widest gap in that column is 1.4, between this build and BF16,
|
| 191 |
+
> and even that is only t = +1.6. We publish ties as ties.
|
| 192 |
+
|
| 193 |
+
Two footnotes on the table. The BF16 row was served at 20,480 context against the quants' 32,768,
|
| 194 |
+
because 74.89 GB of weights leaves only 81,664 tokens of KV on a 96 GB card; the generation budget
|
| 195 |
+
was the same 16,384 tokens for every row. And `out/answer` is a mean over a long tail: median output
|
| 196 |
+
is 204 tokens against a mean of 1,118, a ratio of 5.5×. That shape usually means a model that
|
| 197 |
+
reaches its answer and cannot stop. Here it does not — the official FP8 shows 1,176 against a
|
| 198 |
+
median of 211 on the same items, a ratio of 5.6×, with the same ~4% of items hitting the budget.
|
| 199 |
+
It is how K2-Horizon reasons, and quantization did not cause it.
|
|
|
|
| 200 |
|
| 201 |
---
|
| 202 |
|
|
|
|
| 205 |
Cache-free, 8,192 tokens in and 512 out, one RTX PRO 6000 Blackwell, same nightly and same serve
|
| 206 |
flags as the accuracy rows. Prefix caching is disabled and every measurement runs on its own seed,
|
| 207 |
so no row is reading a cache the previous one filled. These come from one sitting and drift a few
|
| 208 |
+
percent between sittings, so read them as a bracket. BF16 is absent because at 74.89 GB it only
|
| 209 |
+
serves 20,480 context on this card, which would not be the same measurement.
|
| 210 |
|
| 211 |
| build | tok/s @ conc 1 | TPOT @ conc 1 | tok/s @ conc 32 | TPOT @ conc 32 | median TTFT @ conc 32 |
|
| 212 |
|---|---|---|---|---|---|
|
|
|
|
| 214 |
| **this repo** | 29.99 | 32.56 ms | 248.4 | 89.5 ms | 3.59 s |
|
| 215 |
| [our pure NVFP4](https://huggingface.co/primitive-ai/K2-Horizon-MoVA-36B-A4B-NVFP4) | **30.45** | **32.10 ms** | **301.5** | 93.1 ms | **1.54 s** |
|
| 216 |
|
| 217 |
+
**Quantizing this model buys throughput under load, not single-stream latency.** Those three builds
|
| 218 |
+
span 11.6 GB and land within 0.71 tok/s of each other at concurrency 1. At concurrency 32 their
|
| 219 |
+
per-token decode cost is nearly flat too — 89.2, 89.5 and 93.1 ms, a 4.4% spread — so the aggregate
|
| 220 |
+
differences are not a decode-rate effect. They show up in prefill and in scheduling under load,
|
| 221 |
+
where median time to first token falls from 4.46 s to 1.54 s across the range. Decode stays pinned
|
| 222 |
+
because vLLM restacks the 15.1 GB of BF16 MoVA value-experts on every forward pass whatever the
|
| 223 |
+
routed experts are quantized to, and that fixed cost dominates a single stream.
|
| 224 |
|
| 225 |
+
This build sits between the two on all five columns, which is what its size predicts. If throughput
|
| 226 |
+
under load matters more than call accuracy, the pure NVFP4 build is 1.21× this one at concurrency 32
|
| 227 |
+
and reaches first token in 1.54 s against 3.59 s.
|
| 228 |
|
| 229 |
---
|
| 230 |
|
|
|
|
| 233 |
| | **this repo** | [pure NVFP4](https://huggingface.co/primitive-ai/K2-Horizon-MoVA-36B-A4B-NVFP4) |
|
| 234 |
|---|---|---|
|
| 235 |
| size | 44.48 GB | **36.74 GB** |
|
| 236 |
+
| knowledge | 87.3 ±1.0 | 86.5 ±0.5 |
|
| 237 |
+
| call | **73.5 ±1.7** | 71.8 ±1.0 |
|
| 238 |
+
| abstain | 58.9 ±3.1 | 60.4 ±3.7 |
|
| 239 |
+
| tool calling, pooled | 70.6 ±1.4 | 69.5 ±1.4 |
|
| 240 |
| tok/s @ conc 32 | 248.4 | **301.5** |
|
| 241 |
| median TTFT @ conc 32 | 3.59 s | **1.54 s** |
|
| 242 |
| Blackwell | yes | yes |
|
| 243 |
| **Ampere (A100)** | **no** | **yes** |
|
| 244 |
|
| 245 |
+
This build spends 7.74 GB, +21%, and call accuracy is the one axis that pays it back: +1.7 at
|
| 246 |
+
t = +2.4. The pooled tool-calling lead of 1.1 does not separate (t = +1.5), nor does knowledge
|
| 247 |
+
(t = +0.9). **If tool calling dominates your workload and you have 48 GB, IFM's own FP8 is still the
|
| 248 |
+
most accurate option** — it leads this build by 1.4 on call accuracy. What this build offers against
|
| 249 |
+
it is 8% less memory at a gap that neither half of the suite resolves on its own.
|
|
|
|
| 250 |
|
| 251 |
**On Ampere.** We have not tested this build on an A100 and do not expect FP8 block scales to load
|
| 252 |
on sm_80, which has no FP8 tensor cores. The pure NVFP4 build does run there through Marlin
|
|
|
|
| 262 |
table, on this card and on our other cards, comes from the one fixed protocol described above — the
|
| 263 |
same 1,370 items, auto-scored, no LLM judge.
|
| 264 |
|
| 265 |
+
| model | shape | size | overall | knowledge | call | abstain | finished | out/answer |
|
| 266 |
|---|---|---|---|---|---|---|---|---|
|
| 267 |
| [Laguna-XS-2.1](https://huggingface.co/primitive-ai/Laguna-XS-2.1-mixed-NVFP4-MXFP8) | 31 B MoE | 19.3 GiB | 81.7 | 83.8 | 68.4 | 73.5 | 98.9% | 1097 |
|
| 268 |
| [Nemotron-3.5-Lightning-30B-A3B](https://huggingface.co/primitive-ai/Nemotron-3.5-Lightning-30B-A3B-mixed-INT4-INT8) | 30 B MoE+Mamba | 19.2 GiB | 87.1 | 87.9 | 85.4 | 70.5 | 97.9% | 1429 |
|
|
|
|
| 270 |
| [Muse-Glimmer-30B](https://huggingface.co/primitive-ai/Muse-Glimmer-30B-mixed-NVFP4) | 30 B MoE | 20.4 GiB | 86.6 | 88.8 | 78.6 | 54.5 | 99.7% | 800 |
|
| 271 |
| [Qwen3.8-27B](https://huggingface.co/primitive-ai/Qwen3.8-27B-mixed-NVFP4-FP8) | 27 B dense | 20.7 GiB | 88.8 | 90.4 | 85.5 | 54.5 | 99.7% | 651 |
|
| 272 |
| [Granite-4.2-30B](https://huggingface.co/primitive-ai/granite-4.2-30b-mixed-NVFP4-FP8) | 30 B dense | 18.1 GB | 85.5 | 86.2 | 85.8 | 60.8 | 98.5% | 1502 |
|
| 273 |
+
| [K2-Horizon-MoVA-36B-A4B NVFP4](https://huggingface.co/primitive-ai/K2-Horizon-MoVA-36B-A4B-NVFP4) | 37 B MoE+MoVA, 4 B active | 36.7 GB | 84.1 | 86.5 | 71.8 | 60.4 | 95.6% | 1234 |
|
| 274 |
+
| **K2-Horizon-MoVA-36B-A4B mixed** (this repo) | 37 B MoE+MoVA, 4 B active | **44.5 GB** | **84.9** | 87.3 | 73.5 | 58.9 | 96.3% | 1118 |
|
| 275 |
| [Laguna-S-2.1](https://huggingface.co/primitive-ai/Laguna-S-2.1-mixed-NVFP4-MXFP8) | 110 B MoE | 64.0 GiB | 84.3 | 87.1 | 64.6 | 81.0 | 97.3% | 995 |
|
| 276 |
| [Qwen3.8-Flash-Next](https://huggingface.co/primitive-ai/Qwen3.8-Flash-Next-mixed-NVFP4-FP8) | 180 B MoE, 6 B active | 183.7 GB | 90.3 | 92.2 | 84.8 | 56.7 | 99.5% | 686 |
|
| 277 |
|
| 278 |
`overall` pools the two suites as 1,370 items, weighted 85.4% knowledge and 14.6% tool calling by
|
| 279 |
item count. **Read it with `finished`**: `overall` scores an answer that overran the token budget as
|
| 280 |
wrong, but it cannot tell you whether the model needed the room or failed to stop — `finished` and
|
| 281 |
+
`out/answer` separate those, and this model's 96.3% is among the lowest `finished` in the table
|
| 282 |
+
because it reasons in long chains. A gap under **1.0** in `overall` is a tie. Sizes are as each card
|
| 283 |
+
reports them, which mixes GB and GiB.
|
| 284 |
|
| 285 |
---
|
| 286 |
|
|
|
|
| 290 |
|
| 291 |
| | params | share |
|
| 292 |
|---|---|---|
|
| 293 |
+
| routed MoE experts, 45 layers × 100 × 3 × 2560×768 | 26.54 B | 71.0% |
|
| 294 |
| MoVA value-experts, 45 layers × 64 × 2560×1024 | 7.55 B | 20.2% |
|
| 295 |
| attention `qk_proj` / `o_proj` / `gate_proj` | 1.61 B | 4.3% |
|
| 296 |
| `embed_tokens` + `lm_head`, untied, vocab 250624 | 1.28 B | 3.4% |
|
| 297 |
| shared experts + the three dense MLP layers | 0.41 B | 1.1% |
|
| 298 |
|
| 299 |
+
Which of those pieces got which format:
|
| 300 |
+
|
| 301 |
| tensors | count | format |
|
| 302 |
|---|---|---|
|
| 303 |
| routed experts on 30 of the 45 sparse layers | 9,000 | FP8 E4M3, block scales `[128,128]` |
|
| 304 |
| routed experts on the other 15 sparse layers | 4,500 | NVFP4, group 16 |
|
| 305 |
| MoVA `v_experts` and `v_router`; `qk_proj`/`o_proj`/`gate_proj`; `mlp.gate`; shared experts; dense layers 0–2; `lm_head`; embeddings; norms | 3,408 | BF16 |
|
| 306 |
|
| 307 |
+
`compressed-tensors`, top-level format `mixed-precision`, two config groups. The NVFP4 group is W4A4
|
| 308 |
+
and carries observed activation scales plus a tensor-level `weight_global_scale`; the FP8 group is
|
| 309 |
+
weight-only with block scales.
|
| 310 |
|
| 311 |
+
**The second-largest block cannot be quantized at all.** vLLM's MoVA attention does this on every
|
| 312 |
+
forward pass:
|
| 313 |
|
| 314 |
```python
|
| 315 |
w1 = torch.stack([expert.weight for expert in self.v_experts], dim=0).contiguous()
|
|
|
|
| 320 |
quantized `Linear` carries `weight_packed` plus scales and no `weight`, so a quantized v_expert
|
| 321 |
either fails at load or feeds packed bytes to a kernel that reads them as bfloat16. IFM's own FP8
|
| 322 |
ignores all 2,880 of them for the same reason. That is 20% of the model pinned to BF16 in any build,
|
| 323 |
+
which is why lower precision buys less here than the parameter count suggests: those 7.55 B
|
| 324 |
+
parameters are 15.1 GB of BF16 that every forward pass moves regardless. Per the throughput section,
|
| 325 |
+
that is why decode speed barely moves.
|
| 326 |
|
| 327 |
+
Two engine constraints shape the rest. MoVA fuses `q` and `k` into a single `qk_proj`, so those two
|
| 328 |
+
would have to share one scheme. And a layer's experts are quantized as a unit: vLLM's fused MoE
|
| 329 |
+
requires one scheme across an expert's `gate`/`up`/`down`, so the mixture here is per layer, never
|
| 330 |
+
per projection.
|
| 331 |
|
| 332 |
+
---
|
|
|
|
|
|
|
| 333 |
|
| 334 |
## Attribution
|
| 335 |
|
|
|
|
| 338 |
- Calibration: 496 conversations at seqlen 2048, used to observe activation scales.
|
| 339 |
- The checkpoint carries IFM's `modeling_k2_horizon.py` and `configuration_k2_horizon.py`
|
| 340 |
unchanged, so `--trust-remote-code` works for tooling that wants the reference implementation.
|
| 341 |
+
- Audited before publication: every fused NVFP4 group shares one `weight_global_scale`, every FP8
|
| 342 |
+
block-scale tensor has the shape its group declares, no activation scale is zero or NaN, and
|
| 343 |
+
`config.json` agrees with the tensors actually present.
|
| 344 |
|
| 345 |
---
|
| 346 |
|