kmamaroziqov commited on
Commit
430542f
·
verified ·
1 Parent(s): c6e2548

Replace with full-FT v3 checkpoint (weighted 0.4388, was 0.4190); update card with benchmarks + clean usage

Browse files
Files changed (3) hide show
  1. README.md +129 -105
  2. model.safetensors +1 -1
  3. tokenizer_config.json +1 -1
README.md CHANGED
@@ -12,93 +12,98 @@ tags:
12
  - text-generation
13
  - conversational
14
  - axolotl
15
- - lora
16
  ---
17
 
18
- # Qwen3.5 2B Uzbek Fine-Tuned (LoRA Broad)
19
 
20
- This is a merged, text-only Qwen3.5 2B checkpoint fine-tuned primarily for
21
- Uzbek instruction following and conversational use. It is the `lora-broad`
22
- experiment: a broad supervised mixture intended to improve general Uzbek
23
- assistant capability while retaining task-format and English examples.
 
 
 
 
 
24
 
25
  ## Model lineage
26
 
27
  1. `Qwen/Qwen3.5-2B-Base`
28
- 2. Local Uzbek continued-pretraining and annealing checkpoint
29
- 3. Supervised fine-tuning with LoRA
30
- 4. LoRA weights merged into the model for direct inference
31
-
32
- This repository contains the merged model, so PEFT is not required to load it.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
34
  ## Training summary
35
 
36
  - Framework: Axolotl / Transformers
37
- - Training data: 269,467 conversational examples
38
- - Languages: primarily Uzbek, with English retention data
39
- - Context length during SFT: 2,048 tokens
40
- - Epochs: 1
41
- - LoRA rank: 32
42
- - LoRA alpha: 64
43
- - LoRA dropout: 0.05
44
- - Learning rate: 1e-4 with cosine scheduling
45
- - Validation split: 2%
46
- - Final reported training loss: 1.381
47
-
48
- The training mixture contained broad conversational data, task-formatted
49
- examples, and Uzbek knowledge/language material. The underlying dataset is not
50
- included in this repository.
51
 
52
  ## Usage
53
 
54
  ```python
55
- import re
56
  import torch
57
- from transformers import (
58
- AutoModelForCausalLM,
59
- AutoTokenizer,
60
- StoppingCriteria,
61
- StoppingCriteriaList,
62
- )
63
-
64
-
65
- class SentenceLimitCriteria(StoppingCriteria):
66
- """Stop after a fixed number of complete generated sentences."""
67
-
68
- def __init__(self, tokenizer, prompt_length, max_sentences=4):
69
- self.tokenizer = tokenizer
70
- self.prompt_length = prompt_length
71
- self.max_sentences = max_sentences
72
-
73
- def __call__(self, input_ids, scores, **kwargs):
74
- generated = self.tokenizer.decode(
75
- input_ids[0, self.prompt_length:], skip_special_tokens=True
76
- )
77
- endings = re.findall(r'[.!?](?:["\'’”)]*)?\s+', generated)
78
- return len(endings) >= self.max_sentences
79
-
80
 
81
  model_id = "NeuronUz/qwen3.5-2b-fine-tuned"
82
- device = "cuda:0" if torch.cuda.is_available() else "cpu"
83
- max_sentences = 4
84
 
85
  tokenizer = AutoTokenizer.from_pretrained(model_id)
86
  model = AutoModelForCausalLM.from_pretrained(
87
  model_id,
88
- torch_dtype="auto",
89
- # Keep this hybrid model on one device. See the note below.
90
- device_map=device,
91
  )
92
 
93
  messages = [
94
- {
95
- "role": "system",
96
- "content": (
97
- "Siz foydali AI yordamchisiz. Javoblarni qisqa va aniq yozing. "
98
- "Agar foydalanuvchi batafsil javob so'ramasa, odatda 2-4 ta "
99
- "to'liq gap bilan javob bering."
100
- ),
101
- },
102
  {"role": "user", "content": "O'zbekiston haqida qisqacha ma'lumot bering."},
103
  ]
104
 
@@ -109,58 +114,77 @@ inputs = tokenizer.apply_chat_template(
109
  return_dict=True,
110
  ).to(model.device)
111
 
112
- im_end_id = tokenizer.convert_tokens_to_ids("<|im_end|>")
113
- eos_ids = [tokenizer.eos_token_id, im_end_id]
114
- stopping_criteria = StoppingCriteriaList(
115
- [
116
- SentenceLimitCriteria(
117
- tokenizer,
118
- prompt_length=inputs["input_ids"].shape[-1],
119
- max_sentences=max_sentences,
120
- )
121
- ]
122
- )
123
-
124
  with torch.inference_mode():
125
- output = model.generate(
126
- **inputs,
127
- max_new_tokens=256,
128
- do_sample=False,
129
- repetition_penalty=1.15,
130
- no_repeat_ngram_size=3,
131
- eos_token_id=eos_ids,
132
- pad_token_id=tokenizer.eos_token_id,
133
- stopping_criteria=stopping_criteria,
134
- )
135
-
136
- prompt_length = inputs["input_ids"].shape[-1]
137
  reply = tokenizer.decode(
138
- output[0][prompt_length:], skip_special_tokens=True
139
  ).strip()
 
 
140
 
141
- # A token can contain the final period and the start of the next word, so trim
142
- # the displayed output back to the fourth complete sentence.
143
- sentence_end_re = re.compile(r'[.!?](?:["\'’”)]*)?(?=\s|$)')
144
- sentence_endings = list(sentence_end_re.finditer(reply))
145
- if len(sentence_endings) >= max_sentences:
146
- reply = reply[:sentence_endings[max_sentences - 1].end()].strip()
147
 
148
- print(reply)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
  ```
