kmamaroziqov commited on
Commit
f99a82c
·
verified ·
1 Parent(s): 074e8be

Match NeuronAI-4B card format with 2B evidence and Apache license

Browse files
.gitattributes CHANGED
@@ -35,3 +35,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
  tokenizer.json filter=lfs diff=lfs merge=lfs -text
37
  assets/suite_by_task.png filter=lfs diff=lfs merge=lfs -text
 
 
 
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
  tokenizer.json filter=lfs diff=lfs merge=lfs -text
37
  assets/suite_by_task.png filter=lfs diff=lfs merge=lfs -text
38
+ assets/checkpoint_selection.png filter=lfs diff=lfs merge=lfs -text
39
+ assets/tokenizer_fertility.png filter=lfs diff=lfs merge=lfs -text
LICENSE ADDED
@@ -0,0 +1,202 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
README.md CHANGED
@@ -1,19 +1,23 @@
1
  ---
2
  language:
3
- - uz
4
- - en
5
  license: apache-2.0
6
  library_name: transformers
7
  pipeline_tag: text-generation
8
  base_model: Qwen/Qwen3.5-2B-Base
9
  tags:
10
- - qwen3.5
11
- - uzbek
12
- - text-generation
13
- - conversational
14
- - axolotl
15
- - peft
16
- - lora
 
 
 
 
17
  ---
18
 
19
  # NeuronAI-2B
@@ -23,7 +27,11 @@ Qwen3.5-2B-Base. It combines an Uzbek tokenizer retrofit, continued pretraining,
23
  annealing, and assistant-only supervised fine-tuning. The published weights are
24
  fully merged—no LoRA adapter is needed.
25
 
26
- ![Strict eight-task benchmark comparison](assets/weighted_score.png)
 
 
 
 
27
 
28
  ## Quick start
29
 
@@ -42,7 +50,7 @@ tokenizer = AutoTokenizer.from_pretrained(model_id)
42
  model = AutoModelForCausalLM.from_pretrained(
43
  model_id,
44
  dtype=torch.bfloat16,
45
- device_map="cuda:0",
46
  ).eval()
47
 
