piotrkosecki commited on
Commit
36e36f3
·
verified ·
1 Parent(s): d246a4b

Add tested native vLLM TP4 runtime, RTX PRO instructions and validation

Browse files
Files changed (45) hide show
  1. .gitattributes +2 -0
  2. LICENSE +21 -0
  3. README.md +202 -0
  4. SHA256SUMS +49 -0
  5. chat_template.jinja +160 -0
  6. compose.yml +53 -0
  7. config.json +342 -0
  8. configuration_naive_n05_flash.py +155 -0
  9. generation_config.json +9 -0
  10. hf_quant_config.json +110 -0
  11. model.safetensors.index.json +3 -0
  12. modeling_naive_n05_flash.py +243 -0
  13. quantization_provenance.json +61 -0
  14. runtime-lock.json +38 -0
  15. runtime/.dockerignore +2 -0
  16. runtime/Dockerfile +29 -0
  17. runtime/LICENSE +21 -0
  18. runtime/LICENSE-APACHE-2.0.txt +202 -0
  19. runtime/THIRD_PARTY_NOTICES.md +16 -0
  20. runtime/pyproject.toml +14 -0
  21. runtime/requirements.txt +6 -0
  22. runtime/scripts/benchmark_stream.py +84 -0
  23. runtime/scripts/decode_kernels.py +169 -0
  24. runtime/scripts/fused_experts.py +50 -0
  25. runtime/scripts/nvfp4_runtime.py +154 -0
  26. runtime/scripts/preflight.py +63 -0
  27. runtime/scripts/safe_device_transfer.py +30 -0
  28. runtime/scripts/validate_api.py +73 -0
  29. runtime/sitecustomize.py +7 -0
  30. runtime/vllm_naive/__init__.py +11 -0
  31. runtime/vllm_naive/attention.py +242 -0
  32. runtime/vllm_naive/model.py +189 -0
  33. tokenizer.json +3 -0
  34. tokenizer_config.json +32 -0
  35. validation/expert-sharding-tp4-validation.json +17 -0
  36. validation/export-validation.json +8 -0
  37. validation/native-tiny-graphs-validation.json +394 -0
  38. validation/native-vllm-api-validation.json +283 -0
  39. validation/native-vllm-benchmark-repeat.json +0 -0
  40. validation/native-vllm-benchmark.json +0 -0
  41. validation/native-vllm-concurrency-validation.json +184 -0
  42. validation/native-vllm-streaming-validation.json +1493 -0
  43. validation/portable-preflight.json +39 -0
  44. validation/preserved-weights-validation.json +10 -0
  45. validation/runtime-source-validation.json +17 -0