150
 
151
- Use a recent Transformers release with Qwen3.5 support.
152
 
153
- When multiple GPUs are visible, avoid `device_map="auto"` with this checkpoint.
154
- Current Accelerate/Transformers releases may split the Qwen3.5 hybrid layers
155
- across GPUs and produce invalid text. Pin the complete model to one GPU as shown
156
- above. The example uses greedy decoding (`do_sample=False`, equivalent to
157
- temperature 0 in the local chat script) and limits normal answers to four
158
- complete sentences. If sampling is desired, a tested starting point is
159
- `temperature=0.7`, `top_p=0.8`, and `top_k=20`.
160
 
161
  ## Limitations
162
 
163
- The model may produce inaccurate, biased, or fabricated information. It has not
164
- been comprehensively evaluated for safety or high-stakes domains. Outputs should
165
- be independently verified before use in medical, legal, financial, or other
 
 
166
  consequential settings.
 
12
  - text-generation
13
  - conversational
14
  - axolotl
 
15
  ---
16
 
17
+ # Qwen3.5 2B Uzbek Fine-Tuned
18
 
19
+ A text-only Qwen3.5 2B checkpoint for Uzbek instruction following and
20
+ conversation, with English retained. Uzbek continued pretraining and annealing,
21
+ then a full-parameter supervised fine-tune.
22
+
23
+ This release replaces the earlier LoRA-broad checkpoint. It scores higher on
24
+ every benchmark below and, unlike its predecessor, **stops generating on its
25
+ own** — the previous checkpoints never learned to emit the turn terminator and
26
+ needed sentence counters and repetition penalties to produce usable output. The
27
+ usage example below is correspondingly plain.
28
 
29
  ## Model lineage
30
 
31
  1. `Qwen/Qwen3.5-2B-Base`
