cudabenchmarktest commited on
Commit
f1b6e3f
·
verified ·
1 Parent(s): 8bfab3d

Add model card with YAML metadata

Browse files
Files changed (1) hide show
  1. README.md +25 -235
README.md CHANGED
@@ -1,250 +1,40 @@
1
  ---
 
2
  base_model: Qwen/Qwen3.5-9B
 
 
 
 
 
 
 
3
  datasets:
4
- - Crownelius/Opus-4.6-Reasoning-3300x
5
- library_name: peft
6
- license: apache-2.0
7
- language:
8
- - en
9
  pipeline_tag: text-generation
10
- tags:
11
- - reasoning
12
- - distillation
13
- - lora
14
- - qwen3.5
15
- - sft
16
- - tool-use
17
- - function-calling
18
- - vision
19
- - multimodal
20
- - thinking
21
  ---
22
 
23
- # qwen3.5-9b-qwen3.6-distilled (r3-crown)
24
-
25
- LoRA adapter distilled from reasoning traces in
26
- [`Crownelius/Opus-4.6-Reasoning-3300x`](https://huggingface.co/datasets/Crownelius/Opus-4.6-Reasoning-3300x)
27
- on top of [`Qwen/Qwen3.5-9B`](https://huggingface.co/Qwen/Qwen3.5-9B).
28
- Packaged for Ollama via `llama-export-lora` so the base model's vision
29
- tower, tool-calling handlers, and native Q4_K_M quantization are preserved
30
- byte-for-byte — only the text-reasoning tensors our LoRA touched are
31
- updated.
32
-
33
- ## What ships
34
-
35
- | Artifact | Purpose |
36
- |---|---|
37
- | `adapter_model.safetensors` | PEFT LoRA weights (attention + MLP + linear_attn targets, 496 tensors total) |
38
- | `adapter_config.json` | PEFT config |
39
- | `final_report.json` | Machine-readable eval report (hard tool matrix, vision probe, OCR tool demo, training metrics) |
40
- | `filtered_adapter/` | LoRA with `linear_attn.*` tensors removed — this is what converts cleanly to GGUF |
41
- | GGUF repo | `llama-export-lora` merged into base `qwen3.5:9b` Q4_K_M GGUF + Modelfile |
42
-
43
- ## Build pipeline (the path that actually works)
44
-
45
- The single-file combined-GGUF path via `convert_hf_to_gguf.py` is blocked
46
- for Qwen3.5 multimodal today: it emits a separate `clip.*` mmproj GGUF
47
- which is incompatible with Ollama's native `qwen35.vision.*` loader
48
- format. We solved this by not rebuilding the base GGUF at all.
49
-
50
- ```bash
51
- # 1. Train LoRA (target_modules="all-linear" for completeness)
52
- python app.py train # produces final_adapter/
53
-
54
- # 2. Drop the Gated DeltaNet LoRA tensors — llama.cpp's lora-to-gguf
55
- # converter can't reshape-reorder the v-heads inside a low-rank
56
- # A@B decomposition. We keep attention + MLP targets, which are
57
- # 256/496 of the tensors in the adapter.
58
- .venv/bin/python -c "
59
- from safetensors.torch import load_file, save_file
60
- import json
61
- w = load_file('final_adapter/adapter_model.safetensors')
62
- save_file({k:v for k,v in w.items() if 'linear_attn' not in k},
63
- 'final_adapter_filtered/adapter_model.safetensors')
64
- cfg = json.load(open('final_adapter/adapter_config.json'))
65
- cfg['target_modules'] = ['q_proj','k_proj','v_proj','o_proj','gate_proj','up_proj','down_proj']
66
- json.dump(cfg, open('final_adapter_filtered/adapter_config.json','w'), indent=2)
67
- "
68
-
69
- # 3. Convert filtered LoRA to GGUF
70
- python vendor/llama.cpp/convert_lora_to_gguf.py final_adapter_filtered/ \
71
- --outtype f16 --outfile lora.f16.gguf \
72
- --base outputs/merged_vision/...
73
-
74
- # 4. Merge LoRA into the base qwen3.5:9b Q4_K_M GGUF byte-for-byte
75
- vendor/llama.cpp/build/bin/llama-export-lora \
76
- --model /srv/ollama/models/blobs/sha256-dec52a... \
77
- --lora lora.f16.gguf \
78
- --output merged.q4km.gguf
79
-
80
- # 5. Register with Ollama
81
- cat > Modelfile <<'EOM'
82
- FROM ./merged.q4km.gguf
83
- RENDERER qwen3.5
84
- PARSER qwen3.5
85
- PARAMETER temperature 0.6
86
- PARAMETER top_p 0.95
87
- PARAMETER stop "<|im_end|>"
88
- EOM
89
- ollama create qwen3.5-9b-qwen3.6-distilled:crown -f Modelfile
90
- ```
91
-
92
- `llama-export-lora` updates the **128 text tensors** the filtered LoRA
93
- covers (q/k/v/o + gate/up/down in the standard attention/MLP layers) and
94
- leaves the other **755 tensors** (all 441 vision + 15 MTP + the linear_attn
95
- DeltaNet tensors + embeddings + norms) **exactly as base**. Vision is
96
- therefore not "preserved via state-dict surgery"; it is **literally the
97
- base model's vision**, bit-for-bit.
98
-
99
- ## Capabilities — verified via Ollama
100
-
101
- ```
102
- $ ollama show qwen3.5-9b-qwen3.6-distilled:crown
103
- architecture qwen35
104
- parameters 9.7B
105
- Capabilities
106
- completion
107
- vision
108
- tools
109
- thinking
110
- ```
111
-
112
- Smoke-test results (deterministic, `temperature=0`):
113
-
114
- | Path | Result |
115
- |---|---|
116
- | Completion | ✅ `7 * 23 - 45` → step-by-step → `116` (correct) |
117
- | Thinking | ✅ 706-char `<think>` block before the answer |
118
- | Tool calling | ✅ `get_weather({"city": "Paris"})` — structured `tool_calls` |
119
- | Vision | ✅ Base-level: 1/3 on 3-image rendered-text probe, identical failure pattern to base |
120
-
121
- ## Hard tool-calling stress test — 22 scenarios
122
-
123
- Deterministic (`temperature=0, top_p=1, top_k=1, seed=42`) via the OpenAI-
124
- compatible gateway at `http://localhost:11435/v1/chat/completions`.
125
-
126
- | | Base `qwen3.5:9b` | Crown `:crown` |
127
- |---|---:|---:|
128
- | **Score** | **21 / 22** | **21 / 22** |
129
- | HX8 (G7 capitals, 7 parallel calls) | PASS | **PASS** ← fixed |
130
- | HX7 (roll_dice count=5000 vs schema max=1000) | FAIL | FAIL ← shared weakness |
131
- | H1 many-tool distraction latency | 8.4 s | **0.8 s** (10× faster) |
132
-
133
- **HX8 is the critical one.** Our first adapter (r1, trained on the
134
- original 500-row dataset) failed HX8 by substituting Brussels for
135
- Washington D.C. That was a factual regression from distillation on a
136
- small dataset. The r3-crown pipeline fixes it two ways at once:
137
-
138
- 1. **Retrain on a larger, better-aligned dataset** (Crownelius has 2160
139
- rows vs 500) — best val loss dropped from 0.7030 → **0.4439**.
140
- 2. **Merge into base rather than replacing weights** — 755/883 tensors
141
- are bit-for-bit from base, so base's factual knowledge can't be
142
- regressed by LoRA overfitting on the unmodified tensors.
143
-
144
- **HX7 is a shared base-model weakness** (both models call
145
- `roll_dice(count=5000)` ignoring the JSON Schema `maximum: 1000`). Not
146
- introduced by distillation; documented honestly.
147
-
148
- ## Image handling — base-level vision preserved
149
-
150
- | Probe | Base | Crown |
151
- |---|---|---|
152
- | `HELLO` 72pt on black | "HILO" (wrong) | "HILO" (wrong) |
153
- | `42` 72pt on red | **"42"** ✓ | **"42"** ✓ |
154
- | `BANANA` 72pt on yellow | "BANA" (wrong) | "BANA" (wrong) |
155
-
156
- Character-identical outputs confirm the vision tensors are not just
157
- "preserved" but literally the base model's weights — because we merged
158
- the LoRA into base, not the other way around. If you need OCR with higher
159
- fidelity, use the OCR-via-tool pattern below.
160
-
161
- ## OCR-via-tool (recommended for small/dense text)
162
-
163
- No 9B VLM reliably reads small dense text pixel-perfectly. The distilled
164
- model's tool-calling strength makes it an excellent OCR orchestrator:
165
-
166
- ```
167
- user: "What is the total on this receipt? /path/receipt.png"
168
-
169
- crown model emits: extract_text_from_image({"image_path": "/path/receipt.png"})
170
-
171
- tool runs Tesseract with 8 preprocessing variants × 3 PSM modes = 24 passes,
172
- returns best-scored text (88-91% confidence typical)
173
-
174
- crown model: "Based on the receipt, the total is EUR 34.76. Card: VISA ..."
175
- ```
176
-
177
- On our 4-case hard benchmark (two images — a dense 19-line security log
178
- and a coffee receipt — with four questions across them), crown scored
179
- **4/4**, including:
180
-
181
- - Quoting the exact error line verbatim from a 1126-char log extraction
182
- - Distinguishing training loss from validation loss in the quoted text
183
- - Extracting per-item costs from a monospace receipt
184
-
185
- See `final_report.json → ocr_via_tool` for the full transcript with all
186
- tool calls.
187
-
188
- ## Training recipe
189
 
190
- | | Round 1 (superseded) | Round 3 (crown, shipped) |
191
- |---|---|---|
192
- | Dataset | `khazarai/qwen3.6-plus-high-reasoning-500x` | `Crownelius/Opus-4.6-Reasoning-3300x` |
193
- | Rows | 500 | 2160 |
194
- | Splits | 425 / 37 / 38 | 1836 / 162 / 162 |
195
- | Epochs | 3 | early-stopped at 1.17 |
196
- | Steps completed | 54 | 90 |
197
- | LR | 2e-4 cosine | 2e-4 cosine |
198
- | LoRA | r=32 α=64 all-linear | r=32 α=64 all-linear |
199
- | Max seq length | 8192 | 5120 (capped for long tail) |
200
- | **Best val loss** | 0.7030 | **0.4439** |
201
- | Hardware | 3× A100 80GB PCIe DDP | 3× A100 80GB PCIe DDP |
202
- | Training time | 49 min | 28 min |
203
 
204
- ## Limitations
205
 
206
- - **HX7**: both crown and base ignore JSON Schema `maximum: 1000` on numeric
207
- arguments. Don't rely on schema range enforcement as a safety mechanism.
208
- - **`linear_attn` LoRA weights are not packaged in the GGUF** because
209
- llama.cpp's LoRA converter can't reorder v-heads inside a low-rank A@B
210
- decomposition. The HF PEFT adapter (`adapter_model.safetensors`) does
211
- contain them, so if you use this via `transformers + peft` you get the
212
- full LoRA; the Ollama GGUF gets ~52% of LoRA tensors.
213
- - **Vision OCR fidelity** on small dense text is base-level (matches
214
- `qwen3.5:9b`). Use `extract_text_from_image` tool for reliable reads.
215
- - **Non-determinism** at default `temperature=0.6`. Published numbers are
216
- at `temperature=0`.
217
 
218
- ## Running it
219
 
220
- ```bash
221
- # Recommended: pull the merged GGUF + Modelfile from the GGUF repo
222
- hf download cudabenchmarktest/qwen3.5-9b-qwen3.6-reasoning-distilled-GGUF \
223
- Modelfile merged.q4km.gguf \
224
- --local-dir ./qwen-crown
225
- cd qwen-crown
226
- ollama create qwen3.5-9b-qwen3.6-distilled:crown -f Modelfile
227
- ollama show qwen3.5-9b-qwen3.6-distilled:crown # should list: completion, vision, tools, thinking
228
- ollama run qwen3.5-9b-qwen3.6-distilled:crown
229
- ```
230
 
231
- ```bash
232
- # Or hit /api/chat with tools + images
233
- curl -s http://localhost:11434/api/chat -d '{
234
- "model": "qwen3.5-9b-qwen3.6-distilled:crown",
235
- "messages": [{"role": "user", "content": "Weather in Paris?"}],
236
- "tools": [{"type":"function","function":{"name":"get_weather","description":"...","parameters":{"type":"object","properties":{"city":{"type":"string"}},"required":["city"]}}}],
237
- "stream": false
238
- }' | jq .message.tool_calls
239
- ```
240
 
241
- ## Audit trail
 
 
 
242
 
243
- All probe scripts + raw result JSONs are in this repo:
244
 
245
- - `scripts/hard_tool_tests.py` 22 deterministic tool-calling scenarios
246
- - `scripts/ocr_tool_demo.py` — end-to-end OCR-as-tool agent loop
247
- - `scripts/image_probe.py` — 3-image vision probe
248
- - `tool_bench/` — raw per-row results for every probe
249
- - `final_report.json` — everything merged, schema-stable
250
- - `crown_manifest.json` — dataset split SHAs (seed 42)
 
1
  ---
2
+ license: apache-2.0
3
  base_model: Qwen/Qwen3.5-9B
4
+ tags:
5
+ - qwen3.5
6
+ - reasoning
7
+ - distillation
8
+ - lora
9
+ - sft
10
+ - gguf
11
  datasets:
12
+ - Crownelius/Opus-4.6-Reasoning-3300x
 
 
 
 
13
  pipeline_tag: text-generation
 
 
 
 
 
 
 
 
 
 
 
14
  ---
15
 
16
+ # Qwen3.5-9B Reasoning Distilled GGUF (R3 Crown)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
+ GGUF quantized version of fine-tuned [Qwen3.5-9B](https://huggingface.co/Qwen/Qwen3.5-9B) with distilled Opus 4.6 reasoning traces. Early iteration (R3) — superseded by [R7 (86.8% diverse eval)](https://huggingface.co/cudabenchmarktest/qwen3.5-9b-r7-research).
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
+ ## Training
21
 
22
+ - **Base model**: [Qwen/Qwen3.5-9B](https://huggingface.co/Qwen/Qwen3.5-9B)
23
+ - **Method**: LoRA SFT (r=32, alpha=64, LR=2e-4)
24
+ - **Data**: [Crownelius/Opus-4.6-Reasoning-3300x](https://huggingface.co/datasets/Crownelius/Opus-4.6-Reasoning-3300x) (2160 samples)
25
+ - **Training suite**: [robit-man/fine_tuning_suite](https://github.com/robit-man/fine_tuning_suite)
 
 
 
 
 
 
 
26
 
27
+ ## Note
28
 
29
+ This early iteration had regressions in instruction following due to monoculture training data. See the [training suite](https://github.com/robit-man/fine_tuning_suite) for the improved R5/R7 approach.
 
 
 
 
 
 
 
 
 
30
 
31
+ ## Successors
 
 
 
 
 
 
 
 
32
 
33
+ | Model | Eval | Link |
34
+ |-------|------|------|
35
+ | R7 Research | 86.8% | [cudabenchmarktest/qwen3.5-9b-r7-research](https://huggingface.co/cudabenchmarktest/qwen3.5-9b-r7-research) |
36
+ | R7 Vision | 86.8% | [cudabenchmarktest/qwen3.5-9b-r7-research-vision](https://huggingface.co/cudabenchmarktest/qwen3.5-9b-r7-research-vision) |
37
 
38
+ ## License
39
 
40
+ Apache 2.0 (inherited from Qwen3.5-9B).