ngquocvinh commited on
Commit
fa21ea6
·
verified ·
1 Parent(s): 1e27cba

Publish final card checksums and reproducibility manifests

Browse files
LICENSE ADDED
@@ -0,0 +1,209 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Original Qwen model:
191
+ Copyright 2026 Alibaba Cloud
192
+
193
+ Fine-tuning and repackaging modifications:
194
+ Copyright 2026 TokenRhythm
195
+
196
+ NeoHorse-1-4B is based on Qwen/Qwen3.5-4B and was modified
197
+ by TokenRhythm through fine-tuning and repackaging.
198
+
199
+ Licensed under the Apache License, Version 2.0 (the "License");
200
+ you may not use this file except in compliance with the License.
201
+ You may obtain a copy of the License at
202
+
203
+ http://www.apache.org/licenses/LICENSE-2.0
204
+
205
+ Unless required by applicable law or agreed to in writing, software
206
+ distributed under the License is distributed on an "AS IS" BASIS,
207
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
208
+ See the License for the specific language governing permissions and
209
+ limitations under the License.
README.md CHANGED
@@ -27,10 +27,9 @@ I build and test these releases myself. Your coffee helps keep me going.<br>
27
  Thank you for supporting this work.
28
  </div>
29
 
30
- > **Status:** Source lock, direct BF16 conversion, and a CPU chat smoke test
31
- > passed. GPU calibration, the quantization ladder, hold-out evaluation, and
32
- > final artifact smoke tests are still in progress. Files will be listed only
33
- > after direct-from-BF16 conversion and runtime validation pass.
34
 
35
  ## About NeoHorse-1-4B
36
 