32
+ 2. Uzbek tokenizer extension (vocabulary 248,320) and embedding initialization
33
+ 3. Uzbek continued pretraining
34
+ 4. Annealing
35
+ 5. Full-parameter supervised fine-tuning (no LoRA — these are the trained weights)
36
+
37
+ ## Benchmarks
38
+
39
+ Public Uzbek evaluation suite, vLLM backend, full test splits, greedy decoding.
40
+ Identical harness and settings for all three models. Translation is FLORES+ with
41
+ sacreBLEU and COMET (`Unbabel/wmt22-comet-da`).
42
+
43
+ | Benchmark | Metric | **This model** | Previous release (LoRA broad) | Qwen3.5-2B-Instruct (stock) |
44
+ | --- | --- | ---: | ---: | ---: |
45
+ | UzLiB | accuracy | **0.4863** | 0.4782 | 0.2880 |
46
+ | TUMLU-Uzbek | accuracy | **0.3214** | 0.3686 | 0.3129 |
47
+ | News classification | accuracy | **0.7948** | 0.7355 | 0.3675 |
48
+ | Sentiment (binary) | accuracy | **0.9626** | 0.9348 | 0.7676 |
49
+ | MMLU (English) | accuracy | **0.5422** | 0.5300 | 0.5241 |
50
+ | MMLU (Uzbek) | accuracy | **0.4707** | 0.4640 | 0.3711 |
51
+ | FLORES+ en→uz | BLEU | **9.90** | 4.05 | 4.16 |
52
+ | FLORES+ en→uz | COMET | **0.8496** | 0.7413 | 0.6790 |
53
+ | FLORES+ uz→en | BLEU | **23.07** | 5.93 | 17.13 |
54
+ | FLORES+ uz→en | COMET | **0.8314** | 0.6056 | 0.8091 |
55
+ | **Weighted score** | | **0.4388** | 0.4190 | 0.3154 |
56
+
57
+ The weighted score combines all eight tasks (UzLiB 0.20, TUMLU 0.20, en→uz 0.15,
58
+ news 0.10, MMLU-en 0.10, MMLU-uz 0.10, uz→en 0.05, sentiment 0.05), with BLEU
59
+ scaled to a 0–1 range.
60
+
61
+ Notes on reading these numbers honestly:
62
+
63
+ - **Translation is where the gain is largest** (en→uz BLEU 4.05 → 9.90, uz→en
64
+ 5.93 → 23.07). Much of that is the terminator fix: the previous checkpoint ran
65
+ past the end of its answer, which BLEU punishes severely.
66
+ - **TUMLU-Uzbek regressed** (0.3686 → 0.3214) and is this model's weakest task.
67
+ It is also near the 0.25 random baseline for 4-choice questions, so treat
68
+ Uzbek multi-subject knowledge as unreliable.
69
+ - Invalid-output rate was 0.0000 on all format-scored tasks.
70
+ - The checkpoint published here is the one that scored best on this suite
71
+ (1.5 epochs), selected across all 12 training checkpoints. It is not the final
72
+ epoch-3 weights, which scored 0.4310.
73
 
74
  ## Training summary
75
 
76
  - Framework: Axolotl / Transformers
77
+ - Method: full-parameter supervised fine-tuning
78
+ - Data: 169,919 conversational examples (Uzbek-first, with task-format and
79
+ English retention data)
80
+ - Sequence length: 2,048, one sample per sequence (no packing)
81
+ - Epochs: 3, best checkpoint by benchmark score taken at 1.5 epochs
82
+ - Effective batch size: 32
83
+ - Learning rate: 1e-5, cosine schedule, 3% warmup
84
+ - Optimizer: AdamW, β₂ = 0.95, gradient clipping 1.0
85
+ - Precision: bf16
86
+ - Loss on assistant turns only; `<|im_end|>` trained as the turn terminator
87
+
88
+ The training data is not included in this repository.
 
 
89
 
90
  ## Usage
91
 
92
  ```python
 
93
  import torch
94
+ from transformers import AutoModelForCausalLM, AutoTokenizer
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
 
96
  model_id = "NeuronUz/qwen3.5-2b-fine-tuned"
 
 
97
 
98
  tokenizer = AutoTokenizer.from_pretrained(model_id)
99
  model = AutoModelForCausalLM.from_pretrained(
100
  model_id,
101
+ dtype=torch.bfloat16,
102
+ device_map="cuda:0", # keep this hybrid model on a single device
 
103
  )
104
 
105
  messages = [
106
+ {"role": "system", "content": "Siz foydali AI yordamchisiz."},
 
 
 
 
 
 
 
107
  {"role": "user", "content": "O'zbekiston haqida qisqacha ma'lumot bering."},
108
  ]
109
 
 
114
  return_dict=True,
115
  ).to(model.device)
116
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  with torch.inference_mode():
118
+ output = model.generate(**inputs, max_new_tokens=512, do_sample=False)
119
+
 
 
 
 
 
 
 
 
 
 
120
  reply = tokenizer.decode(
121
+ output[0][inputs["input_ids"].shape[-1]:], skip_special_tokens=True
122
  ).strip()
123
+ print(reply)
124
+ ```
125
 