48
  messages = [
@@ -58,7 +66,17 @@ inputs = tokenizer.apply_chat_template(
58
  ).to(model.device)
59
 
60
  with torch.inference_mode():
61
- output = model.generate(**inputs, max_new_tokens=256, do_sample=False)
 
 
 
 
 
 
 
 
 
 
62
 
63
  reply = tokenizer.decode(
64
  output[0, inputs["input_ids"].shape[1]:],
@@ -67,8 +85,12 @@ reply = tokenizer.decode(
67
  print(reply)
68
  ```
69
 
70
- The generation metadata already registers `<|im_end|>` and `<|endoftext|>` as
71
- end-of-sequence tokens.
 
 
 
 
72
 
73
  ### Serve with vLLM
74
 
@@ -77,7 +99,11 @@ pip install -U vllm
77
  vllm serve NeuronUz/NeuronAI-2B \
78
  --dtype bfloat16 \
79
  --max-model-len 4096 \
 
 
 
80
  --language-model-only \
 
81
  --mamba-block-size 16 \
82
  --mamba-cache-mode align
83
  ```
@@ -85,86 +111,169 @@ vllm serve NeuronUz/NeuronAI-2B \
85
  ```bash
86
  curl http://localhost:8000/v1/chat/completions \
87
  -H "Content-Type: application/json" \
88
- -d '{"model":"NeuronUz/NeuronAI-2B","messages":[{"role":"user","content":"O‘zbekiston haqida uchta fakt ayting."}]}'
 
 
 
 
 
 
 
 
 
 
 
 
 
89
  ```
90
 
91
  ## Benchmarks
92
 
93
- The results below are recomputed from archived full-suite runs using the same
94
- eight tasks, COMET-primary scoring, and normalized task weights. Classification
95
- and multiple-choice tasks use accuracy; FLORES+ translation uses COMET. All
96
- format-scored NeuronAI-2B tasks had a 0% invalid-output rate.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
 
98
- ![Per-task comparison](assets/suite_by_task.png)
 
 
 
 
99
 
100
- | Benchmark | Metric | Weight | **NeuronAI-2B** | Qwen3.5-2B | alloma-3B | alloma-1B |
101
- | --- | --- | ---: | ---: | ---: | ---: | ---: |
102
- | UzLiB | accuracy | 0.20 | **49.60%** | 28.69% | 32.08% | 23.32% |
103
- | TUMLU-Uzbek | accuracy | 0.20 | **32.57%** | 31.29% | 27.71% | 22.00% |
104
- | FLORES+ en→uz | COMET | 0.15 | **0.8762** | 0.7010 | 0.8673 | 0.7383 |
105
- | Uzbek news | accuracy | 0.10 | **78.55%** | 36.75% | 13.60% | 25.41% |
106
- | MMLU English | accuracy | 0.10 | **54.07%** | 52.39% | 38.73% | 21.98% |
107
- | MMLU Uzbek | accuracy | 0.10 | **46.85%** | 37.10% | 32.74% | 21.11% |
108
- | FLORES+ uz→en | COMET | 0.05 | **0.8535** | 0.8072 | 0.7954 | 0.7636 |
109
- | Uzbek sentiment | accuracy | 0.05 | **95.50%** | 76.87% | 38.85% | 79.54% |
110
- | **Normalized weighted score** | | 1.00 | **0.5954** | 0.4528 | 0.4147 | 0.3661 |
111
-
112
- The archived runs came from three suite revisions, but every run computed COMET,
113
- allowing the table to use one scoring method. Alloma runs used the `APST`
114
- apostrophe preprocessing required by their model cards.
115
 
116
- ## Uzbek tokenizer efficiency
 
 
 
117
 
118
- The tokenizer is an in-place retrofit rather than a vocabulary extension:
119
- Uzbek merges replace low-value slots while the 248,044-token vocabulary and
120
- parameter count remain unchanged.
121
 
122
- ![Uzbek tokenizer fertility](assets/fertility_uzcrawl.png)
 
 
 
123
 
124
- | Tokenizer | Vocabulary | Tokens per word |
125
- | --- | ---: | ---: |
126
- | NeuronAI-2B | 248,044 | **2.407** |
127
- | Qwen3.5-2B | 248,044 | 3.426 |
128
 
129
- This measurement used 20,000 documents (4.8M whitespace words) sampled with
130
- seed 42 from `uz-crawl`. The retrofit uses about 30% fewer tokens on this
131
- in-domain Uzbek text. Fertility measures tokenization efficiency, not model
132
- quality or measured inference speed.
133
 
134
- ## Model lineage and training
 
 
 
 
 
 
 
135
 
136
- 1. `Qwen/Qwen3.5-2B-Base`
137
- 2. Uzbek tokenizer retrofit with embedding re-initialization
138
- 3. Uzbek continued pretraining
139
- 4. Instruction-data annealing
140
- 5. Assistant-only SFT with LoRA r64
141
- 6. LoRA merged into the model weights
142
 
143
- One epoch of assistant-only LoRA fine-tuning (rank 64, alpha 128) on 152,152
144
- Uzbek-first examples, using a 2,048-token context and effective batch size 32.
145
- Training data is not distributed with this model repository.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146
 
147
  ## Intended use
148
 
149
- Good fits include Uzbek research, education, prototyping, translation
150
- experiments, writing assistance, retrieval-augmented generation, and
151
- local/offline applications.
 
 
152
 
153
  ## Limitations
154
 
155
- - TUMLU-Uzbek remains close to the 0.25 random baseline and should not be
156
- treated as solved.
 
 
 
 
 
157
  - The model can hallucinate, repeat biases in its data, or produce unsafe or
158
  outdated content. It has not been comprehensively safety-evaluated.
159
  - Do not rely on it without expert review for medical, legal, financial, public
160
  safety, or other high-stakes decisions.
161
  - SFT used sequences up to 2,048 tokens; serving at longer inherited context
162
- lengths has not been validated here.
163
- - Use a recent Transformers or vLLM release with Qwen3.5 support. Keep the
164
- hybrid model on one device unless multi-device Gated-DeltaNet inference has
165
- been validated in your serving stack.
166
 
167
  ## License
168
 
169
  NeuronAI-2B is released under the
170
- [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0).
 
 
 
 
1
  ---
2
  language:
3
+ - uz
4
+ - en
5
  license: apache-2.0
6
  library_name: transformers
7
  pipeline_tag: text-generation
8
  base_model: Qwen/Qwen3.5-2B-Base
9
  tags:
10
+ - qwen3.5
11
+ - uzbek
12
+ - conversational
13
+ - translation
14
+ - text-generation-inference
15
+ datasets:
16
+ - HuggingFaceFW/fineweb-2
17
+ - tahrirchi/uz-books
18
+ - tahrirchi/uz-crawl
19
+ - HuggingFaceFW/fineweb-edu
20
+ - HuggingFaceTB/finemath
21
  ---
22
 
23
  # NeuronAI-2B
 
27
  annealing, and assistant-only supervised fine-tuning. The published weights are
28
  fully merged—no LoRA adapter is needed.
29
 
30
+ ![Strict eight-task benchmark comparison](assets/overall_score.png)
31
+
32
+ > **License:** [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0).
33
+ > Commercial and non-commercial use are permitted under the license terms. This
34
+ > differs from the NeuronAI-4B release, which is licensed for non-commercial use.
35
 
36
  ## Quick start
37
 
 
50
  model = AutoModelForCausalLM.from_pretrained(
51
  model_id,
52
  dtype=torch.bfloat16,
53
+ device_map={"": 0},
54
  ).eval()
55
 
56
  messages = [
 
66
  ).to(model.device)
67
 
68
  with torch.inference_mode():
69
+ output = model.generate(
70
+ **inputs,
71
+ max_new_tokens=1024,
72
+ do_sample=True,
73
+ temperature=0.7,
74
+ top_p=0.8,
75
+ top_k=20,
76
+ min_p=0.0,
77
+ repetition_penalty=1.0,
78
+ use_cache=True,
79
+ )
80
 
81
  reply = tokenizer.decode(
82
  output[0, inputs["input_ids"].shape[1]:],
 
85
  print(reply)
86
  ```
87
 
88
+ This is the recommended quality-oriented preset for general assistant use:
89
+ non-thinking mode with Qwen3.5's instruct sampling settings. Greedy decoding
90
+ can cause repetition and lower response quality; reserve `do_sample=False` for
91
+ deterministic evaluation or classification. The generation metadata already
92
+ registers `<|im_end|>` and `<|endoftext|>` as end-of-sequence tokens. Keep the
93
+ combined prompt and output within the validated 4,096-token serving limit.
94
 
95
  ### Serve with vLLM
96
 
 
99
  vllm serve NeuronUz/NeuronAI-2B \
100
  --dtype bfloat16 \
101
  --max-model-len 4096 \
102
+ --tensor-parallel-size 1 \
103
+ --generation-config vllm \
104
+ --default-chat-template-kwargs '{"enable_thinking":false}' \
105
  --language-model-only \
106
+ --enable-prefix-caching \
107
  --mamba-block-size 16 \
108
  --mamba-cache-mode align
109
  ```
 
111
  ```bash
112
  curl http://localhost:8000/v1/chat/completions \
113
  -H "Content-Type: application/json" \
114
+ -d '{
115
+ "model": "NeuronUz/NeuronAI-2B",
116
+ "messages": [
117
+ {"role": "user", "content": "O‘zbekiston haqida uchta fakt ayting."}
118
+ ],
119
+ "max_tokens": 1024,
120
+ "temperature": 0.7,
121
+ "top_p": 0.8,
122
+ "top_k": 20,
123
+ "min_p": 0.0,
124
+ "presence_penalty": 1.5,
125
+ "repetition_penalty": 1.0,
126
+ "chat_template_kwargs": {"enable_thinking": false}
127
+ }'
128
  ```
129
 
130
  ## Benchmarks
131
 
132
+ All five model result sets below cover the same full eight-task suite.
133
+ Classification and multiple-choice tasks use accuracy; FLORES+ translation
134
+ uses COMET. The weighted score is normalized by the 0.95 sum of the published
135
+ task weights. All eight NeuronAI-2B tasks completed and passed the
136
+ invalid-output gate.
137
+
138
+ ![Per-task comparison](assets/tasks_comparison.png)
139
+
140
+ | Benchmark | Metric | Weight | **NeuronAI-2B** | Qwen3.5-2B | alloma-8B | alloma-3B | alloma-1B |
141
+ | --- | --- | ---: | ---: | ---: | ---: | ---: | ---: |
142
+ | UzLiB | accuracy | 0.20 | **49.60%** | 28.69% | 42.40% | 32.08% | 23.32% |
143
+ | TUMLU-Uzbek | accuracy | 0.20 | **32.57%** | 31.29% | 20.71% | 27.71% | 22.00% |
144
+ | FLORES+ en→uz | COMET | 0.15 | 0.8762 | 0.7010 | **0.8779** | 0.8673 | 0.7383 |
145
+ | Uzbek news | accuracy | 0.10 | **78.55%** | 36.75% | 57.77% | 13.60% | 25.41% |
146
+ | MMLU English | accuracy | 0.10 | **54.07%** | 52.39% | 53.47% | 38.73% | 21.98% |
147
+ | MMLU Uzbek | accuracy | 0.10 | **46.85%** | 37.10% | 40.04% | 32.74% | 21.11% |
148
+ | FLORES+ uz→en | COMET | 0.05 | 0.8535 | 0.8072 | **0.8713** | 0.7954 | 0.7636 |
149
+ | Uzbek sentiment | accuracy | 0.05 | **95.50%** | 76.87% | 79.94% | 38.85% | 79.54% |
150
+ | **Normalized weighted score** | | 1.00 | **0.5954** | 0.4528 | 0.5187 | 0.4147 | 0.3661 |
151
+
152
+ Alloma runs used the `APST` apostrophe preprocessing required by their model
153
+ cards; NeuronAI and stock Qwen did not. The alloma-8B column combines its full
154
+ model-card-protocol evaluation with separately archived full UzLiB,
155
+ TUMLU-Uzbek, and MMLU-Uzbek runs. Exact source files, scores, and run IDs are
156
+ included in [`benchmark_results.json`](benchmark_results.json).
157
+
158
+ ### Run the benchmarks on your computer
159
+
160
+ The repository includes a portable Alloma-style benchmark runner. It covers
161
+ FLORES+ (both directions), Uzbek sentiment, Uzbek news, MMLU English, MMLU Uzbek,
162
+ and TUMLU-Uzbek.
163
 
164
+ ```bash
165
+ pip install -r https://huggingface.co/NeuronUz/NeuronAI-2B/resolve/main/benchmark-requirements.txt
166
+ wget https://huggingface.co/NeuronUz/NeuronAI-2B/resolve/main/benchmark.py
167
+ python benchmark.py --limit 200 --output quick-results.json
168
+ ```
169
 
170
+ The quick command uses the same seed on 200 examples per dataset. Run all public
171
+ examples and add COMET with:
 
 
 
 
 
 
 
 
 
 
 
 
 
172
 
173
+ ```bash
174
+ pip install unbabel-comet
175
+ python benchmark.py --limit 0 --comet --output full-results.json
176
+ ```
177
 
178
+ Run one task when you only need a short check:
 
 
179
 
180
+ ```bash
181
+ python benchmark.py --tasks mmlu-uz --limit 200 --output mmlu-uz.json
182
+ python benchmark.py --tasks flores --limit 200 --output flores.json
183
+ ```
184
 
185
+ `--limit 0` means the full dataset. Only full runs are comparable with the table
186
+ above; 200-example quick runs are sanity checks. COMET downloads the
187
+ `Unbabel/wmt22-comet-da` evaluator and needs additional disk/RAM.
 
188
 
189
+ ## Uzbek tokenizer efficiency
 
 
 
190
 
191
+ The tokenizer is an in-place, primarily **Latin-script Uzbek** retrofit rather
192
+ than a vocabulary extension. The initial 20,000-document figure was measured on
193
+ training-source `uz-crawl`, so we replaced it with a larger corpus-stratified
194
+ test: 118,832 held-out-source documents plus a separate 100,000-document
195
+ training-source control. Documents were selected with deterministic SHA-256
196
+ bottom-k sampling (seed `20260825`), exact duplicates were excluded from the
197
+ selected sample, tiny texts were filtered, and raw source text was tokenized
198
+ without apostrophe normalization.
199
 
200
+ ![Uzbek tokenizer fertility](assets/tokenizer_fertility.png)
 
 
 
 
 
201
 
202
+ | Corpus | Status | Documents | Words | NeuronAI-2B | Qwen3.5-2B | Reduction (95% CI) |
203
+ | --- | --- | ---: | ---: | ---: | ---: | ---: |
204
+ | Community OSCAR Uzbek | Held-out web source | 100,000 | 7,618,770 | **2.0304** | 3.3639 | **39.64%** (39.57–39.71%) |
205
+ | Uzbek legal corpus | Held-out legal source/domain | 18,832 | 2,534,566 | **2.3747** | 2.9705 | **20.06%** (19.55–20.57%) |
206
+ | uz-crawl | Training-source control | 100,000 | 20,825,680 | **2.3206** | 3.3224 | **30.15%** (30.02–30.30%) |
207
+
208
+ Across the two held-out sources combined, the tokenizer uses **35.19%
209
+ fewer tokens overall** and **40.90% fewer tokens on Latin-dominant text**,
210
+ matching its intended Latin-Uzbek focus.
211
+
212
+ The paired intervals use 5,000 bootstrap replicates over 1,000 deterministic
213
+ document buckets. OSCAR may still have incidental overlap with other public web
214
+ corpora and was previously checked in a post-hoc weak-token coverage analysis,
215
+ but it contributed no tokenizer-training rows. The legal corpus does not appear
216
+ in the tokenizer or training source manifests and is the cleanest
217
+ source-and-domain holdout in this test. Full results and script/length
218
+ breakdowns: [`fertility_large_20260825.json`](fertility_large_20260825.json) and
219
+ [`fertility_large_20260825.md`](fertility_large_20260825.md).
220
+
221
+ Fertility measures tokenization efficiency—not model quality or measured
222
+ decoding speed. The evaluated 2B and 4B custom tokenizer files are byte-identical,
223
+ as are their evaluated stock-base tokenizer files; SHA-256 fingerprints are
224
+ recorded in the JSON result.
225
+
226
+ ## Training
227
+
228
+ | Item | Value |
229
+ | --- | --- |
230
+ | Parameters | 1,881,825,088 (1.882B) |
231
+ | Prepared train examples | 151,968 (152,152 source rows) |
232
+ | Prepared grouped dev examples | 1,535 (1,537 source rows) |
233
+ | Train/dev prompt-group overlap | 0 |
234
+ | Sequence length / packing | 2,048 / disabled |
235
+ | Training duration / seed | 1 epoch / 42 |
236
+ | Batch size | 16 micro × 2 accumulation × 1 GPU = 32 effective |
237
+ | Optimizer | Fused AdamW; betas 0.9/0.95; weight decay 0.01; gradient clipping 1.0 |
238
+ | Learning-rate schedule | Peak 1e-4; cosine decay; 142 warmup steps (2.99%) |
239
+ | LoRA | rank 64, alpha 128, dropout 0.05; 12 projection types; 67,276,800 trainable parameters |
240
+ | Loss | Fused causal-LM cross-entropy on assistant-response tokens; prompt tokens masked |
241
+ | Precision | bf16 training with TF32; merged embeddings and normalization tensors retained in fp32 |
242
+
243
+ The mixture is Uzbek-first and includes general assistant conversations,
244
+ translation, Uzbek language and literature, spelling, classification, math,
245
+ and English-retention examples. Training data is not distributed with this
246
+ model repository.
247
 
248
  ## Intended use
249
 
250
+ Good fits include Uzbek research, education, commercial and non-commercial
251
+ prototyping, translation experiments, writing assistance, retrieval-augmented
252
+ generation, and local/offline applications. Users remain responsible for
253
+ validating the model for their application and complying with the Apache 2.0
254
+ license and applicable law.
255
 
256
  ## Limitations
257
 
258
+ - This is a public-suite-selected checkpoint. The benchmark results are useful
259
+ for reproducibility and relative comparison, but they are not a locked,
260
+ independent estimate of real-world generalization.
261
+ - LoRA rank, learning rate, batch size, and dropout were not exhaustively swept;
262
+ the table reports the released run, not globally optimal hyperparameters.
263
+ - TUMLU-Uzbek is the weakest reported Uzbek task and should not be treated as
264
+ solved at 32.57% accuracy.
265
  - The model can hallucinate, repeat biases in its data, or produce unsafe or
266
  outdated content. It has not been comprehensively safety-evaluated.
267
  - Do not rely on it without expert review for medical, legal, financial, public
268
  safety, or other high-stakes decisions.
269
  - SFT used sequences up to 2,048 tokens; serving at longer inherited context
270
+ lengths has not been validated here. The published inference examples use
271
+ 4,096 tokens.
 
 
272
 
273
  ## License
274
 
275
  NeuronAI-2B is released under the
276
+ [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). Commercial
277
+ and non-commercial use, modification, and distribution are permitted subject
278
+ to its terms. This summary does not replace the license text; see
279
+ [`LICENSE`](LICENSE).
assets/{suite_by_task.png → checkpoint_selection.png} RENAMED
File without changes
assets/fertility_uzcrawl.png DELETED
Binary file (65.6 kB)
 
assets/overall_score.png ADDED
assets/tasks_comparison.png ADDED
assets/tokenizer_fertility.png ADDED

Git LFS Details

  • SHA256: 76a79c18e4543030376916640642ab759515245ea9132a65f9fb9bba468a05e6
  • Pointer size: 131 Bytes
  • Size of remote file: 161 kB
assets/weighted_score.png DELETED
Binary file (65.2 kB)
 
benchmark-requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ torch
2
+ transformers>=5.1
3
+ accelerate
4
+ datasets
5
+ sacrebleu
6
+ vllm
7
+
8
+ # Optional, only for `python benchmark.py --comet`:
9
+ # unbabel-comet
benchmark.py ADDED
@@ -0,0 +1,355 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Portable NeuronAI-2B / Alloma-style Uzbek benchmark runner.
3
+
4
+ Examples:
5
+ python benchmark.py --limit 200 --output quick-results.json
6
+ python benchmark.py --limit 0 --comet --output full-results.json
7
+
8
+ `--limit 0` evaluates every example. The default 200-example run is a quick,
9
+ deterministically sampled sanity check and must not be compared with the full
10
+ scores in the model card.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import argparse
16
+ import json
17
+ import re
18
+ from datetime import datetime, timezone
19
+ from pathlib import Path
20
+
21
+ import torch
22
+ from datasets import concatenate_datasets, load_dataset
23
+ from transformers import AutoModelForCausalLM, AutoTokenizer
24
+
25
+
26
+ MODEL_ID = "NeuronUz/NeuronAI-2B"
27
+ LETTERS = "ABCD"
28
+
29
+ TRANSLATION_PROMPTS = {
30
+ "uz-en": (
31
+ "Translate each Uzbek sentence into English.\n\n"
32
+ "1991-yilning 1-sentabrida O'zbekiston mustaqilligini e'lon qildi.\n"
33
+ "-> On 1 September 1991, Uzbekistan declared its independence.\n\n"
34
+ "Tadqiqotchilar yangi usul samaradorligi 47 foizga oshganini aniqladilar.\n"
35
+ "-> Researchers found that the new method improved efficiency by 47 percent.\n\n"
36
+ "{text}\n->"
37
+ ),
38
+ "en-uz": "Translate into Uzbek:\n\n{text}",
39
+ }
40
+
41
+ SENTIMENT_PROMPT = (
42
+ "Given the following Uzbek text, determine the sentiment as either "
43
+ "'Positive' or 'Negative'. Respond with only one label.\n\nText: {text}\n\nLabel:"
44
+ )
45
+
46
+ NEWS_PROMPT = """Classify the given Uzbek news article into one category. Respond with only the category number.
47
+
48
+ 0 - Siyosat
49
+ 1 - Iqtisodiyot
50
+ 2 - Texnologiya
51
+ 3 - Sport
52
+ 4 - Madaniyat
53
+ 5 - Salomatlik
54
+ 6 - Oila va Jamiyat
55
+ 7 - Ta'lim
56
+ 8 - Ekologiya
57
+ 9 - Xorijiy Yangiliklar
58
+
59
+ Article: {text}
60
+
61
+ Answer:"""
62
+
63
+ MCQ_SUFFIX = {
64
+ "uz": "Variantlarni diqqat bilan solishtiring. Javobni A, B, C yoki D harfi bilan boshlang.",
65
+ "en": "Compare the options carefully. Start with the answer letter A, B, C, or D.",
66
+ }
67
+
68
+ MCQ_TASKS = {
69
+ "mmlu-en": ("cais/mmlu", "all", "test", "en"),
70
+ "mmlu-uz": ("murodbek/MMLU-uz", "default", "test", "uz"),
71
+ "tumlu": ("jafarisbarov/TUMLU-mini", "uzbek", "test", "uz"),
72
+ }
73
+
74
+
75
+ def choose_rows(dataset, limit: int, seed: int):
76
+ if limit and len(dataset) > limit:
77
+ return dataset.shuffle(seed=seed).select(range(limit))
78
+ return dataset
79
+
80
+
81
+ def strip_thinking(text: str) -> str:
82
+ return re.sub(r"<think>.*?</think>", "", text, flags=re.DOTALL).strip()
83
+
84
+
85
+ class Generator:
86
+ def __init__(self, args: argparse.Namespace):
87
+ self.backend = args.backend
88
+ self.tokenizer = AutoTokenizer.from_pretrained(args.model, trust_remote_code=True)
89
+ self.tokenizer.padding_side = "left"
90
+ if self.tokenizer.pad_token_id is None:
91
+ self.tokenizer.pad_token_id = self.tokenizer.eos_token_id
92
+
93
+ if args.backend == "vllm":
94
+ from vllm import LLM, SamplingParams
95
+
96
+ self.sampling_cls = SamplingParams
97
+ self.model = LLM(
98
+ model=args.model,
99
+ dtype=args.dtype,
100
+ trust_remote_code=True,
101
+ gpu_memory_utilization=args.gpu_memory_utilization,
102
+ max_model_len=args.max_model_len,
103
+ language_model_only=True,
104
+ mamba_block_size=16,
105
+ mamba_cache_mode="align",
106
+ )
107
+ else:
108
+ dtype = torch.bfloat16 if args.dtype == "bfloat16" else torch.float16
109
+ self.model = AutoModelForCausalLM.from_pretrained(
110
+ args.model,
111
+ dtype=dtype,
112
+ device_map="auto",
113
+ trust_remote_code=True,
114
+ ).eval()
115
+
116
+ def render(self, prompt: str) -> str:
117
+ messages = [{"role": "user", "content": prompt}]
118
+ try:
119
+ return self.tokenizer.apply_chat_template(
120
+ messages,
121
+ tokenize=False,
122
+ add_generation_prompt=True,
123
+ enable_thinking=False,
124
+ )
125
+ except TypeError:
126
+ return self.tokenizer.apply_chat_template(
127
+ messages, tokenize=False, add_generation_prompt=True
128
+ )
129
+
130
+ def generate(self, prompts: list[str], max_new_tokens: int, batch_size: int) -> list[str]:
131
+ rendered = [self.render(prompt) for prompt in prompts]
132
+ if self.backend == "vllm":
133
+ params = self.sampling_cls(temperature=0.0, max_tokens=max_new_tokens)
134
+ outputs = self.model.generate(rendered, params)
135
+ return [strip_thinking(item.outputs[0].text) for item in outputs]
136
+
137
+ results: list[str] = []
138
+ for start in range(0, len(rendered), batch_size):
139
+ batch = rendered[start : start + batch_size]
140
+ encoded = self.tokenizer(
141
+ batch,
142
+ return_tensors="pt",
143
+ padding=True,
144
+ truncation=True,
145
+ max_length=4096,
146
+ ).to(self.model.device)
147
+ prompt_width = encoded["input_ids"].shape[1]
148
+ with torch.inference_mode():
149
+ output = self.model.generate(
150
+ **encoded,
151
+ max_new_tokens=max_new_tokens,
152
+ do_sample=False,
153
+ )
154
+ results.extend(
155
+ strip_thinking(text)
156
+ for text in self.tokenizer.batch_decode(
157
+ output[:, prompt_width:], skip_special_tokens=True
158
+ )
159
+ )
160
+ return results
161
+
162
+
163
+ def load_flores(direction: str, limit: int, seed: int) -> list[dict[str, str]]:
164
+ langs = {"uz-en": ("uzn_Latn", "eng_Latn"), "en-uz": ("eng_Latn", "uzn_Latn")}
165
+ src_lang, ref_lang = langs[direction]
166
+ src = concatenate_datasets([
167
+ load_dataset("openlanguagedata/flores_plus", src_lang, split="dev"),
168
+ load_dataset("openlanguagedata/flores_plus", src_lang, split="devtest"),
169
+ ])
170
+ ref = concatenate_datasets([
171
+ load_dataset("openlanguagedata/flores_plus", ref_lang, split="dev"),
172
+ load_dataset("openlanguagedata/flores_plus", ref_lang, split="devtest"),
173
+ ])
174
+ pairs = [
175
+ {"src": src[index]["text"].strip(), "ref": ref[index]["text"].strip()}
176
+ for index in range(min(len(src), len(ref)))
177
+ ]
178
+ if limit and len(pairs) > limit:
179
+ import random
180
+
181
+ random.Random(seed).shuffle(pairs)
182
+ pairs = pairs[:limit]
183
+ return pairs
184
+
185
+
186
+ def score_comet(sources: list[str], hypotheses: list[str], references: list[str]) -> float:
187
+ from comet import download_model, load_from_checkpoint
188
+
189
+ checkpoint = download_model("Unbabel/wmt22-comet-da")
190
+ model = load_from_checkpoint(checkpoint)
191
+ rows = [
192
+ {"src": src, "mt": hypothesis, "ref": reference}
193
+ for src, hypothesis, reference in zip(sources, hypotheses, references, strict=True)
194
+ ]
195
+ return float(model.predict(rows, batch_size=8, gpus=1 if torch.cuda.is_available() else 0).system_score)
196
+
197
+
198
+ def evaluate_flores(generator: Generator, args: argparse.Namespace) -> dict:
199
+ import sacrebleu
200
+
201
+ results = {}
202
+ for direction in ("uz-en", "en-uz"):
203
+ pairs = load_flores(direction, args.limit, args.seed)
204
+ prompts = [TRANSLATION_PROMPTS[direction].format(text=row["src"]) for row in pairs]
205
+ hypotheses = generator.generate(prompts, max_new_tokens=160, batch_size=args.batch_size)
206
+ references = [row["ref"] for row in pairs]
207
+ sources = [row["src"] for row in pairs]
208
+ row = {
209
+ "total": len(pairs),
210
+ "bleu": float(sacrebleu.corpus_bleu(hypotheses, [references]).score),
211
+ "samples": [
212
+ {"source": src, "prediction": hyp, "reference": ref}
213
+ for src, hyp, ref in zip(sources[:3], hypotheses[:3], references[:3])
214
+ ],
215
+ }
216
+ if args.comet:
217
+ row["comet"] = score_comet(sources, hypotheses, references)
218
+ results[direction] = row
219
+ print(f"FLORES+ {direction}: BLEU={row['bleu']:.2f}" + (f", COMET={row['comet']:.4f}" if args.comet else ""))
220
+ return results
221
+
222
+
223
+ def label_to_int(raw, names: list[str]) -> int | None:
224
+ if isinstance(raw, int) and 0 <= raw < len(names):
225
+ return raw
226
+ cleaned = str(raw).strip().casefold().replace("’", "'")
227
+ for index, name in enumerate(names):
228
+ if cleaned == name.casefold():
229
+ return index
230
+ return None
231
+
232
+
233
+ def evaluate_classification(generator: Generator, args: argparse.Namespace, task: str) -> dict:
234
+ if task == "sentiment":
235
+ dataset = load_dataset("behbudiy/uzbek-sentiment-analysis", split="train")
236
+ names = ["Negative", "Positive"]
237
+ rows = [
238
+ {"text": row["text"], "gold": label_to_int(row["label"], names)}
239
+ for row in choose_rows(dataset, args.limit, args.seed)
240
+ ]
241
+ prompt_template = SENTIMENT_PROMPT
242
+ parser = lambda text: 1 if text.casefold().startswith("positive") else (0 if text.casefold().startswith("negative") else None)
243
+ else:
244
+ dataset = load_dataset("risqaliyevds/uzbek-zero-shot-classification", split="train")
245
+ names = ["Siyosat", "Iqtisodiyot", "Texnologiya", "Sport", "Madaniyat",
246
+ "Salomatlik", "Oila va Jamiyat", "Ta'lim", "Ekologiya", "Xorijiy Yangiliklar"]
247
+ rows = [
248
+ {"text": row["text"], "gold": label_to_int(row["class"], names)}
249
+ for row in choose_rows(dataset, args.limit, args.seed)
250
+ ]
251
+ prompt_template = NEWS_PROMPT
252
+ parser = lambda text: int(match.group()) if (match := re.search(r"\d", text)) else None
253
+
254
+ rows = [row for row in rows if row["gold"] is not None]
255
+ prompts = [prompt_template.format(text=row["text"][: args.max_text_chars]) for row in rows]
256
+ outputs = generator.generate(prompts, max_new_tokens=8, batch_size=args.batch_size)
257
+ predictions = [parser(output.strip()) for output in outputs]
258
+ correct = sum(prediction == row["gold"] for prediction, row in zip(predictions, rows, strict=True))
259
+ invalid = sum(prediction is None for prediction in predictions)
260
+ result = {
261
+ "accuracy": correct / len(rows),
262
+ "correct": correct,
263
+ "total": len(rows),
264
+ "invalid_rate": invalid / len(rows),
265
+ }
266
+ print(f"{task}: accuracy={result['accuracy']:.2%} ({correct}/{len(rows)}), invalid={invalid}")
267
+ return result
268
+
269
+
270
+ def answer_letter(raw) -> str | None:
271
+ if isinstance(raw, int) and 0 <= raw < 4:
272
+ return LETTERS[raw]
273
+ cleaned = str(raw).strip().upper()
274
+ return cleaned[0] if cleaned and cleaned[0] in LETTERS else None
275
+
276
+
277
+ def evaluate_mcq(generator: Generator, args: argparse.Namespace, task: str) -> dict:
278
+ dataset_name, config, split, language = MCQ_TASKS[task]
279
+ dataset = choose_rows(load_dataset(dataset_name, config, split=split), args.limit, args.seed)
280
+ rows = []
281
+ for row in dataset:
282
+ choices = row.get("choices") or [row.get(f"option_{letter.lower()}") for letter in LETTERS]
283
+ choices = [str(choice) for choice in choices if choice is not None]
284
+ gold = answer_letter(row.get("answer"))
285
+ if row.get("question") and len(choices) >= 4 and gold:
286
+ rows.append({"question": row["question"], "choices": choices[:4], "gold": gold})
287
+ prompts = []
288
+ for row in rows:
289
+ choices = "\n".join(f"{letter}) {choice}" for letter, choice in zip(LETTERS, row["choices"]))
290
+ prompts.append(f"{row['question']}\n\n{choices}\n\n{MCQ_SUFFIX[language]}")
291
+ outputs = generator.generate(prompts, max_new_tokens=12, batch_size=args.batch_size)
292
+ predictions = []
293
+ for output in outputs:
294
+ match = re.search(r"[ABCD]", output.upper())
295
+ predictions.append(match.group() if match else None)
296
+ correct = sum(prediction == row["gold"] for prediction, row in zip(predictions, rows, strict=True))
297
+ invalid = sum(prediction is None for prediction in predictions)
298
+ result = {
299
+ "accuracy": correct / len(rows),
300
+ "correct": correct,
301
+ "total": len(rows),
302
+ "invalid_rate": invalid / len(rows),
303
+ }
304
+ print(f"{task}: accuracy={result['accuracy']:.2%} ({correct}/{len(rows)}), invalid={invalid}")
305
+ return result
306
+
307
+
308
+ def parse_args() -> argparse.Namespace:
309
+ parser = argparse.ArgumentParser(description=__doc__)
310
+ parser.add_argument("--model", default=MODEL_ID)
311
+ parser.add_argument("--tasks", default="flores,sentiment,news,mmlu-en,mmlu-uz,tumlu")
312
+ parser.add_argument("--backend", choices=["vllm", "transformers"], default="vllm")
313
+ parser.add_argument("--limit", type=int, default=200, help="Examples per dataset; 0 means full dataset.")
314
+ parser.add_argument("--batch-size", type=int, default=16)
315
+ parser.add_argument("--max-text-chars", type=int, default=4000)
316
+ parser.add_argument("--max-model-len", type=int, default=4096)
317
+ parser.add_argument("--gpu-memory-utilization", type=float, default=0.85)
318
+ parser.add_argument("--dtype", choices=["bfloat16", "float16"], default="bfloat16")
319
+ parser.add_argument("--seed", type=int, default=42)
320
+ parser.add_argument("--comet", action="store_true", help="Download WMT22-COMET-DA and score FLORES+.")
321
+ parser.add_argument("--output", type=Path, default=Path("neuronai-2b-benchmark.json"))
322
+ return parser.parse_args()
323
+
324
+
325
+ def main() -> None:
326
+ args = parse_args()
327
+ if args.limit < 0:
328
+ raise ValueError("--limit must be 0 or greater")
329
+ tasks = {task.strip() for task in args.tasks.split(",") if task.strip()}
330
+ unknown = tasks - {"flores", "sentiment", "news", *MCQ_TASKS}
331
+ if unknown:
332
+ raise ValueError(f"Unknown tasks: {sorted(unknown)}")
333
+ generator = Generator(args)
334
+ results = {
335
+ "model": args.model,
336
+ "timestamp": datetime.now(timezone.utc).isoformat(timespec="seconds"),
337
+ "limit_per_dataset": args.limit,
338
+ "seed": args.seed,
339
+ "backend": args.backend,
340
+ "results": {},
341
+ }
342
+ if "flores" in tasks:
343
+ results["results"]["flores"] = evaluate_flores(generator, args)
344
+ for task in ("sentiment", "news"):
345
+ if task in tasks:
346
+ results["results"][task] = evaluate_classification(generator, args, task)
347
+ for task in MCQ_TASKS:
348
+ if task in tasks:
349
+ results["results"][task] = evaluate_mcq(generator, args, task)
350
+ args.output.write_text(json.dumps(results, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
351
+ print(f"Wrote {args.output}")
352
+
353
+
354
+ if __name__ == "__main__":
355
+ main()
benchmark_results.json ADDED
@@ -0,0 +1,264 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "schema_version": 1,
3
+ "metric_note": "Accuracy for non-translation tasks; COMET for FLORES+; weighted sum normalized by 0.95.",
4
+ "weights": {
5
+ "uzlib_slice_full": 0.2,
6
+ "tumlu_uzbek_full": 0.2,
7
+ "flores_en_uz_full": 0.15,
8
+ "news_full": 0.1,
9
+ "mmlu_english_full": 0.1,
10
+ "mmlu_uz_full": 0.1,
11
+ "flores_uz_en_full": 0.05,
12
+ "sentiment_binary_full": 0.05
13
+ },
14
+ "labels": {
15
+ "uzlib_slice_full": "UzLiB",
16
+ "tumlu_uzbek_full": "TUMLU-Uzbek",
17
+ "flores_en_uz_full": "FLORES+ en to uz",
18
+ "news_full": "News",
19
+ "mmlu_english_full": "MMLU English",
20
+ "mmlu_uz_full": "MMLU Uzbek",
21
+ "flores_uz_en_full": "FLORES+ uz to en",
22
+ "sentiment_binary_full": "Sentiment"
23
+ },
24
+ "models": {
25
+ "NeuronAI-2B": {
26
+ "run_id": "qwen35_2b_lora_r64_grouped_identity_ckpt4749_public_v2",
27
+ "suite_id": "public_uzbek_full_comet_vllm_v2",
28
+ "tasks": {
29
+ "uzlib_slice_full": 0.4959699086512628,
30
+ "tumlu_uzbek_full": 0.32571428571428573,
31
+ "flores_en_uz_full": 0.8761537177251785,
32
+ "news_full": 0.7854903578426318,
33
+ "mmlu_english_full": 0.5406637231163652,
34
+ "mmlu_uz_full": 0.4685230024213075,
35
+ "flores_uz_en_full": 0.8534744450736248,
36
+ "sentiment_binary_full": 0.955
37
+ },
38
+ "invalid_rate": {
39
+ "uzlib_slice_full": 0.0,
40
+ "tumlu_uzbek_full": 0.0,
41
+ "flores_en_uz_full": null,
42
+ "news_full": 0.0,
43
+ "mmlu_english_full": 0.0,
44
+ "mmlu_uz_full": 0.0,
45
+ "flores_uz_en_full": null,
46
+ "sentiment_binary_full": 0.0
47
+ },
48
+ "normalized_weighted_score": 0.5954224496037875
49
+ },
50
+ "Qwen3.5-2B": {
51
+ "run_id": "qwen35_2b_instruct_full_20260817_081135",
52
+ "suite_id": "public_uzbek_full_vllm",
53
+ "tasks": {
54
+ "uzlib_slice_full": 0.28694250403009136,
55
+ "tumlu_uzbek_full": 0.31285714285714283,
56
+ "flores_en_uz_full": 0.7009904753173863,
57
+ "news_full": 0.36753635144890173,
58
+ "mmlu_english_full": 0.5239282153539382,
59
+ "mmlu_uz_full": 0.3709585529126905,
60
+ "flores_uz_en_full": 0.8071526469372587,
61
+ "sentiment_binary_full": 0.7687
62
+ },
63
+ "invalid_rate": {
64
+ "uzlib_slice_full": 0.0,
65
+ "tumlu_uzbek_full": 0.0,
66
+ "flores_en_uz_full": null,
67
+ "news_full": 0.0,
68
+ "mmlu_english_full": 0.0,
69
+ "mmlu_uz_full": 0.0,
70
+ "flores_uz_en_full": null,
71
+ "sentiment_binary_full": 0.0002
72
+ },
73
+ "normalized_weighted_score": 0.45278257367733765
74
+ },
75
+ "alloma-8B": {
76
+ "run_id": "alloma_8b_full_public_composite",
77
+ "suite_id": "public_uzbek_full_composite_apst",
78
+ "source_files": [
79
+ "reports/alloma_card_protocol_full/alloma-8B.json",
80
+ "reports/eval_suites/external_public/alloma_8b_uzlib_full_20260615/uzlib_full.json",
81
+ "reports/eval_suites/public_full_comet/alloma_8b_strict_missing_uz_metrics/tumlu_uzbek_full_apst.json",
82
+ "reports/eval_suites/public_full_comet/alloma_8b_strict_missing_uz_metrics/mmlu_uz_full_apst.json"
83
+ ],
84
+ "tasks": {
85
+ "uzlib_slice_full": 0.4239656098871574,
86
+ "tumlu_uzbek_full": 0.20714285714285716,
87
+ "flores_en_uz_full": 0.8779,
88
+ "news_full": 0.5777,
89
+ "mmlu_english_full": 0.5347,
90
+ "mmlu_uz_full": 0.40037031761857284,
91
+ "flores_uz_en_full": 0.8713,
92
+ "sentiment_binary_full": 0.7994
93
+ },
94
+ "invalid_rate": {
95
+ "uzlib_slice_full": 0.0338527673293928,
96
+ "tumlu_uzbek_full": 0.25857142857142856,
97
+ "flores_en_uz_full": null,
98
+ "news_full": null,
99
+ "mmlu_english_full": null,
100
+ "mmlu_uz_full": 0.09051417177040308,
101
+ "flores_uz_en_full": null,
102
+ "sentiment_binary_full": null
103
+ },
104
+ "normalized_weighted_score": 0.5186512896503792
105
+ },
106
+ "alloma-3B": {
107
+ "run_id": "alloma_3B_apst_full_20260815_142714",
108
+ "suite_id": "public_uzbek_full_vllm_apst",
109
+ "tasks": {
110
+ "uzlib_slice_full": 0.32079527135948416,
111
+ "tumlu_uzbek_full": 0.27714285714285714,
112
+ "flores_en_uz_full": 0.8673252673692642,
113
+ "news_full": 0.1359802000618748,
114
+ "mmlu_english_full": 0.3872667711152257,
115
+ "mmlu_uz_full": 0.32744623273038026,
116
+ "flores_uz_en_full": 0.7954316840740269,
117
+ "sentiment_binary_full": 0.3885
118
+ },
119
+ "invalid_rate": {
120
+ "uzlib_slice_full": 0.0010746910263299302,
121
+ "tumlu_uzbek_full": 0.28714285714285714,
122
+ "flores_en_uz_full": null,
123
+ "news_full": 7.218727441476746e-05,
124
+ "mmlu_english_full": 0.06900726392251816,
125
+ "mmlu_uz_full": 0.07726819541375872,
126
+ "flores_uz_en_full": null,
127
+ "sentiment_binary_full": 0.4405
128
+ },
129
+ "normalized_weighted_score": 0.41468665305295505
130
+ },
131
+ "alloma-1B": {
132
+ "run_id": "alloma_1B_apst_full_20260811_114037",
133
+ "suite_id": "public_uzbek_full_vllm_apst",
134
+ "tasks": {
135
+ "uzlib_slice_full": 0.23320795271359485,
136
+ "tumlu_uzbek_full": 0.22,
137
+ "flores_en_uz_full": 0.7383331350348018,
138
+ "news_full": 0.2541404558110756,
139
+ "mmlu_english_full": 0.21976926363765845,
140
+ "mmlu_uz_full": 0.21108104258652613,
141
+ "flores_uz_en_full": 0.7636193416348852,
142
+ "sentiment_binary_full": 0.7954
143
+ },
144
+ "invalid_rate": {
145
+ "uzlib_slice_full": 0.04567436861902203,
146
+ "tumlu_uzbek_full": 0.36714285714285716,
147
+ "flores_en_uz_full": null,
148
+ "news_full": 0.0003506239043002991,
149
+ "mmlu_english_full": 0.09393248824953711,
150
+ "mmlu_uz_full": 0.17882068081469876,
151
+ "flores_uz_en_full": null,
152
+ "sentiment_binary_full": 0.0063
153
+ },
154
+ "normalized_weighted_score": 0.3661490569296942
155
+ }
156
+ },
157
+ "checkpoints": {
158
+ "0.25 epoch": {
159
+ "run_id": "qwen35_2b_lora_r64_grouped_identity_ckpt1188_public_v2",
160
+ "suite_id": "public_uzbek_full_comet_vllm_v2",
161
+ "tasks": {
162
+ "uzlib_slice_full": 0.5432563138097797,
163
+ "tumlu_uzbek_full": 0.32,
164
+ "flores_en_uz_full": 0.8569777911726428,
165
+ "news_full": 0.7521810869341033,
166
+ "mmlu_english_full": 0.5305512035322604,
167
+ "mmlu_uz_full": 0.4598347813701752,
168
+ "flores_uz_en_full": 0.7069662087233046,
169
+ "sentiment_binary_full": 0.9087
170
+ },
171
+ "invalid_rate": {
172
+ "uzlib_slice_full": 0.0,
173
+ "tumlu_uzbek_full": 0.0,
174
+ "flores_en_uz_full": null,
175
+ "news_full": 0.0,
176
+ "mmlu_english_full": 0.0,
177
+ "mmlu_uz_full": 0.0,
178
+ "flores_uz_en_full": null,
179
+ "sentiment_binary_full": 0.0
180
+ },
181
+ "normalized_weighted_score": 0.5855136305870227
182
+ },
183
+ "0.50 epoch": {
184
+ "run_id": "qwen35_2b_lora_r64_grouped_identity_ckpt2376_public_v2",
185
+ "suite_id": "public_uzbek_full_comet_vllm_v2",
186
+ "tasks": {
187
+ "uzlib_slice_full": 0.4954325631380978,
188
+ "tumlu_uzbek_full": 0.3057142857142857,
189
+ "flores_en_uz_full": 0.8641375761503245,
190
+ "news_full": 0.7519542126430855,
191
+ "mmlu_english_full": 0.5307648483122063,
192
+ "mmlu_uz_full": 0.46360917248255235,
193
+ "flores_uz_en_full": 0.8504324527211662,
194
+ "sentiment_binary_full": 0.9502
195
+ },
196
+ "invalid_rate": {
197
+ "uzlib_slice_full": 0.0,
198
+ "tumlu_uzbek_full": 0.0,
199
+ "flores_en_uz_full": null,
200
+ "news_full": 0.0,
201
+ "mmlu_english_full": 0.0,
202
+ "mmlu_uz_full": 0.0,
203
+ "flores_uz_en_full": null,
204
+ "sentiment_binary_full": 0.0
205
+ },
206
+ "normalized_weighted_score": 0.5836994233398612
207
+ },
208
+ "0.75 epoch": {
209
+ "run_id": "qwen35_2b_lora_r64_grouped_identity_ckpt3564_public_v2",
210
+ "suite_id": "public_uzbek_full_comet_vllm_v2",
211
+ "tasks": {
212
+ "uzlib_slice_full": 0.4744760881246642,
213
+ "tumlu_uzbek_full": 0.30857142857142855,
214
+ "flores_en_uz_full": 0.8769590624563133,
215
+ "news_full": 0.7998040631123028,
216
+ "mmlu_english_full": 0.5434411052556616,
217
+ "mmlu_uz_full": 0.46802449793476714,
218
+ "flores_uz_en_full": 0.8535260226727719,
219
+ "sentiment_binary_full": 0.9529
220
+ },
221
+ "invalid_rate": {
222
+ "uzlib_slice_full": 0.0,
223
+ "tumlu_uzbek_full": 0.0,
224
+ "flores_en_uz_full": null,
225
+ "news_full": 0.0,
226
+ "mmlu_english_full": 0.0,
227
+ "mmlu_uz_full": 0.0,
228
+ "flores_uz_en_full": null,
229
+ "sentiment_binary_full": 0.0
230
+ },
231
+ "normalized_weighted_score": 0.5890543478648181
232
+ },
233
+ "1.00 epoch": {
234
+ "run_id": "qwen35_2b_lora_r64_grouped_identity_ckpt4749_public_v2",
235
+ "suite_id": "public_uzbek_full_comet_vllm_v2",
236
+ "tasks": {
237
+ "uzlib_slice_full": 0.4959699086512628,
238
+ "tumlu_uzbek_full": 0.32571428571428573,
239
+ "flores_en_uz_full": 0.8761537177251785,
240
+ "news_full": 0.7854903578426318,
241
+ "mmlu_english_full": 0.5406637231163652,
242
+ "mmlu_uz_full": 0.4685230024213075,
243
+ "flores_uz_en_full": 0.8534744450736248,
244
+ "sentiment_binary_full": 0.955
245
+ },
246
+ "invalid_rate": {
247
+ "uzlib_slice_full": 0.0,
248
+ "tumlu_uzbek_full": 0.0,
249
+ "flores_en_uz_full": null,
250
+ "news_full": 0.0,
251
+ "mmlu_english_full": 0.0,
252
+ "mmlu_uz_full": 0.0,
253
+ "flores_uz_en_full": null,
254
+ "sentiment_binary_full": 0.0
255
+ },
256
+ "normalized_weighted_score": 0.5954224496037875
257
+ }
258
+ },
259
+ "tokenizer_fertility": {
260
+ "status": "superseded",
261
+ "result": "fertility_large_20260825.json",
262
+ "note": "Use the corpus-stratified 2026-08-25 evaluation; the old 20k uz-crawl-only result was in-domain."
263
+ }
264
+ }
fertility_large_20260825.json ADDED
@@ -0,0 +1,643 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "schema_version": 1,
3
+ "created_at": "2026-08-24T19:25:09+00:00",
4
+ "seed": 20260825,
5
+ "sampling": {
6
+ "method": "deterministic SHA-256 bottom-k, exact duplicates excluded from selected sample",
7
+ "requested_documents_per_corpus": 100000,
8
+ "min_chars": 250,
9
+ "max_chars": 20000,
10
+ "min_words": 20
11
+ },
12
+ "tokenizers": {
13
+ "new": "out/qwen35_2b_sft_lora_r64_grouped_identity_v1/merges/ckpt4749/merged",
14
+ "base": "/mnt/raid1/qwen3.5/pipelines/uzbek_tokenizer/artifacts/base_checkpoints/qwen35_2b_base",
15
+ "result_reuse_note": "The evaluated 2B tokenizer files are byte-identical to the evaluated 4B tokenizer files.",
16
+ "new_tokenizer_sha256": "e4731e5df2c95dbfd98c45e08feae7c5fcd0588172778ac35c3703921f5529f9",
17
+ "base_tokenizer_sha256": "fe000e3ed39ed12b8d2481d527d44f93c65d37e87645d2dcc80d1bf9d50d2927",
18
+ "add_special_tokens": false,
19
+ "raw_text_no_preprocessing": true
20
+ },
21
+ "corpora": {
22
+ "OSCAR Uzbek": {
23
+ "domain_status": "held-out web source",
24
+ "source": "xkas2001/uzbek-language-dataset, community-oscar-uzbek/all_metadata_text.txt",
25
+ "sampling": {
26
+ "records_scanned": 4762756,
27
+ "valid_records": 623128,
28
+ "sampled_records": 100000,
29
+ "selected_duplicate_occurrences_skipped": 316611,
30
+ "records_truncated_before_sampling": 67
31
+ },
32
+ "result": {
33
+ "documents": 100000,
34
+ "words": 7618770,
35
+ "characters": 62308307,
36
+ "new_tokens": 15469208,
37
+ "base_tokens": 25628881,
38
+ "new_tokens_per_word": 2.0304075329744826,
39
+ "base_tokens_per_word": 3.363913203837365,
40
+ "token_reduction": 0.3964150053995724,
41
+ "token_reduction_95ci": [
42
+ 0.3956999048249437,
43
+ 0.3971071790721872
44
+ ],
45
+ "median_document_tokens_per_word": {
46
+ "new": 1.9714285714285715,
47
+ "base": 3.3536585365853657
48
+ },
49
+ "document_token_count_comparison": {
50
+ "new_fewer_fraction": 0.99789,
51
+ "equal_fraction": 0.00171,
52
+ "new_more_fraction": 0.0004
53
+ },
54
+ "document_length_chars": {
55
+ "min": 250,
56
+ "median": 448,
57
+ "p90": 1105,
58
+ "p99": 2908,
59
+ "max": 19999
60
+ },
61
+ "by_script": {
62
+ "latin_dominant": {
63
+ "documents": 99876,
64
+ "words": 7609046,
65
+ "characters": 62243858,
66
+ "new_tokens": 15444043,
67
+ "base_tokens": 25601074,
68
+ "new_tokens_per_word": 2.029695049813078,
69
+ "base_tokens_per_word": 3.3645576593964606,
70
+ "token_reduction": 0.39674237885488706,
71
+ "token_reduction_95ci": [
72
+ 0.3960664169063509,
73
+ 0.3974315537014118
74
+ ],
75
+ "median_document_tokens_per_word": {
76
+ "new": 1.9714285714285715,
77
+ "base": 3.3541666666666665
78
+ },
79
+ "document_token_count_comparison": {
80
+ "new_fewer_fraction": 0.9980375665825624,
81
+ "equal_fraction": 0.001571949217029116,
82
+ "new_more_fraction": 0.00039048420040850655
83
+ }
84
+ },
85
+ "cyrillic_dominant": {
86
+ "documents": 121,
87
+ "words": 8853,
88
+ "characters": 61058,
89
+ "new_tokens": 21987,
90
+ "base_tokens": 24636,
91
+ "new_tokens_per_word": 2.4835648932565233,
92
+ "base_tokens_per_word": 2.782785496441884,
93
+ "token_reduction": 0.10752557233317095,
94
+ "token_reduction_95ci": [
95
+ 0.06903186700461168,
96
+ 0.1489608189386225
97
+ ],
98
+ "median_document_tokens_per_word": {
99
+ "new": 2.220779220779221,
100
+ "base": 2.5869565217391304
101
+ },
102
+ "document_token_count_comparison": {
103
+ "new_fewer_fraction": 0.9008264462809917,
104
+ "equal_fraction": 0.09917355371900827,
105
+ "new_more_fraction": 0.0
106
+ }
107
+ },
108
+ "other": {
109
+ "documents": 3,
110
+ "words": 871,
111
+ "characters": 3391,
112
+ "new_tokens": 3178,
113
+ "base_tokens": 3171,
114
+ "new_tokens_per_word": 3.6486796785304247,
115
+ "base_tokens_per_word": 3.640642939150402,
116
+ "token_reduction": -0.002207505518763808,
117
+ "token_reduction_95ci": [
118
+ -0.06363636363636371,
119
+ 0.0
120
+ ],
121
+ "median_document_tokens_per_word": {
122
+ "new": 3.7318295739348373,
123
+ "base": 3.7318295739348373
124
+ },
125
+ "document_token_count_comparison": {
126
+ "new_fewer_fraction": 0.0,
127
+ "equal_fraction": 0.6666666666666666,
128
+ "new_more_fraction": 0.3333333333333333
129
+ }
130
+ }
131
+ },
132
+ "by_document_length_quartile": {
133
+ "q1": {
134
+ "char_bounds": [
135
+ 250,
136
+ 328
137
+ ],
138
+ "documents": 25225,
139
+ "words": 886299,
140
+ "characters": 7229107,
141
+ "new_tokens": 1742025,
142
+ "base_tokens": 2981550,
143
+ "new_tokens_per_word": 1.9655048691243022,
144
+ "base_tokens_per_word": 3.3640453165353903,
145
+ "token_reduction": 0.41573175026412434,
146
+ "token_reduction_95ci": [
147
+ 0.41438530829534354,
148
+ 0.4170515905402432
149
+ ],
150
+ "median_document_tokens_per_word": {
151
+ "new": 1.9142857142857144,
152
+ "base": 3.3636363636363638
153
+ },
154
+ "document_token_count_comparison": {
155
+ "new_fewer_fraction": 0.9958771060455897,
156
+ "equal_fraction": 0.004083250743310208,
157
+ "new_more_fraction": 3.9643211100099105e-05
158
+ }
159
+ },
160
+ "q2": {
161
+ "char_bounds": [
162
+ 329,
163
+ 448
164
+ ],
165
+ "documents": 24838,
166
+ "words": 1159735,
167
+ "characters": 9510849,
168
+ "new_tokens": 2254196,
169
+ "base_tokens": 3895455,
170
+ "new_tokens_per_word": 1.943716452465434,
171
+ "base_tokens_per_word": 3.358918201140778,
172
+ "token_reduction": 0.42132664861999436,
173
+ "token_reduction_95ci": [
174
+ 0.4200747806331761,
175
+ 0.42257126807643025
176
+ ],
177
+ "median_document_tokens_per_word": {
178
+ "new": 1.9166666666666667,
179
+ "base": 3.3617021276595747
180
+ },
181
+ "document_token_count_comparison": {
182
+ "new_fewer_fraction": 0.9986311297205894,
183
+ "equal_fraction": 0.001328609388839681,
184
+ "new_more_fraction": 4.0260890570899426e-05
185
+ }
186
+ },
187
+ "q3": {
188
+ "char_bounds": [
189
+ 449,
190
+ 694
191
+ ],
192
+ "documents": 24973,
193
+ "words": 1683343,
194
+ "characters": 13783621,
195
+ "new_tokens": 3372637,
196
+ "base_tokens": 5654412,
197
+ "new_tokens_per_word": 2.0035352272234475,
198
+ "base_tokens_per_word": 3.359037344141984,
199
+ "token_reduction": 0.4035388648722449,
200
+ "token_reduction_95ci": [
201
+ 0.4023960313587086,
202
+ 0.4046209067071377
203
+ ],
204
+ "median_document_tokens_per_word": {
205
+ "new": 1.9710144927536233,
206
+ "base": 3.3466666666666667
207
+ },
208
+ "document_token_count_comparison": {
209
+ "new_fewer_fraction": 0.9995194810395227,
210
+ "equal_fraction": 0.0004004324670644296,
211
+ "new_more_fraction": 8.008649341288591e-05
212
+ }
213
+ },
214
+ "q4": {
215
+ "char_bounds": [
216
+ 695,
217
+ 19999
218
+ ],
219
+ "documents": 24964,
220
+ "words": 3889393,
221
+ "characters": 31784730,
222
+ "new_tokens": 8100350,
223
+ "base_tokens": 13097464,
224
+ "new_tokens_per_word": 2.0826771683910574,
225
+ "base_tokens_per_word": 3.367482792302038,
226
+ "token_reduction": 0.3815329440874966,
227
+ "token_reduction_95ci": [
228
+ 0.38033518553908646,
229
+ 0.38274511916670123
230
+ ],
231
+ "median_document_tokens_per_word": {
232
+ "new": 2.05603738317757,
233
+ "base": 3.347826086956522
234
+ },
235
+ "document_token_count_comparison": {
236
+ "new_fewer_fraction": 0.9975564813331197,
237
+ "equal_fraction": 0.00100144207659029,
238
+ "new_more_fraction": 0.0014420765902900176
239
+ }
240
+ }
241
+ }
242
+ }
243
+ },
244
+ "Uzbek legal corpus": {
245
+ "domain_status": "held-out legal source/domain",
246
+ "source": "sukhrobnurali/uzbek-legal-corpus-v1, articles",
247
+ "sampling": {
248
+ "records_scanned": 21021,
249
+ "valid_records": 18832,
250
+ "sampled_records": 18832,
251
+ "selected_duplicate_occurrences_skipped": 0,
252
+ "records_truncated_before_sampling": 3
253
+ },
254
+ "result": {
255
+ "documents": 18832,
256
+ "words": 2534566,
257
+ "characters": 21314804,
258
+ "new_tokens": 6018932,
259
+ "base_tokens": 7529043,
260
+ "new_tokens_per_word": 2.374738712663233,
261
+ "base_tokens_per_word": 2.970545253112367,
262
+ "token_reduction": 0.20057144048719078,
263
+ "token_reduction_95ci": [
264
+ 0.19550471065059247,
265
+ 0.20567097138760268
266
+ ],
267
+ "median_document_tokens_per_word": {
268
+ "new": 1.8397191231160697,
269
+ "base": 3.3333333333333335
270
+ },
271
+ "document_token_count_comparison": {
272
+ "new_fewer_fraction": 0.385089209855565,
273
+ "equal_fraction": 0.614910790144435,
274
+ "new_more_fraction": 0.0
275
+ },
276
+ "document_length_chars": {
277
+ "min": 250,
278
+ "median": 812,
279
+ "p90": 2183,
280
+ "p99": 5637,
281
+ "max": 19997
282
+ },
283
+ "by_script": {
284
+ "latin_dominant": {
285
+ "documents": 6354,
286
+ "words": 858053,
287
+ "characters": 7499938,
288
+ "new_tokens": 1410490,
289
+ "base_tokens": 2916524,
290
+ "new_tokens_per_word": 1.6438261972162558,
291
+ "base_tokens_per_word": 3.3990021595402613,
292
+ "token_reduction": 0.51637977263345,
293
+ "token_reduction_95ci": [
294
+ 0.5147582025646525,
295
+ 0.5179880323158793
296
+ ],
297
+ "median_document_tokens_per_word": {
298
+ "new": 1.6153846153846154,
299
+ "base": 3.369890856442811
300
+ },
301
+ "document_token_count_comparison": {
302
+ "new_fewer_fraction": 1.0,
303
+ "equal_fraction": 0.0,
304
+ "new_more_fraction": 0.0
305
+ }
306
+ },
307
+ "cyrillic_dominant": {
308
+ "documents": 12478,
309
+ "words": 1676513,
310
+ "characters": 13814866,
311
+ "new_tokens": 4608442,
312
+ "base_tokens": 4612519,
313
+ "new_tokens_per_word": 2.74882568760278,
314
+ "base_tokens_per_word": 2.7512575208185086,
315
+ "token_reduction": 0.0008838987980320789,
316
+ "token_reduction_95ci": [
317
+ 0.000797593938754379,
318
+ 0.0009744198560997175
319
+ ],
320
+ "median_document_tokens_per_word": {
321
+ "new": 3.1314814814814813,
322
+ "base": 3.1314814814814813
323
+ },
324
+ "document_token_count_comparison": {
325
+ "new_fewer_fraction": 0.07196666132393012,
326
+ "equal_fraction": 0.9280333386760699,
327
+ "new_more_fraction": 0.0
328
+ }
329
+ }
330
+ },
331
+ "by_document_length_quartile": {
332
+ "q1": {
333
+ "char_bounds": [
334
+ 250,
335
+ 506
336
+ ],
337
+ "documents": 4715,
338
+ "words": 213503,
339
+ "characters": 1769357,
340
+ "new_tokens": 505325,
341
+ "base_tokens": 619444,
342
+ "new_tokens_per_word": 2.366828569153595,
343
+ "base_tokens_per_word": 2.901336280989026,
344
+ "token_reduction": 0.1842281142443869,
345
+ "token_reduction_95ci": [
346
+ 0.17673651196691142,
347
+ 0.19222917798968833
348
+ ],
349
+ "median_document_tokens_per_word": {
350
+ "new": 1.868421052631579,
351
+ "base": 3.2857142857142856
352
+ },
353
+ "document_token_count_comparison": {
354
+ "new_fewer_fraction": 0.34612937433722163,
355
+ "equal_fraction": 0.6538706256627783,
356
+ "new_more_fraction": 0.0
357
+ }
358
+ },
359
+ "q2": {
360
+ "char_bounds": [
361
+ 507,
362
+ 812
363
+ ],
364
+ "documents": 4703,
365
+ "words": 369537,
366
+ "characters": 3066781,
367
+ "new_tokens": 873369,
368
+ "base_tokens": 1074262,
369
+ "new_tokens_per_word": 2.3634142183326703,
370
+ "base_tokens_per_word": 2.907048549942225,
371
+ "token_reduction": 0.18700559081490364,
372
+ "token_reduction_95ci": [
373
+ 0.17978162099648665,
374
+ 0.19424970760537358
375
+ ],
376
+ "median_document_tokens_per_word": {
377
+ "new": 1.8421052631578947,
378
+ "base": 3.3076923076923075
379
+ },
380
+ "document_token_count_comparison": {
381
+ "new_fewer_fraction": 0.35721879651286415,
382
+ "equal_fraction": 0.6427812034871359,
383
+ "new_more_fraction": 0.0
384
+ }
385
+ },
386
+ "q3": {
387
+ "char_bounds": [
388
+ 813,
389
+ 1347
390
+ ],
391
+ "documents": 4711,
392
+ "words": 594780,
393
+ "characters": 4943320,
394
+ "new_tokens": 1407482,
395
+ "base_tokens": 1750853,
396
+ "new_tokens_per_word": 2.366390934463163,
397
+ "base_tokens_per_word": 2.9436985103735833,
398
+ "token_reduction": 0.19611640725977564,
399
+ "token_reduction_95ci": [
400
+ 0.18856405345722932,
401
+ 0.20422906152284168
402
+ ],
403
+ "median_document_tokens_per_word": {
404
+ "new": 1.8333333333333333,
405
+ "base": 3.3286713286713288
406
+ },
407
+ "document_token_count_comparison": {
408
+ "new_fewer_fraction": 0.3922734026745914,
409
+ "equal_fraction": 0.6077265973254086,
410
+ "new_more_fraction": 0.0
411
+ }
412
+ },
413
+ "q4": {
414
+ "char_bounds": [
415
+ 1348,
416
+ 19997
417
+ ],
418
+ "documents": 4703,
419
+ "words": 1356746,
420
+ "characters": 11535346,
421
+ "new_tokens": 3232756,
422
+ "base_tokens": 4084484,
423
+ "new_tokens_per_word": 2.3827274965247733,
424
+ "base_tokens_per_word": 3.0105001230886255,
425
+ "token_reduction": 0.2085276867286051,
426
+ "token_reduction_95ci": [
427
+ 0.1998185981685246,
428
+ 0.21714855506411254
429
+ ],
430
+ "median_document_tokens_per_word": {
431
+ "new": 1.819905213270142,
432
+ "base": 3.3981481481481484
433
+ },
434
+ "document_token_count_comparison": {
435
+ "new_fewer_fraction": 0.4448224537529237,
436
+ "equal_fraction": 0.5551775462470764,
437
+ "new_more_fraction": 0.0
438
+ }
439
+ }
440
+ }
441
+ }
442
+ },
443
+ "uz-crawl control": {
444
+ "domain_status": "training-source control",
445
+ "source": "tahrirchi/uz-crawl local training source",
446
+ "sampling": {
447
+ "records_scanned": 1618035,
448
+ "valid_records": 1441908,
449
+ "sampled_records": 100000,
450
+ "selected_duplicate_occurrences_skipped": 174,
451
+ "records_truncated_before_sampling": 9216
452
+ },
453
+ "result": {
454
+ "documents": 100000,
455
+ "words": 20825680,
456
+ "characters": 174743319,
457
+ "new_tokens": 48327821,
458
+ "base_tokens": 69191245,
459
+ "new_tokens_per_word": 2.3205878991706395,
460
+ "base_tokens_per_word": 3.3224002769657464,
461
+ "token_reduction": 0.3015327155914018,
462
+ "token_reduction_95ci": [
463
+ 0.3001693372220501,
464
+ 0.302962741125678
465
+ ],
466
+ "median_document_tokens_per_word": {
467
+ "new": 2.0866859344894024,
468
+ "base": 3.2613636363636362
469
+ },
470
+ "document_token_count_comparison": {
471
+ "new_fewer_fraction": 0.86481,
472
+ "equal_fraction": 0.13306,
473
+ "new_more_fraction": 0.00213
474
+ },
475
+ "document_length_chars": {
476
+ "min": 250,
477
+ "median": 1036,
478
+ "p90": 3408,
479
+ "p99": 14367,
480
+ "max": 19999
481
+ },
482
+ "by_script": {
483
+ "latin_dominant": {
484
+ "documents": 82818,
485
+ "words": 17899459,
486
+ "characters": 152194135,
487
+ "new_tokens": 37942391,
488
+ "base_tokens": 58788459,
489
+ "new_tokens_per_word": 2.119750714253431,
490
+ "base_tokens_per_word": 3.284370717573084,
491
+ "token_reduction": 0.3545945642154015,
492
+ "token_reduction_95ci": [
493
+ 0.35375779400897717,
494
+ 0.35539015324512163
495
+ ],
496
+ "median_document_tokens_per_word": {
497
+ "new": 2.0297619047619047,
498
+ "base": 3.2142857142857144
499
+ },
500
+ "document_token_count_comparison": {
501
+ "new_fewer_fraction": 1.0,
502
+ "equal_fraction": 0.0,
503
+ "new_more_fraction": 0.0
504
+ }
505
+ },
506
+ "cyrillic_dominant": {
507
+ "documents": 17182,
508
+ "words": 2926221,
509
+ "characters": 22549184,
510
+ "new_tokens": 10385430,
511
+ "base_tokens": 10402786,
512
+ "new_tokens_per_word": 3.5490928402195188,
513
+ "base_tokens_per_word": 3.5550240395376838,
514
+ "token_reduction": 0.0016683992153639915,
515
+ "token_reduction_95ci": [
516
+ 0.0013899888640842822,
517
+ 0.001964975103579841
518
+ ],
519
+ "median_document_tokens_per_word": {
520
+ "new": 3.542372881355932,
521
+ "base": 3.5457593062605754
522
+ },
523
+ "document_token_count_comparison": {
524
+ "new_fewer_fraction": 0.21318822023047376,
525
+ "equal_fraction": 0.7744150855546502,
526
+ "new_more_fraction": 0.012396694214876033
527
+ }
528
+ }
529
+ },
530
+ "by_document_length_quartile": {
531
+ "q1": {
532
+ "char_bounds": [
533
+ 250,
534
+ 642
535
+ ],
536
+ "documents": 25014,
537
+ "words": 1443765,
538
+ "characters": 11560305,
539
+ "new_tokens": 3580625,
540
+ "base_tokens": 4717032,
541
+ "new_tokens_per_word": 2.4800608132209883,
542
+ "base_tokens_per_word": 3.2671743670195634,
543
+ "token_reduction": 0.2409156859652426,
544
+ "token_reduction_95ci": [
545
+ 0.2388878125954489,
546
+ 0.243056097563355
547
+ ],
548
+ "median_document_tokens_per_word": {
549
+ "new": 2.2058823529411766,
550
+ "base": 3.2567567567567566
551
+ },
552
+ "document_token_count_comparison": {
553
+ "new_fewer_fraction": 0.7540577276725035,
554
+ "equal_fraction": 0.24566242903973776,
555
+ "new_more_fraction": 0.00027984328775885504
556
+ }
557
+ },
558
+ "q2": {
559
+ "char_bounds": [
560
+ 643,
561
+ 1036
562
+ ],
563
+ "documents": 25032,
564
+ "words": 2534284,
565
+ "characters": 20698884,
566
+ "new_tokens": 5852869,
567
+ "base_tokens": 8233439,
568
+ "new_tokens_per_word": 2.3094763649220056,
569
+ "base_tokens_per_word": 3.248822547117845,
570
+ "token_reduction": 0.2891343459276251,
571
+ "token_reduction_95ci": [
572
+ 0.2871033465654421,
573
+ 0.2910416333852472
574
+ ],
575
+ "median_document_tokens_per_word": {
576
+ "new": 2.0697674418604652,
577
+ "base": 3.2268041237113403
578
+ },
579
+ "document_token_count_comparison": {
580
+ "new_fewer_fraction": 0.8623761585170981,
581
+ "equal_fraction": 0.13690476190476192,
582
+ "new_more_fraction": 0.0007190795781399808
583
+ }
584
+ },
585
+ "q3": {
586
+ "char_bounds": [
587
+ 1037,
588
+ 1827
589
+ ],
590
+ "documents": 24959,
591
+ "words": 4090354,
592
+ "characters": 34187499,
593
+ "new_tokens": 9144176,
594
+ "base_tokens": 13420837,
595
+ "new_tokens_per_word": 2.235546361024009,
596
+ "base_tokens_per_word": 3.281094252477903,
597
+ "token_reduction": 0.31865829232558296,
598
+ "token_reduction_95ci": [
599
+ 0.3168107024780933,
600
+ 0.3205574932440705
601
+ ],
602
+ "median_document_tokens_per_word": {
603
+ "new": 2.051851851851852,
604
+ "base": 3.261904761904762
605
+ },
606
+ "document_token_count_comparison": {
607
+ "new_fewer_fraction": 0.9184662847069194,
608
+ "equal_fraction": 0.08033174406025882,
609
+ "new_more_fraction": 0.0012019712328218278
610
+ }
611
+ },
612
+ "q4": {
613
+ "char_bounds": [
614
+ 1828,
615
+ 19999
616
+ ],
617
+ "documents": 24995,
618
+ "words": 12757277,
619
+ "characters": 108296631,
620
+ "new_tokens": 29750151,
621
+ "base_tokens": 42819937,
622
+ "new_tokens_per_word": 2.3320141908026297,
623
+ "base_tokens_per_word": 3.3565107193329737,
624
+ "token_reduction": 0.30522665178138864,
625
+ "token_reduction_95ci": [
626
+ 0.3030310155219502,
627
+ 0.30739078599543024
628
+ ],
629
+ "median_document_tokens_per_word": {
630
+ "new": 2.07344398340249,
631
+ "base": 3.2913907284768213
632
+ },
633
+ "document_token_count_comparison": {
634
+ "new_fewer_fraction": 0.924504900980196,
635
+ "equal_fraction": 0.0691738347669534,
636
+ "new_more_fraction": 0.00632126425285057
637
+ }
638
+ }
639
+ }
640
+ }
641
+ }
642
+ }
643
+ }
fertility_large_20260825.md ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # NeuronAI-2B large tokenizer fertility evaluation
2
+
3
+ Generated: 2026-08-24T19:25:09+00:00
4
+
5
+ Fertility is the number of tokenizer tokens per whitespace-delimited word; lower is better.
6
+ The confidence interval is a paired 5,000-replicate bootstrap over 1,000 deterministic document buckets.
7
+
8
+ | Corpus | Domain status | Documents | Words | NeuronAI-2B | Qwen3.5-2B | Token reduction (95% CI) |
9
+ | --- | --- | ---: | ---: | ---: | ---: | ---: |
10
+ | OSCAR Uzbek | held-out web source | 100,000 | 7,618,770 | 2.0304 | 3.3639 | 39.64% (39.57%–39.71%) |
11
+ | Uzbek legal corpus | held-out legal source/domain | 18,832 | 2,534,566 | 2.3747 | 2.9705 | 20.06% (19.55%–20.57%) |
12
+ | uz-crawl control | training-source control | 100,000 | 20,825,680 | 2.3206 | 3.3224 | 30.15% (30.02%–30.30%) |
13
+
14
+ ## Interpretation
15
+
16
+ - The 2B and 4B evaluated tokenizer pairs are byte-identical, so their token counts are exactly identical. SHA-256 fingerprints are recorded in the JSON result.
17
+ - The held-out-source corpora are the fairness readout; the training-source corpus is retained only as a control.
18
+ - Exact web overlap cannot be ruled out for OSCAR because both corpora ultimately derive from public web data.
19
+ - OSCAR was checked in a post-hoc weak-token coverage analysis but contributed no tokenizer-training rows.
20
+ - The legal corpus is absent from the tokenizer and CPT source manifests and is the cleanest source-and-domain holdout in this run.
21
+ - Results use raw source text without apostrophe normalization or other model-specific preprocessing.