@@ -40,40 +39,100 @@ See the [official upstream model card](https://huggingface.co/TokenRhythm/NeoHor
40
 
41
  These releases change the storage format through GGUF quantization only. No training or fine-tuning was performed here.
42
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  ## Fidelity measurements
44
 
45
- This section will be completed after a fixed hold-out evaluation against the
46
- BF16 GGUF reference. Until then, this page makes no quality or “best
47
- quantization” claim.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
 
49
  ## Quick start
50
 
51
- After a published GGUF file appears in this repository:
52
 
53
  ```bash
54
  ./llama-cli \
55
- -m <published-file>.gguf \
56
- --chat-template-file chat_template.jinja \
57
  --jinja \
58
  --reasoning off \
59
  -p 'Answer briefly in English: What is GGUF and why is it useful for running language models locally?' \
60
  -n 128 -c 4096 -ngl 99
61
  ```
62
 
63
- The exact filename, runtime validation profile, and supported features will be updated with the release artifacts.
 
64
 
65
  ## Reproducibility and validation
66
 
67
- The locked upstream revision is `56f0584bb40578a2c33b1b40a08ccd17243ad710`.
68
- The direct BF16 conversion has completed and a deterministic CPU chat smoke
69
- test passed with the llama.cpp runtime. The final package will document the
70
- BF16 source hash, model-specific importance matrix hash, converter/runtime
71
- revision, quantization commands, artifact checksums, and load/generate
72
- validation. Detailed build and evaluation logs remain local; compact manifests
73
- and summaries will be added here as the release progresses.
 
 
 
 
74
 
75
  ## License and attribution
76
 
77
- NeoHorse-1-4B is released upstream under the Apache License 2.0. The upstream license and attribution notices will be included with the GGUF package.
 
78
 
79
  These are community GGUF quantizations, not an official TokenRhythm release or endorsement.
 
27
  Thank you for supporting this work.
28
  </div>
29
 
30
+ > **Status:** Complete release. The nine GGUF files below were quantized
31
+ > directly from the locked upstream BF16 snapshot, loaded/generated on GPU 0,
32
+ > and checked against held-out next-token fidelity measurements.
 
33
 
34
  ## About NeoHorse-1-4B
35
 
 
39
 
40
  These releases change the storage format through GGUF quantization only. No training or fine-tuning was performed here.
41
 
42
+ ## Quantized files
43
+
44
+ `Q5_K_M` is the balanced starting point from this evaluation. Use `Q6_K` or
45
+ `Q8_0` when fidelity is more important than size; `Q4_K_M` is the smaller
46
+ practical option. `Q3_K_M` and below are included for experimentation, but the
47
+ hold-out results show a substantial fidelity drop. `IQ1_M` and `Q1_0` are
48
+ compatibility-only options here and are not recommended for normal use.
49
+
50
+ | File | Size (bytes) | Evaluation note |
51
+ |---|---:|---|
52
+ | `NeoHorse-1-4B-Q8_0.gguf` | 4482403104 | closest conventional quant |
53
+ | `NeoHorse-1-4B-Q6_K.gguf` | 3464055872 | high-fidelity option |
54
+ | `NeoHorse-1-4B-Q5_K_M.gguf` | 3074987072 | balanced starting point |
55
+ | `NeoHorse-1-4B-Q4_K_M.gguf` | 2708804672 | smaller practical option |
56
+ | `NeoHorse-1-4B-Q3_K_M.gguf` | 2262064192 | experimental; larger drift |
57
+ | `NeoHorse-1-4B-Q2_K.gguf` | 1915470912 | experimental; large drift |
58
+ | `NeoHorse-1-4B-IQ2_XS.gguf` | 1630594112 | experimental; large drift |
59
+ | `NeoHorse-1-4B-IQ1_M.gguf` | 1426418752 | compatibility-only |
60
+ | `NeoHorse-1-4B-Q1_0.gguf` | 1038189632 | compatibility-only |
61
+
62
  ## Fidelity measurements
63
 
64
+ The table averages eight chunks from each of `wiki.test.raw` and
65
+ `wiki.valid.raw`, using a 4,096-token context and the same llama.cpp runtime
66
+ against the BF16 GGUF reference. The average BF16 PPL in this evaluation was
67
+ 8.635307. Lower Mean KLD, ΔPPL, and RMS Δp, and higher Top-1 agreement, indicate
68
+ closer next-token behavior to BF16. These are fidelity measurements, not a
69
+ direct percentage of capabilities retained.
70
+
71
+ | File | Mean KLD | Top-1 vs BF16 | ΔPPL | RMS Δp |
72
+ |---|---:|---:|---:|---:|
73
+ | `NeoHorse-1-4B-Q8_0.gguf` | 0.006291 | 98.065% | +0.192% | 2.041% |
74
+ | `NeoHorse-1-4B-Q6_K.gguf` | 0.010910 | 96.751% | +0.831% | 2.881% |
75
+ | `NeoHorse-1-4B-Q5_K_M.gguf` | 0.032008 | 94.498% | +1.706% | 4.631% |
76
+ | `NeoHorse-1-4B-Q4_K_M.gguf` | 0.055031 | 91.909% | +1.339% | 5.920% |
77
+ | `NeoHorse-1-4B-Q3_K_M.gguf` | 0.160972 | 85.173% | +11.466% | 10.610% |
78
+ | `NeoHorse-1-4B-Q2_K.gguf` | 0.348854 | 76.007% | +12.720% | 16.212% |
79
+ | `NeoHorse-1-4B-IQ2_XS.gguf` | 0.517311 | 70.662% | +32.407% | 20.489% |
80
+ | `NeoHorse-1-4B-IQ1_M.gguf` | 1.303395 | 54.895% | +168.381% | 32.950% |
81
+ | `NeoHorse-1-4B-Q1_0.gguf` | 12.339880 | 0.406% | +18400566.679% | 60.432% |
82
+
83
+ The fixed hold-out corpus is disjoint from the calibration inputs. See the
84
+ [compact quality summary](reproducibility/quality-summary.tsv) and the
85
+ [reproducibility manifest](reproducibility/manifest.md) for the exact split,
86
+ hashes, and runtime profile.
87
+
88
+ ## Behavior and runtime validation
89
+
90
+ BF16 baseline probes covered English, Vietnamese, Chinese, coding, plain JSON,
91
+ and the upstream-style tool-call text format. Those probes generated usable
92
+ responses for the tested prompts. The strict llama.cpp `--json-schema` probe
93
+ failed during runtime sampler initialization and is recorded as a runtime
94
+ compatibility limitation, not counted as a model capability result. The
95
+ tool-call probe tested serialization format only; it was not an end-to-end tool
96
+ executor test.
97
+
98
+ BF16 and every published quantization loaded and generated non-empty output on
99
+ one NVIDIA A10M using the same GPU-0 profile. Low-bit files can pass this
100
+ compatibility gate while still producing poor responses; the fidelity table is
101
+ why Q3 and lower are marked experimental.
102
 
103
  ## Quick start
104
 
105
+ For the balanced starting point:
106
 
107
  ```bash
108
  ./llama-cli \
109
+ -m NeoHorse-1-4B-Q5_K_M.gguf \
 
110
  --jinja \
111
  --reasoning off \
112
  -p 'Answer briefly in English: What is GGUF and why is it useful for running language models locally?' \
113
  -n 128 -c 4096 -ngl 99
114
  ```
115
 
116
+ The GGUF contains the converted chat template. Reduce `-ngl` or the context
117
+ size if the available VRAM is smaller.
118
 
119
  ## Reproducibility and validation
120
 
121
+ The locked upstream revision is
122
+ `56f0584bb40578a2c33b1b40a08ccd17243ad710`. The BF16 source GGUF SHA256 is
123
+ `10aae5451e1c0b6089b25f68cfe32cd32a4bdcb92e30008e083e6ba351f3cbd8`; the
124
+ NeoHorse-specific combined imatrix SHA256 is
125
+ `8c66b45b73826b0b00fdd973d308d8f81f7db0f8a3b97cf93bc7813d722d6515`.
126
+
127
+ The package includes [SHA256SUMS.txt](SHA256SUMS.txt), the
128
+ [quantization manifest](reproducibility/quantization-manifest.tsv), source and
129
+ calibration manifests, the runtime version, and the copied upstream chat
130
+ template. Detailed conversion, quantization, smoke, behavior, and fidelity
131
+ logs remain local under `reports/neohorse-1-4b/` and are not uploaded.
132
 
133
  ## License and attribution
134
 
135
+ NeoHorse-1-4B is released upstream under the Apache License 2.0. The upstream
136
+ license and attribution notices are included in `LICENSE`.
137
 
138
  These are community GGUF quantizations, not an official TokenRhythm release or endorsement.
SHA256SUMS.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ 9b756eefd6ef534bf23ee3d62eb1b7e404ab4a21d8681a35791a0e39b76f17d0 NeoHorse-1-4B-Q8_0.gguf
2
+ 3af3f1981b8bc0a1fd205b011dc17cd02d5a479e89d35d77b8c20f5e6f0d70d5 NeoHorse-1-4B-Q6_K.gguf
3
+ 71b5e86dc409e1a5b17db34040f7df8dcd11688f27f6134d1c8595069ffe57fe NeoHorse-1-4B-Q5_K_M.gguf
4
+ 5669ad48af5d54a29ed78aed77d2f2e2b921a8aca68c5482696bc8713cf8248b NeoHorse-1-4B-Q4_K_M.gguf
5
+ ef8b4386a54ec1d25024aeae5e5a1c976748bf2bd525c8cdc68edbec68a936f9 NeoHorse-1-4B-Q3_K_M.gguf
6
+ 834bef5dfdbbd2545b2fac9dd46a75c08beab8803a1636fd459cbe27729d8154 NeoHorse-1-4B-Q2_K.gguf
7
+ a77f44a832a5978e4ce921c183cb07a80faa380fe4a8c22b0ba3a57699a34982 NeoHorse-1-4B-IQ2_XS.gguf
8
+ eccb688df4b1c1387bee976db5972fe766d4a9007d3983132957587387efc0bb NeoHorse-1-4B-IQ1_M.gguf
9
+ 9ab2feb77d3ac44677468d32142804df8346b41dc644ff95d0358d868a40aba0 NeoHorse-1-4B-Q1_0.gguf
reproducibility/calibration-manifest.md ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Calibration manifest
2
+
3
+ The importance matrix is model-specific and was collected from the BF16 GGUF.
4
+ WikiText validation and test files were held out.
5
+
6
+ | Input | SHA256 | Collection |
7
+ |---|---|---|
8
+ | `neohorse_en_vi_zh_code_agent.txt` | `235ed59cfc43beeaee7a0787273ff6586829b3ecf19189f4567fe57f64a03c3a` | context 512, requested 4 chunks, 3 collected |
9
+ | `wiki.train.raw` | `6707892fa3788b5ab9ed78ab5ff37d9fe825f6011a2ad4fcd6a6d467f0e7da57` | context 4096, 96 chunks |
10
+ | `wiki.valid.raw` | `4cd0f6876d07a413aa911261ff6d363c72d757d47f0fdd6015702014c89cb9c7` | hold-out only |
11
+ | `wiki.test.raw` | `173c87a53759e0201f33e0ccf978e510c2042d7f2cb78229d9a50d79b9e7dd08` | hold-out only |
12
+
13
+ Commands, with paths relative to the workspace root:
14
+
15
+ ```bash
16
+ CUDA_VISIBLE_DEVICES=0 llama-imatrix \
17
+ -m source-official-bf16-neohorse-1-4b/NeoHorse-1-4B-BF16.gguf \
18
+ -f calibration/neohorse-1-4b/neohorse_en_vi_zh_code_agent.txt \
19
+ -o calibration/neohorse-1-4b/NeoHorse-1-4B-custom.imatrix.gguf \
20
+ -c 512 -b 512 -ub 512 --chunks 4 --no-ppl --parse-special \
21
+ -ngl all --device CUDA0 --split-mode none --main-gpu 0 \
22
+ --fit on --fit-target 1024 -t 64 -tb 64
23
+
24
+ CUDA_VISIBLE_DEVICES=0 llama-imatrix \
25
+ -m source-official-bf16-neohorse-1-4b/NeoHorse-1-4B-BF16.gguf \
26
+ -f calibration/wikitext-2-raw/wiki.train.raw \
27
+ -o calibration/neohorse-1-4b/NeoHorse-1-4B-wikitext-train.imatrix.gguf \
28
+ -c 4096 -b 512 -ub 512 --chunks 96 --no-ppl \
29
+ -ngl all --device CUDA0 --split-mode none --main-gpu 0 \
30
+ --fit on --fit-target 1024 -t 64 -tb 64
31
+
32
+ llama-imatrix -m source-official-bf16-neohorse-1-4b/NeoHorse-1-4B-BF16.gguf \
33
+ --device none -ngl 0 \
34
+ --in-file calibration/neohorse-1-4b/NeoHorse-1-4B-custom.imatrix.gguf,calibration/neohorse-1-4b/NeoHorse-1-4B-wikitext-train.imatrix.gguf \
35
+ -o calibration/neohorse-1-4b/NeoHorse-1-4B-combined.imatrix.gguf
36
+ ```
37
+
38
+ The combined imatrix SHA256 is
39
+ `8c66b45b73826b0b00fdd973d308d8f81f7db0f8a3b97cf93bc7813d722d6515`.
reproducibility/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 %}
reproducibility/manifest.md ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # NeoHorse-1-4B GGUF reproducibility manifest
2
+
3
+ ## Source
4
+
5
+ - Upstream repository: `TokenRhythm/NeoHorse-1-4B`
6
+ - Locked revision: `56f0584bb40578a2c33b1b40a08ccd17243ad710`
7
+ - Source format: upstream BF16 safetensors
8
+ - Architecture: `qwen3_5_text` / `Qwen3_5ForCausalLM`
9
+ - Source BF16 GGUF: `NeoHorse-1-4B-BF16.gguf`
10
+ - Source BF16 GGUF SHA256:
11
+ `10aae5451e1c0b6089b25f68cfe32cd32a4bdcb92e30008e083e6ba351f3cbd8`
12
+ - Conversion used `--outtype bf16 --no-nextn`; the source index contains no
13
+ `mtp`/`nextn` tensors even though the upstream config advertises one MTP
14
+ layer.
15
+ - The converter preserved the upstream text-only model and embedded its chat
16
+ template. It did not modify source weights or the upstream config.
17
+
18
+ ## Importance matrix
19
+
20
+ - Combined imatrix: `NeoHorse-1-4B-combined.imatrix.gguf`
21
+ - Combined imatrix SHA256:
22
+ `8c66b45b73826b0b00fdd973d308d8f81f7db0f8a3b97cf93bc7813d722d6515`
23
+ - Input datasets: the model-specific multilingual/code/agent calibration text
24
+ and `wiki.train.raw`; neither WikiText validation nor test text was used.
25
+ - The custom run used context 512 and four requested chunks (three available
26
+ chunks were collected). The WikiText run used context 4096 and 96 chunks.
27
+ The combined file reports 771 normalized chunks because the input matrices
28
+ use different context sizes.
29
+ - Calibration input hashes and commands are in `calibration-manifest.md`.
30
+
31
+ ## Quantization
32
+
33
+ Each published file was quantized directly from the BF16 GGUF with the Spark
34
+ llama.cpp `llama-quantize` binary. `Q8_0` used no imatrix; every lower rung used
35
+ the combined NeoHorse imatrix. The ladder order was:
36
+
37
+ `Q8_0 -> Q6_K -> Q5_K_M -> Q4_K_M -> Q3_K_M -> Q2_K -> IQ2_XS -> IQ1_M -> Q1_0`
38
+
39
+ Exact commands and artifact hashes are in `quantization-manifest.tsv` and
40
+ `SHA256SUMS.txt`.
41
+
42
+ ## Runtime validation
43
+
44
+ - Runtime repository: `tools-llama.cpp-spark`
45
+ - Runtime commit: `4a3635c32fc9f044c2bde9ebeabf50c7e1ec5991`
46
+ - Runtime version: `0.1.2-dev (build 1, commit 4a3635c)`
47
+ - GPU validation: one NVIDIA A10M, process-local `CUDA_VISIBLE_DEVICES=0`,
48
+ `--device CUDA0`, `--split-mode none`, `--fit on`, fit target 1024 MiB,
49
+ Flash Attention on, context 4096, 64 threads.
50
+ - BF16 and every published GGUF loaded and generated non-empty output using
51
+ the same profile. Low-bit smoke output is not a quality guarantee.
52
+ - The pre-existing GPU 0 service was stopped only for the GPU jobs and
53
+ restored after validation; the GPU 1 service remained running.
54
+
55
+ ## Fidelity evaluation
56
+
57
+ The compact results are in `quality-summary.tsv`. They average eight chunks
58
+ from each of `wiki.test.raw` and `wiki.valid.raw`, context 4096, against the
59
+ BF16 reference using the same runtime. These are next-token fidelity metrics,
60
+ not a direct percentage of capabilities retained.
61
+
62
+ Raw conversion, quantization, smoke, behavior, and fidelity logs remain local
63
+ under `reports/neohorse-1-4b/` and are intentionally excluded from this public
64
+ package.
reproducibility/quality-summary.tsv ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ model mean_kld top1_percent mean_ppl mean_ppl_base ppl_delta_percent p_diff_rms_percent
2
+ Q8_0 0.006291 98.065 8.651847 8.635307 0.192 2.041
3
+ Q6_K 0.010910 96.751 8.707086 8.635307 0.831 2.881
4
+ Q5_K_M 0.032008 94.498 8.782643 8.635307 1.706 4.631
5
+ Q4_K_M 0.055031 91.909 8.750954 8.635307 1.339 5.920
6
+ Q3_K_M 0.160972 85.173 9.625402 8.635307 11.466 10.610
7
+ Q2_K 0.348854 76.007 9.733700 8.635307 12.720 16.212
8
+ IQ2_XS 0.517311 70.662 11.433729 8.635307 32.407 20.489
9
+ IQ1_M 1.303395 54.895 23.175517 8.635307 168.381 32.950
10
+ Q1_0 12.339880 0.406 1588953.965748 8.635307 18400566.679 60.432
reproducibility/quantization-manifest.tsv ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ file type bytes sha256 imatrix direct_source runtime_smoke
2
+ NeoHorse-1-4B-Q8_0.gguf Q8_0 4482403104 9b756eefd6ef534bf23ee3d62eb1b7e404ab4a21d8681a35791a0e39b76f17d0 no NeoHorse-1-4B-BF16.gguf pass
3
+ NeoHorse-1-4B-Q6_K.gguf Q6_K 3464055872 3af3f1981b8bc0a1fd205b011dc17cd02d5a479e89d35d77b8c20f5e6f0d70d5 NeoHorse-1-4B-combined.imatrix.gguf NeoHorse-1-4B-BF16.gguf pass
4
+ NeoHorse-1-4B-Q5_K_M.gguf Q5_K_M 3074987072 71b5e86dc409e1a5b17db34040f7df8dcd11688f27f6134d1c8595069ffe57fe NeoHorse-1-4B-combined.imatrix.gguf NeoHorse-1-4B-BF16.gguf pass
5
+ NeoHorse-1-4B-Q4_K_M.gguf Q4_K_M 2708804672 5669ad48af5d54a29ed78aed77d2f2e2b921a8aca68c5482696bc8713cf8248b NeoHorse-1-4B-combined.imatrix.gguf NeoHorse-1-4B-BF16.gguf pass
6
+ NeoHorse-1-4B-Q3_K_M.gguf Q3_K_M 2262064192 ef8b4386a54ec1d25024aeae5e5a1c976748bf2bd525c8cdc68edbec68a936f9 NeoHorse-1-4B-combined.imatrix.gguf NeoHorse-1-4B-BF16.gguf pass
7
+ NeoHorse-1-4B-Q2_K.gguf Q2_K 1915470912 834bef5dfdbbd2545b2fac9dd46a75c08beab8803a1636fd459cbe27729d8154 NeoHorse-1-4B-combined.imatrix.gguf NeoHorse-1-4B-BF16.gguf pass
8
+ NeoHorse-1-4B-IQ2_XS.gguf IQ2_XS 1630594112 a77f44a832a5978e4ce921c183cb07a80faa380fe4a8c22b0ba3a57699a34982 NeoHorse-1-4B-combined.imatrix.gguf NeoHorse-1-4B-BF16.gguf pass
9
+ NeoHorse-1-4B-IQ1_M.gguf IQ1_M 1426418752 eccb688df4b1c1387bee976db5972fe766d4a9007d3983132957587387efc0bb NeoHorse-1-4B-combined.imatrix.gguf NeoHorse-1-4B-BF16.gguf pass
10
+ NeoHorse-1-4B-Q1_0.gguf Q1_0 1038189632 9ab2feb77d3ac44677468d32142804df8346b41dc644ff95d0358d868a40aba0 NeoHorse-1-4B-combined.imatrix.gguf NeoHorse-1-4B-BF16.gguf pass
reproducibility/runtime-version.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ runtime_repo=tools-llama.cpp-spark
2
+ runtime_commit=4a3635c32fc9f044c2bde9ebeabf50c7e1ec5991
3
+ runtime_version=0.1.2-dev (build 1, commit 4a3635c)
4
+ converter=tools-llama.cpp-spark/convert_hf_to_gguf.py
5
+ converter_options=--outtype bf16 --no-nextn --model-name NeoHorse-1-4B
6
+ quantizer=tools-llama.cpp-spark/build/bin/llama-quantize
7
+ perplexity=tools-llama.cpp-spark/build/bin/llama-perplexity
8
+ chat_runtime=tools-llama.cpp-spark/build/bin/llama-cli
9
+ gpu_validation=NVIDIA A10M physical GPU 0; CUDA_VISIBLE_DEVICES=0; GPU 1 service left running
reproducibility/source-manifest.md ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Source manifest
2
+
3
+ Upstream revision: `56f0584bb40578a2c33b1b40a08ccd17243ad710`
4
+
5
+ | File | SHA256 |
6
+ |---|---|
7
+ | `model-00001-of-00002.safetensors` | `d7f64e7920d47e76bac3296b58e90e7902e3c686f4fb4891303ab832c898bcc3` |
8
+ | `model-00002-of-00002.safetensors` | `36292efc411eb9580ada5f14a792712dd8a4d9e9657812d070d2d0435a64b9f5` |
9
+ | `model.safetensors.index.json` | `315b36f21026e93b74552e5755ec9a52ab6232de8c54f0ecb34fc00a50c7a20a` |
10
+ | `config.json` | `e80a48542cf4dfbd60f19d3fea5a8a6f89e1c7fa65c992fea572aeeaa906b29c` |
11
+ | `tokenizer.json` | `5f9e4d4901a92b997e463c1f46055088b6cca5ca61a6522d1b9f64c4bb81cb42` |
12
+ | `tokenizer_config.json` | `316230d6a809701f4db5ea8f8fc862bc3a6f3229c937c174e674ff3ca0a64ac8` |
13
+ | `chat_template.jinja` | `a4aee8afcf2e0711942cf848899be66016f8d14a889ff9ede07bca099c28f715` |
14
+ | `LICENSE` | `c2c9ab53cedffada40bb3d5ccf733f931fdabb3ee0759e7a7e1eb30d42112df9` |
15
+
16
+ Converted BF16 GGUF SHA256:
17
+ `10aae5451e1c0b6089b25f68cfe32cd32a4bdcb92e30008e083e6ba351f3cbd8`.
reproducibility/summarize_fidelity.py ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Summarize NeoHorse GGUF next-token fidelity across fixed hold-outs."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import re
8
+ from pathlib import Path
9
+
10
+
11
+ FLOAT = r"[-+]?\d+(?:\.\d+)?(?:[eE][-+]?\d+)?"
12
+
13
+
14
+ def value(text: str, pattern: str) -> float:
15
+ matches = re.findall(pattern, text)
16
+ if not matches:
17
+ raise ValueError(f"pattern not found: {pattern}")
18
+ return float(matches[-1])
19
+
20
+
21
+ def parse_log(path: Path) -> dict[str, float]:
22
+ text = path.read_text(errors="replace")
23
+ return {
24
+ "mean_kld": value(text, rf"Mean\s+KLD:\s*({FLOAT})"),
25
+ "top1_percent": value(text, rf"Same top p:\s*({FLOAT})"),
26
+ "mean_ppl": value(text, rf"Mean PPL\(Q\)\s*:\s*({FLOAT})"),
27
+ "mean_ppl_base": value(text, rf"Mean PPL\(base\)\s*:\s*({FLOAT})"),
28
+ "p_diff_rms_percent": value(
29
+ text, rf"RMS Δp\s*:\s*({FLOAT})(?:\s*±\s*{FLOAT})?\s*%"
30
+ ),
31
+ }
32
+
33
+
34
+ def main() -> None:
35
+ parser = argparse.ArgumentParser()
36
+ parser.add_argument("logdir", type=Path)
37
+ parser.add_argument("output", type=Path)
38
+ parser.add_argument("--chunks", type=int, default=8)
39
+ parser.add_argument("--splits", nargs="+", default=["test", "valid"])
40
+ parser.add_argument("--quants", nargs="+", required=True)
41
+ args = parser.parse_args()
42
+
43
+ args.output.parent.mkdir(parents=True, exist_ok=True)
44
+ with args.output.open("w", encoding="utf-8") as handle:
45
+ handle.write(
46
+ "model\tmean_kld\ttop1_percent\tmean_ppl\tmean_ppl_base\t"
47
+ "ppl_delta_percent\tp_diff_rms_percent\n"
48
+ )
49
+ for quant in args.quants:
50
+ records = [
51
+ parse_log(args.logdir / f"{quant}-{split}-chunks{args.chunks}.log")
52
+ for split in args.splits
53
+ ]
54
+ mean_kld = sum(r["mean_kld"] for r in records) / len(records)
55
+ top1 = sum(r["top1_percent"] for r in records) / len(records)
56
+ mean_ppl = sum(r["mean_ppl"] for r in records) / len(records)
57
+ mean_base = sum(r["mean_ppl_base"] for r in records) / len(records)
58
+ rms = sum(r["p_diff_rms_percent"] for r in records) / len(records)
59
+ delta = (mean_ppl / mean_base - 1.0) * 100.0
60
+ handle.write(
61
+ "\t".join(
62
+ (
63
+ quant,
64
+ f"{mean_kld:.6f}",
65
+ f"{top1:.3f}",
66
+ f"{mean_ppl:.6f}",
67
+ f"{mean_base:.6f}",
68
+ f"{delta:.3f}",
69
+ f"{rms:.3f}",
70
+ )
71
+ )
72
+ + "\n"
73
+ )
74
+ print(f"wrote {args.output} ({len(args.quants)} models)")
75
+
76
+
77
+ if __name__ == "__main__":
78
+ main()