126
+ No stopping criteria, repetition penalty, or `no_repeat_ngram_size` are needed
127
+ the model emits `<|im_end|>`, and `generation_config.json` already registers it
128
+ as an end-of-sequence token.
 
 
 
129
 
130
+ ### Multi-turn chat
131
+
132
+ ```python
133
+ messages = [{"role": "system", "content": "Siz foydali AI yordamchisiz."}]
134
+
135
+ while True:
136
+ user = input("> ").strip()
137
+ if user in {"", "exit", "quit"}:
138
+ break
139
+ messages.append({"role": "user", "content": user})
140
+
141
+ inputs = tokenizer.apply_chat_template(
142
+ messages,
143
+ add_generation_prompt=True,
144
+ return_tensors="pt",
145
+ return_dict=True,
146
+ ).to(model.device)
147
+
148
+ with torch.inference_mode():
149
+ output = model.generate(**inputs, max_new_tokens=512, do_sample=False)
150
+
151
+ reply = tokenizer.decode(
152
+ output[0][inputs["input_ids"].shape[-1]:], skip_special_tokens=True
153
+ ).strip()
154
+ print(reply)
155
+ messages.append({"role": "assistant", "content": reply})
156
+ ```
157
+
158
+ ### vLLM
159
+
160
+ ```python
161
+ from vllm import LLM, SamplingParams
162
+
163
+ llm = LLM(model="NeuronUz/qwen3.5-2b-fine-tuned", max_model_len=4096)
164
+ params = SamplingParams(temperature=0.0, max_tokens=512)
165
+
166
+ messages = [
167
+ {"role": "system", "content": "Siz foydali AI yordamchisiz."},
168
+ {"role": "user", "content": "Bugungi ob-havo haqida nima deya olasiz?"},
169
+ ]
170
+ print(llm.chat(messages, params)[0].outputs[0].text)
171
  ```
172
 
173
+ ### Notes
174
 
175
+ - Requires a Transformers release with Qwen3.5 support.
176
+ - Greedy decoding (`do_sample=False`) was used for all benchmark numbers above.
177
+ For sampling, a reasonable starting point is `temperature=0.7`, `top_p=0.8`,
178
+ `top_k=20`.
179
+ - Avoid `device_map="auto"` when several GPUs are visible: current
180
+ Accelerate/Transformers releases may split the Qwen3.5 hybrid layers across
181
+ devices and produce invalid text. Pin the model to one device as shown.
182
 
183
  ## Limitations
184
 
185
+ The model may produce inaccurate, biased, or fabricated information. Uzbek
186
+ multi-subject knowledge (TUMLU) is close to the random baseline, so factual
187
+ answers in specialist domains should not be trusted. It has not been
188
+ comprehensively evaluated for safety or high-stakes use. Verify outputs
189
+ independently before relying on them in medical, legal, financial, or other
190
  consequential settings.
model.safetensors CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:d41fe7acbe94f42dde8dd12e48c791628a1a9a22343e3eaf910b9d4b03813ee1
3
  size 4781022144
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d39d981c03f63bb711d44ab9a7fb963dc118f57eef0cc00bff9d39543e086f03
3
  size 4781022144
tokenizer_config.json CHANGED
@@ -10,7 +10,7 @@
10
  "errors": "replace",
11
  "image_token": "<|image_pad|>",
12
  "is_local": true,
13
- "local_files_only": false,
14
  "model_max_length": 262144,
15
  "model_specific_special_tokens": {
16
  "audio_bos_token": "<|audio_start|>",
 
10
  "errors": "replace",
11
  "image_token": "<|image_pad|>",
12
  "is_local": true,
13
+ "local_files_only": true,
14
  "model_max_length": 262144,
15
  "model_specific_special_tokens": {
16
  "audio_bos_token": "<|audio_start|>",