.gitattributes CHANGED
@@ -33,3 +33,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ model.safetensors.index.json filter=lfs diff=lfs merge=lfs -text
37
+ tokenizer.json filter=lfs diff=lfs merge=lfs -text
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Naive AI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
README.md ADDED
@@ -0,0 +1,202 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ base_model: NaiveAI/Naive-N0.5-Flash
4
+ base_model_relation: quantized
5
+ library_name: vllm
6
+ pipeline_tag: text-generation
7
+ tags:
8
+ - nvfp4
9
+ - modelopt
10
+ - vllm
11
+ - mixture-of-experts
12
+ - custom-code
13
+ - blackwell
14
+ ---
15
+
16
+ # Naive-N0.5-Flash NVFP4 — vLLM on four RTX PRO 6000 Blackwell GPUs
17
+
18
+ **Original model by [Naive AI](https://huggingface.co/NaiveAI). This release is built on their work.**
19
+
20
+ The Naive AI team created and openly released **Naive-N0.5-Flash**, including its sparse-attention adaptation, continued pretraining, model weights and reference implementation. Their research and engineering are the foundation of this repository. Many thanks to the team for sharing the model, code and technical details with the community and making derivatives like this possible.
21
+
22
+ **Please support and credit the original project:** [original model](https://huggingface.co/NaiveAI/Naive-N0.5-Flash) · [GitHub](https://github.com/NaiveAI-Labs/Naive-N0.5-Flash) · [technical report and research](https://naive.ai/en/research/) · [Naive AI](https://naive.ai/).
23
+
24
+ Naive's model in turn builds on **[Xiaomi MiMo-V2.5-Base](https://huggingface.co/XiaomiMiMo/MiMo-V2.5-Base)** and the **DeepSeek** team's sparse-attention research. Credit for that foundation belongs to those teams as well. This repository is an **unofficial community quantization and serving adaptation**: its contribution is the expert-only NVFP4 conversion, validation, and native vLLM integration for RTX PRO Blackwell hardware.
25
+
26
+ NVFP4 expert quantization of [NaiveAI/Naive-N0.5-Flash](https://huggingface.co/NaiveAI/Naive-N0.5-Flash), a sparse-attention derivative of Xiaomi MiMo-V2.5. The model has approximately 309B total parameters and 15.5B active parameters per token. The 49 weight shards occupy **182.57 GB** (170.03 GiB).
27
+
28
+ **Serve this checkpoint with the included native vLLM model plugin and Docker recipe below.** The tested engine is vLLM 0.28.0, with tensor parallelism across four 96 GB RTX PRO 6000 Blackwell GPUs. vLLM runs scheduling, paged KV-cache allocation, sampling, prefix caching, chunked prefill and the streaming OpenAI-compatible API. The plugin supplies Naive's model implementation and NVFP4 expert kernels.
29
+
30
+ Naive's architecture requires this plugin; the pinned stock vLLM image does not implement it. Installing the plugin is part of the Docker build. This repository does not provide a tested SGLang implementation. Keep the original `naive_n05_flash` architecture in `config.json`.
31
+
32
+ ## Run with vLLM
33
+
34
+ The tested machine uses four **NVIDIA RTX PRO 6000 Blackwell Max-Q Workstation Edition 96 GB** GPUs (SM120), a Threadripper PRO 7955WX, 498 GiB host RAM, Linux and driver 595.91.07. Have Docker Compose and NVIDIA Container Toolkit working, with all four GPUs visible to containers. Allow roughly 250 GB of free disk for the checkpoint, container images and compilation caches. This recipe is validated on the four-GPU machine described here; smaller configurations have not been validated.
35
+
36
+ Download the release using the Hugging Face CLI:
37
+
38
+ ```bash
39
+ hf download piotrkosecki/Naive-N0.5-Flash-NVFP4 \
40
+ --revision nvfp4-vllm-v1 \
41
+ --local-dir ./Naive-N0.5-Flash-NVFP4
42
+ cd Naive-N0.5-Flash-NVFP4
43
+ sha256sum --check SHA256SUMS
44
+ ```
45
+
46
+ Build the pinned runtime, check the checkpoint and hardware, and start vLLM:
47
+
48
+ ```bash
49
+ export LOCAL_UID="$(id -u)"
50
+ export LOCAL_GID="$(id -g)"
51
+ mkdir -p runtime-cache
52
+ docker compose build naive-vllm
53
+ docker compose run --rm --no-deps --entrypoint python3 naive-vllm \
54
+ /opt/naive/scripts/preflight.py
55
+ docker compose up -d naive-vllm
56
+ docker compose logs -f naive-vllm
57
+ ```
58
+
59
+ Free the GPUs from other large models before starting. The recipe uses approximately 81–85 GiB per GPU, rising with workspaces and requests; desktop applications require additional memory. Keep `runtime-cache`: the first start and the first request of a new shape can compile kernels and take substantially longer. Cached starts still need model loading and graph capture. Wait for the API server to become ready:
60
+
61
+ ```bash
62
+ curl --fail http://127.0.0.1:8000/health
63
+ curl --fail http://127.0.0.1:8000/version
64
+ curl --fail http://127.0.0.1:8000/v1/models
65
+ ```
66
+
67
+ `/version` reports `0.28.0`; `/v1/models` lists `Naive-N0.5-Flash-NVFP4`. The API binds to localhost, and container restart is manual. Stop it with `docker compose stop naive-vllm`.
68
+
69
+ The image entrypoint is `python3 -m vllm.entrypoints.openai.api_server`. The full launch configuration is in [compose.yml](compose.yml); its vLLM arguments are:
70
+
71
+ ```bash
72
+ --model /models/Naive-N0.5-Flash-NVFP4 \
73
+ --served-model-name Naive-N0.5-Flash-NVFP4 \
74
+ --trust-remote-code \
75
+ --tensor-parallel-size 4 --distributed-executor-backend mp \
76
+ --dtype bfloat16 --max-model-len 8192 \
77
+ --max-num-batched-tokens 256 --max-num-seqs 4 \
78
+ --kv-cache-memory-bytes 4294967296 \
79
+ --disable-custom-all-reduce \
80
+ --enable-prefix-caching --enable-chunked-prefill \
81
+ --compilation-config '{"mode":0,"cudagraph_mode":"FULL_DECODE_ONLY","cudagraph_capture_sizes":[1],"cudagraph_num_of_warmups":2}' \
82
+ --enable-auto-tool-choice --tool-call-parser mimo --reasoning-parser mimo \
83
+ --host 127.0.0.1 --port 8000
84
+ ```
85
+
86
+ ## Send requests
87
+
88
+ Streaming chat:
89
+
90
+ ```bash
91
+ curl -N http://127.0.0.1:8000/v1/chat/completions \
92
+ -H 'Content-Type: application/json' \
93
+ -d '{
94
+ "model": "Naive-N0.5-Flash-NVFP4",
95
+ "messages": [{"role": "user", "content": "Explain how a hash table works."}],
96
+ "temperature": 0,
97
+ "max_tokens": 256,
98
+ "chat_template_kwargs": {"enable_thinking": false},
99
+ "stream": true,
100
+ "stream_options": {"include_usage": true}
101
+ }'
102
+ ```
103
+
104
+ For an OpenAI-compatible client, use base URL `http://127.0.0.1:8000/v1` and model `Naive-N0.5-Flash-NVFP4`. No API key is configured; clients that require a value can use a placeholder.
105
+
106
+ For thinking, set `chat_template_kwargs` to `{"enable_thinking": true}` and allow enough output tokens. This vLLM version returns separate `message.reasoning` and `message.content` fields. Streaming responses use `delta.reasoning` and `delta.content`.
107
+
108
+ Tool calls use the normal OpenAI `tools` schema, for example:
109
+
110
+ ```bash
111
+ curl http://127.0.0.1:8000/v1/chat/completions \
112
+ -H 'Content-Type: application/json' \
113
+ -d '{
114
+ "model": "Naive-N0.5-Flash-NVFP4",
115
+ "messages": [{"role": "user", "content": "Call get_weather for Warsaw."}],
116
+ "tools": [{"type": "function", "function": {
117
+ "name": "get_weather",
118
+ "description": "Get weather for a city",
119
+ "parameters": {"type": "object", "properties": {
120
+ "city": {"type": "string"}
121
+ }, "required": ["city"]}
122
+ }}],
123
+ "tool_choice": "auto",
124
+ "temperature": 0,
125
+ "max_tokens": 192,
126
+ "chat_template_kwargs": {"enable_thinking": false}
127
+ }'
128
+ ```
129
+
130
+ ## Measured performance and validation
131
+
132
+ Measured on September 28, 2026 with the final release build:
133
+
134
+ | Prompt tokens | Generated tokens | Decode tokens/sec | Time to first token (s) | End-to-end tokens/sec |
135
+ |---:|---:|---:|---:|---:|
136
+ | 76 | 256 | 56.56 | 0.074 | 55.87 |
137
+ | 79 | 256 | 56.56 | 0.076 | 55.85 |
138
+ | 1,685 | 256 | 56.44 | 0.484 | 51.18 |
139
+ | 3,845 | 256 | 56.57 | 0.611 | 50.01 |
140
+ | 7,445 | 256 | 56.44 | 1.113 | 45.46 |
141
+
142
+ A second run measured **55.00–55.11 tokens/sec** during decode. Both runs exceeded 50 tokens/sec in all five cases. Raw responses, token IDs, timestamps and usage counts are in [run 1](validation/native-vllm-benchmark.json) and [run 2](validation/native-vllm-benchmark-repeat.json).
143
+
144
+ These measurements use the full model in **native vLLM**, one active request, temperature 0 and 256 generated tokens per response. The client records token-bearing SSE events and checks the exact returned token IDs against vLLM's usage count. Decode rate is the number of tokens after the first event divided by the time from the first to the last token event. Prompt processing and time to first token are reported separately. Prefix caching is enabled; the long prompts share background text, and repeated prompts can reuse cached prefixes. The time-to-first-token column is not a cold-prefill benchmark. Compilation and prompt processing affect end-to-end speed.
145
+
146
+ CUDA graphs currently cover **one active decode request**. Multiple active requests run through the eager path and are slower per request. Four simultaneous requests passed a functional test; the single-request speeds above do not describe concurrency throughput.
147
+
148
+ Reproduce the checks while no other client is using the server:
149
+
150
+ ```bash
151
+ python3 runtime/scripts/validate_api.py
152
+ python3 runtime/scripts/benchmark_stream.py \
153
+ --tokens 256 --cases 5 --output native-vllm-benchmark.json
154
+ ```
155
+
156
+ Validation includes full-model arithmetic, geography, Python code, structured tool calls, reasoning, longer-context generation and four concurrent requests. Tiny-model tests compare 144 greedy tokens exactly with the quantized reference while exercising graph replay, batched scheduling, chunked prefill and prefix caching. A real expert layer was also checked with tensor-parallel slicing. Reports in [validation/](validation/) distinguish these checks from full-model measurements. These are smoke and implementation checks, not an evaluation of accuracy loss versus BF16 on a benchmark suite.
157
+
158
+ ## Runtime limits and implementation
159
+
160
+ - Tested maximum context: **8,192 total input plus output tokens**, with prompts up to 7,445 tokens in the streamed benchmark. The source model's 1M context is not validated by this deployment.
161
+ - TP4, pipeline parallelism 1; 256-token prefill chunks; up to four scheduled sequences; 4 GiB cache budget per GPU, with 17,472 cache tokens shared across requests (about two full 8K requests). Longer concurrent workloads can require vLLM to preempt and recompute requests. Attention K/V are BF16 values stored losslessly in FP32 cache slots alongside FP8-rounded indexer values with FP32 scales. KV cache is not NVFP4.
162
+ - Single-token execution fuses RMS normalization, Q/K/V projection and rotary embedding operations, while retaining source BF16 rounding points.
163
+ - The plugin preserves the source sliding window of 128, sparse selection of up to 2,048 tokens, stable indexer tie ordering and original attention value scaling.
164
+ - `NCCL_P2P_DISABLE=1` and `--disable-custom-all-reduce` are required by the tested workstation's failed direct peer-copy integrity checks. The recipe keeps those settings and uses NCCL's host transport.
165
+ - FlashInfer 0.7.0's direct-micro expert path returned zeros for this checkpoint's TP4 shape. The plugin disables that path and uses its validated regular MMA micro/static/dynamic kernels. This workaround depends on the pinned FlashInfer version.
166
+ - `sitecustomize.py` isolates FlashInfer 0.7 source-built kernels from the base image's older prebuilt cubins. Keep the supplied dependency pins and persistent cache directories.
167
+
168
+ The [Dockerfile](runtime/Dockerfile) pins the public vLLM base image by digest. Tested versions: vLLM 0.28.0, PyTorch 2.13.0+cu130, Transformers 5.17.0, FlashInfer 0.7.0, CUTLASS DSL 4.6.2 and Triton 3.7.1. The plugin uses vLLM's [model registration mechanism](https://docs.vllm.ai/en/latest/design/plugin_system/) and is included as source in [runtime/vllm_naive/](runtime/vllm_naive/).
169
+
170
+ ## Quantization and provenance
171
+
172
+ Source revision: [`0235b3b5ff27422b1f57cdc2acddfaf643e08356`](https://huggingface.co/NaiveAI/Naive-N0.5-Flash/tree/0235b3b5ff27422b1f57cdc2acddfaf643e08356). NVIDIA Model Optimizer revision: [`23355eda90a25c290f9b1fdfb928ad54caae7d10`](https://github.com/NVIDIA/Model-Optimizer/tree/23355eda90a25c290f9b1fdfb928ad54caae7d10).
173
+
174
+ Only routed experts are quantized: NVFP4 E2M1 weights and activations, block size 16, FP8 block scales and FP32 global scales. Attention, indexer, router, embeddings and output head retain source precision. All 472 non-expert tensors match source shapes, dtypes and payload hashes. There are 36,096 packed expert matrices and 144,856 exported tensors; total tensor payload is 182,549,965,184 bytes.
175
+
176
+ Layerwise max calibration used 128 sequences of 4,096 tokens (524,288 total), equally divided between Magicoder OSS Instruct and UltraChat, with seed 20260928. Exact dataset revisions and calibration hash are in [quantization_provenance.json](quantization_provenance.json). Layer 47's router was materialized in BF16 during calibration; the final router was restored byte-for-byte from the FP32 source. An exporter naming issue required reconstructing the unchanged embedding, final norm and output-head tail; all 48 calibrated layer shards were retained and the complete export was subsequently audited.
177
+
178
+ The source model's MIT license is preserved in [LICENSE](LICENSE). Upstream configuration/modeling files retain their Apache-2.0 headers. Additional runtime code is MIT licensed; see [runtime/THIRD_PARTY_NOTICES.md](runtime/THIRD_PARTY_NOTICES.md).
179
+
180
+ ## Acknowledgments and citation
181
+
182
+ This release depends on substantial work by the original model authors and the open-source inference community:
183
+
184
+ - **[Naive AI / NaiveAI Team](https://github.com/NaiveAI-Labs/Naive-N0.5-Flash)** — creation and release of Naive-N0.5-Flash, the hybrid SWA/DSA adaptation, continued pretraining, checkpoint, chat template, model implementation and research documentation. Please cite their work when using this derivative.
185
+ - **[Xiaomi MiMo](https://huggingface.co/XiaomiMiMo/MiMo-V2.5-Base)** — the MiMo-V2.5 base model on which Naive-N0.5-Flash builds.
186
+ - **[DeepSeek](https://github.com/deepseek-ai)** — the DeepSeek Sparse Attention research underpinning Naive's sparse-attention design.
187
+ - **[vLLM](https://github.com/vllm-project/vllm)** and **[FlashInfer](https://github.com/flashinfer-ai/flashinfer)** — the serving engine and Blackwell NVFP4 expert kernels used in this deployment.
188
+ - **[NVIDIA Model Optimizer](https://github.com/NVIDIA/Model-Optimizer)** and **[CUTLASS](https://github.com/NVIDIA/cutlass)** — quantization tooling and GPU kernel infrastructure.
189
+ - **[Hugging Face Transformers](https://github.com/huggingface/transformers)**, **[PyTorch](https://github.com/pytorch/pytorch)** and **[Triton](https://github.com/triton-lang/triton)** — model-loading, tensor-computation and kernel-building infrastructure.
190
+
191
+ The original weights and their capabilities come from the upstream model teams. This quantized release retains Naive AI's model identity, copyright notices and license. Please direct recognition for the model and its research to the original authors.
192
+
193
+ The following is the citation supplied by Naive AI in the original model card:
194
+
195
+ ```bibtex
196
+ @misc{naiveai2026naiven05flash,
197
+ title = {Naive-N0.5-Flash: Building Frontier AI with AI},
198
+ author = {{NaiveAI Team}},
199
+ year = {2026},
200
+ url = {https://naive.ai/en/research/}
201
+ }
202
+ ```
SHA256SUMS ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 5a5221799458f4f22a969ff5bb06556e74dc214f2168da14dac077e13661c4a5 model-layer-00000.safetensors
2
+ ea02f0c21f403c1b080582f57875e8851a4a77056a2bbb50c1041fd8f2b342e2 model-layer-00001.safetensors
3
+ 04c06288df5a794cff43965020272a2e611e52dccc82f85ae4b3a2412b717ff0 model-layer-00002.safetensors
4
+ afde47709532dedae9fc9b3e3b140e31ed2d0027db4461355bc8c00660d95af3 model-layer-00003.safetensors
5
+ 13f9ac46ef988032fab0a064a99101a98b0d466da3d743616213aae4d693d607 model-layer-00004.safetensors
6
+ f44cd75dd4060562fcc108614d3104c7c4cda48ef239ee785c50336ecaecb176 model-layer-00005.safetensors
7
+ 01910d46a12010345a37136155477ef8eff738af39adf6125254b18f1e7405a8 model-layer-00006.safetensors
8
+ 017f899ba6c6890182c334299fb09daa17068e07761c741e1235c7a2ef15075e model-layer-00007.safetensors
9
+ fa9b19c4633a4bc4e0d83768f5a721c35e7abb049cc0e7a9be0d50d2749038a0 model-layer-00008.safetensors
10
+ 1359abf1ed7f385a2cf5d16b3863eb0db5ed34a182d1e99fadbecfd0a0b6370f model-layer-00009.safetensors
11
+ 9f09fd2abf17a4ef2da924785444801edec40a7c52ed84c4c4057f48153d0bf0 model-layer-00010.safetensors
12
+ 1dc08baf20ef80bec9c1219f60ba3267b5dc4eaf7dc8cdf4a0c933c05851cd6b model-layer-00011.safetensors
13
+ 654df6d13f2d250fd87a058219350147435207d5e235a74cf5dddefcbffa6afc model-layer-00012.safetensors
14
+ 803c042c1014924977feead399e9d16198dbb63cad43ed2c2340cdcfcb3487ef model-layer-00013.safetensors
15
+ 67ef2e7acc1bf743a8dc43145ad51ac129913fe76060aa3ab19c220b68ad7919 model-layer-00014.safetensors
16
+ 053f9b45fa2c66a1e19662327532812ac242a8649dec9c457b1c95030d6e7bdb model-layer-00015.safetensors
17
+ ee2d0ea2c37f897482e5ebd158a1f7069785962cd48966ebee9d6f1c5e925cb5 model-layer-00016.safetensors
18
+ 7964ccac2a882f7ed6c391717837a82a1a94d4b3063348d27abeae121c847105 model-layer-00017.safetensors
19
+ 30b2b7bf5cc74bc4564dc820c0e486ebf72815e70b57f01cc5fa1fed512412c1 model-layer-00018.safetensors
20
+ ee74c25f2b33a5a3909083a95bbc25572bfbcc27644600a30cc07a0810c7729a model-layer-00019.safetensors
21
+ a60ad1d87b423286e9e0c19734021e6da48af9f96bbb101ddde8dbffc5f490bb model-layer-00020.safetensors
22
+ a36d517f3a1c629afc88d9ed1da8e41ebae34da3bfc28bd4cd5421161203919c model-layer-00021.safetensors
23
+ c17ef7ede6621cbef4af19e1c1cb90262c5c1a8569e96305314399d9e4743117 model-layer-00022.safetensors
24
+ a3945a6ccd6f8eb49f2fd031c7157c67fdf8be240a5aaf3d264e9d8cef9363ff model-layer-00023.safetensors
25
+ 96de6d3bb2d725f181c8c573ed367db5b3c6bdcffe4664b2ac4b79732fe46928 model-layer-00024.safetensors
26
+ 38b03b993fc0d1faa1561d68dadd92d16016d6c8f1ff45bb878f50eac5187d97 model-layer-00025.safetensors
27
+ 18a984e0005858c6966cd3583d102cf1449cfb33b4eb956da39fbb7f0201f7b0 model-layer-00026.safetensors
28
+ 71b43db7c49d79c9f4e781607368fa427689bc83f04170e07d8f492b004c715b model-layer-00027.safetensors
29
+ 9721a3937de1e68c04b7f27e473c66f027a99db08c183a62f5066a618d204c2f model-layer-00028.safetensors
30
+ 6379291e260ff9c7e6464fb8575bcda918cd2cced4a8aa4c4df25b753fd3c6a8 model-layer-00029.safetensors
31
+ 5a8d77fa6ad0d1ade6fc09412bbc024234cf29500e72f275eb7d0f29635396d3 model-layer-00030.safetensors
32
+ 266f83df2664128a809e73c5a4a66d52f561e12e490d097e767210076d8ac3c7 model-layer-00031.safetensors
33
+ 7fbbe022dee5c5a1abc2f34e4e8233f0889c3a6c136f4a8ade2a30fceb47198f model-layer-00032.safetensors
34
+ 2c9ee12a7ffab178f83ae09b4b32f7d47d0d3f1d66f015b37219684b4fb2fbe5 model-layer-00033.safetensors
35
+ 27741fe3a2ce23fd6aec824eed1c6368027d5b4c7ea7aa2f789ad86058cad2a7 model-layer-00034.safetensors
36
+ 73de4529e86bad56ea9214e72173f1395e118aa560267eff3089b05d1d895b55 model-layer-00035.safetensors
37
+ e342456af59dd2f1cd9af768495671a55247ebf44005c91d951d8b1fa203022b model-layer-00036.safetensors
38
+ b1b31e1a4c70987d53af10c6b69da05b4a6089eaac1beec0fdcbcafc639e17eb model-layer-00037.safetensors
39
+ 2f96937c417f671c23184c6b5c0ae7557c3d9647d59b689a10a3ce47eb40fe7c model-layer-00038.safetensors
40
+ bd1cd8474660df1ae8211ca1ca94b3340727f8f8e35ebe00022837d837952c95 model-layer-00039.safetensors
41
+ 5cdcdb39f00310dcce5f0e744a063b83d3fbed1ea30d888827a807302775f2b5 model-layer-00040.safetensors
42
+ b08cdd0830ba4d69de116de6bc84faa92882c8ce44e42c56fa93639067b94225 model-layer-00041.safetensors
43
+ 142512bab040f4024047142e4f4da369d0d088b87773c16863716c2b9e56379b model-layer-00042.safetensors
44
+ ee5c93564e067b630d5f7638711b9d1c01ec6a78beff5714ce749c2c97279b1f model-layer-00043.safetensors
45
+ 59b9a9e0120ba64dd6661c57b2c30522a03a8eee6cf3d7d93e1ea267af72a148 model-layer-00044.safetensors
46
+ c63b3fe88aef75eb0066d7dd5abe30b80d174b9e82be843cd43f0f7e5977b56e model-layer-00045.safetensors
47
+ 8f53dd271c1f77f684d70673817f0f74142c7ca78e1f2fde6af422e201f2ad38 model-layer-00046.safetensors
48
+ 5a2dc73e627443f2f95dee391123ef4e069d2ad03bffaf13026b6e012ea22803 model-layer-00047.safetensors
49
+ 6394124320964e6dbed2069d11d045c1ee2e8ec4a580c293e2987f1ea1ab6d9c model-tail.safetensors
chat_template.jinja ADDED
@@ -0,0 +1,160 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {%- set effective_reasoning_effort = reasoning_effort if reasoning_effort is defined and reasoning_effort in ['low', 'high'] else 'max' -%}
2
+ {%- if effective_reasoning_effort is not none -%}
3
+ {{- "<|im_start|>system\nReasoning Effort: " ~ (effective_reasoning_effort | capitalize) ~ "<|im_end|>" }}
4
+ {%- endif -%}
5
+ {%- if not add_generation_prompt is defined -%}
6
+ {%- set add_generation_prompt = false -%}
7
+ {%- endif -%}
8
+ {%- if not enable_thinking is defined -%}
9
+ {%- set enable_thinking = true -%}
10
+ {%- endif -%}
11
+ {%- if not keep_all_reasoning is defined -%}
12
+ {%- set keep_all_reasoning = true -%}
13
+ {%- endif -%}
14
+ {%- macro render_extra_keys(json_dict, handled_keys) -%}
15
+ {%- if json_dict is mapping %}
16
+ {%- for json_key in json_dict if json_key not in handled_keys %}
17
+ {%- if json_dict[json_key] is mapping or (json_dict[json_key] is sequence and json_dict[json_key] is not string) %}
18
+ {{- '\n<' ~ json_key ~ '>' ~ (json_dict[json_key] | tojson | safe) ~ '</' ~ json_key ~ '>' }}
19
+ {%- else %}
20
+ {{-'\n<' ~ json_key ~ '>' ~ (json_dict[json_key] | string) ~ '</' ~ json_key ~ '>' }}
21
+ {%- endif %}
22
+ {%- endfor %}
23
+ {%- endif %}
24
+ {%- endmacro -%}
25
+ {%- macro render_content(message_content) -%}
26
+ {%- if message_content is string -%}
27
+ {{- message_content -}}
28
+ {%- else -%}
29
+ {%- for content in message_content -%}
30
+ {%- if 'text' in content -%}
31
+ {{- content['text'] -}}
32
+ {%- endif -%}
33
+ {%- endfor -%}
34
+ {%- endif -%}
35
+ {%- endmacro -%}
36
+ {%- if messages[0]["role"] == "system" %}
37
+ {%- set system_message = messages[0]["content"] %}
38
+ {%- set loop_messages = messages[1:] %}
39
+ {%- else %}
40
+ {%- set loop_messages = messages %}
41
+ {%- endif %}
42
+ {%- set ns = namespace(last_user_index=-1) %}
43
+ {%- for m in loop_messages %}
44
+ {%- if m.role == 'user' %}
45
+ {%- set ns.last_user_index = loop.index0 -%}
46
+ {%- endif %}
47
+ {%- endfor %}
48
+ {%- if not tools is defined %}
49
+ {%- set tools = [] %}
50
+ {%- endif %}
51
+ {%- if system_message is defined %}
52
+ {{- "<|im_start|>system\n" + render_content(system_message) }}
53
+ {%- else %}
54
+ {{- "<|im_start|>system\nYou are Naive-N0.5-Flash, a helpful AI assistant engineered by Naive AI." }}
55
+ {%- endif %}
56
+ {%- if tools is iterable and tools | length > 0 %}
57
+ {{- "\n\n# Tools\n\nYou may call one or more functions to assist with the user query.\n\nYou have access to the following functions:\n\n" }}
58
+ {{- "<tools>" }}
59
+ {%- for tool in tools %}
60
+ {%- if tool.function is defined %}
61
+ {%- set tool = tool.function %}
62
+ {%- endif %}
63
+ {{- "\n<function>\n<name>" ~ tool.name ~ "</name>" }}
64
+ {%- if tool.description is defined %}
65
+ {{- '\n<description>' ~ (tool.description | trim) ~ '</description>' }}
66
+ {%- endif %}
67
+ {{- '\n<parameters>' }}
68
+ {%- if tool.parameters is defined and tool.parameters is mapping and tool.parameters.properties is defined and tool.parameters.properties is mapping %}
69
+ {%- for param_name, param_fields in tool.parameters.properties|items %}
70
+ {{- '\n<parameter>' }}
71
+ {{- '\n<name>' ~ param_name ~ '</name>' }}
72
+ {%- if param_fields.type is defined %}
73
+ {{- '\n<type>' ~ (param_fields.type | string) ~ '</type>' }}
74
+ {%- endif %}
75
+ {%- if param_fields.description is defined %}
76
+ {{- '\n<description>' ~ (param_fields.description | trim) ~ '</description>' }}
77
+ {%- endif %}
78
+ {%- set handled_keys = ['name', 'type', 'description'] %}
79
+ {{- render_extra_keys(param_fields, handled_keys) }}
80
+ {{- '\n</parameter>' }}
81
+ {%- endfor %}
82
+ {%- endif %}
83
+ {%- set handled_keys = ['type', 'properties'] %}
84
+ {{- render_extra_keys(tool.parameters, handled_keys) }}
85
+ {{- '\n</parameters>' }}
86
+ {%- set handled_keys = ['type', 'name', 'description', 'parameters'] %}
87
+ {{- render_extra_keys(tool, handled_keys) }}
88
+ {{- '\n</function>' }}
89
+ {%- endfor %}
90
+ {{- "\n</tools>" }}
91
+ {{- '\n\nFor each function call, output the function name and arguments in the following format:\n<tool_call>\n<function=example_function_name>\n<parameter=example_parameter_1>value_1</parameter>\n<parameter=example_parameter_2>This is the value for the second parameter\nthat can span\nmultiple lines</parameter>\n</function>\n</tool_call>\n\n<IMPORTANT>\n- Function calls MUST follow the specified format: an inner <function=...></function> block must be nested within <tool_call></tool_call> XML tags\n- DO NOT use function calls inside <think></think> tags.\n- The value enclosed between parameter tags is preserved exactly as-is, including newlines and spaces.\n</IMPORTANT>' }}
92
+ {%- endif %}
93
+ {{- '<|im_end|>' }}
94
+ {%- for message in loop_messages %}
95
+ {%- if message.content is string %}
96
+ {%- set content = message.content %}
97
+ {%- else %}
98
+ {%- set content = render_content(message.content) %}
99
+ {%- endif %}
100
+ {%- if message.role == "assistant" %}
101
+ {%- if message.reasoning_content is string %}
102
+ {%- set reasoning_content = message.reasoning_content %}
103
+ {%- else %}
104
+ {%- set reasoning_content = '' %}
105
+ {%- if '</think>' in content %}
106
+ {%- set reasoning_content = content.split('</think>')[0].split('<think>')[-1] %}
107
+ {%- set content = content.split('</think>')[-1] %}
108
+ {%- endif %}
109
+ {%- endif %}
110
+ {%- if (keep_all_reasoning or loop.index0 > ns.last_user_index) and reasoning_content -%}
111
+ {{- '<|im_start|>' + message.role + '\n<think>' + reasoning_content + '</think>' + content }}
112
+ {%- else %}
113
+ {{- '<|im_start|>' + message.role + '\n<think></think>' + content }}
114
+ {%- endif %}
115
+ {%- if message.tool_calls is defined and message.tool_calls is iterable and message.tool_calls | length > 0 %}
116
+ {%- for tool_call in message.tool_calls %}
117
+ {%- if tool_call.function is defined %}
118
+ {%- set tool_call = tool_call.function %}
119
+ {%- endif %}
120
+ {{- '<tool_call>\n<function=' + tool_call.name + '>\n' }}
121
+ {%- if tool_call.arguments is defined %}
122
+ {%- for args_name, args_value in tool_call.arguments|items %}
123
+ {{- '<parameter=' + args_name + '>' }}
124
+ {%- set args_value = args_value | tojson | safe if args_value is mapping or (args_value is sequence and args_value is not string) else args_value | string %}
125
+ {{- args_value }}
126
+ {{- '</parameter>\n' }}
127
+ {%- endfor %}
128
+ {%- endif %}
129
+ {{- '</function>\n</tool_call>' }}
130
+ {%- endfor %}
131
+ {%- endif %}
132
+ {{- '<|im_end|>' }}
133
+ {%- elif message.role == "user" %}
134
+ {{- '<|im_start|>' + message.role + '\n' + render_content(message.content) + '<|im_end|>' }}
135
+ {%- elif message.role == "system" %}
136
+ {{- '<|im_start|>' + message.role + '\n' + render_content(message.content) + '<|im_end|>' }}
137
+ {%- elif message.role == "tool" %}
138
+ {%- if loop.previtem and loop.previtem.role != "tool" %}
139
+ {{- '<|im_start|>tool\n' }}
140
+ {%- endif %}
141
+ {{- '<tool_response>\n' }}
142
+ {{- render_content(message.content) }}
143
+ {{- '\n</tool_response>\n' }}
144
+ {%- if not loop.last and loop.nextitem.role != "tool" %}
145
+ {{- '<|im_end|>' }}
146
+ {%- elif loop.last %}
147
+ {{- '<|im_end|>' }}
148
+ {%- endif %}
149
+ {%- else %}
150
+ {{- '<|im_start|>' + message.role + '\n' + render_content(message.content) + '<|im_end|>' }}
151
+ {%- endif %}
152
+ {%- endfor %}
153
+ {%- if add_generation_prompt %}
154
+ {{- '<|im_start|>assistant\n' }}
155
+ {%- if not enable_thinking -%}
156
+ {{- '<think></think>' -}}
157
+ {%- else -%}
158
+ {{- '' -}}
159
+ {%- endif -%}
160
+ {%- endif %}
compose.yml ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ services:
2
+ naive-vllm:
3
+ build: ./runtime
4
+ image: naive-n05-vllm:local
5
+ container_name: naive-n05-vllm
6
+ user: "${LOCAL_UID:-1000}:${LOCAL_GID:-1000}"
7
+ network_mode: host
8
+ ipc: host
9
+ restart: "no"
10
+ gpus: all
11
+ environment:
12
+ CUDA_VISIBLE_DEVICES: "0,1,2,3"
13
+ MODEL_PATH: /models/Naive-N0.5-Flash-NVFP4
14
+ NCCL_P2P_DISABLE: "1"
15
+ OMP_NUM_THREADS: "1"
16
+ VLLM_FLOAT32_MATMUL_PRECISION: highest
17
+ volumes:
18
+ - ./:/models/Naive-N0.5-Flash-NVFP4:ro
19
+ - ./runtime-cache:/cache
20
+ command:
21
+ - --model
22
+ - /models/Naive-N0.5-Flash-NVFP4
23
+ - --served-model-name
24
+ - Naive-N0.5-Flash-NVFP4
25
+ - --trust-remote-code
26
+ - --tensor-parallel-size
27
+ - "4"
28
+ - --distributed-executor-backend
29
+ - mp
30
+ - --dtype
31
+ - bfloat16
32
+ - --max-model-len
33
+ - "8192"
34
+ - --max-num-batched-tokens
35
+ - "256"
36
+ - --max-num-seqs
37
+ - "4"
38
+ - --kv-cache-memory-bytes
39
+ - "4294967296"
40
+ - --disable-custom-all-reduce
41
+ - --enable-prefix-caching
42
+ - --enable-chunked-prefill
43
+ - --compilation-config
44
+ - '{"mode":0,"cudagraph_mode":"FULL_DECODE_ONLY","cudagraph_capture_sizes":[1],"cudagraph_num_of_warmups":2}'
45
+ - --enable-auto-tool-choice
46
+ - --tool-call-parser
47
+ - mimo
48
+ - --reasoning-parser
49
+ - mimo
50
+ - --host
51
+ - "127.0.0.1"
52
+ - --port
53
+ - "8000"
config.json ADDED
@@ -0,0 +1,342 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_full_attention_sink_bias": false,
3
+ "add_swa_attention_sink_bias": true,
4
+ "architectures": [
5
+ "NaiveN05FlashForCausalLM"
6
+ ],
7
+ "attention_bias": false,
8
+ "attention_chunk_size": 128,
9
+ "attention_dropout": 0.0,
10
+ "attention_projection_layout": "split",
11
+ "attention_value_scale": 0.707,
12
+ "auto_map": {
13
+ "AutoConfig": "configuration_naive_n05_flash.NaiveN05FlashConfig",
14
+ "AutoModel": "modeling_naive_n05_flash.NaiveN05FlashModel",
15
+ "AutoModelForCausalLM": "modeling_naive_n05_flash.NaiveN05FlashForCausalLM"
16
+ },
17
+ "dtype": "bfloat16",
18
+ "enable_dsa": true,
19
+ "eos_token_id": 151645,
20
+ "head_dim": 192,
21
+ "hidden_act": "silu",
22
+ "hidden_size": 4096,
23
+ "hybrid_block_size": null,
24
+ "hybrid_layer_pattern": [
25
+ 0,
26
+ 1,
27
+ 1,
28
+ 1,
29
+ 1,
30
+ 0,
31
+ 1,
32
+ 1,
33
+ 1,
34
+ 1,
35
+ 1,
36
+ 0,
37
+ 1,
38
+ 1,
39
+ 1,
40
+ 1,
41
+ 1,
42
+ 0,
43
+ 1,
44
+ 1,
45
+ 1,
46
+ 1,
47
+ 1,
48
+ 0,
49
+ 1,
50
+ 1,
51
+ 1,
52
+ 1,
53
+ 1,
54
+ 0,
55
+ 1,
56
+ 1,
57
+ 1,
58
+ 1,
59
+ 1,
60
+ 0,
61
+ 1,
62
+ 1,
63
+ 1,
64
+ 1,
65
+ 1,
66
+ 0,
67
+ 1,
68
+ 1,
69
+ 1,
70
+ 1,
71
+ 1,
72
+ 0
73
+ ],
74
+ "index_head_dim": 128,
75
+ "index_n_heads": 16,
76
+ "index_n_kv_heads": 1,
77
+ "index_top_k": 2048,
78
+ "indexer_activation_dtype": "fp8_e4m3",
79
+ "initializer_range": 0.02,
80
+ "intermediate_size": 16384,
81
+ "layer_types": [
82
+ "deepseek_sparse_attention",
83
+ "sliding_attention",
84
+ "sliding_attention",
85
+ "sliding_attention",
86
+ "sliding_attention",
87
+ "deepseek_sparse_attention",
88
+ "sliding_attention",
89
+ "sliding_attention",
90
+ "sliding_attention",
91
+ "sliding_attention",
92
+ "sliding_attention",
93
+ "deepseek_sparse_attention",
94
+ "sliding_attention",
95
+ "sliding_attention",
96
+ "sliding_attention",
97
+ "sliding_attention",
98
+ "sliding_attention",
99
+ "deepseek_sparse_attention",
100
+ "sliding_attention",
101
+ "sliding_attention",
102
+ "sliding_attention",
103
+ "sliding_attention",
104
+ "sliding_attention",
105
+ "deepseek_sparse_attention",
106
+ "sliding_attention",
107
+ "sliding_attention",
108
+ "sliding_attention",
109
+ "sliding_attention",
110
+ "sliding_attention",
111
+ "deepseek_sparse_attention",
112
+ "sliding_attention",
113
+ "sliding_attention",
114
+ "sliding_attention",
115
+ "sliding_attention",
116
+ "sliding_attention",
117
+ "deepseek_sparse_attention",
118
+ "sliding_attention",
119
+ "sliding_attention",
120
+ "sliding_attention",
121
+ "sliding_attention",
122
+ "sliding_attention",
123
+ "deepseek_sparse_attention",
124
+ "sliding_attention",
125
+ "sliding_attention",
126
+ "sliding_attention",
127
+ "sliding_attention",
128
+ "sliding_attention",
129
+ "deepseek_sparse_attention"
130
+ ],
131
+ "layernorm_epsilon": 1e-05,
132
+ "max_position_embeddings": 1048576,
133
+ "model_type": "naive_n05_flash",
134
+ "moe_intermediate_size": 2048,
135
+ "moe_layer_freq": [
136
+ 0,
137
+ 1,
138
+ 1,
139
+ 1,
140
+ 1,
141
+ 1,
142
+ 1,
143
+ 1,
144
+ 1,
145
+ 1,
146
+ 1,
147
+ 1,
148
+ 1,
149
+ 1,
150
+ 1,
151
+ 1,
152
+ 1,
153
+ 1,
154
+ 1,
155
+ 1,
156
+ 1,
157
+ 1,
158
+ 1,
159
+ 1,
160
+ 1,
161
+ 1,
162
+ 1,
163
+ 1,
164
+ 1,
165
+ 1,
166
+ 1,
167
+ 1,
168
+ 1,
169
+ 1,
170
+ 1,
171
+ 1,
172
+ 1,
173
+ 1,
174
+ 1,
175
+ 1,
176
+ 1,
177
+ 1,
178
+ 1,
179
+ 1,
180
+ 1,
181
+ 1,
182
+ 1,
183
+ 1
184
+ ],
185
+ "n_group": 1,
186
+ "n_routed_experts": 256,
187
+ "n_shared_experts": null,
188
+ "norm_topk_prob": true,
189
+ "num_attention_heads": 64,
190
+ "num_experts_per_tok": 8,
191
+ "num_hidden_layers": 48,
192
+ "num_key_value_heads": 4,
193
+ "pad_token_id": 151643,
194
+ "partial_rotary_factor": 0.334,
195
+ "rope_parameters": {
196
+ "rope_type": "default",
197
+ "type": "default"
198
+ },
199
+ "rope_theta": 10000000,
200
+ "routed_scaling_factor": 1.0,
201
+ "scoring_func": "sigmoid",
202
+ "sliding_window": 128,
203
+ "sliding_window_size": 128,
204
+ "swa_head_dim": 192,
205
+ "swa_num_attention_heads": 64,
206
+ "swa_num_key_value_heads": 8,
207
+ "swa_rope_theta": 10000,
208
+ "swa_v_head_dim": 128,
209
+ "tie_word_embeddings": false,
210
+ "topk_group": 1,
211
+ "topk_method": "noaux_tc",
212
+ "transformers_version": "5.17.0",
213
+ "use_cache": true,
214
+ "v_head_dim": 128,
215
+ "vocab_size": 152576,
216
+ "quantization_config": {
217
+ "config_groups": {
218
+ "group_0": {
219
+ "input_activations": {
220
+ "dynamic": false,
221
+ "num_bits": 4,
222
+ "type": "float",
223
+ "group_size": 16
224
+ },
225
+ "weights": {
226
+ "dynamic": false,
227
+ "num_bits": 4,
228
+ "type": "float",
229
+ "group_size": 16
230
+ },
231
+ "targets": [
232
+ "Linear"
233
+ ]
234
+ }
235
+ },
236
+ "ignore": [
237
+ "lm_head",
238
+ "model.embed_tokens",
239
+ "model.layers.0*",
240
+ "model.layers.1.mlp.gate",
241
+ "model.layers.1.self_attn*",
242
+ "model.layers.2.mlp.gate",
243
+ "model.layers.2.self_attn*",
244
+ "model.layers.3.mlp.gate",
245
+ "model.layers.3.self_attn*",
246
+ "model.layers.4.mlp.gate",
247
+ "model.layers.4.self_attn*",
248
+ "model.layers.5.mlp.gate",
249
+ "model.layers.5.self_attn*",
250
+ "model.layers.6.mlp.gate",
251
+ "model.layers.6.self_attn*",
252
+ "model.layers.7.mlp.gate",
253
+ "model.layers.7.self_attn*",
254
+ "model.layers.8.mlp.gate",
255
+ "model.layers.8.self_attn*",
256
+ "model.layers.9.mlp.gate",
257
+ "model.layers.9.self_attn*",
258
+ "model.layers.10.mlp.gate",
259
+ "model.layers.10.self_attn*",
260
+ "model.layers.11.mlp.gate",
261
+ "model.layers.11.self_attn*",
262
+ "model.layers.12.mlp.gate",
263
+ "model.layers.12.self_attn*",
264
+ "model.layers.13.mlp.gate",
265
+ "model.layers.13.self_attn*",
266
+ "model.layers.14.mlp.gate",
267
+ "model.layers.14.self_attn*",
268
+ "model.layers.15.mlp.gate",
269
+ "model.layers.15.self_attn*",
270
+ "model.layers.16.mlp.gate",
271
+ "model.layers.16.self_attn*",
272
+ "model.layers.17.mlp.gate",
273
+ "model.layers.17.self_attn*",
274
+ "model.layers.18.mlp.gate",
275
+ "model.layers.18.self_attn*",
276
+ "model.layers.19.mlp.gate",
277
+ "model.layers.19.self_attn*",
278
+ "model.layers.20.mlp.gate",
279
+ "model.layers.20.self_attn*",
280
+ "model.layers.21.mlp.gate",
281
+ "model.layers.21.self_attn*",
282
+ "model.layers.22.mlp.gate",
283
+ "model.layers.22.self_attn*",
284
+ "model.layers.23.mlp.gate",
285
+ "model.layers.23.self_attn*",
286
+ "model.layers.24.mlp.gate",
287
+ "model.layers.24.self_attn*",
288
+ "model.layers.25.mlp.gate",
289
+ "model.layers.25.self_attn*",
290
+ "model.layers.26.mlp.gate",
291
+ "model.layers.26.self_attn*",
292
+ "model.layers.27.mlp.gate",
293
+ "model.layers.27.self_attn*",
294
+ "model.layers.28.mlp.gate",
295
+ "model.layers.28.self_attn*",
296
+ "model.layers.29.mlp.gate",
297
+ "model.layers.29.self_attn*",
298
+ "model.layers.30.mlp.gate",
299
+ "model.layers.30.self_attn*",
300
+ "model.layers.31.mlp.gate",
301
+ "model.layers.31.self_attn*",
302
+ "model.layers.32.mlp.gate",
303
+ "model.layers.32.self_attn*",
304
+ "model.layers.33.mlp.gate",
305
+ "model.layers.33.self_attn*",
306
+ "model.layers.34.mlp.gate",
307
+ "model.layers.34.self_attn*",
308
+ "model.layers.35.mlp.gate",
309
+ "model.layers.35.self_attn*",
310
+ "model.layers.36.mlp.gate",
311
+ "model.layers.36.self_attn*",
312
+ "model.layers.37.mlp.gate",
313
+ "model.layers.37.self_attn*",
314
+ "model.layers.38.mlp.gate",
315
+ "model.layers.38.self_attn*",
316
+ "model.layers.39.mlp.gate",
317
+ "model.layers.39.self_attn*",
318
+ "model.layers.40.mlp.gate",
319
+ "model.layers.40.self_attn*",
320
+ "model.layers.41.mlp.gate",
321
+ "model.layers.41.self_attn*",
322
+ "model.layers.42.mlp.gate",
323
+ "model.layers.42.self_attn*",
324
+ "model.layers.43.mlp.gate",
325
+ "model.layers.43.self_attn*",
326
+ "model.layers.44.mlp.gate",
327
+ "model.layers.44.self_attn*",
328
+ "model.layers.45.mlp.gate",
329
+ "model.layers.45.self_attn*",
330
+ "model.layers.46.mlp.gate",
331
+ "model.layers.46.self_attn*",
332
+ "model.layers.47.mlp.gate",
333
+ "model.layers.47.self_attn*"
334
+ ],
335
+ "quant_algo": "NVFP4",
336
+ "producer": {
337
+ "name": "modelopt",
338
+ "version": "0.0.1.dev1+g23355eda9"
339
+ },
340
+ "quant_method": "modelopt"
341
+ }
342
+ }
configuration_naive_n05_flash.py ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2026 Naive AI.
2
+ # Copyright 2026 The HuggingFace Inc. team.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ from transformers.configuration_utils import PretrainedConfig
17
+
18
+
19
+ class NaiveN05FlashConfig(PretrainedConfig):
20
+ model_type = "naive_n05_flash"
21
+ keys_to_ignore_at_inference = ["past_key_values"]
22
+ attribute_map = {"num_local_experts": "n_routed_experts"}
23
+
24
+ def __init__(
25
+ self,
26
+ vocab_size: int = 152576,
27
+ hidden_size: int = 4096,
28
+ intermediate_size: int = 16384,
29
+ num_hidden_layers: int = 48,
30
+ num_attention_heads: int = 64,
31
+ num_key_value_heads: int = 4,
32
+ head_dim: int = 192,
33
+ v_head_dim: int = 128,
34
+ swa_num_attention_heads: int = 64,
35
+ swa_num_key_value_heads: int = 8,
36
+ swa_head_dim: int = 192,
37
+ swa_v_head_dim: int = 128,
38
+ hidden_act: str = "silu",
39
+ max_position_embeddings: int = 1048576,
40
+ initializer_range: float = 0.02,
41
+ layernorm_epsilon: float = 1e-5,
42
+ rope_theta: float = 10000000.0,
43
+ swa_rope_theta: float = 10000.0,
44
+ partial_rotary_factor: float = 0.334,
45
+ sliding_window: int = 128,
46
+ hybrid_layer_pattern: list[int] | None = None,
47
+ attention_bias: bool = False,
48
+ attention_projection_layout: str = "split",
49
+ attention_value_scale: float | None = 0.707,
50
+ add_full_attention_sink_bias: bool = False,
51
+ add_swa_attention_sink_bias: bool = True,
52
+ n_routed_experts: int = 256,
53
+ moe_intermediate_size: int = 2048,
54
+ num_experts_per_tok: int = 8,
55
+ routed_scaling_factor: float | None = 1.0,
56
+ scoring_func: str = "sigmoid",
57
+ topk_method: str = "noaux_tc",
58
+ n_group: int = 1,
59
+ topk_group: int = 1,
60
+ norm_topk_prob: bool = True,
61
+ moe_layer_freq: list[int] | None = None,
62
+ enable_dsa: bool = True,
63
+ index_top_k: int = 2048,
64
+ index_head_dim: int = 128,
65
+ index_n_heads: int = 16,
66
+ index_n_kv_heads: int = 1,
67
+ indexer_activation_dtype: str = "fp8_e4m3",
68
+ use_cache: bool = True,
69
+ tie_word_embeddings: bool = False,
70
+ pad_token_id: int | None = 151643,
71
+ eos_token_id: int | list[int] | None = 151645,
72
+ **kwargs,
73
+ ) -> None:
74
+ self.vocab_size = vocab_size
75
+ self.hidden_size = hidden_size
76
+ self.intermediate_size = intermediate_size
77
+ self.num_hidden_layers = num_hidden_layers
78
+ self.num_attention_heads = num_attention_heads
79
+ self.num_key_value_heads = num_key_value_heads
80
+ self.head_dim = head_dim
81
+ self.v_head_dim = v_head_dim
82
+ self.swa_num_attention_heads = swa_num_attention_heads
83
+ self.swa_num_key_value_heads = swa_num_key_value_heads
84
+ self.swa_head_dim = swa_head_dim
85
+ self.swa_v_head_dim = swa_v_head_dim
86
+ self.hidden_act = hidden_act
87
+ self.max_position_embeddings = max_position_embeddings
88
+ self.initializer_range = initializer_range
89
+ self.layernorm_epsilon = layernorm_epsilon
90
+ self.rope_theta = rope_theta
91
+ self.swa_rope_theta = swa_rope_theta
92
+ self.partial_rotary_factor = partial_rotary_factor
93
+ self.sliding_window = sliding_window
94
+ self.hybrid_layer_pattern = hybrid_layer_pattern or [
95
+ int(i != 0 and i % 6 != 5) for i in range(num_hidden_layers)
96
+ ]
97
+ self.attention_bias = attention_bias
98
+ self.attention_projection_layout = attention_projection_layout
99
+ self.attention_value_scale = attention_value_scale
100
+ self.add_full_attention_sink_bias = add_full_attention_sink_bias
101
+ self.add_swa_attention_sink_bias = add_swa_attention_sink_bias
102
+ self.n_routed_experts = n_routed_experts
103
+ self.moe_intermediate_size = moe_intermediate_size
104
+ self.num_experts_per_tok = num_experts_per_tok
105
+ self.routed_scaling_factor = routed_scaling_factor or 1.0
106
+ self.scoring_func = scoring_func
107
+ self.topk_method = topk_method
108
+ self.n_group = n_group
109
+ self.topk_group = topk_group
110
+ self.norm_topk_prob = norm_topk_prob
111
+ self.moe_layer_freq = moe_layer_freq or ([0] + [1] * (num_hidden_layers - 1))
112
+ self.enable_dsa = enable_dsa
113
+ self.index_top_k = index_top_k
114
+ self.index_head_dim = index_head_dim
115
+ self.index_n_heads = index_n_heads
116
+ self.index_n_kv_heads = index_n_kv_heads
117
+ self.indexer_activation_dtype = indexer_activation_dtype
118
+ self.use_cache = use_cache
119
+ super().__init__(
120
+ tie_word_embeddings=tie_word_embeddings, pad_token_id=pad_token_id, eos_token_id=eos_token_id, **kwargs
121
+ )
122
+ self.validate()
123
+
124
+ def validate(self):
125
+ if self.attention_projection_layout != "split" or self.index_n_kv_heads != 1:
126
+ raise ValueError("NaiveN05Flash requires split Q/K/V and one indexer KV head")
127
+ if not self.enable_dsa or self.index_top_k <= 0:
128
+ raise ValueError("NaiveN05Flash requires DSA with a positive index_top_k")
129
+ if self.indexer_activation_dtype not in ("bf16", "fp8_e4m3"):
130
+ raise ValueError("indexer_activation_dtype must be bf16 or fp8_e4m3")
131
+ if self.scoring_func != "sigmoid" or self.topk_method != "noaux_tc":
132
+ raise ValueError("NaiveN05Flash requires sigmoid routing with correction bias")
133
+ if self.n_group != 1 or self.topk_group != 1:
134
+ raise ValueError("NaiveN05Flash uses one expert group")
135
+ for prefix in ("", "swa_"):
136
+ heads = getattr(self, prefix + "num_attention_heads")
137
+ kv_heads = getattr(self, prefix + "num_key_value_heads")
138
+ head_dim = getattr(self, prefix + "head_dim")
139
+ rotary_dim = int(head_dim * self.partial_rotary_factor)
140
+ if kv_heads <= 0 or heads % kv_heads or rotary_dim % 2 or not 0 < rotary_dim <= head_dim:
141
+ raise ValueError("Invalid attention head or rotary dimensions")
142
+ if int(self.head_dim * self.partial_rotary_factor) > self.index_head_dim:
143
+ raise ValueError("Indexer head dimension must cover the rotary dimension")
144
+ if self._attn_implementation not in (None, "eager"):
145
+ raise ValueError("NaiveN05Flash supports eager attention only")
146
+ if len(self.hybrid_layer_pattern) != self.num_hidden_layers:
147
+ raise ValueError("hybrid_layer_pattern must contain one entry per layer")
148
+ if len(self.moe_layer_freq) != self.num_hidden_layers:
149
+ raise ValueError("moe_layer_freq must contain one entry per layer")
150
+ self.layer_types = [
151
+ "sliding_attention" if is_swa else "deepseek_sparse_attention" for is_swa in self.hybrid_layer_pattern
152
+ ]
153
+
154
+
155
+ __all__ = ["NaiveN05FlashConfig"]
generation_config.json ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "do_sample": true,
3
+ "temperature": 1.0,
4
+ "top_p": 0.95,
5
+ "repetition_penalty": 1.0,
6
+ "eos_token_id": 151645,
7
+ "pad_token_id": 151643,
8
+ "max_new_tokens": 131072
9
+ }
hf_quant_config.json ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "producer": {
3
+ "name": "modelopt",
4
+ "version": "0.0.1.dev1+g23355eda9"
5
+ },
6
+ "quantization": {
7
+ "quant_algo": "NVFP4",
8
+ "kv_cache_quant_algo": null,
9
+ "group_size": 16,
10
+ "exclude_modules": [
11
+ "lm_head",
12
+ "model.embed_tokens",
13
+ "model.layers.0*",
14
+ "model.layers.1.mlp.gate",
15
+ "model.layers.1.self_attn*",
16
+ "model.layers.2.mlp.gate",
17
+ "model.layers.2.self_attn*",
18
+ "model.layers.3.mlp.gate",
19
+ "model.layers.3.self_attn*",
20
+ "model.layers.4.mlp.gate",
21
+ "model.layers.4.self_attn*",
22
+ "model.layers.5.mlp.gate",
23
+ "model.layers.5.self_attn*",
24
+ "model.layers.6.mlp.gate",
25
+ "model.layers.6.self_attn*",
26
+ "model.layers.7.mlp.gate",
27
+ "model.layers.7.self_attn*",
28
+ "model.layers.8.mlp.gate",
29
+ "model.layers.8.self_attn*",
30
+ "model.layers.9.mlp.gate",
31
+ "model.layers.9.self_attn*",
32
+ "model.layers.10.mlp.gate",
33
+ "model.layers.10.self_attn*",
34
+ "model.layers.11.mlp.gate",
35
+ "model.layers.11.self_attn*",
36
+ "model.layers.12.mlp.gate",
37
+ "model.layers.12.self_attn*",
38
+ "model.layers.13.mlp.gate",
39
+ "model.layers.13.self_attn*",
40
+ "model.layers.14.mlp.gate",
41
+ "model.layers.14.self_attn*",
42
+ "model.layers.15.mlp.gate",
43
+ "model.layers.15.self_attn*",
44
+ "model.layers.16.mlp.gate",
45
+ "model.layers.16.self_attn*",
46
+ "model.layers.17.mlp.gate",
47
+ "model.layers.17.self_attn*",
48
+ "model.layers.18.mlp.gate",
49
+ "model.layers.18.self_attn*",
50
+ "model.layers.19.mlp.gate",
51
+ "model.layers.19.self_attn*",
52
+ "model.layers.20.mlp.gate",
53
+ "model.layers.20.self_attn*",
54
+ "model.layers.21.mlp.gate",
55
+ "model.layers.21.self_attn*",
56
+ "model.layers.22.mlp.gate",
57
+ "model.layers.22.self_attn*",
58
+ "model.layers.23.mlp.gate",
59
+ "model.layers.23.self_attn*",
60
+ "model.layers.24.mlp.gate",
61
+ "model.layers.24.self_attn*",
62
+ "model.layers.25.mlp.gate",
63
+ "model.layers.25.self_attn*",
64
+ "model.layers.26.mlp.gate",
65
+ "model.layers.26.self_attn*",
66
+ "model.layers.27.mlp.gate",
67
+ "model.layers.27.self_attn*",
68
+ "model.layers.28.mlp.gate",
69
+ "model.layers.28.self_attn*",
70
+ "model.layers.29.mlp.gate",
71
+ "model.layers.29.self_attn*",
72
+ "model.layers.30.mlp.gate",
73
+ "model.layers.30.self_attn*",
74
+ "model.layers.31.mlp.gate",
75
+ "model.layers.31.self_attn*",
76
+ "model.layers.32.mlp.gate",
77
+ "model.layers.32.self_attn*",
78
+ "model.layers.33.mlp.gate",
79
+ "model.layers.33.self_attn*",
80
+ "model.layers.34.mlp.gate",
81
+ "model.layers.34.self_attn*",
82
+ "model.layers.35.mlp.gate",
83
+ "model.layers.35.self_attn*",
84
+ "model.layers.36.mlp.gate",
85
+ "model.layers.36.self_attn*",
86
+ "model.layers.37.mlp.gate",
87
+ "model.layers.37.self_attn*",
88
+ "model.layers.38.mlp.gate",
89
+ "model.layers.38.self_attn*",
90
+ "model.layers.39.mlp.gate",
91
+ "model.layers.39.self_attn*",
92
+ "model.layers.40.mlp.gate",
93
+ "model.layers.40.self_attn*",
94
+ "model.layers.41.mlp.gate",
95
+ "model.layers.41.self_attn*",
96
+ "model.layers.42.mlp.gate",
97
+ "model.layers.42.self_attn*",
98
+ "model.layers.43.mlp.gate",
99
+ "model.layers.43.self_attn*",
100
+ "model.layers.44.mlp.gate",
101
+ "model.layers.44.self_attn*",
102
+ "model.layers.45.mlp.gate",
103
+ "model.layers.45.self_attn*",
104
+ "model.layers.46.mlp.gate",
105
+ "model.layers.46.self_attn*",
106
+ "model.layers.47.mlp.gate",
107
+ "model.layers.47.self_attn*"
108
+ ]
109
+ }
110
+ }
model.safetensors.index.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b989f8e0c01e2b54f46efcd3d134b53b23c59c8faba37df1d8a6a52a0baccdec
3
+ size 13388642
modeling_naive_n05_flash.py ADDED
@@ -0,0 +1,243 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2026 Naive AI.
2
+ # Copyright 2026 The HuggingFace Inc. team.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ from copy import copy
17
+
18
+ import torch
19
+ from torch import nn
20
+ from transformers.cache_utils import DynamicCache
21
+ from transformers.conversion_mapping import get_checkpoint_conversion_mapping, register_checkpoint_conversion_mapping
22
+ from transformers.generation import GenerationMixin
23
+ from transformers.modeling_outputs import CausalLMOutputWithPast
24
+ from transformers.modeling_utils import PreTrainedModel
25
+ from transformers.models.deepseek_v3.modeling_deepseek_v3 import DeepseekV3Experts, DeepseekV3TopkRouter
26
+ from transformers.models.deepseek_v3.modeling_deepseek_v3 import DeepseekV3MLP as NaiveN05FlashMLP
27
+ from transformers.models.gpt_neox.modeling_gpt_neox import GPTNeoXRotaryEmbedding as NaiveN05FlashRotaryEmbedding
28
+ from transformers.models.gpt_neox.modeling_gpt_neox import apply_rotary_pos_emb
29
+ from transformers.models.llama.modeling_llama import LlamaRMSNorm as NaiveN05FlashRMSNorm
30
+ from transformers.models.llama.modeling_llama import repeat_kv
31
+
32
+ from .configuration_naive_n05_flash import NaiveN05FlashConfig
33
+
34
+ # Fuse experts weights
35
+ # mlp.experts.{i}.{gate,up,down}_proj.weight[_scale_inv] -> mlp.experts.{gate,up,down}_proj.weight[_scale_inv]
36
+ register_checkpoint_conversion_mapping("naive_n05_flash", get_checkpoint_conversion_mapping("deepseek_v3"), overwrite=True)
37
+
38
+
39
+ def round_indexer_fp8(states):
40
+ states = states.float()
41
+ scale = states.abs().amax(dim=-1, keepdim=True).clamp_min(1e-4) / 448.0
42
+ return (states / scale).clamp(-448, 448).to(torch.float8_e4m3fn).float() * scale
43
+
44
+
45
+ class NaiveN05FlashMoE(nn.Module):
46
+ """DeepSeek-V3-style routed experts without a shared expert."""
47
+
48
+ def __init__(self, config):
49
+ super().__init__()
50
+ self.experts = DeepseekV3Experts(config)
51
+ self.gate = DeepseekV3TopkRouter(config)
52
+
53
+ def forward(self, states):
54
+ original_shape = states.shape
55
+ _, topk_weights, topk_indices = self.gate(states)
56
+ states = states.view(-1, states.shape[-1])
57
+ states = self.experts(states, topk_indices, topk_weights)
58
+ return states.view(*original_shape)
59
+
60
+
61
+ class NaiveN05FlashIndexer(nn.Module):
62
+ def __init__(self, config, layer_idx):
63
+ super().__init__()
64
+ self.config = config
65
+ self.layer_idx = layer_idx
66
+ self.wq = nn.Linear(config.hidden_size, config.index_n_heads * config.index_head_dim, bias=False)
67
+ self.wk = nn.Linear(config.hidden_size, config.index_head_dim, bias=False)
68
+ self.k_norm = nn.LayerNorm(config.index_head_dim, eps=1e-5)
69
+ self.weights_proj = nn.Linear(config.hidden_size, config.index_n_heads, bias=False)
70
+
71
+ def forward(self, states, position_embeddings, past_key_values=None):
72
+ c = self.config
73
+ batch, length, _ = states.shape
74
+ query = self.wq(states).view(batch, length, c.index_n_heads, c.index_head_dim).transpose(1, 2)
75
+ key = self.k_norm(self.wk(states)).unsqueeze(1)
76
+ query, key = apply_rotary_pos_emb(query, key, *position_embeddings)
77
+ if c.indexer_activation_dtype == "fp8_e4m3":
78
+ query, key = round_indexer_fp8(query), round_indexer_fp8(key)
79
+ if past_key_values is not None:
80
+ key = past_key_values.update_indexer(key.squeeze(1), self.layer_idx).unsqueeze(1)
81
+ scores = (query.float() @ key.float().transpose(-1, -2)).relu()
82
+ weights = self.weights_proj(states) * c.index_n_heads**-0.5
83
+ return (scores * weights.transpose(1, 2).unsqueeze(-1).float()).sum(dim=1)
84
+
85
+
86
+ class NaiveN05FlashAttention(nn.Module):
87
+ def __init__(self, config, layer_idx):
88
+ super().__init__()
89
+ self.config = config
90
+ self.layer_idx = layer_idx
91
+ self.is_swa = bool(config.hybrid_layer_pattern[layer_idx])
92
+ prefix = "swa_" if self.is_swa else ""
93
+ self.heads = getattr(config, prefix + "num_attention_heads")
94
+ self.kv_heads = getattr(config, prefix + "num_key_value_heads")
95
+ self.head_dim = getattr(config, prefix + "head_dim")
96
+ self.v_dim = getattr(config, prefix + "v_head_dim")
97
+ rope_config = copy(config)
98
+ rope_config.head_dim = self.head_dim
99
+ rope_config.rope_parameters = {
100
+ "rope_type": "default",
101
+ "rope_theta": getattr(config, prefix + "rope_theta"),
102
+ "partial_rotary_factor": config.partial_rotary_factor,
103
+ }
104
+ self.rotary_emb = NaiveN05FlashRotaryEmbedding(rope_config)
105
+ self.q_proj = nn.Linear(config.hidden_size, self.heads * self.head_dim, bias=config.attention_bias)
106
+ self.k_proj = nn.Linear(
107
+ config.hidden_size,
108
+ self.kv_heads * self.head_dim,
109
+ bias=config.attention_bias,
110
+ )
111
+ self.v_proj = nn.Linear(config.hidden_size, self.kv_heads * self.v_dim, bias=config.attention_bias)
112
+ self.o_proj = nn.Linear(self.heads * self.v_dim, config.hidden_size, bias=False)
113
+ self.indexer = None if self.is_swa else NaiveN05FlashIndexer(config, layer_idx)
114
+ sink = config.add_swa_attention_sink_bias if self.is_swa else config.add_full_attention_sink_bias
115
+ self.attention_sink_bias = nn.Parameter(torch.zeros(self.heads), requires_grad=False) if sink else None
116
+
117
+ def forward(self, states, positions, allowed, past_key_values=None):
118
+ batch, length, _ = states.shape
119
+ past_length = 0 if past_key_values is None else past_key_values.get_seq_length(self.layer_idx)
120
+ key_offset = 0 if past_key_values is None else past_key_values.get_mask_sizes(length, self.layer_idx)[1]
121
+ query = self.q_proj(states).view(batch, length, self.heads, self.head_dim).transpose(1, 2)
122
+ key = self.k_proj(states).view(batch, length, self.kv_heads, self.head_dim).transpose(1, 2)
123
+ value = self.v_proj(states).view(batch, length, self.kv_heads, self.v_dim).transpose(1, 2)
124
+ position_embeddings = self.rotary_emb(states, positions)
125
+ query, key = apply_rotary_pos_emb(query, key, *position_embeddings)
126
+ if past_key_values is not None:
127
+ key, value = past_key_values.update(key, value, self.layer_idx)
128
+ key_length = key.shape[-2]
129
+ allowed = allowed[..., key_offset : key_offset + key_length]
130
+ if self.is_swa:
131
+ query_offsets = past_length + torch.arange(length, device=states.device)
132
+ key_offsets = key_offset + torch.arange(key_length, device=states.device)
133
+ allowed = allowed & (query_offsets[:, None] - key_offsets[None, :] < self.config.sliding_window)
134
+ else:
135
+ scores = self.indexer(states, position_embeddings, past_key_values).masked_fill(~allowed, -torch.inf)
136
+ # Stable ties keep padding from changing which equal-score keys win.
137
+ selected = scores.argsort(dim=-1, descending=True, stable=True)[..., : self.config.index_top_k]
138
+ allowed = allowed & torch.zeros_like(scores, dtype=torch.bool).scatter(-1, selected, True)
139
+ key = repeat_kv(key, self.heads // self.kv_heads)
140
+ value = repeat_kv(value, self.heads // self.kv_heads)
141
+ if self.config.attention_value_scale is not None:
142
+ value = value * self.config.attention_value_scale
143
+ logits = (query @ key.transpose(-1, -2)) * self.head_dim**-0.5
144
+ logits = logits.masked_fill(~allowed[:, None], -torch.inf)
145
+ if self.attention_sink_bias is not None:
146
+ sink = self.attention_sink_bias[None, :, None, None].expand(batch, -1, length, -1)
147
+ logits = torch.cat((logits, sink), dim=-1)
148
+ probabilities = logits.float().softmax(-1).nan_to_num(0.0)[..., :key_length].to(value.dtype)
149
+ output = (probabilities @ value).transpose(1, 2).reshape(batch, length, -1)
150
+ return self.o_proj(output)
151
+
152
+
153
+ class NaiveN05FlashDecoderLayer(nn.Module):
154
+ def __init__(self, config, layer_idx):
155
+ super().__init__()
156
+ self.self_attn = NaiveN05FlashAttention(config, layer_idx)
157
+ self.mlp = NaiveN05FlashMoE(config) if config.moe_layer_freq[layer_idx] else NaiveN05FlashMLP(config)
158
+ self.input_layernorm = NaiveN05FlashRMSNorm(config.hidden_size, config.layernorm_epsilon)
159
+ self.post_attention_layernorm = NaiveN05FlashRMSNorm(config.hidden_size, config.layernorm_epsilon)
160
+
161
+ def forward(self, states, positions, allowed, past_key_values=None):
162
+ states = states + self.self_attn(self.input_layernorm(states), positions, allowed, past_key_values)
163
+ return states + self.mlp(self.post_attention_layernorm(states))
164
+
165
+
166
+ class NaiveN05FlashModel(PreTrainedModel):
167
+ config_class = NaiveN05FlashConfig
168
+ base_model_prefix = "model"
169
+ _can_set_experts_implementation_cached_value = True
170
+
171
+ def __init__(self, config):
172
+ super().__init__(config)
173
+ self.embed_tokens = nn.Embedding(config.vocab_size, config.hidden_size)
174
+ self.layers = nn.ModuleList([NaiveN05FlashDecoderLayer(config, i) for i in range(config.num_hidden_layers)])
175
+ self.norm = NaiveN05FlashRMSNorm(config.hidden_size, config.layernorm_epsilon)
176
+
177
+ def forward(self, states, positions, allowed, past_key_values=None):
178
+ for layer in self.layers:
179
+ states = layer(states, positions, allowed, past_key_values)
180
+ return self.norm(states)
181
+
182
+
183
+ class NaiveN05FlashForCausalLM(PreTrainedModel, GenerationMixin):
184
+ config_class = NaiveN05FlashConfig
185
+ base_model_prefix = "model"
186
+ _no_split_modules = ["NaiveN05FlashDecoderLayer"]
187
+ _skip_keys_device_placement = ["past_key_values"]
188
+ _keep_in_fp32_modules_strict = ["mlp.gate.weight", "mlp.gate.e_score_correction_bias"]
189
+ _can_set_experts_implementation_cached_value = True
190
+
191
+ def __init__(self, config):
192
+ config.validate()
193
+ super().__init__(config)
194
+ self.model = NaiveN05FlashModel(config)
195
+ self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False)
196
+ self.post_init()
197
+ self.eval().requires_grad_(False)
198
+
199
+ def get_input_embeddings(self):
200
+ return self.model.embed_tokens
201
+
202
+ def get_output_embeddings(self):
203
+ return self.lm_head
204
+
205
+ @torch.inference_mode()
206
+ def forward(
207
+ self,
208
+ input_ids=None,
209
+ attention_mask=None,
210
+ position_ids=None,
211
+ inputs_embeds=None,
212
+ use_cache=None,
213
+ past_key_values=None,
214
+ **kwargs,
215
+ ):
216
+ use_cache = self.config.use_cache if use_cache is None else use_cache
217
+ if past_key_values is not None and not use_cache:
218
+ raise ValueError("Pass use_cache=True when providing past_key_values")
219
+ if use_cache and past_key_values is None:
220
+ past_key_values = DynamicCache(config=self.config)
221
+ if past_key_values is not None and not isinstance(past_key_values, DynamicCache):
222
+ raise ValueError("NaiveN05Flash supports DynamicCache only")
223
+ if (input_ids is None) == (inputs_embeds is None):
224
+ raise ValueError("Provide exactly one of input_ids or inputs_embeds")
225
+ states = self.model.embed_tokens(input_ids) if inputs_embeds is None else inputs_embeds
226
+ batch, length, _ = states.shape
227
+ past_length = 0 if past_key_values is None else past_key_values.get_seq_length()
228
+ total_length = past_length + length
229
+ if attention_mask is None:
230
+ attention_mask = torch.ones(batch, total_length, device=states.device, dtype=torch.bool)
231
+ if attention_mask.shape != (batch, total_length):
232
+ raise ValueError("Expected a 2-D attention_mask covering the cached prefix and new tokens")
233
+ if position_ids is None:
234
+ position_ids = (attention_mask.long().cumsum(-1) - 1).clamp_min(0)[:, -length:]
235
+ query_offsets = past_length + torch.arange(length, device=states.device)
236
+ key_offsets = torch.arange(total_length, device=states.device)
237
+ allowed = query_offsets[:, None] >= key_offsets[None, :]
238
+ allowed = allowed[None] & attention_mask[:, None].bool()
239
+ logits = self.lm_head(self.model(states, position_ids, allowed, past_key_values))
240
+ return CausalLMOutputWithPast(logits=logits, past_key_values=past_key_values)
241
+
242
+
243
+ __all__ = ["NaiveN05FlashForCausalLM", "NaiveN05FlashModel"]
quantization_provenance.json ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "source_repository": "NaiveAI/Naive-N0.5-Flash",
3
+ "source_revision": "0235b3b5ff27422b1f57cdc2acddfaf643e08356",
4
+ "modelopt_revision": "23355eda90a25c290f9b1fdfb928ad54caae7d10",
5
+ "recipe": "NVFP4 experts only; max calibration; original-precision attention, router and KV cache",
6
+ "calibration": {
7
+ "sources": [
8
+ {
9
+ "id": "ise-uiuc/Magicoder-OSS-Instruct-75K",
10
+ "revision": "5f839b1f368a76b161028bb9edff055db34022b2",
11
+ "format": "json",
12
+ "file": "data-oss_instruct-decontaminated.jsonl"
13
+ },
14
+ {
15
+ "id": "HuggingFaceH4/ultrachat_200k",
16
+ "revision": "8049631c405ae6576f93f445c6b8166f76f5505a",
17
+ "format": "parquet",
18
+ "file": "data/train_sft-00000-of-00003-a3ecf92756993583.parquet"
19
+ }
20
+ ],
21
+ "samples": 128,
22
+ "sequence_length": 4096,
23
+ "tokens": 524288,
24
+ "sha256": "19061f6f772f68b6fe9096a01376e236cf27ba03a1c58f2e36acc5f2f0cab758",
25
+ "packing": "Chat-formatted records concatenated with EOS, equal coding/chat token counts",
26
+ "shuffle_seed": 20260928,
27
+ "shuffle_buffer": 128
28
+ },
29
+ "runtime": "Native vLLM 0.28.0 V1 engine, Naive model plugin, TP4, paged KV/indexer cache, FlashInfer 0.7.0 B12x NVFP4 experts, single-request decode CUDA graphs",
30
+ "export_recovery": {
31
+ "calibration_layers_reused": 48,
32
+ "original_precision_tail_tensors": [
33
+ "lm_head.weight",
34
+ "model.embed_tokens.weight",
35
+ "model.norm.weight"
36
+ ],
37
+ "tensor_bytes": 182547868032,
38
+ "reason": "Fused expert source names misidentified as unplaced by generic exporter"
39
+ },
40
+ "source_precision_audit": {
41
+ "passed": true,
42
+ "tensors_checked": 472,
43
+ "restored_from_source": {
44
+ "model-layer-00047.safetensors": [
45
+ "model.layers.47.mlp.gate.weight"
46
+ ]
47
+ },
48
+ "check": "Exact source dtype, shape and SHA-256 of tensor payload"
49
+ },
50
+ "calibration_note": "Layer 47 routing was materialized in BF16 during calibration; its final checkpoint router is restored byte-for-byte from the FP32 source.",
51
+ "final_export_validation": {
52
+ "passed": true,
53
+ "tensor_count": 144856,
54
+ "packed_expert_weights": 36096,
55
+ "safetensor_shards": 49,
56
+ "tensor_bytes": 182549965184,
57
+ "all_source_tensors_accounted_for": true
58
+ },
59
+ "runtime_performance_validation": "validation/native-vllm-benchmark.json",
60
+ "runtime_build": "runtime/Dockerfile"
61
+ }
runtime-lock.json ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "base_image": "vllm/vllm-openai@sha256:61fc8a896b0a4fbbbdc063bc4b0dbc25ce98e02b5050c24aeb7830ac02039b14",
3
+ "tested_local_image_digest": "naive-n05-vllm@sha256:edc59ac2c49c6d62ee358ffd1ffb4a8b4a59b40a704e54da6286cf8b7f942511",
4
+ "image_note": "The tested derived image is locally built, not a public registry artifact. Build runtime/Dockerfile from this release.",
5
+ "runtime_source_sha256": {
6
+ ".dockerignore": "05cc6ae53cfd6129f1d7010aa874c6cf0a6019b1adfeff3f4fab27f2d04f43ca",
7
+ "Dockerfile": "201fa4be561e877098945d37897cc0f7a7c9e7dd15eb4779b15830717682f101",
8
+ "LICENSE": "969b552eb338dc04f165177043e43d2b6daab45accc29021d77c200e3b3ba68a",
9
+ "LICENSE-APACHE-2.0.txt": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
10
+ "THIRD_PARTY_NOTICES.md": "f42c84a8c8a64b743c491d7e1d7ed1e1daa8ea4546f7ec877db30d4379974ece",
11
+ "pyproject.toml": "90ad59f3b03570a9bb18d5d399a721d5c5daf9e2acba2f5a38d6e44c7cb8e9d3",
12
+ "requirements.txt": "829ba4fbb1e769da9505c900701f439a3d2126c4c7d2d15e3b539fa37a20aa18",
13
+ "scripts/benchmark_stream.py": "dab13abe554c6c28f89268ee3a2cec2e6425f73aa91f18692318b76886704157",
14
+ "scripts/decode_kernels.py": "ea0e71f5c4fd678b5cdf423b62ad07d37bed7de5fdc2af9ee89f08856ee34d09",
15
+ "scripts/fused_experts.py": "f77eceec0a969eb7ff99e5177bd9d4cda1bfa3f0668ed614c060d28883f46018",
16
+ "scripts/nvfp4_runtime.py": "be6453ca83d8f9ec528b07f17e78a41bfdcd8859fa9ec2644b6136e7068e9a1a",
17
+ "scripts/preflight.py": "43ac170da1d7cf614fb5f4d7f0ee70635d2d78bd638bfb3af2322baf91a08600",
18
+ "scripts/safe_device_transfer.py": "61e931597e59e72ded3525976181e7164933e72f4647423c00ad2be0a57940db",
19
+ "scripts/validate_api.py": "82e04b0d21e9956da18930e27d35c4fc45f1a4b071bd2a19c6f62271deb74c2d",
20
+ "sitecustomize.py": "552485e6e5e03c72c1d8b76a43a1ede48f8283a5d1e5ab93761125ec4a2c492b",
21
+ "vllm_naive/__init__.py": "8a5fddf2b89a4c33b6774a3ed75004a73db990ee711b8411e8772d7f2786f679",
22
+ "vllm_naive/attention.py": "f3aa650b110495224338b211330f6dcb7598cbeff917e7b1dac77695234f187c",
23
+ "vllm_naive/model.py": "f0d5769018f8487c267d0ee6c3ba4cbf138e47d65c35c0cc0a00a95dfb69d763"
24
+ },
25
+ "versions": {
26
+ "vllm": "0.28.0",
27
+ "torch": "2.13.0+cu130",
28
+ "transformers": "5.17.0",
29
+ "accelerate": "1.15.0",
30
+ "tokenizers": "0.23.2",
31
+ "huggingface-hub": "1.33.0",
32
+ "safetensors": "0.8.0",
33
+ "flashinfer-python": "0.7.0",
34
+ "nvidia-cutlass-dsl": "4.6.2",
35
+ "triton": "3.7.1"
36
+ },
37
+ "tested_at": "2026-09-28T10:42:32.236283+00:00"
38
+ }
runtime/.dockerignore ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ __pycache__
2
+ *.pyc
runtime/Dockerfile ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM vllm/vllm-openai@sha256:61fc8a896b0a4fbbbdc063bc4b0dbc25ce98e02b5050c24aeb7830ac02039b14
2
+
3
+ # Preserve the pinned vLLM/PyTorch/CUDA/CUTLASS/Triton stack.
4
+ COPY requirements.txt /opt/naive/requirements.txt
5
+ RUN python3 -m pip install --no-cache-dir --no-deps --target /opt/naive-python -r /opt/naive/requirements.txt \
6
+ && python3 -m pip install --no-cache-dir --no-deps --target /opt/flashinfer-v070 flashinfer-python==0.7.0
7
+ COPY scripts/ /opt/naive/scripts/
8
+ COPY sitecustomize.py /opt/naive-python/sitecustomize.py
9
+ COPY pyproject.toml /opt/vllm-naive/pyproject.toml
10
+ COPY vllm_naive/ /opt/vllm-naive/vllm_naive/
11
+ RUN python3 -m pip install --no-deps --no-build-isolation /opt/vllm-naive
12
+ ENV PYTHONPATH=/opt/flashinfer-v070:/opt/naive-python:/opt/naive/scripts \
13
+ NAIVE_FLASHINFER_SOURCE_ONLY=1 \
14
+ NAIVE_EXPERT_BACKEND=fused \
15
+ FLASHINFER_WORKSPACE_BASE=/cache/flashinfer-v070 \
16
+ HF_MODULES_CACHE=/cache/hf-modules \
17
+ TORCH_EXTENSIONS_DIR=/cache/torch-extensions \
18
+ TRITON_CACHE_DIR=/cache/triton \
19
+ XDG_CACHE_HOME=/cache/xdg \
20
+ HF_HUB_OFFLINE=1 \
21
+ TRANSFORMERS_OFFLINE=1 \
22
+ OMP_NUM_THREADS=1 \
23
+ NCCL_P2P_DISABLE=1 \
24
+ VLLM_PLUGINS=naive_n05 \
25
+ VLLM_WORKER_MULTIPROC_METHOD=spawn \
26
+ VLLM_CACHE_ROOT=/cache/vllm \
27
+ VLLM_FLOAT32_MATMUL_PRECISION=highest
28
+ WORKDIR /opt/naive
29
+ ENTRYPOINT ["python3", "-m", "vllm.entrypoints.openai.api_server"]
runtime/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Naive NVFP4 runtime contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
runtime/LICENSE-APACHE-2.0.txt ADDED
@@ -0,0 +1,202 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
runtime/THIRD_PARTY_NOTICES.md ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Licensing and attribution
2
+
3
+ The quantized model is derived from Naive AI's `Naive-N0.5-Flash` checkpoint.
4
+ Its MIT license and copyright notice are preserved in the repository's root
5
+ `LICENSE` file. Naive AI describes the original model as a derivative of
6
+ Xiaomi MiMo-V2.5; see the linked upstream model card for that lineage.
7
+
8
+ The upstream `configuration_naive_n05_flash.py` and
9
+ `modeling_naive_n05_flash.py` retain their original Apache-2.0 copyright and
10
+ license headers. The Apache-2.0 license text is in `LICENSE-APACHE-2.0.txt`.
11
+
12
+ The additional runtime scripts and deployment files in `runtime/`, and the
13
+ root `compose.yml`, are provided under the MIT terms in `runtime/LICENSE`.
14
+ Dependencies downloaded during the Docker build retain their own licenses;
15
+ the dependency image and Python packages are not redistributed in this
16
+ repository.
runtime/pyproject.toml ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "vllm-naive-n05"
7
+ version = "0.1.0"
8
+ requires-python = ">=3.12"
9
+
10
+ [project.entry-points."vllm.general_plugins"]
11
+ naive_n05 = "vllm_naive:register"
12
+
13
+ [tool.setuptools.packages.find]
14
+ include = ["vllm_naive*"]
runtime/requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ # Install into an isolated target over the pinned CUDA/PyTorch base image.
2
+ transformers==5.17.0
3
+ accelerate==1.15.0
4
+ tokenizers==0.23.2
5
+ huggingface-hub==1.33.0
6
+ safetensors==0.8.0
runtime/scripts/benchmark_stream.py ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Measure real vLLM streamed token delivery, with exact returned token IDs."""
2
+ import argparse
3
+ import json
4
+ import time
5
+ import urllib.request
6
+ from pathlib import Path
7
+
8
+ PROMPTS = [
9
+ 'Explain how a hash table works in Python, including collisions, resizing, and time complexity. Write a detailed tutorial of at least 800 words.',
10
+ 'Write a complete Python implementation of an LRU cache with type annotations, a detailed explanation, and examples. Include at least 800 words of explanation after the code.',
11
+ ]
12
+ for repetitions in (90, 210, 410):
13
+ PROMPTS.append(
14
+ 'This is background information for a technical documentation exercise. The system stores records and processes requests.\n' * repetitions
15
+ + 'Now write a detailed tutorial of at least 800 words explaining database indexes and their tradeoffs.')
16
+
17
+
18
+ def request(base_url, model, prompt, maximum):
19
+ body = {'model':model, 'messages':[{'role':'user','content':prompt}],
20
+ 'temperature':0, 'max_tokens':maximum, 'chat_template_kwargs':{'enable_thinking':False},
21
+ 'stream':True, 'stream_options':{'include_usage':True}, 'return_token_ids':True}
22
+ req = urllib.request.Request(base_url.rstrip('/')+'/chat/completions',
23
+ data=json.dumps(body).encode(), headers={'Content-Type':'application/json'})
24
+ start = time.perf_counter()
25
+ events, content, reasoning = [], [], []
26
+ usage = None
27
+ with urllib.request.urlopen(req, timeout=1800) as response:
28
+ for line in response:
29
+ if not line.startswith(b'data: '):
30
+ continue
31
+ payload = line[6:].strip()
32
+ if payload == b'[DONE]':
33
+ break
34
+ chunk = json.loads(payload)
35
+ if 'error' in chunk:
36
+ raise RuntimeError(chunk['error'])
37
+ if chunk.get('usage') is not None:
38
+ usage = chunk['usage']
39
+ for choice in chunk.get('choices',[]):
40
+ tokens = choice.get('token_ids') or []
41
+ if tokens:
42
+ events.append({'elapsed_seconds':time.perf_counter()-start,'token_ids':tokens})
43
+ delta = choice.get('delta',{})
44
+ content.append(delta.get('content') or '')
45
+ reasoning.append(delta.get('reasoning') or delta.get('reasoning_content') or '')
46
+ wall = time.perf_counter()-start
47
+ count = sum(len(event['token_ids']) for event in events)
48
+ assert usage and count == usage['completion_tokens'], (count,usage)
49
+ assert len(events) >= 2, 'At least two token-bearing SSE events are required.'
50
+ first_count = len(events[0]['token_ids'])
51
+ seconds = events[-1]['elapsed_seconds']-events[0]['elapsed_seconds']
52
+ return {'request':body,'usage':usage,'content':''.join(content),'reasoning':''.join(reasoning),
53
+ 'wall_seconds':wall,'time_to_first_token_seconds':events[0]['elapsed_seconds'],
54
+ 'decode_tokens':count-first_count,'decode_seconds':seconds,
55
+ 'decode_tokens_per_second':(count-first_count)/seconds,
56
+ 'end_to_end_tokens_per_second':count/wall,'first_event_token_count':first_count,
57
+ 'token_events':events}
58
+
59
+
60
+ def main():
61
+ parser = argparse.ArgumentParser()
62
+ parser.add_argument('--base-url',default='http://127.0.0.1:8000/v1')
63
+ parser.add_argument('--model',default='Naive-N0.5-Flash-NVFP4')
64
+ parser.add_argument('--tokens',type=int,default=256)
65
+ parser.add_argument('--cases',type=int,default=5)
66
+ parser.add_argument('--output',type=Path,required=True)
67
+ args = parser.parse_args()
68
+ request(args.base_url,args.model,'Explain why the sky is blue in several sentences.',32)
69
+ results=[]
70
+ for prompt in PROMPTS[:args.cases]:
71
+ result=request(args.base_url,args.model,prompt,args.tokens)
72
+ assert result['usage']['completion_tokens'] >= min(128,args.tokens)
73
+ results.append(result)
74
+ print(json.dumps({key:result[key] for key in ('usage','time_to_first_token_seconds',
75
+ 'decode_tokens_per_second','end_to_end_tokens_per_second')}),flush=True)
76
+ report={'engine':'vLLM','measurement':'Client wall time between token-bearing SSE events, using exact token IDs; first event excluded from decode rate',
77
+ 'single_active_request':True,'cases':results,'complete':len(results)==args.cases,
78
+ 'target_met':len(results)==args.cases and all(r['decode_tokens_per_second']>=50 for r in results)}
79
+ args.output.parent.mkdir(parents=True,exist_ok=True)
80
+ args.output.write_text(json.dumps(report,indent=2)+'\n')
81
+
82
+
83
+ if __name__ == '__main__':
84
+ main()
runtime/scripts/decode_kernels.py ADDED
@@ -0,0 +1,169 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Small fused decode kernels, preserving the reference BF16 rounding points."""
2
+ import torch
3
+ import triton
4
+ import triton.language as tl
5
+
6
+
7
+ @triton.jit
8
+ def _rmsnorm(x, weight, output, H: tl.constexpr, EPS: tl.constexpr, BLOCK: tl.constexpr):
9
+ row = tl.program_id(0)
10
+ cols = tl.arange(0, BLOCK)
11
+ data = tl.load(x + row * H + cols, cols < H, other=0).to(tl.float32)
12
+ scale = tl.rsqrt(tl.sum(data * data, 0) / H + EPS)
13
+ # LlamaRMSNorm rounds normalized activations before applying its weight.
14
+ normalized = (data * scale).to(tl.bfloat16).to(tl.float32)
15
+ w = tl.load(weight + cols, cols < H, other=0).to(tl.float32)
16
+ tl.store(output + row * H + cols, normalized * w, cols < H)
17
+
18
+
19
+ def rmsnorm(states, weight, eps):
20
+ assert states.is_contiguous() and states.dtype == torch.bfloat16
21
+ width = states.shape[-1]
22
+ result = torch.empty_like(states)
23
+ _rmsnorm[(states.numel() // width,)](states, weight, result, width, eps,
24
+ triton.next_power_of_2(width), num_warps=4, enable_fp_fusion=False)
25
+ return result
26
+
27
+
28
+ @triton.jit
29
+ def _rotary_pair(Q, K, COS, SIN, POS, OQ, OK, HQ: tl.constexpr, D: tl.constexpr,
30
+ R: tl.constexpr, BLOCK: tl.constexpr):
31
+ head = tl.program_id(0)
32
+ dims = tl.arange(0, BLOCK)
33
+ position = tl.load(POS)
34
+ source = tl.where(head < HQ, Q + head * D, K + (head - HQ) * D)
35
+ destination = tl.where(head < HQ, OQ + head * D, OK + (head - HQ) * D)
36
+ values = tl.load(source + dims, dims < D, other=0).to(tl.float32)
37
+ partner = (dims + R // 2) % R
38
+ other = tl.load(source + partner, dims < R, other=0).to(tl.float32)
39
+ other = tl.where(dims < R // 2, -other, other)
40
+ cos = tl.load(COS + position * R + dims, dims < R, other=1).to(tl.float32)
41
+ sin = tl.load(SIN + position * R + dims, dims < R, other=0).to(tl.float32)
42
+ rotated = (values * cos).to(tl.bfloat16).to(tl.float32) + (other * sin).to(tl.bfloat16).to(tl.float32)
43
+ tl.store(destination + dims, tl.where(dims < R, rotated, values), dims < D)
44
+
45
+
46
+ def rotary_pair(query, key, position, cos, sin):
47
+ dimension = query.shape[-1]
48
+ assert query.shape[0] == query.shape[2] == 1 and query.stride(1) == dimension
49
+ oq = torch.empty_like(query, memory_format=torch.contiguous_format)
50
+ if key is None:
51
+ key, ok, key_heads = query, oq, 0
52
+ else:
53
+ assert key.shape[-1] == dimension and key.stride(1) == dimension
54
+ ok, key_heads = torch.empty_like(key, memory_format=torch.contiguous_format), key.shape[1]
55
+ _rotary_pair[(query.shape[1] + key_heads,)](query, key, cos, sin, position, oq, ok,
56
+ query.shape[1], dimension, cos.shape[-1], triton.next_power_of_2(dimension),
57
+ num_warps=4, enable_fp_fusion=False)
58
+ return oq, ok if key_heads else None
59
+
60
+
61
+ @triton.jit
62
+ def _small_attention(Q, K, V, MASK, SINK, OUT,
63
+ L: tl.constexpr, D: tl.constexpr, DV: tl.constexpr, GROUP: tl.constexpr,
64
+ KS: tl.constexpr, VS: tl.constexpr, SCALE: tl.constexpr, VALUE_SCALE: tl.constexpr,
65
+ HAS_SINK: tl.constexpr, BN: tl.constexpr, BD: tl.constexpr, BV: tl.constexpr):
66
+ head = tl.program_id(0)
67
+ kv = head // GROUP
68
+ rows, dims = tl.arange(0, BN), tl.arange(0, BD)
69
+ q = tl.load(Q + head * D + dims, dims < D, other=0).to(tl.float32)
70
+ k = tl.load(K + kv * KS + rows[:, None] * D + dims[None, :],
71
+ (rows[:, None] < L) & (dims[None, :] < D), other=0).to(tl.float32)
72
+ logits = (tl.sum(k * q[None, :], 1).to(tl.bfloat16).to(tl.float32) * SCALE).to(tl.bfloat16).to(tl.float32)
73
+ valid = tl.load(MASK + rows, rows < L, other=False)
74
+ logits = tl.where(valid & (rows < L), logits, -float('inf'))
75
+ maximum = tl.max(logits, 0)
76
+ sink = -float('inf')
77
+ if HAS_SINK:
78
+ sink = tl.load(SINK + head).to(tl.float32)
79
+ maximum = tl.maximum(maximum, sink)
80
+ exps = tl.exp(logits - maximum)
81
+ denominator = tl.sum(exps, 0)
82
+ if HAS_SINK:
83
+ denominator += tl.exp(sink - maximum)
84
+ probabilities = (exps / denominator).to(tl.bfloat16).to(tl.float32)
85
+ vd = tl.arange(0, BV)
86
+ values = tl.load(V + kv * VS + rows[:, None] * DV + vd[None, :],
87
+ (rows[:, None] < L) & (vd[None, :] < DV), other=0).to(tl.float32)
88
+ values = (values * VALUE_SCALE).to(tl.bfloat16).to(tl.float32)
89
+ result = tl.sum(probabilities[:, None] * values, 0)
90
+ tl.store(OUT + head * DV + vd, result, vd < DV)
91
+
92
+
93
+ @triton.jit
94
+ def _attention_logits(Q, K, MASK, LOGITS, L: tl.constexpr, D: tl.constexpr,
95
+ GROUP: tl.constexpr, KS: tl.constexpr, SCALE: tl.constexpr,
96
+ BN: tl.constexpr, BD: tl.constexpr):
97
+ head, block = tl.program_id(0), tl.program_id(1)
98
+ rows, dims = block * BN + tl.arange(0, BN), tl.arange(0, BD)
99
+ q = tl.load(Q + head * D + dims, dims < D, other=0).to(tl.float32)
100
+ k = tl.load(K + (head // GROUP) * KS + rows[:, None] * D + dims[None, :],
101
+ (rows[:, None] < L) & (dims[None, :] < D), other=0).to(tl.float32)
102
+ logits = (tl.sum(k * q[None, :], 1).to(tl.bfloat16).to(tl.float32) * SCALE).to(tl.bfloat16)
103
+ valid = tl.load(MASK + rows, rows < L, other=False)
104
+ tl.store(LOGITS + head * L + rows, tl.where(valid, logits, -float('inf')), rows < L)
105
+
106
+
107
+ @triton.jit
108
+ def _attention_probabilities(LOGITS, SINK, PROBS, L: tl.constexpr, HAS_SINK: tl.constexpr, BN: tl.constexpr):
109
+ head = tl.program_id(0)
110
+ rows = tl.arange(0, BN)
111
+ logits = tl.load(LOGITS + head * L + rows, rows < L, other=-float('inf')).to(tl.float32)
112
+ maximum = tl.max(logits, 0)
113
+ sink = -float('inf')
114
+ if HAS_SINK:
115
+ sink = tl.load(SINK + head).to(tl.float32)
116
+ maximum = tl.maximum(maximum, sink)
117
+ exps = tl.exp(logits - maximum)
118
+ denominator = tl.sum(exps, 0)
119
+ if HAS_SINK:
120
+ denominator += tl.exp(sink - maximum)
121
+ tl.store(PROBS + head * L + rows, exps / denominator, rows < L)
122
+
123
+
124
+ @triton.jit
125
+ def _attention_values(PROBS, V, OUT, L: tl.constexpr, DV: tl.constexpr,
126
+ GROUP: tl.constexpr, VS: tl.constexpr, VALUE_SCALE: tl.constexpr,
127
+ BN: tl.constexpr, BV: tl.constexpr):
128
+ head = tl.program_id(0)
129
+ dims = tl.arange(0, BV)
130
+ result = tl.full((BV,), 0, tl.float32)
131
+ for block in range(tl.cdiv(L, BN)):
132
+ rows = block * BN + tl.arange(0, BN)
133
+ probabilities = tl.load(PROBS + head * L + rows, rows < L, other=0).to(tl.float32)
134
+ values = tl.load(V + (head // GROUP) * VS + rows[:, None] * DV + dims[None, :],
135
+ (rows[:, None] < L) & (dims[None, :] < DV), other=0).to(tl.float32)
136
+ values = (values * VALUE_SCALE).to(tl.bfloat16).to(tl.float32)
137
+ result += tl.sum(probabilities[:, None] * values, 0)
138
+ tl.store(OUT + head * DV + dims, result, dims < DV)
139
+
140
+
141
+ def decode_attention(query, keys, values, allowed, sink, value_scale):
142
+ heads, dimension = query.shape[1], query.shape[-1]
143
+ length, value_dimension = keys.shape[-2], values.shape[-1]
144
+ assert query.shape[0] == query.shape[2] == 1
145
+ assert keys.stride(-1) == values.stride(-1) == 1
146
+ assert keys.stride(-2) == dimension and values.stride(-2) == value_dimension
147
+ result = torch.empty((1, heads, 1, value_dimension), device=query.device, dtype=query.dtype)
148
+ sink_pointer = sink if sink is not None else result
149
+ group = heads // keys.shape[1]
150
+ scale = dimension ** -.5
151
+ value_scale = 1. if value_scale is None else value_scale
152
+ if length <= 128:
153
+ _small_attention[(heads,)](query, keys, values, allowed, sink_pointer, result,
154
+ length, dimension, value_dimension, group, keys.stride(1), values.stride(1),
155
+ scale, value_scale, sink is not None, triton.next_power_of_2(length),
156
+ triton.next_power_of_2(dimension), triton.next_power_of_2(value_dimension),
157
+ num_warps=8, enable_fp_fusion=False)
158
+ else:
159
+ logits = torch.empty((heads, length), dtype=torch.bfloat16, device=query.device)
160
+ probabilities = torch.empty_like(logits)
161
+ _attention_logits[(heads, triton.cdiv(length, 64))](query, keys, allowed, logits,
162
+ length, dimension, group, keys.stride(1), scale, 64, triton.next_power_of_2(dimension),
163
+ num_warps=4, enable_fp_fusion=False)
164
+ _attention_probabilities[(heads,)](logits, sink_pointer, probabilities, length,
165
+ sink is not None, triton.next_power_of_2(length), num_warps=4)
166
+ _attention_values[(heads,)](probabilities, values, result, length, value_dimension,
167
+ group, values.stride(1), value_scale, 64, triton.next_power_of_2(value_dimension),
168
+ num_warps=4, enable_fp_fusion=False)
169
+ return result
runtime/scripts/fused_experts.py ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Fused SM120 NVFP4 experts; original checkpoint weights and calibrated scales."""
2
+ import torch
3
+ from torch import nn
4
+ from flashinfer import nvfp4_block_scale_interleave
5
+ from flashinfer.cute_dsl.utils import convert_sf_to_mma_layout
6
+ from flashinfer.fused_moe import B12xMoEWrapper
7
+
8
+
9
+ class FusedNVFP4Experts(nn.Module):
10
+ def __init__(self, reader, prefix, num_experts, hidden, intermediate, device, top_k=8, max_tokens=256):
11
+ super().__init__()
12
+ self.num_experts, self.hidden, self.intermediate = num_experts, hidden, intermediate
13
+ w1 = torch.empty((num_experts, 2 * intermediate, hidden // 2), dtype=torch.uint8, device=device)
14
+ w2 = torch.empty((num_experts, hidden, intermediate // 2), dtype=torch.uint8, device=device)
15
+ sf1 = torch.empty((num_experts, 2 * intermediate, hidden // 16), dtype=torch.uint8, device=device)
16
+ sf2 = torch.empty((num_experts, hidden, intermediate // 16), dtype=torch.uint8, device=device)
17
+ globals1, globals2, inputs1, inputs2 = [], [], [], []
18
+ for expert in range(num_experts):
19
+ name = f'{prefix}{expert}.'
20
+ values = {p + '.' + k: reader.get_tensor(name + p + '.' + k)
21
+ for p in ('gate_proj', 'up_proj', 'down_proj')
22
+ for k in ('weight', 'weight_scale', 'weight_scale_2', 'input_scale')}
23
+ for kind in ('weight_scale_2', 'input_scale'):
24
+ assert torch.equal(values['gate_proj.' + kind], values['up_proj.' + kind])
25
+ # b12x uses [up, gate]; the reference linear uses [gate, up].
26
+ w1[expert, :intermediate].copy_(values['up_proj.weight'])
27
+ w1[expert, intermediate:].copy_(values['gate_proj.weight'])
28
+ w2[expert].copy_(values['down_proj.weight'])
29
+ logical = torch.cat([values['up_proj.weight_scale'], values['gate_proj.weight_scale']])
30
+ sf1[expert].copy_(nvfp4_block_scale_interleave(logical.view(torch.uint8)).reshape_as(sf1[expert]))
31
+ sf2[expert].copy_(nvfp4_block_scale_interleave(values['down_proj.weight_scale'].view(torch.uint8)).reshape_as(sf2[expert]))
32
+ globals1.append(values['gate_proj.weight_scale_2'].reshape(()))
33
+ globals2.append(values['down_proj.weight_scale_2'].reshape(()))
34
+ inputs1.append(values['gate_proj.input_scale'].reshape(()))
35
+ inputs2.append(values['down_proj.input_scale'].reshape(()))
36
+ for key, value in dict(w1=w1, w2=w2,
37
+ sf1=convert_sf_to_mma_layout(sf1.view(torch.float8_e4m3fn), m=2*intermediate, k=hidden, num_groups=num_experts),
38
+ sf2=convert_sf_to_mma_layout(sf2.view(torch.float8_e4m3fn), m=hidden, k=intermediate, num_groups=num_experts),
39
+ alpha1=torch.stack(globals1).float(),
40
+ alpha2=torch.stack(globals2).float() * torch.stack(inputs2).float(),
41
+ input1=torch.stack(inputs1).float(), input2=torch.stack(inputs2).float()).items():
42
+ self.register_buffer(key, value)
43
+ self.wrapper = B12xMoEWrapper(num_experts, top_k, hidden, intermediate,
44
+ use_cuda_graph=True, max_num_tokens=max_tokens, device=str(device), quant_mode='nvfp4')
45
+
46
+ def forward(self, hidden_states, top_k_index, top_k_weights):
47
+ with torch.cuda.device(hidden_states.device):
48
+ return self.wrapper.run(hidden_states, self.w1, self.sf1, self.w2, self.sf2,
49
+ top_k_index, top_k_weights, w1_alpha=self.alpha1, w2_alpha=self.alpha2,
50
+ fc2_input_scale=self.input2, input_global_scale=self.input1)
runtime/scripts/nvfp4_runtime.py ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Reference local runtime: upstream Naive attention and native Blackwell expert GEMMs.
2
+
3
+ Loads ModelOpt's standard packed checkpoint without changing the source architecture.
4
+ Expert dispatch is eager PyTorch; the matrix multiplications execute as NVFP4 W4A4.
5
+ """
6
+ import os
7
+ from pathlib import Path
8
+
9
+ ROOT = Path(__file__).resolve().parents[1]
10
+ os.environ.setdefault("HF_MODULES_CACHE", str(ROOT / "artifacts/hf-modules"))
11
+
12
+ import torch
13
+ import torch.nn as nn
14
+ import torch.nn.functional as F
15
+ from accelerate import init_empty_weights, dispatch_model
16
+ from accelerate.utils import set_module_tensor_to_device
17
+ from flashinfer import nvfp4_quantize, nvfp4_block_scale_interleave, mm_fp4, SfLayout
18
+ from safetensors import safe_open
19
+ from transformers import AutoConfig, AutoModelForCausalLM
20
+ from safe_device_transfer import install as install_safe_transfers
21
+
22
+ class NVFP4Linear(nn.Module):
23
+ def __init__(self, weight, weight_scale, weight_scale_2, input_scale, backend="cutlass"):
24
+ super().__init__()
25
+ assert weight.dtype == torch.uint8
26
+ assert weight_scale.dtype == torch.float8_e4m3fn
27
+ assert weight_scale.shape == (weight.shape[0], weight.shape[1] // 8)
28
+ assert torch.isfinite(weight_scale.float()).all()
29
+ assert weight_scale_2.numel() == input_scale.numel() == 1
30
+ assert weight_scale_2.item() > 0 and input_scale.item() > 0
31
+ self.register_buffer("weight", weight.contiguous())
32
+ self.register_buffer("scales", nvfp4_block_scale_interleave(weight_scale.contiguous().view(torch.uint8)))
33
+ self.register_buffer("input_scale_inv", input_scale.float().reciprocal().reshape(1))
34
+ self.register_buffer("alpha", (weight_scale_2.float() * input_scale.float()).reshape(1))
35
+ self.backend = backend
36
+
37
+ def forward(self, states):
38
+ shape = states.shape
39
+ states = states.reshape(-1, shape[-1]).contiguous()
40
+ # FlashInfer's quantizer calls .cuda() internally, so its current device
41
+ # must follow the layer's placement in a multi-GPU model.
42
+ with torch.cuda.device(states.device):
43
+ packed, scales = nvfp4_quantize(states, self.input_scale_inv,
44
+ sfLayout=SfLayout.layout_128x4, do_shuffle=False)
45
+ output = mm_fp4(packed, self.weight.T, scales, self.scales,
46
+ self.alpha, out_dtype=states.dtype, backend=self.backend)
47
+ return output.reshape(*shape[:-1], self.weight.shape[0])
48
+
49
+
50
+ class NVFP4Expert(nn.Module):
51
+ def __init__(self, tensors, backend):
52
+ super().__init__()
53
+ for suffix in ("weight_scale_2", "input_scale"):
54
+ if not torch.equal(tensors[f"gate_proj.{suffix}"], tensors[f"up_proj.{suffix}"]):
55
+ raise ValueError(f"Exported gate/up {suffix} must match before fusion")
56
+ self.gate_up = NVFP4Linear(
57
+ torch.cat([tensors["gate_proj.weight"], tensors["up_proj.weight"]]),
58
+ torch.cat([tensors["gate_proj.weight_scale"], tensors["up_proj.weight_scale"]]),
59
+ tensors["gate_proj.weight_scale_2"], tensors["gate_proj.input_scale"], backend)
60
+ self.down = NVFP4Linear(tensors["down_proj.weight"], tensors["down_proj.weight_scale"],
61
+ tensors["down_proj.weight_scale_2"], tensors["down_proj.input_scale"], backend)
62
+
63
+ def forward(self, states):
64
+ gate, up = self.gate_up(states).chunk(2, dim=-1)
65
+ return self.down(F.silu(gate) * up)
66
+
67
+
68
+ class NVFP4Experts(nn.Module):
69
+ def __init__(self, experts):
70
+ super().__init__()
71
+ self.experts = nn.ModuleList(experts)
72
+
73
+ def forward(self, hidden_states, top_k_index, top_k_weights):
74
+ output = torch.zeros_like(hidden_states)
75
+ for expert_id in top_k_index.unique().tolist():
76
+ tokens, slots = torch.where(top_k_index == expert_id)
77
+ current = self.experts[expert_id](hidden_states[tokens])
78
+ weighted = current * top_k_weights[tokens, slots, None].to(current.dtype)
79
+ output.index_add_(0, tokens, weighted)
80
+ return output
81
+
82
+
83
+ def load_model(checkpoint, devices=None, backend="cutlass"):
84
+ install_safe_transfers()
85
+ os.environ.setdefault("HF_MODULES_CACHE", str(ROOT / "artifacts/hf-modules"))
86
+ checkpoint = Path(checkpoint).resolve()
87
+ devices = list(range(torch.cuda.device_count())) if devices is None else devices
88
+ if not devices:
89
+ raise ValueError("At least one Blackwell GPU is required")
90
+ for device in devices:
91
+ assert torch.cuda.get_device_capability(device)[0] >= 10
92
+ config = AutoConfig.from_pretrained(checkpoint, trust_remote_code=True)
93
+ if config.model_type != "naive_n05_flash":
94
+ raise ValueError(f"Unexpected model type: {config.model_type}")
95
+ if hasattr(config, "quantization_config"):
96
+ del config.quantization_config
97
+ config.use_cache = True
98
+ with init_empty_weights():
99
+ model = AutoModelForCausalLM.from_config(config, trust_remote_code=True, dtype=torch.bfloat16)
100
+ device_map = {"model.embed_tokens": devices[0], "model.norm": devices[-1], "lm_head": devices[-1]}
101
+ for i in range(config.num_hidden_layers):
102
+ device_map[f"model.layers.{i}"] = devices[min(i * len(devices) // config.num_hidden_layers, len(devices) - 1)]
103
+ import json
104
+ index = json.loads((checkpoint / "model.safetensors.index.json").read_text())["weight_map"]
105
+ loaded = set()
106
+ # Each ModelOpt layer export is a self-contained shard. Expert tensors are
107
+ # read by exact name so a missing scale fails instead of silently initializing.
108
+ for layer_id, layer in enumerate(model.model.layers):
109
+ prefix = f"model.layers.{layer_id}."
110
+ gpu = device_map[prefix[:-1]]
111
+ names = [name for name in index if name.startswith(prefix)]
112
+ shards = {index[name] for name in names}
113
+ if len(shards) != 1:
114
+ raise ValueError("This loader requires one self-contained shard per decoder layer")
115
+ with torch.cuda.device(gpu), safe_open(checkpoint / next(iter(shards)), framework="pt", device=gpu) as reader:
116
+ if config.moe_layer_freq[layer_id]:
117
+ if os.environ.get('NAIVE_EXPERT_BACKEND', 'reference') == 'fused':
118
+ from fused_experts import FusedNVFP4Experts
119
+ layer.mlp.experts = FusedNVFP4Experts(reader, f'{prefix}mlp.experts.',
120
+ config.n_routed_experts, config.hidden_size, config.moe_intermediate_size,
121
+ torch.device(f'cuda:{gpu}'), top_k=config.num_experts_per_tok,
122
+ max_tokens=int(os.environ.get('PREFILL_CHUNK', '256')))
123
+ loaded.update(name for name in names if name.startswith(f'{prefix}mlp.experts.'))
124
+ else:
125
+ experts = []
126
+ for expert_id in range(config.n_routed_experts):
127
+ ep = f"{prefix}mlp.experts.{expert_id}."
128
+ tensors = {projection + "." + kind: reader.get_tensor(ep + projection + "." + kind)
129
+ for projection in ("gate_proj", "up_proj", "down_proj")
130
+ for kind in ("weight", "weight_scale", "weight_scale_2", "input_scale")}
131
+ experts.append(NVFP4Expert(tensors, backend))
132
+ loaded.update(ep + name for name in tensors)
133
+ layer.mlp.experts = NVFP4Experts(experts)
134
+ for name in names:
135
+ if name in loaded:
136
+ continue
137
+ tensor = reader.get_tensor(name)
138
+ set_module_tensor_to_device(model, name, gpu, value=tensor, dtype=tensor.dtype)
139
+ loaded.add(name)
140
+ print(f"Loaded layer {layer_id + 1}/{config.num_hidden_layers} on cuda:{gpu}", flush=True)
141
+ remaining = set(index) - loaded
142
+ for name in sorted(remaining):
143
+ module_name = name.rsplit(".", 1)[0]
144
+ if module_name not in device_map:
145
+ raise ValueError(f"Unrecognized tensor outside decoder layers: {name}")
146
+ gpu = device_map[module_name]
147
+ with safe_open(checkpoint / index[name], framework="pt", device=gpu) as reader:
148
+ tensor = reader.get_tensor(name)
149
+ set_module_tensor_to_device(model, name, gpu, value=tensor, dtype=tensor.dtype)
150
+ loaded.add(name)
151
+ assert loaded == set(index)
152
+ assert not any(p.is_meta for p in model.parameters())
153
+ model = dispatch_model(model, device_map=device_map, force_hooks=True)
154
+ return model.eval().requires_grad_(False)
runtime/scripts/preflight.py ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Check the tested four-GPU environment and shard headers without loading weights."""
2
+ import importlib.metadata
3
+ import json
4
+ import os
5
+ import struct
6
+ from pathlib import Path
7
+
8
+ import torch
9
+
10
+ from flashinfer.fused_moe import B12xMoEWrapper
11
+ from transformers import AutoConfig, AutoTokenizer
12
+
13
+
14
+ def main():
15
+ versions = {name: importlib.metadata.version(name) for name in (
16
+ 'vllm', 'torch', 'transformers', 'accelerate', 'tokenizers', 'huggingface-hub',
17
+ 'safetensors', 'flashinfer-python', 'nvidia-cutlass-dsl', 'triton')}
18
+ expected = {'vllm': '0.28.0', 'torch': '2.13.0+cu130', 'transformers': '5.17.0', 'accelerate': '1.15.0',
19
+ 'tokenizers': '0.23.2', 'huggingface-hub': '1.33.0', 'safetensors': '0.8.0',
20
+ 'flashinfer-python': '0.7.0', 'nvidia-cutlass-dsl': '4.6.2', 'triton': '3.7.1'}
21
+ assert versions == expected, {'expected': expected, 'actual': versions}
22
+ assert torch.cuda.device_count() == 4, 'This deployment recipe requires four visible GPUs.'
23
+ gpus = []
24
+ for index in range(4):
25
+ props = torch.cuda.get_device_properties(index)
26
+ assert (props.major, props.minor) == (12, 0), 'The fused B12x recipe targets SM120 Blackwell.'
27
+ assert props.total_memory >= 90 * 1024**3, 'The tested configuration uses four 96 GB GPUs.'
28
+ gpus.append({'index': index, 'name': props.name, 'memory_bytes': props.total_memory})
29
+ cache = Path('/cache')
30
+ cache.mkdir(parents=True, exist_ok=True)
31
+ probe = cache / '.write-check'
32
+ probe.write_text('ok\n')
33
+ probe.unlink()
34
+ checkpoint = Path(os.environ['MODEL_PATH'])
35
+ config = AutoConfig.from_pretrained(checkpoint, trust_remote_code=True)
36
+ assert config.model_type == 'naive_n05_flash'
37
+ tokenizer = AutoTokenizer.from_pretrained(checkpoint, trust_remote_code=True)
38
+ assert tokenizer.encode('Hello')
39
+ weight_map = json.loads((checkpoint / 'model.safetensors.index.json').read_text())['weight_map']
40
+ shards = sorted(set(weight_map.values()))
41
+ assert len(shards) == 49
42
+ discovered = {}
43
+ for name in shards:
44
+ shard = checkpoint / name
45
+ with shard.open('rb') as stream:
46
+ header_size = struct.unpack('<Q', stream.read(8))[0]
47
+ assert header_size < 100_000_000
48
+ header = json.loads(stream.read(header_size))
49
+ payload_end = 0
50
+ for key, metadata in header.items():
51
+ if key == '__metadata__':
52
+ continue
53
+ assert key not in discovered
54
+ discovered[key] = name
55
+ payload_end = max(payload_end, metadata['data_offsets'][1])
56
+ assert shard.stat().st_size == 8 + header_size + payload_end, name
57
+ assert discovered == weight_map, 'Shard headers and weight index differ.'
58
+ print(json.dumps({'passed': True, 'versions': versions, 'gpus': gpus,
59
+ 'shards': len(shards), 'tensors': len(discovered)}, indent=2))
60
+
61
+
62
+ if __name__ == '__main__':
63
+ main()
runtime/scripts/safe_device_transfer.py ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Stage Accelerate's cross-GPU copies through host RAM on this workstation.
2
+
3
+ Direct CUDA peer copies report success but fail equality checks here. The existing
4
+ model-manager profiles also disable NCCL P2P. This adapter changes no driver or
5
+ global machine settings; it affects only this Python process.
6
+ """
7
+ import torch
8
+
9
+
10
+ def install():
11
+ import accelerate.hooks
12
+ import accelerate.utils
13
+ import accelerate.utils.operations as operations
14
+ if getattr(operations.send_to_device, "_host_staged", False):
15
+ return
16
+ original = operations.send_to_device
17
+
18
+ def send_to_device(tensor, device, non_blocking=False, skip_keys=None):
19
+ if isinstance(tensor, torch.Tensor) and tensor.is_cuda:
20
+ destination = torch.device(f"cuda:{device}" if isinstance(device, int) else device)
21
+ if destination.type == "cuda":
22
+ index = torch.cuda.current_device() if destination.index is None else destination.index
23
+ if tensor.device.index != index:
24
+ return tensor.to("cpu", non_blocking=False).to(destination, non_blocking=False)
25
+ return original(tensor, device, non_blocking=non_blocking, skip_keys=skip_keys)
26
+
27
+ send_to_device._host_staged = True
28
+ operations.send_to_device = send_to_device
29
+ accelerate.hooks.send_to_device = send_to_device
30
+ accelerate.utils.send_to_device = send_to_device
runtime/scripts/validate_api.py ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Record actual full-model answers, tool calls, longer context and throughput."""
2
+ import json
3
+ import os
4
+ import re
5
+ import subprocess
6
+ import time
7
+ import urllib.request
8
+ from pathlib import Path
9
+
10
+ ROOT = Path(__file__).resolve().parents[2]
11
+ BASE = "http://127.0.0.1:8000"
12
+ MODEL = "Naive-N0.5-Flash-NVFP4"
13
+ REPORT_PATH = Path(os.environ.get('NAIVE_VALIDATION_FILE', 'native-vllm-api-validation.json'))
14
+
15
+
16
+ def complete(prompt, **extra):
17
+ body = {"model": MODEL, "messages": [{"role": "user", "content": prompt}],
18
+ "temperature": 0, "max_tokens": 128,
19
+ "chat_template_kwargs": {"enable_thinking": False}, **extra}
20
+ request = urllib.request.Request(BASE + "/v1/chat/completions",
21
+ data=json.dumps(body).encode(), headers={"Content-Type": "application/json"})
22
+ print(f'Request: {prompt[-110:]}', flush=True)
23
+ start = time.monotonic()
24
+ with urllib.request.urlopen(request, timeout=1200) as response:
25
+ result = json.load(response)
26
+ elapsed = time.monotonic() - start
27
+ result["elapsed_seconds"] = elapsed
28
+ result["completion_tokens_per_second_including_prefill"] = result["usage"]["completion_tokens"] / elapsed
29
+ print(f'Completed in {elapsed:.1f}s: {result["usage"]}; {result["choices"][0]["message"]}', flush=True)
30
+ return result
31
+
32
+
33
+ def main():
34
+ results = {}
35
+ try:
36
+ with urllib.request.urlopen(BASE + "/health") as response:
37
+ assert response.status == 200
38
+ with urllib.request.urlopen(BASE + "/v1/models") as response:
39
+ assert MODEL in {entry["id"] for entry in json.load(response)["data"]}
40
+ results["arithmetic"] = complete("What is 2 + 2? Reply with only the number.", max_tokens=32)
41
+ assert re.search(r"\b4\b", results["arithmetic"]["choices"][0]["message"].get("content") or "")
42
+ results["geography"] = complete("What is the capital of France? Reply with only its name.", max_tokens=32)
43
+ assert "paris" in (results["geography"]["choices"][0]["message"].get("content") or "").lower()
44
+ results["coding"] = complete("Write a Python function named add that returns the sum of two arguments. Return only the code.", max_tokens=128)
45
+ assert "def add" in (results["coding"]["choices"][0]["message"].get("content") or "")
46
+ tools = [{"type": "function", "function": {"name": "get_weather", "description": "Get weather for a city",
47
+ "parameters": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]}}}]
48
+ results["tools"] = complete("Call the get_weather tool for Warsaw. Do not answer from memory.", tools=tools, max_tokens=192)
49
+ calls = results["tools"]["choices"][0]["message"].get("tool_calls", [])
50
+ assert calls and calls[0]["function"]["name"] == "get_weather"
51
+ assert "warsaw" in calls[0]["function"]["arguments"].lower()
52
+ results["reasoning"] = complete("Calculate 6 times 7. Think briefly, then give the answer.",
53
+ chat_template_kwargs={"enable_thinking": True}, reasoning_effort="low", max_tokens=256)
54
+ reasoning_message = results["reasoning"]["choices"][0]["message"]
55
+ assert reasoning_message.get("reasoning")
56
+ assert re.search(r"\b42\b", reasoning_message.get("content") or "")
57
+ filler = "The following paragraph is background material about testing a language model. It contains no instructions.\n"
58
+ results["longer_context"] = complete(filler * 220 + "\nFinal question: what is 2 + 2? Answer only the number.", max_tokens=32)
59
+ assert results["longer_context"]["usage"]["prompt_tokens"] > 2048
60
+ assert re.search(r"\b4\b", results["longer_context"]["choices"][0]["message"].get("content") or "")
61
+ results["gpu_memory"] = subprocess.check_output(["nvidia-smi", "--query-gpu=index,memory.used,memory.total", "--format=csv"], text=True)
62
+ report = {"passed": True, "engine": "vLLM 0.28.0", "model": MODEL, "checks": results,
63
+ "scope": "Basic generation, coding, tool use and sparse-context smoke checks; not an accuracy benchmark"}
64
+ except Exception as error:
65
+ report = {"passed": False, "model": MODEL, "error": repr(error), "checks": results}
66
+ REPORT_PATH.write_text(json.dumps(report, indent=2) + "\n")
67
+ raise
68
+ REPORT_PATH.write_text(json.dumps(report, indent=2) + "\n")
69
+ print("FULL_MODEL_API_VALIDATION_PASSED", flush=True)
70
+
71
+
72
+ if __name__ == "__main__":
73
+ main()
runtime/sitecustomize.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ """Isolate FlashInfer source kernels before vLLM worker imports execute."""
2
+ import os
3
+ import sys
4
+
5
+ if os.environ.get('NAIVE_FLASHINFER_SOURCE_ONLY') == '1':
6
+ sys.modules['flashinfer_jit_cache'] = None
7
+ sys.modules['flashinfer_cubin'] = None
runtime/vllm_naive/__init__.py ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Native model registration for vLLM's V1 engine."""
2
+
3
+
4
+ def register():
5
+ import sys
6
+ # FlashInfer 0.7 kernels must not use the base image's 0.6 prebuilt binaries.
7
+ sys.modules['flashinfer_jit_cache'] = None
8
+ sys.modules['flashinfer_cubin'] = None
9
+ from vllm import ModelRegistry
10
+ ModelRegistry.register_model('NaiveN05FlashForCausalLM',
11
+ 'vllm_naive.model:NaiveN05FlashForCausalLM')
runtime/vllm_naive/attention.py ADDED
@@ -0,0 +1,242 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Naive GQA sparse attention using vLLM-managed paged K/V/indexer storage.
2
+
3
+ Prefill and multiple active requests use eager operations; single-token decode
4
+ supports vLLM CUDA graphs. Both retain upstream indexer FP8 rounding and stable
5
+ sparse-selection ties.
6
+ """
7
+ from dataclasses import dataclass
8
+
9
+ import torch
10
+ from torch import nn
11
+ from vllm.distributed import tensor_model_parallel_all_reduce
12
+ from vllm.forward_context import get_forward_context
13
+ from vllm.model_executor.layers.attention_layer_base import AttentionLayerBase
14
+ from vllm.v1.attention.backend import AttentionBackend, AttentionMetadataBuilder, AttentionCGSupport
15
+ from vllm.v1.kv_cache_interface import FullAttentionSpec
16
+ from decode_kernels import decode_attention, rotary_pair
17
+
18
+
19
+ @dataclass
20
+ class NaiveMetadata:
21
+ starts: list[int]
22
+ lengths: list[int]
23
+ block_table: torch.Tensor
24
+ slot_mapping: torch.Tensor
25
+ num_actual_tokens: int
26
+ single_decode: bool
27
+
28
+
29
+ class NaiveMetadataBuilder(AttentionMetadataBuilder):
30
+ _cudagraph_support = AttentionCGSupport.UNIFORM_SINGLE_TOKEN_DECODE
31
+
32
+ def __init__(self, kv_cache_spec, layer_names, vllm_config, device):
33
+ super().__init__(kv_cache_spec, layer_names, vllm_config, device)
34
+
35
+ def build(self, common_prefix_len, common_attn_metadata, fast_build=False):
36
+ c = common_attn_metadata
37
+ single_decode = c.max_query_len == 1 and c.num_actual_tokens == 1
38
+ lengths = [] if single_decode else c.seq_lens.cpu().tolist()
39
+ return NaiveMetadata(c.query_start_loc_cpu.tolist(), lengths,
40
+ c.block_table_tensor, c.slot_mapping, c.num_actual_tokens, single_decode)
41
+
42
+
43
+ class NaiveBackend(AttentionBackend):
44
+ @staticmethod
45
+ def get_name():
46
+ return 'NAIVE_GQA_DSA'
47
+
48
+ @staticmethod
49
+ def get_impl_cls():
50
+ return NaivePagedAttention
51
+
52
+ @staticmethod
53
+ def get_builder_cls():
54
+ return NaiveMetadataBuilder
55
+
56
+ @staticmethod
57
+ def get_kv_cache_shape(num_blocks, block_size, num_kv_heads, head_size, cache_dtype_str='auto'):
58
+ return (num_blocks, 2, block_size, num_kv_heads, head_size)
59
+
60
+ @staticmethod
61
+ def get_kv_cache_stride_order(include_num_layers_dimension=False):
62
+ return tuple(range(6 if include_num_layers_dimension else 5))
63
+
64
+
65
+ def round_fp8(states):
66
+ values = states.float()
67
+ scale = values.abs().amax(-1, keepdim=True).clamp_min(1e-4) / 448.
68
+ return (values / scale).clamp(-448, 448).to(torch.float8_e4m3fn).float() * scale
69
+
70
+
71
+ class NaivePagedAttention(nn.Module, AttentionLayerBase):
72
+ supports_dcp = False
73
+
74
+ def __init__(self, source, name, vllm_config, tp_size, tp_rank):
75
+ super().__init__()
76
+ self.config = source.config
77
+ self.name = name
78
+ self.tp_size = tp_size
79
+ self.is_swa = source.is_swa
80
+ self.heads = source.heads // tp_size
81
+ self.kv_heads = source.kv_heads // tp_size
82
+ assert source.heads % tp_size == source.kv_heads % tp_size == 0
83
+ self.head_dim, self.v_dim = source.head_dim, source.v_dim
84
+ self.num_heads = self.heads
85
+ self.cache_heads = max(self.config.num_key_value_heads, self.config.swa_num_key_value_heads) // tp_size
86
+ self.cache_width = max(self.config.head_dim, self.config.swa_head_dim) + self.config.index_head_dim
87
+ self.block_size = vllm_config.cache_config.block_size
88
+ self.max_context = vllm_config.model_config.max_model_len
89
+ for key in ('q_proj', 'k_proj', 'v_proj', 'o_proj', 'rotary_emb', 'indexer'):
90
+ setattr(self, key, getattr(source, key))
91
+ self.attention_sink_bias = source.attention_sink_bias
92
+ for key in ('q_proj', 'k_proj', 'v_proj'):
93
+ module = getattr(self, key)
94
+ module.out_features //= tp_size
95
+ module.weight = nn.Parameter(torch.empty(module.out_features, module.in_features, device='meta', dtype=torch.bfloat16))
96
+ self.o_proj.in_features //= tp_size
97
+ self.o_proj.weight = nn.Parameter(torch.empty(self.o_proj.out_features, self.o_proj.in_features, device='meta', dtype=torch.bfloat16))
98
+ if self.attention_sink_bias is not None:
99
+ self.attention_sink_bias = nn.Parameter(torch.empty(self.heads, device='meta', dtype=torch.bfloat16), requires_grad=False)
100
+ self.kv_cache = torch.empty(0)
101
+ context = vllm_config.compilation_config.static_forward_context
102
+ assert name not in context
103
+ context[name] = self
104
+
105
+ def get_attn_backend(self):
106
+ return NaiveBackend
107
+
108
+ def get_kv_cache_spec(self, vllm_config):
109
+ self.block_size = vllm_config.cache_config.block_size
110
+ # Indexer values after FP8 rounding carry FP32 scales. Storing all cache
111
+ # elements as FP32 preserves them exactly; K/V are cast back to BF16.
112
+ return FullAttentionSpec(block_size=self.block_size, num_kv_heads=self.cache_heads,
113
+ head_size=self.cache_width, dtype=torch.float32)
114
+
115
+ def initialize_decode(self):
116
+ """Share packed projection storage and precompute fixed rotary tables."""
117
+ projections = (self.q_proj, self.k_proj, self.v_proj)
118
+ assert all(projection.bias is None for projection in projections)
119
+ sizes = [projection.weight.shape[0] for projection in projections]
120
+ packed = torch.cat([projection.weight for projection in projections])
121
+ self.register_buffer('qkv_weight', packed, persistent=False)
122
+ # Retain the original projection interfaces for prefill without keeping
123
+ # a second copy of the projection weights on the GPU.
124
+ for projection, weight in zip(projections, packed.split(sizes)):
125
+ projection.weight = nn.Parameter(weight, requires_grad=False)
126
+ self.qkv_sizes = sizes
127
+ positions = torch.arange(self.max_context, device=packed.device).unsqueeze(0)
128
+ cos, sin = self.rotary_emb(packed.new_empty((1, 1, 1)), positions)
129
+ self.register_buffer('decode_cos', cos.contiguous(), persistent=False)
130
+ self.register_buffer('decode_sin', sin.contiguous(), persistent=False)
131
+
132
+ def forward(self, states, positions):
133
+ from transformers.models.gpt_neox.modeling_gpt_neox import apply_rotary_pos_emb
134
+ length = states.shape[0]
135
+ if length == 1:
136
+ query, key, value = torch.nn.functional.linear(states, self.qkv_weight).split(self.qkv_sizes, dim=-1)
137
+ else:
138
+ query, key, value = self.q_proj(states), self.k_proj(states), self.v_proj(states)
139
+ query = query.view(1, length, self.heads, self.head_dim).transpose(1, 2)
140
+ key = key.view(1, length, self.kv_heads, self.head_dim).transpose(1, 2)
141
+ value = value.view(length, self.kv_heads, self.v_dim)
142
+ if length == 1:
143
+ query, key = rotary_pair(query, key, positions, self.decode_cos, self.decode_sin)
144
+ else:
145
+ embeddings = self.rotary_emb(states.unsqueeze(0), positions.unsqueeze(0))
146
+ query, key = apply_rotary_pos_emb(query, key, *embeddings)
147
+ index_query = index_key = index_weights = None
148
+ if self.indexer is not None:
149
+ c = self.config
150
+ index_query = self.indexer.wq(states).view(1, length, c.index_n_heads, c.index_head_dim).transpose(1, 2)
151
+ index_key = self.indexer.k_norm(self.indexer.wk(states)).view(1, 1, length, c.index_head_dim)
152
+ if length == 1:
153
+ index_query, _ = rotary_pair(index_query, None, positions, self.decode_cos, self.decode_sin)
154
+ index_key, _ = rotary_pair(index_key, None, positions, self.decode_cos, self.decode_sin)
155
+ else:
156
+ index_query, index_key = apply_rotary_pos_emb(index_query, index_key, *embeddings)
157
+ if c.indexer_activation_dtype == 'fp8_e4m3':
158
+ index_query, index_key = round_fp8(index_query), round_fp8(index_key)
159
+ index_weights = self.indexer.weights_proj(states) * c.index_n_heads**-.5
160
+ metadata = get_forward_context().attn_metadata
161
+ metadata = metadata.get(self.name) if metadata else None
162
+ if metadata is None:
163
+ # vLLM's memory profiling pass has no cache metadata.
164
+ return self.o_proj(torch.zeros(length, self.heads*self.v_dim, dtype=states.dtype, device=states.device))
165
+ n = metadata.num_actual_tokens
166
+ # vLLM uses negative slots for graph-capture dummy tokens. Page zero is
167
+ # its null block; real scheduled tokens always have allocated slots.
168
+ slots = metadata.slot_mapping[:n].long().clamp_min(0)
169
+ blocks, offsets = slots // self.block_size, slots % self.block_size
170
+ self.kv_cache[blocks, 0, offsets, :self.kv_heads, :self.head_dim] = key[0].transpose(0, 1)[:n].float()
171
+ self.kv_cache[blocks, 1, offsets, :self.kv_heads, :self.v_dim] = value[:n].float()
172
+ if index_key is not None:
173
+ self.kv_cache[blocks, 0, offsets, 0, -self.config.index_head_dim:] = index_key[0, 0, :n].float()
174
+ if metadata.single_decode:
175
+ return self.decode(query, positions, index_query, index_weights, metadata)
176
+ output = torch.zeros(length, self.heads*self.v_dim, device=states.device, dtype=states.dtype)
177
+ for request, (start, end) in enumerate(zip(metadata.starts, metadata.starts[1:])):
178
+ if start == end:
179
+ continue
180
+ total = metadata.lengths[request]
181
+ first = max(0, total - (end-start) - self.config.sliding_window + 1) if self.is_swa else 0
182
+ key_positions = torch.arange(first, total, device=states.device)
183
+ page = metadata.block_table[request, key_positions // self.block_size].long()
184
+ offset = key_positions % self.block_size
185
+ keys = self.kv_cache[page, 0, offset, :self.kv_heads, :self.head_dim].to(states.dtype).transpose(0, 1)
186
+ values = self.kv_cache[page, 1, offset, :self.kv_heads, :self.v_dim].to(states.dtype).transpose(0, 1)
187
+ allowed = positions[start:end, None] >= key_positions[None]
188
+ if self.is_swa:
189
+ allowed = allowed & ((positions[start:end, None] - key_positions[None]) < self.config.sliding_window)
190
+ else:
191
+ cached_index = self.kv_cache[page, 0, offset, 0, -self.config.index_head_dim:]
192
+ scores = (index_query[0, :, start:end].float() @ cached_index.T).relu()
193
+ scores = (scores * index_weights[start:end].T[:, :, None].float()).sum(0)
194
+ scores = scores.masked_fill(~allowed, -torch.inf)
195
+ selected = scores.argsort(dim=-1, descending=True, stable=True)[:, :self.config.index_top_k]
196
+ allowed = allowed & torch.zeros_like(scores, dtype=torch.bool).scatter(-1, selected, True)
197
+ keys = keys.repeat_interleave(self.heads//self.kv_heads, dim=0)
198
+ values = values.repeat_interleave(self.heads//self.kv_heads, dim=0)
199
+ if self.config.attention_value_scale is not None:
200
+ values = values * self.config.attention_value_scale
201
+ logits = (query[0, :, start:end] @ keys.transpose(-1, -2)) * self.head_dim**-.5
202
+ logits = logits.masked_fill(~allowed[None], -torch.inf)
203
+ if self.attention_sink_bias is not None:
204
+ sinks = self.attention_sink_bias[:, None, None].expand(-1, end-start, 1)
205
+ logits = torch.cat((logits, sinks), -1)
206
+ probabilities = logits.float().softmax(-1).nan_to_num(0)[..., :len(key_positions)].to(values.dtype)
207
+ output[start:end] = (probabilities @ values).transpose(0, 1).reshape(end-start, -1)
208
+ output = self.o_proj(output)
209
+ return tensor_model_parallel_all_reduce(output) if self.tp_size > 1 else output
210
+
211
+ def decode(self, query, positions, index_query, index_weights, metadata):
212
+ """Fixed-shape single-token path for vLLM's full decode CUDA graphs."""
213
+ if self.is_swa:
214
+ key_positions = positions[0] - self.config.sliding_window + 1 + torch.arange(
215
+ self.config.sliding_window, device=query.device)
216
+ valid = key_positions >= 0
217
+ key_positions = key_positions.clamp_min(0)
218
+ else:
219
+ key_positions = torch.arange(self.max_context, device=query.device)
220
+ valid = key_positions <= positions[0]
221
+ pages = metadata.block_table[0, key_positions // self.block_size].long()
222
+ pages = torch.where(valid, pages, 0)
223
+ cached_index = self.kv_cache[pages, 0, key_positions % self.block_size,
224
+ 0, -self.config.index_head_dim:]
225
+ scores = (index_query[0].float() @ cached_index.T).relu()
226
+ scores = (scores * index_weights.T[:, :, None].float()).sum(0)
227
+ scores = scores.masked_fill(~valid[None], -torch.inf)
228
+ selected = scores.argsort(dim=-1, descending=True, stable=True)[0, :self.config.index_top_k]
229
+ key_positions = selected.sort().values
230
+ valid = key_positions <= positions[0]
231
+ pages = metadata.block_table[0, key_positions // self.block_size].long()
232
+ pages = torch.where(valid, pages, 0)
233
+ offsets = key_positions % self.block_size
234
+ keys = self.kv_cache[pages, 0, offsets, :self.kv_heads, :self.head_dim].to(query.dtype).transpose(0, 1).contiguous()
235
+ values = self.kv_cache[pages, 1, offsets, :self.kv_heads, :self.v_dim].to(query.dtype).transpose(0, 1).contiguous()
236
+ # Unallocated/padding entries may contain arbitrary bits in the cache.
237
+ keys = keys.masked_fill(~valid[None, :, None], 0)
238
+ values = values.masked_fill(~valid[None, :, None], 0)
239
+ output = decode_attention(query, keys[None], values[None], valid,
240
+ self.attention_sink_bias, self.config.attention_value_scale)
241
+ output = self.o_proj(output.transpose(1, 2).reshape(1, -1))
242
+ return tensor_model_parallel_all_reduce(output) if self.tp_size > 1 else output
runtime/vllm_naive/model.py ADDED
@@ -0,0 +1,189 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Naive-N0.5-Flash NVFP4 model executed by the native vLLM V1 model runner."""
2
+ import copy
3
+ import json
4
+ from pathlib import Path
5
+
6
+ import torch
7
+ from torch import nn
8
+ from accelerate import init_empty_weights
9
+ from accelerate.utils import set_module_tensor_to_device
10
+ from safetensors import safe_open
11
+ from transformers import AutoModelForCausalLM
12
+ from vllm.distributed import get_tensor_model_parallel_rank, get_tensor_model_parallel_world_size, tensor_model_parallel_all_reduce
13
+ from vllm_naive.attention import NaivePagedAttention
14
+
15
+ from fused_experts import FusedNVFP4Experts
16
+ from nvfp4_runtime import NVFP4Expert, NVFP4Experts
17
+ from decode_kernels import rmsnorm
18
+ from flashinfer.fused_moe.cute_dsl.blackwell_sm12x import moe_dispatch
19
+
20
+ # FlashInfer 0.7's direct-micro path returned all-zero output for this model's
21
+ # calibrated NVFP4 scales at TP4 (intermediate=512, one token). Keep the regular
22
+ # MMA micro/static/dynamic paths. Covered by validate_expert_sharding.py.
23
+ moe_dispatch._DIRECT_MICRO_MAX_N = 0
24
+
25
+
26
+ class ShardedReader:
27
+ def __init__(self, reader, rank, size, device):
28
+ self.reader, self.rank, self.size, self.device = reader, rank, size, device
29
+
30
+ def get_tensor(self, name):
31
+ tensor = self.reader.get_tensor(name)
32
+ if name.endswith(('.weight', '.weight_scale')):
33
+ dim = 1 if '.down_proj.' in name else 0
34
+ assert tensor.shape[dim] % self.size == 0
35
+ tensor = tensor.chunk(self.size, dim=dim)[self.rank].contiguous()
36
+ return tensor.to(self.device)
37
+
38
+
39
+ class ReduceExperts(nn.Module):
40
+ def __init__(self, experts, tp_size):
41
+ super().__init__()
42
+ self.experts, self.tp_size = experts, tp_size
43
+
44
+ def forward(self, hidden_states, top_k_index, top_k_weights):
45
+ result = self.experts(hidden_states, top_k_index, top_k_weights)
46
+ return tensor_model_parallel_all_reduce(result) if self.tp_size > 1 else result
47
+
48
+
49
+ class StaticReferenceExperts(NVFP4Experts):
50
+ """Small-fixture reference kernels with no data-dependent Python dispatch."""
51
+
52
+ def forward(self, hidden_states, top_k_index, top_k_weights):
53
+ output = torch.zeros_like(hidden_states)
54
+ for expert_id, expert in enumerate(self.experts):
55
+ weight = (top_k_weights * (top_k_index == expert_id)).sum(-1).to(hidden_states.dtype)
56
+ output = output + expert(hidden_states) * weight[:, None]
57
+ return output
58
+
59
+
60
+ class ShardedDense(nn.Module):
61
+ def __init__(self, source, tp_size):
62
+ super().__init__()
63
+ self.tp_size = tp_size
64
+ self.act_fn = source.act_fn
65
+ for name in ('gate_proj', 'up_proj', 'down_proj'):
66
+ module = getattr(source, name)
67
+ if name == 'down_proj':
68
+ module.in_features //= tp_size
69
+ else:
70
+ module.out_features //= tp_size
71
+ module.weight = nn.Parameter(torch.empty(module.out_features, module.in_features,
72
+ dtype=torch.bfloat16, device='meta'))
73
+ setattr(self, name, module)
74
+
75
+ def forward(self, states):
76
+ result = self.down_proj(self.act_fn(self.gate_proj(states)) * self.up_proj(states))
77
+ return tensor_model_parallel_all_reduce(result) if self.tp_size > 1 else result
78
+
79
+
80
+ class NaiveN05FlashForCausalLM(nn.Module):
81
+ packed_modules_mapping = {}
82
+
83
+ def __init__(self, *, vllm_config, prefix=''):
84
+ super().__init__()
85
+ self.vllm_config = vllm_config
86
+ assert vllm_config.parallel_config.pipeline_parallel_size == 1
87
+ self.tp_size = get_tensor_model_parallel_world_size()
88
+ self.tp_rank = get_tensor_model_parallel_rank()
89
+ self.config = copy.deepcopy(vllm_config.model_config.hf_config)
90
+ if hasattr(self.config, 'quantization_config'):
91
+ del self.config.quantization_config
92
+ with init_empty_weights():
93
+ original = AutoModelForCausalLM.from_config(self.config, trust_remote_code=True, dtype=torch.bfloat16)
94
+ self.model, self.lm_head = original.model, original.lm_head
95
+ for i, layer in enumerate(self.model.layers):
96
+ layer.self_attn = NaivePagedAttention(layer.self_attn, f'model.layers.{i}.self_attn',
97
+ vllm_config, self.tp_size, self.tp_rank)
98
+ if not self.config.moe_layer_freq[i]:
99
+ layer.mlp = ShardedDense(layer.mlp, self.tp_size)
100
+
101
+ def embed_input_ids(self, input_ids):
102
+ return self.model.embed_tokens(input_ids)
103
+
104
+ def forward(self, input_ids, positions, intermediate_tensors=None, inputs_embeds=None):
105
+ states = self.embed_input_ids(input_ids) if inputs_embeds is None else inputs_embeds
106
+ for layer in self.model.layers:
107
+ norm = layer.input_layernorm
108
+ states = states + layer.self_attn(rmsnorm(states, norm.weight, norm.variance_epsilon), positions)
109
+ norm = layer.post_attention_layernorm
110
+ states = states + layer.mlp(rmsnorm(states, norm.weight, norm.variance_epsilon))
111
+ return rmsnorm(states, self.model.norm.weight, self.model.norm.variance_epsilon)
112
+
113
+ def compute_logits(self, hidden_states):
114
+ # Vocabulary and embedding/head are replicated across TP ranks.
115
+ return self.lm_head(hidden_states)
116
+
117
+ def load_weights(self, weights):
118
+ # Layer shards allow streaming only this rank's slices onto its GPU.
119
+ # The vLLM loader has resolved/downloaded the model path before this call.
120
+ # Initialize the framework loader's lazy download/timing iterator.
121
+ next(iter(weights), None)
122
+ checkpoint = Path(self.vllm_config.model_config.model)
123
+ if not checkpoint.is_dir():
124
+ from huggingface_hub import snapshot_download
125
+ checkpoint = Path(snapshot_download(self.vllm_config.model_config.model,
126
+ revision=self.vllm_config.model_config.revision))
127
+ index = json.loads((checkpoint/'model.safetensors.index.json').read_text())['weight_map']
128
+ device = torch.device('cuda', torch.cuda.current_device())
129
+ loaded = set()
130
+ for i, layer in enumerate(self.model.layers):
131
+ prefix = f'model.layers.{i}.'
132
+ names = [name for name in index if name.startswith(prefix)]
133
+ shards = {index[name] for name in names}
134
+ assert len(shards) == 1
135
+ with safe_open(checkpoint / next(iter(shards)), framework='pt', device='cpu') as reader:
136
+ if self.config.moe_layer_freq[i]:
137
+ expert_prefix = prefix + 'mlp.experts.'
138
+ sliced = ShardedReader(reader, self.tp_rank, self.tp_size, device)
139
+ with torch.inference_mode(False):
140
+ if self.config.hidden_size >= 4096:
141
+ expert_module = FusedNVFP4Experts(sliced, expert_prefix, self.config.n_routed_experts,
142
+ self.config.hidden_size, self.config.moe_intermediate_size//self.tp_size,
143
+ device, top_k=self.config.num_experts_per_tok,
144
+ max_tokens=self.vllm_config.scheduler_config.max_num_batched_tokens)
145
+ else:
146
+ experts = []
147
+ for expert in range(self.config.n_routed_experts):
148
+ tensors = {p+'.'+kind:sliced.get_tensor(expert_prefix+str(expert)+'.'+p+'.'+kind).to(device)
149
+ for p in ('gate_proj','up_proj','down_proj')
150
+ for kind in ('weight','weight_scale','weight_scale_2','input_scale')}
151
+ experts.append(NVFP4Expert(tensors, 'cutlass'))
152
+ expert_module = StaticReferenceExperts(experts)
153
+ layer.mlp.experts = ReduceExperts(expert_module, self.tp_size)
154
+ loaded.update(name for name in names if name.startswith(expert_prefix))
155
+ for name in names:
156
+ if name in loaded:
157
+ continue
158
+ tensor = reader.get_tensor(name)
159
+ dim = None
160
+ if any('.self_attn.'+key+'.' in name for key in ('q_proj','k_proj','v_proj')):
161
+ dim = 0
162
+ elif '.self_attn.o_proj.weight' in name:
163
+ dim = 1
164
+ elif name.endswith('.self_attn.attention_sink_bias'):
165
+ dim = 0
166
+ elif not self.config.moe_layer_freq[i]:
167
+ if any('.mlp.'+key+'.' in name for key in ('gate_proj','up_proj')):
168
+ dim = 0
169
+ elif '.mlp.down_proj.weight' in name:
170
+ dim = 1
171
+ if dim is not None:
172
+ tensor = tensor.chunk(self.tp_size, dim=dim)[self.tp_rank].contiguous()
173
+ set_module_tensor_to_device(self, name, device, value=tensor, dtype=tensor.dtype)
174
+ loaded.add(name)
175
+ print(f'NAIVE_VLLM_LOADED_LAYER {i+1}/{self.config.num_hidden_layers} TP={self.tp_rank}', flush=True)
176
+ for name in sorted(set(index)-loaded):
177
+ assert name in {'model.embed_tokens.weight','model.norm.weight','lm_head.weight'}
178
+ with safe_open(checkpoint/index[name], framework='pt', device='cpu') as reader:
179
+ tensor = reader.get_tensor(name)
180
+ set_module_tensor_to_device(self, name, device, value=tensor, dtype=tensor.dtype)
181
+ loaded.add(name)
182
+ assert loaded == set(index)
183
+ assert not any(p.is_meta for p in self.parameters())
184
+ self.eval().requires_grad_(False)
185
+ for layer in self.model.layers:
186
+ layer.self_attn.initialize_decode()
187
+ # Parameter names differ for the fused experts; all source tensors were
188
+ # explicitly checked above, so use vLLM's optional return convention.
189
+ return None
tokenizer.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9871eef5422b8cd120d4ecb00a08dd2f5c939d6dd46af384233a8c5078b224e2
3
+ size 11422840
tokenizer_config.json ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_comment": "Tokenizer copied from the open-source MiMo 2.5",
3
+ "add_prefix_space": false,
4
+ "backend": "tokenizers",
5
+ "bos_token": null,
6
+ "clean_up_tokenization_spaces": false,
7
+ "eos_token": "<|im_end|>",
8
+ "errors": "replace",
9
+ "extra_special_tokens": [
10
+ "<|im_start|>",
11
+ "<|im_end|>",
12
+ "<|object_ref_start|>",
13
+ "<|object_ref_end|>",
14
+ "<|box_start|>",
15
+ "<|box_end|>",
16
+ "<|quad_start|>",
17
+ "<|quad_end|>",
18
+ "<|vision_start|>",
19
+ "<|vision_end|>",
20
+ "<|vision_pad|>",
21
+ "<|image_pad|>",
22
+ "<|video_pad|>",
23
+ "<|audio_pad|>"
24
+ ],
25
+ "is_local": true,
26
+ "local_files_only": false,
27
+ "model_max_length": 1048576,
28
+ "pad_token": "<|endoftext|>",
29
+ "split_special_tokens": false,
30
+ "tokenizer_class": "Qwen2Tokenizer",
31
+ "unk_token": null
32
+ }
validation/expert-sharding-tp4-validation.json ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "passed": true,
3
+ "checks": [
4
+ {
5
+ "tokens": 1,
6
+ "cosine": 0.9999017715454102,
7
+ "relative_rmse": 0.014022702351212502,
8
+ "max_error": 0.046875
9
+ },
10
+ {
11
+ "tokens": 16,
12
+ "cosine": 0.9999954104423523,
13
+ "relative_rmse": 0.003035087138414383,
14
+ "max_error": 0.03125
15
+ }
16
+ ]
17
+ }
validation/export-validation.json ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "passed": true,
3
+ "tensor_count": 144856,
4
+ "packed_expert_weights": 36096,
5
+ "safetensor_shards": 49,
6
+ "tensor_bytes": 182549965184,
7
+ "all_source_tensors_accounted_for": true
8
+ }
validation/native-tiny-graphs-validation.json ADDED
@@ -0,0 +1,394 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "passed": true,
3
+ "decode_graphs": true,
4
+ "scope": "Real vLLM V1 engine versus quantized upstream reference, tiny architecture fixture",
5
+ "chunked_prefill": true,
6
+ "prefix_caching": true,
7
+ "max_num_seqs": 2,
8
+ "checks": [
9
+ {
10
+ "prompt_tokens": 8,
11
+ "expected": [
12
+ 58,
13
+ 193,
14
+ 46,
15
+ 193,
16
+ 46,
17
+ 58,
18
+ 193,
19
+ 46,
20
+ 58,
21
+ 193,
22
+ 46,
23
+ 58
24
+ ],
25
+ "actual": [
26
+ 58,
27
+ 193,
28
+ 46,
29
+ 193,
30
+ 46,
31
+ 58,
32
+ 193,
33
+ 46,
34
+ 58,
35
+ 193,
36
+ 46,
37
+ 58
38
+ ],
39
+ "exact_token_match": true
40
+ },
41
+ {
42
+ "prompt_tokens": 35,
43
+ "expected": [
44
+ 193,
45
+ 98,
46
+ 120,
47
+ 46,
48
+ 120,
49
+ 46,
50
+ 120,
51
+ 46,
52
+ 120,
53
+ 46,
54
+ 98,
55
+ 120
56
+ ],
57
+ "actual": [
58
+ 193,
59
+ 98,
60
+ 120,
61
+ 46,
62
+ 120,
63
+ 46,
64
+ 120,
65
+ 46,
66
+ 120,
67
+ 46,
68
+ 98,
69
+ 120
70
+ ],
71
+ "exact_token_match": true
72
+ },
73
+ {
74
+ "prompt_tokens": 80,
75
+ "expected": [
76
+ 11,
77
+ 11,
78
+ 11,
79
+ 11,
80
+ 245,
81
+ 11,
82
+ 11,
83
+ 163,
84
+ 11,
85
+ 38,
86
+ 11,
87
+ 245
88
+ ],
89
+ "actual": [
90
+ 11,
91
+ 11,
92
+ 11,
93
+ 11,
94
+ 245,
95
+ 11,
96
+ 11,
97
+ 163,
98
+ 11,
99
+ 38,
100
+ 11,
101
+ 245
102
+ ],
103
+ "exact_token_match": true
104
+ },
105
+ {
106
+ "prompt_tokens": 17,
107
+ "expected": [
108
+ 193,
109
+ 197,
110
+ 11,
111
+ 98,
112
+ 120,
113
+ 46,
114
+ 11,
115
+ 46,
116
+ 11,
117
+ 98,
118
+ 120,
119
+ 46
120
+ ],
121
+ "actual": [
122
+ 193,
123
+ 197,
124
+ 11,
125
+ 98,
126
+ 120,
127
+ 46,
128
+ 11,
129
+ 46,
130
+ 11,
131
+ 98,
132
+ 120,
133
+ 46
134
+ ],
135
+ "exact_token_match": true
136
+ },
137
+ {
138
+ "prompt_tokens": 35,
139
+ "expected": [
140
+ 193,
141
+ 98,
142
+ 120,
143
+ 46,
144
+ 120,
145
+ 46,
146
+ 120,
147
+ 46,
148
+ 120,
149
+ 46,
150
+ 98,
151
+ 120
152
+ ],
153
+ "actual": [
154
+ 193,
155
+ 98,
156
+ 120,
157
+ 46,
158
+ 120,
159
+ 46,
160
+ 120,
161
+ 46,
162
+ 120,
163
+ 46,
164
+ 98,
165
+ 120
166
+ ],
167
+ "exact_token_match": true
168
+ },
169
+ {
170
+ "prompt_tokens": 8,
171
+ "expected": [
172
+ 58,
173
+ 193,
174
+ 46,
175
+ 193,
176
+ 46,
177
+ 58,
178
+ 193,
179
+ 46,
180
+ 58,
181
+ 193,
182
+ 46,
183
+ 58
184
+ ],
185
+ "actual": [
186
+ 58,
187
+ 193,
188
+ 46,
189
+ 193,
190
+ 46,
191
+ 58,
192
+ 193,
193
+ 46,
194
+ 58,
195
+ 193,
196
+ 46,
197
+ 58
198
+ ],
199
+ "exact_token_match": true
200
+ },
201
+ {
202
+ "prompt_tokens": 8,
203
+ "expected": [
204
+ 58,
205
+ 193,
206
+ 46,
207
+ 193,
208
+ 46,
209
+ 58,
210
+ 193,
211
+ 46,
212
+ 58,
213
+ 193,
214
+ 46,
215
+ 58
216
+ ],
217
+ "actual": [
218
+ 58,
219
+ 193,
220
+ 46,
221
+ 193,
222
+ 46,
223
+ 58,
224
+ 193,
225
+ 46,
226
+ 58,
227
+ 193,
228
+ 46,
229
+ 58
230
+ ],
231
+ "exact_token_match": true
232
+ },
233
+ {
234
+ "prompt_tokens": 35,
235
+ "expected": [
236
+ 193,
237
+ 98,
238
+ 120,
239
+ 46,
240
+ 120,
241
+ 46,
242
+ 120,
243
+ 46,
244
+ 120,
245
+ 46,
246
+ 98,
247
+ 120
248
+ ],
249
+ "actual": [
250
+ 193,
251
+ 98,
252
+ 120,
253
+ 46,
254
+ 120,
255
+ 46,
256
+ 120,
257
+ 46,
258
+ 120,
259
+ 46,
260
+ 98,
261
+ 120
262
+ ],
263
+ "exact_token_match": true
264
+ },
265
+ {
266
+ "prompt_tokens": 80,
267
+ "expected": [
268
+ 11,
269
+ 11,
270
+ 11,
271
+ 11,
272
+ 245,
273
+ 11,
274
+ 11,
275
+ 163,
276
+ 11,
277
+ 38,
278
+ 11,
279
+ 245
280
+ ],
281
+ "actual": [
282
+ 11,
283
+ 11,
284
+ 11,
285
+ 11,
286
+ 245,
287
+ 11,
288
+ 11,
289
+ 163,
290
+ 11,
291
+ 38,
292
+ 11,
293
+ 245
294
+ ],
295
+ "exact_token_match": true
296
+ },
297
+ {
298
+ "prompt_tokens": 17,
299
+ "expected": [
300
+ 193,
301
+ 197,
302
+ 11,
303
+ 98,
304
+ 120,
305
+ 46,
306
+ 11,
307
+ 46,
308
+ 11,
309
+ 98,
310
+ 120,
311
+ 46
312
+ ],
313
+ "actual": [
314
+ 193,
315
+ 197,
316
+ 11,
317
+ 98,
318
+ 120,
319
+ 46,
320
+ 11,
321
+ 46,
322
+ 11,
323
+ 98,
324
+ 120,
325
+ 46
326
+ ],
327
+ "exact_token_match": true
328
+ },
329
+ {
330
+ "prompt_tokens": 35,
331
+ "expected": [
332
+ 193,
333
+ 98,
334
+ 120,
335
+ 46,
336
+ 120,
337
+ 46,
338
+ 120,
339
+ 46,
340
+ 120,
341
+ 46,
342
+ 98,
343
+ 120
344
+ ],
345
+ "actual": [
346
+ 193,
347
+ 98,
348
+ 120,
349
+ 46,
350
+ 120,
351
+ 46,
352
+ 120,
353
+ 46,
354
+ 120,
355
+ 46,
356
+ 98,
357
+ 120
358
+ ],
359
+ "exact_token_match": true
360
+ },
361
+ {
362
+ "prompt_tokens": 8,
363
+ "expected": [
364
+ 58,
365
+ 193,
366
+ 46,
367
+ 193,
368
+ 46,
369
+ 58,
370
+ 193,
371
+ 46,
372
+ 58,
373
+ 193,
374
+ 46,
375
+ 58
376
+ ],
377
+ "actual": [
378
+ 58,
379
+ 193,
380
+ 46,
381
+ 193,
382
+ 46,
383
+ 58,
384
+ 193,
385
+ 46,
386
+ 58,
387
+ 193,
388
+ 46,
389
+ 58
390
+ ],
391
+ "exact_token_match": true
392
+ }
393
+ ]
394
+ }
validation/native-vllm-api-validation.json ADDED
@@ -0,0 +1,283 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "passed": true,
3
+ "engine": "vLLM 0.28.0",
4
+ "model": "Naive-N0.5-Flash-NVFP4",
5
+ "checks": {
6
+ "arithmetic": {
7
+ "id": "chatcmpl-b57ff21de144f7ca",
8
+ "object": "chat.completion",
9
+ "created": 1790592276,
10
+ "model": "Naive-N0.5-Flash-NVFP4",
11
+ "choices": [
12
+ {
13
+ "index": 0,
14
+ "message": {
15
+ "role": "assistant",
16
+ "content": "\n\n4",
17
+ "refusal": null,
18
+ "annotations": null,
19
+ "audio": null,
20
+ "function_call": null,
21
+ "reasoning": null
22
+ },
23
+ "logprobs": null,
24
+ "finish_reason": "stop",
25
+ "stop_reason": null,
26
+ "token_ids": null,
27
+ "routed_experts": null
28
+ }
29
+ ],
30
+ "service_tier": null,
31
+ "system_fingerprint": "vllm-0.28.0-tp4-13be3b5b",
32
+ "usage": {
33
+ "prompt_tokens": 58,
34
+ "total_tokens": 61,
35
+ "completion_tokens": 3,
36
+ "prompt_tokens_details": null,
37
+ "completion_tokens_details": {
38
+ "reasoning_tokens": 0
39
+ }
40
+ },
41
+ "prompt_logprobs": null,
42
+ "prompt_token_ids": null,
43
+ "prompt_text": null,
44
+ "kv_transfer_params": null,
45
+ "ec_transfer_params": null,
46
+ "metrics": null,
47
+ "elapsed_seconds": 0.10958343200036325,
48
+ "completion_tokens_per_second_including_prefill": 27.376401206252197
49
+ },
50
+ "geography": {
51
+ "id": "chatcmpl-9a328e34a75310ee",
52
+ "object": "chat.completion",
53
+ "created": 1790592276,
54
+ "model": "Naive-N0.5-Flash-NVFP4",
55
+ "choices": [
56
+ {
57
+ "index": 0,
58
+ "message": {
59
+ "role": "assistant",
60
+ "content": "\n\nParis",
61
+ "refusal": null,
62
+ "annotations": null,
63
+ "audio": null,
64
+ "function_call": null,
65
+ "reasoning": null
66
+ },
67
+ "logprobs": null,
68
+ "finish_reason": "stop",
69
+ "stop_reason": null,
70
+ "token_ids": null,
71
+ "routed_experts": null
72
+ }
73
+ ],
74
+ "service_tier": null,
75
+ "system_fingerprint": "vllm-0.28.0-tp4-13be3b5b",
76
+ "usage": {
77
+ "prompt_tokens": 57,
78
+ "total_tokens": 60,
79
+ "completion_tokens": 3,
80
+ "prompt_tokens_details": null,
81
+ "completion_tokens_details": {
82
+ "reasoning_tokens": 0
83
+ }
84
+ },
85
+ "prompt_logprobs": null,
86
+ "prompt_token_ids": null,
87
+ "prompt_text": null,
88
+ "kv_transfer_params": null,
89
+ "ec_transfer_params": null,
90
+ "metrics": null,
91
+ "elapsed_seconds": 0.12031267199927242,
92
+ "completion_tokens_per_second_including_prefill": 24.93502928783879
93
+ },
94
+ "coding": {
95
+ "id": "chatcmpl-a8ad4110a48efbdb",
96
+ "object": "chat.completion",
97
+ "created": 1790592276,
98
+ "model": "Naive-N0.5-Flash-NVFP4",
99
+ "choices": [
100
+ {
101
+ "index": 0,
102
+ "message": {
103
+ "role": "assistant",
104
+ "content": "\n\ndef add(a, b):\n return a + b",
105
+ "refusal": null,
106
+ "annotations": null,
107
+ "audio": null,
108
+ "function_call": null,
109
+ "reasoning": null
110
+ },
111
+ "logprobs": null,
112
+ "finish_reason": "stop",
113
+ "stop_reason": null,
114
+ "token_ids": null,
115
+ "routed_experts": null
116
+ }
117
+ ],
118
+ "service_tier": null,
119
+ "system_fingerprint": "vllm-0.28.0-tp4-13be3b5b",
120
+ "usage": {
121
+ "prompt_tokens": 63,
122
+ "total_tokens": 76,
123
+ "completion_tokens": 13,
124
+ "prompt_tokens_details": null,
125
+ "completion_tokens_details": {
126
+ "reasoning_tokens": 0
127
+ }
128
+ },
129
+ "prompt_logprobs": null,
130
+ "prompt_token_ids": null,
131
+ "prompt_text": null,
132
+ "kv_transfer_params": null,
133
+ "ec_transfer_params": null,
134
+ "metrics": null,
135
+ "elapsed_seconds": 0.3035910079997848,
136
+ "completion_tokens_per_second_including_prefill": 42.82076760326583
137
+ },
138
+ "tools": {
139
+ "id": "chatcmpl-9b641c57e20da9a6",
140
+ "object": "chat.completion",
141
+ "created": 1790592277,
142
+ "model": "Naive-N0.5-Flash-NVFP4",
143
+ "choices": [
144
+ {
145
+ "index": 0,
146
+ "message": {
147
+ "role": "assistant",
148
+ "content": null,
149
+ "refusal": null,
150
+ "annotations": null,
151
+ "audio": null,
152
+ "function_call": null,
153
+ "tool_calls": [
154
+ {
155
+ "id": "chatcmpl-tool-8eeac683e7c34ae0",
156
+ "type": "function",
157
+ "function": {
158
+ "name": "get_weather",
159
+ "arguments": "{\"city\": \"Warsaw\"}"
160
+ }
161
+ }
162
+ ],
163
+ "reasoning": null
164
+ },
165
+ "logprobs": null,
166
+ "finish_reason": "tool_calls",
167
+ "stop_reason": null,
168
+ "token_ids": null,
169
+ "routed_experts": null
170
+ }
171
+ ],
172
+ "service_tier": null,
173
+ "system_fingerprint": "vllm-0.28.0-tp4-13be3b5b",
174
+ "usage": {
175
+ "prompt_tokens": 284,
176
+ "total_tokens": 307,
177
+ "completion_tokens": 23,
178
+ "prompt_tokens_details": null,
179
+ "completion_tokens_details": {
180
+ "reasoning_tokens": 0
181
+ }
182
+ },
183
+ "prompt_logprobs": null,
184
+ "prompt_token_ids": null,
185
+ "prompt_text": null,
186
+ "kv_transfer_params": null,
187
+ "ec_transfer_params": null,
188
+ "metrics": null,
189
+ "elapsed_seconds": 0.4892891299969051,
190
+ "completion_tokens_per_second_including_prefill": 47.00697111367563
191
+ },
192
+ "reasoning": {
193
+ "id": "chatcmpl-bebdc22c27f814ba",
194
+ "object": "chat.completion",
195
+ "created": 1790592277,
196
+ "model": "Naive-N0.5-Flash-NVFP4",
197
+ "choices": [
198
+ {
199
+ "index": 0,
200
+ "message": {
201
+ "role": "assistant",
202
+ "content": "\n\n42",
203
+ "refusal": null,
204
+ "annotations": null,
205
+ "audio": null,
206
+ "function_call": null,
207
+ "reasoning": "\nWe need answer simple arithmetic. Need think briefly then give answer. We can just answer 42. Need maybe no extra. Ensure final only answer.\n"
208
+ },
209
+ "logprobs": null,
210
+ "finish_reason": "stop",
211
+ "stop_reason": null,
212
+ "token_ids": null,
213
+ "routed_experts": null
214
+ }
215
+ ],
216
+ "service_tier": null,
217
+ "system_fingerprint": "vllm-0.28.0-tp4-13be3b5b",
218
+ "usage": {
219
+ "prompt_tokens": 57,
220
+ "total_tokens": 95,
221
+ "completion_tokens": 38,
222
+ "prompt_tokens_details": null,
223
+ "completion_tokens_details": {
224
+ "reasoning_tokens": 32
225
+ }
226
+ },
227
+ "prompt_logprobs": null,
228
+ "prompt_token_ids": null,
229
+ "prompt_text": null,
230
+ "kv_transfer_params": null,
231
+ "ec_transfer_params": null,
232
+ "metrics": null,
233
+ "elapsed_seconds": 0.7566590700007509,
234
+ "completion_tokens_per_second_including_prefill": 50.220768515947725
235
+ },
236
+ "longer_context": {
237
+ "id": "chatcmpl-ab4c6172888cf312",
238
+ "object": "chat.completion",
239
+ "created": 1790592278,
240
+ "model": "Naive-N0.5-Flash-NVFP4",
241
+ "choices": [
242
+ {
243
+ "index": 0,
244
+ "message": {
245
+ "role": "assistant",
246
+ "content": "\n\n4",
247
+ "refusal": null,
248
+ "annotations": null,
249
+ "audio": null,
250
+ "function_call": null,
251
+ "reasoning": null
252
+ },
253
+ "logprobs": null,
254
+ "finish_reason": "stop",
255
+ "stop_reason": null,
256
+ "token_ids": null,
257
+ "routed_experts": null
258
+ }
259
+ ],
260
+ "service_tier": null,
261
+ "system_fingerprint": "vllm-0.28.0-tp4-13be3b5b",
262
+ "usage": {
263
+ "prompt_tokens": 3800,
264
+ "total_tokens": 3803,
265
+ "completion_tokens": 3,
266
+ "prompt_tokens_details": null,
267
+ "completion_tokens_details": {
268
+ "reasoning_tokens": 0
269
+ }
270
+ },
271
+ "prompt_logprobs": null,
272
+ "prompt_token_ids": null,
273
+ "prompt_text": null,
274
+ "kv_transfer_params": null,
275
+ "ec_transfer_params": null,
276
+ "metrics": null,
277
+ "elapsed_seconds": 1.0702180820007925,
278
+ "completion_tokens_per_second_including_prefill": 2.8031669904057726
279
+ },
280
+ "gpu_memory": "index, memory.used [MiB], memory.total [MiB]\n0, 86684 MiB, 97887 MiB\n1, 86684 MiB, 97887 MiB\n2, 91002 MiB, 97887 MiB\n3, 86684 MiB, 97887 MiB\n"
281
+ },
282
+ "scope": "Basic generation, coding, tool use and sparse-context smoke checks; not an accuracy benchmark"
283
+ }
validation/native-vllm-benchmark-repeat.json ADDED
The diff for this file is too large to render. See raw diff
 
validation/native-vllm-benchmark.json ADDED
The diff for this file is too large to render. See raw diff
 
validation/native-vllm-concurrency-validation.json ADDED
@@ -0,0 +1,184 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "passed": true,
3
+ "engine": "vLLM 0.28.0",
4
+ "concurrent_requests": 4,
5
+ "scope": "Concurrent scheduling/cache/output smoke test, not a throughput or accuracy benchmark",
6
+ "results": [
7
+ {
8
+ "id": "chatcmpl-8f7154ae17b91c78",
9
+ "object": "chat.completion",
10
+ "created": 1790592282,
11
+ "model": "Naive-N0.5-Flash-NVFP4",
12
+ "choices": [
13
+ {
14
+ "index": 0,
15
+ "message": {
16
+ "role": "assistant",
17
+ "content": "\n\n23\n\nTo add 20 and 3, you can think of it as combining two quantities. Start with the number 20, which represents two tens. Then, add 3 more to it. One simple way is to count forward: begin at 20 and count three steps: 21, 22, 23. Alternatively, you can break it down by place value. The number 20 has a 2 in the tens place and a 0 in the ones place. The number 3 has a 3 in the ones place. When you add them, you add the ones first: 0 + 3 = 3. Then, you add the tens: 2 + 0 = 2. Combining these gives you 2 tens and 3 ones, which is 23. This method works because you are simply combining the values in each place without any carrying",
18
+ "refusal": null,
19
+ "annotations": null,
20
+ "audio": null,
21
+ "function_call": null,
22
+ "reasoning": null
23
+ },
24
+ "logprobs": null,
25
+ "finish_reason": "length",
26
+ "stop_reason": null,
27
+ "token_ids": null,
28
+ "routed_experts": null
29
+ }
30
+ ],
31
+ "service_tier": null,
32
+ "system_fingerprint": "vllm-0.28.0-tp4-13be3b5b",
33
+ "usage": {
34
+ "prompt_tokens": 78,
35
+ "total_tokens": 270,
36
+ "completion_tokens": 192,
37
+ "prompt_tokens_details": null,
38
+ "completion_tokens_details": {
39
+ "reasoning_tokens": 0
40
+ }
41
+ },
42
+ "prompt_logprobs": null,
43
+ "prompt_token_ids": null,
44
+ "prompt_text": null,
45
+ "kv_transfer_params": null,
46
+ "ec_transfer_params": null,
47
+ "metrics": null,
48
+ "elapsed_seconds": 25.521290875003615,
49
+ "completion_tokens_per_second_including_prefill": 7.523130430210764
50
+ },
51
+ {
52
+ "id": "chatcmpl-b6950169c10c14bf",
53
+ "object": "chat.completion",
54
+ "created": 1790592282,
55
+ "model": "Naive-N0.5-Flash-NVFP4",
56
+ "choices": [
57
+ {
58
+ "index": 0,
59
+ "message": {
60
+ "role": "assistant",
61
+ "content": "\n\n25\n\nTo add 20 and 5, you can think of it as combining two quantities. Start with the number 20, which represents two groups of ten. Then, add 5 more to it. One simple way to visualize this is to count forward from 20: 21, 22, 23, 24, 25. After five steps, you land on 25. Alternatively, you can break the numbers down by place value. The number 20 has a 2 in the tens place and a 0 in the ones place. The number 5 has a 5 in the ones place. When you add them, you add the ones digits: 0 + 5 = 5. The tens digit remains 2, since there is no other tens digit to add. So, you get 2 in the tens place and 5 in the",
62
+ "refusal": null,
63
+ "annotations": null,
64
+ "audio": null,
65
+ "function_call": null,
66
+ "reasoning": null
67
+ },
68
+ "logprobs": null,
69
+ "finish_reason": "length",
70
+ "stop_reason": null,
71
+ "token_ids": null,
72
+ "routed_experts": null
73
+ }
74
+ ],
75
+ "service_tier": null,
76
+ "system_fingerprint": "vllm-0.28.0-tp4-13be3b5b",
77
+ "usage": {
78
+ "prompt_tokens": 78,
79
+ "total_tokens": 270,
80
+ "completion_tokens": 192,
81
+ "prompt_tokens_details": null,
82
+ "completion_tokens_details": {
83
+ "reasoning_tokens": 0
84
+ }
85
+ },
86
+ "prompt_logprobs": null,
87
+ "prompt_token_ids": null,
88
+ "prompt_text": null,
89
+ "kv_transfer_params": null,
90
+ "ec_transfer_params": null,
91
+ "metrics": null,
92
+ "elapsed_seconds": 23.55511791400204,
93
+ "completion_tokens_per_second_including_prefill": 8.151094836416338
94
+ },
95
+ {
96
+ "id": "chatcmpl-ae5bdf320cff8063",
97
+ "object": "chat.completion",
98
+ "created": 1790592282,
99
+ "model": "Naive-N0.5-Flash-NVFP4",
100
+ "choices": [
101
+ {
102
+ "index": 0,
103
+ "message": {
104
+ "role": "assistant",
105
+ "content": "\n\n27\n\nTo add 20 and 7, you can think of it as combining two quantities. Start with the number 20, which represents two groups of ten. Then, add 7 more to it. One simple way is to count up from 20: 21, 22, 23, 24, 25, 26, 27. After seven steps, you land on 27. Another method is to break 20 into 10 and 10, then add 7 to one of the tens to get 17, and finally add the other 10 to reach 27. You can also use place value: 20 has a 2 in the tens place and a 0 in the ones place. Adding 7 affects only the ones place, so 0 + 7 = 7, while the",
106
+ "refusal": null,
107
+ "annotations": null,
108
+ "audio": null,
109
+ "function_call": null,
110
+ "reasoning": null
111
+ },
112
+ "logprobs": null,
113
+ "finish_reason": "length",
114
+ "stop_reason": null,
115
+ "token_ids": null,
116
+ "routed_experts": null
117
+ }
118
+ ],
119
+ "service_tier": null,
120
+ "system_fingerprint": "vllm-0.28.0-tp4-13be3b5b",
121
+ "usage": {
122
+ "prompt_tokens": 78,
123
+ "total_tokens": 270,
124
+ "completion_tokens": 192,
125
+ "prompt_tokens_details": null,
126
+ "completion_tokens_details": {
127
+ "reasoning_tokens": 0
128
+ }
129
+ },
130
+ "prompt_logprobs": null,
131
+ "prompt_token_ids": null,
132
+ "prompt_text": null,
133
+ "kv_transfer_params": null,
134
+ "ec_transfer_params": null,
135
+ "metrics": null,
136
+ "elapsed_seconds": 23.458772466001392,
137
+ "completion_tokens_per_second_including_prefill": 8.184571476545248
138
+ },
139
+ {
140
+ "id": "chatcmpl-a7f84a9ffb302b3b",
141
+ "object": "chat.completion",
142
+ "created": 1790592282,
143
+ "model": "Naive-N0.5-Flash-NVFP4",
144
+ "choices": [
145
+ {
146
+ "index": 0,
147
+ "message": {
148
+ "role": "assistant",
149
+ "content": "\n\n29\n\nTo add 20 and 9, you can think of it as combining two groups of objects. Imagine you have 20 apples in one basket and 9 apples in another basket. If you pour all the apples together into a single large container, you would count them one by one to find the total. Starting with the 20 apples, you would count 21, 22, 23, 24, 25, 26, 27, 28, and finally 29. This process of counting upward from 20 by nine steps gives you the answer. Alternatively, you can use place value: 20 is two tens and zero ones, while 9 is zero tens and nine ones. Adding the ones together gives 0 + 9 = 9, and adding the tens gives 2 + 0 = 2 tens, which",
150
+ "refusal": null,
151
+ "annotations": null,
152
+ "audio": null,
153
+ "function_call": null,
154
+ "reasoning": null
155
+ },
156
+ "logprobs": null,
157
+ "finish_reason": "length",
158
+ "stop_reason": null,
159
+ "token_ids": null,
160
+ "routed_experts": null
161
+ }
162
+ ],
163
+ "service_tier": null,
164
+ "system_fingerprint": "vllm-0.28.0-tp4-13be3b5b",
165
+ "usage": {
166
+ "prompt_tokens": 78,
167
+ "total_tokens": 270,
168
+ "completion_tokens": 192,
169
+ "prompt_tokens_details": null,
170
+ "completion_tokens_details": {
171
+ "reasoning_tokens": 0
172
+ }
173
+ },
174
+ "prompt_logprobs": null,
175
+ "prompt_token_ids": null,
176
+ "prompt_text": null,
177
+ "kv_transfer_params": null,
178
+ "ec_transfer_params": null,
179
+ "metrics": null,
180
+ "elapsed_seconds": 25.521558972002822,
181
+ "completion_tokens_per_second_including_prefill": 7.523051401782478
182
+ }
183
+ ]
184
+ }
validation/native-vllm-streaming-validation.json ADDED
@@ -0,0 +1,1493 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "passed": true,
3
+ "engine": "vLLM 0.28.0",
4
+ "tool_call": {
5
+ "request": {
6
+ "model": "Naive-N0.5-Flash-NVFP4",
7
+ "messages": [
8
+ {
9
+ "role": "user",
10
+ "content": "Call get_weather for Warsaw. Do not answer from memory."
11
+ }
12
+ ],
13
+ "temperature": 0,
14
+ "max_tokens": 256,
15
+ "stream": true,
16
+ "stream_options": {
17
+ "include_usage": true
18
+ },
19
+ "return_token_ids": true,
20
+ "chat_template_kwargs": {
21
+ "enable_thinking": false
22
+ },
23
+ "tools": [
24
+ {
25
+ "type": "function",
26
+ "function": {
27
+ "name": "get_weather",
28
+ "description": "Get weather for a city",
29
+ "parameters": {
30
+ "type": "object",
31
+ "properties": {
32
+ "city": {
33
+ "type": "string"
34
+ }
35
+ },
36
+ "required": [
37
+ "city"
38
+ ]
39
+ }
40
+ }
41
+ }
42
+ ],
43
+ "tool_choice": "auto"
44
+ },
45
+ "content": "",
46
+ "reasoning": "",
47
+ "tool_calls": {
48
+ "0": {
49
+ "name": "get_weather",
50
+ "arguments": "{\"city\": \"Warsaw\"}"
51
+ }
52
+ },
53
+ "usage": {
54
+ "prompt_tokens": 282,
55
+ "total_tokens": 305,
56
+ "completion_tokens": 23,
57
+ "completion_tokens_details": {
58
+ "reasoning_tokens": 0
59
+ }
60
+ },
61
+ "events": [
62
+ {
63
+ "id": "chatcmpl-a08784d157aa41e3",
64
+ "object": "chat.completion.chunk",
65
+ "created": 1790592279,
66
+ "model": "Naive-N0.5-Flash-NVFP4",
67
+ "choices": [
68
+ {
69
+ "index": 0,
70
+ "delta": {
71
+ "role": "assistant",
72
+ "content": ""
73
+ },
74
+ "logprobs": null,
75
+ "finish_reason": null
76
+ }
77
+ ],
78
+ "prompt_token_ids": [
79
+ 151644,
80
+ 8948,
81
+ 198,
82
+ 25139,
83
+ 287,
84
+ 30022,
85
+ 371,
86
+ 25,
87
+ 7487,
88
+ 151645,
89
+ 151644,
90
+ 8948,
91
+ 198,
92
+ 2610,
93
+ 525,
94
+ 12812,
95
+ 533,
96
+ 11250,
97
+ 15,
98
+ 13,
99
+ 20,
100
+ 12,
101
+ 23876,
102
+ 11,
103
+ 264,
104
+ 10950,
105
+ 15235,
106
+ 17847,
107
+ 44936,
108
+ 553,
109
+ 12812,
110
+ 533,
111
+ 15235,
112
+ 382,
113
+ 2,
114
+ 13852,
115
+ 271,
116
+ 2610,
117
+ 1231,
118
+ 1618,
119
+ 825,
120
+ 476,
121
+ 803,
122
+ 5746,
123
+ 311,
124
+ 7789,
125
+ 448,
126
+ 279,
127
+ 1196,
128
+ 3239,
129
+ 382,
130
+ 2610,
131
+ 614,
132
+ 2615,
133
+ 311,
134
+ 279,
135
+ 2701,
136
+ 5746,
137
+ 1447,
138
+ 27,
139
+ 15918,
140
+ 397,
141
+ 27,
142
+ 1688,
143
+ 397,
144
+ 27,
145
+ 606,
146
+ 29,
147
+ 455,
148
+ 69364,
149
+ 522,
150
+ 606,
151
+ 397,
152
+ 27,
153
+ 4684,
154
+ 29,
155
+ 1949,
156
+ 9104,
157
+ 369,
158
+ 264,
159
+ 3283,
160
+ 522,
161
+ 4684,
162
+ 397,
163
+ 27,
164
+ 13786,
165
+ 397,
166
+ 27,
167
+ 16181,
168
+ 397,
169
+ 27,
170
+ 606,
171
+ 29,
172
+ 8926,
173
+ 522,
174
+ 606,
175
+ 397,
176
+ 27,
177
+ 1313,
178
+ 29,
179
+ 917,
180
+ 522,
181
+ 1313,
182
+ 397,
183
+ 522,
184
+ 16181,
185
+ 397,
186
+ 27,
187
+ 6279,
188
+ 29,
189
+ 1183,
190
+ 8926,
191
+ 1341,
192
+ 522,
193
+ 6279,
194
+ 397,
195
+ 522,
196
+ 13786,
197
+ 397,
198
+ 522,
199
+ 1688,
200
+ 397,
201
+ 522,
202
+ 15918,
203
+ 1339,
204
+ 2461,
205
+ 1817,
206
+ 729,
207
+ 1618,
208
+ 11,
209
+ 2550,
210
+ 279,
211
+ 729,
212
+ 829,
213
+ 323,
214
+ 5977,
215
+ 304,
216
+ 279,
217
+ 2701,
218
+ 3561,
219
+ 510,
220
+ 151657,
221
+ 198,
222
+ 27,
223
+ 1688,
224
+ 28,
225
+ 8687,
226
+ 9174,
227
+ 1269,
228
+ 397,
229
+ 27,
230
+ 16181,
231
+ 28,
232
+ 8687,
233
+ 24899,
234
+ 62,
235
+ 16,
236
+ 29,
237
+ 957,
238
+ 62,
239
+ 16,
240
+ 522,
241
+ 16181,
242
+ 397,
243
+ 27,
244
+ 16181,
245
+ 28,
246
+ 8687,
247
+ 24899,
248
+ 62,
249
+ 17,
250
+ 41993,
251
+ 374,
252
+ 279,
253
+ 897,
254
+ 369,
255
+ 279,
256
+ 2086,
257
+ 5733,
258
+ 198,
259
+ 9033,
260
+ 646,
261
+ 9390,
262
+ 198,
263
+ 35673,
264
+ 5128,
265
+ 522,
266
+ 16181,
267
+ 397,
268
+ 522,
269
+ 1688,
270
+ 397,
271
+ 151658,
272
+ 271,
273
+ 27,
274
+ 98743,
275
+ 397,
276
+ 12,
277
+ 5712,
278
+ 6738,
279
+ 27732,
280
+ 1795,
281
+ 279,
282
+ 5189,
283
+ 3561,
284
+ 25,
285
+ 458,
286
+ 9179,
287
+ 366,
288
+ 1688,
289
+ 28,
290
+ 1112,
291
+ 1472,
292
+ 1688,
293
+ 29,
294
+ 2504,
295
+ 1969,
296
+ 387,
297
+ 24034,
298
+ 2878,
299
+ 220,
300
+ 151657,
301
+ 151658,
302
+ 11874,
303
+ 9492,
304
+ 198,
305
+ 12,
306
+ 9319,
307
+ 4183,
308
+ 990,
309
+ 729,
310
+ 6738,
311
+ 4766,
312
+ 220,
313
+ 151667,
314
+ 151668,
315
+ 9492,
316
+ 624,
317
+ 12,
318
+ 576,
319
+ 897,
320
+ 43810,
321
+ 1948,
322
+ 5733,
323
+ 9492,
324
+ 374,
325
+ 33583,
326
+ 6896,
327
+ 438,
328
+ 30430,
329
+ 11,
330
+ 2670,
331
+ 501,
332
+ 7969,
333
+ 323,
334
+ 12621,
335
+ 624,
336
+ 522,
337
+ 98743,
338
+ 29,
339
+ 151645,
340
+ 151644,
341
+ 872,
342
+ 198,
343
+ 7220,
344
+ 633,
345
+ 69364,
346
+ 369,
347
+ 72176,
348
+ 13,
349
+ 3155,
350
+ 537,
351
+ 4226,
352
+ 504,
353
+ 4938,
354
+ 13,
355
+ 151645,
356
+ 151644,
357
+ 77091,
358
+ 198,
359
+ 151667,
360
+ 151668
361
+ ],
362
+ "prompt_text": null
363
+ },
364
+ {
365
+ "id": "chatcmpl-a08784d157aa41e3",
366
+ "object": "chat.completion.chunk",
367
+ "created": 1790592279,
368
+ "model": "Naive-N0.5-Flash-NVFP4",
369
+ "choices": [
370
+ {
371
+ "index": 0,
372
+ "delta": {},
373
+ "logprobs": null,
374
+ "finish_reason": null,
375
+ "token_ids": [
376
+ 271
377
+ ]
378
+ }
379
+ ]
380
+ },
381
+ {
382
+ "id": "chatcmpl-a08784d157aa41e3",
383
+ "object": "chat.completion.chunk",
384
+ "created": 1790592279,
385
+ "model": "Naive-N0.5-Flash-NVFP4",
386
+ "choices": [
387
+ {
388
+ "index": 0,
389
+ "delta": {},
390
+ "logprobs": null,
391
+ "finish_reason": null,
392
+ "token_ids": [
393
+ 151657
394
+ ]
395
+ }
396
+ ]
397
+ },
398
+ {
399
+ "id": "chatcmpl-a08784d157aa41e3",
400
+ "object": "chat.completion.chunk",
401
+ "created": 1790592279,
402
+ "model": "Naive-N0.5-Flash-NVFP4",
403
+ "choices": [
404
+ {
405
+ "index": 0,
406
+ "delta": {},
407
+ "logprobs": null,
408
+ "finish_reason": null,
409
+ "token_ids": [
410
+ 198
411
+ ]
412
+ }
413
+ ]
414
+ },
415
+ {
416
+ "id": "chatcmpl-a08784d157aa41e3",
417
+ "object": "chat.completion.chunk",
418
+ "created": 1790592279,
419
+ "model": "Naive-N0.5-Flash-NVFP4",
420
+ "choices": [
421
+ {
422
+ "index": 0,
423
+ "delta": {},
424
+ "logprobs": null,
425
+ "finish_reason": null,
426
+ "token_ids": [
427
+ 27
428
+ ]
429
+ }
430
+ ]
431
+ },
432
+ {
433
+ "id": "chatcmpl-a08784d157aa41e3",
434
+ "object": "chat.completion.chunk",
435
+ "created": 1790592279,
436
+ "model": "Naive-N0.5-Flash-NVFP4",
437
+ "choices": [
438
+ {
439
+ "index": 0,
440
+ "delta": {},
441
+ "logprobs": null,
442
+ "finish_reason": null,
443
+ "token_ids": [
444
+ 1688
445
+ ]
446
+ }
447
+ ]
448
+ },
449
+ {
450
+ "id": "chatcmpl-a08784d157aa41e3",
451
+ "object": "chat.completion.chunk",
452
+ "created": 1790592279,
453
+ "model": "Naive-N0.5-Flash-NVFP4",
454
+ "choices": [
455
+ {
456
+ "index": 0,
457
+ "delta": {},
458
+ "logprobs": null,
459
+ "finish_reason": null,
460
+ "token_ids": [
461
+ 28280
462
+ ]
463
+ }
464
+ ]
465
+ },
466
+ {
467
+ "id": "chatcmpl-a08784d157aa41e3",
468
+ "object": "chat.completion.chunk",
469
+ "created": 1790592279,
470
+ "model": "Naive-N0.5-Flash-NVFP4",
471
+ "choices": [
472
+ {
473
+ "index": 0,
474
+ "delta": {},
475
+ "logprobs": null,
476
+ "finish_reason": null,
477
+ "token_ids": [
478
+ 69364
479
+ ]
480
+ }
481
+ ]
482
+ },
483
+ {
484
+ "id": "chatcmpl-a08784d157aa41e3",
485
+ "object": "chat.completion.chunk",
486
+ "created": 1790592279,
487
+ "model": "Naive-N0.5-Flash-NVFP4",
488
+ "choices": [
489
+ {
490
+ "index": 0,
491
+ "delta": {
492
+ "tool_calls": [
493
+ {
494
+ "id": "chatcmpl-tool-b7a4891d78286e7f",
495
+ "type": "function",
496
+ "index": 0,
497
+ "function": {
498
+ "name": "get_weather"
499
+ }
500
+ }
501
+ ]
502
+ },
503
+ "logprobs": null,
504
+ "finish_reason": null,
505
+ "token_ids": [
506
+ 397
507
+ ]
508
+ }
509
+ ]
510
+ },
511
+ {
512
+ "id": "chatcmpl-a08784d157aa41e3",
513
+ "object": "chat.completion.chunk",
514
+ "created": 1790592279,
515
+ "model": "Naive-N0.5-Flash-NVFP4",
516
+ "choices": [
517
+ {
518
+ "index": 0,
519
+ "delta": {},
520
+ "logprobs": null,
521
+ "finish_reason": null,
522
+ "token_ids": [
523
+ 27
524
+ ]
525
+ }
526
+ ]
527
+ },
528
+ {
529
+ "id": "chatcmpl-a08784d157aa41e3",
530
+ "object": "chat.completion.chunk",
531
+ "created": 1790592279,
532
+ "model": "Naive-N0.5-Flash-NVFP4",
533
+ "choices": [
534
+ {
535
+ "index": 0,
536
+ "delta": {},
537
+ "logprobs": null,
538
+ "finish_reason": null,
539
+ "token_ids": [
540
+ 16181
541
+ ]
542
+ }
543
+ ]
544
+ },
545
+ {
546
+ "id": "chatcmpl-a08784d157aa41e3",
547
+ "object": "chat.completion.chunk",
548
+ "created": 1790592279,
549
+ "model": "Naive-N0.5-Flash-NVFP4",
550
+ "choices": [
551
+ {
552
+ "index": 0,
553
+ "delta": {},
554
+ "logprobs": null,
555
+ "finish_reason": null,
556
+ "token_ids": [
557
+ 28
558
+ ]
559
+ }
560
+ ]
561
+ },
562
+ {
563
+ "id": "chatcmpl-a08784d157aa41e3",
564
+ "object": "chat.completion.chunk",
565
+ "created": 1790592279,
566
+ "model": "Naive-N0.5-Flash-NVFP4",
567
+ "choices": [
568
+ {
569
+ "index": 0,
570
+ "delta": {},
571
+ "logprobs": null,
572
+ "finish_reason": null,
573
+ "token_ids": [
574
+ 8926
575
+ ]
576
+ }
577
+ ]
578
+ },
579
+ {
580
+ "id": "chatcmpl-a08784d157aa41e3",
581
+ "object": "chat.completion.chunk",
582
+ "created": 1790592279,
583
+ "model": "Naive-N0.5-Flash-NVFP4",
584
+ "choices": [
585
+ {
586
+ "index": 0,
587
+ "delta": {
588
+ "tool_calls": [
589
+ {
590
+ "index": 0,
591
+ "function": {
592
+ "arguments": "{\"city\": \""
593
+ }
594
+ }
595
+ ]
596
+ },
597
+ "logprobs": null,
598
+ "finish_reason": null,
599
+ "token_ids": [
600
+ 29
601
+ ]
602
+ }
603
+ ]
604
+ },
605
+ {
606
+ "id": "chatcmpl-a08784d157aa41e3",
607
+ "object": "chat.completion.chunk",
608
+ "created": 1790592279,
609
+ "model": "Naive-N0.5-Flash-NVFP4",
610
+ "choices": [
611
+ {
612
+ "index": 0,
613
+ "delta": {
614
+ "tool_calls": [
615
+ {
616
+ "index": 0,
617
+ "function": {
618
+ "arguments": "Wars"
619
+ }
620
+ }
621
+ ]
622
+ },
623
+ "logprobs": null,
624
+ "finish_reason": null,
625
+ "token_ids": [
626
+ 98970
627
+ ]
628
+ }
629
+ ]
630
+ },
631
+ {
632
+ "id": "chatcmpl-a08784d157aa41e3",
633
+ "object": "chat.completion.chunk",
634
+ "created": 1790592279,
635
+ "model": "Naive-N0.5-Flash-NVFP4",
636
+ "choices": [
637
+ {
638
+ "index": 0,
639
+ "delta": {
640
+ "tool_calls": [
641
+ {
642
+ "index": 0,
643
+ "function": {
644
+ "arguments": "aw"
645
+ }
646
+ }
647
+ ]
648
+ },
649
+ "logprobs": null,
650
+ "finish_reason": null,
651
+ "token_ids": [
652
+ 672
653
+ ]
654
+ }
655
+ ]
656
+ },
657
+ {
658
+ "id": "chatcmpl-a08784d157aa41e3",
659
+ "object": "chat.completion.chunk",
660
+ "created": 1790592279,
661
+ "model": "Naive-N0.5-Flash-NVFP4",
662
+ "choices": [
663
+ {
664
+ "index": 0,
665
+ "delta": {},
666
+ "logprobs": null,
667
+ "finish_reason": null,
668
+ "token_ids": [
669
+ 522
670
+ ]
671
+ }
672
+ ]
673
+ },
674
+ {
675
+ "id": "chatcmpl-a08784d157aa41e3",
676
+ "object": "chat.completion.chunk",
677
+ "created": 1790592279,
678
+ "model": "Naive-N0.5-Flash-NVFP4",
679
+ "choices": [
680
+ {
681
+ "index": 0,
682
+ "delta": {},
683
+ "logprobs": null,
684
+ "finish_reason": null,
685
+ "token_ids": [
686
+ 16181
687
+ ]
688
+ }
689
+ ]
690
+ },
691
+ {
692
+ "id": "chatcmpl-a08784d157aa41e3",
693
+ "object": "chat.completion.chunk",
694
+ "created": 1790592279,
695
+ "model": "Naive-N0.5-Flash-NVFP4",
696
+ "choices": [
697
+ {
698
+ "index": 0,
699
+ "delta": {},
700
+ "logprobs": null,
701
+ "finish_reason": null,
702
+ "token_ids": [
703
+ 397
704
+ ]
705
+ }
706
+ ]
707
+ },
708
+ {
709
+ "id": "chatcmpl-a08784d157aa41e3",
710
+ "object": "chat.completion.chunk",
711
+ "created": 1790592279,
712
+ "model": "Naive-N0.5-Flash-NVFP4",
713
+ "choices": [
714
+ {
715
+ "index": 0,
716
+ "delta": {},
717
+ "logprobs": null,
718
+ "finish_reason": null,
719
+ "token_ids": [
720
+ 522
721
+ ]
722
+ }
723
+ ]
724
+ },
725
+ {
726
+ "id": "chatcmpl-a08784d157aa41e3",
727
+ "object": "chat.completion.chunk",
728
+ "created": 1790592279,
729
+ "model": "Naive-N0.5-Flash-NVFP4",
730
+ "choices": [
731
+ {
732
+ "index": 0,
733
+ "delta": {},
734
+ "logprobs": null,
735
+ "finish_reason": null,
736
+ "token_ids": [
737
+ 1688
738
+ ]
739
+ }
740
+ ]
741
+ },
742
+ {
743
+ "id": "chatcmpl-a08784d157aa41e3",
744
+ "object": "chat.completion.chunk",
745
+ "created": 1790592279,
746
+ "model": "Naive-N0.5-Flash-NVFP4",
747
+ "choices": [
748
+ {
749
+ "index": 0,
750
+ "delta": {
751
+ "tool_calls": [
752
+ {
753
+ "index": 0,
754
+ "function": {
755
+ "arguments": "\"}"
756
+ }
757
+ }
758
+ ]
759
+ },
760
+ "logprobs": null,
761
+ "finish_reason": null,
762
+ "token_ids": [
763
+ 397
764
+ ]
765
+ }
766
+ ]
767
+ },
768
+ {
769
+ "id": "chatcmpl-a08784d157aa41e3",
770
+ "object": "chat.completion.chunk",
771
+ "created": 1790592279,
772
+ "model": "Naive-N0.5-Flash-NVFP4",
773
+ "choices": [
774
+ {
775
+ "index": 0,
776
+ "delta": {},
777
+ "logprobs": null,
778
+ "finish_reason": null,
779
+ "token_ids": [
780
+ 151658
781
+ ]
782
+ }
783
+ ]
784
+ },
785
+ {
786
+ "id": "chatcmpl-a08784d157aa41e3",
787
+ "object": "chat.completion.chunk",
788
+ "created": 1790592279,
789
+ "model": "Naive-N0.5-Flash-NVFP4",
790
+ "choices": [
791
+ {
792
+ "index": 0,
793
+ "delta": {},
794
+ "logprobs": null,
795
+ "finish_reason": "tool_calls",
796
+ "stop_reason": null,
797
+ "token_ids": [
798
+ 151645
799
+ ]
800
+ }
801
+ ]
802
+ },
803
+ {
804
+ "id": "chatcmpl-a08784d157aa41e3",
805
+ "object": "chat.completion.chunk",
806
+ "created": 1790592279,
807
+ "model": "Naive-N0.5-Flash-NVFP4",
808
+ "choices": [],
809
+ "usage": {
810
+ "prompt_tokens": 282,
811
+ "total_tokens": 305,
812
+ "completion_tokens": 23,
813
+ "completion_tokens_details": {
814
+ "reasoning_tokens": 0
815
+ }
816
+ },
817
+ "system_fingerprint": "vllm-0.28.0-tp4-13be3b5b"
818
+ }
819
+ ]
820
+ },
821
+ "thinking": {
822
+ "request": {
823
+ "model": "Naive-N0.5-Flash-NVFP4",
824
+ "messages": [
825
+ {
826
+ "role": "user",
827
+ "content": "Calculate 6 times 7. Think briefly, then give the answer."
828
+ }
829
+ ],
830
+ "temperature": 0,
831
+ "max_tokens": 256,
832
+ "stream": true,
833
+ "stream_options": {
834
+ "include_usage": true
835
+ },
836
+ "return_token_ids": true,
837
+ "chat_template_kwargs": {
838
+ "enable_thinking": true
839
+ },
840
+ "reasoning_effort": "low"
841
+ },
842
+ "content": "\n\n42",
843
+ "reasoning": "\nWe need answer simple. Need think briefly then answer. 6*7=42. Final concise.\n",
844
+ "tool_calls": {},
845
+ "usage": {
846
+ "prompt_tokens": 57,
847
+ "total_tokens": 86,
848
+ "completion_tokens": 29,
849
+ "completion_tokens_details": {
850
+ "reasoning_tokens": 23
851
+ }
852
+ },
853
+ "events": [
854
+ {
855
+ "id": "chatcmpl-a9f0496c02f6b857",
856
+ "object": "chat.completion.chunk",
857
+ "created": 1790592280,
858
+ "model": "Naive-N0.5-Flash-NVFP4",
859
+ "choices": [
860
+ {
861
+ "index": 0,
862
+ "delta": {
863
+ "role": "assistant",
864
+ "content": ""
865
+ },
866
+ "logprobs": null,
867
+ "finish_reason": null
868
+ }
869
+ ],
870
+ "prompt_token_ids": [
871
+ 151644,
872
+ 8948,
873
+ 198,
874
+ 25139,
875
+ 287,
876
+ 30022,
877
+ 371,
878
+ 25,
879
+ 12041,
880
+ 151645,
881
+ 151644,
882
+ 8948,
883
+ 198,
884
+ 2610,
885
+ 525,
886
+ 12812,
887
+ 533,
888
+ 11250,
889
+ 15,
890
+ 13,
891
+ 20,
892
+ 12,
893
+ 23876,
894
+ 11,
895
+ 264,
896
+ 10950,
897
+ 15235,
898
+ 17847,
899
+ 44936,
900
+ 553,
901
+ 12812,
902
+ 533,
903
+ 15235,
904
+ 13,
905
+ 151645,
906
+ 151644,
907
+ 872,
908
+ 198,
909
+ 47866,
910
+ 220,
911
+ 21,
912
+ 3039,
913
+ 220,
914
+ 22,
915
+ 13,
916
+ 21149,
917
+ 26753,
918
+ 11,
919
+ 1221,
920
+ 2968,
921
+ 279,
922
+ 4226,
923
+ 13,
924
+ 151645,
925
+ 151644,
926
+ 77091,
927
+ 198
928
+ ],
929
+ "prompt_text": null
930
+ },
931
+ {
932
+ "id": "chatcmpl-a9f0496c02f6b857",
933
+ "object": "chat.completion.chunk",
934
+ "created": 1790592280,
935
+ "model": "Naive-N0.5-Flash-NVFP4",
936
+ "choices": [
937
+ {
938
+ "index": 0,
939
+ "delta": {},
940
+ "logprobs": null,
941
+ "finish_reason": null,
942
+ "token_ids": [
943
+ 151667
944
+ ]
945
+ }
946
+ ]
947
+ },
948
+ {
949
+ "id": "chatcmpl-a9f0496c02f6b857",
950
+ "object": "chat.completion.chunk",
951
+ "created": 1790592280,
952
+ "model": "Naive-N0.5-Flash-NVFP4",
953
+ "choices": [
954
+ {
955
+ "index": 0,
956
+ "delta": {
957
+ "reasoning": "\n"
958
+ },
959
+ "logprobs": null,
960
+ "finish_reason": null,
961
+ "token_ids": [
962
+ 198
963
+ ]
964
+ }
965
+ ]
966
+ },
967
+ {
968
+ "id": "chatcmpl-a9f0496c02f6b857",
969
+ "object": "chat.completion.chunk",
970
+ "created": 1790592280,
971
+ "model": "Naive-N0.5-Flash-NVFP4",
972
+ "choices": [
973
+ {
974
+ "index": 0,
975
+ "delta": {
976
+ "reasoning": "We"
977
+ },
978
+ "logprobs": null,
979
+ "finish_reason": null,
980
+ "token_ids": [
981
+ 1654
982
+ ]
983
+ }
984
+ ]
985
+ },
986
+ {
987
+ "id": "chatcmpl-a9f0496c02f6b857",
988
+ "object": "chat.completion.chunk",
989
+ "created": 1790592280,
990
+ "model": "Naive-N0.5-Flash-NVFP4",
991
+ "choices": [
992
+ {
993
+ "index": 0,
994
+ "delta": {
995
+ "reasoning": " need"
996
+ },
997
+ "logprobs": null,
998
+ "finish_reason": null,
999
+ "token_ids": [
1000
+ 1184
1001
+ ]
1002
+ }
1003
+ ]
1004
+ },
1005
+ {
1006
+ "id": "chatcmpl-a9f0496c02f6b857",
1007
+ "object": "chat.completion.chunk",
1008
+ "created": 1790592280,
1009
+ "model": "Naive-N0.5-Flash-NVFP4",
1010
+ "choices": [
1011
+ {
1012
+ "index": 0,
1013
+ "delta": {
1014
+ "reasoning": " answer"
1015
+ },
1016
+ "logprobs": null,
1017
+ "finish_reason": null,
1018
+ "token_ids": [
1019
+ 4226
1020
+ ]
1021
+ }
1022
+ ]
1023
+ },
1024
+ {
1025
+ "id": "chatcmpl-a9f0496c02f6b857",
1026
+ "object": "chat.completion.chunk",
1027
+ "created": 1790592280,
1028
+ "model": "Naive-N0.5-Flash-NVFP4",
1029
+ "choices": [
1030
+ {
1031
+ "index": 0,
1032
+ "delta": {
1033
+ "reasoning": " simple"
1034
+ },
1035
+ "logprobs": null,
1036
+ "finish_reason": null,
1037
+ "token_ids": [
1038
+ 4285
1039
+ ]
1040
+ }
1041
+ ]
1042
+ },
1043
+ {
1044
+ "id": "chatcmpl-a9f0496c02f6b857",
1045
+ "object": "chat.completion.chunk",
1046
+ "created": 1790592280,
1047
+ "model": "Naive-N0.5-Flash-NVFP4",
1048
+ "choices": [
1049
+ {
1050
+ "index": 0,
1051
+ "delta": {
1052
+ "reasoning": "."
1053
+ },
1054
+ "logprobs": null,
1055
+ "finish_reason": null,
1056
+ "token_ids": [
1057
+ 13
1058
+ ]
1059
+ }
1060
+ ]
1061
+ },
1062
+ {
1063
+ "id": "chatcmpl-a9f0496c02f6b857",
1064
+ "object": "chat.completion.chunk",
1065
+ "created": 1790592280,
1066
+ "model": "Naive-N0.5-Flash-NVFP4",
1067
+ "choices": [
1068
+ {
1069
+ "index": 0,
1070
+ "delta": {
1071
+ "reasoning": " Need"
1072
+ },
1073
+ "logprobs": null,
1074
+ "finish_reason": null,
1075
+ "token_ids": [
1076
+ 14656
1077
+ ]
1078
+ }
1079
+ ]
1080
+ },
1081
+ {
1082
+ "id": "chatcmpl-a9f0496c02f6b857",
1083
+ "object": "chat.completion.chunk",
1084
+ "created": 1790592280,
1085
+ "model": "Naive-N0.5-Flash-NVFP4",
1086
+ "choices": [
1087
+ {
1088
+ "index": 0,
1089
+ "delta": {
1090
+ "reasoning": " think"
1091
+ },
1092
+ "logprobs": null,
1093
+ "finish_reason": null,
1094
+ "token_ids": [
1095
+ 1744
1096
+ ]
1097
+ }
1098
+ ]
1099
+ },
1100
+ {
1101
+ "id": "chatcmpl-a9f0496c02f6b857",
1102
+ "object": "chat.completion.chunk",
1103
+ "created": 1790592280,
1104
+ "model": "Naive-N0.5-Flash-NVFP4",
1105
+ "choices": [
1106
+ {
1107
+ "index": 0,
1108
+ "delta": {
1109
+ "reasoning": " briefly"
1110
+ },
1111
+ "logprobs": null,
1112
+ "finish_reason": null,
1113
+ "token_ids": [
1114
+ 26753
1115
+ ]
1116
+ }
1117
+ ]
1118
+ },
1119
+ {
1120
+ "id": "chatcmpl-a9f0496c02f6b857",
1121
+ "object": "chat.completion.chunk",
1122
+ "created": 1790592280,
1123
+ "model": "Naive-N0.5-Flash-NVFP4",
1124
+ "choices": [
1125
+ {
1126
+ "index": 0,
1127
+ "delta": {
1128
+ "reasoning": " then"
1129
+ },
1130
+ "logprobs": null,
1131
+ "finish_reason": null,
1132
+ "token_ids": [
1133
+ 1221
1134
+ ]
1135
+ }
1136
+ ]
1137
+ },
1138
+ {
1139
+ "id": "chatcmpl-a9f0496c02f6b857",
1140
+ "object": "chat.completion.chunk",
1141
+ "created": 1790592280,
1142
+ "model": "Naive-N0.5-Flash-NVFP4",
1143
+ "choices": [
1144
+ {
1145
+ "index": 0,
1146
+ "delta": {
1147
+ "reasoning": " answer"
1148
+ },
1149
+ "logprobs": null,
1150
+ "finish_reason": null,
1151
+ "token_ids": [
1152
+ 4226
1153
+ ]
1154
+ }
1155
+ ]
1156
+ },
1157
+ {
1158
+ "id": "chatcmpl-a9f0496c02f6b857",
1159
+ "object": "chat.completion.chunk",
1160
+ "created": 1790592280,
1161
+ "model": "Naive-N0.5-Flash-NVFP4",
1162
+ "choices": [
1163
+ {
1164
+ "index": 0,
1165
+ "delta": {
1166
+ "reasoning": "."
1167
+ },
1168
+ "logprobs": null,
1169
+ "finish_reason": null,
1170
+ "token_ids": [
1171
+ 13
1172
+ ]
1173
+ }
1174
+ ]
1175
+ },
1176
+ {
1177
+ "id": "chatcmpl-a9f0496c02f6b857",
1178
+ "object": "chat.completion.chunk",
1179
+ "created": 1790592280,
1180
+ "model": "Naive-N0.5-Flash-NVFP4",
1181
+ "choices": [
1182
+ {
1183
+ "index": 0,
1184
+ "delta": {
1185
+ "reasoning": " "
1186
+ },
1187
+ "logprobs": null,
1188
+ "finish_reason": null,
1189
+ "token_ids": [
1190
+ 220
1191
+ ]
1192
+ }
1193
+ ]
1194
+ },
1195
+ {
1196
+ "id": "chatcmpl-a9f0496c02f6b857",
1197
+ "object": "chat.completion.chunk",
1198
+ "created": 1790592280,
1199
+ "model": "Naive-N0.5-Flash-NVFP4",
1200
+ "choices": [
1201
+ {
1202
+ "index": 0,
1203
+ "delta": {
1204
+ "reasoning": "6"
1205
+ },
1206
+ "logprobs": null,
1207
+ "finish_reason": null,
1208
+ "token_ids": [
1209
+ 21
1210
+ ]
1211
+ }
1212
+ ]
1213
+ },
1214
+ {
1215
+ "id": "chatcmpl-a9f0496c02f6b857",
1216
+ "object": "chat.completion.chunk",
1217
+ "created": 1790592280,
1218
+ "model": "Naive-N0.5-Flash-NVFP4",
1219
+ "choices": [
1220
+ {
1221
+ "index": 0,
1222
+ "delta": {
1223
+ "reasoning": "*"
1224
+ },
1225
+ "logprobs": null,
1226
+ "finish_reason": null,
1227
+ "token_ids": [
1228
+ 9
1229
+ ]
1230
+ }
1231
+ ]
1232
+ },
1233
+ {
1234
+ "id": "chatcmpl-a9f0496c02f6b857",
1235
+ "object": "chat.completion.chunk",
1236
+ "created": 1790592280,
1237
+ "model": "Naive-N0.5-Flash-NVFP4",
1238
+ "choices": [
1239
+ {
1240
+ "index": 0,
1241
+ "delta": {
1242
+ "reasoning": "7"
1243
+ },
1244
+ "logprobs": null,
1245
+ "finish_reason": null,
1246
+ "token_ids": [
1247
+ 22
1248
+ ]
1249
+ }
1250
+ ]
1251
+ },
1252
+ {
1253
+ "id": "chatcmpl-a9f0496c02f6b857",
1254
+ "object": "chat.completion.chunk",
1255
+ "created": 1790592280,
1256
+ "model": "Naive-N0.5-Flash-NVFP4",
1257
+ "choices": [
1258
+ {
1259
+ "index": 0,
1260
+ "delta": {
1261
+ "reasoning": "="
1262
+ },
1263
+ "logprobs": null,
1264
+ "finish_reason": null,
1265
+ "token_ids": [
1266
+ 28
1267
+ ]
1268
+ }
1269
+ ]
1270
+ },
1271
+ {
1272
+ "id": "chatcmpl-a9f0496c02f6b857",
1273
+ "object": "chat.completion.chunk",
1274
+ "created": 1790592280,
1275
+ "model": "Naive-N0.5-Flash-NVFP4",
1276
+ "choices": [
1277
+ {
1278
+ "index": 0,
1279
+ "delta": {
1280
+ "reasoning": "4"
1281
+ },
1282
+ "logprobs": null,
1283
+ "finish_reason": null,
1284
+ "token_ids": [
1285
+ 19
1286
+ ]
1287
+ }
1288
+ ]
1289
+ },
1290
+ {
1291
+ "id": "chatcmpl-a9f0496c02f6b857",
1292
+ "object": "chat.completion.chunk",
1293
+ "created": 1790592280,
1294
+ "model": "Naive-N0.5-Flash-NVFP4",
1295
+ "choices": [
1296
+ {
1297
+ "index": 0,
1298
+ "delta": {
1299
+ "reasoning": "2"
1300
+ },
1301
+ "logprobs": null,
1302
+ "finish_reason": null,
1303
+ "token_ids": [
1304
+ 17
1305
+ ]
1306
+ }
1307
+ ]
1308
+ },
1309
+ {
1310
+ "id": "chatcmpl-a9f0496c02f6b857",
1311
+ "object": "chat.completion.chunk",
1312
+ "created": 1790592280,
1313
+ "model": "Naive-N0.5-Flash-NVFP4",
1314
+ "choices": [
1315
+ {
1316
+ "index": 0,
1317
+ "delta": {
1318
+ "reasoning": "."
1319
+ },
1320
+ "logprobs": null,
1321
+ "finish_reason": null,
1322
+ "token_ids": [
1323
+ 13
1324
+ ]
1325
+ }
1326
+ ]
1327
+ },
1328
+ {
1329
+ "id": "chatcmpl-a9f0496c02f6b857",
1330
+ "object": "chat.completion.chunk",
1331
+ "created": 1790592280,
1332
+ "model": "Naive-N0.5-Flash-NVFP4",
1333
+ "choices": [
1334
+ {
1335
+ "index": 0,
1336
+ "delta": {
1337
+ "reasoning": " Final"
1338
+ },
1339
+ "logprobs": null,
1340
+ "finish_reason": null,
1341
+ "token_ids": [
1342
+ 13023
1343
+ ]
1344
+ }
1345
+ ]
1346
+ },
1347
+ {
1348
+ "id": "chatcmpl-a9f0496c02f6b857",
1349
+ "object": "chat.completion.chunk",
1350
+ "created": 1790592280,
1351
+ "model": "Naive-N0.5-Flash-NVFP4",
1352
+ "choices": [
1353
+ {
1354
+ "index": 0,
1355
+ "delta": {
1356
+ "reasoning": " concise"
1357
+ },
1358
+ "logprobs": null,
1359
+ "finish_reason": null,
1360
+ "token_ids": [
1361
+ 63594
1362
+ ]
1363
+ }
1364
+ ]
1365
+ },
1366
+ {
1367
+ "id": "chatcmpl-a9f0496c02f6b857",
1368
+ "object": "chat.completion.chunk",
1369
+ "created": 1790592280,
1370
+ "model": "Naive-N0.5-Flash-NVFP4",
1371
+ "choices": [
1372
+ {
1373
+ "index": 0,
1374
+ "delta": {
1375
+ "reasoning": ".\n"
1376
+ },
1377
+ "logprobs": null,
1378
+ "finish_reason": null,
1379
+ "token_ids": [
1380
+ 624
1381
+ ]
1382
+ }
1383
+ ]
1384
+ },
1385
+ {
1386
+ "id": "chatcmpl-a9f0496c02f6b857",
1387
+ "object": "chat.completion.chunk",
1388
+ "created": 1790592280,
1389
+ "model": "Naive-N0.5-Flash-NVFP4",
1390
+ "choices": [
1391
+ {
1392
+ "index": 0,
1393
+ "delta": {},
1394
+ "logprobs": null,
1395
+ "finish_reason": null,
1396
+ "token_ids": [
1397
+ 151668
1398
+ ]
1399
+ }
1400
+ ]
1401
+ },
1402
+ {
1403
+ "id": "chatcmpl-a9f0496c02f6b857",
1404
+ "object": "chat.completion.chunk",
1405
+ "created": 1790592280,
1406
+ "model": "Naive-N0.5-Flash-NVFP4",
1407
+ "choices": [
1408
+ {
1409
+ "index": 0,
1410
+ "delta": {},
1411
+ "logprobs": null,
1412
+ "finish_reason": null,
1413
+ "token_ids": [
1414
+ 271
1415
+ ]
1416
+ }
1417
+ ]
1418
+ },
1419
+ {
1420
+ "id": "chatcmpl-a9f0496c02f6b857",
1421
+ "object": "chat.completion.chunk",
1422
+ "created": 1790592280,
1423
+ "model": "Naive-N0.5-Flash-NVFP4",
1424
+ "choices": [
1425
+ {
1426
+ "index": 0,
1427
+ "delta": {
1428
+ "content": "\n\n4"
1429
+ },
1430
+ "logprobs": null,
1431
+ "finish_reason": null,
1432
+ "token_ids": [
1433
+ 19
1434
+ ]
1435
+ }
1436
+ ]
1437
+ },
1438
+ {
1439
+ "id": "chatcmpl-a9f0496c02f6b857",
1440
+ "object": "chat.completion.chunk",
1441
+ "created": 1790592280,
1442
+ "model": "Naive-N0.5-Flash-NVFP4",
1443
+ "choices": [
1444
+ {
1445
+ "index": 0,
1446
+ "delta": {
1447
+ "content": "2"
1448
+ },
1449
+ "logprobs": null,
1450
+ "finish_reason": null,
1451
+ "token_ids": [
1452
+ 17
1453
+ ]
1454
+ }
1455
+ ]
1456
+ },
1457
+ {
1458
+ "id": "chatcmpl-a9f0496c02f6b857",
1459
+ "object": "chat.completion.chunk",
1460
+ "created": 1790592280,
1461
+ "model": "Naive-N0.5-Flash-NVFP4",
1462
+ "choices": [
1463
+ {
1464
+ "index": 0,
1465
+ "delta": {},
1466
+ "logprobs": null,
1467
+ "finish_reason": "stop",
1468
+ "stop_reason": null,
1469
+ "token_ids": [
1470
+ 151645
1471
+ ]
1472
+ }
1473
+ ]
1474
+ },
1475
+ {
1476
+ "id": "chatcmpl-a9f0496c02f6b857",
1477
+ "object": "chat.completion.chunk",
1478
+ "created": 1790592280,
1479
+ "model": "Naive-N0.5-Flash-NVFP4",
1480
+ "choices": [],
1481
+ "usage": {
1482
+ "prompt_tokens": 57,
1483
+ "total_tokens": 86,
1484
+ "completion_tokens": 29,
1485
+ "completion_tokens_details": {
1486
+ "reasoning_tokens": 23
1487
+ }
1488
+ },
1489
+ "system_fingerprint": "vllm-0.28.0-tp4-13be3b5b"
1490
+ }
1491
+ ]
1492
+ }
1493
+ }
validation/portable-preflight.json ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "passed": true,
3
+ "versions": {
4
+ "vllm": "0.28.0",
5
+ "torch": "2.13.0+cu130",
6
+ "transformers": "5.17.0",
7
+ "accelerate": "1.15.0",
8
+ "tokenizers": "0.23.2",
9
+ "huggingface-hub": "1.33.0",
10
+ "safetensors": "0.8.0",
11
+ "flashinfer-python": "0.7.0",
12
+ "nvidia-cutlass-dsl": "4.6.2",
13
+ "triton": "3.7.1"
14
+ },
15
+ "gpus": [
16
+ {
17
+ "index": 0,
18
+ "name": "NVIDIA RTX PRO 6000 Blackwell Max-Q Workstation Edition",
19
+ "memory_bytes": 101973491712
20
+ },
21
+ {
22
+ "index": 1,
23
+ "name": "NVIDIA RTX PRO 6000 Blackwell Max-Q Workstation Edition",
24
+ "memory_bytes": 101973491712
25
+ },
26
+ {
27
+ "index": 2,
28
+ "name": "NVIDIA RTX PRO 6000 Blackwell Max-Q Workstation Edition",
29
+ "memory_bytes": 101970345984
30
+ },
31
+ {
32
+ "index": 3,
33
+ "name": "NVIDIA RTX PRO 6000 Blackwell Max-Q Workstation Edition",
34
+ "memory_bytes": 101973491712
35
+ }
36
+ ],
37
+ "shards": 49,
38
+ "tensors": 144856
39
+ }
validation/preserved-weights-validation.json ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "passed": true,
3
+ "tensors_checked": 472,
4
+ "restored_from_source": {
5
+ "model-layer-00047.safetensors": [
6
+ "model.layers.47.mlp.gate.weight"
7
+ ]
8
+ },
9
+ "check": "Exact source dtype, shape and SHA-256 of tensor payload"
10
+ }
validation/runtime-source-validation.json ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "passed": true,
3
+ "scope": "Active native vLLM container module bytes match published source files",
4
+ "files": {
5
+ "vllm_naive/attention.py": "f3aa650b110495224338b211330f6dcb7598cbeff917e7b1dac77695234f187c",
6
+ "vllm_naive/__init__.py": "8a5fddf2b89a4c33b6774a3ed75004a73db990ee711b8411e8772d7f2786f679",
7
+ "vllm_naive/model.py": "f0d5769018f8487c267d0ee6c3ba4cbf138e47d65c35c0cc0a00a95dfb69d763",
8
+ "scripts/benchmark_stream.py": "dab13abe554c6c28f89268ee3a2cec2e6425f73aa91f18692318b76886704157",
9
+ "scripts/safe_device_transfer.py": "61e931597e59e72ded3525976181e7164933e72f4647423c00ad2be0a57940db",
10
+ "scripts/decode_kernels.py": "ea0e71f5c4fd678b5cdf423b62ad07d37bed7de5fdc2af9ee89f08856ee34d09",
11
+ "scripts/validate_api.py": "82e04b0d21e9956da18930e27d35c4fc45f1a4b071bd2a19c6f62271deb74c2d",
12
+ "scripts/nvfp4_runtime.py": "be6453ca83d8f9ec528b07f17e78a41bfdcd8859fa9ec2644b6136e7068e9a1a",
13
+ "scripts/fused_experts.py": "f77eceec0a969eb7ff99e5177bd9d4cda1bfa3f0668ed614c060d28883f46018",
14
+ "scripts/preflight.py": "43ac170da1d7cf614fb5f4d7f0ee70635d2d78bd638bfb3af2322baf91a08600",
15
+ "sitecustomize.py": "552485e6e5e03c72c1d8b76a43a1ede48f8283a5d1e5ab93761125ec4a2c492b"
16
+ }
17
+ }