Instructions to use davidr99/qwen35-address-std-4B-v5 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use davidr99/qwen35-address-std-4B-v5 with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="davidr99/qwen35-address-std-4B-v5") messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] pipe(text=messages)# Load model directly from transformers import AutoProcessor, AutoModelForMultimodalLM processor = AutoProcessor.from_pretrained("davidr99/qwen35-address-std-4B-v5") model = AutoModelForMultimodalLM.from_pretrained("davidr99/qwen35-address-std-4B-v5", device_map="auto") messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] inputs = processor.apply_chat_template( messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt", ).to(model.device) outputs = model.generate(**inputs, max_new_tokens=40) print(processor.decode(outputs[0][inputs["input_ids"].shape[-1]:])) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use davidr99/qwen35-address-std-4B-v5 with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "davidr99/qwen35-address-std-4B-v5" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "davidr99/qwen35-address-std-4B-v5", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/davidr99/qwen35-address-std-4B-v5
- SGLang
How to use davidr99/qwen35-address-std-4B-v5 with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "davidr99/qwen35-address-std-4B-v5" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "davidr99/qwen35-address-std-4B-v5", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "davidr99/qwen35-address-std-4B-v5" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "davidr99/qwen35-address-std-4B-v5", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }' - Unsloth Studio
How to use davidr99/qwen35-address-std-4B-v5 with Unsloth Studio:
Install Unsloth Studio (macOS, Linux, WSL)
curl -fsSL https://unsloth.ai/install.sh | sh # Run unsloth studio unsloth studio -H 0.0.0.0 -p 8888 # Then open http://localhost:8888 in your browser # Search for davidr99/qwen35-address-std-4B-v5 to start chatting
Install Unsloth Studio (Windows)
irm https://unsloth.ai/install.ps1 | iex # Run unsloth studio unsloth studio -H 0.0.0.0 -p 8888 # Then open http://localhost:8888 in your browser # Search for davidr99/qwen35-address-std-4B-v5 to start chatting
Using HuggingFace Spaces for Unsloth
# No setup required # Open https://huggingface.co/spaces/unsloth/studio in your browser # Search for davidr99/qwen35-address-std-4B-v5 to start chatting
Load model with FastModel
pip install unsloth from unsloth import FastModel model, tokenizer = FastModel.from_pretrained( model_name="davidr99/qwen35-address-std-4B-v5", max_seq_length=2048, ) - Docker Model Runner
How to use davidr99/qwen35-address-std-4B-v5 with Docker Model Runner:
docker model run hf.co/davidr99/qwen35-address-std-4B-v5
qwen35-address-std-4B-v5
Qwen3.5-4B fine-tuned (LoRA, merged 16-bit) for two US-address tasks, selected by the system prompt you send:
- Normalize -- one raw US address string -> a strict JSON object of standardized
components (PostGIS
address_standardizerstdaddr schema, camelCase keys). - Compare -- two addresses (raw + components each) -> per-bucket match verdict
(
MATCH/PLAUSIBLE/NOT_MATCHED).
Trained on dataset revision v5 (pinned tags on both datasets): ~49k unique
normalize rows with 100% US city coverage (all ~18.6k city names from ~30k real
city/state/ZIP triples), plus 8.1k compare rows. 1 epoch, effective batch 16.
v5 output contract (important)
Empty fields are OMITTED from the output JSON (a missing key means "not present in the input"). This cuts output tokens ~43% for proportionally faster generation. Consumers must treat a missing key as empty. Example:
{"houseNum":"4422","predir":"N","name":"GROVE","suftype":"AVE","sufdir":"SW","city":"RIVERSIDE","country":"USA","zipcode":"64150"}
Results
Greedy decoding, enable_thinking=False, on the v5 validation split (2,139 rows, held
out; every val city also appears in train so this measures learned accuracy, not
unseen-city luck).
Normalize: exact-match 2121/2139 = 99.2% (all 16 fields correct simultaneously)
| Field | Acc | Field | Acc | Field | Acc | Field | Acc |
|---|---|---|---|---|---|---|---|
| building | 100.0% | pretype | 100.0% | ruralRoute | 100.0% | country | 100.0% |
| houseNum | 100.0% | name | 99.9% | extra | 99.9% | zipcode | 100.0% |
| predir | 100.0% | suftype | 99.8% | city | 99.5% | box | 100.0% |
| qual | 100.0% | sufdir | 100.0% | state | 99.7% | unit | 99.8% |
No city-spelling alterations were observed in the misses (the 2B variants occasionally garbled rare city names, e.g. PATCHOGUE->PATCHOQUE; the 4B does not). Residual misses are dominated by genuinely ambiguous inputs: a bare state-name word with no ZIP ("3219 Big Spring COURT, NEVADA") can be a city (Nevada, MO) or a state -- either reading is defensible.
Version history (same harness; v4 models evaluated on the v4 split):
| Model | Data | Normalize exact-match | Notes |
|---|---|---|---|
| 2B-v4 | v4 (full JSON) | 98.8% | rare-city spelling garbles present |
| 2B-v5 | v5 (trimmed) | 98.6% | fastest; garbles persist (model-size floor) |
| 4B-v4 | v4 (full JSON) | 99.3% | garbles eliminated |
| 4B-v5 (this) | v5 (trimmed) | 99.2% | garble-free + 43% fewer output tokens |
Comparison task (same harness, 900-row val): 99.9% exact-match across all 7 buckets on the 4B-v4 predecessor; the single miss was a boundary PLAUSIBLE/NOT_MATCHED judgment.
Usage
from transformers import AutoModelForCausalLM, AutoTokenizer
import json, re
repo = "davidr99/qwen35-address-std-4B-v5"
tok = AutoTokenizer.from_pretrained(repo)
mdl = AutoModelForCausalLM.from_pretrained(repo, device_map="auto")
# Qwen3.5 ships a multimodal processor; use the inner text tokenizer if present.
_tok = getattr(tok, "tokenizer", tok)
def run(system, user, max_new_tokens=256):
prompt = _tok.apply_chat_template(
[{"role": "system", "content": system}, {"role": "user", "content": user}],
tokenize=False, add_generation_prompt=True, enable_thinking=False)
inputs = _tok(prompt, return_tensors="pt").to(mdl.device)
out = mdl.generate(**inputs, max_new_tokens=max_new_tokens, do_sample=False)
text = _tok.decode(out[0][inputs["input_ids"].shape[1]:], skip_special_tokens=True)
m = re.search(r"\{.*\}", text, flags=re.DOTALL)
return json.loads(m.group(0)) if m else None
print(run(NORMALIZE_PROMPT, "155 W North St, Wooster OH 44691"))
NORMALIZE_PROMPT and COMPARE_PROMPT are the exact training prompts below (also in
scripts/address_schema.py / scripts/compare_schema.py in this repo). For compare,
build the user turn as:
Address A: <raw A>
A components: <normalize JSON for A>
Address B: <raw B>
B components: <normalize JSON for B>
Normalize system prompt (verbatim)
You standardize a single raw US address string into structured components.
Return ONLY a JSON object using these keys (include ONLY keys that have a value; OMIT absent fields entirely):
building, houseNum, predir, qual, pretype, name, suftype, sufdir,
ruralRoute, extra, city, state, country, zipcode, box, unit
Field meanings & rules:
- building: a named building/place that precedes the street address (e.g. "EMPIRE STATE BUILDING").
- houseNum: the primary street number.
- predir: directional BEFORE the street name (N, S, E, W, NE, NW, SE, SW).
- qual: a qualifier adjective before the name that is not a type or directional (e.g. "OLD", "NEW").
- pretype: street type or route descriptor BEFORE the name (e.g. "AVE", "US RTE", "STATE RTE").
- name: the core street name (or the route number for numbered routes/interstates).
- suftype: street type AFTER the name (e.g. "ST", "RD", "AVE", "BLVD").
- sufdir: directional AFTER the street (post-directional), e.g. "NW" in "Pennsylvania Ave NW".
- ruralRoute: the rural route NUMBER only (e.g. "2" for "RR 2", "1" for "HC 1").
- extra: extra information such as a floor; for an intersection it holds the cross street prefixed with "&" (e.g. "& 5TH AVE").
- city / state / zipcode: the locality, 2-letter state, and ZIP.
- country: always "USA".
- box: a post-office / route box, normalized to "BOX <number>" (e.g. "BOX 152"); drop any "PO"/"P.O." prefix.
- unit: secondary unit (e.g. "APT 5B", "STE 200"), OR any leftover token trailing the street type.
Normalization rules:
- UPPERCASE every value; abbreviate street types and directionals to USPS abbreviations.
- Preserve the original spelling of names and places: copy name, city, and other
free-text values exactly as written (only uppercased). Do NOT fix typos, expand,
or change spelling. (Street types and directionals are still abbreviated as above.)
- "St"/"Saint" before a name is part of the name ("ST CHARLES"), not the type "ST".
- street type before the name -> pretype; after the name -> suftype.
- directional AFTER the street (and after the suftype) -> sufdir (e.g. "NW" in "Pennsylvania Ave NW").
- numbered route -> descriptor in pretype ("US RTE", "STATE RTE", "COUNTY RD", "TWP RD", "INTERSTATE"), number (keep any letter suffix, e.g. "75A") in name.
- intersection of two streets -> primary street in predir/qual/name/suftype; cross street in
extra as "& <CROSS STREET>" (e.g. "& 5TH AVE"); houseNum is omitted.
- any leftover token trailing the street type -> unit (whatever it is).
- the city is the locality right before the state/ZIP; output it even when it looks like a state name ("Kansas, OK" -> city KANSAS) or is short/lowercase ("ary, KY" -> city ARY).
- zipcode may include a ZIP+4 suffix (e.g. "44646-1234"); keep it if present, else use the 5-digit ZIP (omit zipcode when there is none).
- country is always "USA".
- only output fields that are present: never infer or guess a missing city, state, ZIP, or any field from the others -- OMIT the key entirely if it is not in the input.
- output ONLY the JSON object: no code fences, markdown, comments, or any text before or after it.
Compare system prompt (verbatim)
You compare two US addresses and judge whether they refer to the same place, part by part.
You are given two addresses. For each you receive the raw text and its standardized JSON components with keys:
building, houseNum, predir, qual, pretype, name, suftype, sufdir, ruralRoute, extra, city, state, country, zipcode, box, unit
Return ONLY a JSON object with these keys, in this order:
overall_estimate, street, house_number, city, state, zip, unit
Each value is an object of the form {"match_type": "MATCH" | "PLAUSIBLE" | "NOT_MATCHED"}.
Map the components into these buckets:
- street: name, pretype, suftype, predir, sufdir, qual -- plus building and extra (an intersection's cross street).
- house_number: houseNum -- plus box and ruralRoute.
- city: city. state: state. zip: zipcode. unit: unit.
- country is always "USA" and is ignored.
match_type meaning (same logic for every bucket):
- MATCH: the two values are equivalent after standardization. Two empty values also MATCH (both agree the field is absent).
- PLAUSIBLE: cannot be ruled out as the same place. Use when one side is missing the field, or the values are a close variant: a minor spelling difference; a ZIP+4 versus the 5-digit ZIP sharing the same first five digits; a house number differing only by a letter or "1/2"; a street that matches by name but differs in type or directional.
- NOT_MATCHED: both sides have the field and they clearly conflict (different house number, different street name, different city, different state, different 5-digit ZIP, or different unit).
overall_estimate:
- NOT_MATCHED if street, house_number, city, state, or zip is NOT_MATCHED.
- otherwise MATCH if every bucket is MATCH.
- otherwise PLAUSIBLE.
Output the JSON object only.
Deployment notes
- Missing keys = empty. Parse the output into a struct with empty-string defaults.
- Recommended copy-guard:
cityandnameare transcription fields -- their correct value always appears verbatim (case-insensitively) in the input. Validating that at serve time (and snapping to the nearest input span on mismatch) makes spelling drift structurally impossible. - Thinking mode must be disabled (
enable_thinking=False/ a non-thinking chat template). With thinking enabled the model emits reasoning before the JSON. - GGUF: convert with llama.cpp
convert_hf_to_gguf.py --no-mtp(the MTP draft head is for speculative decoding only and is not needed for inference). - Known limitation: a bare state-name token with no ZIP ("..., NEVADA") is inherently ambiguous between city and state; expect occasional disagreement on that class.
Training
- Base:
unsloth/Qwen3.5-4B, LoRA r=16 alpha=16 on attention+MLP projections, merged to 16-bit for release. - 1 epoch over ~57k interleaved rows (normalize + compare), max seq 2048, effective batch 16 (2 x 8 under a 25GB VRAM cap), lr 2e-4, adamw_8bit.
- Data generation, evaluation, and dataset-QA tooling are in
scripts/in this repo (label-first synthetic generator, PostGIS-grammar coverage oracle, regression guard, hard-case miner). Eval notebook:eval_address_model.ipynb.
- Downloads last month
- 10