Files
qwen3-1.7b-json/README.md
ModelHub XC 50ba52db7e 初始化项目,由ModelHub XC社区提供模型
Model: ujwal00/qwen3-1.7b-json
Source: Original Platform
2026-07-21 20:34:14 +08:00

117 lines
5.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
license: apache-2.0
base_model: Qwen/Qwen3-1.7B
pipeline_tag: text-generation
library_name: transformers
tags:
- json
- json-schema
- structured-output
- qlora
- function-calling
datasets:
- ujwal00/jsonschema-sft
language:
- en
---
# Qwen3-1.7B-JSON — native JSON-Schema compliance fine-tune
Fine-tune of **Qwen/Qwen3-1.7B** that emits JSON conforming to a requested
**JSON Schema** *natively* — no grammar-constrained decoding — with a large
gain on the hard case: **nested / `$ref` / `$defs` schemas**.
- **Base model:** Qwen/Qwen3-1.7B (Apache-2.0)
- **Method:** QLoRA SFT (Unsloth), r=16, α=32, 2 epochs, NEFTune α=5
- **Data:** ~4k schema→valid-instance pairs generated from JSONSchemaBench
*train-split* schemas (72% nested), every target validated with a
Draft-2020-12 validator; val/test schemas hash-excluded (decontaminated)
- **Eval:** native (unconstrained, greedy) schema-compliance, scored with the
Draft-2020-12 validator + full format checker
## Results (held-out, measured identically base vs fine-tuned)
Measured on 150200 held-out schemas the model never trained on. Fine-tuned
result independently cross-checked via the merged fp16 model (74% nested).
| Metric | Base Qwen3-1.7B | **Fine-tuned** | Δ |
|---|---|---|---|
| Nested / `$ref` schemas | 58% | **7274%** | **+1416** |
| Flat schemas | 87% | **92%** | +5 |
| Overall | 72.5% | **8283%** | +10 |
| Parse-fail rate | 4% | **2.54%** | ~flat |
## Official results — JSONSchemaBench test split (n=360, native/unconstrained)
Base Qwen3-1.7B vs fine-tuned, identical prompt + Draft-2020-12 validator, greedy.
| Dataset | Base | Fine-tuned | Gain |
|---|---|---|---|
| Github_trivial | 49% | **82%** | +33% |
| Github_easy | 78% | **93%** | +16% |
| Github_medium | 42% | **56%** | +13% |
| Github_hard | 11% | **24%** | +13% |
| Glaiveai2K | 98% | **96%** | -2% |
| Kubernetes | 53% | **67%** | +13% |
| Snowplow | 33% | **73%** | +40% |
| JsonSchemaStore | 31% | **42%** | +11% |
| **Overall** | 49% | **67%** | +17% |
**McNemar paired test:** 76 schemas fixed, 14 broke, p=1.78e-11 (highly significant).
Our base measurement aligns with the published Llama-3.2-1B native numbers
(confirming comparability); the fine-tune beats published small-model native
compliance on nearly every dataset.
## Why this matters
Small models are widely deployed for narrow, high-volume, structured tasks —
but their published *native* schema-compliance collapses on complex schemas
(JSONSchemaBench reports ~1338% for small models on the hardest datasets).
This fine-tune lifts native compliance on exactly that hard regime, so the
model is more usable **without** attaching a constrained-decoding engine
(and better as a base *with* one).
## How to use
```python
from transformers import AutoModelForCausalLM, AutoTokenizer
import json, torch
m = AutoModelForCausalLM.from_pretrained("ujwal00/qwen3-1.7b-json", dtype=torch.float16, device_map="auto")
tok = AutoTokenizer.from_pretrained("ujwal00/qwen3-1.7b-json")
SYSTEM = ("You are a precise JSON generator. Given a JSON Schema, output ONE JSON value "
"that strictly validates against it. Output ONLY the JSON value.")
schema = {"type":"object","properties":{"name":{"type":"string"},"age":{"type":"integer"}},"required":["name","age"]}
msgs = [{"role":"system","content":SYSTEM},
{"role":"user","content":f"Generate a JSON value that validates against this JSON Schema:\n\n{json.dumps(schema)}\n\nReturn only the JSON value."}]
ids = tok.apply_chat_template(msgs, add_generation_prompt=True, enable_thinking=False, return_tensors="pt").to(m.device)
out = m.generate(ids, max_new_tokens=512, do_sample=False)
print(tok.decode(out[0][ids.shape[1]:], skip_special_tokens=True))
```
**Low-VRAM machines** (e.g. a 6 GB laptop GPU): add `low_cpu_mem_usage=True` to
`from_pretrained` (and optionally `max_memory={0: "5GiB", "cpu": "6GiB"}`) so
loading doesn't exhaust memory. On a normal 8 GB+ GPU the snippet above works as-is.
### Verified live output
| Schema | Model output | Valid? |
|---|---|---|
| `{name:str, age:int}` (required both) | `{"name": "sample_value", "age": 50}` | ✅ |
| nested: user{id,email:email-format, roles:enum[]} | `{"user": {"id": 50, "email": "user@example.com", "roles": ["user"]}}` | ✅ |
## Limitations (stated honestly)
- Numbers are **native / unconstrained**; constrained decoding scores differently and is out of scope.
- Trained on JSONSchemaBench-style schemas; may generalize less to very different schema dialects.
- Ultra-large schemas (>4000 chars) were excluded from training data.
- Reported gains are on held-out gold; the official test-split table is the definitive comparison.
## Reproducibility
Data recipe, generator, validator, training + eval code, and manifest are in the
project repo (`jsonc/`, `kaggle/`). Seed=42; prompt hashed; validator format
self-tested. Base and fine-tuned measured with identical prompt/validator/greedy.