Downloads · 30 days
0
AmeenAhmed2/zico
zico is a zero-shot classification model from AmeenAhmed2. Use it when you need labels you did not train the model on. The card lists the license as cc-by-nc-4.0.
zico is a 4B decision model. You give it a state (a message, a document, a JSON object, an image) and a set of typed questions. It answers every question with a calibrated probability distribution over the options you…
Downloads · 30 days
0
Access
Public
Updated Sep 20, 2026
Repo size
9.1 GB
Likes
0
Public
Click a slice to open those files.
.safetensors9.1 GB · 100%
From the Hugging Face model README
zico is a 4B decision model. You give it a state (a message, a document, a JSON object, an image) and a set of typed questions. It answers every question with a calibrated probability distribution over the options you listed — in one forward pass, without generating any text.
// request // response
{ "state": { "ticket": { "body": "Charged twice, refund me { "answers": {
or I cancel." } }, "wants_refund": { "type": "noul", "noul": 0.89 },
"questions": { "team": { "type": "choice", "choice": "billing",
"wants_refund": { "type": "noul", "probabilities": { "billing": 0.94, "technical": 0.02, … },
"instructions": "The customer asks for a refund." }, "confidence": 0.81 },
"team": { "type": "choice", "frustration": { "type": "score", "score": 2.26,
"instructions": "Which team should handle this?", "probabilities": { "0": 0.04, "1": 0.08, "2": 0.54, … } } },
"criteria": { "billing": "Charges, refunds", "usage": { "input_tokens": 240, "output_tokens": 0 } }
"technical": "Bugs, outages", … } },
"frustration": { "type": "score",
"criteria": ["Calm", "Annoyed", "Frustrated", "Angry", "Furious"] } } }
It is meant for the many small decisions inside software — routing, triage, moderation, guardrails, tool selection, "is this answer grounded?", document and image sorting — where you want a fast, cheap, typed answer with a probability you can threshold, not a paragraph to parse.
| Question type | You provide | You get |
|---|---|---|
| Choice | 2–255 named options, each with an optional description | the most likely option, the full distribution, a confidence |
| Score | an ordered rubric of 2–10 level descriptions, lowest first | the expected level (e.g. 2.26), the distribution over levels |
| Noul | a statement that is true or false about the state | the probability that it is true |
pip install -U "huggingface_hub[cli]"
hf download AmeenAhmed2/zico --local-dir zico && cd zico
python -m venv .venv && source .venv/bin/activate
pip install -e ".[serve]" # Apple silicon: pip install -e ".[serve,mlx]"
python scripts/infer.py . examples/request.json
On Apple silicon scripts/infer.py (PyTorch) works but is slow — there is no fused Gated-DeltaNet kernel for MPS, so a
request takes ≈1.7 s; the server below uses the MLX backend there and answers in ≈0.3 s.
The repository is the checkpoint and the code that runs it (zico/, a small Python package). The model cannot be
loaded with transformers.AutoModel alone: the language backbone is a standard Qwen3.5 checkpoint, but the decision
head and the input format are zico's own.
import torch
from zico import DecisionModel, Choice, Score, Noul
model, renderer, _ = DecisionModel.load(".", device="cuda", dtype=torch.bfloat16) # or "mps" / "cpu"
model.autocast_dtype = torch.bfloat16
answers = model.answer(
renderer,
state={"message": "hey can u move my 3pm with dr patel to next week, mornings are better"},
questions={
"intent": Choice("What does the patient want?", {"book": None, "reschedule": None, "cancel": None, "billing": None, "other": None}),
"time_preference": Noul("The patient states a preferred time of day."),
"urgency": Score("How urgent is this?", ["Whenever", "This week", "Today", "Emergency"]),
},
)
print(answers["answers"]["intent"]) # {'type': 'choice', 'choice': 'reschedule', 'probabilities': {...}, 'confidence': ...}
An image is a JSON object inside the state — {"type": "image", "data": "<base64>"}, optionally with
"detail": "low" | "high" (64 to 1,024 image tokens; default ≤ 256):
import base64
photo = {"type": "image", "data": base64.b64encode(open("scan.png", "rb").read()).decode()}
model.answer(renderer, {"scan": photo}, {"kind": Choice("What type of document is this?", {"invoice": None, "letter": None, "form": None, "resume": None})})
ZICO_CKPT=. scripts/serve.sh start # also: stop | restart | status | log | key-path
This starts a small FastAPI server on http://127.0.0.1:8787 (on Apple silicon it uses the MLX backend automatically):
POST /v1/systemone with Authorization: Bearer <key> takes the JSON request shown at the top (plus
"model": "zico") and returns the response shown there. A key is generated on first start; scripts/serve.sh key-path
says where it is.GET / is a test page: write a state, drop in an image, build questions, and watch the probability bars. "Live"
mode re-runs on every edit and shows how far each probability moved.The request and response shapes follow the System One wire format that TypeSafe AI documents publicly for its API, so
client code written for that format can be pointed at this server (ZICO_MODEL_ALIASES adds any fixed model name such a
client sends). See "Relation to other work" below.
row = ### State\n{state}\n\n ### Choice\n{instructions}\n- billing: Charges…<OPT>\n- technical: Bugs…<OPT>\nAnswer:<ANS>
└──── shared prefix ────┘ └──────────────────────────── one question ──────────────────────────────────────┘
logit_i = q(h[<ANS>]) · k(h[<OPT>_i]) / √d + u(h[<OPT>_i]) p = softmax over this question's own options
Qwen/Qwen3.5-4B-Base (a hybrid of Gated-DeltaNet and attention layers), fully fine-tuned, language-model
head removed. It is only ever used for prefill: there is no decoding loop.<OPT> slot and each question in an <ANS> slot. Their input
embeddings come from a learned 4-row table, so the tokenizer and embedding matrix are untouched.<ANS> is scored against the hidden state at every <OPT>; the softmax runs
over exactly those positions. Choice → arg-max key, Score → Σ i·pᵢ, Noul → p(true), confidence = 1 − H(p)/log K. The
head has 1.3M parameters.(state + question) row per question. At inference the state is
prefilled once and its cache — attention KV and the recurrent / convolution state of the DeltaNet layers — is
forked across the questions, which run as one batch. Because the backbone is causal both compute the same function;
the test-suite asserts it.vision/), placed where the image
sits in the state's JSON, with Qwen's 3-part rotary positions. They are part of the shared prefix, so an image is
encoded once for all questions.Training and data-building code is in scripts/ (build_data.py, build_image_data.py, make_soft_targets.py,
train.py, eval.py).
All numbers are this checkpoint, bf16, raw probabilities unless stated. "Held out" means the dataset (or the whole instruction task) never appeared in training, so the label set and the wording are new to the model. Sample sizes are small (150–500 per set; 5.5k for the unseen-task pool): differences under ≈3 points are noise.
Text, held-out (zero-shot)
| Set | Question | Accuracy | ECE |
|---|---|---|---|
| ARC-Easy | Choice, free-text options | 97.6 % | 0.031 |
| IMDB sentiment | Noul | 94.0 % | 0.033 |
| MASSIVE, 60 intents | Choice ×60 | 74.6 % | 0.090 |
| 19 unseen Super-NaturalInstructions tasks | mixed | 75.2 % | 0.055 |
| PubMedQA | Choice ×3 | 70.8 % | 0.088 |
| dair-ai/emotion | Choice ×6 | 58.0 % | 0.200 |
| AskUbuntu duplicate reranking (pick 1 of many) | Choice | 51.8 % | 0.161 |
Text, in-distribution test split: 86.2 % over 37 sources (3,000 rows). Examples: Banking77 96.7 %, CLINC-150 with out-of-scope 95.3 %, AG News 93.0 %, MNLI 92.0 %, BoolQ 92.0 %, VitaminC fact-checking 92.9 %, SQuAD-v2 answerability 88.0 %, jailbreak / prompt-injection detection 100 % (small sets), SST-5 67.3 %, MS MARCO passage selection 57.1 %. By question type over the whole test split (text and images): Choice 90.0 %, Noul 92.3 %, Score 68.5 % exact level.
Images, held-out sets (zero-shot: never trained on, full label set in every question)
| Set | Options per question | Accuracy | ECE |
|---|---|---|---|
| CIFAR-10 | 10 | 97.7 % | 0.024 |
| MNIST digits | 10 | 95.3 % | 0.032 |
| POPE object presence | Noul | 90.0 % | 0.073 |
| Food-101 | 101 | 87.7 % | 0.043 |
| Oxford-IIIT pets | 37 | 85.0 % | 0.064 |
Images, test splits of the training sets. As in training, a question lists either the full label set or a random subset that contains the right answer, and about a quarter are "the image shows X" Noul questions — so these are easier than standard full-label benchmarks and are not comparable to published leaderboard numbers. 150–300 questions per set.
| Set | Options per question | Accuracy | ECE |
|---|---|---|---|
| RVL-CDIP scanned document types | 6 or all 16 | 92.3 % | 0.036 |
| Stanford Cars | 8–64 of 196 | 98.5 % | 0.023 |
| EuroSAT land use | 5 or all 10 | 97.0 % | 0.023 |
| SUN397 scenes | 8–64 of 397 | 96.6 % | 0.028 |
| ImageNet-100 | 8–100 | 95.2 % | 0.017 |
| RESISC45 aerial scenes | 8–45 | 94.5 % | 0.032 |
| CIFAR-100 | 10–100 | 93.6 % | 0.026 |
| DTD textures | 8–47 | 93.3 % | 0.046 |
| CUB-200 birds | 8–64 of 200 | 92.8 % | 0.034 |
| GTSRB traffic signs | 8–43 | 92.7 % | 0.035 |
Calibration. Over all 9.9k held-out rows (text and images): ECE 0.055 raw, 0.041 with the stored temperatures. On the
in-distribution test split: 0.011 raw. Full per-source results are in eval.json.
Consistency. Forked (batched) answers equal single-question answers to ≈1e-6 in fp32 (6e-5 in bf16 on an H100). The MLX backend matches PyTorch: 388 probabilities from real requests differ by 0.0003 on average, with the same top answer every time.
scripts/build_data.py --exclude-nc builds the text set without the two non-commercial text
sources if you want to train a variant.zico/, scripts/, tests/): Apache-2.0.vision/ is the unmodified vision tower of Qwen/Qwen3.5-4B-Base (Apache-2.0, © Alibaba Cloud), redistributed so the
checkpoint is self-contained. See NOTICE.@misc{zico2026,
title = {zico: a calibrated, typed decision model in a single forward pass},
author = {AmeenAhmed2},
year = {2026},
url = {https://huggingface.co/AmeenAhmed2/zico}
}