Image-Text-to-Text
Transformers
Safetensors
English
Chinese
sensenova_loop
text-generation
nvfp4
modelopt
quantized
multimodal
looped-transformer
mhc
mtp
custom_code
conversational
8-bit precision
Instructions to use gitcommit90/SenseNova-Loop-9B-Preview-NVFP4 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use gitcommit90/SenseNova-Loop-9B-Preview-NVFP4 with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("image-text-to-text", model="gitcommit90/SenseNova-Loop-9B-Preview-NVFP4", trust_remote_code=True) messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] pipe(text=messages)# pip install -U transformers accelerate # Load model directly from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained("gitcommit90/SenseNova-Loop-9B-Preview-NVFP4", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use gitcommit90/SenseNova-Loop-9B-Preview-NVFP4 with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "gitcommit90/SenseNova-Loop-9B-Preview-NVFP4" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "gitcommit90/SenseNova-Loop-9B-Preview-NVFP4", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }'Use Docker
docker model run hf.co/gitcommit90/SenseNova-Loop-9B-Preview-NVFP4
- SGLang
How to use gitcommit90/SenseNova-Loop-9B-Preview-NVFP4 with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "gitcommit90/SenseNova-Loop-9B-Preview-NVFP4" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "gitcommit90/SenseNova-Loop-9B-Preview-NVFP4", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "gitcommit90/SenseNova-Loop-9B-Preview-NVFP4" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "gitcommit90/SenseNova-Loop-9B-Preview-NVFP4", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }' - Docker Model Runner
How to use gitcommit90/SenseNova-Loop-9B-Preview-NVFP4 with Docker Model Runner:
docker model run hf.co/gitcommit90/SenseNova-Loop-9B-Preview-NVFP4
NVFP4 (ModelOpt) quantization of sensenova/SenseNova-Loop-9B-Preview @27abea77 with BF16 MTP head
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .gitattributes +11 -0
- LICENSE +201 -0
- README.md +186 -0
- SHA256SUMS +65 -0
- chat_template.jinja +154 -0
- config.json +261 -0
- evaluation/QUALITY_GATES.md +14 -0
- evaluation/compare_vs_ref.json +138 -0
- evaluation/eval_data_MANIFEST.json +67 -0
- evaluation/harness/build_eval_data.py +139 -0
- evaluation/harness/common.py +177 -0
- evaluation/harness/compare.py +133 -0
- evaluation/harness/ifeval_lite.py +236 -0
- evaluation/harness/mock_server.py +171 -0
- evaluation/harness/perf_bench.py +188 -0
- evaluation/harness/requirements.lock +48 -0
- evaluation/harness/run_eval.py +139 -0
- evaluation/harness/tasks.py +284 -0
- evaluation/harness/test_harness.py +147 -0
- evaluation/harness/tool_cases.py +116 -0
- evaluation/hf_bf16_checks.json +85 -0
- evaluation/kernel_summary.txt +28 -0
- evaluation/nvfp4_v1_mtp_release_probe.json +82 -0
- evaluation/nvfp4_v1_probe.json +82 -0
- evaluation/perf_sglang_bf16.json +170 -0
- evaluation/perf_sglang_bf16_mtp.json +170 -0
- evaluation/perf_sglang_nvfp4_v1.json +170 -0
- evaluation/perf_sglang_nvfp4_v1_marlin_w4a16.json +98 -0
- evaluation/perf_sglang_nvfp4_v1_mtp.json +170 -0
- evaluation/sglang_bf16_mtp_probe.json +82 -0
- evaluation/sglang_bf16_probe.json +82 -0
- evaluation/summary_sglang_bf16.json +148 -0
- evaluation/summary_sglang_bf16_mtp.json +103 -0
- evaluation/summary_sglang_nvfp4_v1.json +148 -0
- evaluation/summary_sglang_nvfp4_v1_marlin_w4a16_gsm8k.json +62 -0
- evaluation/summary_sglang_nvfp4_v1_mtp.json +103 -0
- generation_config.json +12 -0
- hf_quant_config.json +103 -0
- model.safetensors +3 -0
- modeling_sensenova_loop.py +395 -0
- preprocessor_config.json +26 -0
- processor_config.json +60 -0
- quantization/10_reference_checks.py +92 -0
- quantization/20_quantize.py +134 -0
- quantization/30_verify_export.py +126 -0
- quantization/build_calib.py +329 -0
- quantization/calib_v1.jsonl.sha256 +1 -0
- quantization/calib_v1.meta.json +72 -0
- quantization/quantization_stats.json +389 -0
- quantization/requirements-quant.lock +107 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,14 @@ 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 |
+
assets/loop-mhc-overview.jpg filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
assets/loop9b-benchmark-results.png filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
examples/chocolate/chocolate-horizontal.jpg filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
examples/energy-analysis/energy-analysis.png filter=lfs diff=lfs merge=lfs -text
|
| 40 |
+
examples/iceland/iceland-horizontal-v2.jpg filter=lfs diff=lfs merge=lfs -text
|
| 41 |
+
examples/ink-journey/ink-journey-demo.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 42 |
+
examples/ink-journey/ink-journey-preview.gif filter=lfs diff=lfs merge=lfs -text
|
| 43 |
+
examples/moon-simulation/moon-simulation.gif filter=lfs diff=lfs merge=lfs -text
|
| 44 |
+
examples/teacher-day/teacher-day-horizontal.jpg filter=lfs diff=lfs merge=lfs -text
|
| 45 |
+
tokenizer.json filter=lfs diff=lfs merge=lfs -text
|
| 46 |
+
examples/odyssey/odyssey-preview.gif filter=lfs diff=lfs merge=lfs -text
|
LICENSE
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Apache License
|
| 2 |
+
Version 2.0, January 2004
|
| 3 |
+
http://www.apache.org/licenses/
|
| 4 |
+
|
| 5 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
| 6 |
+
|
| 7 |
+
1. Definitions.
|
| 8 |
+
|
| 9 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
| 10 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
| 11 |
+
|
| 12 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
| 13 |
+
the copyright owner that is granting the License.
|
| 14 |
+
|
| 15 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
| 16 |
+
other entities that control, are controlled by, or are under common
|
| 17 |
+
control with that entity. For the purposes of this definition,
|
| 18 |
+
"control" means (i) the power, direct or indirect, to cause the
|
| 19 |
+
direction or management of such entity, whether by contract or
|
| 20 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
| 21 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
| 22 |
+
|
| 23 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
| 24 |
+
exercising permissions granted by this License.
|
| 25 |
+
|
| 26 |
+
"Source" form shall mean the preferred form for making modifications,
|
| 27 |
+
including but not limited to software source code, documentation
|
| 28 |
+
source, and configuration files.
|
| 29 |
+
|
| 30 |
+
"Object" form shall mean any form resulting from mechanical
|
| 31 |
+
transformation or translation of a Source form, including but
|
| 32 |
+
not limited to compiled object code, generated documentation,
|
| 33 |
+
and conversions to other media types.
|
| 34 |
+
|
| 35 |
+
"Work" shall mean the work of authorship, whether in Source or
|
| 36 |
+
Object form, made available under the License, as indicated by a
|
| 37 |
+
copyright notice that is included in or attached to the work
|
| 38 |
+
(an example is provided in the Appendix below).
|
| 39 |
+
|
| 40 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
| 41 |
+
form, that is based on (or derived from) the Work and for which the
|
| 42 |
+
editorial revisions, annotations, elaborations, or other modifications
|
| 43 |
+
represent, as a whole, an original work of authorship. For the purposes
|
| 44 |
+
of this License, Derivative Works shall not include works that remain
|
| 45 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
| 46 |
+
the Work and Derivative Works thereof.
|
| 47 |
+
|
| 48 |
+
"Contribution" shall mean any work of authorship, including
|
| 49 |
+
the original version of the Work and any modifications or additions
|
| 50 |
+
to that Work or Derivative Works thereof, that is intentionally
|
| 51 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
| 52 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
| 53 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
| 54 |
+
means any form of electronic, verbal, or written communication sent
|
| 55 |
+
to the Licensor or its representatives, including but not limited to
|
| 56 |
+
communication on electronic mailing lists, source code control systems,
|
| 57 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
| 58 |
+
Licensor for the purpose of discussing and improving the Work, but
|
| 59 |
+
excluding communication that is conspicuously marked or otherwise
|
| 60 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
| 61 |
+
|
| 62 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
| 63 |
+
on behalf of whom a Contribution has been received by Licensor and
|
| 64 |
+
subsequently incorporated within the Work.
|
| 65 |
+
|
| 66 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
| 67 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 68 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 69 |
+
copyright license to reproduce, prepare Derivative Works of,
|
| 70 |
+
publicly display, publicly perform, sublicense, and distribute the
|
| 71 |
+
Work and such Derivative Works in Source or Object form.
|
| 72 |
+
|
| 73 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
| 74 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 75 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 76 |
+
(except as stated in this section) patent license to make, have made,
|
| 77 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
| 78 |
+
where such license applies only to those patent claims licensable
|
| 79 |
+
by such Contributor that are necessarily infringed by their
|
| 80 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
| 81 |
+
with the Work to which such Contribution(s) was submitted. If You
|
| 82 |
+
institute patent litigation against any entity (including a
|
| 83 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
| 84 |
+
or a Contribution incorporated within the Work constitutes direct
|
| 85 |
+
or contributory patent infringement, then any patent licenses
|
| 86 |
+
granted to You under this License for that Work shall terminate
|
| 87 |
+
as of the date such litigation is filed.
|
| 88 |
+
|
| 89 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
| 90 |
+
Work or Derivative Works thereof in any medium, with or without
|
| 91 |
+
modifications, and in Source or Object form, provided that You
|
| 92 |
+
meet the following conditions:
|
| 93 |
+
|
| 94 |
+
(a) You must give any other recipients of the Work or
|
| 95 |
+
Derivative Works a copy of this License; and
|
| 96 |
+
|
| 97 |
+
(b) You must cause any modified files to carry prominent notices
|
| 98 |
+
stating that You changed the files; and
|
| 99 |
+
|
| 100 |
+
(c) You must retain, in the Source form of any Derivative Works
|
| 101 |
+
that You distribute, all copyright, patent, trademark, and
|
| 102 |
+
attribution notices from the Source form of the Work,
|
| 103 |
+
excluding those notices that do not pertain to any part of
|
| 104 |
+
the Derivative Works; and
|
| 105 |
+
|
| 106 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
| 107 |
+
distribution, then any Derivative Works that You distribute must
|
| 108 |
+
include a readable copy of the attribution notices contained
|
| 109 |
+
within such NOTICE file, excluding those notices that do not
|
| 110 |
+
pertain to any part of the Derivative Works, in at least one
|
| 111 |
+
of the following places: within a NOTICE text file distributed
|
| 112 |
+
as part of the Derivative Works; within the Source form or
|
| 113 |
+
documentation, if provided along with the Derivative Works; or,
|
| 114 |
+
within a display generated by the Derivative Works, if and
|
| 115 |
+
wherever such third-party notices normally appear. The contents
|
| 116 |
+
of the NOTICE file are for informational purposes only and
|
| 117 |
+
do not modify the License. You may add Your own attribution
|
| 118 |
+
notices within Derivative Works that You distribute, alongside
|
| 119 |
+
or as an addendum to the NOTICE text from the Work, provided
|
| 120 |
+
that such additional attribution notices cannot be construed
|
| 121 |
+
as modifying the License.
|
| 122 |
+
|
| 123 |
+
You may add Your own copyright statement to Your modifications and
|
| 124 |
+
may provide additional or different license terms and conditions
|
| 125 |
+
for use, reproduction, or distribution of Your modifications, or
|
| 126 |
+
for any such Derivative Works as a whole, provided Your use,
|
| 127 |
+
reproduction, and distribution of the Work otherwise complies with
|
| 128 |
+
the conditions stated in this License.
|
| 129 |
+
|
| 130 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
| 131 |
+
any Contribution intentionally submitted for inclusion in the Work
|
| 132 |
+
by You to the Licensor shall be under the terms and conditions of
|
| 133 |
+
this License, without any additional terms or conditions.
|
| 134 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
| 135 |
+
the terms of any separate license agreement you may have executed
|
| 136 |
+
with Licensor regarding such Contributions.
|
| 137 |
+
|
| 138 |
+
6. Trademarks. This License does not grant permission to use the trade
|
| 139 |
+
names, trademarks, service marks, or product names of the Licensor,
|
| 140 |
+
except as required for reasonable and customary use in describing the
|
| 141 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
| 142 |
+
|
| 143 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
| 144 |
+
agreed to in writing, Licensor provides the Work (and each
|
| 145 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
| 146 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
| 147 |
+
implied, including, without limitation, any warranties or conditions
|
| 148 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
| 149 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
| 150 |
+
appropriateness of using or redistributing the Work and assume any
|
| 151 |
+
risks associated with Your exercise of permissions under this License.
|
| 152 |
+
|
| 153 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
| 154 |
+
whether in tort (including negligence), contract, or otherwise,
|
| 155 |
+
unless required by applicable law (such as deliberate and grossly
|
| 156 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
| 157 |
+
liable to You for damages, including any direct, indirect, special,
|
| 158 |
+
incidental, or consequential damages of any character arising as a
|
| 159 |
+
result of this License or out of the use or inability to use the
|
| 160 |
+
Work (including but not limited to damages for loss of goodwill,
|
| 161 |
+
work stoppage, computer failure or malfunction, or any and all
|
| 162 |
+
other commercial damages or losses), even if such Contributor
|
| 163 |
+
has been advised of the possibility of such damages.
|
| 164 |
+
|
| 165 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
| 166 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
| 167 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
| 168 |
+
or other liability obligations and/or rights consistent with this
|
| 169 |
+
License. However, in accepting such obligations, You may act only
|
| 170 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
| 171 |
+
of any other Contributor, and only if You agree to indemnify,
|
| 172 |
+
defend, and hold each Contributor harmless for any liability
|
| 173 |
+
incurred by, or claims asserted against, such Contributor by reason
|
| 174 |
+
of your accepting any such warranty or additional liability.
|
| 175 |
+
|
| 176 |
+
END OF TERMS AND CONDITIONS
|
| 177 |
+
|
| 178 |
+
APPENDIX: How to apply the Apache License to your work.
|
| 179 |
+
|
| 180 |
+
To apply the Apache License to your work, attach the following
|
| 181 |
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
| 182 |
+
replaced with your own identifying information. (Don't include
|
| 183 |
+
the brackets!) The text should be enclosed in the appropriate
|
| 184 |
+
comment syntax for the file format. We also recommend that a
|
| 185 |
+
file or class name and description of purpose be included on the
|
| 186 |
+
same "printed page" as the copyright notice for easier
|
| 187 |
+
identification within third-party archives.
|
| 188 |
+
|
| 189 |
+
Copyright [yyyy] [name of copyright owner]
|
| 190 |
+
|
| 191 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
| 192 |
+
you may not use this file except in compliance with the License.
|
| 193 |
+
You may obtain a copy of the License at
|
| 194 |
+
|
| 195 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
| 196 |
+
|
| 197 |
+
Unless required by applicable law or agreed to in writing, software
|
| 198 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
| 199 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 200 |
+
See the License for the specific language governing permissions and
|
| 201 |
+
limitations under the License.
|
README.md
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: apache-2.0
|
| 3 |
+
base_model: sensenova/SenseNova-Loop-9B-Preview
|
| 4 |
+
base_model_relation: quantized
|
| 5 |
+
library_name: transformers
|
| 6 |
+
pipeline_tag: image-text-to-text
|
| 7 |
+
language:
|
| 8 |
+
- en
|
| 9 |
+
- zh
|
| 10 |
+
tags:
|
| 11 |
+
- nvfp4
|
| 12 |
+
- modelopt
|
| 13 |
+
- quantized
|
| 14 |
+
- multimodal
|
| 15 |
+
- looped-transformer
|
| 16 |
+
- mhc
|
| 17 |
+
- mtp
|
| 18 |
+
- custom_code
|
| 19 |
+
---
|
| 20 |
+
|
| 21 |
+
# SenseNova-Loop-9B-Preview-NVFP4
|
| 22 |
+
|
| 23 |
+
> **Unofficial community quantization.** The original model, architecture and weights are by **SenseNova**:
|
| 24 |
+
> [sensenova/SenseNova-Loop-9B-Preview](https://huggingface.co/sensenova/SenseNova-Loop-9B-Preview)
|
| 25 |
+
> (revision `27abea779b1e6634b136805b6519371739d551f7`), licensed Apache-2.0. We did not train this model.
|
| 26 |
+
> This repository contains modified weights (post-training quantization only — no fine-tuning, QAT or distillation).
|
| 27 |
+
|
| 28 |
+
A calibrated, packed **NVFP4** (ModelOpt) checkpoint of SenseNova-Loop-9B-Preview with the **MTP head kept BF16**
|
| 29 |
+
so MTP speculative decoding works, validated on an NVIDIA DGX Spark (GB10, SM121) with **native W4A4 FP4 GEMMs**.
|
| 30 |
+
|
| 31 |
+
## Provenance
|
| 32 |
+
| Item | Value |
|
| 33 |
+
| --- | --- |
|
| 34 |
+
| Base model | `sensenova/SenseNova-Loop-9B-Preview` @ `27abea779b1e6634b136805b6519371739d551f7` (weights stored FP32 upstream; loaded as BF16 backbone + FP32 mHC, as the upstream card prescribes) |
|
| 35 |
+
| Quantization tool | NVIDIA Model Optimizer `nvidia-modelopt==0.48.0rc1` (`NVFP4_DEFAULT_CFG`, `max` calibration), PyTorch 2.11.0+cu130, Transformers 5.18.0 |
|
| 36 |
+
| Format | NVFP4: E2M1 weights, group size 16, FP8-E4M3 block scales, FP32 per-tensor global scale (`weight_scale_2`) and static activation global scale (`input_scale`); activations quantized to NVFP4 at runtime (W4A4); KV cache **not** quantized (BF16) |
|
| 37 |
+
| Export | 2026-10-30, `export_hf_checkpoint`, single `model.safetensors` (9.38 GB) |
|
| 38 |
+
| Hardware | NVIDIA DGX Spark: GB10 (SM121), 128 GB unified memory, driver 580.159.03, CUDA 13.0 |
|
| 39 |
+
|
| 40 |
+
## Changes from the original (Apache-2.0 §4(b) notice)
|
| 41 |
+
- Decoder linear-layer weights quantized to NVFP4 (see exclusions); `config.json` gains `quantization_config`;
|
| 42 |
+
`hf_quant_config.json` added. Upstream FP32-stored tensors that were not quantized are stored as BF16, except the
|
| 43 |
+
mHC routing parameters, which remain FP32.
|
| 44 |
+
- `mtp.*` (MTP head) is included in `model.safetensors` as BF16 (upstream shipped it as a separate FP32 `mtp.safetensors`).
|
| 45 |
+
- Tokenizer, processor configs, chat template, generation config and `modeling_sensenova_loop.py` are byte-identical
|
| 46 |
+
to the pinned upstream revision (see `SHA256SUMS`).
|
| 47 |
+
- `runtime/` contains SGLang source files from the open SGLang PR
|
| 48 |
+
[#47281](https://github.com/sgl-project/sglang/pull/47281) (Apache-2.0, sgl-project) plus two small patches of ours
|
| 49 |
+
(`runtime/patches/`), needed to serve this checkpoint.
|
| 50 |
+
|
| 51 |
+
## Architecture-specific handling
|
| 52 |
+
- **Looped block (layers 4–27 run twice, shared weights):** calibration ran through the real two-pass forward; every
|
| 53 |
+
looped layer was observed on both visits for every sample, so each shared quantizer's amax is the max over both
|
| 54 |
+
visits. One physical copy of each layer is stored (32 layers, not 56); per-visit KV/recurrent state remains
|
| 55 |
+
independent in the runtime.
|
| 56 |
+
- **mHC routers** (`mhc_attn`, `mhc_ffn`): FP32 parameters and FP32 routing math (Sinkhorn, 20 iterations), untouched.
|
| 57 |
+
- No scale folding / smoothing / graph transforms were applied (plain max calibration), so nothing assumes a single visit.
|
| 58 |
+
|
| 59 |
+
## Precision exclusions
|
| 60 |
+
| Module group | Kept in | Reason |
|
| 61 |
+
| --- | --- | --- |
|
| 62 |
+
| Vision encoder + merger (`model.visual*`) | BF16 | fragile, small share of compute |
|
| 63 |
+
| `lm_head`, `embed_tokens` | BF16 | output/embedding sensitivity |
|
| 64 |
+
| mHC routing (`mhc_attn`, `mhc_ffn`, 96 tensors) | FP32 | required by the architecture |
|
| 65 |
+
| Gated-DeltaNet `in_proj_a`, `in_proj_b`, `conv1d`, `A_log`, `dt_bias`, norms | BF16 / FP32 | recurrent-state gates, tiny |
|
| 66 |
+
| All RMSNorms | BF16 | not linear |
|
| 67 |
+
| MTP head (`mtp.*`, 15 tensors) | BF16 | draft head; keeps MTP acceptance |
|
| 68 |
+
| **Quantized (NVFP4):** full-attention `q/k/v/o_proj`, GDN `in_proj_qkv`, `in_proj_z`, `out_proj`, MLP `gate/up/down_proj` in all 32 layers (200 linears) | NVFP4 | |
|
| 69 |
+
|
| 70 |
+
Parameters quantized: **73.4 %** of the backbone loaded by Transformers (6.91 B of 9.41 B), 71.6 % including the MTP
|
| 71 |
+
head. Checkpoint size: **9.38 GB** (upstream: 38.1 GB FP32 on disk ≈ 19.3 GB as BF16). Weight memory in SGLang:
|
| 72 |
+
8.8 GB (vs 17.5 GiB BF16 weights in Transformers).
|
| 73 |
+
|
| 74 |
+
## Calibration data
|
| 75 |
+
256 chat-formatted examples (`calib_v1`, sha256 `9a4d2112ef71820a…`, see `quantization/calib_v1.jsonl.sha256`), rendered
|
| 76 |
+
with the model's own chat template/processor: 98,458 tokens incl. 39 images. Calibration data is not redistributed.
|
| 77 |
+
|
| 78 |
+
| Share | Source | Split / revision | Licence |
|
| 79 |
+
| --- | --- | --- | --- |
|
| 80 |
+
| 30 % chat (en/zh/es/ca) | OpenAssistant/oasst2 | train @ 179dd21f | Apache-2.0 |
|
| 81 |
+
| 20 % code | google-research-datasets/mbpp | full/train @ 4bb6404f | CC-BY-4.0 |
|
| 82 |
+
| 20 % math (half with `<think>` traces) | openai/gsm8k | main/train @ 740312ad | MIT |
|
| 83 |
+
| 15 % tool-calling trajectories | glaiveai/glaive-function-calling-v2 | @ e7f4b645 | Apache-2.0 |
|
| 84 |
+
| 15 % image QA | lmms-lab/textvqa | train shard 0 @ 9c0699cd | CC-BY-4.0 (images: OpenImages, CC-BY-2.0) |
|
| 85 |
+
|
| 86 |
+
Disjoint from all evaluation items (different splits/datasets; 13-gram overlap check found only shared tool-schema boilerplate).
|
| 87 |
+
|
| 88 |
+
## Quality vs BF16 reference (same SGLang build and flags, greedy, thinking off)
|
| 89 |
+
Small fixed suite (300 items; data hashes in `evaluation/eval_data_MANIFEST.json`). Gates were declared before
|
| 90 |
+
any NVFP4 result was seen (`evaluation/QUALITY_GATES.md`). Paired-bootstrap 95 % CI for the delta. These are
|
| 91 |
+
**subsets**, not full-benchmark scores; differences inside the CI are "not detectable at this n", not "lossless".
|
| 92 |
+
|
| 93 |
+
| Task | n | BF16 | NVFP4 | Δ (pp) [95 % CI] |
|
| 94 |
+
| --- | --- | --- | --- | --- |
|
| 95 |
+
| IFEval subset (prompt-level strict, re-implemented checker) | 60 | 78.3 | 75.0 | −3.3 [−13.3, +6.7] |
|
| 96 |
+
| GSM8K test subset | 80 | 92.5 | 95.0 | +2.5 [−2.5, +7.5] |
|
| 97 |
+
| MMLU-Pro test subset | 60 | 65.0 | 68.3 | +3.3 [−6.7, +13.3] |
|
| 98 |
+
| HumanEval subset (pass@1) | 40 | 82.5 | 80.0 | −2.5 [−7.5, 0.0] |
|
| 99 |
+
| Function calling (20 hand-written BFCL-style cases) | 20 | 95.0 | 95.0 | 0.0 [−15, +15] |
|
| 100 |
+
| TextVQA val subset | 40 | 90.0 | 90.0 | 0.0 [−7.5, +7.5] |
|
| 101 |
+
| **All (micro)** | **300** | **82.7** | **83.0** | **+0.3 [−3.0, +4.0]** |
|
| 102 |
+
|
| 103 |
+
Tool calls: 100 % well-formed for both. 0 request errors. Truncations at the max-token limit: 14 (NVFP4) vs 19 (BF16).
|
| 104 |
+
With MTP enabled the NVFP4 model scored GSM8K 96.3 % (n=80), HumanEval 80.0 % (n=40), tools 90 % (n=20); MTP is
|
| 105 |
+
lossless in principle at temperature 0, small differences come from batch-dependent numerics.
|
| 106 |
+
|
| 107 |
+
## Performance (DGX Spark GB10, SGLang, same flags for all rows)
|
| 108 |
+
Prompt 1,051 tokens, exactly 256 output tokens (`ignore_eos`), greedy, unique prompts (no prefix-cache hits),
|
| 109 |
+
`--mem-fraction-static 0.45`, CUDA graphs on. No MTP rows: 16 requests per level; MTP rows: 8 requests per level.
|
| 110 |
+
Aggregate output tokens/s (per-request decode tok/s p50 in parentheses):
|
| 111 |
+
|
| 112 |
+
| Concurrency | BF16 | NVFP4 W4A4 | BF16 + MTP | **NVFP4 W4A4 + MTP** | NVFP4 W4A16 (Marlin) |
|
| 113 |
+
| --- | --- | --- | --- | --- | --- |
|
| 114 |
+
| 1 | 5.75 (5.8) | 9.39 (9.6) | 7.51 (7.6) | **12.21 (12.6)** | 10.98 (11.4) |
|
| 115 |
+
| 2 | 11.44 | 17.61 | 14.77 | **24.79** | – |
|
| 116 |
+
| 4 | 21.86 | 33.48 | 26.81 | **42.51** | – |
|
| 117 |
+
| 8 | 39.93 (5.5) | 64.79 (9.3) | 45.70 (7.0) | **64.43 (12.2)** | 58.17 (8.8) |
|
| 118 |
+
|
| 119 |
+
TTFT p50 at c=1: 0.75 s BF16 → 0.58 s NVFP4. 0 errors / OOMs at any level. MTP mean accepted length (3 draft
|
| 120 |
+
steps): **2.93 NVFP4 vs 2.95 BF16** on the eval tasks; on the synthetic perf prompts ≈2.0, which is why MTP gives
|
| 121 |
+
no extra aggregate throughput at c=8 there. KV-cache capacity at the same memory budget: 407 k tokens (NVFP4) vs
|
| 122 |
+
308 k (BF16).
|
| 123 |
+
|
| 124 |
+
**Kernel evidence (native FP4):** a torch-profiler trace of NVFP4 serving shows the quantized linears executing
|
| 125 |
+
`cutlass3x_sm120_bstensorop_…gemm_block_scaled_ue4m3xe2m1_ue4m3xe2m1…` (block-scaled FP4×FP4 tensor-core GEMM,
|
| 126 |
+
dispatched via the FlashInfer cuDNN backend) with activations quantized by `quantize_with_block_size` — i.e. true
|
| 127 |
+
W4A4, not dequantize-to-BF16 (`evaluation/kernel_summary.txt`). The W4A16 column uses the same checkpoint with
|
| 128 |
+
Marlin weight-only kernels; it is faster for single-stream decode on GB10 but slower under concurrency.
|
| 129 |
+
|
| 130 |
+
## Hardware & software requirements
|
| 131 |
+
- NVIDIA Blackwell GPU with FP4 tensor cores. **Tested only on DGX Spark (GB10, SM121)**. Weights need ≈9 GB plus
|
| 132 |
+
KV/recurrent-state memory.
|
| 133 |
+
- Serving: SGLang image `lmsysorg/sglang:nightly-dev-cu13-20261029-c10e0e17`
|
| 134 |
+
(`sha256:78142f9f4b7fb3ee27f59065615dc7bb263f643ed256c9299c3861086ade4d47`) with the files in `runtime/overlay`
|
| 135 |
+
(SGLang PR #47281 @ `336c54ac1e721197806d94b6929f567446a59693` + our patches) mounted over the image.
|
| 136 |
+
As of 2026-10-30 we found no engine supporting `sensenova_loop` + NVFP4 out of the box (checked: SGLang main,
|
| 137 |
+
LightLLM main — model supported but no NVFP4, vLLM 0.27.1 — no `sensenova_loop`).
|
| 138 |
+
- Plain Transformers (`trust_remote_code=True`) loads the original BF16 model but **cannot** execute this packed NVFP4
|
| 139 |
+
checkpoint or MTP; use the SGLang runtime above.
|
| 140 |
+
|
| 141 |
+
## Usage
|
| 142 |
+
```bash
|
| 143 |
+
# from the repository root (Docker + NVIDIA container runtime required)
|
| 144 |
+
runtime/serve_sglang.sh . # NVFP4 W4A4 + MTP (NEXTN, 3 steps), 127.0.0.1:30080
|
| 145 |
+
curl -s http://127.0.0.1:30080/v1/models
|
| 146 |
+
python3 runtime/probe.py http://127.0.0.1:30080/v1 sensenova-loop-9b-nvfp4 [image.jpg] # text / thinking / tool / image smoke test
|
| 147 |
+
# options: --no-mtp ; W4A16: SGLANG_DISABLE_SILU_FP4_QUANT_FUSION=1 runtime/serve_sglang.sh . --fp4-gemm-backend marlin
|
| 148 |
+
```
|
| 149 |
+
OpenAI-compatible API; thinking is toggled with `chat_template_kwargs: {"enable_thinking": false|true}`; tools use the
|
| 150 |
+
`qwen3_coder` parser (the model's XML `<tool_call><function=…>` format).
|
| 151 |
+
|
| 152 |
+
## Limitations
|
| 153 |
+
- Upstream is a *Preview* model; all upstream limitations and intended-use terms apply.
|
| 154 |
+
- The serving path depends on an **unmerged** SGLang PR plus our patches, pinned to one nightly image; it was tested
|
| 155 |
+
only on GB10. Pipeline/tensor parallelism and other GPUs were not tested.
|
| 156 |
+
- Evaluation is small (300 items, thinking off, contexts ≤ ~3 K tokens). Long context (> 32 K), video input, thinking-mode
|
| 157 |
+
quality at scale and non-English quality were not evaluated. Only greedy decoding was benchmarked.
|
| 158 |
+
- The mHC Sinkhorn routing runs as many small FP32 PyTorch kernels and dominates a large share of GPU time in both BF16 and
|
| 159 |
+
NVFP4; a fused kernel would likely improve speed further (not attempted).
|
| 160 |
+
- In this SGLang build, `--fp4-gemm-backend marlin` crashes unless `SGLANG_DISABLE_SILU_FP4_QUANT_FUSION=1` is set
|
| 161 |
+
(upstream bug: the fused SiLU+FP4-quant path is enabled regardless of backend).
|
| 162 |
+
- Quantization may change behaviour on inputs unlike the calibration mixture.
|
| 163 |
+
|
| 164 |
+
## Files
|
| 165 |
+
- `model.safetensors`, `config.json`, `hf_quant_config.json` — NVFP4 checkpoint (+ BF16 MTP head, FP32 mHC).
|
| 166 |
+
- Upstream (unchanged): `tokenizer*.json`, `chat_template.jinja`, `*processor_config.json`, `generation_config.json`, `modeling_sensenova_loop.py`.
|
| 167 |
+
- `runtime/` — tested launcher, SGLang overlay and patches, probe script, compatibility notes.
|
| 168 |
+
- `quantization/` — quantization/verification scripts, stats, structural verification report, environment lock, calibration manifest.
|
| 169 |
+
- `evaluation/` — quality gates, eval summaries, paired comparison, perf JSONs, kernel trace summary, reference checks.
|
| 170 |
+
- `SHA256SUMS` — checksums of every file.
|
| 171 |
+
|
| 172 |
+
## Licence
|
| 173 |
+
Apache-2.0, inherited from the base model (`LICENSE`, verbatim from `OpenSenseNova/SenseNova-Loop` @ `a521b0af`; the
|
| 174 |
+
upstream repository has no NOTICE file). SGLang files in `runtime/overlay` are Apache-2.0 (sgl-project).
|
| 175 |
+
|
| 176 |
+
## Citation
|
| 177 |
+
Please cite the original model:
|
| 178 |
+
```bibtex
|
| 179 |
+
@misc{sensenova2026loop,
|
| 180 |
+
title = {{SenseNova-Loop-9B-Preview}},
|
| 181 |
+
author = {{SenseNova}},
|
| 182 |
+
year = {2026},
|
| 183 |
+
howpublished = {Hugging Face model repository},
|
| 184 |
+
url = {https://huggingface.co/sensenova/SenseNova-Loop-9B-Preview}
|
| 185 |
+
}
|
| 186 |
+
```
|
SHA256SUMS
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
a4aee8afcf2e0711942cf848899be66016f8d14a889ff9ede07bca099c28f715 ./chat_template.jinja
|
| 2 |
+
5bec5643138a09f2917a0b7471a673baecfbf85f59af49cc048f4318f32e7a3d ./config.json
|
| 3 |
+
021b420e4757b37909200d1cc52bf308116461735a6b50c67df652267f54c587 ./evaluation/compare_vs_ref.json
|
| 4 |
+
5d01579bee6c0863addc3236392b4d88c8d7a7d3cf66b62ae65db1430c0110a3 ./evaluation/eval_data_MANIFEST.json
|
| 5 |
+
6df2bf0438b64d1353c1737e3659c86bce501dc188de9ce448492895e8b5ae63 ./evaluation/harness/build_eval_data.py
|
| 6 |
+
e2818e8c8ff581d65ac8a4dbfc07b58eaea97546dfd63cc3f8f31faaf8ed0f22 ./evaluation/harness/common.py
|
| 7 |
+
0423139c0573e09181f065dbdb273b123aa4a966a5ec57a3643b2fe4f8f43b92 ./evaluation/harness/compare.py
|
| 8 |
+
535255ccff9b6032494d918331dce7d7bbd5a455771143afeaf7977458b52bf4 ./evaluation/harness/ifeval_lite.py
|
| 9 |
+
c0e6d611823b672513730fae4f83d6e72cb0927202a0df1112176465d316731f ./evaluation/harness/mock_server.py
|
| 10 |
+
8909f46e7c6383cce45dbad9c64d78035316031b6f7d99be664ae8b7c3d3577a ./evaluation/harness/perf_bench.py
|
| 11 |
+
d2b24fe51830bf6ed99af01c66ed1b861a50eff88d130fac3f9369e6865837cd ./evaluation/harness/requirements.lock
|
| 12 |
+
49f85f32fb01f029182491d5dd803c26c37814e9ecfa283f37d705543242bc3d ./evaluation/harness/run_eval.py
|
| 13 |
+
fe25e6a9d5432922ff4509a9a80e7b996072ee2091353840a6d0fdf764d8daef ./evaluation/harness/tasks.py
|
| 14 |
+
8c28fad23d10bfa56897a6c0d306b0a474cb6bc2ac7a08355682bd697a2dcd3f ./evaluation/harness/test_harness.py
|
| 15 |
+
ec6899745f66eaf5eb92975341bd44b8c6d5ede2116ea6d0d56d8ba008ae7702 ./evaluation/harness/tool_cases.py
|
| 16 |
+
90dbf7789104b8763f8980f564d8da2c6d033a2207707a386dba8756cd8d2063 ./evaluation/hf_bf16_checks.json
|
| 17 |
+
a1a5de6483f0d8c2d759b9c60cb86da4794a4036c6101bba104cc1d5dba63dfb ./evaluation/kernel_summary.txt
|
| 18 |
+
ce49434ad0c1806bcf01a57957add6fb2ca67f1aa6a61394ae248a75d41b7c80 ./evaluation/nvfp4_v1_mtp_release_probe.json
|
| 19 |
+
4cfff7659e057c02133576124dd0dd65b28a8d6869d1b460d68055dc01a2454a ./evaluation/nvfp4_v1_probe.json
|
| 20 |
+
a588317f6ba1071ab5f67a850e0ced977dfbf3f3dd0b34ea2d5ac54767947c17 ./evaluation/perf_sglang_bf16.json
|
| 21 |
+
7f9aa0a53f019234a256057b0f759695cf0ac266ac033e3e02b84bf71ffcec41 ./evaluation/perf_sglang_bf16_mtp.json
|
| 22 |
+
8a115863344c244470a3a18959e89c914aa852602e75cb365554d62adfd66c9f ./evaluation/perf_sglang_nvfp4_v1.json
|
| 23 |
+
d68a9f7a151718b65b6782ea48f4db0aa60f068ab8636eb51f2f2935a61b0058 ./evaluation/perf_sglang_nvfp4_v1_marlin_w4a16.json
|
| 24 |
+
546730231cdf739cf84f0d92768c2a31378c165b3e48a1840117b9a2faa5035a ./evaluation/perf_sglang_nvfp4_v1_mtp.json
|
| 25 |
+
ccdb9203010fc0534d37b0b475d85f088f5e62568d3cbd76229af4d8e50ffb28 ./evaluation/QUALITY_GATES.md
|
| 26 |
+
8f50277ef8a232dc4abab998fa80ffdcc46c13cbebea1d9328e93878af035157 ./evaluation/sglang_bf16_mtp_probe.json
|
| 27 |
+
92c0708bb0d27772bedefc3d5f458b742c48325025af5a1269535de6dca2d914 ./evaluation/sglang_bf16_probe.json
|
| 28 |
+
ec88f909edcbf225936bbeac88ede9312520593eb53db976d5079d9dd6c45ed1 ./evaluation/summary_sglang_bf16.json
|
| 29 |
+
58cd6bbadfc9fc070a784e65810414a24919084e4570e1ff7680e8a00f14504b ./evaluation/summary_sglang_bf16_mtp.json
|
| 30 |
+
c6d75330180b2d1bd5f2dda574afeee8844e18e44c46ba0f3a1128eb052d2326 ./evaluation/summary_sglang_nvfp4_v1.json
|
| 31 |
+
aff7bcc52ad3e83e6394a8d31e733d8b5725d213836beb98824c397e726c66c6 ./evaluation/summary_sglang_nvfp4_v1_marlin_w4a16_gsm8k.json
|
| 32 |
+
944d3ce06cffbfb7a8e10c1af186aaa62a196e6b96cd8c3a1e6800e5d998fa70 ./evaluation/summary_sglang_nvfp4_v1_mtp.json
|
| 33 |
+
f288bb4281580138395c6acc7b3adb62f45c21530bc0708cb2cf9edf093f6a4f ./generation_config.json
|
| 34 |
+
8951a99119cdcd06c699d91ccc5db0a40b595961041a5ec2e6103b88112757e8 ./.gitattributes
|
| 35 |
+
b197af747a1f072419a8e7e2db3252d9aeea84d21f65db37f748430ab7f83bfd ./hf_quant_config.json
|
| 36 |
+
c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4 ./LICENSE
|
| 37 |
+
26e11d3522aa730c0ba031340ce42632bc2834da8cc0b6804006bb207d979a5b ./modeling_sensenova_loop.py
|
| 38 |
+
1e420ea69111b7bb3c7c529cdbbb4ff4e6ebb531c0cd2be5c634cd88cd40eaca ./model.safetensors
|
| 39 |
+
3a159dfec9978a186a72ba085e0ad6a050f3968d8b364218d7bd13f5c89381f2 ./preprocessor_config.json
|
| 40 |
+
d89ef49ce9cd37fbf510158e13c1ef063d9286411c1ec9049932dbe0487143b1 ./processor_config.json
|
| 41 |
+
df49d802cffe959b3176eed9abee2277d3e4291cdaf2d9abf8430ee17aeba700 ./quantization/10_reference_checks.py
|
| 42 |
+
67d6edacb11e519afb6d81adb4c559930b17ce9a8adeed0e7c8c2043d8383337 ./quantization/20_quantize.py
|
| 43 |
+
27dcbf33dfb7e83cace92cc8221e20d2ead29d4090bf15c9348e181b6bb5ba47 ./quantization/30_verify_export.py
|
| 44 |
+
dc54da6f2e37136c3172779d86ae0134a353942f341eaa8934d3000a01f34682 ./quantization/build_calib.py
|
| 45 |
+
04c164fb57e8125eed5d624cefa806a61bc28cb929aca6406d2923ea43f11825 ./quantization/calib_v1.jsonl.sha256
|
| 46 |
+
3a2015bbf02262d97e0de28f4fa2b3e73d43f58635a507a96788bf7b587236d8 ./quantization/calib_v1.meta.json
|
| 47 |
+
4d71bc0045ee80c45f5eef89e5e721e064e2505020b327942501b017daf0fdf8 ./quantization/quantization_stats.json
|
| 48 |
+
723419a376e5f2339f4f0d4f9376b16ea2d5359e54659ccb85c2bb2d5c3028fd ./quantization/requirements-quant.lock
|
| 49 |
+
be632c83213d44b4a18f367c59fcb55f5d0d738b8c67f64ccc61df3c6a9fb598 ./quantization/verify.json
|
| 50 |
+
9d1df67a6eb124431baf4bfbd9eb9b30b00d8f9a8116dec05c847a39036ba8a3 ./README.md
|
| 51 |
+
1b95e589cd65a97a97fae93cdeec07fcadbf0ff204be746fe20db32550a2c248 ./runtime/COMPAT_NOTES.md
|
| 52 |
+
e00d2fafe780fcf4c04ab52b040e43ec7143c7bd6e070637563f2724b59888d1 ./runtime/overlay/python/sglang/srt/configs/__init__.py
|
| 53 |
+
bdc7fa2055b799ce07441a5d499fafa554b7b797d4c4a24fd251b846b51260fd ./runtime/overlay/python/sglang/srt/configs/model_config.py
|
| 54 |
+
eb6df8f37ac06e6f439dd24f687e5bf1078599ade28acaa20d8799bf77c7e057 ./runtime/overlay/python/sglang/srt/configs/sensenova_loop.py
|
| 55 |
+
b3b4959f2336d1afdf4f0353a0a0eecfc38495226912022dd862489cbb532c98 ./runtime/overlay/python/sglang/srt/layers/rotary_embedding/mrope_rope_index.py
|
| 56 |
+
0883bffeff0519db0fb8035b3260eca57c48ebe00e42323fb75cb7f455c1ddad ./runtime/overlay/python/sglang/srt/models/sensenova_loop.py
|
| 57 |
+
7fc07bd18b974aa8f54013f2bb39536a65d32ad0cc1a1df2d239ead0dc136754 ./runtime/overlay/python/sglang/srt/multimodal/processors/qwen_vl.py
|
| 58 |
+
68e1076237ed67adfa06530139d79df0783a2519620443a58cce94c5143d56c4 ./runtime/overlay/python/sglang/srt/utils/hf_transformers/common.py
|
| 59 |
+
d93e6342f9487567a7847443eb47b41701b4510474cd5664c8dc51b37eb6f6fd ./runtime/patches/model_config_mtp_draft.patch
|
| 60 |
+
029fa25bb4ea5a16c9fce8de412e7ea6481fc540508c63bdd629026b9a56f926 ./runtime/patches/sensenova_loop_quant.patch
|
| 61 |
+
7b9fd04a5e756a982cac292d314ef2ca84dca0517a4abb4f8a4c009745fd0267 ./runtime/probe.py
|
| 62 |
+
be2e56aca0bdbc48bab616db27b37ab36a170b2a3a35534e8be25b291508e54a ./runtime/serve_sglang.sh
|
| 63 |
+
792fa3f0cb88b111e54ef3134c873531008c4df471d108da17903426e308aa7b ./tokenizer_config.json
|
| 64 |
+
06b9509352d2af50381ab2247e083b80d32d5c0aba91c272ca9ff729b6a0e523 ./tokenizer.json
|
| 65 |
+
bd96830cce1312679aa1f2ea43ed17da20e8ebbcea2398cfa64e2d275a96fdd7 ./video_preprocessor_config.json
|
chat_template.jinja
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{%- set image_count = namespace(value=0) %}
|
| 2 |
+
{%- set video_count = namespace(value=0) %}
|
| 3 |
+
{%- macro render_content(content, do_vision_count, is_system_content=false) %}
|
| 4 |
+
{%- if content is string %}
|
| 5 |
+
{{- content }}
|
| 6 |
+
{%- elif content is iterable and content is not mapping %}
|
| 7 |
+
{%- for item in content %}
|
| 8 |
+
{%- if 'image' in item or 'image_url' in item or item.type == 'image' %}
|
| 9 |
+
{%- if is_system_content %}
|
| 10 |
+
{{- raise_exception('System message cannot contain images.') }}
|
| 11 |
+
{%- endif %}
|
| 12 |
+
{%- if do_vision_count %}
|
| 13 |
+
{%- set image_count.value = image_count.value + 1 %}
|
| 14 |
+
{%- endif %}
|
| 15 |
+
{%- if add_vision_id %}
|
| 16 |
+
{{- 'Picture ' ~ image_count.value ~ ': ' }}
|
| 17 |
+
{%- endif %}
|
| 18 |
+
{{- '<|vision_start|><|image_pad|><|vision_end|>' }}
|
| 19 |
+
{%- elif 'video' in item or item.type == 'video' %}
|
| 20 |
+
{%- if is_system_content %}
|
| 21 |
+
{{- raise_exception('System message cannot contain videos.') }}
|
| 22 |
+
{%- endif %}
|
| 23 |
+
{%- if do_vision_count %}
|
| 24 |
+
{%- set video_count.value = video_count.value + 1 %}
|
| 25 |
+
{%- endif %}
|
| 26 |
+
{%- if add_vision_id %}
|
| 27 |
+
{{- 'Video ' ~ video_count.value ~ ': ' }}
|
| 28 |
+
{%- endif %}
|
| 29 |
+
{{- '<|vision_start|><|video_pad|><|vision_end|>' }}
|
| 30 |
+
{%- elif 'text' in item %}
|
| 31 |
+
{{- item.text }}
|
| 32 |
+
{%- else %}
|
| 33 |
+
{{- raise_exception('Unexpected item type in content.') }}
|
| 34 |
+
{%- endif %}
|
| 35 |
+
{%- endfor %}
|
| 36 |
+
{%- elif content is none or content is undefined %}
|
| 37 |
+
{{- '' }}
|
| 38 |
+
{%- else %}
|
| 39 |
+
{{- raise_exception('Unexpected content type.') }}
|
| 40 |
+
{%- endif %}
|
| 41 |
+
{%- endmacro %}
|
| 42 |
+
{%- if not messages %}
|
| 43 |
+
{{- raise_exception('No messages provided.') }}
|
| 44 |
+
{%- endif %}
|
| 45 |
+
{%- if tools and tools is iterable and tools is not mapping %}
|
| 46 |
+
{{- '<|im_start|>system\n' }}
|
| 47 |
+
{{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }}
|
| 48 |
+
{%- for tool in tools %}
|
| 49 |
+
{{- "\n" }}
|
| 50 |
+
{{- tool | tojson }}
|
| 51 |
+
{%- endfor %}
|
| 52 |
+
{{- "\n</tools>" }}
|
| 53 |
+
{{- '\n\nIf you choose to call a function ONLY reply in the following format with NO suffix:\n\n<tool_call>\n<function=example_function_name>\n<parameter=example_parameter_1>\nvalue_1\n</parameter>\n<parameter=example_parameter_2>\nThis is the value for the second parameter\nthat can span\nmultiple lines\n</parameter>\n</function>\n</tool_call>\n\n<IMPORTANT>\nReminder:\n- Function calls MUST follow the specified format: an inner <function=...></function> block must be nested within <tool_call></tool_call> XML tags\n- Required parameters MUST be specified\n- You may provide optional reasoning for your function call in natural language BEFORE the function call, but NOT after\n- If there is no function call available, answer the question like normal with your current knowledge and do not tell the user about function calls\n</IMPORTANT>' }}
|
| 54 |
+
{%- if messages[0].role == 'system' %}
|
| 55 |
+
{%- set content = render_content(messages[0].content, false, true)|trim %}
|
| 56 |
+
{%- if content %}
|
| 57 |
+
{{- '\n\n' + content }}
|
| 58 |
+
{%- endif %}
|
| 59 |
+
{%- endif %}
|
| 60 |
+
{{- '<|im_end|>\n' }}
|
| 61 |
+
{%- else %}
|
| 62 |
+
{%- if messages[0].role == 'system' %}
|
| 63 |
+
{%- set content = render_content(messages[0].content, false, true)|trim %}
|
| 64 |
+
{{- '<|im_start|>system\n' + content + '<|im_end|>\n' }}
|
| 65 |
+
{%- endif %}
|
| 66 |
+
{%- endif %}
|
| 67 |
+
{%- set ns = namespace(multi_step_tool=true, last_query_index=messages|length - 1) %}
|
| 68 |
+
{%- for message in messages[::-1] %}
|
| 69 |
+
{%- set index = (messages|length - 1) - loop.index0 %}
|
| 70 |
+
{%- if ns.multi_step_tool and message.role == "user" %}
|
| 71 |
+
{%- set content = render_content(message.content, false)|trim %}
|
| 72 |
+
{%- if not(content.startswith('<tool_response>') and content.endswith('</tool_response>')) %}
|
| 73 |
+
{%- set ns.multi_step_tool = false %}
|
| 74 |
+
{%- set ns.last_query_index = index %}
|
| 75 |
+
{%- endif %}
|
| 76 |
+
{%- endif %}
|
| 77 |
+
{%- endfor %}
|
| 78 |
+
{%- if ns.multi_step_tool %}
|
| 79 |
+
{{- raise_exception('No user query found in messages.') }}
|
| 80 |
+
{%- endif %}
|
| 81 |
+
{%- for message in messages %}
|
| 82 |
+
{%- set content = render_content(message.content, true)|trim %}
|
| 83 |
+
{%- if message.role == "system" %}
|
| 84 |
+
{%- if not loop.first %}
|
| 85 |
+
{{- raise_exception('System message must be at the beginning.') }}
|
| 86 |
+
{%- endif %}
|
| 87 |
+
{%- elif message.role == "user" %}
|
| 88 |
+
{{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>' + '\n' }}
|
| 89 |
+
{%- elif message.role == "assistant" %}
|
| 90 |
+
{%- set reasoning_content = '' %}
|
| 91 |
+
{%- if message.reasoning_content is string %}
|
| 92 |
+
{%- set reasoning_content = message.reasoning_content %}
|
| 93 |
+
{%- else %}
|
| 94 |
+
{%- if '</think>' in content %}
|
| 95 |
+
{%- set reasoning_content = content.split('</think>')[0].rstrip('\n').split('<think>')[-1].lstrip('\n') %}
|
| 96 |
+
{%- set content = content.split('</think>')[-1].lstrip('\n') %}
|
| 97 |
+
{%- endif %}
|
| 98 |
+
{%- endif %}
|
| 99 |
+
{%- set reasoning_content = reasoning_content|trim %}
|
| 100 |
+
{%- if loop.index0 > ns.last_query_index %}
|
| 101 |
+
{{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }}
|
| 102 |
+
{%- else %}
|
| 103 |
+
{{- '<|im_start|>' + message.role + '\n' + content }}
|
| 104 |
+
{%- endif %}
|
| 105 |
+
{%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %}
|
| 106 |
+
{%- for tool_call in message.tool_calls %}
|
| 107 |
+
{%- if tool_call.function is defined %}
|
| 108 |
+
{%- set tool_call = tool_call.function %}
|
| 109 |
+
{%- endif %}
|
| 110 |
+
{%- if loop.first %}
|
| 111 |
+
{%- if content|trim %}
|
| 112 |
+
{{- '\n\n<tool_call>\n<function=' + tool_call.name + '>\n' }}
|
| 113 |
+
{%- else %}
|
| 114 |
+
{{- '<tool_call>\n<function=' + tool_call.name + '>\n' }}
|
| 115 |
+
{%- endif %}
|
| 116 |
+
{%- else %}
|
| 117 |
+
{{- '\n<tool_call>\n<function=' + tool_call.name + '>\n' }}
|
| 118 |
+
{%- endif %}
|
| 119 |
+
{%- if tool_call.arguments is defined %}
|
| 120 |
+
{%- for args_name, args_value in tool_call.arguments|items %}
|
| 121 |
+
{{- '<parameter=' + args_name + '>\n' }}
|
| 122 |
+
{%- 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 %}
|
| 123 |
+
{{- args_value }}
|
| 124 |
+
{{- '\n</parameter>\n' }}
|
| 125 |
+
{%- endfor %}
|
| 126 |
+
{%- endif %}
|
| 127 |
+
{{- '</function>\n</tool_call>' }}
|
| 128 |
+
{%- endfor %}
|
| 129 |
+
{%- endif %}
|
| 130 |
+
{{- '<|im_end|>\n' }}
|
| 131 |
+
{%- elif message.role == "tool" %}
|
| 132 |
+
{%- if loop.previtem and loop.previtem.role != "tool" %}
|
| 133 |
+
{{- '<|im_start|>user' }}
|
| 134 |
+
{%- endif %}
|
| 135 |
+
{{- '\n<tool_response>\n' }}
|
| 136 |
+
{{- content }}
|
| 137 |
+
{{- '\n</tool_response>' }}
|
| 138 |
+
{%- if not loop.last and loop.nextitem.role != "tool" %}
|
| 139 |
+
{{- '<|im_end|>\n' }}
|
| 140 |
+
{%- elif loop.last %}
|
| 141 |
+
{{- '<|im_end|>\n' }}
|
| 142 |
+
{%- endif %}
|
| 143 |
+
{%- else %}
|
| 144 |
+
{{- raise_exception('Unexpected message role.') }}
|
| 145 |
+
{%- endif %}
|
| 146 |
+
{%- endfor %}
|
| 147 |
+
{%- if add_generation_prompt %}
|
| 148 |
+
{{- '<|im_start|>assistant\n' }}
|
| 149 |
+
{%- if enable_thinking is defined and enable_thinking is false %}
|
| 150 |
+
{{- '<think>\n\n</think>\n\n' }}
|
| 151 |
+
{%- else %}
|
| 152 |
+
{{- '<think>\n' }}
|
| 153 |
+
{%- endif %}
|
| 154 |
+
{%- endif %}
|
config.json
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"architectures": [
|
| 3 |
+
"SenseNovaLoopForConditionalGeneration"
|
| 4 |
+
],
|
| 5 |
+
"auto_map": {
|
| 6 |
+
"AutoConfig": "modeling_sensenova_loop.SenseNovaLoopConfig",
|
| 7 |
+
"AutoModel": "modeling_sensenova_loop.SenseNovaLoopModel",
|
| 8 |
+
"AutoModelForCausalLM": "modeling_sensenova_loop.SenseNovaLoopForConditionalGeneration",
|
| 9 |
+
"AutoModelForImageTextToText": "modeling_sensenova_loop.SenseNovaLoopForConditionalGeneration"
|
| 10 |
+
},
|
| 11 |
+
"bos_token_id": null,
|
| 12 |
+
"dtype": "bfloat16",
|
| 13 |
+
"eos_token_id": 248046,
|
| 14 |
+
"hidden_size": 4096,
|
| 15 |
+
"image_token_id": 248056,
|
| 16 |
+
"loop_settings": {
|
| 17 |
+
"counts": [
|
| 18 |
+
2
|
| 19 |
+
],
|
| 20 |
+
"end": 28,
|
| 21 |
+
"eval_count": 2,
|
| 22 |
+
"start": 4
|
| 23 |
+
},
|
| 24 |
+
"mhc": {
|
| 25 |
+
"end": 28,
|
| 26 |
+
"fixed_identity": false,
|
| 27 |
+
"iterations": 20,
|
| 28 |
+
"pre_scale": 1.0,
|
| 29 |
+
"start": 4,
|
| 30 |
+
"streams": 2
|
| 31 |
+
},
|
| 32 |
+
"model_name": "SenseNova-Loop-9B-Preview",
|
| 33 |
+
"model_type": "sensenova_loop",
|
| 34 |
+
"pad_token_id": 248044,
|
| 35 |
+
"patch_conv3d": true,
|
| 36 |
+
"text_config": {
|
| 37 |
+
"attention_bias": false,
|
| 38 |
+
"attention_dropout": 0.0,
|
| 39 |
+
"attn_output_gate": true,
|
| 40 |
+
"bos_token_id": null,
|
| 41 |
+
"dtype": "bfloat16",
|
| 42 |
+
"eos_token_id": 248044,
|
| 43 |
+
"full_attention_interval": 4,
|
| 44 |
+
"head_dim": 256,
|
| 45 |
+
"hidden_act": "silu",
|
| 46 |
+
"hidden_size": 4096,
|
| 47 |
+
"initializer_range": 0.02,
|
| 48 |
+
"intermediate_size": 12288,
|
| 49 |
+
"layer_types": [
|
| 50 |
+
"linear_attention",
|
| 51 |
+
"linear_attention",
|
| 52 |
+
"linear_attention",
|
| 53 |
+
"full_attention",
|
| 54 |
+
"linear_attention",
|
| 55 |
+
"linear_attention",
|
| 56 |
+
"linear_attention",
|
| 57 |
+
"full_attention",
|
| 58 |
+
"linear_attention",
|
| 59 |
+
"linear_attention",
|
| 60 |
+
"linear_attention",
|
| 61 |
+
"full_attention",
|
| 62 |
+
"linear_attention",
|
| 63 |
+
"linear_attention",
|
| 64 |
+
"linear_attention",
|
| 65 |
+
"full_attention",
|
| 66 |
+
"linear_attention",
|
| 67 |
+
"linear_attention",
|
| 68 |
+
"linear_attention",
|
| 69 |
+
"full_attention",
|
| 70 |
+
"linear_attention",
|
| 71 |
+
"linear_attention",
|
| 72 |
+
"linear_attention",
|
| 73 |
+
"full_attention",
|
| 74 |
+
"linear_attention",
|
| 75 |
+
"linear_attention",
|
| 76 |
+
"linear_attention",
|
| 77 |
+
"full_attention",
|
| 78 |
+
"linear_attention",
|
| 79 |
+
"linear_attention",
|
| 80 |
+
"linear_attention",
|
| 81 |
+
"full_attention"
|
| 82 |
+
],
|
| 83 |
+
"linear_conv_kernel_dim": 4,
|
| 84 |
+
"linear_key_head_dim": 128,
|
| 85 |
+
"linear_num_key_heads": 16,
|
| 86 |
+
"linear_num_value_heads": 32,
|
| 87 |
+
"linear_value_head_dim": 128,
|
| 88 |
+
"mamba_ssm_dtype": "float32",
|
| 89 |
+
"max_position_embeddings": 262144,
|
| 90 |
+
"mlp_only_layers": [],
|
| 91 |
+
"model_type": "qwen3_5_text",
|
| 92 |
+
"mtp_num_hidden_layers": 1,
|
| 93 |
+
"mtp_use_dedicated_embeddings": false,
|
| 94 |
+
"num_attention_heads": 16,
|
| 95 |
+
"num_hidden_layers": 32,
|
| 96 |
+
"num_key_value_heads": 4,
|
| 97 |
+
"pad_token_id": 248044,
|
| 98 |
+
"partial_rotary_factor": 0.25,
|
| 99 |
+
"rms_norm_eps": 1e-06,
|
| 100 |
+
"rope_parameters": {
|
| 101 |
+
"mrope_interleaved": true,
|
| 102 |
+
"mrope_section": [
|
| 103 |
+
11,
|
| 104 |
+
11,
|
| 105 |
+
10
|
| 106 |
+
],
|
| 107 |
+
"partial_rotary_factor": 0.25,
|
| 108 |
+
"rope_theta": 10000000,
|
| 109 |
+
"rope_type": "default"
|
| 110 |
+
},
|
| 111 |
+
"tie_word_embeddings": false,
|
| 112 |
+
"use_cache": true,
|
| 113 |
+
"vocab_size": 248320
|
| 114 |
+
},
|
| 115 |
+
"tie_word_embeddings": false,
|
| 116 |
+
"transformers_version": "5.18.0",
|
| 117 |
+
"video_token_id": 248057,
|
| 118 |
+
"vision_config": {
|
| 119 |
+
"deepstack_visual_indexes": [],
|
| 120 |
+
"depth": 27,
|
| 121 |
+
"dtype": "bfloat16",
|
| 122 |
+
"hidden_act": "gelu_pytorch_tanh",
|
| 123 |
+
"hidden_size": 1152,
|
| 124 |
+
"in_channels": 3,
|
| 125 |
+
"initializer_range": 0.02,
|
| 126 |
+
"intermediate_size": 4304,
|
| 127 |
+
"model_type": "qwen3_5_vision",
|
| 128 |
+
"num_heads": 16,
|
| 129 |
+
"num_position_embeddings": 2304,
|
| 130 |
+
"out_hidden_size": 4096,
|
| 131 |
+
"patch_size": 16,
|
| 132 |
+
"rope_parameters": {
|
| 133 |
+
"rope_theta": 10000.0,
|
| 134 |
+
"rope_type": "axial"
|
| 135 |
+
},
|
| 136 |
+
"spatial_merge_size": 2,
|
| 137 |
+
"temporal_patch_size": 2
|
| 138 |
+
},
|
| 139 |
+
"vision_end_token_id": 248054,
|
| 140 |
+
"vision_start_token_id": 248053,
|
| 141 |
+
"quantization_config": {
|
| 142 |
+
"config_groups": {
|
| 143 |
+
"group_0": {
|
| 144 |
+
"input_activations": {
|
| 145 |
+
"dynamic": false,
|
| 146 |
+
"num_bits": 4,
|
| 147 |
+
"type": "float",
|
| 148 |
+
"group_size": 16
|
| 149 |
+
},
|
| 150 |
+
"weights": {
|
| 151 |
+
"dynamic": false,
|
| 152 |
+
"num_bits": 4,
|
| 153 |
+
"type": "float",
|
| 154 |
+
"group_size": 16
|
| 155 |
+
},
|
| 156 |
+
"targets": [
|
| 157 |
+
"Linear"
|
| 158 |
+
]
|
| 159 |
+
}
|
| 160 |
+
},
|
| 161 |
+
"ignore": [
|
| 162 |
+
"lm_head",
|
| 163 |
+
"model.language_model.embed_tokens",
|
| 164 |
+
"model.language_model.layers.0.linear_attn.conv1d",
|
| 165 |
+
"model.language_model.layers.0.linear_attn.in_proj_a",
|
| 166 |
+
"model.language_model.layers.0.linear_attn.in_proj_b",
|
| 167 |
+
"model.language_model.layers.1.linear_attn.conv1d",
|
| 168 |
+
"model.language_model.layers.1.linear_attn.in_proj_a",
|
| 169 |
+
"model.language_model.layers.1.linear_attn.in_proj_b",
|
| 170 |
+
"model.language_model.layers.10.linear_attn.conv1d",
|
| 171 |
+
"model.language_model.layers.10.linear_attn.in_proj_a",
|
| 172 |
+
"model.language_model.layers.10.linear_attn.in_proj_b",
|
| 173 |
+
"model.language_model.layers.12.linear_attn.conv1d",
|
| 174 |
+
"model.language_model.layers.12.linear_attn.in_proj_a",
|
| 175 |
+
"model.language_model.layers.12.linear_attn.in_proj_b",
|
| 176 |
+
"model.language_model.layers.13.linear_attn.conv1d",
|
| 177 |
+
"model.language_model.layers.13.linear_attn.in_proj_a",
|
| 178 |
+
"model.language_model.layers.13.linear_attn.in_proj_b",
|
| 179 |
+
"model.language_model.layers.14.linear_attn.conv1d",
|
| 180 |
+
"model.language_model.layers.14.linear_attn.in_proj_a",
|
| 181 |
+
"model.language_model.layers.14.linear_attn.in_proj_b",
|
| 182 |
+
"model.language_model.layers.16.linear_attn.conv1d",
|
| 183 |
+
"model.language_model.layers.16.linear_attn.in_proj_a",
|
| 184 |
+
"model.language_model.layers.16.linear_attn.in_proj_b",
|
| 185 |
+
"model.language_model.layers.17.linear_attn.conv1d",
|
| 186 |
+
"model.language_model.layers.17.linear_attn.in_proj_a",
|
| 187 |
+
"model.language_model.layers.17.linear_attn.in_proj_b",
|
| 188 |
+
"model.language_model.layers.18.linear_attn.conv1d",
|
| 189 |
+
"model.language_model.layers.18.linear_attn.in_proj_a",
|
| 190 |
+
"model.language_model.layers.18.linear_attn.in_proj_b",
|
| 191 |
+
"model.language_model.layers.2.linear_attn.conv1d",
|
| 192 |
+
"model.language_model.layers.2.linear_attn.in_proj_a",
|
| 193 |
+
"model.language_model.layers.2.linear_attn.in_proj_b",
|
| 194 |
+
"model.language_model.layers.20.linear_attn.conv1d",
|
| 195 |
+
"model.language_model.layers.20.linear_attn.in_proj_a",
|
| 196 |
+
"model.language_model.layers.20.linear_attn.in_proj_b",
|
| 197 |
+
"model.language_model.layers.21.linear_attn.conv1d",
|
| 198 |
+
"model.language_model.layers.21.linear_attn.in_proj_a",
|
| 199 |
+
"model.language_model.layers.21.linear_attn.in_proj_b",
|
| 200 |
+
"model.language_model.layers.22.linear_attn.conv1d",
|
| 201 |
+
"model.language_model.layers.22.linear_attn.in_proj_a",
|
| 202 |
+
"model.language_model.layers.22.linear_attn.in_proj_b",
|
| 203 |
+
"model.language_model.layers.24.linear_attn.conv1d",
|
| 204 |
+
"model.language_model.layers.24.linear_attn.in_proj_a",
|
| 205 |
+
"model.language_model.layers.24.linear_attn.in_proj_b",
|
| 206 |
+
"model.language_model.layers.25.linear_attn.conv1d",
|
| 207 |
+
"model.language_model.layers.25.linear_attn.in_proj_a",
|
| 208 |
+
"model.language_model.layers.25.linear_attn.in_proj_b",
|
| 209 |
+
"model.language_model.layers.26.linear_attn.conv1d",
|
| 210 |
+
"model.language_model.layers.26.linear_attn.in_proj_a",
|
| 211 |
+
"model.language_model.layers.26.linear_attn.in_proj_b",
|
| 212 |
+
"model.language_model.layers.28.linear_attn.conv1d",
|
| 213 |
+
"model.language_model.layers.28.linear_attn.in_proj_a",
|
| 214 |
+
"model.language_model.layers.28.linear_attn.in_proj_b",
|
| 215 |
+
"model.language_model.layers.29.linear_attn.conv1d",
|
| 216 |
+
"model.language_model.layers.29.linear_attn.in_proj_a",
|
| 217 |
+
"model.language_model.layers.29.linear_attn.in_proj_b",
|
| 218 |
+
"model.language_model.layers.30.linear_attn.conv1d",
|
| 219 |
+
"model.language_model.layers.30.linear_attn.in_proj_a",
|
| 220 |
+
"model.language_model.layers.30.linear_attn.in_proj_b",
|
| 221 |
+
"model.language_model.layers.4.linear_attn.conv1d",
|
| 222 |
+
"model.language_model.layers.4.linear_attn.in_proj_a",
|
| 223 |
+
"model.language_model.layers.4.linear_attn.in_proj_b",
|
| 224 |
+
"model.language_model.layers.5.linear_attn.conv1d",
|
| 225 |
+
"model.language_model.layers.5.linear_attn.in_proj_a",
|
| 226 |
+
"model.language_model.layers.5.linear_attn.in_proj_b",
|
| 227 |
+
"model.language_model.layers.6.linear_attn.conv1d",
|
| 228 |
+
"model.language_model.layers.6.linear_attn.in_proj_a",
|
| 229 |
+
"model.language_model.layers.6.linear_attn.in_proj_b",
|
| 230 |
+
"model.language_model.layers.8.linear_attn.conv1d",
|
| 231 |
+
"model.language_model.layers.8.linear_attn.in_proj_a",
|
| 232 |
+
"model.language_model.layers.8.linear_attn.in_proj_b",
|
| 233 |
+
"model.language_model.layers.9.linear_attn.conv1d",
|
| 234 |
+
"model.language_model.layers.9.linear_attn.in_proj_a",
|
| 235 |
+
"model.language_model.layers.9.linear_attn.in_proj_b",
|
| 236 |
+
"model.visual*",
|
| 237 |
+
"mtp.fc",
|
| 238 |
+
"mtp.layers.0.input_layernorm",
|
| 239 |
+
"mtp.layers.0.mlp.down_proj",
|
| 240 |
+
"mtp.layers.0.mlp.gate_proj",
|
| 241 |
+
"mtp.layers.0.mlp.up_proj",
|
| 242 |
+
"mtp.layers.0.post_attention_layernorm",
|
| 243 |
+
"mtp.layers.0.self_attn.k_norm",
|
| 244 |
+
"mtp.layers.0.self_attn.k_proj",
|
| 245 |
+
"mtp.layers.0.self_attn.o_proj",
|
| 246 |
+
"mtp.layers.0.self_attn.q_norm",
|
| 247 |
+
"mtp.layers.0.self_attn.q_proj",
|
| 248 |
+
"mtp.layers.0.self_attn.v_proj",
|
| 249 |
+
"mtp.norm",
|
| 250 |
+
"mtp.pre_fc_norm_embedding",
|
| 251 |
+
"mtp.pre_fc_norm_hidden"
|
| 252 |
+
],
|
| 253 |
+
"quant_algo": "NVFP4",
|
| 254 |
+
"group_size": 16,
|
| 255 |
+
"producer": {
|
| 256 |
+
"name": "modelopt",
|
| 257 |
+
"version": "0.48.0rc1"
|
| 258 |
+
},
|
| 259 |
+
"quant_method": "modelopt"
|
| 260 |
+
}
|
| 261 |
+
}
|
evaluation/QUALITY_GATES.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Quality / performance gates (declared 2026-10-30 ~15:25 PDT, BEFORE any NVFP4 eval result was seen)
|
| 2 |
+
|
| 3 |
+
Eval: eval/ (300 fixed items: IFEval 60, GSM8K 80, MMLU-Pro 60, HumanEval 40, tools 20, TextVQA 40),
|
| 4 |
+
temperature 0, thinking off, same SGLang build/flags for reference (BF16 backbone, FP32 mHC) and candidate.
|
| 5 |
+
|
| 6 |
+
Quality (candidate vs BF16 reference, paired):
|
| 7 |
+
- G1 pooled accuracy (all 300 items, item-weighted): delta point estimate >= -3.0 pp AND paired-bootstrap 95% CI lower bound >= -7.0 pp.
|
| 8 |
+
- G2 no single task point-estimate drop > 8 pp (n=20-80 per task, so this is a coarse tripwire, not a significance test).
|
| 9 |
+
- G3 tool calling: 0 malformed tool calls beyond the reference's count; image task (TextVQA) drop <= 8 pp.
|
| 10 |
+
- G4 stability: 0 request errors, all outputs finite/non-degenerate (no repetition collapse in truncation counts beyond ref + 3).
|
| 11 |
+
- G5 MTP: mean accepted length (spec) with NVFP4 target >= 85% of the BF16-target value under identical spec settings.
|
| 12 |
+
Performance (same engine, same flags, fixed 1024-in/256-out, concurrency 1/2/4/8):
|
| 13 |
+
- P1 0 errors/OOM at c=1..8. P2 report decode tok/s, TTFT, aggregate throughput honestly; speedup is reported, not gated.
|
| 14 |
+
If a recipe fails G1-G5, try the next recipe (max 3: decoder-all -> MLP-only -> decoder w/ first/last layers BF16).
|
evaluation/compare_vs_ref.json
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"ref": "eval/runs/sglang_bf16",
|
| 3 |
+
"cand": "eval/runs/sglang_nvfp4_v1",
|
| 4 |
+
"tasks": {
|
| 5 |
+
"gsm8k": {
|
| 6 |
+
"n": 80,
|
| 7 |
+
"ref_acc": 0.925,
|
| 8 |
+
"cand_acc": 0.95,
|
| 9 |
+
"delta": 0.025,
|
| 10 |
+
"delta_boot95": [
|
| 11 |
+
-0.025,
|
| 12 |
+
0.075
|
| 13 |
+
],
|
| 14 |
+
"ref_only_correct": 1,
|
| 15 |
+
"cand_only_correct": 3,
|
| 16 |
+
"mcnemar_p": 0.625,
|
| 17 |
+
"ref_agreement": 0.9375,
|
| 18 |
+
"identical_output": 0.075,
|
| 19 |
+
"mean_tokens_ref": 191.5,
|
| 20 |
+
"mean_tokens_cand": 187.2,
|
| 21 |
+
"truncated_ref": 1,
|
| 22 |
+
"truncated_cand": 1,
|
| 23 |
+
"errors_cand": 0
|
| 24 |
+
},
|
| 25 |
+
"humaneval": {
|
| 26 |
+
"n": 40,
|
| 27 |
+
"ref_acc": 0.825,
|
| 28 |
+
"cand_acc": 0.8,
|
| 29 |
+
"delta": -0.025,
|
| 30 |
+
"delta_boot95": [
|
| 31 |
+
-0.075,
|
| 32 |
+
0.0
|
| 33 |
+
],
|
| 34 |
+
"ref_only_correct": 1,
|
| 35 |
+
"cand_only_correct": 0,
|
| 36 |
+
"mcnemar_p": 1.0,
|
| 37 |
+
"ref_agreement": 0.425,
|
| 38 |
+
"identical_output": 0.375,
|
| 39 |
+
"mean_tokens_ref": 226.6,
|
| 40 |
+
"mean_tokens_cand": 198.0,
|
| 41 |
+
"truncated_ref": 0,
|
| 42 |
+
"truncated_cand": 0,
|
| 43 |
+
"errors_cand": 0
|
| 44 |
+
},
|
| 45 |
+
"ifeval": {
|
| 46 |
+
"n": 60,
|
| 47 |
+
"ref_acc": 0.7833333333333333,
|
| 48 |
+
"cand_acc": 0.75,
|
| 49 |
+
"delta": -0.03333333333333333,
|
| 50 |
+
"delta_boot95": [
|
| 51 |
+
-0.13333333333333333,
|
| 52 |
+
0.06666666666666667
|
| 53 |
+
],
|
| 54 |
+
"ref_only_correct": 6,
|
| 55 |
+
"cand_only_correct": 4,
|
| 56 |
+
"mcnemar_p": 0.75390625,
|
| 57 |
+
"ref_agreement": 0.05,
|
| 58 |
+
"identical_output": 0.05,
|
| 59 |
+
"mean_tokens_ref": 318.9,
|
| 60 |
+
"mean_tokens_cand": 272.7,
|
| 61 |
+
"truncated_ref": 5,
|
| 62 |
+
"truncated_cand": 4,
|
| 63 |
+
"errors_cand": 0
|
| 64 |
+
},
|
| 65 |
+
"mmlu_pro": {
|
| 66 |
+
"n": 60,
|
| 67 |
+
"ref_acc": 0.65,
|
| 68 |
+
"cand_acc": 0.6833333333333333,
|
| 69 |
+
"delta": 0.03333333333333333,
|
| 70 |
+
"delta_boot95": [
|
| 71 |
+
-0.06666666666666667,
|
| 72 |
+
0.13333333333333333
|
| 73 |
+
],
|
| 74 |
+
"ref_only_correct": 4,
|
| 75 |
+
"cand_only_correct": 6,
|
| 76 |
+
"mcnemar_p": 0.75390625,
|
| 77 |
+
"ref_agreement": 0.7666666666666667,
|
| 78 |
+
"identical_output": 0.0,
|
| 79 |
+
"mean_tokens_ref": 622.1,
|
| 80 |
+
"mean_tokens_cand": 588.5,
|
| 81 |
+
"truncated_ref": 13,
|
| 82 |
+
"truncated_cand": 9,
|
| 83 |
+
"errors_cand": 0
|
| 84 |
+
},
|
| 85 |
+
"tools": {
|
| 86 |
+
"n": 20,
|
| 87 |
+
"ref_acc": 0.95,
|
| 88 |
+
"cand_acc": 0.95,
|
| 89 |
+
"delta": 0.0,
|
| 90 |
+
"delta_boot95": [
|
| 91 |
+
-0.15,
|
| 92 |
+
0.15
|
| 93 |
+
],
|
| 94 |
+
"ref_only_correct": 1,
|
| 95 |
+
"cand_only_correct": 1,
|
| 96 |
+
"mcnemar_p": 1.0,
|
| 97 |
+
"ref_agreement": 0.85,
|
| 98 |
+
"identical_output": 0.0,
|
| 99 |
+
"mean_tokens_ref": 64.2,
|
| 100 |
+
"mean_tokens_cand": 54.3,
|
| 101 |
+
"truncated_ref": 0,
|
| 102 |
+
"truncated_cand": 0,
|
| 103 |
+
"errors_cand": 0
|
| 104 |
+
},
|
| 105 |
+
"vqa": {
|
| 106 |
+
"n": 40,
|
| 107 |
+
"ref_acc": 0.9,
|
| 108 |
+
"cand_acc": 0.9,
|
| 109 |
+
"delta": 0.0,
|
| 110 |
+
"delta_boot95": [
|
| 111 |
+
-0.075,
|
| 112 |
+
0.075
|
| 113 |
+
],
|
| 114 |
+
"ref_only_correct": 1,
|
| 115 |
+
"cand_only_correct": 1,
|
| 116 |
+
"mcnemar_p": 1.0,
|
| 117 |
+
"ref_agreement": 0.925,
|
| 118 |
+
"identical_output": 0.925,
|
| 119 |
+
"mean_tokens_ref": 4.1,
|
| 120 |
+
"mean_tokens_cand": 4.1,
|
| 121 |
+
"truncated_ref": 0,
|
| 122 |
+
"truncated_cand": 0,
|
| 123 |
+
"errors_cand": 0
|
| 124 |
+
}
|
| 125 |
+
},
|
| 126 |
+
"overall_micro": {
|
| 127 |
+
"n": 300,
|
| 128 |
+
"ref_acc": 0.8266666666666667,
|
| 129 |
+
"cand_acc": 0.83,
|
| 130 |
+
"delta": 0.0033333333333333335,
|
| 131 |
+
"delta_boot95": [
|
| 132 |
+
-0.03,
|
| 133 |
+
0.04
|
| 134 |
+
],
|
| 135 |
+
"ref_agreement": 0.65,
|
| 136 |
+
"identical_output": 0.20333333333333334
|
| 137 |
+
}
|
| 138 |
+
}
|
evaluation/eval_data_MANIFEST.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"eval_version": "sn-loop-eval-v1",
|
| 3 |
+
"seed": 20261030,
|
| 4 |
+
"tasks": {
|
| 5 |
+
"ifeval": {
|
| 6 |
+
"n": 60,
|
| 7 |
+
"file": "ifeval_input_data.jsonl",
|
| 8 |
+
"sha256": "3e9e9e7bd42ef54862f0c71c9a4e6f0b17a9c259f8f4b2b4e5fbcad917228118",
|
| 9 |
+
"repo": "google/IFEval",
|
| 10 |
+
"rev": "966cd89545d6b6acfd7638bc708b98261ca58e84",
|
| 11 |
+
"split": "train (only split; = the IFEval eval set)",
|
| 12 |
+
"license": "Apache-2.0",
|
| 13 |
+
"eligible_pool": "495/541 prompts with only supported instruction ids",
|
| 14 |
+
"raw_file_sha256": "6a85310ca8ce15eff755aa08a3a4ff931c7e273e7515ebb3c492ea85fd8288f2"
|
| 15 |
+
},
|
| 16 |
+
"gsm8k": {
|
| 17 |
+
"n": 80,
|
| 18 |
+
"file": "main/test-00000-of-00001.parquet",
|
| 19 |
+
"sha256": "5bb91d328c1ffc424d6679fe8edb36ed08152e4c75e75b343303e15cacc2da49",
|
| 20 |
+
"repo": "openai/gsm8k",
|
| 21 |
+
"rev": "740312add88f781978c0658806c59bc2815b9866",
|
| 22 |
+
"split": "main/test",
|
| 23 |
+
"license": "MIT",
|
| 24 |
+
"raw_file_sha256": "ee7b8da9e381df27b9e3f7758a159ab2bdaa4dbaa910546cbbc47e0cb44e4f59"
|
| 25 |
+
},
|
| 26 |
+
"mmlu_pro": {
|
| 27 |
+
"n": 60,
|
| 28 |
+
"file": "data/test-00000-of-00001.parquet",
|
| 29 |
+
"sha256": "e9d8d5717def43a0b995710ab093a13de48b4cfb4db19cd7c66affacfb492ea7",
|
| 30 |
+
"repo": "TIGER-Lab/MMLU-Pro",
|
| 31 |
+
"rev": "b189ec765aa7ed75c8acfea42df31fdae71f97be",
|
| 32 |
+
"split": "test",
|
| 33 |
+
"license": "MIT",
|
| 34 |
+
"raw_file_sha256": "0e24a191921c2f453518a537a8b2117bd137e7714d4ef1565e9ba06c1ecb9ad8"
|
| 35 |
+
},
|
| 36 |
+
"humaneval": {
|
| 37 |
+
"n": 40,
|
| 38 |
+
"file": "openai_humaneval/test-00000-of-00001.parquet",
|
| 39 |
+
"sha256": "1e775e30085b890c19c48a583bfabb8f5f54598b5bf54796839b92e5bafdab9f",
|
| 40 |
+
"repo": "openai/openai_humaneval",
|
| 41 |
+
"rev": "7dce6050a7d6d172f3cc5c32aa97f52fa1a2e544",
|
| 42 |
+
"split": "test",
|
| 43 |
+
"license": "MIT",
|
| 44 |
+
"raw_file_sha256": "2f2871a15fbc95b6c683043359f4ed8e144c5a1c4f24f25f66bc51f598dfcfb6"
|
| 45 |
+
},
|
| 46 |
+
"tools": {
|
| 47 |
+
"n": 20,
|
| 48 |
+
"file": "eval/tool_cases.py",
|
| 49 |
+
"sha256": "037b2e288f4f063e8a2d994799b4a51e4d97740b1cf62da75844243749dbb08a",
|
| 50 |
+
"repo": "(hand-written, eval/tool_cases.py)",
|
| 51 |
+
"rev": "in-repo",
|
| 52 |
+
"split": "n/a",
|
| 53 |
+
"license": "Apache-2.0 (this project); BFCL-style categories, no BFCL text"
|
| 54 |
+
},
|
| 55 |
+
"vqa": {
|
| 56 |
+
"n": 40,
|
| 57 |
+
"file": "data/validation-00000-of-00003.parquet",
|
| 58 |
+
"sha256": "7d47303ecdf3386d04a852ab8b7e8be8d34137a1c4d10143331cc7175ce80d9d",
|
| 59 |
+
"repo": "lmms-lab/textvqa",
|
| 60 |
+
"rev": "9c0699cd19768ac5ab97568f6b3cbac4c0062884",
|
| 61 |
+
"split": "validation (shard 0 of 3, 1667 of 5000 rows)",
|
| 62 |
+
"license": "TextVQA annotations CC-BY-4.0; images from OpenImages (CC-BY-2.0, per-image Flickr attribution)",
|
| 63 |
+
"eligible_pool": "1630/1667 questions with a >=3-annotator consensus answer",
|
| 64 |
+
"raw_file_sha256": "491649b5b8add2c5bde13a1e36707002fcd11898699255d65e2e568ac4fbddff"
|
| 65 |
+
}
|
| 66 |
+
}
|
| 67 |
+
}
|
evaluation/harness/build_eval_data.py
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python
|
| 2 |
+
"""Select the FIXED eval items from pinned dataset revisions and write them to eval/data/.
|
| 3 |
+
|
| 4 |
+
Run once (needs HF access only if eval/data/raw is missing; see download list in DATASETS):
|
| 5 |
+
.venv-eval/bin/python eval/build_eval_data.py
|
| 6 |
+
Outputs: eval/data/<task>.jsonl, eval/data/images/*.jpg, eval/data/MANIFEST.json (with sha256s).
|
| 7 |
+
Re-running produces byte-identical files (fixed seeds, sorted inputs).
|
| 8 |
+
"""
|
| 9 |
+
from __future__ import annotations
|
| 10 |
+
|
| 11 |
+
import hashlib
|
| 12 |
+
import json
|
| 13 |
+
import os
|
| 14 |
+
import random
|
| 15 |
+
import sys
|
| 16 |
+
from pathlib import Path
|
| 17 |
+
|
| 18 |
+
HERE = Path(__file__).resolve().parent
|
| 19 |
+
sys.path.insert(0, str(HERE))
|
| 20 |
+
import pyarrow.parquet as pq # noqa: E402
|
| 21 |
+
|
| 22 |
+
import ifeval_lite # noqa: E402
|
| 23 |
+
from common import EVAL_VERSION, write_jsonl # noqa: E402
|
| 24 |
+
from tool_cases import CASES # noqa: E402
|
| 25 |
+
|
| 26 |
+
DATA = HERE / "data"
|
| 27 |
+
RAW = DATA / "raw"
|
| 28 |
+
SEED = 20261030
|
| 29 |
+
N = {"ifeval": 60, "gsm8k": 80, "mmlu_pro": 60, "humaneval": 40, "tools": len(CASES), "vqa": 40}
|
| 30 |
+
|
| 31 |
+
DATASETS = {
|
| 32 |
+
"ifeval": dict(repo="google/IFEval", rev="966cd89545d6b6acfd7638bc708b98261ca58e84",
|
| 33 |
+
file="ifeval_input_data.jsonl", split="train (only split; = the IFEval eval set)",
|
| 34 |
+
license="Apache-2.0"),
|
| 35 |
+
"gsm8k": dict(repo="openai/gsm8k", rev="740312add88f781978c0658806c59bc2815b9866",
|
| 36 |
+
file="main/test-00000-of-00001.parquet", split="main/test", license="MIT"),
|
| 37 |
+
"mmlu_pro": dict(repo="TIGER-Lab/MMLU-Pro", rev="b189ec765aa7ed75c8acfea42df31fdae71f97be",
|
| 38 |
+
file="data/test-00000-of-00001.parquet", split="test", license="MIT"),
|
| 39 |
+
"humaneval": dict(repo="openai/openai_humaneval", rev="7dce6050a7d6d172f3cc5c32aa97f52fa1a2e544",
|
| 40 |
+
file="openai_humaneval/test-00000-of-00001.parquet", split="test", license="MIT"),
|
| 41 |
+
"tools": dict(repo="(hand-written, eval/tool_cases.py)", rev="in-repo", file="eval/tool_cases.py",
|
| 42 |
+
split="n/a", license="Apache-2.0 (this project); BFCL-style categories, no BFCL text"),
|
| 43 |
+
"vqa": dict(repo="lmms-lab/textvqa", rev="9c0699cd19768ac5ab97568f6b3cbac4c0062884",
|
| 44 |
+
file="data/validation-00000-of-00003.parquet",
|
| 45 |
+
split="validation (shard 0 of 3, 1667 of 5000 rows)",
|
| 46 |
+
license="TextVQA annotations CC-BY-4.0; images from OpenImages (CC-BY-2.0, per-image Flickr attribution)"),
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def raw_path(task):
|
| 51 |
+
d = DATASETS[task]
|
| 52 |
+
return RAW / d["repo"].replace("/", "__") / d["file"]
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
def sha256(p):
|
| 56 |
+
h = hashlib.sha256()
|
| 57 |
+
with open(p, "rb") as f:
|
| 58 |
+
for chunk in iter(lambda: f.read(1 << 20), b""):
|
| 59 |
+
h.update(chunk)
|
| 60 |
+
return h.hexdigest()
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
def pick(rows, n, task):
|
| 64 |
+
rng = random.Random(f"{SEED}-{task}")
|
| 65 |
+
idx = sorted(rng.sample(range(len(rows)), n))
|
| 66 |
+
return idx
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
def build():
|
| 70 |
+
DATA.mkdir(exist_ok=True)
|
| 71 |
+
(DATA / "images").mkdir(exist_ok=True)
|
| 72 |
+
out = {}
|
| 73 |
+
|
| 74 |
+
# IFEval: restrict to prompts whose instructions are all supported by ifeval_lite
|
| 75 |
+
rows = [json.loads(l) for l in open(raw_path("ifeval"))]
|
| 76 |
+
rows.sort(key=lambda r: r["key"])
|
| 77 |
+
elig = [r for r in rows if all(i in ifeval_lite.SUPPORTED for i in r["instruction_id_list"])]
|
| 78 |
+
sel = [elig[i] for i in pick(elig, N["ifeval"], "ifeval")]
|
| 79 |
+
out["ifeval"] = [dict(id=f"ifeval_{r['key']}", key=r["key"], prompt=r["prompt"],
|
| 80 |
+
instruction_id_list=r["instruction_id_list"], kwargs=r["kwargs"]) for r in sel]
|
| 81 |
+
DATASETS["ifeval"]["eligible_pool"] = f"{len(elig)}/{len(rows)} prompts with only supported instruction ids"
|
| 82 |
+
|
| 83 |
+
rows = pq.read_table(raw_path("gsm8k")).to_pylist()
|
| 84 |
+
idx = pick(rows, N["gsm8k"], "gsm8k")
|
| 85 |
+
out["gsm8k"] = [dict(id=f"gsm8k_test_{i}", source_index=i, question=rows[i]["question"],
|
| 86 |
+
answer=rows[i]["answer"].split("####")[-1].strip().replace(",", ""),
|
| 87 |
+
solution=rows[i]["answer"]) for i in idx]
|
| 88 |
+
|
| 89 |
+
rows = pq.read_table(raw_path("mmlu_pro"), columns=["question_id", "question", "options", "answer",
|
| 90 |
+
"category", "src"]).to_pylist()
|
| 91 |
+
rows.sort(key=lambda r: r["question_id"])
|
| 92 |
+
idx = pick(rows, N["mmlu_pro"], "mmlu_pro")
|
| 93 |
+
out["mmlu_pro"] = [dict(id=f"mmlupro_{rows[i]['question_id']}", **rows[i]) for i in idx]
|
| 94 |
+
|
| 95 |
+
rows = pq.read_table(raw_path("humaneval")).to_pylist()
|
| 96 |
+
idx = pick(rows, N["humaneval"], "humaneval")
|
| 97 |
+
out["humaneval"] = [dict(id=rows[i]["task_id"].replace("/", "_"), **rows[i]) for i in idx]
|
| 98 |
+
|
| 99 |
+
out["tools"] = [dict(c) for c in CASES]
|
| 100 |
+
|
| 101 |
+
tbl = pq.read_table(raw_path("vqa"), columns=["question_id", "question", "answers", "image_id",
|
| 102 |
+
"image", "flickr_original_url"])
|
| 103 |
+
qids = tbl.column("question_id").to_pylist()
|
| 104 |
+
order = sorted(range(len(qids)), key=lambda i: qids[i])
|
| 105 |
+
# only questions with a consensus answer (some normalized answer given by >=3 of 10 annotators)
|
| 106 |
+
from collections import Counter
|
| 107 |
+
from tasks import vqa_norm
|
| 108 |
+
answers = tbl.column("answers").to_pylist()
|
| 109 |
+
order = [i for i in order if Counter(vqa_norm(a) for a in answers[i]).most_common(1)[0][1] >= 3]
|
| 110 |
+
DATASETS["vqa"]["eligible_pool"] = f"{len(order)}/{len(qids)} questions with a >=3-annotator consensus answer"
|
| 111 |
+
idx = [order[i] for i in pick(order, N["vqa"], "vqa")]
|
| 112 |
+
items = []
|
| 113 |
+
for i in idx:
|
| 114 |
+
r = tbl.slice(i, 1).to_pylist()[0]
|
| 115 |
+
img = r["image"]["bytes"]
|
| 116 |
+
ext = "png" if img[:4] == b"\x89PNG" else "jpg"
|
| 117 |
+
rel = f"images/textvqa_val_{r['question_id']}.{ext}"
|
| 118 |
+
(DATA / rel).write_bytes(img)
|
| 119 |
+
items.append(dict(id=f"textvqa_val_{r['question_id']}", question_id=r["question_id"],
|
| 120 |
+
image_id=r["image_id"], image=rel, image_sha256=hashlib.sha256(img).hexdigest(),
|
| 121 |
+
question=r["question"], answers=r["answers"],
|
| 122 |
+
image_source_url=r["flickr_original_url"]))
|
| 123 |
+
out["vqa"] = items
|
| 124 |
+
|
| 125 |
+
manifest = {"eval_version": EVAL_VERSION, "seed": SEED, "tasks": {}}
|
| 126 |
+
for task, rows in out.items():
|
| 127 |
+
assert len(rows) == N[task], (task, len(rows))
|
| 128 |
+
p = DATA / f"{task}.jsonl"
|
| 129 |
+
write_jsonl(p, rows)
|
| 130 |
+
manifest["tasks"][task] = {"n": len(rows), "file": p.name, "sha256": sha256(p), **DATASETS[task]}
|
| 131 |
+
if raw_path(task).exists() if task != "tools" else False:
|
| 132 |
+
manifest["tasks"][task]["raw_file_sha256"] = sha256(raw_path(task))
|
| 133 |
+
with open(DATA / "MANIFEST.json", "w") as f:
|
| 134 |
+
json.dump(manifest, f, indent=2)
|
| 135 |
+
print(json.dumps({t: v["n"] for t, v in manifest["tasks"].items()}), "total", sum(N.values()))
|
| 136 |
+
|
| 137 |
+
|
| 138 |
+
if __name__ == "__main__":
|
| 139 |
+
build()
|
evaluation/harness/common.py
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Shared helpers for the SenseNova-Loop NVFP4 eval harness (stdlib + requests only)."""
|
| 2 |
+
from __future__ import annotations
|
| 3 |
+
|
| 4 |
+
import json
|
| 5 |
+
import math
|
| 6 |
+
import re
|
| 7 |
+
import time
|
| 8 |
+
from typing import Any
|
| 9 |
+
|
| 10 |
+
EVAL_VERSION = "sn-loop-eval-v1"
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
# ----------------------------------------------------------------------------- stats
|
| 14 |
+
def wilson_ci(k: int, n: int, z: float = 1.959964) -> tuple[float, float]:
|
| 15 |
+
if n == 0:
|
| 16 |
+
return (float("nan"), float("nan"))
|
| 17 |
+
p = k / n
|
| 18 |
+
den = 1 + z * z / n
|
| 19 |
+
centre = (p + z * z / (2 * n)) / den
|
| 20 |
+
half = z * math.sqrt(p * (1 - p) / n + z * z / (4 * n * n)) / den
|
| 21 |
+
return (max(0.0, centre - half), min(1.0, centre + half))
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
# ----------------------------------------------------------------------------- text utils
|
| 25 |
+
THINK_RE = re.compile(r"<think>.*?</think>\s*", re.S)
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def strip_think(text: str | None) -> str:
|
| 29 |
+
"""Remove any <think>...</think> block (and a dangling '...</think>' prefix)."""
|
| 30 |
+
if not text:
|
| 31 |
+
return ""
|
| 32 |
+
text = THINK_RE.sub("", text)
|
| 33 |
+
if "</think>" in text:
|
| 34 |
+
text = text.split("</think>")[-1]
|
| 35 |
+
return text.strip()
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
# ----------------------------------------------------------------------------- tool-call parsing
|
| 39 |
+
# Chat template (Qwen3.5-style XML) emits:
|
| 40 |
+
# <tool_call>\n<function=NAME>\n<parameter=ARG>\nVALUE\n</parameter>\n...</function>\n</tool_call>
|
| 41 |
+
# String values are written raw; dict/list values as JSON (tojson); numbers/bools via |string
|
| 42 |
+
# (so Python-ish 'True'/'False' are possible).
|
| 43 |
+
TOOL_CALL_RE = re.compile(r"<tool_call>\s*<function=([^>\n]+)>(.*?)</function>\s*</tool_call>", re.S)
|
| 44 |
+
PARAM_RE = re.compile(r"<parameter=([^>\n]+)>\n?(.*?)\n?</parameter>", re.S)
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
def _coerce(value: str, schema: dict | None) -> Any:
|
| 48 |
+
typ = (schema or {}).get("type")
|
| 49 |
+
if typ == "string":
|
| 50 |
+
return value
|
| 51 |
+
v = value.strip()
|
| 52 |
+
if typ == "boolean" or v in ("True", "False"):
|
| 53 |
+
if v.lower() in ("true", "false"):
|
| 54 |
+
return v.lower() == "true"
|
| 55 |
+
try:
|
| 56 |
+
return json.loads(v)
|
| 57 |
+
except Exception:
|
| 58 |
+
pass
|
| 59 |
+
if typ in ("integer", "number"):
|
| 60 |
+
try:
|
| 61 |
+
return float(v) if "." in v else int(v)
|
| 62 |
+
except ValueError:
|
| 63 |
+
return v
|
| 64 |
+
return value
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
def parse_xml_tool_calls(text: str, tools: list[dict] | None = None) -> tuple[list[dict], dict]:
|
| 68 |
+
"""Fallback parser for raw-text tool calls. Returns (calls, format_report)."""
|
| 69 |
+
schemas: dict[str, dict] = {}
|
| 70 |
+
for t in tools or []:
|
| 71 |
+
fn = t.get("function", t)
|
| 72 |
+
schemas[fn.get("name")] = (fn.get("parameters") or {}).get("properties") or {}
|
| 73 |
+
calls = []
|
| 74 |
+
for m in TOOL_CALL_RE.finditer(text or ""):
|
| 75 |
+
name = m.group(1).strip()
|
| 76 |
+
args = {}
|
| 77 |
+
for pm in PARAM_RE.finditer(m.group(2)):
|
| 78 |
+
pname = pm.group(1).strip()
|
| 79 |
+
args[pname] = _coerce(pm.group(2), schemas.get(name, {}).get(pname))
|
| 80 |
+
calls.append({"name": name, "arguments": args})
|
| 81 |
+
n_open = (text or "").count("<tool_call>")
|
| 82 |
+
n_close = (text or "").count("</tool_call>")
|
| 83 |
+
tail = (text or "").split("</tool_call>")[-1].strip() if n_close else ""
|
| 84 |
+
report = {
|
| 85 |
+
"n_tool_call_tags": n_open,
|
| 86 |
+
"balanced_tags": n_open == n_close,
|
| 87 |
+
"all_blocks_parsed": n_open == len(calls),
|
| 88 |
+
"suffix_after_last_call": bool(tail), # template says: NO suffix after the call
|
| 89 |
+
"well_formed": n_open > 0 and n_open == n_close == len(calls),
|
| 90 |
+
}
|
| 91 |
+
return calls, report
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
def calls_from_message(msg: dict, tools: list[dict] | None) -> tuple[list[dict], str, dict]:
|
| 95 |
+
"""Return (calls, source, format_report). source in {'server','fallback_xml','none'}."""
|
| 96 |
+
tcs = msg.get("tool_calls") or []
|
| 97 |
+
if tcs:
|
| 98 |
+
calls, ok = [], True
|
| 99 |
+
for tc in tcs:
|
| 100 |
+
fn = tc.get("function", tc)
|
| 101 |
+
raw = fn.get("arguments")
|
| 102 |
+
if isinstance(raw, str):
|
| 103 |
+
try:
|
| 104 |
+
args = json.loads(raw) if raw.strip() else {}
|
| 105 |
+
except Exception:
|
| 106 |
+
args, ok = {"__unparseable__": raw}, False
|
| 107 |
+
else:
|
| 108 |
+
args = raw or {}
|
| 109 |
+
calls.append({"name": fn.get("name"), "arguments": args})
|
| 110 |
+
return calls, "server", {"well_formed": ok, "args_valid_json": ok}
|
| 111 |
+
content = strip_think(msg.get("content") or "")
|
| 112 |
+
calls, rep = parse_xml_tool_calls(content, tools)
|
| 113 |
+
return calls, ("fallback_xml" if calls else "none"), rep
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
# ----------------------------------------------------------------------------- HTTP client
|
| 117 |
+
def chat(session, base_url: str, model: str, messages: list, *, max_tokens: int,
|
| 118 |
+
tools: list | None = None, enable_thinking: bool = False, timeout: float = 600,
|
| 119 |
+
retries: int = 2, extra: dict | None = None) -> dict:
|
| 120 |
+
"""One deterministic chat completion. Returns a dict with response + timing (never raises)."""
|
| 121 |
+
body: dict[str, Any] = {
|
| 122 |
+
"model": model,
|
| 123 |
+
"messages": messages,
|
| 124 |
+
"temperature": 0.0,
|
| 125 |
+
"top_p": 1.0,
|
| 126 |
+
"max_tokens": max_tokens,
|
| 127 |
+
"seed": 0,
|
| 128 |
+
"chat_template_kwargs": {"enable_thinking": enable_thinking},
|
| 129 |
+
}
|
| 130 |
+
if tools:
|
| 131 |
+
body["tools"] = tools
|
| 132 |
+
body["tool_choice"] = "auto"
|
| 133 |
+
if extra:
|
| 134 |
+
body.update(extra)
|
| 135 |
+
url = base_url.rstrip("/") + "/chat/completions"
|
| 136 |
+
last_err = None
|
| 137 |
+
for attempt in range(retries + 1):
|
| 138 |
+
t0 = time.time()
|
| 139 |
+
try:
|
| 140 |
+
r = session.post(url, json=body, timeout=timeout)
|
| 141 |
+
dt = time.time() - t0
|
| 142 |
+
if r.status_code != 200:
|
| 143 |
+
last_err = f"HTTP {r.status_code}: {r.text[:500]}"
|
| 144 |
+
if r.status_code < 500:
|
| 145 |
+
break
|
| 146 |
+
time.sleep(1 + attempt)
|
| 147 |
+
continue
|
| 148 |
+
j = r.json()
|
| 149 |
+
ch = j["choices"][0]
|
| 150 |
+
msg = ch.get("message") or {}
|
| 151 |
+
return {
|
| 152 |
+
"ok": True,
|
| 153 |
+
"content": msg.get("content") or "",
|
| 154 |
+
"reasoning_content": msg.get("reasoning_content") or msg.get("reasoning") or "",
|
| 155 |
+
"tool_calls": msg.get("tool_calls") or [],
|
| 156 |
+
"message": msg,
|
| 157 |
+
"finish_reason": ch.get("finish_reason"),
|
| 158 |
+
"usage": j.get("usage") or {},
|
| 159 |
+
"latency_s": round(dt, 3),
|
| 160 |
+
"error": None,
|
| 161 |
+
}
|
| 162 |
+
except Exception as e: # noqa: BLE001
|
| 163 |
+
last_err = f"{type(e).__name__}: {e}"
|
| 164 |
+
time.sleep(1 + attempt)
|
| 165 |
+
return {"ok": False, "content": "", "reasoning_content": "", "tool_calls": [], "message": {},
|
| 166 |
+
"finish_reason": None, "usage": {}, "latency_s": None, "error": last_err}
|
| 167 |
+
|
| 168 |
+
|
| 169 |
+
def read_jsonl(path) -> list[dict]:
|
| 170 |
+
with open(path) as f:
|
| 171 |
+
return [json.loads(l) for l in f if l.strip()]
|
| 172 |
+
|
| 173 |
+
|
| 174 |
+
def write_jsonl(path, rows) -> None:
|
| 175 |
+
with open(path, "w") as f:
|
| 176 |
+
for r in rows:
|
| 177 |
+
f.write(json.dumps(r, ensure_ascii=False) + "\n")
|
evaluation/harness/compare.py
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python
|
| 2 |
+
"""Paired comparison of two run_eval.py output dirs (reference vs candidate).
|
| 3 |
+
|
| 4 |
+
.venv-eval/bin/python eval/compare.py eval/runs/bf16 eval/runs/nvfp4 [--json out.json]
|
| 5 |
+
|
| 6 |
+
Per task (on the intersection of item ids):
|
| 7 |
+
* ref / cand accuracy, delta, paired bootstrap 95% CI of the delta (10k resamples, seed 0),
|
| 8 |
+
discordant counts (ref-only correct / cand-only correct) and exact McNemar p-value;
|
| 9 |
+
* reference agreement (label-free): fraction of items whose extracted answer == reference's;
|
| 10 |
+
* identical raw outputs %, mean completion tokens ref/cand, truncation counts.
|
| 11 |
+
"""
|
| 12 |
+
from __future__ import annotations
|
| 13 |
+
|
| 14 |
+
import argparse
|
| 15 |
+
import json
|
| 16 |
+
import math
|
| 17 |
+
import random
|
| 18 |
+
import sys
|
| 19 |
+
from pathlib import Path
|
| 20 |
+
|
| 21 |
+
HERE = Path(__file__).resolve().parent
|
| 22 |
+
sys.path.insert(0, str(HERE))
|
| 23 |
+
from common import read_jsonl # noqa: E402
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def load(d):
|
| 27 |
+
d = Path(d)
|
| 28 |
+
out = {}
|
| 29 |
+
for p in sorted(d.glob("raw_*.jsonl")):
|
| 30 |
+
task = p.stem[4:]
|
| 31 |
+
out[task] = {r["id"]: r for r in read_jsonl(p)}
|
| 32 |
+
return out
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def boot_ci(a, b, iters=10000, seed=0):
|
| 36 |
+
n = len(a)
|
| 37 |
+
if n == 0:
|
| 38 |
+
return (float("nan"), float("nan"))
|
| 39 |
+
rng = random.Random(seed)
|
| 40 |
+
diffs = [y - x for x, y in zip(a, b)]
|
| 41 |
+
stats = []
|
| 42 |
+
for _ in range(iters):
|
| 43 |
+
s = 0
|
| 44 |
+
for _ in range(n):
|
| 45 |
+
s += diffs[rng.randrange(n)]
|
| 46 |
+
stats.append(s / n)
|
| 47 |
+
stats.sort()
|
| 48 |
+
return (stats[int(0.025 * iters)], stats[int(0.975 * iters) - 1])
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
def mcnemar_exact(b, c):
|
| 52 |
+
n = b + c
|
| 53 |
+
if n == 0:
|
| 54 |
+
return 1.0
|
| 55 |
+
k = min(b, c)
|
| 56 |
+
p = sum(math.comb(n, i) for i in range(k + 1)) / 2 ** n
|
| 57 |
+
return min(1.0, 2 * p)
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
def norm_out(r):
|
| 61 |
+
return json.dumps([r.get("content") or "", r.get("tool_calls") or []], sort_keys=True)
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
def compare(ref_dir, cand_dir):
|
| 65 |
+
ref, cand = load(ref_dir), load(cand_dir)
|
| 66 |
+
res = {"ref": str(ref_dir), "cand": str(cand_dir), "tasks": {}}
|
| 67 |
+
tot = {"n": 0, "ref": 0, "cand": 0, "agree": 0, "ident": 0, "a": [], "b": []}
|
| 68 |
+
for task in ref:
|
| 69 |
+
if task not in cand:
|
| 70 |
+
continue
|
| 71 |
+
ids = sorted(set(ref[task]) & set(cand[task]))
|
| 72 |
+
a = [int(ref[task][i]["correct"]) for i in ids]
|
| 73 |
+
b = [int(cand[task][i]["correct"]) for i in ids]
|
| 74 |
+
n = len(ids)
|
| 75 |
+
agree = sum(1 for i in ids if json.dumps(ref[task][i].get("agree_key"), sort_keys=True)
|
| 76 |
+
== json.dumps(cand[task][i].get("agree_key"), sort_keys=True))
|
| 77 |
+
ident = sum(1 for i in ids if norm_out(ref[task][i]) == norm_out(cand[task][i]))
|
| 78 |
+
ref_only = sum(1 for x, y in zip(a, b) if x and not y)
|
| 79 |
+
cand_only = sum(1 for x, y in zip(a, b) if y and not x)
|
| 80 |
+
|
| 81 |
+
def mtok(rs):
|
| 82 |
+
t = [r["completion_tokens"] for r in rs if r.get("completion_tokens") is not None]
|
| 83 |
+
return round(sum(t) / len(t), 1) if t else None
|
| 84 |
+
lo, hi = boot_ci(a, b)
|
| 85 |
+
res["tasks"][task] = {
|
| 86 |
+
"n": n, "ref_acc": sum(a) / n, "cand_acc": sum(b) / n, "delta": (sum(b) - sum(a)) / n,
|
| 87 |
+
"delta_boot95": [lo, hi], "ref_only_correct": ref_only, "cand_only_correct": cand_only,
|
| 88 |
+
"mcnemar_p": mcnemar_exact(ref_only, cand_only),
|
| 89 |
+
"ref_agreement": agree / n, "identical_output": ident / n,
|
| 90 |
+
"mean_tokens_ref": mtok([ref[task][i] for i in ids]),
|
| 91 |
+
"mean_tokens_cand": mtok([cand[task][i] for i in ids]),
|
| 92 |
+
"truncated_ref": sum(1 for i in ids if ref[task][i].get("finish_reason") == "length"),
|
| 93 |
+
"truncated_cand": sum(1 for i in ids if cand[task][i].get("finish_reason") == "length"),
|
| 94 |
+
"errors_cand": sum(1 for i in ids if cand[task][i].get("error")),
|
| 95 |
+
}
|
| 96 |
+
tot["n"] += n
|
| 97 |
+
tot["ref"] += sum(a)
|
| 98 |
+
tot["cand"] += sum(b)
|
| 99 |
+
tot["agree"] += agree
|
| 100 |
+
tot["ident"] += ident
|
| 101 |
+
tot["a"] += a
|
| 102 |
+
tot["b"] += b
|
| 103 |
+
if tot["n"]:
|
| 104 |
+
lo, hi = boot_ci(tot["a"], tot["b"])
|
| 105 |
+
res["overall_micro"] = {"n": tot["n"], "ref_acc": tot["ref"] / tot["n"], "cand_acc": tot["cand"] / tot["n"],
|
| 106 |
+
"delta": (tot["cand"] - tot["ref"]) / tot["n"], "delta_boot95": [lo, hi],
|
| 107 |
+
"ref_agreement": tot["agree"] / tot["n"], "identical_output": tot["ident"] / tot["n"]}
|
| 108 |
+
return res
|
| 109 |
+
|
| 110 |
+
|
| 111 |
+
def main():
|
| 112 |
+
ap = argparse.ArgumentParser()
|
| 113 |
+
ap.add_argument("ref_dir")
|
| 114 |
+
ap.add_argument("cand_dir")
|
| 115 |
+
ap.add_argument("--json", default=None)
|
| 116 |
+
args = ap.parse_args()
|
| 117 |
+
res = compare(args.ref_dir, args.cand_dir)
|
| 118 |
+
hdr = f"{'task':10s} {'n':>4s} {'ref':>6s} {'cand':>6s} {'delta':>7s} {'boot95':>17s} {'r-/c+':>6s} {'mcnemar':>7s} {'agree':>6s} {'ident':>6s} {'tok r/c':>13s}"
|
| 119 |
+
print(hdr)
|
| 120 |
+
rows = list(res["tasks"].items()) + ([("ALL(micro)", res["overall_micro"])] if "overall_micro" in res else [])
|
| 121 |
+
for t, s in rows:
|
| 122 |
+
print(f"{t:10s} {s['n']:4d} {s['ref_acc']:6.3f} {s['cand_acc']:6.3f} {s['delta']:+7.3f} "
|
| 123 |
+
f"[{s['delta_boot95'][0]:+.3f},{s['delta_boot95'][1]:+.3f}] "
|
| 124 |
+
f"{str(s.get('ref_only_correct', '')) + '/' + str(s.get('cand_only_correct', '')):>6s} "
|
| 125 |
+
f"{s.get('mcnemar_p', float('nan')):7.3f} {s['ref_agreement']:6.3f} {s['identical_output']:6.3f} "
|
| 126 |
+
f"{str(s.get('mean_tokens_ref'))+'/'+str(s.get('mean_tokens_cand')):>13s}")
|
| 127 |
+
out = args.json or str(Path(args.cand_dir) / "compare_vs_ref.json")
|
| 128 |
+
Path(out).write_text(json.dumps(res, indent=2))
|
| 129 |
+
print("wrote", out)
|
| 130 |
+
|
| 131 |
+
|
| 132 |
+
if __name__ == "__main__":
|
| 133 |
+
main()
|
evaluation/harness/ifeval_lite.py
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Light-weight re-implementation of a SUBSET of the IFEval instruction checkers.
|
| 2 |
+
|
| 3 |
+
Semantics follow google-research/google-research `instruction_following_eval/instructions.py`
|
| 4 |
+
(Apache-2.0, (c) Google LLC), re-written from scratch with these documented deviations:
|
| 5 |
+
* word tokenisation uses regex \\w+ (orig: nltk RegexpTokenizer(r"\\w+") -> identical) and
|
| 6 |
+
capital-word counting uses whitespace/punct split instead of nltk.word_tokenize;
|
| 7 |
+
* `length_constraints:number_sentences` and a few rarely used ids are NOT supported; the eval
|
| 8 |
+
builder only selects prompts whose every instruction id is in SUPPORTED.
|
| 9 |
+
* language detection uses `langdetect` (Apache-2.0) with a fixed seed, like the original.
|
| 10 |
+
Only "strict" scoring is implemented (prompt-level: all instructions pass).
|
| 11 |
+
"""
|
| 12 |
+
from __future__ import annotations
|
| 13 |
+
|
| 14 |
+
import json
|
| 15 |
+
import re
|
| 16 |
+
import threading
|
| 17 |
+
|
| 18 |
+
_LANG_LOCK = threading.Lock() # langdetect seeds the *global* random module -> not thread-safe
|
| 19 |
+
|
| 20 |
+
try:
|
| 21 |
+
import langdetect
|
| 22 |
+
langdetect.DetectorFactory.seed = 0
|
| 23 |
+
except Exception: # pragma: no cover
|
| 24 |
+
langdetect = None
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def _rel(count: int, relation: str, target: int) -> bool:
|
| 28 |
+
if relation == "less than":
|
| 29 |
+
return count < target
|
| 30 |
+
if relation == "at least":
|
| 31 |
+
return count >= target
|
| 32 |
+
raise ValueError(relation)
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def _lang(text: str) -> str | None:
|
| 36 |
+
if langdetect is None:
|
| 37 |
+
return None
|
| 38 |
+
try:
|
| 39 |
+
with _LANG_LOCK:
|
| 40 |
+
langdetect.DetectorFactory.seed = 0
|
| 41 |
+
return langdetect.detect(text)
|
| 42 |
+
except Exception:
|
| 43 |
+
return None
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
def no_comma(r, **k):
|
| 47 |
+
return "," not in r
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def number_highlighted_sections(r, num_highlights, **k):
|
| 51 |
+
n = 0
|
| 52 |
+
for h in re.findall(r"\*[^\n\*]*\*", r):
|
| 53 |
+
if h.strip("*").strip():
|
| 54 |
+
n += 1
|
| 55 |
+
for h in re.findall(r"\*\*[^\n\*]*\*\*", r):
|
| 56 |
+
if h.removeprefix("**").removesuffix("**").strip():
|
| 57 |
+
n += 1
|
| 58 |
+
return n >= num_highlights
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
def title(r, **k):
|
| 62 |
+
return any(t.lstrip("<").rstrip(">").strip() for t in re.findall(r"<<[^\n]+>>", r))
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
def number_bullet_lists(r, num_bullets, **k):
|
| 66 |
+
a = re.findall(r"^\s*\*[^\*].*$", r, flags=re.M)
|
| 67 |
+
b = re.findall(r"^\s*-.*$", r, flags=re.M)
|
| 68 |
+
return len(a) + len(b) == num_bullets
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
def json_format(r, **k):
|
| 72 |
+
v = r.strip()
|
| 73 |
+
v = re.sub(r"^```(?:json|Json|JSON)?\s*", "", v)
|
| 74 |
+
v = re.sub(r"\s*```$", "", v).strip()
|
| 75 |
+
try:
|
| 76 |
+
json.loads(v)
|
| 77 |
+
return True
|
| 78 |
+
except ValueError:
|
| 79 |
+
return False
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
def multiple_sections(r, section_spliter, num_sections, **k):
|
| 83 |
+
pat = r"\s?" + re.escape(section_spliter.strip()) + r"\s?\d+\s?"
|
| 84 |
+
return len(re.split(pat, r)) - 1 >= num_sections
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
def constrained_response(r, **k):
|
| 88 |
+
v = r.strip()
|
| 89 |
+
return any(o in v for o in ("My answer is yes.", "My answer is no.", "My answer is maybe."))
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
def english_lowercase(r, **k):
|
| 93 |
+
return r == r.lower() and _lang(r) == "en"
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
def english_capital(r, **k):
|
| 97 |
+
return r == r.upper() and _lang(r) == "en"
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
def capital_word_frequency(r, capital_frequency, capital_relation, **k):
|
| 101 |
+
words = re.findall(r"[A-Za-z][A-Za-z'\-]*", r)
|
| 102 |
+
n = sum(1 for w in words if w.isupper())
|
| 103 |
+
return _rel(n, capital_relation, capital_frequency)
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
def number_words(r, num_words, relation, **k):
|
| 107 |
+
return _rel(len(re.findall(r"\w+", r)), relation, num_words)
|
| 108 |
+
|
| 109 |
+
|
| 110 |
+
def number_paragraphs(r, num_paragraphs, **k):
|
| 111 |
+
paras = re.split(r"\s?\*\*\*\s?", r)
|
| 112 |
+
n = len(paras)
|
| 113 |
+
for i, p in enumerate(paras):
|
| 114 |
+
if not p.strip():
|
| 115 |
+
if i == 0 or i == len(paras) - 1:
|
| 116 |
+
n -= 1
|
| 117 |
+
else:
|
| 118 |
+
return False
|
| 119 |
+
return n == num_paragraphs
|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
def nth_paragraph_first_word(r, num_paragraphs, nth_paragraph, first_word, **k):
|
| 123 |
+
paras = re.split(r"\n\n", r)
|
| 124 |
+
n = sum(1 for p in paras if p.strip())
|
| 125 |
+
paras_ne = [p for p in paras if p.strip()]
|
| 126 |
+
if nth_paragraph > len(paras_ne):
|
| 127 |
+
return False
|
| 128 |
+
p = paras_ne[nth_paragraph - 1].strip()
|
| 129 |
+
if not p:
|
| 130 |
+
return False
|
| 131 |
+
word = p.split()[0].strip()
|
| 132 |
+
word = word.lstrip("'\"").rstrip(".,?!'\"").lower()
|
| 133 |
+
# original strips leading/trailing punctuation char by char
|
| 134 |
+
word = re.sub(r"[^\w]+$", "", re.sub(r"^[^\w]+", "", word))
|
| 135 |
+
return n == num_paragraphs and word == first_word.lower()
|
| 136 |
+
|
| 137 |
+
|
| 138 |
+
def existence(r, keywords, **k):
|
| 139 |
+
return all(re.search(kw, r, flags=re.I) for kw in keywords)
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
def frequency(r, keyword, frequency, relation, **k):
|
| 143 |
+
return _rel(len(re.findall(keyword, r, flags=re.I)), relation, frequency)
|
| 144 |
+
|
| 145 |
+
|
| 146 |
+
def forbidden_words(r, forbidden_words, **k):
|
| 147 |
+
return not any(re.search(r"\b" + w + r"\b", r, flags=re.I) for w in forbidden_words)
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
def letter_frequency(r, letter, let_frequency, let_relation, **k):
|
| 151 |
+
return _rel(r.lower().count(letter.lower()), let_relation, let_frequency)
|
| 152 |
+
|
| 153 |
+
|
| 154 |
+
def end_checker(r, end_phrase, **k):
|
| 155 |
+
return r.strip().strip('"').lower().endswith(end_phrase.strip().lower())
|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
def quotation(r, **k):
|
| 159 |
+
v = r.strip()
|
| 160 |
+
return len(v) > 1 and v[0] == '"' and v[-1] == '"'
|
| 161 |
+
|
| 162 |
+
|
| 163 |
+
def postscript(r, postscript_marker, **k):
|
| 164 |
+
v = r.lower()
|
| 165 |
+
m = postscript_marker.strip()
|
| 166 |
+
if m == "P.P.S":
|
| 167 |
+
pat = r"\s*p\.\s?p\.\s?s.*$"
|
| 168 |
+
elif m == "P.S.":
|
| 169 |
+
pat = r"\s*p\.\s?s\..*$"
|
| 170 |
+
else:
|
| 171 |
+
pat = r"\s*" + re.escape(m.lower()) + r".*$"
|
| 172 |
+
return bool(re.findall(pat, v, flags=re.M))
|
| 173 |
+
|
| 174 |
+
|
| 175 |
+
def number_placeholders(r, num_placeholders, **k):
|
| 176 |
+
return len(re.findall(r"\[.*?\]", r)) >= num_placeholders
|
| 177 |
+
|
| 178 |
+
|
| 179 |
+
def repeat_prompt(r, prompt_to_repeat, **k):
|
| 180 |
+
return r.strip().lower().startswith(prompt_to_repeat.strip().lower())
|
| 181 |
+
|
| 182 |
+
|
| 183 |
+
def two_responses(r, **k):
|
| 184 |
+
parts = r.split("******")
|
| 185 |
+
valid = []
|
| 186 |
+
for i, p in enumerate(parts):
|
| 187 |
+
if not p.strip():
|
| 188 |
+
if i != 0 and i != len(parts) - 1:
|
| 189 |
+
return False
|
| 190 |
+
else:
|
| 191 |
+
valid.append(p)
|
| 192 |
+
return len(valid) == 2 and valid[0].strip() != valid[1].strip()
|
| 193 |
+
|
| 194 |
+
|
| 195 |
+
def response_language(r, language, **k):
|
| 196 |
+
return _lang(r) == language
|
| 197 |
+
|
| 198 |
+
|
| 199 |
+
SUPPORTED = {
|
| 200 |
+
"punctuation:no_comma": no_comma,
|
| 201 |
+
"detectable_format:number_highlighted_sections": number_highlighted_sections,
|
| 202 |
+
"detectable_format:title": title,
|
| 203 |
+
"detectable_format:number_bullet_lists": number_bullet_lists,
|
| 204 |
+
"detectable_format:json_format": json_format,
|
| 205 |
+
"detectable_format:multiple_sections": multiple_sections,
|
| 206 |
+
"detectable_format:constrained_response": constrained_response,
|
| 207 |
+
"change_case:english_lowercase": english_lowercase,
|
| 208 |
+
"change_case:english_capital": english_capital,
|
| 209 |
+
"change_case:capital_word_frequency": capital_word_frequency,
|
| 210 |
+
"length_constraints:number_words": number_words,
|
| 211 |
+
"length_constraints:number_paragraphs": number_paragraphs,
|
| 212 |
+
"length_constraints:nth_paragraph_first_word": nth_paragraph_first_word,
|
| 213 |
+
"keywords:existence": existence,
|
| 214 |
+
"keywords:frequency": frequency,
|
| 215 |
+
"keywords:forbidden_words": forbidden_words,
|
| 216 |
+
"keywords:letter_frequency": letter_frequency,
|
| 217 |
+
"startend:end_checker": end_checker,
|
| 218 |
+
"startend:quotation": quotation,
|
| 219 |
+
"detectable_content:postscript": postscript,
|
| 220 |
+
"detectable_content:number_placeholders": number_placeholders,
|
| 221 |
+
"combination:repeat_prompt": repeat_prompt,
|
| 222 |
+
"combination:two_responses": two_responses,
|
| 223 |
+
"language:response_language": response_language,
|
| 224 |
+
}
|
| 225 |
+
|
| 226 |
+
|
| 227 |
+
def check(response: str, instruction_ids: list[str], kwargs_list: list[dict]) -> list[bool]:
|
| 228 |
+
out = []
|
| 229 |
+
for iid, kw in zip(instruction_ids, kwargs_list):
|
| 230 |
+
kw = {k: v for k, v in (kw or {}).items() if v is not None}
|
| 231 |
+
fn = SUPPORTED[iid]
|
| 232 |
+
try:
|
| 233 |
+
out.append(bool(response.strip()) and bool(fn(response, **kw)))
|
| 234 |
+
except Exception:
|
| 235 |
+
out.append(False)
|
| 236 |
+
return out
|
evaluation/harness/mock_server.py
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python
|
| 2 |
+
"""Tiny OpenAI-compatible mock server that answers eval items with their GOLD answers.
|
| 3 |
+
Used only to test the harness offline (scorers, raw-text tool-call fallback parser, compare, perf_bench).
|
| 4 |
+
|
| 5 |
+
.venv-eval/bin/python eval/mock_server.py --port 18999 [--tool-mode server|xml] [--corrupt-every K]
|
| 6 |
+
|
| 7 |
+
--tool-mode xml returns tool calls as raw Qwen3.5-XML text in `content` (as a server without a
|
| 8 |
+
tool parser would), exercising the fallback parser. --corrupt-every K returns a wrong answer for
|
| 9 |
+
items whose id hash % K == 0 (to test compare.py deltas). Streaming is supported for perf_bench.
|
| 10 |
+
"""
|
| 11 |
+
from __future__ import annotations
|
| 12 |
+
|
| 13 |
+
import argparse
|
| 14 |
+
import hashlib
|
| 15 |
+
import json
|
| 16 |
+
import sys
|
| 17 |
+
import time
|
| 18 |
+
from collections import Counter
|
| 19 |
+
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
| 20 |
+
from pathlib import Path
|
| 21 |
+
|
| 22 |
+
HERE = Path(__file__).resolve().parent
|
| 23 |
+
sys.path.insert(0, str(HERE))
|
| 24 |
+
from common import read_jsonl # noqa: E402
|
| 25 |
+
from tasks import TASKS, vqa_norm # noqa: E402
|
| 26 |
+
|
| 27 |
+
ARGS = None
|
| 28 |
+
INDEX: dict[str, tuple[str, dict]] = {}
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
def last_user_text(messages):
|
| 32 |
+
for m in reversed(messages):
|
| 33 |
+
if m["role"] == "user":
|
| 34 |
+
c = m["content"]
|
| 35 |
+
if isinstance(c, list):
|
| 36 |
+
return "".join(p.get("text", "") for p in c if p.get("type") == "text")
|
| 37 |
+
return c
|
| 38 |
+
return ""
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
def build_index():
|
| 42 |
+
for task, (build, _) in TASKS.items():
|
| 43 |
+
for item in read_jsonl(HERE / "data" / f"{task}.jsonl"):
|
| 44 |
+
msgs, _ = build(item, HERE / "data")
|
| 45 |
+
INDEX[last_user_text(msgs)] = (task, item)
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
def xml_call(c):
|
| 49 |
+
s = f"<tool_call>\n<function={c['name']}>\n"
|
| 50 |
+
for k, v in c["arguments"].items():
|
| 51 |
+
v = json.dumps(v) if isinstance(v, (dict, list)) else (str(v) if not isinstance(v, bool) else str(v))
|
| 52 |
+
s += f"<parameter={k}>\n{v}\n</parameter>\n"
|
| 53 |
+
return s + "</function>\n</tool_call>"
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
def gold_response(task, item, corrupt):
|
| 57 |
+
"""Return (content, tool_calls)."""
|
| 58 |
+
if task == "ifeval":
|
| 59 |
+
return "this is a mock response without commas.", None
|
| 60 |
+
if task == "gsm8k":
|
| 61 |
+
ans = str(int(item["answer"]) + 1) if corrupt else item["answer"]
|
| 62 |
+
body = item["solution"].split("####")[0].strip()
|
| 63 |
+
return f"{body}\nThe final answer is {ans}", None
|
| 64 |
+
if task == "mmlu_pro":
|
| 65 |
+
a = "ABCDEFGHIJ"[(("ABCDEFGHIJ".index(item["answer"]) + 1) % len(item["options"]))] if corrupt else item["answer"]
|
| 66 |
+
return f"Let's think. The answer is ({a}).", None
|
| 67 |
+
if task == "humaneval":
|
| 68 |
+
sol = " return None\n" if corrupt else item["canonical_solution"]
|
| 69 |
+
return f"Here is the code:\n```python\n{item['prompt']}{sol}```", None
|
| 70 |
+
if task == "vqa":
|
| 71 |
+
return ("zzz" if corrupt else Counter(vqa_norm(a) for a in item["answers"]).most_common(1)[0][0]), None
|
| 72 |
+
if task == "tools":
|
| 73 |
+
if not item["gold_calls"] or corrupt:
|
| 74 |
+
return "I can answer that directly: mock.", None
|
| 75 |
+
calls = []
|
| 76 |
+
for g in item["gold_calls"]:
|
| 77 |
+
args = {k: v[0] for k, v in g["arguments"].items() if v and v[0] != "__optional__"}
|
| 78 |
+
calls.append({"name": g["name"], "arguments": args})
|
| 79 |
+
if ARGS.tool_mode == "xml":
|
| 80 |
+
return "\n".join(xml_call(c) for c in calls), None
|
| 81 |
+
return None, [{"id": f"call_{i}", "type": "function",
|
| 82 |
+
"function": {"name": c["name"], "arguments": json.dumps(c["arguments"])}}
|
| 83 |
+
for i, c in enumerate(calls)]
|
| 84 |
+
return "unknown", None
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
class H(BaseHTTPRequestHandler):
|
| 88 |
+
protocol_version = "HTTP/1.1"
|
| 89 |
+
|
| 90 |
+
def log_message(self, *a):
|
| 91 |
+
pass
|
| 92 |
+
|
| 93 |
+
def _send(self, code, obj):
|
| 94 |
+
b = json.dumps(obj).encode()
|
| 95 |
+
self.send_response(code)
|
| 96 |
+
self.send_header("Content-Type", "application/json")
|
| 97 |
+
self.send_header("Content-Length", str(len(b)))
|
| 98 |
+
self.end_headers()
|
| 99 |
+
self.wfile.write(b)
|
| 100 |
+
|
| 101 |
+
def do_GET(self):
|
| 102 |
+
if self.path.endswith("/models"):
|
| 103 |
+
return self._send(200, {"object": "list", "data": [{"id": "mock", "object": "model"}]})
|
| 104 |
+
self._send(404, {"error": "not found"})
|
| 105 |
+
|
| 106 |
+
def do_POST(self):
|
| 107 |
+
body = json.loads(self.rfile.read(int(self.headers.get("Content-Length", 0))))
|
| 108 |
+
msgs = body["messages"]
|
| 109 |
+
text = last_user_text(msgs)
|
| 110 |
+
prompt_tokens = sum(len(json.dumps(m["content"])) for m in msgs) // 4
|
| 111 |
+
if body.get("stream"):
|
| 112 |
+
return self._stream(body, prompt_tokens)
|
| 113 |
+
task_item = INDEX.get(text)
|
| 114 |
+
if task_item is None:
|
| 115 |
+
content, tcs = "mock: unknown prompt", None
|
| 116 |
+
else:
|
| 117 |
+
task, item = task_item
|
| 118 |
+
corrupt = ARGS.corrupt_every and int(hashlib.md5(item["id"].encode()).hexdigest(), 16) % ARGS.corrupt_every == 0
|
| 119 |
+
content, tcs = gold_response(task, item, corrupt)
|
| 120 |
+
msg = {"role": "assistant", "content": content}
|
| 121 |
+
if tcs:
|
| 122 |
+
msg["tool_calls"] = tcs
|
| 123 |
+
ct = max(1, len((content or "") + json.dumps(tcs or "")) // 4)
|
| 124 |
+
self._send(200, {"id": "mock", "object": "chat.completion", "model": body["model"],
|
| 125 |
+
"choices": [{"index": 0, "message": msg, "finish_reason": "tool_calls" if tcs else "stop"}],
|
| 126 |
+
"usage": {"prompt_tokens": prompt_tokens, "completion_tokens": ct,
|
| 127 |
+
"total_tokens": prompt_tokens + ct}})
|
| 128 |
+
|
| 129 |
+
def _stream(self, body, prompt_tokens):
|
| 130 |
+
n = int(body.get("max_tokens") or 16)
|
| 131 |
+
self.send_response(200)
|
| 132 |
+
self.send_header("Content-Type", "text/event-stream")
|
| 133 |
+
self.send_header("Transfer-Encoding", "chunked")
|
| 134 |
+
self.end_headers()
|
| 135 |
+
|
| 136 |
+
def chunk(obj):
|
| 137 |
+
data = f"data: {obj if isinstance(obj, str) else json.dumps(obj)}\n\n".encode()
|
| 138 |
+
self.wfile.write(f"{len(data):x}\r\n".encode() + data + b"\r\n")
|
| 139 |
+
self.wfile.flush()
|
| 140 |
+
time.sleep(ARGS.ttft)
|
| 141 |
+
for i in range(n):
|
| 142 |
+
chunk({"choices": [{"index": 0, "delta": {"content": "tok "}, "finish_reason": None}]})
|
| 143 |
+
time.sleep(ARGS.itl)
|
| 144 |
+
chunk({"choices": [{"index": 0, "delta": {}, "finish_reason": "length"}]})
|
| 145 |
+
if (body.get("stream_options") or {}).get("include_usage"):
|
| 146 |
+
chunk({"choices": [], "usage": {"prompt_tokens": prompt_tokens, "completion_tokens": n,
|
| 147 |
+
"total_tokens": prompt_tokens + n}})
|
| 148 |
+
chunk("[DONE]")
|
| 149 |
+
self.wfile.write(b"0\r\n\r\n")
|
| 150 |
+
self.wfile.flush()
|
| 151 |
+
|
| 152 |
+
|
| 153 |
+
def main():
|
| 154 |
+
global ARGS
|
| 155 |
+
ap = argparse.ArgumentParser()
|
| 156 |
+
ap.add_argument("--port", type=int, default=18999)
|
| 157 |
+
ap.add_argument("--tool-mode", choices=["server", "xml"], default="server")
|
| 158 |
+
ap.add_argument("--corrupt-every", type=int, default=0)
|
| 159 |
+
ap.add_argument("--ttft", type=float, default=0.02)
|
| 160 |
+
ap.add_argument("--itl", type=float, default=0.002)
|
| 161 |
+
ARGS = ap.parse_args()
|
| 162 |
+
build_index()
|
| 163 |
+
print(f"mock server on 127.0.0.1:{ARGS.port} ({len(INDEX)} items indexed)", flush=True)
|
| 164 |
+
srv = ThreadingHTTPServer(("127.0.0.1", ARGS.port), H)
|
| 165 |
+
srv.handle_error = lambda *a: None # quiet on client disconnects
|
| 166 |
+
srv.daemon_threads = True
|
| 167 |
+
srv.serve_forever()
|
| 168 |
+
|
| 169 |
+
|
| 170 |
+
if __name__ == "__main__":
|
| 171 |
+
main()
|
evaluation/harness/perf_bench.py
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python
|
| 2 |
+
"""Streaming throughput/latency benchmark for an OpenAI-compatible Chat Completions server.
|
| 3 |
+
|
| 4 |
+
.venv-eval/bin/python eval/perf_bench.py --base-url http://localhost:30000/v1 \
|
| 5 |
+
--model SenseNova-Loop-9B-Preview --concurrency 1,2,4,8 --num-requests 16 \
|
| 6 |
+
--input-tokens 1024 --output-tokens 256 --out eval/runs/perf_bf16.json
|
| 7 |
+
|
| 8 |
+
Prompt: deterministic pseudo-text (fixed seed) cut to exactly --input-tokens tokens with the model's
|
| 9 |
+
own tokenizer.json (the chat template adds a few more; actual prompt_tokens come from `usage`).
|
| 10 |
+
Each request gets a unique numeric prefix so prefix caching cannot serve it (disable with
|
| 11 |
+
--allow-prefix-cache). Requests use temperature 0, ignore_eos=true and min_tokens=max_tokens
|
| 12 |
+
(vLLM/SGLang extensions; disable with --no-ignore-eos) and thinking off.
|
| 13 |
+
Metrics per concurrency level: TTFT p50/p90/mean, per-request decode tok/s ((n_out-1)/(t_last-t_first)),
|
| 14 |
+
inter-token latency, E2E latency p50/p90, aggregate output tok/s (sum out tokens / level wall time),
|
| 15 |
+
request throughput, errors, actual generated lengths (from usage; falls back to chunk count).
|
| 16 |
+
"""
|
| 17 |
+
from __future__ import annotations
|
| 18 |
+
|
| 19 |
+
import argparse
|
| 20 |
+
import json
|
| 21 |
+
import platform
|
| 22 |
+
import random
|
| 23 |
+
import statistics
|
| 24 |
+
import sys
|
| 25 |
+
import time
|
| 26 |
+
from concurrent.futures import ThreadPoolExecutor
|
| 27 |
+
from pathlib import Path
|
| 28 |
+
|
| 29 |
+
import requests
|
| 30 |
+
|
| 31 |
+
HERE = Path(__file__).resolve().parent
|
| 32 |
+
DEFAULT_TOK = HERE.parent / "upstream/SenseNova-Loop-9B-Preview/tokenizer.json"
|
| 33 |
+
WORDS = ("the of and to in is was for on that with as by at from his her an were are which this be has "
|
| 34 |
+
"had it not or have one their they its first new after who two been more year also other some "
|
| 35 |
+
"into all time only most over three city river mountain village market winter summer story "
|
| 36 |
+
"engine signal harbor garden library window letter bridge forest island station machine "
|
| 37 |
+
"children ancient quiet bright careful distant golden narrow sudden gentle measured").split()
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
def build_prompt_text(n_tokens: int, tokenizer_path: str | None):
|
| 41 |
+
rng = random.Random(1234)
|
| 42 |
+
sents = []
|
| 43 |
+
for _ in range(n_tokens): # plenty of text
|
| 44 |
+
k = rng.randint(8, 18)
|
| 45 |
+
s = " ".join(rng.choice(WORDS) for _ in range(k))
|
| 46 |
+
sents.append(s[0].upper() + s[1:] + ".")
|
| 47 |
+
text = " ".join(sents)
|
| 48 |
+
if tokenizer_path and Path(tokenizer_path).exists():
|
| 49 |
+
from tokenizers import Tokenizer
|
| 50 |
+
tok = Tokenizer.from_file(str(tokenizer_path))
|
| 51 |
+
ids = tok.encode(text, add_special_tokens=False).ids[:n_tokens]
|
| 52 |
+
text = tok.decode(ids)
|
| 53 |
+
return text, len(tok.encode(text, add_special_tokens=False).ids), "tokenizer.json"
|
| 54 |
+
words = text.split()[: int(n_tokens * 0.75)]
|
| 55 |
+
return " ".join(words), None, "approx(0.75 words/token)"
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
def pct(xs, q):
|
| 59 |
+
if not xs:
|
| 60 |
+
return None
|
| 61 |
+
xs = sorted(xs)
|
| 62 |
+
k = (len(xs) - 1) * q
|
| 63 |
+
f = int(k)
|
| 64 |
+
c = min(f + 1, len(xs) - 1)
|
| 65 |
+
return xs[f] + (xs[c] - xs[f]) * (k - f)
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
def one_request(args, session, text, idx):
|
| 69 |
+
prefix = "" if args.allow_prefix_cache else f"[req {idx:06d}] "
|
| 70 |
+
body = {"model": args.model, "stream": True, "stream_options": {"include_usage": True},
|
| 71 |
+
"messages": [{"role": "user", "content": prefix + text + "\n\nContinue this text."}],
|
| 72 |
+
"max_tokens": args.output_tokens, "temperature": 0.0,
|
| 73 |
+
"chat_template_kwargs": {"enable_thinking": False}}
|
| 74 |
+
if not args.no_ignore_eos:
|
| 75 |
+
body.update({"ignore_eos": True, "min_tokens": args.output_tokens})
|
| 76 |
+
t0 = time.perf_counter()
|
| 77 |
+
t_first = t_last = None
|
| 78 |
+
n_chunks = 0
|
| 79 |
+
usage = None
|
| 80 |
+
finish = None
|
| 81 |
+
try:
|
| 82 |
+
with session.post(args.base_url.rstrip("/") + "/chat/completions", json=body, stream=True,
|
| 83 |
+
timeout=args.timeout) as r:
|
| 84 |
+
if r.status_code != 200:
|
| 85 |
+
return {"ok": False, "error": f"HTTP {r.status_code}: {r.text[:300]}"}
|
| 86 |
+
for line in r.iter_lines():
|
| 87 |
+
if not line or not line.startswith(b"data:"):
|
| 88 |
+
continue
|
| 89 |
+
data = line[5:].strip()
|
| 90 |
+
if data == b"[DONE]":
|
| 91 |
+
break
|
| 92 |
+
j = json.loads(data)
|
| 93 |
+
if j.get("usage"):
|
| 94 |
+
usage = j["usage"]
|
| 95 |
+
for ch in j.get("choices") or []:
|
| 96 |
+
d = ch.get("delta") or {}
|
| 97 |
+
if d.get("content") or d.get("reasoning_content") or d.get("reasoning"):
|
| 98 |
+
now = time.perf_counter()
|
| 99 |
+
if t_first is None:
|
| 100 |
+
t_first = now
|
| 101 |
+
t_last = now
|
| 102 |
+
n_chunks += 1
|
| 103 |
+
if ch.get("finish_reason"):
|
| 104 |
+
finish = ch["finish_reason"]
|
| 105 |
+
except Exception as e: # noqa: BLE001
|
| 106 |
+
return {"ok": False, "error": f"{type(e).__name__}: {e}"}
|
| 107 |
+
t_end = time.perf_counter()
|
| 108 |
+
if t_first is None:
|
| 109 |
+
return {"ok": False, "error": "no tokens received"}
|
| 110 |
+
n_out = (usage or {}).get("completion_tokens") or n_chunks
|
| 111 |
+
decode_t = (t_last - t_first) if t_last and t_last > t_first else None
|
| 112 |
+
return {"ok": True, "ttft_s": t_first - t0, "e2e_s": t_end - t0, "output_tokens": n_out,
|
| 113 |
+
"prompt_tokens": (usage or {}).get("prompt_tokens"), "n_chunks": n_chunks, "finish_reason": finish,
|
| 114 |
+
"decode_tok_s": (n_out - 1) / decode_t if decode_t and n_out > 1 else None,
|
| 115 |
+
"itl_s": decode_t / (n_out - 1) if decode_t and n_out > 1 else None,
|
| 116 |
+
"usage_present": usage is not None}
|
| 117 |
+
|
| 118 |
+
|
| 119 |
+
def run_level(args, session, text, c, base_idx):
|
| 120 |
+
n = args.num_requests if args.num_requests else max(8, 4 * c)
|
| 121 |
+
t0 = time.perf_counter()
|
| 122 |
+
with ThreadPoolExecutor(c) as ex:
|
| 123 |
+
res = list(ex.map(lambda i: one_request(args, session, text, base_idx + i), range(n)))
|
| 124 |
+
wall = time.perf_counter() - t0
|
| 125 |
+
ok = [r for r in res if r["ok"]]
|
| 126 |
+
|
| 127 |
+
def stat(key):
|
| 128 |
+
xs = [r[key] for r in ok if r.get(key) is not None]
|
| 129 |
+
return {"p50": pct(xs, 0.5), "p90": pct(xs, 0.9), "mean": statistics.fmean(xs) if xs else None}
|
| 130 |
+
outs = [r["output_tokens"] for r in ok]
|
| 131 |
+
return {"concurrency": c, "n_requests": n, "n_ok": len(ok), "n_errors": len(res) - len(ok),
|
| 132 |
+
"errors": [r["error"] for r in res if not r["ok"]][:5], "wall_s": wall,
|
| 133 |
+
"ttft_s": stat("ttft_s"), "e2e_s": stat("e2e_s"), "decode_tok_s_per_req": stat("decode_tok_s"),
|
| 134 |
+
"itl_s": stat("itl_s"),
|
| 135 |
+
"output_tokens_mean": statistics.fmean(outs) if outs else None,
|
| 136 |
+
"output_tokens_min": min(outs) if outs else None, "output_tokens_max": max(outs) if outs else None,
|
| 137 |
+
"prompt_tokens_mean": statistics.fmean([r["prompt_tokens"] for r in ok if r.get("prompt_tokens")] or [0]),
|
| 138 |
+
"n_short_outputs": sum(1 for o in outs if o < args.output_tokens),
|
| 139 |
+
"aggregate_output_tok_s": sum(outs) / wall if wall else None,
|
| 140 |
+
"requests_per_s": len(ok) / wall if wall else None,
|
| 141 |
+
"usage_reported": all(r.get("usage_present") for r in ok)}
|
| 142 |
+
|
| 143 |
+
|
| 144 |
+
def main():
|
| 145 |
+
ap = argparse.ArgumentParser()
|
| 146 |
+
ap.add_argument("--base-url", required=True)
|
| 147 |
+
ap.add_argument("--model", required=True)
|
| 148 |
+
ap.add_argument("--concurrency", default="1,2,4,8")
|
| 149 |
+
ap.add_argument("--num-requests", type=int, default=16, help="per level (0 => max(8, 4*c))")
|
| 150 |
+
ap.add_argument("--warmup", type=int, default=2)
|
| 151 |
+
ap.add_argument("--input-tokens", type=int, default=1024)
|
| 152 |
+
ap.add_argument("--output-tokens", type=int, default=256)
|
| 153 |
+
ap.add_argument("--tokenizer", default=str(DEFAULT_TOK))
|
| 154 |
+
ap.add_argument("--allow-prefix-cache", action="store_true")
|
| 155 |
+
ap.add_argument("--no-ignore-eos", action="store_true")
|
| 156 |
+
ap.add_argument("--timeout", type=float, default=600)
|
| 157 |
+
ap.add_argument("--label", default="")
|
| 158 |
+
ap.add_argument("--out", required=True)
|
| 159 |
+
args = ap.parse_args()
|
| 160 |
+
|
| 161 |
+
text, n_tok, how = build_prompt_text(args.input_tokens, args.tokenizer)
|
| 162 |
+
levels = [int(x) for x in args.concurrency.split(",")]
|
| 163 |
+
session = requests.Session()
|
| 164 |
+
session.mount("http://", requests.adapters.HTTPAdapter(pool_maxsize=max(levels) * 2 + 4))
|
| 165 |
+
for i in range(args.warmup):
|
| 166 |
+
w = one_request(args, session, text, 900000 + i)
|
| 167 |
+
if not w["ok"]:
|
| 168 |
+
print("warmup error:", w["error"], file=sys.stderr)
|
| 169 |
+
res = {"label": args.label, "model": args.model, "base_url": args.base_url, "host": platform.node(),
|
| 170 |
+
"time": time.strftime("%Y-%m-%dT%H:%M:%S%z"),
|
| 171 |
+
"config": {**vars(args), "prompt_text_tokens": n_tok, "prompt_build": how}, "levels": []}
|
| 172 |
+
base = 0
|
| 173 |
+
for c in levels:
|
| 174 |
+
lv = run_level(args, session, text, c, base)
|
| 175 |
+
base += 10000
|
| 176 |
+
res["levels"].append(lv)
|
| 177 |
+
f = lambda x: "n/a" if x is None else f"{x:.3f}" # noqa: E731
|
| 178 |
+
print(f"c={c:3d} ok={lv['n_ok']}/{lv['n_requests']} TTFT p50={f(lv['ttft_s']['p50'])}s "
|
| 179 |
+
f"p90={f(lv['ttft_s']['p90'])}s decode/req p50={f(lv['decode_tok_s_per_req']['p50'])} tok/s "
|
| 180 |
+
f"E2E p50={f(lv['e2e_s']['p50'])}s agg={f(lv['aggregate_output_tok_s'])} tok/s "
|
| 181 |
+
f"out_len={lv['output_tokens_mean']}", flush=True)
|
| 182 |
+
Path(args.out).parent.mkdir(parents=True, exist_ok=True)
|
| 183 |
+
Path(args.out).write_text(json.dumps(res, indent=2))
|
| 184 |
+
print("wrote", args.out)
|
| 185 |
+
|
| 186 |
+
|
| 187 |
+
if __name__ == "__main__":
|
| 188 |
+
main()
|
evaluation/harness/requirements.lock
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
aiohappyeyeballs==2.7.1
|
| 2 |
+
aiohttp==3.14.5
|
| 3 |
+
aiosignal==1.4.0
|
| 4 |
+
anyio==4.15.1
|
| 5 |
+
attrs==26.1.0
|
| 6 |
+
certifi==2026.10.23
|
| 7 |
+
charset-normalizer==3.5.2
|
| 8 |
+
click==8.5.0
|
| 9 |
+
cloudpickle==3.1.2
|
| 10 |
+
datasets==5.1.0
|
| 11 |
+
defusedxml==0.7.1
|
| 12 |
+
dill==0.4.1
|
| 13 |
+
filelock==4.2.5
|
| 14 |
+
frozenlist==1.8.0
|
| 15 |
+
fsspec==2026.7.0
|
| 16 |
+
h11==0.16.0
|
| 17 |
+
hf-xet==1.8.0
|
| 18 |
+
httpcore2==2.16.0
|
| 19 |
+
httpx2==2.16.0
|
| 20 |
+
huggingface-hub==2.4.0
|
| 21 |
+
idna==3.20
|
| 22 |
+
immutabledict==4.3.1
|
| 23 |
+
jinja2==3.1.6
|
| 24 |
+
joblib==1.6.0
|
| 25 |
+
langdetect==1.0.9
|
| 26 |
+
markupsafe==3.0.4
|
| 27 |
+
multidict==7.2.1
|
| 28 |
+
multiprocess==0.70.19
|
| 29 |
+
nltk==3.10.4
|
| 30 |
+
numpy==2.5.4
|
| 31 |
+
packaging==26.3
|
| 32 |
+
pandas==3.1.0
|
| 33 |
+
pillow==13.0.0
|
| 34 |
+
propcache==0.5.4
|
| 35 |
+
pyarrow==26.0.0
|
| 36 |
+
python-dateutil==3.0.0
|
| 37 |
+
pyyaml==6.0.3
|
| 38 |
+
regex==2026.9.29
|
| 39 |
+
requests==2.34.2
|
| 40 |
+
six==1.17.0
|
| 41 |
+
tokenizers==0.23.3
|
| 42 |
+
tqdm==4.70.1
|
| 43 |
+
truststore==0.10.5
|
| 44 |
+
typing-extensions==4.16.0
|
| 45 |
+
tzdata==2026.6
|
| 46 |
+
urllib3==2.8.0
|
| 47 |
+
xxhash==4.0.2
|
| 48 |
+
yarl==1.25.1
|
evaluation/harness/run_eval.py
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python
|
| 2 |
+
"""Run the fixed eval suite against an OpenAI-compatible Chat Completions endpoint.
|
| 3 |
+
|
| 4 |
+
Example:
|
| 5 |
+
.venv-eval/bin/python eval/run_eval.py --base-url http://localhost:30000/v1 \
|
| 6 |
+
--model SenseNova-Loop-9B-Preview --out eval/runs/bf16 --concurrency 16
|
| 7 |
+
Writes <out>/raw_<task>.jsonl (one line per item, full response + score) and <out>/summary.json.
|
| 8 |
+
"""
|
| 9 |
+
from __future__ import annotations
|
| 10 |
+
|
| 11 |
+
import argparse
|
| 12 |
+
import hashlib
|
| 13 |
+
import json
|
| 14 |
+
import platform
|
| 15 |
+
import sys
|
| 16 |
+
import time
|
| 17 |
+
from concurrent.futures import ThreadPoolExecutor
|
| 18 |
+
from pathlib import Path
|
| 19 |
+
|
| 20 |
+
HERE = Path(__file__).resolve().parent
|
| 21 |
+
sys.path.insert(0, str(HERE))
|
| 22 |
+
import requests # noqa: E402
|
| 23 |
+
|
| 24 |
+
from common import EVAL_VERSION, chat, read_jsonl, wilson_ci, write_jsonl # noqa: E402
|
| 25 |
+
from tasks import MAX_TOKENS, TASKS, agreement_key # noqa: E402
|
| 26 |
+
|
| 27 |
+
DATA = HERE / "data"
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def run_item(task, item, args, session):
|
| 31 |
+
build, score = TASKS[task]
|
| 32 |
+
messages, tools = build(item, DATA)
|
| 33 |
+
resp = chat(session, args.base_url, args.model, messages, max_tokens=MAX_TOKENS[task], tools=tools,
|
| 34 |
+
enable_thinking=args.enable_thinking, timeout=args.timeout)
|
| 35 |
+
try:
|
| 36 |
+
sc = score(item, resp) if resp["ok"] else {"pred": None, "correct": False}
|
| 37 |
+
except Exception as e: # noqa: BLE001
|
| 38 |
+
sc = {"pred": None, "correct": False, "score_error": f"{type(e).__name__}: {e}"}
|
| 39 |
+
sc["correct"] = bool(sc["correct"])
|
| 40 |
+
return {
|
| 41 |
+
"id": item["id"], "task": task,
|
| 42 |
+
"prompt_sha256": hashlib.sha256(json.dumps(messages, sort_keys=True)[:200000].encode()).hexdigest()[:16],
|
| 43 |
+
"content": resp["content"], "reasoning_content": resp["reasoning_content"],
|
| 44 |
+
"tool_calls": resp["tool_calls"], "finish_reason": resp["finish_reason"],
|
| 45 |
+
"usage": resp["usage"], "completion_tokens": (resp["usage"] or {}).get("completion_tokens"),
|
| 46 |
+
"latency_s": resp["latency_s"], "error": resp["error"],
|
| 47 |
+
"agree_key": agreement_key(task, sc, resp), **sc,
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
def summarize_task(rows):
|
| 52 |
+
n = len(rows)
|
| 53 |
+
k = sum(r["correct"] for r in rows)
|
| 54 |
+
lo, hi = wilson_ci(k, n)
|
| 55 |
+
toks = [r["completion_tokens"] for r in rows if r["completion_tokens"] is not None]
|
| 56 |
+
s = {"n": n, "correct": k, "accuracy": k / n if n else None, "wilson95": [lo, hi],
|
| 57 |
+
"n_errors": sum(1 for r in rows if r["error"]),
|
| 58 |
+
"n_truncated": sum(1 for r in rows if r["finish_reason"] == "length"),
|
| 59 |
+
"mean_completion_tokens": sum(toks) / len(toks) if toks else None,
|
| 60 |
+
"sum_completion_tokens": sum(toks)}
|
| 61 |
+
if rows and "vqa_soft_acc" in rows[0]:
|
| 62 |
+
s["vqa_soft_acc"] = sum(r.get("vqa_soft_acc", 0) for r in rows) / n
|
| 63 |
+
if rows and rows[0]["task"] == "tools":
|
| 64 |
+
s["names_correct"] = sum(1 for r in rows if r.get("names_correct")) / n
|
| 65 |
+
s["parse_source_counts"] = {}
|
| 66 |
+
for r in rows:
|
| 67 |
+
src = r.get("parse_source", "none")
|
| 68 |
+
s["parse_source_counts"][src] = s["parse_source_counts"].get(src, 0) + 1
|
| 69 |
+
fmt = [r.get("format", {}) for r in rows if r.get("parse_source") != "none"]
|
| 70 |
+
s["format_well_formed"] = (sum(1 for f in fmt if f.get("well_formed")) / len(fmt)) if fmt else None
|
| 71 |
+
s["raw_tool_call_tags_in_content"] = sum(1 for r in rows if "<tool_call>" in (r["content"] or ""))
|
| 72 |
+
by = {}
|
| 73 |
+
for r in rows:
|
| 74 |
+
c = r["id"].split("_")[1]
|
| 75 |
+
by.setdefault(c, [0, 0])
|
| 76 |
+
by[c][0] += r["correct"]
|
| 77 |
+
by[c][1] += 1
|
| 78 |
+
s["by_category"] = {c: f"{a}/{b}" for c, (a, b) in sorted(by.items())}
|
| 79 |
+
if rows and rows[0]["task"] == "ifeval":
|
| 80 |
+
flat = [x for r in rows for x in r.get("per_instruction", [])]
|
| 81 |
+
s["instruction_level_acc"] = sum(flat) / len(flat) if flat else None
|
| 82 |
+
s["n_instructions"] = len(flat)
|
| 83 |
+
return s
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
def main():
|
| 87 |
+
ap = argparse.ArgumentParser()
|
| 88 |
+
ap.add_argument("--base-url", required=True, help="e.g. http://localhost:30000/v1")
|
| 89 |
+
ap.add_argument("--model", required=True)
|
| 90 |
+
ap.add_argument("--out", required=True)
|
| 91 |
+
ap.add_argument("--tasks", default=",".join(TASKS))
|
| 92 |
+
ap.add_argument("--concurrency", type=int, default=8)
|
| 93 |
+
ap.add_argument("--limit", type=int, default=None, help="debug: first N items per task")
|
| 94 |
+
ap.add_argument("--enable-thinking", action="store_true", help="default OFF")
|
| 95 |
+
ap.add_argument("--timeout", type=float, default=900)
|
| 96 |
+
ap.add_argument("--api-key", default="EMPTY")
|
| 97 |
+
args = ap.parse_args()
|
| 98 |
+
|
| 99 |
+
out = Path(args.out)
|
| 100 |
+
out.mkdir(parents=True, exist_ok=True)
|
| 101 |
+
session = requests.Session()
|
| 102 |
+
session.headers["Authorization"] = f"Bearer {args.api_key}"
|
| 103 |
+
adapter = requests.adapters.HTTPAdapter(pool_maxsize=max(16, args.concurrency * 2))
|
| 104 |
+
session.mount("http://", adapter)
|
| 105 |
+
session.mount("https://", adapter)
|
| 106 |
+
|
| 107 |
+
manifest = json.loads((DATA / "MANIFEST.json").read_text())
|
| 108 |
+
summary = {"eval_version": EVAL_VERSION, "model": args.model, "base_url": args.base_url,
|
| 109 |
+
"started": time.strftime("%Y-%m-%dT%H:%M:%S%z"), "enable_thinking": args.enable_thinking,
|
| 110 |
+
"sampling": {"temperature": 0.0, "top_p": 1.0, "seed": 0, "max_tokens": MAX_TOKENS},
|
| 111 |
+
"concurrency": args.concurrency, "limit": args.limit, "host": platform.node(),
|
| 112 |
+
"data_sha256": {t: v["sha256"] for t, v in manifest["tasks"].items()}, "tasks": {}}
|
| 113 |
+
try:
|
| 114 |
+
summary["server_models"] = session.get(args.base_url.rstrip("/") + "/models", timeout=10).json()
|
| 115 |
+
except Exception as e: # noqa: BLE001
|
| 116 |
+
summary["server_models"] = f"unavailable: {e}"
|
| 117 |
+
|
| 118 |
+
t_all = time.time()
|
| 119 |
+
for task in args.tasks.split(","):
|
| 120 |
+
items = read_jsonl(DATA / f"{task}.jsonl")
|
| 121 |
+
if args.limit:
|
| 122 |
+
items = items[: args.limit]
|
| 123 |
+
t0 = time.time()
|
| 124 |
+
with ThreadPoolExecutor(args.concurrency) as ex:
|
| 125 |
+
rows = list(ex.map(lambda it: run_item(task, it, args, session), items))
|
| 126 |
+
write_jsonl(out / f"raw_{task}.jsonl", rows)
|
| 127 |
+
s = summarize_task(rows)
|
| 128 |
+
s["wall_s"] = round(time.time() - t0, 1)
|
| 129 |
+
summary["tasks"][task] = s
|
| 130 |
+
print(f"{task:10s} n={s['n']:3d} acc={s['accuracy']:.3f} "
|
| 131 |
+
f"CI95=[{s['wilson95'][0]:.3f},{s['wilson95'][1]:.3f}] err={s['n_errors']} "
|
| 132 |
+
f"trunc={s['n_truncated']} mean_tok={s['mean_completion_tokens']} {s['wall_s']}s", flush=True)
|
| 133 |
+
summary["wall_s"] = round(time.time() - t_all, 1)
|
| 134 |
+
(out / "summary.json").write_text(json.dumps(summary, indent=2, default=str))
|
| 135 |
+
print("wrote", out / "summary.json")
|
| 136 |
+
|
| 137 |
+
|
| 138 |
+
if __name__ == "__main__":
|
| 139 |
+
main()
|
evaluation/harness/tasks.py
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Task definitions: prompt construction, max_tokens, answer extraction and scoring.
|
| 2 |
+
|
| 3 |
+
Every task exposes:
|
| 4 |
+
build_messages(item, data_dir) -> (messages, tools|None)
|
| 5 |
+
score(item, resp) -> dict(pred=..., correct=bool, **details) (resp = common.chat() result)
|
| 6 |
+
"""
|
| 7 |
+
from __future__ import annotations
|
| 8 |
+
|
| 9 |
+
import base64
|
| 10 |
+
import json
|
| 11 |
+
import os
|
| 12 |
+
import re
|
| 13 |
+
import subprocess
|
| 14 |
+
import sys
|
| 15 |
+
import tempfile
|
| 16 |
+
from pathlib import Path
|
| 17 |
+
|
| 18 |
+
import ifeval_lite
|
| 19 |
+
from common import calls_from_message, strip_think
|
| 20 |
+
|
| 21 |
+
# Fixed per-task generation budgets (thinking OFF). Changing these => bump EVAL_VERSION.
|
| 22 |
+
MAX_TOKENS = {"ifeval": 1024, "gsm8k": 1024, "mmlu_pro": 1024, "humaneval": 1024,
|
| 23 |
+
"tools": 512, "vqa": 64}
|
| 24 |
+
|
| 25 |
+
# ============================================================================ IFEval
|
| 26 |
+
def ifeval_messages(item, data_dir):
|
| 27 |
+
return [{"role": "user", "content": item["prompt"]}], None
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def ifeval_score(item, resp):
|
| 31 |
+
text = strip_think(resp["content"])
|
| 32 |
+
per = ifeval_lite.check(text, item["instruction_id_list"], item["kwargs"])
|
| 33 |
+
return {"pred": None, "correct": all(per), "per_instruction": per}
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
# ============================================================================ GSM8K
|
| 37 |
+
GSM_TMPL = ("Solve the following math problem step by step. At the end, write the final "
|
| 38 |
+
"answer on its own line in the form \"The final answer is <number>\".\n\n{q}")
|
| 39 |
+
NUM_RE = r"-?\$?\s?\d[\d,]*(?:\.\d+)?"
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
def _norm_num(s):
|
| 43 |
+
if s is None:
|
| 44 |
+
return None
|
| 45 |
+
s = s.replace(",", "").replace("$", "").replace(" ", "").rstrip(".")
|
| 46 |
+
try:
|
| 47 |
+
x = float(s)
|
| 48 |
+
except ValueError:
|
| 49 |
+
return None
|
| 50 |
+
return str(int(x)) if x == int(x) else repr(round(x, 6))
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
def gsm_extract(text):
|
| 54 |
+
text = strip_think(text)
|
| 55 |
+
m = re.findall(r"final answer is[:\s]*\**\s*\\?\(?\\?(?:boxed\{)?\s*(" + NUM_RE + ")", text, re.I)
|
| 56 |
+
if m:
|
| 57 |
+
return _norm_num(m[-1])
|
| 58 |
+
m = re.findall(r"\\boxed\{\s*(" + NUM_RE + ")", text)
|
| 59 |
+
if m:
|
| 60 |
+
return _norm_num(m[-1])
|
| 61 |
+
m = re.findall(NUM_RE, text)
|
| 62 |
+
return _norm_num(m[-1]) if m else None
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
def gsm8k_messages(item, data_dir):
|
| 66 |
+
return [{"role": "user", "content": GSM_TMPL.format(q=item["question"])}], None
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
def gsm8k_score(item, resp):
|
| 70 |
+
pred = gsm_extract(resp["content"])
|
| 71 |
+
return {"pred": pred, "correct": pred is not None and pred == _norm_num(item["answer"])}
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
# ============================================================================ MMLU-Pro
|
| 75 |
+
LETTERS = "ABCDEFGHIJ"
|
| 76 |
+
MC_TMPL = ("The following is a multiple choice question about {cat}. Think step by step briefly, "
|
| 77 |
+
"then finish with \"The answer is (X)\" where X is the letter of the correct option.\n\n"
|
| 78 |
+
"Question: {q}\n{opts}")
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
def mmlu_pro_messages(item, data_dir):
|
| 82 |
+
opts = "\n".join(f"({LETTERS[i]}) {o}" for i, o in enumerate(item["options"]))
|
| 83 |
+
return [{"role": "user", "content": MC_TMPL.format(cat=item["category"], q=item["question"], opts=opts)}], None
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
def mc_extract(text, n_opts):
|
| 87 |
+
text = strip_think(text)
|
| 88 |
+
valid = LETTERS[:n_opts]
|
| 89 |
+
m = re.findall(r"answer is:?\s*\**\(?([A-J])\)?", text, re.I)
|
| 90 |
+
m = [x.upper() for x in m if x.upper() in valid]
|
| 91 |
+
if m:
|
| 92 |
+
return m[-1]
|
| 93 |
+
m = re.findall(r"(?:^|\s)\(?([A-J])\)?[\.\s]*$", text.strip())
|
| 94 |
+
if m and m[-1] in valid:
|
| 95 |
+
return m[-1]
|
| 96 |
+
m = re.findall(r"\(([A-J])\)", text)
|
| 97 |
+
m = [x for x in m if x in valid]
|
| 98 |
+
return m[-1] if m else None
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
def mmlu_pro_score(item, resp):
|
| 102 |
+
pred = mc_extract(resp["content"], len(item["options"]))
|
| 103 |
+
return {"pred": pred, "correct": pred == item["answer"]}
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
# ============================================================================ HumanEval
|
| 107 |
+
HE_TMPL = ("Complete the following Python function. Return the complete function definition "
|
| 108 |
+
"(including the signature and any needed imports) in a single ```python code block.\n\n"
|
| 109 |
+
"```python\n{p}```")
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
def humaneval_messages(item, data_dir):
|
| 113 |
+
return [{"role": "user", "content": HE_TMPL.format(p=item["prompt"])}], None
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
def extract_code(text, item):
|
| 117 |
+
text = strip_think(text)
|
| 118 |
+
blocks = re.findall(r"```(?:python|py|Python)?\s*\n(.*?)```", text, re.S)
|
| 119 |
+
code = None
|
| 120 |
+
for b in blocks:
|
| 121 |
+
if f"def {item['entry_point']}" in b:
|
| 122 |
+
code = b
|
| 123 |
+
break
|
| 124 |
+
if code is None and blocks:
|
| 125 |
+
code = blocks[0]
|
| 126 |
+
if code is None:
|
| 127 |
+
code = text
|
| 128 |
+
if f"def {item['entry_point']}" not in code: # body-only completion
|
| 129 |
+
code = item["prompt"] + code
|
| 130 |
+
else: # keep the prompt's imports/helper defs available
|
| 131 |
+
code = item["prompt"].split(f"def {item['entry_point']}")[0] + "\n" + code
|
| 132 |
+
return code
|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
def run_python_sandboxed(program: str, timeout: float = 10.0) -> tuple[bool, str]:
|
| 136 |
+
"""Execute untrusted code in a fresh isolated interpreter in a temp dir with rlimits."""
|
| 137 |
+
with tempfile.TemporaryDirectory(prefix="he_") as td:
|
| 138 |
+
path = os.path.join(td, "prog.py")
|
| 139 |
+
with open(path, "w") as f:
|
| 140 |
+
f.write(program)
|
| 141 |
+
|
| 142 |
+
def limits():
|
| 143 |
+
import resource
|
| 144 |
+
resource.setrlimit(resource.RLIMIT_AS, (2 << 30, 2 << 30))
|
| 145 |
+
resource.setrlimit(resource.RLIMIT_CPU, (int(timeout) + 1, int(timeout) + 1))
|
| 146 |
+
resource.setrlimit(resource.RLIMIT_FSIZE, (10 << 20, 10 << 20))
|
| 147 |
+
os.setsid()
|
| 148 |
+
env = {"PATH": "/usr/bin:/bin", "HOME": td, "PYTHONHASHSEED": "0"}
|
| 149 |
+
try:
|
| 150 |
+
p = subprocess.run([sys.executable, "-I", "-B", path], cwd=td, env=env, capture_output=True,
|
| 151 |
+
timeout=timeout, preexec_fn=limits, text=True)
|
| 152 |
+
return p.returncode == 0, (p.stderr or "")[-400:]
|
| 153 |
+
except subprocess.TimeoutExpired:
|
| 154 |
+
return False, "timeout"
|
| 155 |
+
|
| 156 |
+
|
| 157 |
+
def humaneval_score(item, resp):
|
| 158 |
+
code = extract_code(resp["content"], item)
|
| 159 |
+
prog = code + "\n\n" + item["test"] + f"\n\ncheck({item['entry_point']})\n"
|
| 160 |
+
ok, err = run_python_sandboxed(prog)
|
| 161 |
+
return {"pred": code, "correct": ok, "exec_error": None if ok else err}
|
| 162 |
+
|
| 163 |
+
|
| 164 |
+
# ============================================================================ Tool calling
|
| 165 |
+
def tools_messages(item, data_dir):
|
| 166 |
+
msgs = []
|
| 167 |
+
if item.get("system"):
|
| 168 |
+
msgs.append({"role": "system", "content": item["system"]})
|
| 169 |
+
msgs.append({"role": "user", "content": item["user"]})
|
| 170 |
+
return msgs, item["tools"]
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
def _val_match(got, allowed):
|
| 174 |
+
for a in allowed:
|
| 175 |
+
if isinstance(a, (int, float)) and not isinstance(a, bool):
|
| 176 |
+
try:
|
| 177 |
+
if abs(float(got) - float(a)) < 1e-6:
|
| 178 |
+
return True
|
| 179 |
+
except (TypeError, ValueError):
|
| 180 |
+
pass
|
| 181 |
+
elif isinstance(a, str) and isinstance(got, str):
|
| 182 |
+
if got.strip().lower() == a.strip().lower():
|
| 183 |
+
return True
|
| 184 |
+
elif got == a:
|
| 185 |
+
return True
|
| 186 |
+
return False
|
| 187 |
+
|
| 188 |
+
|
| 189 |
+
def _call_match(call, gold):
|
| 190 |
+
if call.get("name") != gold["name"]:
|
| 191 |
+
return False
|
| 192 |
+
args = call.get("arguments") or {}
|
| 193 |
+
if not isinstance(args, dict):
|
| 194 |
+
return False
|
| 195 |
+
spec = gold["arguments"] # name -> list of allowed values; [] or containing "__optional__"
|
| 196 |
+
for k, allowed in spec.items():
|
| 197 |
+
optional = "__optional__" in allowed
|
| 198 |
+
allowed = [a for a in allowed if a != "__optional__"]
|
| 199 |
+
if k not in args:
|
| 200 |
+
if not optional:
|
| 201 |
+
return False
|
| 202 |
+
continue
|
| 203 |
+
if allowed and not _val_match(args[k], allowed):
|
| 204 |
+
return False
|
| 205 |
+
return all(k in spec for k in args) # no hallucinated params
|
| 206 |
+
|
| 207 |
+
|
| 208 |
+
def tools_score(item, resp):
|
| 209 |
+
calls, source, fmt = calls_from_message(resp["message"] or {"content": resp["content"]}, item["tools"])
|
| 210 |
+
gold = item["gold_calls"]
|
| 211 |
+
if not gold: # irrelevance: must NOT call any tool
|
| 212 |
+
correct = len(calls) == 0
|
| 213 |
+
else:
|
| 214 |
+
remaining = list(calls)
|
| 215 |
+
correct = len(calls) == len(gold)
|
| 216 |
+
for g in gold: # order-insensitive matching for parallel calls
|
| 217 |
+
hit = next((c for c in remaining if _call_match(c, g)), None)
|
| 218 |
+
if hit is None:
|
| 219 |
+
correct = False
|
| 220 |
+
break
|
| 221 |
+
remaining.remove(hit)
|
| 222 |
+
names_ok = sorted(c.get("name") or "" for c in calls) == sorted(g["name"] for g in gold)
|
| 223 |
+
return {"pred": calls, "correct": correct, "names_correct": names_ok, "parse_source": source,
|
| 224 |
+
"format": fmt}
|
| 225 |
+
|
| 226 |
+
|
| 227 |
+
# ============================================================================ VQA (TextVQA)
|
| 228 |
+
VQA_SUFFIX = "\nAnswer the question using a single word or phrase."
|
| 229 |
+
_CONTRACT = {"dont": "don't", "doesnt": "doesn't", "isnt": "isn't", "cant": "can't", "wont": "won't",
|
| 230 |
+
"im": "i'm", "ive": "i've", "youre": "you're", "thats": "that's"}
|
| 231 |
+
_NUMW = {"none": "0", "zero": "0", "one": "1", "two": "2", "three": "3", "four": "4", "five": "5",
|
| 232 |
+
"six": "6", "seven": "7", "eight": "8", "nine": "9", "ten": "10"}
|
| 233 |
+
_ART = {"a", "an", "the"}
|
| 234 |
+
|
| 235 |
+
|
| 236 |
+
def vqa_norm(s: str) -> str:
|
| 237 |
+
s = (s or "").strip().lower().replace("\n", " ").replace("\t", " ")
|
| 238 |
+
s = s.rstrip(".")
|
| 239 |
+
s = re.sub(r"(?<=\d),(?=\d)", "", s)
|
| 240 |
+
s = re.sub(r"[;/\[\]\"{}()=+\\_\-><@`,?!*#%^&$:~|]", " ", s)
|
| 241 |
+
s = re.sub(r"(?<!\d)\.(?!\d)", "", s)
|
| 242 |
+
words = [_NUMW.get(w, _CONTRACT.get(w, w)) for w in s.split()]
|
| 243 |
+
return " ".join(w for w in words if w not in _ART)
|
| 244 |
+
|
| 245 |
+
|
| 246 |
+
def vqa_messages(item, data_dir):
|
| 247 |
+
img_path = Path(data_dir) / item["image"]
|
| 248 |
+
b64 = base64.b64encode(img_path.read_bytes()).decode()
|
| 249 |
+
return [{"role": "user", "content": [
|
| 250 |
+
{"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{b64}"}},
|
| 251 |
+
{"type": "text", "text": item["question"] + VQA_SUFFIX},
|
| 252 |
+
]}], None
|
| 253 |
+
|
| 254 |
+
|
| 255 |
+
def vqa_score(item, resp):
|
| 256 |
+
pred = vqa_norm(strip_think(resp["content"]).split("\n")[0])
|
| 257 |
+
golds = [vqa_norm(a) for a in item["answers"]]
|
| 258 |
+
matches = sum(1 for g in golds if g == pred)
|
| 259 |
+
soft = min(1.0, matches / 3.0)
|
| 260 |
+
# primary binary metric (relaxed): normalized exact match with >=2 of the 10 annotator answers
|
| 261 |
+
# (robust to a single noisy annotation); standard VQA soft accuracy min(1, m/3) also recorded.
|
| 262 |
+
return {"pred": pred, "correct": matches >= 2 and bool(pred), "vqa_soft_acc": soft,
|
| 263 |
+
"any_annotator_match": matches >= 1}
|
| 264 |
+
|
| 265 |
+
|
| 266 |
+
TASKS = {
|
| 267 |
+
"ifeval": (ifeval_messages, ifeval_score),
|
| 268 |
+
"gsm8k": (gsm8k_messages, gsm8k_score),
|
| 269 |
+
"mmlu_pro": (mmlu_pro_messages, mmlu_pro_score),
|
| 270 |
+
"humaneval": (humaneval_messages, humaneval_score),
|
| 271 |
+
"tools": (tools_messages, tools_score),
|
| 272 |
+
"vqa": (vqa_messages, vqa_score),
|
| 273 |
+
}
|
| 274 |
+
|
| 275 |
+
|
| 276 |
+
def agreement_key(task: str, scored: dict, resp: dict):
|
| 277 |
+
"""Label-free comparable answer used for reference agreement."""
|
| 278 |
+
if task == "ifeval":
|
| 279 |
+
return strip_think(resp.get("content", "")).strip()
|
| 280 |
+
if task == "humaneval":
|
| 281 |
+
return (scored.get("pred") or "").strip()
|
| 282 |
+
if task == "tools":
|
| 283 |
+
return json.dumps(scored.get("pred"), sort_keys=True, default=str)
|
| 284 |
+
return scored.get("pred")
|
evaluation/harness/test_harness.py
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python
|
| 2 |
+
"""Offline tests for scorers + end-to-end harness against eval/mock_server.py (no GPU/model needed).
|
| 3 |
+
|
| 4 |
+
.venv-eval/bin/python eval/test_harness.py
|
| 5 |
+
"""
|
| 6 |
+
from __future__ import annotations
|
| 7 |
+
|
| 8 |
+
import json
|
| 9 |
+
import subprocess
|
| 10 |
+
import sys
|
| 11 |
+
import tempfile
|
| 12 |
+
import time
|
| 13 |
+
from pathlib import Path
|
| 14 |
+
|
| 15 |
+
HERE = Path(__file__).resolve().parent
|
| 16 |
+
sys.path.insert(0, str(HERE))
|
| 17 |
+
import ifeval_lite # noqa: E402
|
| 18 |
+
from common import parse_xml_tool_calls, read_jsonl, strip_think, wilson_ci # noqa: E402
|
| 19 |
+
from tasks import (extract_code, gsm_extract, humaneval_score, mc_extract, run_python_sandboxed, # noqa: E402
|
| 20 |
+
tools_score, vqa_norm, vqa_score)
|
| 21 |
+
|
| 22 |
+
PY = sys.executable
|
| 23 |
+
FAILS = []
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def check(cond, msg):
|
| 27 |
+
if not cond:
|
| 28 |
+
FAILS.append(msg)
|
| 29 |
+
print("FAIL:", msg)
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def unit():
|
| 33 |
+
lo, hi = wilson_ci(50, 100)
|
| 34 |
+
check(abs(lo - 0.4038) < 1e-3 and abs(hi - 0.5962) < 1e-3, f"wilson {lo},{hi}")
|
| 35 |
+
check(strip_think("<think>\nabc\n</think>\n\nHi") == "Hi", "strip_think")
|
| 36 |
+
# GSM8K
|
| 37 |
+
check(gsm_extract("so 3+4=7.\nThe final answer is 1,234.") == "1234", "gsm final")
|
| 38 |
+
check(gsm_extract("The final answer is $18.00") == "18", "gsm dollars")
|
| 39 |
+
check(gsm_extract("answer \\boxed{42}") == "42", "gsm boxed")
|
| 40 |
+
check(gsm_extract("it is -3.5 or so") == "-3.5", "gsm last num")
|
| 41 |
+
# MC
|
| 42 |
+
check(mc_extract("blah (B) ... The answer is (C).", 4) == "C", "mc 1")
|
| 43 |
+
check(mc_extract("The answer is J", 10) == "J", "mc 2")
|
| 44 |
+
check(mc_extract("The answer is (J)", 4) is None, "mc invalid letter")
|
| 45 |
+
# IFEval
|
| 46 |
+
C = ifeval_lite.check
|
| 47 |
+
check(C("hello world", ["punctuation:no_comma"], [{}]) == [True], "no_comma +")
|
| 48 |
+
check(C("hello, world", ["punctuation:no_comma"], [{}]) == [False], "no_comma -")
|
| 49 |
+
check(C("<<My Title>> text", ["detectable_format:title"], [{}]) == [True], "title")
|
| 50 |
+
check(C("* a\n* b\n- c", ["detectable_format:number_bullet_lists"], [{"num_bullets": 3}]) == [True], "bullets")
|
| 51 |
+
check(C('```json\n{"a": 1}\n```', ["detectable_format:json_format"], [{}]) == [True], "json")
|
| 52 |
+
check(C("p1\n***\np2", ["length_constraints:number_paragraphs"], [{"num_paragraphs": 2}]) == [True], "paras")
|
| 53 |
+
check(C("one two three", ["length_constraints:number_words"], [{"num_words": 5, "relation": "less than"}]) == [True], "words")
|
| 54 |
+
check(C("THIS IS ALL CAPS ENGLISH TEXT ABOUT THE WEATHER TODAY", ["change_case:english_capital"], [{}]) == [True], "caps")
|
| 55 |
+
check(C("text\nP.S. bye", ["detectable_content:postscript"], [{"postscript_marker": "P.S."}]) == [True], "ps")
|
| 56 |
+
check(C("a ****** b", ["combination:two_responses"], [{}]) == [True], "two resp")
|
| 57 |
+
check(C("Is it? My answer is yes.", ["detectable_format:constrained_response"], [{}]) == [True], "constrained")
|
| 58 |
+
check(C("Das ist ein deutscher Satz über das Wetter in Berlin heute.", ["language:response_language"],
|
| 59 |
+
[{"language": "de"}]) == [True], "lang")
|
| 60 |
+
check(C("We like apples", ["keywords:forbidden_words"], [{"forbidden_words": ["apples"]}]) == [False], "forbidden")
|
| 61 |
+
# Sandbox
|
| 62 |
+
ok, _ = run_python_sandboxed("assert 1+1==2\n")
|
| 63 |
+
check(ok, "sandbox pass")
|
| 64 |
+
ok, _ = run_python_sandboxed("assert 1+1==3\n")
|
| 65 |
+
check(not ok, "sandbox fail")
|
| 66 |
+
t = time.time()
|
| 67 |
+
ok, err = run_python_sandboxed("while True: pass\n", timeout=2)
|
| 68 |
+
check(not ok and time.time() - t < 6, f"sandbox timeout {err}")
|
| 69 |
+
ok, _ = run_python_sandboxed("import os; open('/tmp/../' + 'x','r')\n") # expected to fail cleanly
|
| 70 |
+
he = read_jsonl(HERE / "data/humaneval.jsonl")[0]
|
| 71 |
+
r = humaneval_score(he, {"content": f"```python\n{he['prompt']}{he['canonical_solution']}```"})
|
| 72 |
+
check(r["correct"], "humaneval canonical passes")
|
| 73 |
+
r = humaneval_score(he, {"content": f"```python\n{he['canonical_solution']}```"}) # body-only
|
| 74 |
+
check(r["correct"], "humaneval body-only passes")
|
| 75 |
+
check("def " in extract_code("no code", he), "extract fallback")
|
| 76 |
+
# XML tool-call parser (format from chat_template.jinja)
|
| 77 |
+
tools = [{"type": "function", "function": {"name": "f", "parameters": {"type": "object", "properties": {
|
| 78 |
+
"s": {"type": "string"}, "n": {"type": "integer"}, "b": {"type": "boolean"}, "o": {"type": "object"}}}}}]
|
| 79 |
+
txt = ("Sure.\n\n<tool_call>\n<function=f>\n<parameter=s>\n42\n</parameter>\n<parameter=n>\n7\n</parameter>\n"
|
| 80 |
+
"<parameter=b>\nTrue\n</parameter>\n<parameter=o>\n{\"k\": [1, 2]}\n</parameter>\n</function>\n</tool_call>")
|
| 81 |
+
calls, rep = parse_xml_tool_calls(txt, tools)
|
| 82 |
+
check(calls == [{"name": "f", "arguments": {"s": "42", "n": 7, "b": True, "o": {"k": [1, 2]}}}], f"xml {calls}")
|
| 83 |
+
check(rep["well_formed"] and not rep["suffix_after_last_call"], f"xml rep {rep}")
|
| 84 |
+
calls, rep = parse_xml_tool_calls("<tool_call>\n<function=f>\n<parameter=s>\nx", tools)
|
| 85 |
+
check(calls == [] and not rep["well_formed"], "xml truncated")
|
| 86 |
+
tc = read_jsonl(HERE / "data/tools.jsonl")
|
| 87 |
+
par = next(c for c in tc if c["id"] == "tool_parallel_03")
|
| 88 |
+
msg = {"content": None, "tool_calls": [
|
| 89 |
+
{"function": {"name": "set_timer", "arguments": '{"minutes": 10}'}},
|
| 90 |
+
{"function": {"name": "set_light_state", "arguments": '{"room": "Bedroom", "on": false}'}}]}
|
| 91 |
+
check(tools_score(par, {"message": msg, "content": ""})["correct"], "tools parallel order-insensitive")
|
| 92 |
+
msg["tool_calls"][0]["function"]["arguments"] = '{"minutes": 10, "bogus": 1}'
|
| 93 |
+
check(not tools_score(par, {"message": msg, "content": ""})["correct"], "tools hallucinated param")
|
| 94 |
+
irr = next(c for c in tc if c["category"] == "irrelevance")
|
| 95 |
+
check(tools_score(irr, {"message": {"content": "Jane Austen"}, "content": "Jane Austen"})["correct"], "irrelevance")
|
| 96 |
+
# VQA
|
| 97 |
+
check(vqa_norm("The Two Dogs.") == "2 dogs", f"vqa norm {vqa_norm('The Two Dogs.')}")
|
| 98 |
+
v = {"answers": ["dakota"] * 6 + ["x"] * 4}
|
| 99 |
+
check(vqa_score(v, {"content": "Dakota"})["correct"], "vqa")
|
| 100 |
+
check(not vqa_score({"answers": ["a1"] + ["z"] * 9}, {"content": "a1"})["correct"], "vqa single-annotator")
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
def e2e():
|
| 104 |
+
with tempfile.TemporaryDirectory() as td:
|
| 105 |
+
procs = []
|
| 106 |
+
try:
|
| 107 |
+
for port, extra in ((18991, []), (18992, ["--tool-mode", "xml"]), (18993, ["--corrupt-every", "5"])):
|
| 108 |
+
procs.append(subprocess.Popen([PY, "-I", str(HERE / "mock_server.py"), "--port", str(port), *extra],
|
| 109 |
+
stdout=subprocess.DEVNULL))
|
| 110 |
+
time.sleep(2.5)
|
| 111 |
+
for port, name in ((18991, "gold"), (18992, "xml"), (18993, "corrupt")):
|
| 112 |
+
subprocess.run([PY, "-I", str(HERE / "run_eval.py"), "--base-url", f"http://127.0.0.1:{port}/v1",
|
| 113 |
+
"--model", "mock", "--out", f"{td}/{name}", "--concurrency", "8"], check=True)
|
| 114 |
+
g = json.load(open(f"{td}/gold/summary.json"))["tasks"]
|
| 115 |
+
for t in ("gsm8k", "mmlu_pro", "humaneval", "tools", "vqa"):
|
| 116 |
+
check(g[t]["accuracy"] == 1.0, f"gold run {t} acc={g[t]['accuracy']}")
|
| 117 |
+
x = json.load(open(f"{td}/xml/summary.json"))["tasks"]["tools"]
|
| 118 |
+
check(x["accuracy"] == 1.0 and x["parse_source_counts"].get("fallback_xml") == 17,
|
| 119 |
+
f"xml fallback {x}")
|
| 120 |
+
check(x["format_well_formed"] == 1.0, "xml well formed")
|
| 121 |
+
out = subprocess.run([PY, "-I", str(HERE / "compare.py"), f"{td}/gold", f"{td}/corrupt"],
|
| 122 |
+
check=True, capture_output=True, text=True).stdout
|
| 123 |
+
print(out)
|
| 124 |
+
cmp_ = json.load(open(f"{td}/corrupt/compare_vs_ref.json"))
|
| 125 |
+
o = cmp_["overall_micro"]
|
| 126 |
+
check(o["delta"] < 0 and o["delta_boot95"][1] < 0 and o["ref_agreement"] < 1, f"compare {o}")
|
| 127 |
+
check(cmp_["tasks"]["ifeval"]["ref_agreement"] == 1.0, "ifeval agreement identical")
|
| 128 |
+
pb = subprocess.run([PY, "-I", str(HERE / "perf_bench.py"), "--base-url", "http://127.0.0.1:18991/v1",
|
| 129 |
+
"--model", "mock", "--concurrency", "1,4", "--num-requests", "4",
|
| 130 |
+
"--input-tokens", "256", "--output-tokens", "32", "--out", f"{td}/perf.json"],
|
| 131 |
+
capture_output=True, text=True)
|
| 132 |
+
check(pb.returncode == 0, f"perf_bench rc {pb.stderr[-800:]}")
|
| 133 |
+
if pb.returncode == 0:
|
| 134 |
+
p = json.load(open(f"{td}/perf.json"))
|
| 135 |
+
lv = p["levels"][-1]
|
| 136 |
+
check(lv["n_ok"] == 4 and lv["output_tokens_mean"] == 32, f"perf {lv}")
|
| 137 |
+
finally:
|
| 138 |
+
for p in procs:
|
| 139 |
+
p.terminate()
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
if __name__ == "__main__":
|
| 143 |
+
unit()
|
| 144 |
+
if "--unit-only" not in sys.argv:
|
| 145 |
+
e2e()
|
| 146 |
+
print("ALL OK" if not FAILS else f"{len(FAILS)} FAILURES")
|
| 147 |
+
sys.exit(1 if FAILS else 0)
|
evaluation/harness/tool_cases.py
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""20 hand-written function-calling cases (provenance: authored for this project, 2026-10-30,
|
| 2 |
+
released under Apache-2.0 alongside the harness; style modelled on BFCL categories
|
| 3 |
+
simple / multiple / parallel / irrelevance; no text copied from BFCL).
|
| 4 |
+
|
| 5 |
+
gold_calls: list of {name, arguments: {param: [allowed values...]}}; "__optional__" in the list
|
| 6 |
+
means the parameter may be omitted. Empty gold_calls => the model must NOT call a tool.
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def fn(name, desc, props, required):
|
| 11 |
+
return {"type": "function", "function": {"name": name, "description": desc, "parameters": {
|
| 12 |
+
"type": "object", "properties": props, "required": required}}}
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
S = lambda d, **kw: {"type": "string", "description": d, **kw} # noqa: E731
|
| 16 |
+
I = lambda d: {"type": "integer", "description": d} # noqa: E731
|
| 17 |
+
N = lambda d: {"type": "number", "description": d} # noqa: E731
|
| 18 |
+
B = lambda d: {"type": "boolean", "description": d} # noqa: E731
|
| 19 |
+
|
| 20 |
+
WEATHER = fn("get_current_weather", "Get the current weather for a city.",
|
| 21 |
+
{"city": S("City name, e.g. 'Paris'"), "unit": S("Temperature unit", enum=["celsius", "fahrenheit"])},
|
| 22 |
+
["city"])
|
| 23 |
+
FX = fn("convert_currency", "Convert an amount between currencies using today's rate.",
|
| 24 |
+
{"amount": N("Amount to convert"), "from_currency": S("ISO 4217 code"), "to_currency": S("ISO 4217 code")},
|
| 25 |
+
["amount", "from_currency", "to_currency"])
|
| 26 |
+
EMAIL = fn("send_email", "Send an email.",
|
| 27 |
+
{"to": S("Recipient email address"), "subject": S("Subject line"), "body": S("Plain-text body")},
|
| 28 |
+
["to", "subject", "body"])
|
| 29 |
+
FLIGHTS = fn("search_flights", "Search one-way flights.",
|
| 30 |
+
{"origin": S("IATA airport code"), "destination": S("IATA airport code"),
|
| 31 |
+
"date": S("Departure date YYYY-MM-DD"), "passengers": I("Number of passengers")},
|
| 32 |
+
["origin", "destination", "date"])
|
| 33 |
+
TIMER = fn("set_timer", "Start a countdown timer.", {"minutes": I("Duration in minutes"), "label": S("Optional label")},
|
| 34 |
+
["minutes"])
|
| 35 |
+
STOCK = fn("get_stock_price", "Get the latest stock price for a ticker symbol.", {"ticker": S("Ticker, e.g. AAPL")},
|
| 36 |
+
["ticker"])
|
| 37 |
+
TRANSLATE = fn("translate_text", "Translate text to a target language.",
|
| 38 |
+
{"text": S("Text to translate"), "target_language": S("ISO 639-1 code, e.g. 'de'")},
|
| 39 |
+
["text", "target_language"])
|
| 40 |
+
CAL = fn("create_calendar_event", "Create a calendar event.",
|
| 41 |
+
{"title": S("Event title"), "date": S("YYYY-MM-DD"), "start_time": S("HH:MM 24h"),
|
| 42 |
+
"duration_minutes": I("Length in minutes")}, ["title", "date", "start_time"])
|
| 43 |
+
SQL = fn("run_sql_query", "Run a read-only SQL query against the analytics warehouse.",
|
| 44 |
+
{"query": S("SQL SELECT statement")}, ["query"])
|
| 45 |
+
FILES = fn("list_files", "List files in a directory.", {"path": S("Directory path"), "recursive": B("Recurse")},
|
| 46 |
+
["path"])
|
| 47 |
+
BMI = fn("calculate_bmi", "Calculate body-mass index.", {"weight_kg": N("Weight in kg"), "height_m": N("Height in metres")},
|
| 48 |
+
["weight_kg", "height_m"])
|
| 49 |
+
LIGHT = fn("set_light_state", "Turn a smart light on/off and set brightness.",
|
| 50 |
+
{"room": S("Room name"), "on": B("Power state"), "brightness": I("0-100")}, ["room", "on"])
|
| 51 |
+
TICKET = fn("create_support_ticket", "Open a customer-support ticket.",
|
| 52 |
+
{"customer_id": S("Customer id"), "priority": S("Priority", enum=["low", "medium", "high"]),
|
| 53 |
+
"summary": S("Short summary")}, ["customer_id", "priority", "summary"])
|
| 54 |
+
TZ = fn("get_time_in_timezone", "Get the current local time for an IANA timezone.", {"timezone": S("e.g. Asia/Tokyo")},
|
| 55 |
+
["timezone"])
|
| 56 |
+
|
| 57 |
+
O = "__optional__"
|
| 58 |
+
CASES = [
|
| 59 |
+
# ---------------- simple (single tool available, single call)
|
| 60 |
+
dict(id="tool_simple_01", category="simple", tools=[WEATHER], user="What's the weather like in Lisbon right now? Use celsius.",
|
| 61 |
+
gold_calls=[{"name": "get_current_weather", "arguments": {"city": ["Lisbon", "Lisbon, Portugal"], "unit": ["celsius"]}}]),
|
| 62 |
+
dict(id="tool_simple_02", category="simple", tools=[FX], user="How much is 250 US dollars in euros?",
|
| 63 |
+
gold_calls=[{"name": "convert_currency", "arguments": {"amount": [250], "from_currency": ["USD"], "to_currency": ["EUR"]}}]),
|
| 64 |
+
dict(id="tool_simple_03", category="simple", tools=[TIMER], user="Set a 25 minute timer labelled pomodoro.",
|
| 65 |
+
gold_calls=[{"name": "set_timer", "arguments": {"minutes": [25], "label": ["pomodoro", "Pomodoro"]}}]),
|
| 66 |
+
dict(id="tool_simple_04", category="simple", tools=[STOCK], user="What's NVIDIA trading at? (ticker NVDA)",
|
| 67 |
+
gold_calls=[{"name": "get_stock_price", "arguments": {"ticker": ["NVDA"]}}]),
|
| 68 |
+
dict(id="tool_simple_05", category="simple", tools=[BMI], user="I weigh 72.5 kg and I'm 1.80 m tall. What's my BMI?",
|
| 69 |
+
gold_calls=[{"name": "calculate_bmi", "arguments": {"weight_kg": [72.5], "height_m": [1.8]}}]),
|
| 70 |
+
dict(id="tool_simple_06", category="simple", tools=[FILES], user="List everything under /var/log recursively.",
|
| 71 |
+
gold_calls=[{"name": "list_files", "arguments": {"path": ["/var/log", "/var/log/"], "recursive": [True]}}]),
|
| 72 |
+
dict(id="tool_simple_07", category="simple", tools=[TZ], user="What time is it in Tokyo right now? The IANA zone is Asia/Tokyo.",
|
| 73 |
+
gold_calls=[{"name": "get_time_in_timezone", "arguments": {"timezone": ["Asia/Tokyo"]}}]),
|
| 74 |
+
dict(id="tool_simple_08", category="simple", tools=[LIGHT], user="Turn on the kitchen light at 40% brightness.",
|
| 75 |
+
gold_calls=[{"name": "set_light_state", "arguments": {"room": ["kitchen"], "on": [True], "brightness": [40]}}]),
|
| 76 |
+
# ---------------- multiple (several tools available, pick one)
|
| 77 |
+
dict(id="tool_multiple_01", category="multiple", tools=[WEATHER, FLIGHTS, FX, TIMER],
|
| 78 |
+
user="Find me flights from SFO to JFK on 2026-12-03 for 2 passengers.",
|
| 79 |
+
gold_calls=[{"name": "search_flights", "arguments": {"origin": ["SFO"], "destination": ["JFK"], "date": ["2026-12-03"], "passengers": [2]}}]),
|
| 80 |
+
dict(id="tool_multiple_02", category="multiple", tools=[EMAIL, CAL, TICKET],
|
| 81 |
+
user="Email bob@example.com with subject 'Lunch' and body 'Are we still on for noon tomorrow?'",
|
| 82 |
+
gold_calls=[{"name": "send_email", "arguments": {"to": ["bob@example.com"], "subject": ["Lunch"], "body": ["Are we still on for noon tomorrow?"]}}]),
|
| 83 |
+
dict(id="tool_multiple_03", category="multiple", tools=[TRANSLATE, STOCK, WEATHER],
|
| 84 |
+
user="Translate 'Where is the train station?' into German.",
|
| 85 |
+
gold_calls=[{"name": "translate_text", "arguments": {"text": ["Where is the train station?"], "target_language": ["de"]}}]),
|
| 86 |
+
dict(id="tool_multiple_04", category="multiple", tools=[CAL, TIMER, EMAIL],
|
| 87 |
+
user="Put 'Quarterly review' on my calendar for 2026-11-14 at 15:30, lasting 90 minutes.",
|
| 88 |
+
gold_calls=[{"name": "create_calendar_event", "arguments": {"title": ["Quarterly review"], "date": ["2026-11-14"], "start_time": ["15:30"], "duration_minutes": [90]}}]),
|
| 89 |
+
dict(id="tool_multiple_05", category="multiple", tools=[SQL, FILES, STOCK],
|
| 90 |
+
user="Run this query on the warehouse: SELECT COUNT(*) FROM orders",
|
| 91 |
+
gold_calls=[{"name": "run_sql_query", "arguments": {"query": ["SELECT COUNT(*) FROM orders", "SELECT COUNT(*) FROM orders;"]}}]),
|
| 92 |
+
dict(id="tool_multiple_06", category="multiple", tools=[TICKET, EMAIL, LIGHT],
|
| 93 |
+
system="You are a support agent for Acme Corp.",
|
| 94 |
+
user="Customer C-1042 says their router keeps rebooting. Open a high priority ticket with summary 'Router reboot loop'.",
|
| 95 |
+
gold_calls=[{"name": "create_support_ticket", "arguments": {"customer_id": ["C-1042"], "priority": ["high"], "summary": ["Router reboot loop"]}}]),
|
| 96 |
+
# ---------------- parallel (two calls expected)
|
| 97 |
+
dict(id="tool_parallel_01", category="parallel", tools=[WEATHER],
|
| 98 |
+
user="What's the current weather in Oslo and in Cairo? Use celsius for both.",
|
| 99 |
+
gold_calls=[{"name": "get_current_weather", "arguments": {"city": ["Oslo"], "unit": ["celsius"]}},
|
| 100 |
+
{"name": "get_current_weather", "arguments": {"city": ["Cairo"], "unit": ["celsius"]}}]),
|
| 101 |
+
dict(id="tool_parallel_02", category="parallel", tools=[STOCK, FX],
|
| 102 |
+
user="Get me the stock prices of AAPL and MSFT.",
|
| 103 |
+
gold_calls=[{"name": "get_stock_price", "arguments": {"ticker": ["AAPL"]}},
|
| 104 |
+
{"name": "get_stock_price", "arguments": {"ticker": ["MSFT"]}}]),
|
| 105 |
+
dict(id="tool_parallel_03", category="parallel", tools=[TIMER, LIGHT],
|
| 106 |
+
user="Turn off the bedroom light and set a 10 minute timer.",
|
| 107 |
+
gold_calls=[{"name": "set_light_state", "arguments": {"room": ["bedroom"], "on": [False], "brightness": [O, 0]}},
|
| 108 |
+
{"name": "set_timer", "arguments": {"minutes": [10], "label": [O]}}]),
|
| 109 |
+
# ---------------- irrelevance (tools present but none applicable)
|
| 110 |
+
dict(id="tool_irrelevance_01", category="irrelevance", tools=[WEATHER, FX],
|
| 111 |
+
user="Who wrote the novel 'Pride and Prejudice'?", gold_calls=[]),
|
| 112 |
+
dict(id="tool_irrelevance_02", category="irrelevance", tools=[STOCK, TIMER],
|
| 113 |
+
user="What is 17 multiplied by 23?", gold_calls=[]),
|
| 114 |
+
dict(id="tool_irrelevance_03", category="irrelevance", tools=[FLIGHTS, CAL],
|
| 115 |
+
user="Write a two-line poem about autumn leaves.", gold_calls=[]),
|
| 116 |
+
]
|
evaluation/hf_bf16_checks.json
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"model_dir": "upstream/SenseNova-Loop-9B-Preview",
|
| 3 |
+
"torch": "2.11.0+cu130",
|
| 4 |
+
"load_s": 12.2,
|
| 5 |
+
"gpu_mem_after_load_GiB": 17.54,
|
| 6 |
+
"loop_plan_len": 56,
|
| 7 |
+
"mhc_param_count": 96,
|
| 8 |
+
"mhc_all_fp32": true,
|
| 9 |
+
"layer_param_dtypes": [
|
| 10 |
+
"torch.bfloat16"
|
| 11 |
+
],
|
| 12 |
+
"text_mult": {
|
| 13 |
+
"prompt_tokens": 27,
|
| 14 |
+
"gen_tokens": 3,
|
| 15 |
+
"seconds": 1.61,
|
| 16 |
+
"text": "91<|im_end|>"
|
| 17 |
+
},
|
| 18 |
+
"loop_calls_per_layer": {
|
| 19 |
+
"0": 3,
|
| 20 |
+
"1": 3,
|
| 21 |
+
"2": 3,
|
| 22 |
+
"3": 3,
|
| 23 |
+
"4": 6,
|
| 24 |
+
"5": 6,
|
| 25 |
+
"6": 6,
|
| 26 |
+
"7": 6,
|
| 27 |
+
"8": 6,
|
| 28 |
+
"9": 6,
|
| 29 |
+
"10": 6,
|
| 30 |
+
"11": 6,
|
| 31 |
+
"12": 6,
|
| 32 |
+
"13": 6,
|
| 33 |
+
"14": 6,
|
| 34 |
+
"15": 6,
|
| 35 |
+
"16": 6,
|
| 36 |
+
"17": 6,
|
| 37 |
+
"18": 6,
|
| 38 |
+
"19": 6,
|
| 39 |
+
"20": 6,
|
| 40 |
+
"21": 6,
|
| 41 |
+
"22": 6,
|
| 42 |
+
"23": 6,
|
| 43 |
+
"24": 6,
|
| 44 |
+
"25": 6,
|
| 45 |
+
"26": 6,
|
| 46 |
+
"27": 6,
|
| 47 |
+
"28": 3,
|
| 48 |
+
"29": 3,
|
| 49 |
+
"30": 3,
|
| 50 |
+
"31": 3
|
| 51 |
+
},
|
| 52 |
+
"looped_layers_called_twice": true,
|
| 53 |
+
"text_haiku": {
|
| 54 |
+
"prompt_tokens": 21,
|
| 55 |
+
"gen_tokens": 20,
|
| 56 |
+
"seconds": 5.08,
|
| 57 |
+
"text": "Green sphere, white seam,\nBounces high in summer sun,\nA game begins.<|im_end|>"
|
| 58 |
+
},
|
| 59 |
+
"thinking": {
|
| 60 |
+
"prompt_tokens": 32,
|
| 61 |
+
"gen_tokens": 262,
|
| 62 |
+
"seconds": 66.44,
|
| 63 |
+
"text": "The train goes 60 km in 45 minutes.\n\nTo find the speed in km/h, I need to convert 45 minutes to hours.\n\n45 minutes = 45/60 hours = 3/4 hours\n\nSpeed = Distance / Time = 60 km / (3/4 hours) = 60 × 4/3 = 80 km/h\n</think>\n\n# Finding the Train's Speed\n\n## Given Information\n- Distance = 60 km\n- Time = 45 minutes\n\n## Solution\n\n**Step 1:** Convert time to hours.\n\n$$45 \\text{ minutes} = \\frac{45}{60} \\text{ hours} = \\frac{3}{4} \\text{ hours}$$\n\n**Step 2:** Use the speed formula.\n\n$$\\text{Speed} = \\frac{\\text{Distance}}{\\text{Time}} = \\frac{60 \\text{ km}}{\\frac{3}{4} \\text{ hr}}$$\n\n**Step 3:** Calculate.\n\n$$\\text{Speed} = 60 \\times \\frac{4}{3} = \\boxed{80 \\text{ km/h}}$$<|im_end|>"
|
| 64 |
+
},
|
| 65 |
+
"tool_call": {
|
| 66 |
+
"prompt_tokens": 300,
|
| 67 |
+
"gen_tokens": 39,
|
| 68 |
+
"seconds": 10.13,
|
| 69 |
+
"text": "<tool_call>\n<function=get_weather>\n<parameter=city>\nParis\n</parameter>\n<parameter=unit>\ncelsius\n</parameter>\n</function>\n</tool_call><|im_end|>",
|
| 70 |
+
"has_tool_call_xml": true
|
| 71 |
+
},
|
| 72 |
+
"image": {
|
| 73 |
+
"prompt_tokens": 1013,
|
| 74 |
+
"gen_tokens": 61,
|
| 75 |
+
"seconds": 17.08,
|
| 76 |
+
"text": "A yellow mobile tyre fitting service van, branded with \"ATS\" and \"Euromaster\" logos, is driving on a road with a driver visible inside wearing a blue shirt. Behind it, a white van with a red warning light on top and a dark car are also present on the road.<|im_end|>"
|
| 77 |
+
},
|
| 78 |
+
"cache_consistency": {
|
| 79 |
+
"n": 64,
|
| 80 |
+
"match": 64,
|
| 81 |
+
"first_mismatch": null,
|
| 82 |
+
"finite_logits": true
|
| 83 |
+
},
|
| 84 |
+
"peak_gpu_mem_GiB": 17.98
|
| 85 |
+
}
|
evaluation/kernel_summary.txt
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
distinct kernels: 97 total GPU us: 553403.1010000036
|
| 2 |
+
{'other': 273.4, 'GEMM(other)': 81.8, 'FP4-related': 198.2} (ms)
|
| 3 |
+
--- top 25 kernels by time ---
|
| 4 |
+
130.2 ms 672x [FP4-related] cutlass3x_sm120_bstensorop_s16864gemm_block_scaled_ue4m3xe2m1_ue4m3xe2m1_f32_bf16_bf16_128x128x256_1x1x1_0_tnn_align32_o_vs16_bias_bf16_relu
|
| 5 |
+
71.5 ms 216x [GEMM(other)] std::enable_if<!(false), void>::type internal::gemvx::kernel<int, int, __nv_bfloat16, __nv_bfloat16, __nv_bfloat16, float, false, true, true, false, 7
|
| 6 |
+
67.4 ms 672x [FP4-related] cutlass3x_sm120_bstensorop_s16864gemm_block_scaled_ue4m3xe2m1_ue4m3xe2m1_f32_bf16_bf16_128x128x256_1x1x1_0_tnn_align32_o_vs16_bias_bf16_relu_stream_k
|
| 7 |
+
41.3 ms 46080x [other] void at::native::elementwise_kernel<128, 2, at::native::gpu_kernel_impl_nocast<at::native::CUDAFunctor_add<float> >(at::TensorIteratorBase&, at::nativ
|
| 8 |
+
23.7 ms 23616x [other] void at::native::vectorized_elementwise_kernel<4, at::native::exp_kernel_cuda(at::TensorIteratorBase&)::{lambda()#2}::operator()() const::{lambda()#2}
|
| 9 |
+
23.4 ms 23040x [other] void at::native::vectorized_elementwise_kernel<4, at::native::log_kernel_cuda(at::TensorIteratorBase&)::{lambda()#2}::operator()() const::{lambda()#2}
|
| 10 |
+
22.8 ms 23040x [other] void at::native::vectorized_elementwise_kernel<4, at::native::(anonymous namespace)::masked_fill_kernel(at::TensorIterator&, c10::Scalar const&)::{lam
|
| 11 |
+
21.8 ms 23040x [other] void at::native::vectorized_elementwise_kernel<4, at::native::CUDAFunctor_add<float>, std::array<char*, 3ul>, false>(int, at::native::CUDAFunctor_add<
|
| 12 |
+
21.4 ms 23040x [other] void at::native::vectorized_elementwise_kernel<4, at::native::AbsFunctor<float>, std::array<char*, 2ul>, false>(int, at::native::AbsFunctor<float>, st
|
| 13 |
+
21.2 ms 11520x [other] void at::native::reduce_kernel<256, 2, at::native::ReduceOp<float, at::native::func_wrapper_t<float, at::native::MaxNanFunctor<float> >, unsigned int,
|
| 14 |
+
21.0 ms 23040x [other] void at::native::vectorized_elementwise_kernel<4, at::native::AUnaryFunctor<float, float, bool, at::native::(anonymous namespace)::CompareEqFunctor<fl
|
| 15 |
+
20.6 ms 11520x [other] void at::native::reduce_kernel<256, 2, at::native::ReduceOp<float, at::native::func_wrapper_t<float, at::native::sum_functor<float, float, float>::ope
|
| 16 |
+
18.1 ms 11520x [other] void at::native::reduce_kernel<512, 1, at::native::ReduceOp<float, at::native::func_wrapper_t<float, at::native::MaxNanFunctor<float> >, unsigned int,
|
| 17 |
+
17.2 ms 11520x [other] void at::native::reduce_kernel<512, 1, at::native::ReduceOp<float, at::native::func_wrapper_t<float, at::native::sum_functor<float, float, float>::ope
|
| 18 |
+
3.4 ms 96x [GEMM(other)] void sgemm_largek_lds64<true, false, 5, 5, 4, 4, 4, 34>(float*, float const*, float const*, int, int, int, int, int, int, float const*, float const*,
|
| 19 |
+
2.6 ms 210x [other] fused_recurrent_gated_delta_rule_packed_decode_kernel
|
| 20 |
+
2.3 ms 1092x [other] void tensorrt_llm::kernels::quantize_with_block_size<(tensorrt_llm::BlockScaleQuantizationType)0, __nv_bfloat16, 16, false, false, false, false, std::
|
| 21 |
+
1.7 ms 1728x [other] void at::native::vectorized_elementwise_kernel<4, at::native::bfloat16_copy_kernel_cuda(at::TensorIteratorBase&)::{lambda(float)#1}, std::array<char*,
|
| 22 |
+
1.4 ms 480x [GEMM(other)] void dot_kernel<float, 128, 0, cublasDotParams<cublasGemvTensorStridedBatched<float const>, cublasGemvTensorStridedBatched<float> > >(cublasDotParams<
|
| 23 |
+
1.3 ms 576x [other] void at::native::reduce_kernel<512, 1, at::native::ReduceOp<float, at::native::MeanOps<float, float, float, float>, unsigned int, float, 4, 4> >(at::n
|
| 24 |
+
1.3 ms 577x [other] void at::native::unrolled_elementwise_kernel<at::native::direct_copy_kernel_cuda(at::TensorIteratorBase&)::{lambda()#3}::operator()() const::{lambda()
|
| 25 |
+
1.3 ms 96x [GEMM(other)] void cutlass::Kernel2<cutlass_80_wmma_tensorop_bf16_s161616gemm_bf16_32x32_32x1_nn_align2>(cutlass_80_wmma_tensorop_bf16_s161616gemm_bf16_32x32_32x1_n
|
| 26 |
+
1.2 ms 576x [other] void at::native::elementwise_kernel<128, 4, at::native::gpu_kernel_impl_nocast<at::native::BinaryFunctor<c10::BFloat16, c10::BFloat16, c10::BFloat16,
|
| 27 |
+
1.1 ms 588x [GEMM(other)] kernel_cutlass_kernel_flashinfernormkernelsrmsnormRMSNormKernel_object_at__tensorptrbf16gmemalign128oi64409640961_tensorptrbf16gmemalign16o40961_tenso
|
| 28 |
+
1.0 ms 480x [GEMM(other)] void cutlass::Kernel2<cutlass_80_wmma_tensorop_bf16_s161616gemm_bf16_16x16_32x1_nn_align2>(cutlass_80_wmma_tensorop_bf16_s161616gemm_bf16_16x16_32x1_n
|
evaluation/nvfp4_v1_mtp_release_probe.json
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"mult": {
|
| 3 |
+
"content": "91",
|
| 4 |
+
"reasoning": "",
|
| 5 |
+
"tool_calls": null,
|
| 6 |
+
"usage": {
|
| 7 |
+
"prompt_tokens": 27,
|
| 8 |
+
"total_tokens": 30,
|
| 9 |
+
"completion_tokens": 3,
|
| 10 |
+
"prompt_tokens_details": null,
|
| 11 |
+
"reasoning_tokens": 0,
|
| 12 |
+
"completion_tokens_details": null
|
| 13 |
+
}
|
| 14 |
+
},
|
| 15 |
+
"haiku": {
|
| 16 |
+
"content": "Green sphere, white seam,\nBounces true on court's warm ground,\nA fleeting, bright joy.",
|
| 17 |
+
"reasoning": "",
|
| 18 |
+
"tool_calls": null,
|
| 19 |
+
"usage": {
|
| 20 |
+
"prompt_tokens": 21,
|
| 21 |
+
"total_tokens": 45,
|
| 22 |
+
"completion_tokens": 24,
|
| 23 |
+
"prompt_tokens_details": null,
|
| 24 |
+
"reasoning_tokens": 0,
|
| 25 |
+
"completion_tokens_details": null
|
| 26 |
+
}
|
| 27 |
+
},
|
| 28 |
+
"thinking": {
|
| 29 |
+
"content": "\n\n# Finding the Train's Speed\n\n**Given:**\n- Distance = 60 km\n- Time = 45 minutes\n\n**Step 1: Convert time to hours**\n\n45 minutes = 45/60 = **3/4 hour**\n\n**Step 2: Calculate speed**\n\n$$\\text{Speed} = \\frac{\\text{Distance}}{\\text{Time}} = \\frac{60 \\text{ km}}{3/4 \\text{ hour}} = 60 \\times \\frac{4}{3} = \\boxed{80 \\text{ km/h}}$$",
|
| 30 |
+
"reasoning": "The train goes 60 km in 45 minutes.\n\nTo find the speed in km/h:\n\nSpeed = Distance / Time\n\nTime = 45 minutes = 45/60 hours = 3/4 hours\n\nSpeed = 60 km / (3/4 hours) = 60 × 4/3 = 80 km/h\n",
|
| 31 |
+
"tool_calls": null,
|
| 32 |
+
"usage": {
|
| 33 |
+
"prompt_tokens": 32,
|
| 34 |
+
"total_tokens": 244,
|
| 35 |
+
"completion_tokens": 212,
|
| 36 |
+
"prompt_tokens_details": null,
|
| 37 |
+
"reasoning_tokens": 80,
|
| 38 |
+
"completion_tokens_details": {
|
| 39 |
+
"reasoning_tokens": 80
|
| 40 |
+
}
|
| 41 |
+
}
|
| 42 |
+
},
|
| 43 |
+
"tool": {
|
| 44 |
+
"content": "",
|
| 45 |
+
"reasoning": "",
|
| 46 |
+
"tool_calls": [
|
| 47 |
+
{
|
| 48 |
+
"id": "call_3bdd055af15c4337a2b9fe21",
|
| 49 |
+
"index": 0,
|
| 50 |
+
"type": "function",
|
| 51 |
+
"function": {
|
| 52 |
+
"name": "get_weather",
|
| 53 |
+
"arguments": "{\"city\": \"Paris\", \"unit\": \"celsius\"}"
|
| 54 |
+
}
|
| 55 |
+
}
|
| 56 |
+
],
|
| 57 |
+
"usage": {
|
| 58 |
+
"prompt_tokens": 306,
|
| 59 |
+
"total_tokens": 345,
|
| 60 |
+
"completion_tokens": 39,
|
| 61 |
+
"prompt_tokens_details": null,
|
| 62 |
+
"reasoning_tokens": 0,
|
| 63 |
+
"completion_tokens_details": null
|
| 64 |
+
}
|
| 65 |
+
},
|
| 66 |
+
"image": {
|
| 67 |
+
"content": "A yellow mobile tyre fitting service van, branded with \"ATS\" and \"Euromaster\" logos, is driving on a road with its driver visible inside. Behind it, a white van and a dark car are also traveling on the same road.",
|
| 68 |
+
"reasoning": "",
|
| 69 |
+
"tool_calls": null,
|
| 70 |
+
"usage": {
|
| 71 |
+
"prompt_tokens": 1013,
|
| 72 |
+
"total_tokens": 1064,
|
| 73 |
+
"completion_tokens": 51,
|
| 74 |
+
"prompt_tokens_details": {
|
| 75 |
+
"cached_tokens": 0,
|
| 76 |
+
"image_tokens": 992
|
| 77 |
+
},
|
| 78 |
+
"reasoning_tokens": 0,
|
| 79 |
+
"completion_tokens_details": null
|
| 80 |
+
}
|
| 81 |
+
}
|
| 82 |
+
}
|
evaluation/nvfp4_v1_probe.json
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"mult": {
|
| 3 |
+
"content": "91",
|
| 4 |
+
"reasoning": "",
|
| 5 |
+
"tool_calls": null,
|
| 6 |
+
"usage": {
|
| 7 |
+
"prompt_tokens": 27,
|
| 8 |
+
"total_tokens": 30,
|
| 9 |
+
"completion_tokens": 3,
|
| 10 |
+
"prompt_tokens_details": null,
|
| 11 |
+
"reasoning_tokens": 0,
|
| 12 |
+
"completion_tokens_details": null
|
| 13 |
+
}
|
| 14 |
+
},
|
| 15 |
+
"haiku": {
|
| 16 |
+
"content": "Green and white, it bounces true,\nA fleeting arc through summer air,\nA brief, bright, spinning joy.",
|
| 17 |
+
"reasoning": "",
|
| 18 |
+
"tool_calls": null,
|
| 19 |
+
"usage": {
|
| 20 |
+
"prompt_tokens": 21,
|
| 21 |
+
"total_tokens": 48,
|
| 22 |
+
"completion_tokens": 27,
|
| 23 |
+
"prompt_tokens_details": null,
|
| 24 |
+
"reasoning_tokens": 0,
|
| 25 |
+
"completion_tokens_details": null
|
| 26 |
+
}
|
| 27 |
+
},
|
| 28 |
+
"thinking": {
|
| 29 |
+
"content": "\n\n# Finding the Train's Speed\n\n**Given:**\n- Distance = 60 km\n- Time = 45 minutes\n\n**Step 1:** Convert time to hours.\n\n$$45 \\text{ minutes} = \\frac{45}{60} \\text{ hours} = \\frac{3}{4} \\text{ hours}$$\n\n**Step 2:** Calculate speed.\n\n$$\\text{Speed} = \\frac{\\text{Distance}}{\\text{Time}} = \\frac{60}{\\frac{3}{4}} = 60 \\times \\frac{4}{3} = \\boxed{80 \\text{ km/h}}$$",
|
| 30 |
+
"reasoning": "The train goes 60 km in 45 minutes.\n\nTo find the speed in km/h:\n\nSpeed = Distance / Time\n\nTime = 45 minutes = 45/60 hours = 3/4 hours\n\nSpeed = 60 km / (3/4 hours) = 60 × 4/3 = 80 km/h\n",
|
| 31 |
+
"tool_calls": null,
|
| 32 |
+
"usage": {
|
| 33 |
+
"prompt_tokens": 32,
|
| 34 |
+
"total_tokens": 258,
|
| 35 |
+
"completion_tokens": 226,
|
| 36 |
+
"prompt_tokens_details": null,
|
| 37 |
+
"reasoning_tokens": 80,
|
| 38 |
+
"completion_tokens_details": {
|
| 39 |
+
"reasoning_tokens": 80
|
| 40 |
+
}
|
| 41 |
+
}
|
| 42 |
+
},
|
| 43 |
+
"tool": {
|
| 44 |
+
"content": "",
|
| 45 |
+
"reasoning": "",
|
| 46 |
+
"tool_calls": [
|
| 47 |
+
{
|
| 48 |
+
"id": "call_f059ff08a40946de871cc501",
|
| 49 |
+
"index": 0,
|
| 50 |
+
"type": "function",
|
| 51 |
+
"function": {
|
| 52 |
+
"name": "get_weather",
|
| 53 |
+
"arguments": "{\"city\": \"Paris\", \"unit\": \"celsius\"}"
|
| 54 |
+
}
|
| 55 |
+
}
|
| 56 |
+
],
|
| 57 |
+
"usage": {
|
| 58 |
+
"prompt_tokens": 306,
|
| 59 |
+
"total_tokens": 345,
|
| 60 |
+
"completion_tokens": 39,
|
| 61 |
+
"prompt_tokens_details": null,
|
| 62 |
+
"reasoning_tokens": 0,
|
| 63 |
+
"completion_tokens_details": null
|
| 64 |
+
}
|
| 65 |
+
},
|
| 66 |
+
"image": {
|
| 67 |
+
"content": "A yellow mobile tyre fitting service van, branded with \"ATS\" and \"Euromaster\" logos, is driving on a road with its amber warning lights on. Behind it, a white van with the license plate \"WG53 JNU\" and a dark car are also visible on the road.",
|
| 68 |
+
"reasoning": "",
|
| 69 |
+
"tool_calls": null,
|
| 70 |
+
"usage": {
|
| 71 |
+
"prompt_tokens": 1013,
|
| 72 |
+
"total_tokens": 1075,
|
| 73 |
+
"completion_tokens": 62,
|
| 74 |
+
"prompt_tokens_details": {
|
| 75 |
+
"cached_tokens": 0,
|
| 76 |
+
"image_tokens": 992
|
| 77 |
+
},
|
| 78 |
+
"reasoning_tokens": 0,
|
| 79 |
+
"completion_tokens_details": null
|
| 80 |
+
}
|
| 81 |
+
}
|
| 82 |
+
}
|
evaluation/perf_sglang_bf16.json
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"label": "",
|
| 3 |
+
"model": "sensenova-loop-bf16",
|
| 4 |
+
"base_url": "http://127.0.0.1:30080/v1",
|
| 5 |
+
"host": "tux",
|
| 6 |
+
"time": "2026-10-30T15:47:00-0700",
|
| 7 |
+
"config": {
|
| 8 |
+
"base_url": "http://127.0.0.1:30080/v1",
|
| 9 |
+
"model": "sensenova-loop-bf16",
|
| 10 |
+
"concurrency": "1,2,4,8",
|
| 11 |
+
"num_requests": 16,
|
| 12 |
+
"warmup": 2,
|
| 13 |
+
"input_tokens": 1024,
|
| 14 |
+
"output_tokens": 256,
|
| 15 |
+
"tokenizer": "upstream/SenseNova-Loop-9B-Preview/tokenizer.json",
|
| 16 |
+
"allow_prefix_cache": false,
|
| 17 |
+
"no_ignore_eos": false,
|
| 18 |
+
"timeout": 600,
|
| 19 |
+
"label": "",
|
| 20 |
+
"out": "eval/runs/perf_sglang_bf16.json",
|
| 21 |
+
"prompt_text_tokens": 1024,
|
| 22 |
+
"prompt_build": "tokenizer.json"
|
| 23 |
+
},
|
| 24 |
+
"levels": [
|
| 25 |
+
{
|
| 26 |
+
"concurrency": 1,
|
| 27 |
+
"n_requests": 16,
|
| 28 |
+
"n_ok": 16,
|
| 29 |
+
"n_errors": 0,
|
| 30 |
+
"errors": [],
|
| 31 |
+
"wall_s": 712.4458575863391,
|
| 32 |
+
"ttft_s": {
|
| 33 |
+
"p50": 0.7494839327409863,
|
| 34 |
+
"p90": 0.752388886641711,
|
| 35 |
+
"mean": 0.7490631011896767
|
| 36 |
+
},
|
| 37 |
+
"e2e_s": {
|
| 38 |
+
"p50": 44.54232191387564,
|
| 39 |
+
"p90": 44.74176003783941,
|
| 40 |
+
"mean": 44.52777633216465
|
| 41 |
+
},
|
| 42 |
+
"decode_tok_s_per_req": {
|
| 43 |
+
"p50": 5.82298062979468,
|
| 44 |
+
"p90": 5.857639877869307,
|
| 45 |
+
"mean": 5.8248643173510715
|
| 46 |
+
},
|
| 47 |
+
"itl_s": {
|
| 48 |
+
"p50": 0.17173366795531383,
|
| 49 |
+
"p90": 0.17253968634587877,
|
| 50 |
+
"mean": 0.17168066543298682
|
| 51 |
+
},
|
| 52 |
+
"output_tokens_mean": 256.0,
|
| 53 |
+
"output_tokens_min": 256,
|
| 54 |
+
"output_tokens_max": 256,
|
| 55 |
+
"prompt_tokens_mean": 1051.0,
|
| 56 |
+
"n_short_outputs": 0,
|
| 57 |
+
"aggregate_output_tok_s": 5.7492088084793425,
|
| 58 |
+
"requests_per_s": 0.02245784690812243,
|
| 59 |
+
"usage_reported": true
|
| 60 |
+
},
|
| 61 |
+
{
|
| 62 |
+
"concurrency": 2,
|
| 63 |
+
"n_requests": 16,
|
| 64 |
+
"n_ok": 16,
|
| 65 |
+
"n_errors": 0,
|
| 66 |
+
"errors": [],
|
| 67 |
+
"wall_s": 358.13540337421,
|
| 68 |
+
"ttft_s": {
|
| 69 |
+
"p50": 1.4381381664425135,
|
| 70 |
+
"p90": 1.493556933477521,
|
| 71 |
+
"mean": 1.451384060550481
|
| 72 |
+
},
|
| 73 |
+
"e2e_s": {
|
| 74 |
+
"p50": 44.76612635422498,
|
| 75 |
+
"p90": 45.01789597328752,
|
| 76 |
+
"mean": 44.76674999552779
|
| 77 |
+
},
|
| 78 |
+
"decode_tok_s_per_req": {
|
| 79 |
+
"p50": 5.888547972827849,
|
| 80 |
+
"p90": 5.919728871447871,
|
| 81 |
+
"mean": 5.8871749230165396
|
| 82 |
+
},
|
| 83 |
+
"itl_s": {
|
| 84 |
+
"p50": 0.16982132055997556,
|
| 85 |
+
"p90": 0.1708354555380841,
|
| 86 |
+
"mean": 0.16986371961846838
|
| 87 |
+
},
|
| 88 |
+
"output_tokens_mean": 256.0,
|
| 89 |
+
"output_tokens_min": 256,
|
| 90 |
+
"output_tokens_max": 256,
|
| 91 |
+
"prompt_tokens_mean": 1051.0,
|
| 92 |
+
"n_short_outputs": 0,
|
| 93 |
+
"aggregate_output_tok_s": 11.43701505466678,
|
| 94 |
+
"requests_per_s": 0.04467584005729211,
|
| 95 |
+
"usage_reported": true
|
| 96 |
+
},
|
| 97 |
+
{
|
| 98 |
+
"concurrency": 4,
|
| 99 |
+
"n_requests": 16,
|
| 100 |
+
"n_ok": 16,
|
| 101 |
+
"n_errors": 0,
|
| 102 |
+
"errors": [],
|
| 103 |
+
"wall_s": 187.37603424675763,
|
| 104 |
+
"ttft_s": {
|
| 105 |
+
"p50": 2.734584681224078,
|
| 106 |
+
"p90": 2.7569230226799846,
|
| 107 |
+
"mean": 2.7020455568563193
|
| 108 |
+
},
|
| 109 |
+
"e2e_s": {
|
| 110 |
+
"p50": 46.840107245370746,
|
| 111 |
+
"p90": 46.998931530397385,
|
| 112 |
+
"mean": 46.84355494793272
|
| 113 |
+
},
|
| 114 |
+
"decode_tok_s_per_req": {
|
| 115 |
+
"p50": 5.772806069829697,
|
| 116 |
+
"p90": 5.803642233569628,
|
| 117 |
+
"mean": 5.776986593431426
|
| 118 |
+
},
|
| 119 |
+
"itl_s": {
|
| 120 |
+
"p50": 0.17322622279947003,
|
| 121 |
+
"p90": 0.1738359775942038,
|
| 122 |
+
"mean": 0.1731030160166305
|
| 123 |
+
},
|
| 124 |
+
"output_tokens_mean": 256.0,
|
| 125 |
+
"output_tokens_min": 256,
|
| 126 |
+
"output_tokens_max": 256,
|
| 127 |
+
"prompt_tokens_mean": 1051.0,
|
| 128 |
+
"n_short_outputs": 0,
|
| 129 |
+
"aggregate_output_tok_s": 21.859785945762578,
|
| 130 |
+
"requests_per_s": 0.08538978885063507,
|
| 131 |
+
"usage_reported": true
|
| 132 |
+
},
|
| 133 |
+
{
|
| 134 |
+
"concurrency": 8,
|
| 135 |
+
"n_requests": 16,
|
| 136 |
+
"n_ok": 16,
|
| 137 |
+
"n_errors": 0,
|
| 138 |
+
"errors": [],
|
| 139 |
+
"wall_s": 102.59108853153884,
|
| 140 |
+
"ttft_s": {
|
| 141 |
+
"p50": 4.974256161600351,
|
| 142 |
+
"p90": 5.0004629092291,
|
| 143 |
+
"mean": 4.947074577212334
|
| 144 |
+
},
|
| 145 |
+
"e2e_s": {
|
| 146 |
+
"p50": 51.294219580013305,
|
| 147 |
+
"p90": 51.56152600981295,
|
| 148 |
+
"mean": 51.29352270014351
|
| 149 |
+
},
|
| 150 |
+
"decode_tok_s_per_req": {
|
| 151 |
+
"p50": 5.488342640760974,
|
| 152 |
+
"p90": 5.537196663306641,
|
| 153 |
+
"mean": 5.502280519349593
|
| 154 |
+
},
|
| 155 |
+
"itl_s": {
|
| 156 |
+
"p50": 0.18220517470811803,
|
| 157 |
+
"p90": 0.18259358133244163,
|
| 158 |
+
"mean": 0.18174918959711622
|
| 159 |
+
},
|
| 160 |
+
"output_tokens_mean": 256.0,
|
| 161 |
+
"output_tokens_min": 256,
|
| 162 |
+
"output_tokens_max": 256,
|
| 163 |
+
"prompt_tokens_mean": 1051.0,
|
| 164 |
+
"n_short_outputs": 0,
|
| 165 |
+
"aggregate_output_tok_s": 39.925495075927536,
|
| 166 |
+
"requests_per_s": 0.15595896514034194,
|
| 167 |
+
"usage_reported": true
|
| 168 |
+
}
|
| 169 |
+
]
|
| 170 |
+
}
|
evaluation/perf_sglang_bf16_mtp.json
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"label": "",
|
| 3 |
+
"model": "sensenova-loop-bf16",
|
| 4 |
+
"base_url": "http://127.0.0.1:30080/v1",
|
| 5 |
+
"host": "tux",
|
| 6 |
+
"time": "2026-10-30T16:33:57-0700",
|
| 7 |
+
"config": {
|
| 8 |
+
"base_url": "http://127.0.0.1:30080/v1",
|
| 9 |
+
"model": "sensenova-loop-bf16",
|
| 10 |
+
"concurrency": "1,2,4,8",
|
| 11 |
+
"num_requests": 8,
|
| 12 |
+
"warmup": 2,
|
| 13 |
+
"input_tokens": 1024,
|
| 14 |
+
"output_tokens": 256,
|
| 15 |
+
"tokenizer": "upstream/SenseNova-Loop-9B-Preview/tokenizer.json",
|
| 16 |
+
"allow_prefix_cache": false,
|
| 17 |
+
"no_ignore_eos": false,
|
| 18 |
+
"timeout": 600,
|
| 19 |
+
"label": "",
|
| 20 |
+
"out": "eval/runs/perf_sglang_bf16_mtp.json",
|
| 21 |
+
"prompt_text_tokens": 1024,
|
| 22 |
+
"prompt_build": "tokenizer.json"
|
| 23 |
+
},
|
| 24 |
+
"levels": [
|
| 25 |
+
{
|
| 26 |
+
"concurrency": 1,
|
| 27 |
+
"n_requests": 8,
|
| 28 |
+
"n_ok": 8,
|
| 29 |
+
"n_errors": 0,
|
| 30 |
+
"errors": [],
|
| 31 |
+
"wall_s": 272.73132864851505,
|
| 32 |
+
"ttft_s": {
|
| 33 |
+
"p50": 0.7848195834085345,
|
| 34 |
+
"p90": 0.9759742130525411,
|
| 35 |
+
"mean": 0.8312031434616074
|
| 36 |
+
},
|
| 37 |
+
"e2e_s": {
|
| 38 |
+
"p50": 34.21052242349833,
|
| 39 |
+
"p90": 34.438923329673706,
|
| 40 |
+
"mean": 34.09125282650348
|
| 41 |
+
},
|
| 42 |
+
"decode_tok_s_per_req": {
|
| 43 |
+
"p50": 7.627452517131835,
|
| 44 |
+
"p90": 7.763279273008121,
|
| 45 |
+
"mean": 7.669396340870895
|
| 46 |
+
},
|
| 47 |
+
"itl_s": {
|
| 48 |
+
"p50": 0.1311053762084567,
|
| 49 |
+
"p90": 0.13172920723317885,
|
| 50 |
+
"mean": 0.13043050938103276
|
| 51 |
+
},
|
| 52 |
+
"output_tokens_mean": 256.0,
|
| 53 |
+
"output_tokens_min": 256,
|
| 54 |
+
"output_tokens_max": 256,
|
| 55 |
+
"prompt_tokens_mean": 1051.0,
|
| 56 |
+
"n_short_outputs": 0,
|
| 57 |
+
"aggregate_output_tok_s": 7.50922165835733,
|
| 58 |
+
"requests_per_s": 0.02933289710295832,
|
| 59 |
+
"usage_reported": true
|
| 60 |
+
},
|
| 61 |
+
{
|
| 62 |
+
"concurrency": 2,
|
| 63 |
+
"n_requests": 8,
|
| 64 |
+
"n_ok": 8,
|
| 65 |
+
"n_errors": 0,
|
| 66 |
+
"errors": [],
|
| 67 |
+
"wall_s": 138.61350492294878,
|
| 68 |
+
"ttft_s": {
|
| 69 |
+
"p50": 1.1976498886942863,
|
| 70 |
+
"p90": 1.6063555277884007,
|
| 71 |
+
"mean": 1.2973694901447743
|
| 72 |
+
},
|
| 73 |
+
"e2e_s": {
|
| 74 |
+
"p50": 34.72376540116966,
|
| 75 |
+
"p90": 36.45519359242171,
|
| 76 |
+
"mean": 34.5663175820373
|
| 77 |
+
},
|
| 78 |
+
"decode_tok_s_per_req": {
|
| 79 |
+
"p50": 7.653260406224514,
|
| 80 |
+
"p90": 8.09628260642012,
|
| 81 |
+
"mean": 7.677757556692128
|
| 82 |
+
},
|
| 83 |
+
"itl_s": {
|
| 84 |
+
"p50": 0.13067035353651235,
|
| 85 |
+
"p90": 0.13736926173243452,
|
| 86 |
+
"mean": 0.13046496708274763
|
| 87 |
+
},
|
| 88 |
+
"output_tokens_mean": 256.0,
|
| 89 |
+
"output_tokens_min": 256,
|
| 90 |
+
"output_tokens_max": 256,
|
| 91 |
+
"prompt_tokens_mean": 1051.0,
|
| 92 |
+
"n_short_outputs": 0,
|
| 93 |
+
"aggregate_output_tok_s": 14.774895138380808,
|
| 94 |
+
"requests_per_s": 0.05771443413430003,
|
| 95 |
+
"usage_reported": true
|
| 96 |
+
},
|
| 97 |
+
{
|
| 98 |
+
"concurrency": 4,
|
| 99 |
+
"n_requests": 8,
|
| 100 |
+
"n_ok": 8,
|
| 101 |
+
"n_errors": 0,
|
| 102 |
+
"errors": [],
|
| 103 |
+
"wall_s": 76.38755708001554,
|
| 104 |
+
"ttft_s": {
|
| 105 |
+
"p50": 2.5858272635377944,
|
| 106 |
+
"p90": 2.779972269944847,
|
| 107 |
+
"mean": 2.2637667186791077
|
| 108 |
+
},
|
| 109 |
+
"e2e_s": {
|
| 110 |
+
"p50": 36.801751386839896,
|
| 111 |
+
"p90": 39.171385447308424,
|
| 112 |
+
"mean": 37.270905990269966
|
| 113 |
+
},
|
| 114 |
+
"decode_tok_s_per_req": {
|
| 115 |
+
"p50": 7.2633816269398785,
|
| 116 |
+
"p90": 7.592177491148207,
|
| 117 |
+
"mean": 7.294118130503968
|
| 118 |
+
},
|
| 119 |
+
"itl_s": {
|
| 120 |
+
"p50": 0.1376772181057901,
|
| 121 |
+
"p90": 0.1427121850625411,
|
| 122 |
+
"mean": 0.13728188767883123
|
| 123 |
+
},
|
| 124 |
+
"output_tokens_mean": 256.0,
|
| 125 |
+
"output_tokens_min": 256,
|
| 126 |
+
"output_tokens_max": 256,
|
| 127 |
+
"prompt_tokens_mean": 1051.0,
|
| 128 |
+
"n_short_outputs": 0,
|
| 129 |
+
"aggregate_output_tok_s": 26.810649250829314,
|
| 130 |
+
"requests_per_s": 0.10472909863605201,
|
| 131 |
+
"usage_reported": true
|
| 132 |
+
},
|
| 133 |
+
{
|
| 134 |
+
"concurrency": 8,
|
| 135 |
+
"n_requests": 8,
|
| 136 |
+
"n_ok": 8,
|
| 137 |
+
"n_errors": 0,
|
| 138 |
+
"errors": [],
|
| 139 |
+
"wall_s": 44.81087386980653,
|
| 140 |
+
"ttft_s": {
|
| 141 |
+
"p50": 5.374245874583721,
|
| 142 |
+
"p90": 5.41043642014265,
|
| 143 |
+
"mean": 5.388463915442117
|
| 144 |
+
},
|
| 145 |
+
"e2e_s": {
|
| 146 |
+
"p50": 41.73927395185456,
|
| 147 |
+
"p90": 43.86301381308586,
|
| 148 |
+
"mean": 41.677275480818935
|
| 149 |
+
},
|
| 150 |
+
"decode_tok_s_per_req": {
|
| 151 |
+
"p50": 7.0119672437329355,
|
| 152 |
+
"p90": 7.471562651588895,
|
| 153 |
+
"mean": 7.0494192349641605
|
| 154 |
+
},
|
| 155 |
+
"itl_s": {
|
| 156 |
+
"p50": 0.1426148278529153,
|
| 157 |
+
"p90": 0.1509358527029262,
|
| 158 |
+
"mean": 0.14230802183349928
|
| 159 |
+
},
|
| 160 |
+
"output_tokens_mean": 256.0,
|
| 161 |
+
"output_tokens_min": 256,
|
| 162 |
+
"output_tokens_max": 256,
|
| 163 |
+
"prompt_tokens_mean": 1051.0,
|
| 164 |
+
"n_short_outputs": 0,
|
| 165 |
+
"aggregate_output_tok_s": 45.7031926212878,
|
| 166 |
+
"requests_per_s": 0.17852809617690546,
|
| 167 |
+
"usage_reported": true
|
| 168 |
+
}
|
| 169 |
+
]
|
| 170 |
+
}
|
evaluation/perf_sglang_nvfp4_v1.json
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"label": "",
|
| 3 |
+
"model": "sensenova-loop-nvfp4",
|
| 4 |
+
"base_url": "http://127.0.0.1:30080/v1",
|
| 5 |
+
"host": "tux",
|
| 6 |
+
"time": "2026-10-30T17:00:57-0700",
|
| 7 |
+
"config": {
|
| 8 |
+
"base_url": "http://127.0.0.1:30080/v1",
|
| 9 |
+
"model": "sensenova-loop-nvfp4",
|
| 10 |
+
"concurrency": "1,2,4,8",
|
| 11 |
+
"num_requests": 16,
|
| 12 |
+
"warmup": 2,
|
| 13 |
+
"input_tokens": 1024,
|
| 14 |
+
"output_tokens": 256,
|
| 15 |
+
"tokenizer": "upstream/SenseNova-Loop-9B-Preview/tokenizer.json",
|
| 16 |
+
"allow_prefix_cache": false,
|
| 17 |
+
"no_ignore_eos": false,
|
| 18 |
+
"timeout": 600,
|
| 19 |
+
"label": "",
|
| 20 |
+
"out": "eval/runs/perf_sglang_nvfp4_v1.json",
|
| 21 |
+
"prompt_text_tokens": 1024,
|
| 22 |
+
"prompt_build": "tokenizer.json"
|
| 23 |
+
},
|
| 24 |
+
"levels": [
|
| 25 |
+
{
|
| 26 |
+
"concurrency": 1,
|
| 27 |
+
"n_requests": 16,
|
| 28 |
+
"n_ok": 16,
|
| 29 |
+
"n_errors": 0,
|
| 30 |
+
"errors": [],
|
| 31 |
+
"wall_s": 436.37869714573026,
|
| 32 |
+
"ttft_s": {
|
| 33 |
+
"p50": 0.5826272442936897,
|
| 34 |
+
"p90": 0.5880275997333229,
|
| 35 |
+
"mean": 0.5825185888679698
|
| 36 |
+
},
|
| 37 |
+
"e2e_s": {
|
| 38 |
+
"p50": 27.272629408165812,
|
| 39 |
+
"p90": 27.33341192267835,
|
| 40 |
+
"mean": 27.273564630304463
|
| 41 |
+
},
|
| 42 |
+
"decode_tok_s_per_req": {
|
| 43 |
+
"p50": 9.555136327634862,
|
| 44 |
+
"p90": 9.571729349173973,
|
| 45 |
+
"mean": 9.55383492852507
|
| 46 |
+
},
|
| 47 |
+
"itl_s": {
|
| 48 |
+
"p50": 0.10465575453697466,
|
| 49 |
+
"p90": 0.10489086669814937,
|
| 50 |
+
"mean": 0.10467025827383622
|
| 51 |
+
},
|
| 52 |
+
"output_tokens_mean": 256.0,
|
| 53 |
+
"output_tokens_min": 256,
|
| 54 |
+
"output_tokens_max": 256,
|
| 55 |
+
"prompt_tokens_mean": 1051.0,
|
| 56 |
+
"n_short_outputs": 0,
|
| 57 |
+
"aggregate_output_tok_s": 9.386342703690978,
|
| 58 |
+
"requests_per_s": 0.036665401186292884,
|
| 59 |
+
"usage_reported": true
|
| 60 |
+
},
|
| 61 |
+
{
|
| 62 |
+
"concurrency": 2,
|
| 63 |
+
"n_requests": 16,
|
| 64 |
+
"n_ok": 16,
|
| 65 |
+
"n_errors": 0,
|
| 66 |
+
"errors": [],
|
| 67 |
+
"wall_s": 232.5841392017901,
|
| 68 |
+
"ttft_s": {
|
| 69 |
+
"p50": 1.1243764483369887,
|
| 70 |
+
"p90": 1.1582226920872927,
|
| 71 |
+
"mean": 1.117659447598271
|
| 72 |
+
},
|
| 73 |
+
"e2e_s": {
|
| 74 |
+
"p50": 29.07659900886938,
|
| 75 |
+
"p90": 29.158572073560208,
|
| 76 |
+
"mean": 29.072850470547564
|
| 77 |
+
},
|
| 78 |
+
"decode_tok_s_per_req": {
|
| 79 |
+
"p50": 9.119639853361988,
|
| 80 |
+
"p90": 9.150102465833314,
|
| 81 |
+
"mean": 9.121841848607799
|
| 82 |
+
},
|
| 83 |
+
"itl_s": {
|
| 84 |
+
"p50": 0.1096534530486108,
|
| 85 |
+
"p90": 0.10988617092918823,
|
| 86 |
+
"mean": 0.10962762238854981
|
| 87 |
+
},
|
| 88 |
+
"output_tokens_mean": 256.0,
|
| 89 |
+
"output_tokens_min": 256,
|
| 90 |
+
"output_tokens_max": 256,
|
| 91 |
+
"prompt_tokens_mean": 1051.0,
|
| 92 |
+
"n_short_outputs": 0,
|
| 93 |
+
"aggregate_output_tok_s": 17.610831134303226,
|
| 94 |
+
"requests_per_s": 0.06879230911837197,
|
| 95 |
+
"usage_reported": true
|
| 96 |
+
},
|
| 97 |
+
{
|
| 98 |
+
"concurrency": 4,
|
| 99 |
+
"n_requests": 16,
|
| 100 |
+
"n_ok": 16,
|
| 101 |
+
"n_errors": 0,
|
| 102 |
+
"errors": [],
|
| 103 |
+
"wall_s": 122.35653864778578,
|
| 104 |
+
"ttft_s": {
|
| 105 |
+
"p50": 2.017746684141457,
|
| 106 |
+
"p90": 2.0371825736947358,
|
| 107 |
+
"mean": 2.0016646458534524
|
| 108 |
+
},
|
| 109 |
+
"e2e_s": {
|
| 110 |
+
"p50": 30.58990833349526,
|
| 111 |
+
"p90": 30.627535844687372,
|
| 112 |
+
"mean": 30.58872388175223
|
| 113 |
+
},
|
| 114 |
+
"decode_tok_s_per_req": {
|
| 115 |
+
"p50": 8.92044357838708,
|
| 116 |
+
"p90": 8.939535982689941,
|
| 117 |
+
"mean": 8.920202608225608
|
| 118 |
+
},
|
| 119 |
+
"itl_s": {
|
| 120 |
+
"p50": 0.11210204872540107,
|
| 121 |
+
"p90": 0.11229545274091994,
|
| 122 |
+
"mean": 0.1121052856137063
|
| 123 |
+
},
|
| 124 |
+
"output_tokens_mean": 256.0,
|
| 125 |
+
"output_tokens_min": 256,
|
| 126 |
+
"output_tokens_max": 256,
|
| 127 |
+
"prompt_tokens_mean": 1051.0,
|
| 128 |
+
"n_short_outputs": 0,
|
| 129 |
+
"aggregate_output_tok_s": 33.47593880365235,
|
| 130 |
+
"requests_per_s": 0.13076538595176698,
|
| 131 |
+
"usage_reported": true
|
| 132 |
+
},
|
| 133 |
+
{
|
| 134 |
+
"concurrency": 8,
|
| 135 |
+
"n_requests": 16,
|
| 136 |
+
"n_ok": 16,
|
| 137 |
+
"n_errors": 0,
|
| 138 |
+
"errors": [],
|
| 139 |
+
"wall_s": 63.220375599339604,
|
| 140 |
+
"ttft_s": {
|
| 141 |
+
"p50": 4.205650780815631,
|
| 142 |
+
"p90": 4.5575914164073765,
|
| 143 |
+
"mean": 4.21742238936713
|
| 144 |
+
},
|
| 145 |
+
"e2e_s": {
|
| 146 |
+
"p50": 31.60961770033464,
|
| 147 |
+
"p90": 32.07297795498744,
|
| 148 |
+
"mean": 31.608251873170957
|
| 149 |
+
},
|
| 150 |
+
"decode_tok_s_per_req": {
|
| 151 |
+
"p50": 9.306845748863292,
|
| 152 |
+
"p90": 9.356793657252013,
|
| 153 |
+
"mean": 9.310041888446369
|
| 154 |
+
},
|
| 155 |
+
"itl_s": {
|
| 156 |
+
"p50": 0.10744962619946283,
|
| 157 |
+
"p90": 0.10790295124090478,
|
| 158 |
+
"mean": 0.10741330675379027
|
| 159 |
+
},
|
| 160 |
+
"output_tokens_mean": 256.0,
|
| 161 |
+
"output_tokens_min": 256,
|
| 162 |
+
"output_tokens_max": 256,
|
| 163 |
+
"prompt_tokens_mean": 1051.0,
|
| 164 |
+
"n_short_outputs": 0,
|
| 165 |
+
"aggregate_output_tok_s": 64.78923861443788,
|
| 166 |
+
"requests_per_s": 0.25308296333764796,
|
| 167 |
+
"usage_reported": true
|
| 168 |
+
}
|
| 169 |
+
]
|
| 170 |
+
}
|
evaluation/perf_sglang_nvfp4_v1_marlin_w4a16.json
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"label": "",
|
| 3 |
+
"model": "sensenova-loop-nvfp4",
|
| 4 |
+
"base_url": "http://127.0.0.1:30080/v1",
|
| 5 |
+
"host": "tux",
|
| 6 |
+
"time": "2026-10-30T17:34:28-0700",
|
| 7 |
+
"config": {
|
| 8 |
+
"base_url": "http://127.0.0.1:30080/v1",
|
| 9 |
+
"model": "sensenova-loop-nvfp4",
|
| 10 |
+
"concurrency": "1,8",
|
| 11 |
+
"num_requests": 8,
|
| 12 |
+
"warmup": 2,
|
| 13 |
+
"input_tokens": 1024,
|
| 14 |
+
"output_tokens": 256,
|
| 15 |
+
"tokenizer": "upstream/SenseNova-Loop-9B-Preview/tokenizer.json",
|
| 16 |
+
"allow_prefix_cache": false,
|
| 17 |
+
"no_ignore_eos": false,
|
| 18 |
+
"timeout": 600,
|
| 19 |
+
"label": "",
|
| 20 |
+
"out": "eval/runs/perf_sglang_nvfp4_v1_marlin_w4a16.json",
|
| 21 |
+
"prompt_text_tokens": 1024,
|
| 22 |
+
"prompt_build": "tokenizer.json"
|
| 23 |
+
},
|
| 24 |
+
"levels": [
|
| 25 |
+
{
|
| 26 |
+
"concurrency": 1,
|
| 27 |
+
"n_requests": 8,
|
| 28 |
+
"n_ok": 8,
|
| 29 |
+
"n_errors": 0,
|
| 30 |
+
"errors": [],
|
| 31 |
+
"wall_s": 186.50683353003114,
|
| 32 |
+
"ttft_s": {
|
| 33 |
+
"p50": 0.7810423010960221,
|
| 34 |
+
"p90": 0.7850782623514533,
|
| 35 |
+
"mean": 0.7793308835243806
|
| 36 |
+
},
|
| 37 |
+
"e2e_s": {
|
| 38 |
+
"p50": 23.208507381845266,
|
| 39 |
+
"p90": 23.798335312213748,
|
| 40 |
+
"mean": 23.31315671908669
|
| 41 |
+
},
|
| 42 |
+
"decode_tok_s_per_req": {
|
| 43 |
+
"p50": 11.369868579529511,
|
| 44 |
+
"p90": 11.574229702673124,
|
| 45 |
+
"mean": 11.320382232025935
|
| 46 |
+
},
|
| 47 |
+
"itl_s": {
|
| 48 |
+
"p50": 0.08795635091761747,
|
| 49 |
+
"p90": 0.09028583205250257,
|
| 50 |
+
"mean": 0.0883674864250911
|
| 51 |
+
},
|
| 52 |
+
"output_tokens_mean": 256.0,
|
| 53 |
+
"output_tokens_min": 256,
|
| 54 |
+
"output_tokens_max": 256,
|
| 55 |
+
"prompt_tokens_mean": 1051.0,
|
| 56 |
+
"n_short_outputs": 0,
|
| 57 |
+
"aggregate_output_tok_s": 10.980830896312618,
|
| 58 |
+
"requests_per_s": 0.042893870688721164,
|
| 59 |
+
"usage_reported": true
|
| 60 |
+
},
|
| 61 |
+
{
|
| 62 |
+
"concurrency": 8,
|
| 63 |
+
"n_requests": 8,
|
| 64 |
+
"n_ok": 8,
|
| 65 |
+
"n_errors": 0,
|
| 66 |
+
"errors": [],
|
| 67 |
+
"wall_s": 35.205060383304954,
|
| 68 |
+
"ttft_s": {
|
| 69 |
+
"p50": 6.181970591191202,
|
| 70 |
+
"p90": 6.18461575973779,
|
| 71 |
+
"mean": 6.14046993048396
|
| 72 |
+
},
|
| 73 |
+
"e2e_s": {
|
| 74 |
+
"p50": 35.20080000348389,
|
| 75 |
+
"p90": 35.20238197837025,
|
| 76 |
+
"mean": 35.2009118568385
|
| 77 |
+
},
|
| 78 |
+
"decode_tok_s_per_req": {
|
| 79 |
+
"p50": 8.787708328163664,
|
| 80 |
+
"p90": 8.78777517236657,
|
| 81 |
+
"mean": 8.774984883438263
|
| 82 |
+
},
|
| 83 |
+
"itl_s": {
|
| 84 |
+
"p50": 0.11379531075191848,
|
| 85 |
+
"p90": 0.11419632067502129,
|
| 86 |
+
"mean": 0.11396200469439374
|
| 87 |
+
},
|
| 88 |
+
"output_tokens_mean": 256.0,
|
| 89 |
+
"output_tokens_min": 256,
|
| 90 |
+
"output_tokens_max": 256,
|
| 91 |
+
"prompt_tokens_mean": 1051.0,
|
| 92 |
+
"n_short_outputs": 0,
|
| 93 |
+
"aggregate_output_tok_s": 58.17345511417468,
|
| 94 |
+
"requests_per_s": 0.22724005903974484,
|
| 95 |
+
"usage_reported": true
|
| 96 |
+
}
|
| 97 |
+
]
|
| 98 |
+
}
|
evaluation/perf_sglang_nvfp4_v1_mtp.json
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"label": "",
|
| 3 |
+
"model": "sensenova-loop-nvfp4",
|
| 4 |
+
"base_url": "http://127.0.0.1:30080/v1",
|
| 5 |
+
"host": "tux",
|
| 6 |
+
"time": "2026-10-30T17:21:08-0700",
|
| 7 |
+
"config": {
|
| 8 |
+
"base_url": "http://127.0.0.1:30080/v1",
|
| 9 |
+
"model": "sensenova-loop-nvfp4",
|
| 10 |
+
"concurrency": "1,2,4,8",
|
| 11 |
+
"num_requests": 8,
|
| 12 |
+
"warmup": 2,
|
| 13 |
+
"input_tokens": 1024,
|
| 14 |
+
"output_tokens": 256,
|
| 15 |
+
"tokenizer": "upstream/SenseNova-Loop-9B-Preview/tokenizer.json",
|
| 16 |
+
"allow_prefix_cache": false,
|
| 17 |
+
"no_ignore_eos": false,
|
| 18 |
+
"timeout": 600,
|
| 19 |
+
"label": "",
|
| 20 |
+
"out": "eval/runs/perf_sglang_nvfp4_v1_mtp.json",
|
| 21 |
+
"prompt_text_tokens": 1024,
|
| 22 |
+
"prompt_build": "tokenizer.json"
|
| 23 |
+
},
|
| 24 |
+
"levels": [
|
| 25 |
+
{
|
| 26 |
+
"concurrency": 1,
|
| 27 |
+
"n_requests": 8,
|
| 28 |
+
"n_ok": 8,
|
| 29 |
+
"n_errors": 0,
|
| 30 |
+
"errors": [],
|
| 31 |
+
"wall_s": 167.7497703190893,
|
| 32 |
+
"ttft_s": {
|
| 33 |
+
"p50": 0.7368478225544095,
|
| 34 |
+
"p90": 0.7410881330259145,
|
| 35 |
+
"mean": 0.7100226980401203
|
| 36 |
+
},
|
| 37 |
+
"e2e_s": {
|
| 38 |
+
"p50": 20.956795112695545,
|
| 39 |
+
"p90": 22.442169491481035,
|
| 40 |
+
"mean": 20.96854761627037
|
| 41 |
+
},
|
| 42 |
+
"decode_tok_s_per_req": {
|
| 43 |
+
"p50": 12.574976715274474,
|
| 44 |
+
"p90": 13.522581057360785,
|
| 45 |
+
"mean": 12.629198610683233
|
| 46 |
+
},
|
| 47 |
+
"itl_s": {
|
| 48 |
+
"p50": 0.07952795094609552,
|
| 49 |
+
"p90": 0.08523689763364839,
|
| 50 |
+
"mean": 0.07944462552721447
|
| 51 |
+
},
|
| 52 |
+
"output_tokens_mean": 256.0,
|
| 53 |
+
"output_tokens_min": 256,
|
| 54 |
+
"output_tokens_max": 256,
|
| 55 |
+
"prompt_tokens_mean": 1051.0,
|
| 56 |
+
"n_short_outputs": 0,
|
| 57 |
+
"aggregate_output_tok_s": 12.208660531125302,
|
| 58 |
+
"requests_per_s": 0.04769008019970821,
|
| 59 |
+
"usage_reported": true
|
| 60 |
+
},
|
| 61 |
+
{
|
| 62 |
+
"concurrency": 2,
|
| 63 |
+
"n_requests": 8,
|
| 64 |
+
"n_ok": 8,
|
| 65 |
+
"n_errors": 0,
|
| 66 |
+
"errors": [],
|
| 67 |
+
"wall_s": 82.62508355267346,
|
| 68 |
+
"ttft_s": {
|
| 69 |
+
"p50": 0.8884775410406291,
|
| 70 |
+
"p90": 1.168848348222673,
|
| 71 |
+
"mean": 0.9600589442998171
|
| 72 |
+
},
|
| 73 |
+
"e2e_s": {
|
| 74 |
+
"p50": 20.495888442732394,
|
| 75 |
+
"p90": 23.237484936509283,
|
| 76 |
+
"mean": 20.539230286842212
|
| 77 |
+
},
|
| 78 |
+
"decode_tok_s_per_req": {
|
| 79 |
+
"p50": 13.113690417487145,
|
| 80 |
+
"p90": 15.40404216440473,
|
| 81 |
+
"mean": 13.185971019742919
|
| 82 |
+
},
|
| 83 |
+
"itl_s": {
|
| 84 |
+
"p50": 0.07629031224687602,
|
| 85 |
+
"p90": 0.08763312555082581,
|
| 86 |
+
"mean": 0.0767804972402861
|
| 87 |
+
},
|
| 88 |
+
"output_tokens_mean": 256.0,
|
| 89 |
+
"output_tokens_min": 256,
|
| 90 |
+
"output_tokens_max": 256,
|
| 91 |
+
"prompt_tokens_mean": 1051.0,
|
| 92 |
+
"n_short_outputs": 0,
|
| 93 |
+
"aggregate_output_tok_s": 24.786661773169655,
|
| 94 |
+
"requests_per_s": 0.09682289755144396,
|
| 95 |
+
"usage_reported": true
|
| 96 |
+
},
|
| 97 |
+
{
|
| 98 |
+
"concurrency": 4,
|
| 99 |
+
"n_requests": 8,
|
| 100 |
+
"n_ok": 8,
|
| 101 |
+
"n_errors": 0,
|
| 102 |
+
"errors": [],
|
| 103 |
+
"wall_s": 48.18132451828569,
|
| 104 |
+
"ttft_s": {
|
| 105 |
+
"p50": 1.4830374312587082,
|
| 106 |
+
"p90": 2.075450401753187,
|
| 107 |
+
"mean": 1.469463941641152
|
| 108 |
+
},
|
| 109 |
+
"e2e_s": {
|
| 110 |
+
"p50": 22.7819732921198,
|
| 111 |
+
"p90": 24.27312577702105,
|
| 112 |
+
"mean": 22.48564152873587
|
| 113 |
+
},
|
| 114 |
+
"decode_tok_s_per_req": {
|
| 115 |
+
"p50": 12.02420852876317,
|
| 116 |
+
"p90": 13.446927005044758,
|
| 117 |
+
"mean": 12.240232030320389
|
| 118 |
+
},
|
| 119 |
+
"itl_s": {
|
| 120 |
+
"p50": 0.08323863003512516,
|
| 121 |
+
"p90": 0.09169133495101157,
|
| 122 |
+
"mean": 0.08241570999380202
|
| 123 |
+
},
|
| 124 |
+
"output_tokens_mean": 256.0,
|
| 125 |
+
"output_tokens_min": 256,
|
| 126 |
+
"output_tokens_max": 256,
|
| 127 |
+
"prompt_tokens_mean": 1051.0,
|
| 128 |
+
"n_short_outputs": 0,
|
| 129 |
+
"aggregate_output_tok_s": 42.50609588830931,
|
| 130 |
+
"requests_per_s": 0.16603943706370825,
|
| 131 |
+
"usage_reported": true
|
| 132 |
+
},
|
| 133 |
+
{
|
| 134 |
+
"concurrency": 8,
|
| 135 |
+
"n_requests": 8,
|
| 136 |
+
"n_ok": 8,
|
| 137 |
+
"n_errors": 0,
|
| 138 |
+
"errors": [],
|
| 139 |
+
"wall_s": 31.786477480083704,
|
| 140 |
+
"ttft_s": {
|
| 141 |
+
"p50": 5.049089141655713,
|
| 142 |
+
"p90": 5.0829355555586515,
|
| 143 |
+
"mean": 5.062669638660736
|
| 144 |
+
},
|
| 145 |
+
"e2e_s": {
|
| 146 |
+
"p50": 25.993340300396085,
|
| 147 |
+
"p90": 29.076695342641322,
|
| 148 |
+
"mean": 26.93958732835017
|
| 149 |
+
},
|
| 150 |
+
"decode_tok_s_per_req": {
|
| 151 |
+
"p50": 12.175041260252009,
|
| 152 |
+
"p90": 12.51746500245328,
|
| 153 |
+
"mean": 11.74804181220008
|
| 154 |
+
},
|
| 155 |
+
"itl_s": {
|
| 156 |
+
"p50": 0.08213639315948182,
|
| 157 |
+
"p90": 0.09391973348115297,
|
| 158 |
+
"mean": 0.08579115118813135
|
| 159 |
+
},
|
| 160 |
+
"output_tokens_mean": 256.0,
|
| 161 |
+
"output_tokens_min": 256,
|
| 162 |
+
"output_tokens_max": 256,
|
| 163 |
+
"prompt_tokens_mean": 1051.0,
|
| 164 |
+
"n_short_outputs": 0,
|
| 165 |
+
"aggregate_output_tok_s": 64.42991367266805,
|
| 166 |
+
"requests_per_s": 0.25167935028385957,
|
| 167 |
+
"usage_reported": true
|
| 168 |
+
}
|
| 169 |
+
]
|
| 170 |
+
}
|
evaluation/sglang_bf16_mtp_probe.json
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"mult": {
|
| 3 |
+
"content": "91",
|
| 4 |
+
"reasoning": "",
|
| 5 |
+
"tool_calls": null,
|
| 6 |
+
"usage": {
|
| 7 |
+
"prompt_tokens": 27,
|
| 8 |
+
"total_tokens": 30,
|
| 9 |
+
"completion_tokens": 3,
|
| 10 |
+
"prompt_tokens_details": null,
|
| 11 |
+
"reasoning_tokens": 0,
|
| 12 |
+
"completion_tokens_details": null
|
| 13 |
+
}
|
| 14 |
+
},
|
| 15 |
+
"haiku": {
|
| 16 |
+
"content": "Green and white, it flies,\nBounces high in summer air,\nA game of joy.",
|
| 17 |
+
"reasoning": "",
|
| 18 |
+
"tool_calls": null,
|
| 19 |
+
"usage": {
|
| 20 |
+
"prompt_tokens": 21,
|
| 21 |
+
"total_tokens": 43,
|
| 22 |
+
"completion_tokens": 22,
|
| 23 |
+
"prompt_tokens_details": null,
|
| 24 |
+
"reasoning_tokens": 0,
|
| 25 |
+
"completion_tokens_details": null
|
| 26 |
+
}
|
| 27 |
+
},
|
| 28 |
+
"thinking": {
|
| 29 |
+
"content": "\n\n# Finding the Train's Speed\n\n## Given Information\n- Distance = 60 km\n- Time = 45 minutes\n\n## Solution\n\n**Step 1:** Convert time to hours.\n\n$$45 \\text{ minutes} = \\frac{45}{60} \\text{ hours} = \\frac{3}{4} \\text{ hours}$$\n\n**Step 2:** Use the speed formula.\n\n$$\\text{Speed} = \\frac{\\text{Distance}}{\\text{Time}} = \\frac{60 \\text{ km}}{\\frac{3}{4} \\text{ hr}}$$\n\n**Step 3:** Calculate.\n\n$$\\text{Speed} = 60 \\times \\frac{4}{3} = \\boxed{80 \\text{ km/h}}$$",
|
| 30 |
+
"reasoning": "The train goes 60 km in 45 minutes.\n\nTo find the speed in km/h, I need to convert 45 minutes to hours.\n\n45 minutes = 45/60 hours = 3/4 hours\n\nSpeed = Distance / Time = 60 km / (3/4 hours) = 60 × 4/3 = 80 km/h\n",
|
| 31 |
+
"tool_calls": null,
|
| 32 |
+
"usage": {
|
| 33 |
+
"prompt_tokens": 32,
|
| 34 |
+
"total_tokens": 294,
|
| 35 |
+
"completion_tokens": 262,
|
| 36 |
+
"prompt_tokens_details": null,
|
| 37 |
+
"reasoning_tokens": 86,
|
| 38 |
+
"completion_tokens_details": {
|
| 39 |
+
"reasoning_tokens": 86
|
| 40 |
+
}
|
| 41 |
+
}
|
| 42 |
+
},
|
| 43 |
+
"tool": {
|
| 44 |
+
"content": "",
|
| 45 |
+
"reasoning": "",
|
| 46 |
+
"tool_calls": [
|
| 47 |
+
{
|
| 48 |
+
"id": "call_ecd429c744ef4cdc945856fd",
|
| 49 |
+
"index": 0,
|
| 50 |
+
"type": "function",
|
| 51 |
+
"function": {
|
| 52 |
+
"name": "get_weather",
|
| 53 |
+
"arguments": "{\"city\": \"Paris\", \"unit\": \"celsius\"}"
|
| 54 |
+
}
|
| 55 |
+
}
|
| 56 |
+
],
|
| 57 |
+
"usage": {
|
| 58 |
+
"prompt_tokens": 306,
|
| 59 |
+
"total_tokens": 345,
|
| 60 |
+
"completion_tokens": 39,
|
| 61 |
+
"prompt_tokens_details": null,
|
| 62 |
+
"reasoning_tokens": 0,
|
| 63 |
+
"completion_tokens_details": null
|
| 64 |
+
}
|
| 65 |
+
},
|
| 66 |
+
"image": {
|
| 67 |
+
"content": "A yellow mobile tyre fitting service van, branded with \"ATS\" and \"Euromaster\" logos, is driving on a road with a white van and a dark car visible in the background. The yellow van's license plate reads \"AJ52 UYV,\" and it features orange warning lights on its roof along with text advertising services such as tyres, batteries, exhausts, shocks, and brakes.",
|
| 68 |
+
"reasoning": "",
|
| 69 |
+
"tool_calls": null,
|
| 70 |
+
"usage": {
|
| 71 |
+
"prompt_tokens": 1013,
|
| 72 |
+
"total_tokens": 1096,
|
| 73 |
+
"completion_tokens": 83,
|
| 74 |
+
"prompt_tokens_details": {
|
| 75 |
+
"cached_tokens": 0,
|
| 76 |
+
"image_tokens": 992
|
| 77 |
+
},
|
| 78 |
+
"reasoning_tokens": 0,
|
| 79 |
+
"completion_tokens_details": null
|
| 80 |
+
}
|
| 81 |
+
}
|
| 82 |
+
}
|
evaluation/sglang_bf16_probe.json
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"mult": {
|
| 3 |
+
"content": "91",
|
| 4 |
+
"reasoning": "",
|
| 5 |
+
"tool_calls": null,
|
| 6 |
+
"usage": {
|
| 7 |
+
"prompt_tokens": 27,
|
| 8 |
+
"total_tokens": 30,
|
| 9 |
+
"completion_tokens": 3,
|
| 10 |
+
"prompt_tokens_details": null,
|
| 11 |
+
"reasoning_tokens": 0,
|
| 12 |
+
"completion_tokens_details": null
|
| 13 |
+
}
|
| 14 |
+
},
|
| 15 |
+
"haiku": {
|
| 16 |
+
"content": "Green sphere, white seam,\nBounces high in summer sun,\nA game begins.",
|
| 17 |
+
"reasoning": "",
|
| 18 |
+
"tool_calls": null,
|
| 19 |
+
"usage": {
|
| 20 |
+
"prompt_tokens": 21,
|
| 21 |
+
"total_tokens": 41,
|
| 22 |
+
"completion_tokens": 20,
|
| 23 |
+
"prompt_tokens_details": null,
|
| 24 |
+
"reasoning_tokens": 0,
|
| 25 |
+
"completion_tokens_details": null
|
| 26 |
+
}
|
| 27 |
+
},
|
| 28 |
+
"thinking": {
|
| 29 |
+
"content": "\n\n# Finding the Train's Speed\n\n## Given Information\n- Distance = 60 km\n- Time = 45 minutes\n\n## Solution\n\n**Step 1:** Convert time to hours.\n\n$$45 \\text{ minutes} = \\frac{45}{60} \\text{ hours} = \\frac{3}{4} \\text{ hours}$$\n\n**Step 2:** Calculate speed using the formula:\n\n$$\\text{Speed} = \\frac{\\text{Distance}}{\\text{Time}}$$\n\n$$\\text{Speed} = \\frac{60 \\text{ km}}{\\frac{3}{4} \\text{ hours}} = 60 \\times \\frac{4}{3} = \\boxed{80 \\text{ km/h}}$$",
|
| 30 |
+
"reasoning": "The train goes 60 km in 45 minutes.\n\nTo find the speed in km/h, I need to convert 45 minutes to hours.\n\n45 minutes = 45/60 hours = 3/4 hours\n\nSpeed = Distance / Time = 60 km / (3/4 hours) = 60 × 4/3 = 80 km/h\n",
|
| 31 |
+
"tool_calls": null,
|
| 32 |
+
"usage": {
|
| 33 |
+
"prompt_tokens": 32,
|
| 34 |
+
"total_tokens": 287,
|
| 35 |
+
"completion_tokens": 255,
|
| 36 |
+
"prompt_tokens_details": null,
|
| 37 |
+
"reasoning_tokens": 86,
|
| 38 |
+
"completion_tokens_details": {
|
| 39 |
+
"reasoning_tokens": 86
|
| 40 |
+
}
|
| 41 |
+
}
|
| 42 |
+
},
|
| 43 |
+
"tool": {
|
| 44 |
+
"content": "",
|
| 45 |
+
"reasoning": "",
|
| 46 |
+
"tool_calls": [
|
| 47 |
+
{
|
| 48 |
+
"id": "call_5048fd622c914bf7acade944",
|
| 49 |
+
"index": 0,
|
| 50 |
+
"type": "function",
|
| 51 |
+
"function": {
|
| 52 |
+
"name": "get_weather",
|
| 53 |
+
"arguments": "{\"city\": \"Paris\", \"unit\": \"celsius\"}"
|
| 54 |
+
}
|
| 55 |
+
}
|
| 56 |
+
],
|
| 57 |
+
"usage": {
|
| 58 |
+
"prompt_tokens": 306,
|
| 59 |
+
"total_tokens": 345,
|
| 60 |
+
"completion_tokens": 39,
|
| 61 |
+
"prompt_tokens_details": null,
|
| 62 |
+
"reasoning_tokens": 0,
|
| 63 |
+
"completion_tokens_details": null
|
| 64 |
+
}
|
| 65 |
+
},
|
| 66 |
+
"image": {
|
| 67 |
+
"content": "A yellow mobile tyre fitting service van, branded with \"ATS\" and \"Euromaster\" logos, is driving on a road with a white van and a dark car visible in the background. The yellow van's license plate reads \"AJ52 UYV,\" and it features orange warning lights on its roof along with text advertising services such as tyres, batteries, exhausts, shocks, and brakes.",
|
| 68 |
+
"reasoning": "",
|
| 69 |
+
"tool_calls": null,
|
| 70 |
+
"usage": {
|
| 71 |
+
"prompt_tokens": 1013,
|
| 72 |
+
"total_tokens": 1096,
|
| 73 |
+
"completion_tokens": 83,
|
| 74 |
+
"prompt_tokens_details": {
|
| 75 |
+
"cached_tokens": 0,
|
| 76 |
+
"image_tokens": 992
|
| 77 |
+
},
|
| 78 |
+
"reasoning_tokens": 0,
|
| 79 |
+
"completion_tokens_details": null
|
| 80 |
+
}
|
| 81 |
+
}
|
| 82 |
+
}
|
evaluation/summary_sglang_bf16.json
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"eval_version": "sn-loop-eval-v1",
|
| 3 |
+
"model": "sensenova-loop-bf16",
|
| 4 |
+
"base_url": "http://127.0.0.1:30080/v1",
|
| 5 |
+
"started": "2026-10-30T15:15:24-0700",
|
| 6 |
+
"enable_thinking": false,
|
| 7 |
+
"sampling": {
|
| 8 |
+
"temperature": 0.0,
|
| 9 |
+
"top_p": 1.0,
|
| 10 |
+
"seed": 0,
|
| 11 |
+
"max_tokens": {
|
| 12 |
+
"ifeval": 1024,
|
| 13 |
+
"gsm8k": 1024,
|
| 14 |
+
"mmlu_pro": 1024,
|
| 15 |
+
"humaneval": 1024,
|
| 16 |
+
"tools": 512,
|
| 17 |
+
"vqa": 64
|
| 18 |
+
}
|
| 19 |
+
},
|
| 20 |
+
"concurrency": 16,
|
| 21 |
+
"limit": null,
|
| 22 |
+
"host": "tux",
|
| 23 |
+
"data_sha256": {
|
| 24 |
+
"ifeval": "3e9e9e7bd42ef54862f0c71c9a4e6f0b17a9c259f8f4b2b4e5fbcad917228118",
|
| 25 |
+
"gsm8k": "5bb91d328c1ffc424d6679fe8edb36ed08152e4c75e75b343303e15cacc2da49",
|
| 26 |
+
"mmlu_pro": "e9d8d5717def43a0b995710ab093a13de48b4cfb4db19cd7c66affacfb492ea7",
|
| 27 |
+
"humaneval": "1e775e30085b890c19c48a583bfabb8f5f54598b5bf54796839b92e5bafdab9f",
|
| 28 |
+
"tools": "037b2e288f4f063e8a2d994799b4a51e4d97740b1cf62da75844243749dbb08a",
|
| 29 |
+
"vqa": "7d47303ecdf3386d04a852ab8b7e8be8d34137a1c4d10143331cc7175ce80d9d"
|
| 30 |
+
},
|
| 31 |
+
"tasks": {
|
| 32 |
+
"ifeval": {
|
| 33 |
+
"n": 60,
|
| 34 |
+
"correct": 47,
|
| 35 |
+
"accuracy": 0.7833333333333333,
|
| 36 |
+
"wilson95": [
|
| 37 |
+
0.6637997232345094,
|
| 38 |
+
0.8687695600460952
|
| 39 |
+
],
|
| 40 |
+
"n_errors": 0,
|
| 41 |
+
"n_truncated": 5,
|
| 42 |
+
"mean_completion_tokens": 318.95,
|
| 43 |
+
"sum_completion_tokens": 19137,
|
| 44 |
+
"instruction_level_acc": 0.8433734939759037,
|
| 45 |
+
"n_instructions": 83,
|
| 46 |
+
"wall_s": 392.1
|
| 47 |
+
},
|
| 48 |
+
"gsm8k": {
|
| 49 |
+
"n": 80,
|
| 50 |
+
"correct": 74,
|
| 51 |
+
"accuracy": 0.925,
|
| 52 |
+
"wilson95": [
|
| 53 |
+
0.8458798383979047,
|
| 54 |
+
0.9651747509106547
|
| 55 |
+
],
|
| 56 |
+
"n_errors": 0,
|
| 57 |
+
"n_truncated": 1,
|
| 58 |
+
"mean_completion_tokens": 191.5375,
|
| 59 |
+
"sum_completion_tokens": 15323,
|
| 60 |
+
"wall_s": 370.3
|
| 61 |
+
},
|
| 62 |
+
"mmlu_pro": {
|
| 63 |
+
"n": 60,
|
| 64 |
+
"correct": 39,
|
| 65 |
+
"accuracy": 0.65,
|
| 66 |
+
"wilson95": [
|
| 67 |
+
0.5236261874086521,
|
| 68 |
+
0.7583222566810799
|
| 69 |
+
],
|
| 70 |
+
"n_errors": 0,
|
| 71 |
+
"n_truncated": 13,
|
| 72 |
+
"mean_completion_tokens": 622.15,
|
| 73 |
+
"sum_completion_tokens": 37329,
|
| 74 |
+
"wall_s": 707.9
|
| 75 |
+
},
|
| 76 |
+
"humaneval": {
|
| 77 |
+
"n": 40,
|
| 78 |
+
"correct": 33,
|
| 79 |
+
"accuracy": 0.825,
|
| 80 |
+
"wilson95": [
|
| 81 |
+
0.6805000953869541,
|
| 82 |
+
0.9125458630150444
|
| 83 |
+
],
|
| 84 |
+
"n_errors": 0,
|
| 85 |
+
"n_truncated": 0,
|
| 86 |
+
"mean_completion_tokens": 226.575,
|
| 87 |
+
"sum_completion_tokens": 9063,
|
| 88 |
+
"wall_s": 233.7
|
| 89 |
+
},
|
| 90 |
+
"tools": {
|
| 91 |
+
"n": 20,
|
| 92 |
+
"correct": 19,
|
| 93 |
+
"accuracy": 0.95,
|
| 94 |
+
"wilson95": [
|
| 95 |
+
0.7638688045357189,
|
| 96 |
+
0.9911185512976646
|
| 97 |
+
],
|
| 98 |
+
"n_errors": 0,
|
| 99 |
+
"n_truncated": 0,
|
| 100 |
+
"mean_completion_tokens": 64.25,
|
| 101 |
+
"sum_completion_tokens": 1285,
|
| 102 |
+
"names_correct": 0.95,
|
| 103 |
+
"parse_source_counts": {
|
| 104 |
+
"server": 16,
|
| 105 |
+
"none": 4
|
| 106 |
+
},
|
| 107 |
+
"format_well_formed": 1.0,
|
| 108 |
+
"raw_tool_call_tags_in_content": 0,
|
| 109 |
+
"by_category": {
|
| 110 |
+
"irrelevance": "3/3",
|
| 111 |
+
"multiple": "6/6",
|
| 112 |
+
"parallel": "3/3",
|
| 113 |
+
"simple": "7/8"
|
| 114 |
+
},
|
| 115 |
+
"wall_s": 55.8
|
| 116 |
+
},
|
| 117 |
+
"vqa": {
|
| 118 |
+
"n": 40,
|
| 119 |
+
"correct": 36,
|
| 120 |
+
"accuracy": 0.9,
|
| 121 |
+
"wilson95": [
|
| 122 |
+
0.7694822464406407,
|
| 123 |
+
0.9604204715925885
|
| 124 |
+
],
|
| 125 |
+
"n_errors": 0,
|
| 126 |
+
"n_truncated": 0,
|
| 127 |
+
"mean_completion_tokens": 4.125,
|
| 128 |
+
"sum_completion_tokens": 165,
|
| 129 |
+
"vqa_soft_acc": 0.8833333333333334,
|
| 130 |
+
"wall_s": 38.3
|
| 131 |
+
}
|
| 132 |
+
},
|
| 133 |
+
"server_models": {
|
| 134 |
+
"object": "list",
|
| 135 |
+
"data": [
|
| 136 |
+
{
|
| 137 |
+
"id": "sensenova-loop-bf16",
|
| 138 |
+
"object": "model",
|
| 139 |
+
"created": 1793398524,
|
| 140 |
+
"owned_by": "sglang",
|
| 141 |
+
"root": "sensenova-loop-bf16",
|
| 142 |
+
"parent": null,
|
| 143 |
+
"max_model_len": 32768
|
| 144 |
+
}
|
| 145 |
+
]
|
| 146 |
+
},
|
| 147 |
+
"wall_s": 1798.0
|
| 148 |
+
}
|
evaluation/summary_sglang_bf16_mtp.json
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"eval_version": "sn-loop-eval-v1",
|
| 3 |
+
"model": "sensenova-loop-bf16",
|
| 4 |
+
"base_url": "http://127.0.0.1:30080/v1",
|
| 5 |
+
"started": "2026-10-30T16:28:25-0700",
|
| 6 |
+
"enable_thinking": false,
|
| 7 |
+
"sampling": {
|
| 8 |
+
"temperature": 0.0,
|
| 9 |
+
"top_p": 1.0,
|
| 10 |
+
"seed": 0,
|
| 11 |
+
"max_tokens": {
|
| 12 |
+
"ifeval": 1024,
|
| 13 |
+
"gsm8k": 1024,
|
| 14 |
+
"mmlu_pro": 1024,
|
| 15 |
+
"humaneval": 1024,
|
| 16 |
+
"tools": 512,
|
| 17 |
+
"vqa": 64
|
| 18 |
+
}
|
| 19 |
+
},
|
| 20 |
+
"concurrency": 16,
|
| 21 |
+
"limit": null,
|
| 22 |
+
"host": "tux",
|
| 23 |
+
"data_sha256": {
|
| 24 |
+
"ifeval": "3e9e9e7bd42ef54862f0c71c9a4e6f0b17a9c259f8f4b2b4e5fbcad917228118",
|
| 25 |
+
"gsm8k": "5bb91d328c1ffc424d6679fe8edb36ed08152e4c75e75b343303e15cacc2da49",
|
| 26 |
+
"mmlu_pro": "e9d8d5717def43a0b995710ab093a13de48b4cfb4db19cd7c66affacfb492ea7",
|
| 27 |
+
"humaneval": "1e775e30085b890c19c48a583bfabb8f5f54598b5bf54796839b92e5bafdab9f",
|
| 28 |
+
"tools": "037b2e288f4f063e8a2d994799b4a51e4d97740b1cf62da75844243749dbb08a",
|
| 29 |
+
"vqa": "7d47303ecdf3386d04a852ab8b7e8be8d34137a1c4d10143331cc7175ce80d9d"
|
| 30 |
+
},
|
| 31 |
+
"tasks": {
|
| 32 |
+
"gsm8k": {
|
| 33 |
+
"n": 80,
|
| 34 |
+
"correct": 74,
|
| 35 |
+
"accuracy": 0.925,
|
| 36 |
+
"wilson95": [
|
| 37 |
+
0.8458798383979047,
|
| 38 |
+
0.9651747509106547
|
| 39 |
+
],
|
| 40 |
+
"n_errors": 0,
|
| 41 |
+
"n_truncated": 1,
|
| 42 |
+
"mean_completion_tokens": 186.425,
|
| 43 |
+
"sum_completion_tokens": 14914,
|
| 44 |
+
"wall_s": 138.4
|
| 45 |
+
},
|
| 46 |
+
"humaneval": {
|
| 47 |
+
"n": 40,
|
| 48 |
+
"correct": 32,
|
| 49 |
+
"accuracy": 0.8,
|
| 50 |
+
"wilson95": [
|
| 51 |
+
0.6524269352437855,
|
| 52 |
+
0.8950001032811363
|
| 53 |
+
],
|
| 54 |
+
"n_errors": 0,
|
| 55 |
+
"n_truncated": 0,
|
| 56 |
+
"mean_completion_tokens": 230.5,
|
| 57 |
+
"sum_completion_tokens": 9220,
|
| 58 |
+
"wall_s": 94.4
|
| 59 |
+
},
|
| 60 |
+
"tools": {
|
| 61 |
+
"n": 20,
|
| 62 |
+
"correct": 19,
|
| 63 |
+
"accuracy": 0.95,
|
| 64 |
+
"wilson95": [
|
| 65 |
+
0.7638688045357189,
|
| 66 |
+
0.9911185512976646
|
| 67 |
+
],
|
| 68 |
+
"n_errors": 0,
|
| 69 |
+
"n_truncated": 0,
|
| 70 |
+
"mean_completion_tokens": 64.9,
|
| 71 |
+
"sum_completion_tokens": 1298,
|
| 72 |
+
"names_correct": 0.95,
|
| 73 |
+
"parse_source_counts": {
|
| 74 |
+
"server": 16,
|
| 75 |
+
"none": 4
|
| 76 |
+
},
|
| 77 |
+
"format_well_formed": 1.0,
|
| 78 |
+
"raw_tool_call_tags_in_content": 0,
|
| 79 |
+
"by_category": {
|
| 80 |
+
"irrelevance": "3/3",
|
| 81 |
+
"multiple": "6/6",
|
| 82 |
+
"parallel": "3/3",
|
| 83 |
+
"simple": "7/8"
|
| 84 |
+
},
|
| 85 |
+
"wall_s": 24.8
|
| 86 |
+
}
|
| 87 |
+
},
|
| 88 |
+
"server_models": {
|
| 89 |
+
"object": "list",
|
| 90 |
+
"data": [
|
| 91 |
+
{
|
| 92 |
+
"id": "sensenova-loop-bf16",
|
| 93 |
+
"object": "model",
|
| 94 |
+
"created": 1793402905,
|
| 95 |
+
"owned_by": "sglang",
|
| 96 |
+
"root": "sensenova-loop-bf16",
|
| 97 |
+
"parent": null,
|
| 98 |
+
"max_model_len": 32768
|
| 99 |
+
}
|
| 100 |
+
]
|
| 101 |
+
},
|
| 102 |
+
"wall_s": 257.7
|
| 103 |
+
}
|
evaluation/summary_sglang_nvfp4_v1.json
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"eval_version": "sn-loop-eval-v1",
|
| 3 |
+
"model": "sensenova-loop-nvfp4",
|
| 4 |
+
"base_url": "http://127.0.0.1:30080/v1",
|
| 5 |
+
"started": "2026-10-30T16:45:48-0700",
|
| 6 |
+
"enable_thinking": false,
|
| 7 |
+
"sampling": {
|
| 8 |
+
"temperature": 0.0,
|
| 9 |
+
"top_p": 1.0,
|
| 10 |
+
"seed": 0,
|
| 11 |
+
"max_tokens": {
|
| 12 |
+
"ifeval": 1024,
|
| 13 |
+
"gsm8k": 1024,
|
| 14 |
+
"mmlu_pro": 1024,
|
| 15 |
+
"humaneval": 1024,
|
| 16 |
+
"tools": 512,
|
| 17 |
+
"vqa": 64
|
| 18 |
+
}
|
| 19 |
+
},
|
| 20 |
+
"concurrency": 16,
|
| 21 |
+
"limit": null,
|
| 22 |
+
"host": "tux",
|
| 23 |
+
"data_sha256": {
|
| 24 |
+
"ifeval": "3e9e9e7bd42ef54862f0c71c9a4e6f0b17a9c259f8f4b2b4e5fbcad917228118",
|
| 25 |
+
"gsm8k": "5bb91d328c1ffc424d6679fe8edb36ed08152e4c75e75b343303e15cacc2da49",
|
| 26 |
+
"mmlu_pro": "e9d8d5717def43a0b995710ab093a13de48b4cfb4db19cd7c66affacfb492ea7",
|
| 27 |
+
"humaneval": "1e775e30085b890c19c48a583bfabb8f5f54598b5bf54796839b92e5bafdab9f",
|
| 28 |
+
"tools": "037b2e288f4f063e8a2d994799b4a51e4d97740b1cf62da75844243749dbb08a",
|
| 29 |
+
"vqa": "7d47303ecdf3386d04a852ab8b7e8be8d34137a1c4d10143331cc7175ce80d9d"
|
| 30 |
+
},
|
| 31 |
+
"tasks": {
|
| 32 |
+
"ifeval": {
|
| 33 |
+
"n": 60,
|
| 34 |
+
"correct": 45,
|
| 35 |
+
"accuracy": 0.75,
|
| 36 |
+
"wilson95": [
|
| 37 |
+
0.6276792981955739,
|
| 38 |
+
0.8422347752873125
|
| 39 |
+
],
|
| 40 |
+
"n_errors": 0,
|
| 41 |
+
"n_truncated": 4,
|
| 42 |
+
"mean_completion_tokens": 272.6666666666667,
|
| 43 |
+
"sum_completion_tokens": 16360,
|
| 44 |
+
"instruction_level_acc": 0.7831325301204819,
|
| 45 |
+
"n_instructions": 83,
|
| 46 |
+
"wall_s": 196.0
|
| 47 |
+
},
|
| 48 |
+
"gsm8k": {
|
| 49 |
+
"n": 80,
|
| 50 |
+
"correct": 76,
|
| 51 |
+
"accuracy": 0.95,
|
| 52 |
+
"wilson95": [
|
| 53 |
+
0.8783772371965909,
|
| 54 |
+
0.9803864456007073
|
| 55 |
+
],
|
| 56 |
+
"n_errors": 0,
|
| 57 |
+
"n_truncated": 1,
|
| 58 |
+
"mean_completion_tokens": 187.2,
|
| 59 |
+
"sum_completion_tokens": 14976,
|
| 60 |
+
"wall_s": 156.1
|
| 61 |
+
},
|
| 62 |
+
"mmlu_pro": {
|
| 63 |
+
"n": 60,
|
| 64 |
+
"correct": 41,
|
| 65 |
+
"accuracy": 0.6833333333333333,
|
| 66 |
+
"wilson95": [
|
| 67 |
+
0.5576623287169538,
|
| 68 |
+
0.7869413251704964
|
| 69 |
+
],
|
| 70 |
+
"n_errors": 0,
|
| 71 |
+
"n_truncated": 9,
|
| 72 |
+
"mean_completion_tokens": 588.55,
|
| 73 |
+
"sum_completion_tokens": 35313,
|
| 74 |
+
"wall_s": 352.6
|
| 75 |
+
},
|
| 76 |
+
"humaneval": {
|
| 77 |
+
"n": 40,
|
| 78 |
+
"correct": 32,
|
| 79 |
+
"accuracy": 0.8,
|
| 80 |
+
"wilson95": [
|
| 81 |
+
0.6524269352437855,
|
| 82 |
+
0.8950001032811363
|
| 83 |
+
],
|
| 84 |
+
"n_errors": 0,
|
| 85 |
+
"n_truncated": 0,
|
| 86 |
+
"mean_completion_tokens": 197.975,
|
| 87 |
+
"sum_completion_tokens": 7919,
|
| 88 |
+
"wall_s": 79.5
|
| 89 |
+
},
|
| 90 |
+
"tools": {
|
| 91 |
+
"n": 20,
|
| 92 |
+
"correct": 19,
|
| 93 |
+
"accuracy": 0.95,
|
| 94 |
+
"wilson95": [
|
| 95 |
+
0.7638688045357189,
|
| 96 |
+
0.9911185512976646
|
| 97 |
+
],
|
| 98 |
+
"n_errors": 0,
|
| 99 |
+
"n_truncated": 0,
|
| 100 |
+
"mean_completion_tokens": 54.3,
|
| 101 |
+
"sum_completion_tokens": 1086,
|
| 102 |
+
"names_correct": 0.95,
|
| 103 |
+
"parse_source_counts": {
|
| 104 |
+
"server": 16,
|
| 105 |
+
"none": 4
|
| 106 |
+
},
|
| 107 |
+
"format_well_formed": 1.0,
|
| 108 |
+
"raw_tool_call_tags_in_content": 0,
|
| 109 |
+
"by_category": {
|
| 110 |
+
"irrelevance": "3/3",
|
| 111 |
+
"multiple": "5/6",
|
| 112 |
+
"parallel": "3/3",
|
| 113 |
+
"simple": "8/8"
|
| 114 |
+
},
|
| 115 |
+
"wall_s": 24.6
|
| 116 |
+
},
|
| 117 |
+
"vqa": {
|
| 118 |
+
"n": 40,
|
| 119 |
+
"correct": 36,
|
| 120 |
+
"accuracy": 0.9,
|
| 121 |
+
"wilson95": [
|
| 122 |
+
0.7694822464406407,
|
| 123 |
+
0.9604204715925885
|
| 124 |
+
],
|
| 125 |
+
"n_errors": 0,
|
| 126 |
+
"n_truncated": 0,
|
| 127 |
+
"mean_completion_tokens": 4.075,
|
| 128 |
+
"sum_completion_tokens": 163,
|
| 129 |
+
"vqa_soft_acc": 0.8833333333333334,
|
| 130 |
+
"wall_s": 25.5
|
| 131 |
+
}
|
| 132 |
+
},
|
| 133 |
+
"server_models": {
|
| 134 |
+
"object": "list",
|
| 135 |
+
"data": [
|
| 136 |
+
{
|
| 137 |
+
"id": "sensenova-loop-nvfp4",
|
| 138 |
+
"object": "model",
|
| 139 |
+
"created": 1793403948,
|
| 140 |
+
"owned_by": "sglang",
|
| 141 |
+
"root": "sensenova-loop-nvfp4",
|
| 142 |
+
"parent": null,
|
| 143 |
+
"max_model_len": 32768
|
| 144 |
+
}
|
| 145 |
+
]
|
| 146 |
+
},
|
| 147 |
+
"wall_s": 834.3
|
| 148 |
+
}
|
evaluation/summary_sglang_nvfp4_v1_marlin_w4a16_gsm8k.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"eval_version": "sn-loop-eval-v1",
|
| 3 |
+
"model": "sensenova-loop-nvfp4",
|
| 4 |
+
"base_url": "http://127.0.0.1:30080/v1",
|
| 5 |
+
"started": "2026-10-30T17:38:10-0700",
|
| 6 |
+
"enable_thinking": false,
|
| 7 |
+
"sampling": {
|
| 8 |
+
"temperature": 0.0,
|
| 9 |
+
"top_p": 1.0,
|
| 10 |
+
"seed": 0,
|
| 11 |
+
"max_tokens": {
|
| 12 |
+
"ifeval": 1024,
|
| 13 |
+
"gsm8k": 1024,
|
| 14 |
+
"mmlu_pro": 1024,
|
| 15 |
+
"humaneval": 1024,
|
| 16 |
+
"tools": 512,
|
| 17 |
+
"vqa": 64
|
| 18 |
+
}
|
| 19 |
+
},
|
| 20 |
+
"concurrency": 16,
|
| 21 |
+
"limit": null,
|
| 22 |
+
"host": "tux",
|
| 23 |
+
"data_sha256": {
|
| 24 |
+
"ifeval": "3e9e9e7bd42ef54862f0c71c9a4e6f0b17a9c259f8f4b2b4e5fbcad917228118",
|
| 25 |
+
"gsm8k": "5bb91d328c1ffc424d6679fe8edb36ed08152e4c75e75b343303e15cacc2da49",
|
| 26 |
+
"mmlu_pro": "e9d8d5717def43a0b995710ab093a13de48b4cfb4db19cd7c66affacfb492ea7",
|
| 27 |
+
"humaneval": "1e775e30085b890c19c48a583bfabb8f5f54598b5bf54796839b92e5bafdab9f",
|
| 28 |
+
"tools": "037b2e288f4f063e8a2d994799b4a51e4d97740b1cf62da75844243749dbb08a",
|
| 29 |
+
"vqa": "7d47303ecdf3386d04a852ab8b7e8be8d34137a1c4d10143331cc7175ce80d9d"
|
| 30 |
+
},
|
| 31 |
+
"tasks": {
|
| 32 |
+
"gsm8k": {
|
| 33 |
+
"n": 80,
|
| 34 |
+
"correct": 77,
|
| 35 |
+
"accuracy": 0.9625,
|
| 36 |
+
"wilson95": [
|
| 37 |
+
0.8954527983617241,
|
| 38 |
+
0.9871654311799435
|
| 39 |
+
],
|
| 40 |
+
"n_errors": 0,
|
| 41 |
+
"n_truncated": 0,
|
| 42 |
+
"mean_completion_tokens": 184.425,
|
| 43 |
+
"sum_completion_tokens": 14754,
|
| 44 |
+
"wall_s": 137.2
|
| 45 |
+
}
|
| 46 |
+
},
|
| 47 |
+
"server_models": {
|
| 48 |
+
"object": "list",
|
| 49 |
+
"data": [
|
| 50 |
+
{
|
| 51 |
+
"id": "sensenova-loop-nvfp4",
|
| 52 |
+
"object": "model",
|
| 53 |
+
"created": 1793407090,
|
| 54 |
+
"owned_by": "sglang",
|
| 55 |
+
"root": "sensenova-loop-nvfp4",
|
| 56 |
+
"parent": null,
|
| 57 |
+
"max_model_len": 32768
|
| 58 |
+
}
|
| 59 |
+
]
|
| 60 |
+
},
|
| 61 |
+
"wall_s": 137.2
|
| 62 |
+
}
|
evaluation/summary_sglang_nvfp4_v1_mtp.json
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"eval_version": "sn-loop-eval-v1",
|
| 3 |
+
"model": "sensenova-loop-nvfp4",
|
| 4 |
+
"base_url": "http://127.0.0.1:30080/v1",
|
| 5 |
+
"started": "2026-10-30T17:17:37-0700",
|
| 6 |
+
"enable_thinking": false,
|
| 7 |
+
"sampling": {
|
| 8 |
+
"temperature": 0.0,
|
| 9 |
+
"top_p": 1.0,
|
| 10 |
+
"seed": 0,
|
| 11 |
+
"max_tokens": {
|
| 12 |
+
"ifeval": 1024,
|
| 13 |
+
"gsm8k": 1024,
|
| 14 |
+
"mmlu_pro": 1024,
|
| 15 |
+
"humaneval": 1024,
|
| 16 |
+
"tools": 512,
|
| 17 |
+
"vqa": 64
|
| 18 |
+
}
|
| 19 |
+
},
|
| 20 |
+
"concurrency": 16,
|
| 21 |
+
"limit": null,
|
| 22 |
+
"host": "tux",
|
| 23 |
+
"data_sha256": {
|
| 24 |
+
"ifeval": "3e9e9e7bd42ef54862f0c71c9a4e6f0b17a9c259f8f4b2b4e5fbcad917228118",
|
| 25 |
+
"gsm8k": "5bb91d328c1ffc424d6679fe8edb36ed08152e4c75e75b343303e15cacc2da49",
|
| 26 |
+
"mmlu_pro": "e9d8d5717def43a0b995710ab093a13de48b4cfb4db19cd7c66affacfb492ea7",
|
| 27 |
+
"humaneval": "1e775e30085b890c19c48a583bfabb8f5f54598b5bf54796839b92e5bafdab9f",
|
| 28 |
+
"tools": "037b2e288f4f063e8a2d994799b4a51e4d97740b1cf62da75844243749dbb08a",
|
| 29 |
+
"vqa": "7d47303ecdf3386d04a852ab8b7e8be8d34137a1c4d10143331cc7175ce80d9d"
|
| 30 |
+
},
|
| 31 |
+
"tasks": {
|
| 32 |
+
"gsm8k": {
|
| 33 |
+
"n": 80,
|
| 34 |
+
"correct": 77,
|
| 35 |
+
"accuracy": 0.9625,
|
| 36 |
+
"wilson95": [
|
| 37 |
+
0.8954527983617241,
|
| 38 |
+
0.9871654311799435
|
| 39 |
+
],
|
| 40 |
+
"n_errors": 0,
|
| 41 |
+
"n_truncated": 1,
|
| 42 |
+
"mean_completion_tokens": 190.3875,
|
| 43 |
+
"sum_completion_tokens": 15231,
|
| 44 |
+
"wall_s": 94.6
|
| 45 |
+
},
|
| 46 |
+
"humaneval": {
|
| 47 |
+
"n": 40,
|
| 48 |
+
"correct": 32,
|
| 49 |
+
"accuracy": 0.8,
|
| 50 |
+
"wilson95": [
|
| 51 |
+
0.6524269352437855,
|
| 52 |
+
0.8950001032811363
|
| 53 |
+
],
|
| 54 |
+
"n_errors": 0,
|
| 55 |
+
"n_truncated": 0,
|
| 56 |
+
"mean_completion_tokens": 191.3,
|
| 57 |
+
"sum_completion_tokens": 7652,
|
| 58 |
+
"wall_s": 46.1
|
| 59 |
+
},
|
| 60 |
+
"tools": {
|
| 61 |
+
"n": 20,
|
| 62 |
+
"correct": 18,
|
| 63 |
+
"accuracy": 0.9,
|
| 64 |
+
"wilson95": [
|
| 65 |
+
0.6989663528135878,
|
| 66 |
+
0.9721335190383086
|
| 67 |
+
],
|
| 68 |
+
"n_errors": 0,
|
| 69 |
+
"n_truncated": 0,
|
| 70 |
+
"mean_completion_tokens": 60.2,
|
| 71 |
+
"sum_completion_tokens": 1204,
|
| 72 |
+
"names_correct": 0.9,
|
| 73 |
+
"parse_source_counts": {
|
| 74 |
+
"server": 15,
|
| 75 |
+
"none": 5
|
| 76 |
+
},
|
| 77 |
+
"format_well_formed": 1.0,
|
| 78 |
+
"raw_tool_call_tags_in_content": 0,
|
| 79 |
+
"by_category": {
|
| 80 |
+
"irrelevance": "3/3",
|
| 81 |
+
"multiple": "5/6",
|
| 82 |
+
"parallel": "3/3",
|
| 83 |
+
"simple": "7/8"
|
| 84 |
+
},
|
| 85 |
+
"wall_s": 16.6
|
| 86 |
+
}
|
| 87 |
+
},
|
| 88 |
+
"server_models": {
|
| 89 |
+
"object": "list",
|
| 90 |
+
"data": [
|
| 91 |
+
{
|
| 92 |
+
"id": "sensenova-loop-nvfp4",
|
| 93 |
+
"object": "model",
|
| 94 |
+
"created": 1793405857,
|
| 95 |
+
"owned_by": "sglang",
|
| 96 |
+
"root": "sensenova-loop-nvfp4",
|
| 97 |
+
"parent": null,
|
| 98 |
+
"max_model_len": 32768
|
| 99 |
+
}
|
| 100 |
+
]
|
| 101 |
+
},
|
| 102 |
+
"wall_s": 157.4
|
| 103 |
+
}
|
generation_config.json
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_from_model_config": true,
|
| 3 |
+
"eos_token_id": [
|
| 4 |
+
248044,
|
| 5 |
+
248046
|
| 6 |
+
],
|
| 7 |
+
"transformers_version": "5.18.0",
|
| 8 |
+
"use_cache": true,
|
| 9 |
+
"temperature": 1.0,
|
| 10 |
+
"do_sample": true,
|
| 11 |
+
"top_p": 0.95
|
| 12 |
+
}
|
hf_quant_config.json
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"producer": {
|
| 3 |
+
"name": "modelopt",
|
| 4 |
+
"version": "0.48.0rc1"
|
| 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.language_model.embed_tokens",
|
| 13 |
+
"model.language_model.layers.0.linear_attn.conv1d",
|
| 14 |
+
"model.language_model.layers.0.linear_attn.in_proj_a",
|
| 15 |
+
"model.language_model.layers.0.linear_attn.in_proj_b",
|
| 16 |
+
"model.language_model.layers.1.linear_attn.conv1d",
|
| 17 |
+
"model.language_model.layers.1.linear_attn.in_proj_a",
|
| 18 |
+
"model.language_model.layers.1.linear_attn.in_proj_b",
|
| 19 |
+
"model.language_model.layers.10.linear_attn.conv1d",
|
| 20 |
+
"model.language_model.layers.10.linear_attn.in_proj_a",
|
| 21 |
+
"model.language_model.layers.10.linear_attn.in_proj_b",
|
| 22 |
+
"model.language_model.layers.12.linear_attn.conv1d",
|
| 23 |
+
"model.language_model.layers.12.linear_attn.in_proj_a",
|
| 24 |
+
"model.language_model.layers.12.linear_attn.in_proj_b",
|
| 25 |
+
"model.language_model.layers.13.linear_attn.conv1d",
|
| 26 |
+
"model.language_model.layers.13.linear_attn.in_proj_a",
|
| 27 |
+
"model.language_model.layers.13.linear_attn.in_proj_b",
|
| 28 |
+
"model.language_model.layers.14.linear_attn.conv1d",
|
| 29 |
+
"model.language_model.layers.14.linear_attn.in_proj_a",
|
| 30 |
+
"model.language_model.layers.14.linear_attn.in_proj_b",
|
| 31 |
+
"model.language_model.layers.16.linear_attn.conv1d",
|
| 32 |
+
"model.language_model.layers.16.linear_attn.in_proj_a",
|
| 33 |
+
"model.language_model.layers.16.linear_attn.in_proj_b",
|
| 34 |
+
"model.language_model.layers.17.linear_attn.conv1d",
|
| 35 |
+
"model.language_model.layers.17.linear_attn.in_proj_a",
|
| 36 |
+
"model.language_model.layers.17.linear_attn.in_proj_b",
|
| 37 |
+
"model.language_model.layers.18.linear_attn.conv1d",
|
| 38 |
+
"model.language_model.layers.18.linear_attn.in_proj_a",
|
| 39 |
+
"model.language_model.layers.18.linear_attn.in_proj_b",
|
| 40 |
+
"model.language_model.layers.2.linear_attn.conv1d",
|
| 41 |
+
"model.language_model.layers.2.linear_attn.in_proj_a",
|
| 42 |
+
"model.language_model.layers.2.linear_attn.in_proj_b",
|
| 43 |
+
"model.language_model.layers.20.linear_attn.conv1d",
|
| 44 |
+
"model.language_model.layers.20.linear_attn.in_proj_a",
|
| 45 |
+
"model.language_model.layers.20.linear_attn.in_proj_b",
|
| 46 |
+
"model.language_model.layers.21.linear_attn.conv1d",
|
| 47 |
+
"model.language_model.layers.21.linear_attn.in_proj_a",
|
| 48 |
+
"model.language_model.layers.21.linear_attn.in_proj_b",
|
| 49 |
+
"model.language_model.layers.22.linear_attn.conv1d",
|
| 50 |
+
"model.language_model.layers.22.linear_attn.in_proj_a",
|
| 51 |
+
"model.language_model.layers.22.linear_attn.in_proj_b",
|
| 52 |
+
"model.language_model.layers.24.linear_attn.conv1d",
|
| 53 |
+
"model.language_model.layers.24.linear_attn.in_proj_a",
|
| 54 |
+
"model.language_model.layers.24.linear_attn.in_proj_b",
|
| 55 |
+
"model.language_model.layers.25.linear_attn.conv1d",
|
| 56 |
+
"model.language_model.layers.25.linear_attn.in_proj_a",
|
| 57 |
+
"model.language_model.layers.25.linear_attn.in_proj_b",
|
| 58 |
+
"model.language_model.layers.26.linear_attn.conv1d",
|
| 59 |
+
"model.language_model.layers.26.linear_attn.in_proj_a",
|
| 60 |
+
"model.language_model.layers.26.linear_attn.in_proj_b",
|
| 61 |
+
"model.language_model.layers.28.linear_attn.conv1d",
|
| 62 |
+
"model.language_model.layers.28.linear_attn.in_proj_a",
|
| 63 |
+
"model.language_model.layers.28.linear_attn.in_proj_b",
|
| 64 |
+
"model.language_model.layers.29.linear_attn.conv1d",
|
| 65 |
+
"model.language_model.layers.29.linear_attn.in_proj_a",
|
| 66 |
+
"model.language_model.layers.29.linear_attn.in_proj_b",
|
| 67 |
+
"model.language_model.layers.30.linear_attn.conv1d",
|
| 68 |
+
"model.language_model.layers.30.linear_attn.in_proj_a",
|
| 69 |
+
"model.language_model.layers.30.linear_attn.in_proj_b",
|
| 70 |
+
"model.language_model.layers.4.linear_attn.conv1d",
|
| 71 |
+
"model.language_model.layers.4.linear_attn.in_proj_a",
|
| 72 |
+
"model.language_model.layers.4.linear_attn.in_proj_b",
|
| 73 |
+
"model.language_model.layers.5.linear_attn.conv1d",
|
| 74 |
+
"model.language_model.layers.5.linear_attn.in_proj_a",
|
| 75 |
+
"model.language_model.layers.5.linear_attn.in_proj_b",
|
| 76 |
+
"model.language_model.layers.6.linear_attn.conv1d",
|
| 77 |
+
"model.language_model.layers.6.linear_attn.in_proj_a",
|
| 78 |
+
"model.language_model.layers.6.linear_attn.in_proj_b",
|
| 79 |
+
"model.language_model.layers.8.linear_attn.conv1d",
|
| 80 |
+
"model.language_model.layers.8.linear_attn.in_proj_a",
|
| 81 |
+
"model.language_model.layers.8.linear_attn.in_proj_b",
|
| 82 |
+
"model.language_model.layers.9.linear_attn.conv1d",
|
| 83 |
+
"model.language_model.layers.9.linear_attn.in_proj_a",
|
| 84 |
+
"model.language_model.layers.9.linear_attn.in_proj_b",
|
| 85 |
+
"model.visual*",
|
| 86 |
+
"mtp.fc",
|
| 87 |
+
"mtp.layers.0.input_layernorm",
|
| 88 |
+
"mtp.layers.0.mlp.down_proj",
|
| 89 |
+
"mtp.layers.0.mlp.gate_proj",
|
| 90 |
+
"mtp.layers.0.mlp.up_proj",
|
| 91 |
+
"mtp.layers.0.post_attention_layernorm",
|
| 92 |
+
"mtp.layers.0.self_attn.k_norm",
|
| 93 |
+
"mtp.layers.0.self_attn.k_proj",
|
| 94 |
+
"mtp.layers.0.self_attn.o_proj",
|
| 95 |
+
"mtp.layers.0.self_attn.q_norm",
|
| 96 |
+
"mtp.layers.0.self_attn.q_proj",
|
| 97 |
+
"mtp.layers.0.self_attn.v_proj",
|
| 98 |
+
"mtp.norm",
|
| 99 |
+
"mtp.pre_fc_norm_embedding",
|
| 100 |
+
"mtp.pre_fc_norm_hidden"
|
| 101 |
+
]
|
| 102 |
+
}
|
| 103 |
+
}
|
model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:1e420ea69111b7bb3c7c529cdbbb4ff4e6ebb531c0cd2be5c634cd88cd40eaca
|
| 3 |
+
size 9382671592
|
modeling_sensenova_loop.py
ADDED
|
@@ -0,0 +1,395 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Hugging Face remote-code support for shared-weight SenseNova Loop and MHC.
|
| 2 |
+
|
| 3 |
+
This single file contains configuration, plan validation, MHC routing and the
|
| 4 |
+
model implementation. The original physical layer weights are reused on every
|
| 5 |
+
Loop visit; autoregressive cache states are independent per visit.
|
| 6 |
+
"""
|
| 7 |
+
import copy
|
| 8 |
+
import math
|
| 9 |
+
from contextvars import ContextVar
|
| 10 |
+
|
| 11 |
+
import torch
|
| 12 |
+
from torch import nn
|
| 13 |
+
from transformers import Qwen3_5Config
|
| 14 |
+
from transformers.cache_utils import DynamicCache
|
| 15 |
+
from transformers.models.qwen3_5 import modeling_qwen3_5 as hf
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
_attention_capture = ContextVar("sensenova_attention_capture", default=None)
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
class SenseNovaLoopConfig(Qwen3_5Config):
|
| 22 |
+
model_type = "sensenova_loop"
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
def execution_plan(config):
|
| 26 |
+
"""Return physical layer indices in the order they execute during inference."""
|
| 27 |
+
loop = config.get("loop_settings")
|
| 28 |
+
if not isinstance(loop, dict):
|
| 29 |
+
raise ValueError("This implementation requires explicit loop_settings")
|
| 30 |
+
|
| 31 |
+
text_config = config["text_config"]
|
| 32 |
+
num_layers = text_config["num_hidden_layers"]
|
| 33 |
+
start, end, count = loop.get("start"), loop.get("end"), loop.get("eval_count")
|
| 34 |
+
if any(type(value) is not int for value in (num_layers, start, end, count)) or not (
|
| 35 |
+
0 <= start < end <= num_layers and count >= 1
|
| 36 |
+
):
|
| 37 |
+
raise ValueError("Invalid Loop interval or eval_count")
|
| 38 |
+
if loop.get("counts") != [count]:
|
| 39 |
+
raise ValueError("Only fixed-count Loop checkpoints are supported")
|
| 40 |
+
|
| 41 |
+
layer_types = text_config["layer_types"]
|
| 42 |
+
if len(layer_types) != num_layers or set(layer_types) - {"full_attention", "linear_attention"}:
|
| 43 |
+
raise ValueError("Unexpected physical layer types")
|
| 44 |
+
if "full_attention" not in layer_types:
|
| 45 |
+
raise ValueError("At least one full-attention layer is required for sequence-length tracking")
|
| 46 |
+
|
| 47 |
+
mhc = config.get("mhc")
|
| 48 |
+
if mhc is not None:
|
| 49 |
+
mhc_start, mhc_end, streams, iterations = (
|
| 50 |
+
mhc.get(key) for key in ("start", "end", "streams", "iterations")
|
| 51 |
+
)
|
| 52 |
+
if (
|
| 53 |
+
any(type(value) is not int for value in (mhc_start, mhc_end, streams, iterations))
|
| 54 |
+
or not 0 <= mhc_start < mhc_end <= num_layers
|
| 55 |
+
or streams not in (2, 4)
|
| 56 |
+
or iterations < 1
|
| 57 |
+
):
|
| 58 |
+
raise ValueError("Invalid MHC range, stream count, or iterations")
|
| 59 |
+
if type(mhc.get("fixed_identity")) is not bool:
|
| 60 |
+
raise ValueError("MHC fixed_identity must be a boolean")
|
| 61 |
+
scale = mhc.get("pre_scale", 1.0)
|
| 62 |
+
if not isinstance(scale, (int, float)) or not math.isfinite(scale) or scale <= 0:
|
| 63 |
+
raise ValueError("Invalid MHC pre_scale")
|
| 64 |
+
allowed = {"start", "end", "streams", "iterations", "fixed_identity", "pre_scale"}
|
| 65 |
+
if set(mhc) - allowed:
|
| 66 |
+
raise ValueError("Unknown MHC configuration fields")
|
| 67 |
+
phase_boundaries = (0, start, end, num_layers)
|
| 68 |
+
if not any(
|
| 69 |
+
left <= mhc_start < mhc_end <= right
|
| 70 |
+
for left, right in zip(phase_boundaries, phase_boundaries[1:])
|
| 71 |
+
):
|
| 72 |
+
raise ValueError("MHC cannot cross a Loop phase boundary")
|
| 73 |
+
|
| 74 |
+
return tuple(range(start)) + tuple(range(start, end)) * count + tuple(range(end, num_layers))
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
def sinkhorn(logits, iterations):
|
| 78 |
+
"""Normalize routing logits across rows and columns in log space."""
|
| 79 |
+
logits = logits.float()
|
| 80 |
+
for _ in range(iterations):
|
| 81 |
+
logits = logits - torch.logsumexp(logits, dim=-1, keepdim=True)
|
| 82 |
+
logits = logits - torch.logsumexp(logits, dim=-2, keepdim=True)
|
| 83 |
+
return logits.exp()
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
class MHCRouter(nn.Module):
|
| 87 |
+
def __init__(self, dim, settings):
|
| 88 |
+
super().__init__()
|
| 89 |
+
self.streams = settings["streams"]
|
| 90 |
+
self.iterations = settings["iterations"]
|
| 91 |
+
self.fixed_identity = settings["fixed_identity"]
|
| 92 |
+
self.pre_scale = settings.get("pre_scale", 1.0)
|
| 93 |
+
streams = self.streams
|
| 94 |
+
output_size = 2 * streams + (0 if self.fixed_identity else streams * streams)
|
| 95 |
+
self.weight = nn.Parameter(torch.zeros(output_size, streams * dim, dtype=torch.float32))
|
| 96 |
+
self.bias = nn.Parameter(torch.zeros(output_size, dtype=torch.float32))
|
| 97 |
+
with torch.no_grad():
|
| 98 |
+
initial_probabilities = {2: (0.25, 0.75), 4: (0.0625, 0.1875, 0.25, 0.5)}[streams]
|
| 99 |
+
self.bias[:streams].copy_(torch.logit(torch.tensor(initial_probabilities, device=self.bias.device)))
|
| 100 |
+
if not self.fixed_identity:
|
| 101 |
+
diagonal = math.log((1 - (streams - 1) / 16) * 16)
|
| 102 |
+
self.bias[2 * streams:].copy_((torch.eye(streams, device=self.bias.device) * diagonal).flatten())
|
| 103 |
+
|
| 104 |
+
def _apply(self, fn, recurse=True):
|
| 105 |
+
# Keep the original FP32 values when the surrounding model is cast to BF16.
|
| 106 |
+
def keep_fp32(tensor):
|
| 107 |
+
result = fn(tensor)
|
| 108 |
+
if tensor.is_floating_point() and result.dtype != torch.float32:
|
| 109 |
+
if tensor.device.type == "meta" and result.device.type != "meta":
|
| 110 |
+
return torch.empty_like(result, dtype=torch.float32)
|
| 111 |
+
return tensor.to(device=result.device, dtype=torch.float32)
|
| 112 |
+
return result
|
| 113 |
+
|
| 114 |
+
return super()._apply(keep_fp32, recurse=recurse)
|
| 115 |
+
|
| 116 |
+
def forward(self, residual):
|
| 117 |
+
if self.weight.dtype != torch.float32 or self.bias.dtype != torch.float32:
|
| 118 |
+
raise RuntimeError("mHC routers require FP32 parameters; configure FSDP per-module precision")
|
| 119 |
+
with torch.autocast(device_type=residual.device.type, enabled=False):
|
| 120 |
+
flat = residual.flatten(-2).float()
|
| 121 |
+
normalized = flat * torch.rsqrt(flat.square().mean(-1, keepdim=True) + 1e-6)
|
| 122 |
+
logits = torch.nn.functional.linear(normalized, self.weight, self.bias)
|
| 123 |
+
streams = self.streams
|
| 124 |
+
pre = logits[..., :streams].sigmoid()
|
| 125 |
+
post = 2 * logits[..., streams:2 * streams].sigmoid()
|
| 126 |
+
if self.fixed_identity:
|
| 127 |
+
mix = torch.eye(streams, device=flat.device, dtype=torch.float32).expand(
|
| 128 |
+
*flat.shape[:-1], streams, streams
|
| 129 |
+
)
|
| 130 |
+
else:
|
| 131 |
+
mix = sinkhorn(logits[..., 2 * streams:].unflatten(-1, (streams, streams)), self.iterations)
|
| 132 |
+
branch = torch.matmul(pre.to(residual.dtype).unsqueeze(-2), residual).squeeze(-2)
|
| 133 |
+
if self.pre_scale != 1.0:
|
| 134 |
+
branch = branch * self.pre_scale
|
| 135 |
+
return branch, post, mix
|
| 136 |
+
|
| 137 |
+
@staticmethod
|
| 138 |
+
def merge(residual, branch, post, mix):
|
| 139 |
+
"""Mix residual streams and add the branch output to each stream."""
|
| 140 |
+
with torch.autocast(device_type=residual.device.type, enabled=False):
|
| 141 |
+
mixed_residual = torch.matmul(mix.to(residual.dtype), residual)
|
| 142 |
+
branch_update = post.to(branch.dtype).unsqueeze(-1) * branch.unsqueeze(-2)
|
| 143 |
+
return mixed_residual + branch_update
|
| 144 |
+
|
| 145 |
+
|
| 146 |
+
def enter(hidden, physical, settings):
|
| 147 |
+
"""Expand to residual streams at the first mHC layer, or restore their shape."""
|
| 148 |
+
if physical == settings["start"]:
|
| 149 |
+
return hidden.unsqueeze(-2).expand(
|
| 150 |
+
*hidden.shape[:-1], settings["streams"], hidden.shape[-1]
|
| 151 |
+
).contiguous()
|
| 152 |
+
return hidden.unflatten(-1, (settings["streams"], -1))
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
def leave(residual, physical, settings):
|
| 156 |
+
"""Reduce streams at the last mHC layer; otherwise carry them forward."""
|
| 157 |
+
return residual.mean(-2) if physical == settings["end"] - 1 else residual.flatten(-2)
|
| 158 |
+
|
| 159 |
+
|
| 160 |
+
class _CacheLayersView:
|
| 161 |
+
"""Expose the execution slot when a layer accesses its physical index."""
|
| 162 |
+
def __init__(self, cache, physical, virtual):
|
| 163 |
+
self.cache = cache
|
| 164 |
+
self.physical = physical
|
| 165 |
+
self.virtual = virtual
|
| 166 |
+
|
| 167 |
+
def __getitem__(self, index):
|
| 168 |
+
if index != self.physical:
|
| 169 |
+
raise IndexError("A physical layer may only access its own virtual cache slot")
|
| 170 |
+
return self.cache.layers[self.virtual]
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
class _VisitCache:
|
| 174 |
+
"""Map a physical attention module's layer_idx to one execution slot.
|
| 175 |
+
|
| 176 |
+
Mapping is local to this forward call: shared modules and their layer_idx are
|
| 177 |
+
never mutated. `layers` supports Transformers 5.12; state accessors support
|
| 178 |
+
newer official backbone cache APIs as well.
|
| 179 |
+
"""
|
| 180 |
+
def __init__(self, cache, physical, virtual):
|
| 181 |
+
self.cache = cache
|
| 182 |
+
self.virtual = virtual
|
| 183 |
+
self.layers = _CacheLayersView(cache, physical, virtual)
|
| 184 |
+
|
| 185 |
+
def update(self, key_states, value_states, layer_idx, **kwargs):
|
| 186 |
+
return self.cache.update(key_states, value_states, self.virtual, **kwargs)
|
| 187 |
+
|
| 188 |
+
def has_previous_state(self, layer_idx=None, **kwargs):
|
| 189 |
+
return self.cache.has_previous_state(self.virtual, **kwargs)
|
| 190 |
+
|
| 191 |
+
def update_conv_state(self, state, layer_idx, **kwargs):
|
| 192 |
+
return self.cache.update_conv_state(state, self.virtual, **kwargs)
|
| 193 |
+
|
| 194 |
+
def update_recurrent_state(self, state, layer_idx, **kwargs):
|
| 195 |
+
return self.cache.update_recurrent_state(state, self.virtual, **kwargs)
|
| 196 |
+
|
| 197 |
+
def get_conv_state(self, layer_idx, **kwargs):
|
| 198 |
+
return self.cache.get_conv_state(self.virtual, **kwargs)
|
| 199 |
+
|
| 200 |
+
def get_recurrent_state(self, layer_idx, **kwargs):
|
| 201 |
+
return self.cache.get_recurrent_state(self.virtual, **kwargs)
|
| 202 |
+
|
| 203 |
+
def is_recording_past(self, layer_idx):
|
| 204 |
+
return self.cache.is_recording_past(self.virtual)
|
| 205 |
+
|
| 206 |
+
|
| 207 |
+
class SenseNovaLoopTextModel(hf.Qwen3_5TextModel):
|
| 208 |
+
def forward(self, input_ids=None, attention_mask=None, position_ids=None,
|
| 209 |
+
past_key_values=None, inputs_embeds=None, use_cache=None,
|
| 210 |
+
output_hidden_states=None, output_attentions=None, **kwargs):
|
| 211 |
+
"""Run Loop visits, optionally returning their states and attention weights.
|
| 212 |
+
|
| 213 |
+
Hidden states include the initial embedding and one state per visit.
|
| 214 |
+
MHC states between its boundaries retain their flattened residual streams.
|
| 215 |
+
Attention entries follow visit order, with None for linear-attention layers.
|
| 216 |
+
"""
|
| 217 |
+
if (input_ids is None) == (inputs_embeds is None):
|
| 218 |
+
raise ValueError("Specify exactly one of input_ids or inputs_embeds")
|
| 219 |
+
if inputs_embeds is None:
|
| 220 |
+
inputs_embeds = self.embed_tokens(input_ids)
|
| 221 |
+
use_cache = self.config.use_cache if use_cache is None else use_cache
|
| 222 |
+
if output_hidden_states is None:
|
| 223 |
+
output_hidden_states = getattr(self.config, "output_hidden_states", False)
|
| 224 |
+
if output_attentions is None:
|
| 225 |
+
output_attentions = getattr(self.config, "output_attentions", False)
|
| 226 |
+
if not isinstance(output_hidden_states, bool):
|
| 227 |
+
raise TypeError("output_hidden_states must be a boolean.")
|
| 228 |
+
if output_attentions and self.config._attn_implementation != "eager":
|
| 229 |
+
raise ValueError(
|
| 230 |
+
"Attention weights require attn_implementation='eager' when loading the model."
|
| 231 |
+
)
|
| 232 |
+
if self.gradient_checkpointing and self.training and use_cache:
|
| 233 |
+
raise ValueError("Disable use_cache when training with gradient checkpointing")
|
| 234 |
+
if not use_cache and past_key_values is not None:
|
| 235 |
+
raise ValueError("past_key_values requires use_cache=True")
|
| 236 |
+
if past_key_values is not None and not isinstance(past_key_values, DynamicCache):
|
| 237 |
+
raise TypeError("Loop generation currently supports DynamicCache only")
|
| 238 |
+
if use_cache:
|
| 239 |
+
if past_key_values is None:
|
| 240 |
+
past_key_values = DynamicCache(config=self._loop_cache_config)
|
| 241 |
+
past_key_values._loop_execution_plan = self._loop_plan
|
| 242 |
+
elif getattr(past_key_values, "_loop_execution_plan", None) != self._loop_plan:
|
| 243 |
+
# GenerationMixin may allocate an empty physical-depth cache.
|
| 244 |
+
# A populated foreign cache cannot be reinterpreted safely.
|
| 245 |
+
if past_key_values.get_seq_length() != 0 or past_key_values.has_previous_state():
|
| 246 |
+
raise ValueError("A populated cache from another execution plan cannot be reused")
|
| 247 |
+
past_key_values = DynamicCache(config=self._loop_cache_config)
|
| 248 |
+
past_key_values._loop_execution_plan = self._loop_plan
|
| 249 |
+
|
| 250 |
+
if position_ids is None:
|
| 251 |
+
seen = past_key_values.get_seq_length() if past_key_values is not None else 0
|
| 252 |
+
position_ids = torch.arange(inputs_embeds.shape[1], device=inputs_embeds.device) + seen
|
| 253 |
+
position_ids = position_ids.view(1, 1, -1).expand(4, inputs_embeds.shape[0], -1)
|
| 254 |
+
elif position_ids.ndim == 2:
|
| 255 |
+
position_ids = position_ids.unsqueeze(0).expand(4, -1, -1)
|
| 256 |
+
if position_ids.ndim == 3 and position_ids.shape[0] == 4:
|
| 257 |
+
text_positions, position_ids = position_ids[0], position_ids[1:]
|
| 258 |
+
else:
|
| 259 |
+
text_positions = None
|
| 260 |
+
|
| 261 |
+
if isinstance(attention_mask, dict):
|
| 262 |
+
masks = attention_mask
|
| 263 |
+
else:
|
| 264 |
+
mask_args = dict(
|
| 265 |
+
config=self._loop_cache_config,
|
| 266 |
+
inputs_embeds=inputs_embeds,
|
| 267 |
+
attention_mask=attention_mask,
|
| 268 |
+
past_key_values=past_key_values,
|
| 269 |
+
position_ids=text_positions,
|
| 270 |
+
)
|
| 271 |
+
if hasattr(hf, "create_recurrent_attention_mask"):
|
| 272 |
+
linear_mask = hf.create_recurrent_attention_mask(**mask_args)
|
| 273 |
+
else:
|
| 274 |
+
linear_mask = self._update_linear_attn_mask(attention_mask, past_key_values)
|
| 275 |
+
masks = {
|
| 276 |
+
"full_attention": hf.create_causal_mask(**mask_args),
|
| 277 |
+
"linear_attention": linear_mask,
|
| 278 |
+
}
|
| 279 |
+
|
| 280 |
+
hidden = inputs_embeds
|
| 281 |
+
position_embeddings = self.rotary_emb(hidden, position_ids)
|
| 282 |
+
hidden_states = [hidden] if output_hidden_states else None
|
| 283 |
+
attentions = [] if output_attentions else None
|
| 284 |
+
hooks = []
|
| 285 |
+
capture_token = None
|
| 286 |
+
|
| 287 |
+
def record_attention(_module, _inputs, output):
|
| 288 |
+
if _attention_capture.get() is attentions:
|
| 289 |
+
if output[1] is None:
|
| 290 |
+
raise RuntimeError("The attention backend did not return attention weights.")
|
| 291 |
+
attentions.append(output[1])
|
| 292 |
+
|
| 293 |
+
# Repeated visits share weights, but each visit has its own cache slot.
|
| 294 |
+
try:
|
| 295 |
+
if attentions is not None:
|
| 296 |
+
for layer in self.layers:
|
| 297 |
+
if hasattr(layer, "self_attn"):
|
| 298 |
+
hooks.append(layer.self_attn.register_forward_hook(record_attention))
|
| 299 |
+
capture_token = _attention_capture.set(attentions)
|
| 300 |
+
for execution_index, physical_index in enumerate(self._loop_plan):
|
| 301 |
+
layer_type = self.config.layer_types[physical_index]
|
| 302 |
+
if attentions is not None and layer_type == "linear_attention":
|
| 303 |
+
attentions.append(None)
|
| 304 |
+
cache = (
|
| 305 |
+
_VisitCache(past_key_values, physical_index, execution_index)
|
| 306 |
+
if use_cache else None
|
| 307 |
+
)
|
| 308 |
+
hidden = self.layers[physical_index](
|
| 309 |
+
hidden, position_embeddings=position_embeddings,
|
| 310 |
+
attention_mask=masks[layer_type],
|
| 311 |
+
position_ids=text_positions, past_key_values=cache,
|
| 312 |
+
use_cache=use_cache, **kwargs,
|
| 313 |
+
)
|
| 314 |
+
if hidden_states is not None:
|
| 315 |
+
hidden_states.append(hidden)
|
| 316 |
+
finally:
|
| 317 |
+
if capture_token is not None:
|
| 318 |
+
_attention_capture.reset(capture_token)
|
| 319 |
+
for hook in hooks:
|
| 320 |
+
hook.remove()
|
| 321 |
+
|
| 322 |
+
hidden = self.norm(hidden)
|
| 323 |
+
if hidden_states is not None:
|
| 324 |
+
hidden_states[-1] = hidden
|
| 325 |
+
return hf.Qwen3_5ModelOutputWithPast(
|
| 326 |
+
last_hidden_state=hidden, past_key_values=past_key_values,
|
| 327 |
+
hidden_states=tuple(hidden_states) if hidden_states is not None else None,
|
| 328 |
+
attentions=tuple(attentions) if attentions is not None else None,
|
| 329 |
+
)
|
| 330 |
+
|
| 331 |
+
|
| 332 |
+
class MHCDecoderLayer(hf.Qwen3_5DecoderLayer):
|
| 333 |
+
def forward(self, hidden_states, position_embeddings, attention_mask=None,
|
| 334 |
+
position_ids=None, past_key_values=None, **kwargs):
|
| 335 |
+
residual = enter(hidden_states, self._mhc_physical, self._mhc_settings)
|
| 336 |
+
branch, post, mix = self.mhc_attn(residual)
|
| 337 |
+
branch = self.input_layernorm(branch)
|
| 338 |
+
kind = self.layer_type if hasattr(self, "layer_type") else self.block_type
|
| 339 |
+
if kind == "linear_attention":
|
| 340 |
+
branch = self.linear_attn(hidden_states=branch, cache_params=past_key_values,
|
| 341 |
+
attention_mask=attention_mask, **kwargs)
|
| 342 |
+
else:
|
| 343 |
+
branch, _ = self.self_attn(
|
| 344 |
+
hidden_states=branch, position_embeddings=position_embeddings,
|
| 345 |
+
attention_mask=attention_mask, position_ids=position_ids,
|
| 346 |
+
past_key_values=past_key_values, **kwargs)
|
| 347 |
+
residual = MHCRouter.merge(residual, branch, post, mix)
|
| 348 |
+
branch, post, mix = self.mhc_ffn(residual)
|
| 349 |
+
branch = self.mlp(self.post_attention_layernorm(branch))
|
| 350 |
+
return leave(MHCRouter.merge(residual, branch, post, mix),
|
| 351 |
+
self._mhc_physical, self._mhc_settings)
|
| 352 |
+
|
| 353 |
+
|
| 354 |
+
def _configure_text_model(text, config):
|
| 355 |
+
raw = config.to_dict()
|
| 356 |
+
plan = execution_plan(raw)
|
| 357 |
+
# Change only these new model instances, preserving canonical state_dict
|
| 358 |
+
# names and avoiding a second allocation of the full backbone.
|
| 359 |
+
text.__class__ = SenseNovaLoopTextModel
|
| 360 |
+
text._loop_plan = plan
|
| 361 |
+
text._loop_cache_config = copy.deepcopy(text.config)
|
| 362 |
+
text._loop_cache_config.num_hidden_layers = len(plan)
|
| 363 |
+
text._loop_cache_config.layer_types = [text.config.layer_types[i] for i in plan]
|
| 364 |
+
if raw.get("mhc") is not None:
|
| 365 |
+
settings = raw["mhc"]
|
| 366 |
+
for i in range(settings["start"], settings["end"]):
|
| 367 |
+
layer = text.layers[i]
|
| 368 |
+
layer.__class__ = MHCDecoderLayer
|
| 369 |
+
layer._mhc_physical, layer._mhc_settings = i, dict(settings)
|
| 370 |
+
layer.mhc_attn = MHCRouter(text.config.hidden_size, settings)
|
| 371 |
+
layer.mhc_ffn = MHCRouter(text.config.hidden_size, settings)
|
| 372 |
+
|
| 373 |
+
|
| 374 |
+
class SenseNovaLoopModel(hf.Qwen3_5Model):
|
| 375 |
+
config_class = SenseNovaLoopConfig
|
| 376 |
+
_keep_in_fp32_modules = ["mhc_attn", "mhc_ffn"]
|
| 377 |
+
_no_split_modules = ["Qwen3_5DecoderLayer", "MHCDecoderLayer", "Qwen3_5VisionBlock"]
|
| 378 |
+
_keys_to_ignore_on_load_unexpected = [r"^mtp\."]
|
| 379 |
+
|
| 380 |
+
def __init__(self, config):
|
| 381 |
+
execution_plan(config.to_dict())
|
| 382 |
+
super().__init__(config)
|
| 383 |
+
_configure_text_model(self.language_model, config)
|
| 384 |
+
|
| 385 |
+
|
| 386 |
+
class SenseNovaLoopForConditionalGeneration(hf.Qwen3_5ForConditionalGeneration):
|
| 387 |
+
config_class = SenseNovaLoopConfig
|
| 388 |
+
_keep_in_fp32_modules = ["mhc_attn", "mhc_ffn"]
|
| 389 |
+
_no_split_modules = ["Qwen3_5DecoderLayer", "MHCDecoderLayer", "Qwen3_5VisionBlock"]
|
| 390 |
+
_keys_to_ignore_on_load_unexpected = [r"^mtp\."]
|
| 391 |
+
|
| 392 |
+
def __init__(self, config):
|
| 393 |
+
execution_plan(config.to_dict())
|
| 394 |
+
super().__init__(config)
|
| 395 |
+
_configure_text_model(self.model.language_model, config)
|
preprocessor_config.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"do_convert_rgb": true,
|
| 3 |
+
"do_normalize": true,
|
| 4 |
+
"do_rescale": true,
|
| 5 |
+
"do_resize": true,
|
| 6 |
+
"image_mean": [
|
| 7 |
+
0.5,
|
| 8 |
+
0.5,
|
| 9 |
+
0.5
|
| 10 |
+
],
|
| 11 |
+
"image_processor_type": "Qwen2VLImageProcessor",
|
| 12 |
+
"image_std": [
|
| 13 |
+
0.5,
|
| 14 |
+
0.5,
|
| 15 |
+
0.5
|
| 16 |
+
],
|
| 17 |
+
"merge_size": 2,
|
| 18 |
+
"patch_size": 16,
|
| 19 |
+
"resample": 3,
|
| 20 |
+
"rescale_factor": 0.00392156862745098,
|
| 21 |
+
"size": {
|
| 22 |
+
"longest_edge": 16777216,
|
| 23 |
+
"shortest_edge": 65536
|
| 24 |
+
},
|
| 25 |
+
"temporal_patch_size": 2
|
| 26 |
+
}
|
processor_config.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"image_processor": {
|
| 3 |
+
"do_convert_rgb": true,
|
| 4 |
+
"do_normalize": true,
|
| 5 |
+
"do_rescale": true,
|
| 6 |
+
"do_resize": true,
|
| 7 |
+
"image_mean": [
|
| 8 |
+
0.5,
|
| 9 |
+
0.5,
|
| 10 |
+
0.5
|
| 11 |
+
],
|
| 12 |
+
"image_processor_type": "Qwen2VLImageProcessor",
|
| 13 |
+
"image_std": [
|
| 14 |
+
0.5,
|
| 15 |
+
0.5,
|
| 16 |
+
0.5
|
| 17 |
+
],
|
| 18 |
+
"merge_size": 2,
|
| 19 |
+
"patch_size": 16,
|
| 20 |
+
"resample": 3,
|
| 21 |
+
"rescale_factor": 0.00392156862745098,
|
| 22 |
+
"size": {
|
| 23 |
+
"longest_edge": 16777216,
|
| 24 |
+
"shortest_edge": 65536
|
| 25 |
+
},
|
| 26 |
+
"temporal_patch_size": 2
|
| 27 |
+
},
|
| 28 |
+
"processor_class": "Qwen3VLProcessor",
|
| 29 |
+
"video_processor": {
|
| 30 |
+
"do_convert_rgb": true,
|
| 31 |
+
"do_normalize": true,
|
| 32 |
+
"do_rescale": true,
|
| 33 |
+
"do_resize": true,
|
| 34 |
+
"do_sample_frames": true,
|
| 35 |
+
"fps": 2,
|
| 36 |
+
"image_mean": [
|
| 37 |
+
0.5,
|
| 38 |
+
0.5,
|
| 39 |
+
0.5
|
| 40 |
+
],
|
| 41 |
+
"image_std": [
|
| 42 |
+
0.5,
|
| 43 |
+
0.5,
|
| 44 |
+
0.5
|
| 45 |
+
],
|
| 46 |
+
"max_frames": 768,
|
| 47 |
+
"merge_size": 2,
|
| 48 |
+
"min_frames": 4,
|
| 49 |
+
"patch_size": 16,
|
| 50 |
+
"resample": 3,
|
| 51 |
+
"rescale_factor": 0.00392156862745098,
|
| 52 |
+
"return_metadata": false,
|
| 53 |
+
"size": {
|
| 54 |
+
"longest_edge": 25165824,
|
| 55 |
+
"shortest_edge": 4096
|
| 56 |
+
},
|
| 57 |
+
"temporal_patch_size": 2,
|
| 58 |
+
"video_processor_type": "Qwen3VLVideoProcessor"
|
| 59 |
+
}
|
| 60 |
+
}
|
quantization/10_reference_checks.py
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""HF-transformers functional checks for SenseNova-Loop (reference BF16 backbone + FP32 mHC).
|
| 3 |
+
|
| 4 |
+
Checks: mHC router dtype, shared-weight looping, text greedy, thinking, tool-call format,
|
| 5 |
+
image understanding, and cached-vs-uncached decoding consistency (teacher-forced argmax).
|
| 6 |
+
Writes a JSON report; does not modify the model directory.
|
| 7 |
+
|
| 8 |
+
usage: python -I scripts/10_reference_checks.py MODEL_DIR OUT_JSON [IMAGE]
|
| 9 |
+
"""
|
| 10 |
+
import json, sys, time
|
| 11 |
+
import torch
|
| 12 |
+
from PIL import Image
|
| 13 |
+
from transformers import AutoModelForImageTextToText, AutoProcessor
|
| 14 |
+
|
| 15 |
+
model_dir, out_path = sys.argv[1], sys.argv[2]
|
| 16 |
+
image_path = sys.argv[3] if len(sys.argv) > 3 else None
|
| 17 |
+
dev = "cuda:0"
|
| 18 |
+
report = {"model_dir": model_dir, "torch": torch.__version__}
|
| 19 |
+
|
| 20 |
+
t0 = time.time()
|
| 21 |
+
proc = AutoProcessor.from_pretrained(model_dir, trust_remote_code=True)
|
| 22 |
+
model = AutoModelForImageTextToText.from_pretrained(
|
| 23 |
+
model_dir, trust_remote_code=True, dtype=torch.bfloat16, device_map={"": dev}).eval()
|
| 24 |
+
report["load_s"] = round(time.time() - t0, 1)
|
| 25 |
+
report["gpu_mem_after_load_GiB"] = round(torch.cuda.memory_allocated() / 2**30, 2)
|
| 26 |
+
|
| 27 |
+
text = model.model.language_model
|
| 28 |
+
report["loop_plan_len"] = len(text._loop_plan)
|
| 29 |
+
routers = {n: p.dtype for n, p in model.named_parameters() if ".mhc_" in n}
|
| 30 |
+
report["mhc_param_count"] = len(routers)
|
| 31 |
+
report["mhc_all_fp32"] = all(d == torch.float32 for d in routers.values())
|
| 32 |
+
report["layer_param_dtypes"] = sorted({str(p.dtype) for n, p in model.named_parameters() if ".mhc_" not in n})
|
| 33 |
+
|
| 34 |
+
# Each physical looped layer must be called twice per forward (shared weights).
|
| 35 |
+
calls = {}
|
| 36 |
+
hooks = [l.register_forward_hook(lambda m, i, o, k=k: calls.__setitem__(k, calls.get(k, 0) + 1))
|
| 37 |
+
for k, l in enumerate(text.layers)]
|
| 38 |
+
tok = proc.tokenizer
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
def chat(messages, max_new=128, tools=None, thinking=False, images=None):
|
| 42 |
+
prompt = proc.apply_chat_template(messages, tools=tools, tokenize=False, add_generation_prompt=True,
|
| 43 |
+
enable_thinking=thinking)
|
| 44 |
+
inputs = proc(text=[prompt], images=images, return_tensors="pt").to(dev)
|
| 45 |
+
t = time.time()
|
| 46 |
+
with torch.inference_mode():
|
| 47 |
+
out = model.generate(**inputs, max_new_tokens=max_new, do_sample=False, use_cache=True)
|
| 48 |
+
gen = out[0, inputs["input_ids"].shape[1]:]
|
| 49 |
+
return {"prompt_tokens": int(inputs["input_ids"].shape[1]), "gen_tokens": int(gen.shape[0]),
|
| 50 |
+
"seconds": round(time.time() - t, 2), "text": tok.decode(gen, skip_special_tokens=False)}, out, inputs
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
r, _, _ = chat([{"role": "user", "content": "What is 13 times 7? Reply with the number only."}], 16)
|
| 54 |
+
report["text_mult"] = r
|
| 55 |
+
report["loop_calls_per_layer"] = {str(k): v for k, v in sorted(calls.items())}
|
| 56 |
+
report["looped_layers_called_twice"] = all(calls[k] == (2 if 4 <= k < 28 else 1) * calls[0] for k in calls)
|
| 57 |
+
for h in hooks:
|
| 58 |
+
h.remove()
|
| 59 |
+
|
| 60 |
+
report["text_haiku"] = chat([{"role": "user", "content": "Write a haiku about a tennis ball."}], 64)[0]
|
| 61 |
+
report["thinking"] = chat([{"role": "user", "content": "If a train goes 60 km in 45 minutes, what is its speed in km/h?"}],
|
| 62 |
+
384, thinking=True)[0]
|
| 63 |
+
tools = [{"type": "function", "function": {
|
| 64 |
+
"name": "get_weather", "description": "Get current weather for a city.",
|
| 65 |
+
"parameters": {"type": "object", "properties": {
|
| 66 |
+
"city": {"type": "string"}, "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}},
|
| 67 |
+
"required": ["city"]}}}]
|
| 68 |
+
r = chat([{"role": "user", "content": "What's the weather in Paris in celsius?"}], 96, tools=tools)[0]
|
| 69 |
+
r["has_tool_call_xml"] = ("<tool_call>" in r["text"] and "<function=get_weather>" in r["text"]
|
| 70 |
+
and "<parameter=city>" in r["text"])
|
| 71 |
+
report["tool_call"] = r
|
| 72 |
+
|
| 73 |
+
if image_path:
|
| 74 |
+
img = Image.open(image_path).convert("RGB")
|
| 75 |
+
msgs = [{"role": "user", "content": [{"type": "image"},
|
| 76 |
+
{"type": "text", "text": "Describe this image in two sentences."}]}]
|
| 77 |
+
report["image"] = chat(msgs, 96, images=[img])[0]
|
| 78 |
+
|
| 79 |
+
# Cached generation consistency: greedy tokens from cached decoding must equal the
|
| 80 |
+
# argmax of a single uncached forward over prompt+generation (teacher forcing).
|
| 81 |
+
r, out, inputs = chat([{"role": "user", "content": "Explain in one paragraph why the sky is blue."}], 64)
|
| 82 |
+
plen = inputs["input_ids"].shape[1]
|
| 83 |
+
with torch.inference_mode():
|
| 84 |
+
logits = model(input_ids=out, use_cache=False).logits[0, plen - 1:-1].float()
|
| 85 |
+
pred = logits.argmax(-1)
|
| 86 |
+
gen = out[0, plen:]
|
| 87 |
+
report["cache_consistency"] = {"n": int(gen.numel()), "match": int((pred == gen).sum()),
|
| 88 |
+
"first_mismatch": int((pred != gen).nonzero()[0]) if (pred != gen).any() else None,
|
| 89 |
+
"finite_logits": bool(torch.isfinite(logits).all())}
|
| 90 |
+
report["peak_gpu_mem_GiB"] = round(torch.cuda.max_memory_allocated() / 2**30, 2)
|
| 91 |
+
json.dump(report, open(out_path, "w"), indent=2, ensure_ascii=False)
|
| 92 |
+
print(json.dumps(report, indent=2, ensure_ascii=False))
|
quantization/20_quantize.py
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""ModelOpt NVFP4 PTQ of SenseNova-Loop-9B-Preview through the real looped (2-visit) forward.
|
| 3 |
+
|
| 4 |
+
Recipes:
|
| 5 |
+
mlp - NVFP4 on decoder MLP gate/up/down only (conservative)
|
| 6 |
+
decoder - NVFP4 on all decoder linears (full-attn q/k/v/o, GDN in_proj_qkv/in_proj_z/out_proj, MLP)
|
| 7 |
+
Always higher precision: vision tower, lm_head, embeddings, GDN in_proj_a/in_proj_b (tiny gate projs),
|
| 8 |
+
GDN conv1d/A_log/dt_bias, norms, mHC routers (FP32, not nn.Linear), MTP head (not loaded by HF; copied BF16).
|
| 9 |
+
KV cache: not quantized.
|
| 10 |
+
|
| 11 |
+
usage: python -I scripts/20_quantize.py --recipe decoder --calib calib/calib_v1.jsonl --out work/nvfp4-decoder [--limit N]
|
| 12 |
+
"""
|
| 13 |
+
import argparse, copy, json, os, sys, time
|
| 14 |
+
import torch
|
| 15 |
+
from PIL import Image
|
| 16 |
+
from transformers import AutoModelForImageTextToText, AutoProcessor
|
| 17 |
+
import modelopt
|
| 18 |
+
import modelopt.torch.quantization as mtq
|
| 19 |
+
from modelopt.torch.export import export_hf_checkpoint
|
| 20 |
+
|
| 21 |
+
ap = argparse.ArgumentParser()
|
| 22 |
+
ap.add_argument("--model", default="upstream/SenseNova-Loop-9B-Preview")
|
| 23 |
+
ap.add_argument("--recipe", choices=["mlp", "decoder"], required=True)
|
| 24 |
+
ap.add_argument("--calib", default="calib/calib_v1.jsonl")
|
| 25 |
+
ap.add_argument("--root", default=".", help="base dir for calib image paths")
|
| 26 |
+
ap.add_argument("--out", required=True)
|
| 27 |
+
ap.add_argument("--limit", type=int, default=0)
|
| 28 |
+
ap.add_argument("--max-len", type=int, default=2048)
|
| 29 |
+
args = ap.parse_args()
|
| 30 |
+
dev = "cuda:0"
|
| 31 |
+
torch.manual_seed(0)
|
| 32 |
+
|
| 33 |
+
proc = AutoProcessor.from_pretrained(args.model, trust_remote_code=True)
|
| 34 |
+
model = AutoModelForImageTextToText.from_pretrained(
|
| 35 |
+
args.model, trust_remote_code=True, dtype=torch.bfloat16, device_map={"": dev}).eval()
|
| 36 |
+
text = model.model.language_model
|
| 37 |
+
|
| 38 |
+
# --- quantization config -------------------------------------------------------------
|
| 39 |
+
cfg = copy.deepcopy(mtq.NVFP4_DEFAULT_CFG)
|
| 40 |
+
qc = cfg["quant_cfg"] # ModelOpt >=0.48: ordered list, later entries win
|
| 41 |
+
for pat in ["*lm_head*", "*visual*", "*vision*", "*mtp*", "*in_proj_a*", "*in_proj_b*",
|
| 42 |
+
"*mhc_*", "*embed_tokens*", "*conv1d*"]:
|
| 43 |
+
qc.append({"quantizer_name": pat, "enable": False})
|
| 44 |
+
if args.recipe == "mlp":
|
| 45 |
+
for pat in ["*self_attn*", "*linear_attn*"]:
|
| 46 |
+
qc.append({"quantizer_name": pat, "enable": False})
|
| 47 |
+
|
| 48 |
+
# --- calibration data: rendered with the model's own template + processor ----------------
|
| 49 |
+
rows = [json.loads(l) for l in open(args.calib)]
|
| 50 |
+
if args.limit:
|
| 51 |
+
rows = rows[: args.limit]
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
def render(row):
|
| 55 |
+
msgs, images = [], []
|
| 56 |
+
for m in row["messages"]:
|
| 57 |
+
m = dict(m)
|
| 58 |
+
if isinstance(m.get("content"), list):
|
| 59 |
+
parts = []
|
| 60 |
+
for p in m["content"]:
|
| 61 |
+
if p.get("type") == "image":
|
| 62 |
+
images.append(Image.open(os.path.join(args.root, p["image"])).convert("RGB"))
|
| 63 |
+
parts.append({"type": "image"})
|
| 64 |
+
else:
|
| 65 |
+
parts.append(p)
|
| 66 |
+
m["content"] = parts
|
| 67 |
+
msgs.append(m)
|
| 68 |
+
prompt = proc.apply_chat_template(msgs, tools=row.get("tools"), tokenize=False,
|
| 69 |
+
add_generation_prompt=False,
|
| 70 |
+
enable_thinking=bool(row.get("enable_thinking")))
|
| 71 |
+
batch = proc(text=[prompt], images=images or None, return_tensors="pt")
|
| 72 |
+
if batch["input_ids"].shape[1] > args.max_len and not images:
|
| 73 |
+
batch = {k: v[:, : args.max_len] for k, v in batch.items()}
|
| 74 |
+
return batch
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
batches = [render(r) for r in rows]
|
| 78 |
+
ntok = sum(int(b["input_ids"].shape[1]) for b in batches)
|
| 79 |
+
print(f"calib: {len(batches)} samples, {ntok} tokens, {sum(r.get('n_images', 0) for r in rows)} images", flush=True)
|
| 80 |
+
|
| 81 |
+
visits = {}
|
| 82 |
+
hooks = [l.register_forward_hook(lambda m, i, o, k=k: visits.__setitem__(k, visits.get(k, 0) + 1))
|
| 83 |
+
for k, l in enumerate(text.layers)]
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
def forward_loop(m):
|
| 87 |
+
t = time.time()
|
| 88 |
+
for i, b in enumerate(batches):
|
| 89 |
+
b = {k: v.to(dev) for k, v in b.items()}
|
| 90 |
+
with torch.inference_mode():
|
| 91 |
+
m(**b, use_cache=False)
|
| 92 |
+
if i % 32 == 0:
|
| 93 |
+
print(f" calib {i}/{len(batches)} {time.time() - t:.0f}s", flush=True)
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
t0 = time.time()
|
| 97 |
+
model = mtq.quantize(model, cfg, forward_loop)
|
| 98 |
+
for h in hooks:
|
| 99 |
+
h.remove()
|
| 100 |
+
calib_s = time.time() - t0
|
| 101 |
+
mtq.print_quant_summary(model) if hasattr(mtq, "print_quant_summary") else None
|
| 102 |
+
|
| 103 |
+
# --- bookkeeping: what got quantized ----------------------------------------------------
|
| 104 |
+
quantized, excluded = [], []
|
| 105 |
+
for name, mod in model.named_modules():
|
| 106 |
+
if isinstance(mod, torch.nn.Linear):
|
| 107 |
+
wq = getattr(mod, "weight_quantizer", None)
|
| 108 |
+
(quantized if (wq is not None and wq.is_enabled) else excluded).append((name, mod.weight.numel()))
|
| 109 |
+
total_params = sum(p.numel() for p in model.parameters())
|
| 110 |
+
q_params = sum(n for _, n in quantized)
|
| 111 |
+
looped = [k for k, v in visits.items() if v == 2 * len(batches)]
|
| 112 |
+
stats = {
|
| 113 |
+
"recipe": args.recipe, "modelopt": modelopt.__version__, "torch": torch.__version__,
|
| 114 |
+
"calib_file": args.calib, "calib_samples": len(batches), "calib_tokens": ntok, "calib_seconds": round(calib_s, 1),
|
| 115 |
+
"layers_visited_twice_per_sample": looped,
|
| 116 |
+
"quantized_linear_modules": len(quantized), "excluded_linear_modules": [n for n, _ in excluded],
|
| 117 |
+
"quantized_params": q_params, "total_params_hf_loaded": total_params,
|
| 118 |
+
"fraction_params_quantized": round(q_params / total_params, 4),
|
| 119 |
+
"quant_cfg": qc,
|
| 120 |
+
}
|
| 121 |
+
|
| 122 |
+
# Sanity: logits stay finite through the fake-quant model.
|
| 123 |
+
with torch.inference_mode():
|
| 124 |
+
b = {k: v.to(dev) for k, v in batches[0].items()}
|
| 125 |
+
stats["fakequant_logits_finite"] = bool(torch.isfinite(model(**b, use_cache=False).logits).all())
|
| 126 |
+
|
| 127 |
+
os.makedirs(args.out, exist_ok=True)
|
| 128 |
+
t0 = time.time()
|
| 129 |
+
with torch.inference_mode():
|
| 130 |
+
export_hf_checkpoint(model, export_dir=args.out)
|
| 131 |
+
stats["export_seconds"] = round(time.time() - t0, 1)
|
| 132 |
+
json.dump(stats, open(os.path.join(args.out, "quantization_stats.json"), "w"), indent=2)
|
| 133 |
+
print(json.dumps({k: v for k, v in stats.items() if k != "excluded_linear_modules"}, indent=2))
|
| 134 |
+
print("excluded linear modules:", len(excluded))
|
quantization/30_verify_export.py
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Independent structural verification of an exported NVFP4 checkpoint (reads files only).
|
| 3 |
+
|
| 4 |
+
Checks against the upstream checkpoint: every upstream tensor is present (as BF16/FP32 or as an
|
| 5 |
+
NVFP4 packed weight + scales), packed shapes are consistent (uint8 [out, in/2], fp8 e4m3 block scales
|
| 6 |
+
[out, in/16], fp32 global scales), all scales finite/positive, mHC routers FP32, exactly one copy of
|
| 7 |
+
each physical (shared, looped) layer, MTP tensors present, config/quant metadata consistent.
|
| 8 |
+
|
| 9 |
+
usage: python -I scripts/30_verify_export.py EXPORT_DIR UPSTREAM_DIR OUT_JSON
|
| 10 |
+
"""
|
| 11 |
+
import json, os, sys, collections
|
| 12 |
+
import torch
|
| 13 |
+
from safetensors import safe_open
|
| 14 |
+
|
| 15 |
+
exp, up, out = sys.argv[1:4]
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def index(d):
|
| 19 |
+
idx = os.path.join(d, "model.safetensors.index.json")
|
| 20 |
+
if os.path.exists(idx):
|
| 21 |
+
wm = json.load(open(idx))["weight_map"]
|
| 22 |
+
else:
|
| 23 |
+
wm = {}
|
| 24 |
+
for f in os.listdir(d):
|
| 25 |
+
if f.endswith(".safetensors"):
|
| 26 |
+
with safe_open(os.path.join(d, f), "pt") as fh:
|
| 27 |
+
wm.update({k: f for k in fh.keys()})
|
| 28 |
+
return wm
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
def header(d, wm):
|
| 32 |
+
meta = {}
|
| 33 |
+
for f in set(wm.values()):
|
| 34 |
+
with safe_open(os.path.join(d, f), "pt") as fh:
|
| 35 |
+
for k in fh.keys():
|
| 36 |
+
sl = fh.get_slice(k)
|
| 37 |
+
meta[k] = (sl.get_dtype(), tuple(sl.get_shape()), f)
|
| 38 |
+
return meta
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
ewm, uwm = index(exp), index(up)
|
| 42 |
+
E, U = header(exp, ewm), header(up, uwm)
|
| 43 |
+
qcfg = json.load(open(os.path.join(exp, "hf_quant_config.json")))["quantization"]
|
| 44 |
+
cfg = json.load(open(os.path.join(exp, "config.json")))
|
| 45 |
+
rep = {"export_dir": exp, "quant_algo": qcfg.get("quant_algo"), "group_size": qcfg.get("group_size"),
|
| 46 |
+
"kv_cache_quant_algo": qcfg.get("kv_cache_quant_algo"),
|
| 47 |
+
"config_has_quantization_config": "quantization_config" in cfg,
|
| 48 |
+
"n_tensors_export": len(E), "n_tensors_upstream": len(U)}
|
| 49 |
+
problems = []
|
| 50 |
+
|
| 51 |
+
packed = [k[: -len(".weight")] for k, (dt, _, _) in E.items() if k.endswith(".weight") and dt == "U8"]
|
| 52 |
+
rep["nvfp4_linear_modules"] = len(packed)
|
| 53 |
+
q_params = 0
|
| 54 |
+
for m in packed:
|
| 55 |
+
dt, shp, _ = E[m + ".weight"]
|
| 56 |
+
ref = U.get(m + ".weight")
|
| 57 |
+
if ref is None:
|
| 58 |
+
problems.append(f"packed {m} not in upstream"); continue
|
| 59 |
+
o, i = ref[1]
|
| 60 |
+
q_params += o * i
|
| 61 |
+
if shp != (o, i // 2):
|
| 62 |
+
problems.append(f"{m}: packed shape {shp} != {(o, i // 2)}")
|
| 63 |
+
s = E.get(m + ".weight_scale")
|
| 64 |
+
if s is None or s[0] != "F8_E4M3" or s[1] != (o, i // qcfg["group_size"]):
|
| 65 |
+
problems.append(f"{m}: weight_scale {s}")
|
| 66 |
+
for k in ("weight_scale_2", "input_scale"):
|
| 67 |
+
t = E.get(f"{m}.{k}")
|
| 68 |
+
if t is None or t[0] != "F32" or (len(t[1]) and t[1] != (1,)):
|
| 69 |
+
problems.append(f"{m}: {k} {t}")
|
| 70 |
+
|
| 71 |
+
# Load all scales and check finite / positive.
|
| 72 |
+
bad_scales, n_scales = 0, 0
|
| 73 |
+
by_file = collections.defaultdict(list)
|
| 74 |
+
for k in E:
|
| 75 |
+
if k.endswith(("weight_scale", "weight_scale_2", "input_scale")):
|
| 76 |
+
by_file[E[k][2]].append(k)
|
| 77 |
+
for f, keys in by_file.items():
|
| 78 |
+
with safe_open(os.path.join(exp, f), "pt") as fh:
|
| 79 |
+
for k in keys:
|
| 80 |
+
t = fh.get_tensor(k).float()
|
| 81 |
+
n_scales += 1
|
| 82 |
+
if not torch.isfinite(t).all() or (t[t != 0] <= 0).any() or (k.endswith("input_scale") and (t <= 0).any()):
|
| 83 |
+
bad_scales += 1
|
| 84 |
+
problems.append(f"bad scale {k}")
|
| 85 |
+
rep["scale_tensors_checked"] = n_scales
|
| 86 |
+
rep["bad_scale_tensors"] = bad_scales
|
| 87 |
+
|
| 88 |
+
# Upstream coverage: every upstream tensor present in export (either same name or packed).
|
| 89 |
+
missing = [k for k in U if k not in E]
|
| 90 |
+
rep["upstream_tensors_missing_in_export"] = missing[:20]
|
| 91 |
+
rep["n_upstream_missing"] = len(missing)
|
| 92 |
+
extra = [k for k in E if k not in U and not k.endswith(("weight_scale", "weight_scale_2", "input_scale"))]
|
| 93 |
+
rep["unexpected_extra_tensors"] = extra[:20]
|
| 94 |
+
|
| 95 |
+
mhc = {k: E[k][0] for k in E if ".mhc_" in k}
|
| 96 |
+
rep["mhc_tensors"] = len(mhc)
|
| 97 |
+
rep["mhc_all_fp32"] = all(v == "F32" for v in mhc.values()) and len(mhc) == 96
|
| 98 |
+
mtp = [k for k in E if k.startswith("mtp.")]
|
| 99 |
+
rep["mtp_tensors"] = len(mtp)
|
| 100 |
+
rep["mtp_dtypes"] = sorted({E[k][0] for k in mtp})
|
| 101 |
+
|
| 102 |
+
# Shared weights: layer ids present must be exactly 0..31 (no duplicated per-visit copies).
|
| 103 |
+
lids = sorted({int(k.split(".layers.")[1].split(".")[0]) for k in E if "language_model.layers." in k})
|
| 104 |
+
rep["physical_layer_ids"] = f"{lids[0]}..{lids[-1]} ({len(lids)})"
|
| 105 |
+
if lids != list(range(32)):
|
| 106 |
+
problems.append(f"layer ids {lids}")
|
| 107 |
+
|
| 108 |
+
dtypes = collections.Counter()
|
| 109 |
+
nbytes = collections.Counter()
|
| 110 |
+
size = {"U8": 1, "F8_E4M3": 1, "BF16": 2, "F16": 2, "F32": 4}
|
| 111 |
+
import math
|
| 112 |
+
for k, (dt, shp, _) in E.items():
|
| 113 |
+
n = math.prod(shp)
|
| 114 |
+
dtypes[dt] += n
|
| 115 |
+
nbytes[dt] += n * size.get(dt, 0)
|
| 116 |
+
rep["elements_by_dtype"] = dict(dtypes)
|
| 117 |
+
rep["GB_by_dtype"] = {k: round(v / 1e9, 3) for k, v in nbytes.items()}
|
| 118 |
+
rep["total_file_GB"] = round(sum(os.path.getsize(os.path.join(exp, f)) for f in set(ewm.values())) / 1e9, 3)
|
| 119 |
+
total_up = sum(math.prod(s) for (_, s, _) in U.values())
|
| 120 |
+
rep["upstream_params_incl_mtp"] = total_up
|
| 121 |
+
rep["nvfp4_params"] = q_params
|
| 122 |
+
rep["fraction_params_nvfp4"] = round(q_params / total_up, 4)
|
| 123 |
+
rep["problems"] = problems
|
| 124 |
+
rep["ok"] = not problems and not missing and rep["mhc_all_fp32"] and len(mtp) > 0
|
| 125 |
+
json.dump(rep, open(out, "w"), indent=2)
|
| 126 |
+
print(json.dumps(rep, indent=2))
|
quantization/build_calib.py
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python
|
| 2 |
+
"""Build calib/calib_v1.jsonl: 256 chat-format calibration examples for NVFP4 (ModelOpt) PTQ.
|
| 3 |
+
|
| 4 |
+
.venv-eval/bin/python calib/build_calib.py # raw files are expected under calib/raw/
|
| 5 |
+
(downloads: see SOURCES; fetched with huggingface_hub.hf_hub_download at the pinned revisions)
|
| 6 |
+
|
| 7 |
+
Each line: {"id", "category", "source", "messages": [...OpenAI-style...], "tools"?: [...],
|
| 8 |
+
"enable_thinking": bool, "approx_text_tokens": int, "n_images": int}
|
| 9 |
+
Images: {"type": "image", "image": "calib/images/<file>.jpg"} (path relative to project root),
|
| 10 |
+
which HF processors' apply_chat_template understand; the chat template also accepts image_url.
|
| 11 |
+
Thinking examples carry the trace in the assistant's `reasoning_content` (the chat template renders
|
| 12 |
+
it as <think>\n...\n</think>\n\n before the answer); all other final assistant turns render with
|
| 13 |
+
the empty <think>\n\n</think>\n\n block, matching enable_thinking=False inference.
|
| 14 |
+
Disjointness from eval/data is enforced by construction (different datasets/splits) AND checked
|
| 15 |
+
by 13-gram overlap against every eval prompt (summary in calib/calib_v1.meta.json).
|
| 16 |
+
"""
|
| 17 |
+
from __future__ import annotations
|
| 18 |
+
|
| 19 |
+
import hashlib
|
| 20 |
+
import json
|
| 21 |
+
import random
|
| 22 |
+
import re
|
| 23 |
+
import sys
|
| 24 |
+
from collections import Counter
|
| 25 |
+
from pathlib import Path
|
| 26 |
+
|
| 27 |
+
import pyarrow.parquet as pq
|
| 28 |
+
|
| 29 |
+
ROOT = Path(__file__).resolve().parent.parent
|
| 30 |
+
CAL = ROOT / "calib"
|
| 31 |
+
RAW = CAL / "raw"
|
| 32 |
+
SEED = 20261030
|
| 33 |
+
MAX_TEXT_TOKENS = 1800
|
| 34 |
+
TARGET = {"chat": 77, "code": 51, "math": 51, "tools": 38, "image": 39} # = 256 (30/20/20/15/15 %)
|
| 35 |
+
N_THINK_MATH = 26
|
| 36 |
+
|
| 37 |
+
SOURCES = {
|
| 38 |
+
"chat": dict(repo="OpenAssistant/oasst2", rev="179dd21fc55192153d94adb0e0ce8f69e222bf75",
|
| 39 |
+
file="data/train-00000-of-00001-88ba0162028a73fc.parquet", split="train", license="Apache-2.0"),
|
| 40 |
+
"code": dict(repo="google-research-datasets/mbpp", rev="4bb6404fdc6cacfda99d4ac4205087b89d32030c",
|
| 41 |
+
file="full/train-00000-of-00001.parquet", split="full/train", license="CC-BY-4.0"),
|
| 42 |
+
"math": dict(repo="openai/gsm8k", rev="740312add88f781978c0658806c59bc2815b9866",
|
| 43 |
+
file="main/train-00000-of-00001.parquet", split="main/train", license="MIT"),
|
| 44 |
+
"tools": dict(repo="glaiveai/glaive-function-calling-v2", rev="e7f4b6456019f5d8bcb991ef0dd67d8ff23221ac",
|
| 45 |
+
file="glaive-function-calling-v2.json", split="train", license="Apache-2.0"),
|
| 46 |
+
"image": dict(repo="lmms-lab/textvqa", rev="9c0699cd19768ac5ab97568f6b3cbac4c0062884",
|
| 47 |
+
file="data/train-00000-of-00020.parquet", split="train (shard 0 of 20)",
|
| 48 |
+
license="TextVQA annotations CC-BY-4.0; images OpenImages CC-BY-2.0 (Flickr attribution)"),
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def raw(cat):
|
| 53 |
+
s = SOURCES[cat]
|
| 54 |
+
return RAW / s["repo"].replace("/", "__") / s["file"]
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
_tok = None
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
def ntok(text):
|
| 61 |
+
global _tok
|
| 62 |
+
if _tok is None:
|
| 63 |
+
from tokenizers import Tokenizer
|
| 64 |
+
_tok = Tokenizer.from_file(str(ROOT / "upstream/SenseNova-Loop-9B-Preview/tokenizer.json"))
|
| 65 |
+
return len(_tok.encode(text, add_special_tokens=False).ids)
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
def ex_text(ex):
|
| 69 |
+
parts = [json.dumps(ex.get("tools") or "")]
|
| 70 |
+
for m in ex["messages"]:
|
| 71 |
+
c = m.get("content")
|
| 72 |
+
if isinstance(c, list):
|
| 73 |
+
c = " ".join(p.get("text", "") for p in c)
|
| 74 |
+
parts.append(c or "")
|
| 75 |
+
parts.append(m.get("reasoning_content") or "")
|
| 76 |
+
parts.append(json.dumps(m.get("tool_calls") or ""))
|
| 77 |
+
return "\n".join(parts)
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
# ----------------------------------------------------------------------------- chat (oasst2)
|
| 81 |
+
def build_chat(rng):
|
| 82 |
+
t = pq.read_table(raw("chat"), columns=["message_id", "parent_id", "text", "role", "lang", "deleted",
|
| 83 |
+
"review_result", "rank", "tree_state", "synthetic"]).to_pylist()
|
| 84 |
+
kids = {}
|
| 85 |
+
roots = []
|
| 86 |
+
for m in t:
|
| 87 |
+
if m["deleted"] or m["review_result"] is False or m["synthetic"]:
|
| 88 |
+
continue
|
| 89 |
+
if m["parent_id"] is None:
|
| 90 |
+
if m["role"] == "prompter" and m["tree_state"] == "ready_for_export":
|
| 91 |
+
roots.append(m)
|
| 92 |
+
else:
|
| 93 |
+
kids.setdefault(m["parent_id"], []).append(m)
|
| 94 |
+
|
| 95 |
+
def best(mid, role):
|
| 96 |
+
cs = [c for c in kids.get(mid, []) if c["role"] == role]
|
| 97 |
+
cs.sort(key=lambda c: (c["rank"] if c["rank"] is not None else 99, c["message_id"]))
|
| 98 |
+
return cs[0] if cs else None
|
| 99 |
+
roots.sort(key=lambda m: m["message_id"])
|
| 100 |
+
rng.shuffle(roots)
|
| 101 |
+
want = {"en": 58, "zh": 10, "other": 9}
|
| 102 |
+
got = {"en": [], "zh": [], "other": []}
|
| 103 |
+
for r in roots:
|
| 104 |
+
bucket = r["lang"] if r["lang"] in ("en", "zh") else "other"
|
| 105 |
+
if len(got[bucket]) >= want[bucket]:
|
| 106 |
+
continue
|
| 107 |
+
msgs, cur = [{"role": "user", "content": r["text"]}], r
|
| 108 |
+
turns = rng.choice([1, 1, 2])
|
| 109 |
+
for k in range(turns):
|
| 110 |
+
a = best(cur["message_id"], "assistant")
|
| 111 |
+
if a is None:
|
| 112 |
+
break
|
| 113 |
+
msgs.append({"role": "assistant", "content": a["text"]})
|
| 114 |
+
if k + 1 < turns:
|
| 115 |
+
u = best(a["message_id"], "prompter")
|
| 116 |
+
a2 = best(u["message_id"], "assistant") if u else None
|
| 117 |
+
if not (u and a2):
|
| 118 |
+
break
|
| 119 |
+
msgs.append({"role": "user", "content": u["text"]})
|
| 120 |
+
cur = u
|
| 121 |
+
if msgs[-1]["role"] != "assistant":
|
| 122 |
+
continue
|
| 123 |
+
ex = {"category": "chat", "source": f"oasst2:{r['message_id']}", "lang": r["lang"], "messages": msgs}
|
| 124 |
+
if ntok(ex_text(ex)) > MAX_TEXT_TOKENS:
|
| 125 |
+
continue
|
| 126 |
+
got[bucket].append(ex)
|
| 127 |
+
if all(len(got[b]) >= want[b] for b in want):
|
| 128 |
+
break
|
| 129 |
+
return got["en"] + got["zh"] + got["other"]
|
| 130 |
+
|
| 131 |
+
|
| 132 |
+
# ----------------------------------------------------------------------------- code (MBPP train)
|
| 133 |
+
def build_code(rng):
|
| 134 |
+
rows = pq.read_table(raw("code")).to_pylist()
|
| 135 |
+
rows.sort(key=lambda r: r["task_id"])
|
| 136 |
+
idx = sorted(rng.sample(range(len(rows)), TARGET["code"]))
|
| 137 |
+
out = []
|
| 138 |
+
for i in idx:
|
| 139 |
+
r = rows[i]
|
| 140 |
+
tests = "\n".join(r["test_list"])
|
| 141 |
+
user = f"{r['text']} Your code should pass these tests:\n\n```python\n{tests}\n```"
|
| 142 |
+
asst = f"```python\n{r['code'].strip()}\n```"
|
| 143 |
+
out.append({"category": "code", "source": f"mbpp:task_id={r['task_id']}",
|
| 144 |
+
"messages": [{"role": "user", "content": user}, {"role": "assistant", "content": asst}]})
|
| 145 |
+
return out
|
| 146 |
+
|
| 147 |
+
|
| 148 |
+
# ----------------------------------------------------------------------------- math (GSM8K train)
|
| 149 |
+
def build_math(rng):
|
| 150 |
+
rows = pq.read_table(raw("math")).to_pylist()
|
| 151 |
+
idx = sorted(rng.sample(range(len(rows)), TARGET["math"]))
|
| 152 |
+
out = []
|
| 153 |
+
for j, i in enumerate(idx):
|
| 154 |
+
q, sol = rows[i]["question"], rows[i]["answer"]
|
| 155 |
+
steps, final = sol.split("####")
|
| 156 |
+
steps = re.sub(r"<<[^>]*>>", "", steps).strip()
|
| 157 |
+
final = final.strip()
|
| 158 |
+
think = j < N_THINK_MATH
|
| 159 |
+
if think:
|
| 160 |
+
asst = {"role": "assistant", "reasoning_content": steps,
|
| 161 |
+
"content": f"The final answer is {final}."}
|
| 162 |
+
else:
|
| 163 |
+
asst = {"role": "assistant", "content": f"{steps}\nThe final answer is {final}."}
|
| 164 |
+
out.append({"category": "math", "source": f"gsm8k:train:{i}", "enable_thinking": think,
|
| 165 |
+
"messages": [{"role": "user", "content": q}, asst]})
|
| 166 |
+
return out
|
| 167 |
+
|
| 168 |
+
|
| 169 |
+
# ----------------------------------------------------------------------------- tools (glaive v2)
|
| 170 |
+
def parse_glaive(rec):
|
| 171 |
+
sysm = rec["system"]
|
| 172 |
+
if "following functions" not in sysm:
|
| 173 |
+
return None
|
| 174 |
+
body = sysm.split("Use them if required -", 1)[-1].strip()
|
| 175 |
+
dec, pos, fns = json.JSONDecoder(), 0, []
|
| 176 |
+
while pos < len(body):
|
| 177 |
+
while pos < len(body) and body[pos] in " \n\t":
|
| 178 |
+
pos += 1
|
| 179 |
+
if pos >= len(body):
|
| 180 |
+
break
|
| 181 |
+
try:
|
| 182 |
+
obj, pos = dec.raw_decode(body, pos)
|
| 183 |
+
except json.JSONDecodeError:
|
| 184 |
+
return None
|
| 185 |
+
fns.append({"type": "function", "function": obj})
|
| 186 |
+
if not fns:
|
| 187 |
+
return None
|
| 188 |
+
turns = re.split(r"\n*(USER|ASSISTANT|FUNCTION RESPONSE): ", "\n" + rec["chat"])
|
| 189 |
+
msgs, n_calls = [], 0
|
| 190 |
+
it = iter(turns[1:])
|
| 191 |
+
for role, text in zip(it, it):
|
| 192 |
+
text = text.replace("<|endoftext|>", "").strip()
|
| 193 |
+
if role == "USER":
|
| 194 |
+
msgs.append({"role": "user", "content": text})
|
| 195 |
+
elif role == "FUNCTION RESPONSE":
|
| 196 |
+
msgs.append({"role": "tool", "content": text})
|
| 197 |
+
else:
|
| 198 |
+
if "<functioncall>" in text:
|
| 199 |
+
pre, call = text.split("<functioncall>", 1)
|
| 200 |
+
m = re.match(r'\s*\{\s*"name"\s*:\s*"([^"]+)"\s*,\s*"arguments"\s*:\s*\'(.*)\'\s*\}\s*$', call, re.S)
|
| 201 |
+
if not m:
|
| 202 |
+
return None
|
| 203 |
+
try:
|
| 204 |
+
args = json.loads(m.group(2))
|
| 205 |
+
except json.JSONDecodeError:
|
| 206 |
+
return None
|
| 207 |
+
if not isinstance(args, dict):
|
| 208 |
+
return None
|
| 209 |
+
msgs.append({"role": "assistant", "content": pre.strip(),
|
| 210 |
+
"tool_calls": [{"id": f"call_{n_calls}", "type": "function",
|
| 211 |
+
"function": {"name": m.group(1), "arguments": args}}]})
|
| 212 |
+
n_calls += 1
|
| 213 |
+
else:
|
| 214 |
+
msgs.append({"role": "assistant", "content": text})
|
| 215 |
+
if n_calls == 0 or not msgs or msgs[0]["role"] != "user" or msgs[-1]["role"] != "assistant":
|
| 216 |
+
return None
|
| 217 |
+
if not any(m["role"] == "tool" for m in msgs):
|
| 218 |
+
return None
|
| 219 |
+
return fns, msgs
|
| 220 |
+
|
| 221 |
+
|
| 222 |
+
def build_tools(rng):
|
| 223 |
+
data = json.load(open(raw("tools")))
|
| 224 |
+
order = list(range(len(data)))
|
| 225 |
+
rng.shuffle(order)
|
| 226 |
+
out = []
|
| 227 |
+
for i in order:
|
| 228 |
+
p = parse_glaive(data[i])
|
| 229 |
+
if not p:
|
| 230 |
+
continue
|
| 231 |
+
ex = {"category": "tools", "source": f"glaive-fc-v2:{i}", "tools": p[0], "messages": p[1]}
|
| 232 |
+
if ntok(ex_text(ex)) > MAX_TEXT_TOKENS:
|
| 233 |
+
continue
|
| 234 |
+
out.append(ex)
|
| 235 |
+
if len(out) >= TARGET["tools"]:
|
| 236 |
+
break
|
| 237 |
+
return out
|
| 238 |
+
|
| 239 |
+
|
| 240 |
+
# ----------------------------------------------------------------------------- image (TextVQA train)
|
| 241 |
+
def build_image(rng, eval_image_ids):
|
| 242 |
+
from tasks import vqa_norm # eval/ is on sys.path
|
| 243 |
+
t = pq.read_table(raw("image"), columns=["question_id", "question", "answers", "image_id"]).to_pylist()
|
| 244 |
+
cand = [i for i, r in enumerate(t) if r["image_id"] not in eval_image_ids
|
| 245 |
+
and Counter(vqa_norm(a) for a in r["answers"]).most_common(1)[0][1] >= 3]
|
| 246 |
+
rng.shuffle(cand)
|
| 247 |
+
seen_img, pickd = set(), []
|
| 248 |
+
for i in cand:
|
| 249 |
+
if t[i]["image_id"] in seen_img:
|
| 250 |
+
continue
|
| 251 |
+
seen_img.add(t[i]["image_id"])
|
| 252 |
+
pickd.append(i)
|
| 253 |
+
if len(pickd) >= TARGET["image"]:
|
| 254 |
+
break
|
| 255 |
+
pickd.sort()
|
| 256 |
+
imgs = pq.read_table(raw("image"), columns=["image"]).take(pickd).column("image").to_pylist()
|
| 257 |
+
(CAL / "images").mkdir(exist_ok=True)
|
| 258 |
+
out = []
|
| 259 |
+
for i, im in zip(pickd, imgs):
|
| 260 |
+
r = t[i]
|
| 261 |
+
b = im["bytes"]
|
| 262 |
+
ext = "png" if b[:4] == b"\x89PNG" else "jpg"
|
| 263 |
+
rel = f"calib/images/textvqa_train_{r['question_id']}.{ext}"
|
| 264 |
+
(ROOT / rel).write_bytes(b)
|
| 265 |
+
ans = Counter(a.strip() for a in r["answers"]).most_common(1)[0][0]
|
| 266 |
+
out.append({"category": "image", "source": f"textvqa:train:qid={r['question_id']}", "image_id": r["image_id"],
|
| 267 |
+
"image_sha256": hashlib.sha256(b).hexdigest(), "messages": [
|
| 268 |
+
{"role": "user", "content": [{"type": "image", "image": rel},
|
| 269 |
+
{"type": "text", "text": r["question"].strip().capitalize()
|
| 270 |
+
+ "\nAnswer the question using a single word or phrase."}]},
|
| 271 |
+
{"role": "assistant", "content": ans}]})
|
| 272 |
+
return out
|
| 273 |
+
|
| 274 |
+
|
| 275 |
+
# ----------------------------------------------------------------------------- overlap check
|
| 276 |
+
def shingles(text, n=13):
|
| 277 |
+
w = re.findall(r"\w+", text.lower())
|
| 278 |
+
return {" ".join(w[i:i + n]) for i in range(max(0, len(w) - n + 1))}
|
| 279 |
+
|
| 280 |
+
|
| 281 |
+
def main():
|
| 282 |
+
sys.path.insert(0, str(ROOT / "eval"))
|
| 283 |
+
eval_dir = ROOT / "eval/data"
|
| 284 |
+
eval_sh, eval_imgs = set(), set()
|
| 285 |
+
for p in eval_dir.glob("*.jsonl"):
|
| 286 |
+
for l in open(p):
|
| 287 |
+
r = json.loads(l)
|
| 288 |
+
eval_sh |= shingles(json.dumps(r, ensure_ascii=False))
|
| 289 |
+
if "image_id" in r:
|
| 290 |
+
eval_imgs.add(r["image_id"])
|
| 291 |
+
exs = []
|
| 292 |
+
exs += build_chat(random.Random(f"{SEED}-chat"))
|
| 293 |
+
exs += build_code(random.Random(f"{SEED}-code"))
|
| 294 |
+
exs += build_math(random.Random(f"{SEED}-math"))
|
| 295 |
+
exs += build_tools(random.Random(f"{SEED}-tools"))
|
| 296 |
+
exs += build_image(random.Random(f"{SEED}-image"), eval_imgs)
|
| 297 |
+
cnt = Counter(e["category"] for e in exs)
|
| 298 |
+
assert dict(cnt) == TARGET, cnt
|
| 299 |
+
overlaps = []
|
| 300 |
+
for k, e in enumerate(exs):
|
| 301 |
+
e["id"] = f"calib_v1_{k:03d}"
|
| 302 |
+
e.setdefault("enable_thinking", False)
|
| 303 |
+
e["approx_text_tokens"] = ntok(ex_text(e))
|
| 304 |
+
e["n_images"] = sum(1 for m in e["messages"] if isinstance(m["content"], list)
|
| 305 |
+
for p in m["content"] if p.get("type") == "image")
|
| 306 |
+
ov = shingles(ex_text(e)) & eval_sh
|
| 307 |
+
if ov:
|
| 308 |
+
overlaps.append({"id": e["id"], "source": e["source"], "n_shared_13grams": len(ov),
|
| 309 |
+
"example": sorted(ov)[0]})
|
| 310 |
+
order = ["id", "category", "source", "enable_thinking", "approx_text_tokens", "n_images"]
|
| 311 |
+
with open(CAL / "calib_v1.jsonl", "w") as f:
|
| 312 |
+
for e in exs:
|
| 313 |
+
f.write(json.dumps({**{k: e[k] for k in order}, **{k: v for k, v in e.items() if k not in order}},
|
| 314 |
+
ensure_ascii=False) + "\n")
|
| 315 |
+
toks = [e["approx_text_tokens"] for e in exs]
|
| 316 |
+
meta = {"version": "calib_v1", "seed": SEED, "n": len(exs), "counts": dict(cnt),
|
| 317 |
+
"n_thinking_examples": sum(e["enable_thinking"] for e in exs),
|
| 318 |
+
"langs_chat": dict(Counter(e.get("lang") for e in exs if e["category"] == "chat")),
|
| 319 |
+
"text_tokens": {"min": min(toks), "max": max(toks), "mean": sum(toks) / len(toks), "sum": sum(toks)},
|
| 320 |
+
"max_text_tokens_filter": MAX_TEXT_TOKENS, "sources": SOURCES,
|
| 321 |
+
"eval_overlap_13gram": overlaps,
|
| 322 |
+
"sha256": hashlib.sha256((CAL / "calib_v1.jsonl").read_bytes()).hexdigest()}
|
| 323 |
+
(CAL / "calib_v1.meta.json").write_text(json.dumps(meta, indent=2, ensure_ascii=False))
|
| 324 |
+
print(json.dumps({k: meta[k] for k in ("n", "counts", "n_thinking_examples", "langs_chat", "text_tokens")}))
|
| 325 |
+
print("13-gram overlaps with eval:", len(overlaps), overlaps[:3])
|
| 326 |
+
|
| 327 |
+
|
| 328 |
+
if __name__ == "__main__":
|
| 329 |
+
main()
|
quantization/calib_v1.jsonl.sha256
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
9a4d2112ef71820a5a6d8b015b4996092d4c08c3a2aa1abf7303aa5cd3b7ff83 calib/calib_v1.jsonl
|
quantization/calib_v1.meta.json
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"version": "calib_v1",
|
| 3 |
+
"seed": 20261030,
|
| 4 |
+
"n": 256,
|
| 5 |
+
"counts": {
|
| 6 |
+
"chat": 77,
|
| 7 |
+
"code": 51,
|
| 8 |
+
"math": 51,
|
| 9 |
+
"tools": 38,
|
| 10 |
+
"image": 39
|
| 11 |
+
},
|
| 12 |
+
"n_thinking_examples": 26,
|
| 13 |
+
"langs_chat": {
|
| 14 |
+
"en": 58,
|
| 15 |
+
"zh": 10,
|
| 16 |
+
"es": 7,
|
| 17 |
+
"ca": 2
|
| 18 |
+
},
|
| 19 |
+
"text_tokens": {
|
| 20 |
+
"min": 25,
|
| 21 |
+
"max": 1551,
|
| 22 |
+
"mean": 233.29296875,
|
| 23 |
+
"sum": 59723
|
| 24 |
+
},
|
| 25 |
+
"max_text_tokens_filter": 1800,
|
| 26 |
+
"sources": {
|
| 27 |
+
"chat": {
|
| 28 |
+
"repo": "OpenAssistant/oasst2",
|
| 29 |
+
"rev": "179dd21fc55192153d94adb0e0ce8f69e222bf75",
|
| 30 |
+
"file": "data/train-00000-of-00001-88ba0162028a73fc.parquet",
|
| 31 |
+
"split": "train",
|
| 32 |
+
"license": "Apache-2.0"
|
| 33 |
+
},
|
| 34 |
+
"code": {
|
| 35 |
+
"repo": "google-research-datasets/mbpp",
|
| 36 |
+
"rev": "4bb6404fdc6cacfda99d4ac4205087b89d32030c",
|
| 37 |
+
"file": "full/train-00000-of-00001.parquet",
|
| 38 |
+
"split": "full/train",
|
| 39 |
+
"license": "CC-BY-4.0"
|
| 40 |
+
},
|
| 41 |
+
"math": {
|
| 42 |
+
"repo": "openai/gsm8k",
|
| 43 |
+
"rev": "740312add88f781978c0658806c59bc2815b9866",
|
| 44 |
+
"file": "main/train-00000-of-00001.parquet",
|
| 45 |
+
"split": "main/train",
|
| 46 |
+
"license": "MIT"
|
| 47 |
+
},
|
| 48 |
+
"tools": {
|
| 49 |
+
"repo": "glaiveai/glaive-function-calling-v2",
|
| 50 |
+
"rev": "e7f4b6456019f5d8bcb991ef0dd67d8ff23221ac",
|
| 51 |
+
"file": "glaive-function-calling-v2.json",
|
| 52 |
+
"split": "train",
|
| 53 |
+
"license": "Apache-2.0"
|
| 54 |
+
},
|
| 55 |
+
"image": {
|
| 56 |
+
"repo": "lmms-lab/textvqa",
|
| 57 |
+
"rev": "9c0699cd19768ac5ab97568f6b3cbac4c0062884",
|
| 58 |
+
"file": "data/train-00000-of-00020.parquet",
|
| 59 |
+
"split": "train (shard 0 of 20)",
|
| 60 |
+
"license": "TextVQA annotations CC-BY-4.0; images OpenImages CC-BY-2.0 (Flickr attribution)"
|
| 61 |
+
}
|
| 62 |
+
},
|
| 63 |
+
"eval_overlap_13gram": [
|
| 64 |
+
{
|
| 65 |
+
"id": "calib_v1_203",
|
| 66 |
+
"source": "glaive-fc-v2:108408",
|
| 67 |
+
"n_shared_13grams": 1,
|
| 68 |
+
"example": "type function function name send_email description send an email parameters type object properties"
|
| 69 |
+
}
|
| 70 |
+
],
|
| 71 |
+
"sha256": "9a4d2112ef71820a5a6d8b015b4996092d4c08c3a2aa1abf7303aa5cd3b7ff83"
|
| 72 |
+
}
|
quantization/quantization_stats.json
ADDED
|
@@ -0,0 +1,389 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"recipe": "decoder",
|
| 3 |
+
"modelopt": "0.48.0rc1",
|
| 4 |
+
"torch": "2.11.0+cu130",
|
| 5 |
+
"calib_file": "calib/calib_v1.jsonl",
|
| 6 |
+
"calib_samples": 256,
|
| 7 |
+
"calib_tokens": 98458,
|
| 8 |
+
"calib_seconds": 1579.2,
|
| 9 |
+
"layers_visited_twice_per_sample": [
|
| 10 |
+
4,
|
| 11 |
+
5,
|
| 12 |
+
6,
|
| 13 |
+
7,
|
| 14 |
+
8,
|
| 15 |
+
9,
|
| 16 |
+
10,
|
| 17 |
+
11,
|
| 18 |
+
12,
|
| 19 |
+
13,
|
| 20 |
+
14,
|
| 21 |
+
15,
|
| 22 |
+
16,
|
| 23 |
+
17,
|
| 24 |
+
18,
|
| 25 |
+
19,
|
| 26 |
+
20,
|
| 27 |
+
21,
|
| 28 |
+
22,
|
| 29 |
+
23,
|
| 30 |
+
24,
|
| 31 |
+
25,
|
| 32 |
+
26,
|
| 33 |
+
27
|
| 34 |
+
],
|
| 35 |
+
"quantized_linear_modules": 200,
|
| 36 |
+
"excluded_linear_modules": [
|
| 37 |
+
"model.visual.blocks.0.attn.qkv",
|
| 38 |
+
"model.visual.blocks.0.attn.proj",
|
| 39 |
+
"model.visual.blocks.0.mlp.linear_fc1",
|
| 40 |
+
"model.visual.blocks.0.mlp.linear_fc2",
|
| 41 |
+
"model.visual.blocks.1.attn.qkv",
|
| 42 |
+
"model.visual.blocks.1.attn.proj",
|
| 43 |
+
"model.visual.blocks.1.mlp.linear_fc1",
|
| 44 |
+
"model.visual.blocks.1.mlp.linear_fc2",
|
| 45 |
+
"model.visual.blocks.2.attn.qkv",
|
| 46 |
+
"model.visual.blocks.2.attn.proj",
|
| 47 |
+
"model.visual.blocks.2.mlp.linear_fc1",
|
| 48 |
+
"model.visual.blocks.2.mlp.linear_fc2",
|
| 49 |
+
"model.visual.blocks.3.attn.qkv",
|
| 50 |
+
"model.visual.blocks.3.attn.proj",
|
| 51 |
+
"model.visual.blocks.3.mlp.linear_fc1",
|
| 52 |
+
"model.visual.blocks.3.mlp.linear_fc2",
|
| 53 |
+
"model.visual.blocks.4.attn.qkv",
|
| 54 |
+
"model.visual.blocks.4.attn.proj",
|
| 55 |
+
"model.visual.blocks.4.mlp.linear_fc1",
|
| 56 |
+
"model.visual.blocks.4.mlp.linear_fc2",
|
| 57 |
+
"model.visual.blocks.5.attn.qkv",
|
| 58 |
+
"model.visual.blocks.5.attn.proj",
|
| 59 |
+
"model.visual.blocks.5.mlp.linear_fc1",
|
| 60 |
+
"model.visual.blocks.5.mlp.linear_fc2",
|
| 61 |
+
"model.visual.blocks.6.attn.qkv",
|
| 62 |
+
"model.visual.blocks.6.attn.proj",
|
| 63 |
+
"model.visual.blocks.6.mlp.linear_fc1",
|
| 64 |
+
"model.visual.blocks.6.mlp.linear_fc2",
|
| 65 |
+
"model.visual.blocks.7.attn.qkv",
|
| 66 |
+
"model.visual.blocks.7.attn.proj",
|
| 67 |
+
"model.visual.blocks.7.mlp.linear_fc1",
|
| 68 |
+
"model.visual.blocks.7.mlp.linear_fc2",
|
| 69 |
+
"model.visual.blocks.8.attn.qkv",
|
| 70 |
+
"model.visual.blocks.8.attn.proj",
|
| 71 |
+
"model.visual.blocks.8.mlp.linear_fc1",
|
| 72 |
+
"model.visual.blocks.8.mlp.linear_fc2",
|
| 73 |
+
"model.visual.blocks.9.attn.qkv",
|
| 74 |
+
"model.visual.blocks.9.attn.proj",
|
| 75 |
+
"model.visual.blocks.9.mlp.linear_fc1",
|
| 76 |
+
"model.visual.blocks.9.mlp.linear_fc2",
|
| 77 |
+
"model.visual.blocks.10.attn.qkv",
|
| 78 |
+
"model.visual.blocks.10.attn.proj",
|
| 79 |
+
"model.visual.blocks.10.mlp.linear_fc1",
|
| 80 |
+
"model.visual.blocks.10.mlp.linear_fc2",
|
| 81 |
+
"model.visual.blocks.11.attn.qkv",
|
| 82 |
+
"model.visual.blocks.11.attn.proj",
|
| 83 |
+
"model.visual.blocks.11.mlp.linear_fc1",
|
| 84 |
+
"model.visual.blocks.11.mlp.linear_fc2",
|
| 85 |
+
"model.visual.blocks.12.attn.qkv",
|
| 86 |
+
"model.visual.blocks.12.attn.proj",
|
| 87 |
+
"model.visual.blocks.12.mlp.linear_fc1",
|
| 88 |
+
"model.visual.blocks.12.mlp.linear_fc2",
|
| 89 |
+
"model.visual.blocks.13.attn.qkv",
|
| 90 |
+
"model.visual.blocks.13.attn.proj",
|
| 91 |
+
"model.visual.blocks.13.mlp.linear_fc1",
|
| 92 |
+
"model.visual.blocks.13.mlp.linear_fc2",
|
| 93 |
+
"model.visual.blocks.14.attn.qkv",
|
| 94 |
+
"model.visual.blocks.14.attn.proj",
|
| 95 |
+
"model.visual.blocks.14.mlp.linear_fc1",
|
| 96 |
+
"model.visual.blocks.14.mlp.linear_fc2",
|
| 97 |
+
"model.visual.blocks.15.attn.qkv",
|
| 98 |
+
"model.visual.blocks.15.attn.proj",
|
| 99 |
+
"model.visual.blocks.15.mlp.linear_fc1",
|
| 100 |
+
"model.visual.blocks.15.mlp.linear_fc2",
|
| 101 |
+
"model.visual.blocks.16.attn.qkv",
|
| 102 |
+
"model.visual.blocks.16.attn.proj",
|
| 103 |
+
"model.visual.blocks.16.mlp.linear_fc1",
|
| 104 |
+
"model.visual.blocks.16.mlp.linear_fc2",
|
| 105 |
+
"model.visual.blocks.17.attn.qkv",
|
| 106 |
+
"model.visual.blocks.17.attn.proj",
|
| 107 |
+
"model.visual.blocks.17.mlp.linear_fc1",
|
| 108 |
+
"model.visual.blocks.17.mlp.linear_fc2",
|
| 109 |
+
"model.visual.blocks.18.attn.qkv",
|
| 110 |
+
"model.visual.blocks.18.attn.proj",
|
| 111 |
+
"model.visual.blocks.18.mlp.linear_fc1",
|
| 112 |
+
"model.visual.blocks.18.mlp.linear_fc2",
|
| 113 |
+
"model.visual.blocks.19.attn.qkv",
|
| 114 |
+
"model.visual.blocks.19.attn.proj",
|
| 115 |
+
"model.visual.blocks.19.mlp.linear_fc1",
|
| 116 |
+
"model.visual.blocks.19.mlp.linear_fc2",
|
| 117 |
+
"model.visual.blocks.20.attn.qkv",
|
| 118 |
+
"model.visual.blocks.20.attn.proj",
|
| 119 |
+
"model.visual.blocks.20.mlp.linear_fc1",
|
| 120 |
+
"model.visual.blocks.20.mlp.linear_fc2",
|
| 121 |
+
"model.visual.blocks.21.attn.qkv",
|
| 122 |
+
"model.visual.blocks.21.attn.proj",
|
| 123 |
+
"model.visual.blocks.21.mlp.linear_fc1",
|
| 124 |
+
"model.visual.blocks.21.mlp.linear_fc2",
|
| 125 |
+
"model.visual.blocks.22.attn.qkv",
|
| 126 |
+
"model.visual.blocks.22.attn.proj",
|
| 127 |
+
"model.visual.blocks.22.mlp.linear_fc1",
|
| 128 |
+
"model.visual.blocks.22.mlp.linear_fc2",
|
| 129 |
+
"model.visual.blocks.23.attn.qkv",
|
| 130 |
+
"model.visual.blocks.23.attn.proj",
|
| 131 |
+
"model.visual.blocks.23.mlp.linear_fc1",
|
| 132 |
+
"model.visual.blocks.23.mlp.linear_fc2",
|
| 133 |
+
"model.visual.blocks.24.attn.qkv",
|
| 134 |
+
"model.visual.blocks.24.attn.proj",
|
| 135 |
+
"model.visual.blocks.24.mlp.linear_fc1",
|
| 136 |
+
"model.visual.blocks.24.mlp.linear_fc2",
|
| 137 |
+
"model.visual.blocks.25.attn.qkv",
|
| 138 |
+
"model.visual.blocks.25.attn.proj",
|
| 139 |
+
"model.visual.blocks.25.mlp.linear_fc1",
|
| 140 |
+
"model.visual.blocks.25.mlp.linear_fc2",
|
| 141 |
+
"model.visual.blocks.26.attn.qkv",
|
| 142 |
+
"model.visual.blocks.26.attn.proj",
|
| 143 |
+
"model.visual.blocks.26.mlp.linear_fc1",
|
| 144 |
+
"model.visual.blocks.26.mlp.linear_fc2",
|
| 145 |
+
"model.visual.merger.linear_fc1",
|
| 146 |
+
"model.visual.merger.linear_fc2",
|
| 147 |
+
"model.language_model.layers.0.linear_attn.in_proj_b",
|
| 148 |
+
"model.language_model.layers.0.linear_attn.in_proj_a",
|
| 149 |
+
"model.language_model.layers.1.linear_attn.in_proj_b",
|
| 150 |
+
"model.language_model.layers.1.linear_attn.in_proj_a",
|
| 151 |
+
"model.language_model.layers.2.linear_attn.in_proj_b",
|
| 152 |
+
"model.language_model.layers.2.linear_attn.in_proj_a",
|
| 153 |
+
"model.language_model.layers.4.linear_attn.in_proj_b",
|
| 154 |
+
"model.language_model.layers.4.linear_attn.in_proj_a",
|
| 155 |
+
"model.language_model.layers.5.linear_attn.in_proj_b",
|
| 156 |
+
"model.language_model.layers.5.linear_attn.in_proj_a",
|
| 157 |
+
"model.language_model.layers.6.linear_attn.in_proj_b",
|
| 158 |
+
"model.language_model.layers.6.linear_attn.in_proj_a",
|
| 159 |
+
"model.language_model.layers.8.linear_attn.in_proj_b",
|
| 160 |
+
"model.language_model.layers.8.linear_attn.in_proj_a",
|
| 161 |
+
"model.language_model.layers.9.linear_attn.in_proj_b",
|
| 162 |
+
"model.language_model.layers.9.linear_attn.in_proj_a",
|
| 163 |
+
"model.language_model.layers.10.linear_attn.in_proj_b",
|
| 164 |
+
"model.language_model.layers.10.linear_attn.in_proj_a",
|
| 165 |
+
"model.language_model.layers.12.linear_attn.in_proj_b",
|
| 166 |
+
"model.language_model.layers.12.linear_attn.in_proj_a",
|
| 167 |
+
"model.language_model.layers.13.linear_attn.in_proj_b",
|
| 168 |
+
"model.language_model.layers.13.linear_attn.in_proj_a",
|
| 169 |
+
"model.language_model.layers.14.linear_attn.in_proj_b",
|
| 170 |
+
"model.language_model.layers.14.linear_attn.in_proj_a",
|
| 171 |
+
"model.language_model.layers.16.linear_attn.in_proj_b",
|
| 172 |
+
"model.language_model.layers.16.linear_attn.in_proj_a",
|
| 173 |
+
"model.language_model.layers.17.linear_attn.in_proj_b",
|
| 174 |
+
"model.language_model.layers.17.linear_attn.in_proj_a",
|
| 175 |
+
"model.language_model.layers.18.linear_attn.in_proj_b",
|
| 176 |
+
"model.language_model.layers.18.linear_attn.in_proj_a",
|
| 177 |
+
"model.language_model.layers.20.linear_attn.in_proj_b",
|
| 178 |
+
"model.language_model.layers.20.linear_attn.in_proj_a",
|
| 179 |
+
"model.language_model.layers.21.linear_attn.in_proj_b",
|
| 180 |
+
"model.language_model.layers.21.linear_attn.in_proj_a",
|
| 181 |
+
"model.language_model.layers.22.linear_attn.in_proj_b",
|
| 182 |
+
"model.language_model.layers.22.linear_attn.in_proj_a",
|
| 183 |
+
"model.language_model.layers.24.linear_attn.in_proj_b",
|
| 184 |
+
"model.language_model.layers.24.linear_attn.in_proj_a",
|
| 185 |
+
"model.language_model.layers.25.linear_attn.in_proj_b",
|
| 186 |
+
"model.language_model.layers.25.linear_attn.in_proj_a",
|
| 187 |
+
"model.language_model.layers.26.linear_attn.in_proj_b",
|
| 188 |
+
"model.language_model.layers.26.linear_attn.in_proj_a",
|
| 189 |
+
"model.language_model.layers.28.linear_attn.in_proj_b",
|
| 190 |
+
"model.language_model.layers.28.linear_attn.in_proj_a",
|
| 191 |
+
"model.language_model.layers.29.linear_attn.in_proj_b",
|
| 192 |
+
"model.language_model.layers.29.linear_attn.in_proj_a",
|
| 193 |
+
"model.language_model.layers.30.linear_attn.in_proj_b",
|
| 194 |
+
"model.language_model.layers.30.linear_attn.in_proj_a",
|
| 195 |
+
"lm_head"
|
| 196 |
+
],
|
| 197 |
+
"quantized_params": 6912212992,
|
| 198 |
+
"total_params_hf_loaded": 9412959856,
|
| 199 |
+
"fraction_params_quantized": 0.7343,
|
| 200 |
+
"quant_cfg": [
|
| 201 |
+
{
|
| 202 |
+
"quantizer_name": "*",
|
| 203 |
+
"enable": false
|
| 204 |
+
},
|
| 205 |
+
{
|
| 206 |
+
"quantizer_name": "*weight_quantizer",
|
| 207 |
+
"cfg": {
|
| 208 |
+
"num_bits": [
|
| 209 |
+
2,
|
| 210 |
+
1
|
| 211 |
+
],
|
| 212 |
+
"effective_bits": 4.5,
|
| 213 |
+
"block_sizes": {
|
| 214 |
+
"-1": 16,
|
| 215 |
+
"type": "dynamic",
|
| 216 |
+
"scale_bits": [
|
| 217 |
+
4,
|
| 218 |
+
3
|
| 219 |
+
]
|
| 220 |
+
}
|
| 221 |
+
}
|
| 222 |
+
},
|
| 223 |
+
{
|
| 224 |
+
"quantizer_name": "*input_quantizer",
|
| 225 |
+
"cfg": {
|
| 226 |
+
"num_bits": [
|
| 227 |
+
2,
|
| 228 |
+
1
|
| 229 |
+
],
|
| 230 |
+
"effective_bits": 4.5,
|
| 231 |
+
"block_sizes": {
|
| 232 |
+
"-1": 16,
|
| 233 |
+
"type": "dynamic",
|
| 234 |
+
"scale_bits": [
|
| 235 |
+
4,
|
| 236 |
+
3
|
| 237 |
+
]
|
| 238 |
+
}
|
| 239 |
+
}
|
| 240 |
+
},
|
| 241 |
+
{
|
| 242 |
+
"quantizer_name": "*gdn_state_quantizer",
|
| 243 |
+
"enable": false
|
| 244 |
+
},
|
| 245 |
+
{
|
| 246 |
+
"quantizer_name": "*gdn_w_quantizer",
|
| 247 |
+
"enable": false
|
| 248 |
+
},
|
| 249 |
+
{
|
| 250 |
+
"quantizer_name": "*block_sparse_moe.gate*",
|
| 251 |
+
"enable": false
|
| 252 |
+
},
|
| 253 |
+
{
|
| 254 |
+
"quantizer_name": "*linear_attn.conv1d*",
|
| 255 |
+
"enable": false
|
| 256 |
+
},
|
| 257 |
+
{
|
| 258 |
+
"quantizer_name": "*self_attention.conv1d*",
|
| 259 |
+
"enable": false
|
| 260 |
+
},
|
| 261 |
+
{
|
| 262 |
+
"quantizer_name": "*linear_attn.in_proj_a*",
|
| 263 |
+
"enable": false
|
| 264 |
+
},
|
| 265 |
+
{
|
| 266 |
+
"quantizer_name": "*linear_attn.in_proj_b*",
|
| 267 |
+
"enable": false
|
| 268 |
+
},
|
| 269 |
+
{
|
| 270 |
+
"quantizer_name": "*lm_head*",
|
| 271 |
+
"enable": false
|
| 272 |
+
},
|
| 273 |
+
{
|
| 274 |
+
"quantizer_name": "*mixer.conv1d*",
|
| 275 |
+
"enable": false
|
| 276 |
+
},
|
| 277 |
+
{
|
| 278 |
+
"quantizer_name": "*mlp.gate.*",
|
| 279 |
+
"enable": false
|
| 280 |
+
},
|
| 281 |
+
{
|
| 282 |
+
"quantizer_name": "*mlp.shared_expert_gate.*",
|
| 283 |
+
"enable": false
|
| 284 |
+
},
|
| 285 |
+
{
|
| 286 |
+
"quantizer_name": "*output_layer*",
|
| 287 |
+
"enable": false
|
| 288 |
+
},
|
| 289 |
+
{
|
| 290 |
+
"quantizer_name": "*proj_out.*",
|
| 291 |
+
"enable": false
|
| 292 |
+
},
|
| 293 |
+
{
|
| 294 |
+
"quantizer_name": "*router*",
|
| 295 |
+
"enable": false
|
| 296 |
+
},
|
| 297 |
+
{
|
| 298 |
+
"quantizer_name": "mtp.*",
|
| 299 |
+
"enable": false
|
| 300 |
+
},
|
| 301 |
+
{
|
| 302 |
+
"quantizer_name": "output.*",
|
| 303 |
+
"enable": false
|
| 304 |
+
},
|
| 305 |
+
{
|
| 306 |
+
"quantizer_name": "*embed_vision*",
|
| 307 |
+
"enable": false
|
| 308 |
+
},
|
| 309 |
+
{
|
| 310 |
+
"quantizer_name": "*vision_tower*",
|
| 311 |
+
"enable": false
|
| 312 |
+
},
|
| 313 |
+
{
|
| 314 |
+
"quantizer_name": "*visual*",
|
| 315 |
+
"enable": false
|
| 316 |
+
},
|
| 317 |
+
{
|
| 318 |
+
"quantizer_name": "*vision_model*",
|
| 319 |
+
"enable": false
|
| 320 |
+
},
|
| 321 |
+
{
|
| 322 |
+
"quantizer_name": "*multi_modal_projector*",
|
| 323 |
+
"enable": false
|
| 324 |
+
},
|
| 325 |
+
{
|
| 326 |
+
"quantizer_name": "*",
|
| 327 |
+
"parent_class": "nn.BatchNorm1d",
|
| 328 |
+
"enable": false
|
| 329 |
+
},
|
| 330 |
+
{
|
| 331 |
+
"quantizer_name": "*",
|
| 332 |
+
"parent_class": "nn.BatchNorm2d",
|
| 333 |
+
"enable": false
|
| 334 |
+
},
|
| 335 |
+
{
|
| 336 |
+
"quantizer_name": "*",
|
| 337 |
+
"parent_class": "nn.BatchNorm3d",
|
| 338 |
+
"enable": false
|
| 339 |
+
},
|
| 340 |
+
{
|
| 341 |
+
"quantizer_name": "*",
|
| 342 |
+
"parent_class": "nn.LeakyReLU",
|
| 343 |
+
"enable": false
|
| 344 |
+
},
|
| 345 |
+
{
|
| 346 |
+
"quantizer_name": "*",
|
| 347 |
+
"parent_class": "nn.Embedding",
|
| 348 |
+
"enable": false
|
| 349 |
+
},
|
| 350 |
+
{
|
| 351 |
+
"quantizer_name": "*lm_head*",
|
| 352 |
+
"enable": false
|
| 353 |
+
},
|
| 354 |
+
{
|
| 355 |
+
"quantizer_name": "*visual*",
|
| 356 |
+
"enable": false
|
| 357 |
+
},
|
| 358 |
+
{
|
| 359 |
+
"quantizer_name": "*vision*",
|
| 360 |
+
"enable": false
|
| 361 |
+
},
|
| 362 |
+
{
|
| 363 |
+
"quantizer_name": "*mtp*",
|
| 364 |
+
"enable": false
|
| 365 |
+
},
|
| 366 |
+
{
|
| 367 |
+
"quantizer_name": "*in_proj_a*",
|
| 368 |
+
"enable": false
|
| 369 |
+
},
|
| 370 |
+
{
|
| 371 |
+
"quantizer_name": "*in_proj_b*",
|
| 372 |
+
"enable": false
|
| 373 |
+
},
|
| 374 |
+
{
|
| 375 |
+
"quantizer_name": "*mhc_*",
|
| 376 |
+
"enable": false
|
| 377 |
+
},
|
| 378 |
+
{
|
| 379 |
+
"quantizer_name": "*embed_tokens*",
|
| 380 |
+
"enable": false
|
| 381 |
+
},
|
| 382 |
+
{
|
| 383 |
+
"quantizer_name": "*conv1d*",
|
| 384 |
+
"enable": false
|
| 385 |
+
}
|
| 386 |
+
],
|
| 387 |
+
"fakequant_logits_finite": true,
|
| 388 |
+
"export_seconds": 140.7
|
| 389 |
+
}
|
quantization/requirements-quant.lock
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
accelerate==1.15.0
|
| 2 |
+
aiohappyeyeballs==2.7.1
|
| 3 |
+
aiohttp==3.14.5
|
| 4 |
+
aiosignal==1.4.0
|
| 5 |
+
annotated-doc==0.0.5
|
| 6 |
+
annotated-types==0.8.0
|
| 7 |
+
anyio==4.15.1
|
| 8 |
+
attrs==26.1.0
|
| 9 |
+
certifi==2026.10.23
|
| 10 |
+
charset-normalizer==3.5.2
|
| 11 |
+
click==8.5.0
|
| 12 |
+
cloudpickle==3.1.2
|
| 13 |
+
cuda-bindings==13.4.4
|
| 14 |
+
cuda-pathfinder==1.8.4
|
| 15 |
+
cuda-toolkit==13.0.2
|
| 16 |
+
datasets==5.1.0
|
| 17 |
+
deepspeed==0.19.9
|
| 18 |
+
defusedxml==0.7.1
|
| 19 |
+
diffusers==0.42.1
|
| 20 |
+
dill==0.4.1
|
| 21 |
+
einops==0.8.2
|
| 22 |
+
filelock==4.2.4
|
| 23 |
+
frozenlist==1.8.0
|
| 24 |
+
fsspec==2026.7.0
|
| 25 |
+
h11==0.16.0
|
| 26 |
+
hf-xet==1.8.0
|
| 27 |
+
hjson==3.1.0
|
| 28 |
+
httpcore==1.0.9
|
| 29 |
+
httpcore2==2.16.0
|
| 30 |
+
httpx==0.28.1
|
| 31 |
+
httpx2==2.16.0
|
| 32 |
+
huggingface-hub==2.4.0
|
| 33 |
+
idna==3.20
|
| 34 |
+
importlib-metadata==10.1.0
|
| 35 |
+
jinja2==3.1.6
|
| 36 |
+
joblib==1.6.0
|
| 37 |
+
markdown-it-py==4.2.0
|
| 38 |
+
markupsafe==3.0.3
|
| 39 |
+
mdurl==0.1.2
|
| 40 |
+
mpmath==1.3.0
|
| 41 |
+
msgpack==1.2.4
|
| 42 |
+
multidict==7.2.1
|
| 43 |
+
multiprocess==0.70.19
|
| 44 |
+
networkx==3.7
|
| 45 |
+
ninja==1.13.2
|
| 46 |
+
nltk==3.10.4
|
| 47 |
+
numpy==2.5.4
|
| 48 |
+
nvidia-cublas==13.1.0.3
|
| 49 |
+
nvidia-cuda-cccl==13.3.4.3.1
|
| 50 |
+
nvidia-cuda-cupti==13.0.85
|
| 51 |
+
nvidia-cuda-nvrtc==13.0.88
|
| 52 |
+
nvidia-cuda-runtime==13.0.96
|
| 53 |
+
nvidia-cudnn-cu13==9.19.0.56
|
| 54 |
+
nvidia-cufft==12.0.0.61
|
| 55 |
+
nvidia-cufile==1.15.1.6
|
| 56 |
+
nvidia-curand==10.4.0.35
|
| 57 |
+
nvidia-cusolver==12.0.4.66
|
| 58 |
+
nvidia-cusparse==12.6.3.3
|
| 59 |
+
nvidia-cusparselt-cu13==0.8.0
|
| 60 |
+
nvidia-ml-py==13.615.71
|
| 61 |
+
nvidia-modelopt==0.48.0rc1
|
| 62 |
+
nvidia-nccl-cu13==2.28.9
|
| 63 |
+
nvidia-nvjitlink==13.0.88
|
| 64 |
+
nvidia-nvshmem-cu13==3.4.5
|
| 65 |
+
nvidia-nvtx==13.0.85
|
| 66 |
+
omegaconf==2.4.0
|
| 67 |
+
packaging==26.3
|
| 68 |
+
pandas==3.1.0
|
| 69 |
+
peft==0.21.2
|
| 70 |
+
pillow==13.0.0
|
| 71 |
+
propcache==0.5.4
|
| 72 |
+
psutil==7.2.2
|
| 73 |
+
pulp==3.3.2
|
| 74 |
+
py-cpuinfo==9.0.0
|
| 75 |
+
pyarrow==26.0.0
|
| 76 |
+
pydantic==2.14.2
|
| 77 |
+
pydantic-core==2.50.2
|
| 78 |
+
pygments==2.21.0
|
| 79 |
+
python-dateutil==3.0.0
|
| 80 |
+
pyyaml==6.0.3
|
| 81 |
+
regex==2026.9.29
|
| 82 |
+
requests==2.34.2
|
| 83 |
+
rich==15.0.0
|
| 84 |
+
safetensors==0.8.0
|
| 85 |
+
scipy==1.18.1
|
| 86 |
+
sentencepiece==0.2.2
|
| 87 |
+
setuptools==81.0.0
|
| 88 |
+
shellingham==1.5.4
|
| 89 |
+
six==1.17.0
|
| 90 |
+
sympy==1.14.0
|
| 91 |
+
tiktoken==0.14.0
|
| 92 |
+
tokenizers==0.23.3
|
| 93 |
+
torch==2.11.0+cu130
|
| 94 |
+
torchvision==0.26.0+cu130
|
| 95 |
+
tqdm==4.70.1
|
| 96 |
+
transformers==5.18.0
|
| 97 |
+
triton==3.6.0
|
| 98 |
+
truststore==0.10.5
|
| 99 |
+
typer==0.27.3
|
| 100 |
+
typing-extensions==4.16.0
|
| 101 |
+
typing-inspection==0.4.4
|
| 102 |
+
tzdata==2026.6
|
| 103 |
+
urllib3==2.8.0
|
| 104 |
+
wonderwords==3.0.1
|
| 105 |
+
xxhash==4.0.2
|
| 106 |
+
yarl==1.25.1
|
| 107 |
+
zipp==4.1.2
|