Upload folder using huggingface_hub
Browse files- README.md +178 -232
- decider_config.json +1 -1
- eval_results.json +0 -0
- model.safetensors +1 -1
README.md
CHANGED
|
@@ -6,39 +6,39 @@ pipeline_tag: text-classification
|
|
| 6 |
tags: [decision-model, calibrated, structured-output, multi-task, system-one, one-pass]
|
| 7 |
---
|
| 8 |
|
| 9 |
-
# decider-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
|
|
|
| 26 |
|
| 27 |
## Usage
|
| 28 |
|
| 29 |
```python
|
| 30 |
from decider.infer import Decider # decider/ is included in this repo
|
| 31 |
-
d = Decider("
|
| 32 |
d.decide("My card was charged twice for the same purchase.",
|
| 33 |
[{"question": "Which department should handle this?", "options": ["billing", "technical support", "sales"]},
|
| 34 |
{"question": "Does this need a refund action?", "options": ["no", "yes"]}])
|
| 35 |
# [{'choice': 'billing', 'confidence': 0.99, 'probs': {...}}, {'choice': 'yes', 'confidence': 0.99, 'probs': {...}}]
|
| 36 |
```
|
| 37 |
|
| 38 |
-
`decide_batch` scores many
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
option, see `decider/prompt.py`).
|
| 42 |
|
| 43 |
The same request shape as TypeSafe's Jev (`POST /v1/systemone`), in process or over HTTP:
|
| 44 |
|
|
@@ -50,26 +50,25 @@ d.system_one({"ticket": {"messages": [{"from": "customer", "text": "I was charge
|
|
| 50 |
"billing": {"what": "Charges, invoices", "not_for": "delivery"}, "other": None}},
|
| 51 |
"refund_requested": {"type": "noul", "instructions": "Does `ticket.messages[0].text` request a refund?"},
|
| 52 |
"frustration": {"type": "score", "instructions": "How frustrated is the customer?", "criteria": ["calm", "frustrated", "very frustrated"]}})
|
| 53 |
-
# {"model": "decider-
|
| 54 |
# "refund_requested": {"type": "noul", "noul": ...}, "frustration": {"type": "score", "score": ..., "legend": {...}, ...}}, "usage": {...}}
|
| 55 |
```
|
| 56 |
|
| 57 |
-
|
| 58 |
-
description may be a string or any JSON value
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
|
| 64 |
For a fixed set of questions, `s = d.schema(questions)` computes the question prefix once and `s(state)` / `s.batch(states)`
|
| 65 |
-
then run only the state (1.2
|
| 66 |
-
accuracy: about 1.5 points on fixed label sets, 5 on per-example options, more on 50
|
| 67 |
-
`
|
|
|
|
| 68 |
|
| 69 |
-
Requirements: `torch`, `transformers>=5`, and `flash-linear-attention` (Triton
|
| 70 |
-
|
| 71 |
-
several times slower). Python 3.11+ recommended so those kernels can use
|
| 72 |
-
`torch.compile`.
|
| 73 |
|
| 74 |
Without the helper package, the same computation in plain `transformers`:
|
| 75 |
|
|
@@ -83,230 +82,177 @@ ids = tok(prompt, return_tensors="pt").to("cuda")
|
|
| 83 |
with torch.no_grad():
|
| 84 |
logits = m(**ids).logits[0, -1]
|
| 85 |
letters = [tok.encode(L, add_special_tokens=False)[0] for L in "ABC"]
|
| 86 |
-
probs = torch.softmax(logits[letters].float(), -1) # -> P(billing), P(technical support), P(sales)
|
| 87 |
```
|
| 88 |
|
| 89 |
-
For several questions in one pass, append further `Question k: ... Answer k: (`
|
| 90 |
-
|
| 91 |
|
| 92 |
## How it works
|
| 93 |
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
training example (gold always kept, order shuffled), so the model conditions on
|
| 100 |
-
the supplied candidates rather than a fixed head.
|
| 101 |
|
| 102 |
## Field types
|
| 103 |
|
| 104 |
-
* **
|
| 105 |
-
* **choice**: argmax option, its probability,
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 127 |
|
| 128 |
## Evaluation
|
| 129 |
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
| **this model (v5)** | in-task (69) | 0.815 | 0.445 | 0.248 | 0.028 | 0.093 | 0.866 |
|
| 137 |
-
| **this model (v5)** | held-out (24) | 0.738 | 0.678 | 0.360 | 0.084 | 0.145 | 0.793 |
|
| 138 |
-
| **this model (v6, T=1.15)** | in-task (69) | 0.813 | 0.450 | 0.251 | 0.032 | 0.094 | 0.864 |
|
| 139 |
-
| **this model (v6, T=1.15)** | held-out (24) | 0.736 | 0.664 | 0.358 | 0.084 | 0.145 | 0.793 |
|
| 140 |
-
| **this model (v8, T=1.30)** | in-task (69) | 0.811 | 0.460 | | 0.037 | | |
|
| 141 |
-
| **this model (v8, T=1.30)** | held-out (24) | 0.741 | 0.655 | | 0.088 | | |
|
| 142 |
-
| v8, questions-first layout (schema cache), T=1.18 | held-out (24) | 0.707 | 0.757 | | 0.104 | | |
|
| 143 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 144 |
|
| 145 |
-
|
|
|
|
|
|
|
| 146 |
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
|
| 150 |
-
|
|
| 151 |
-
|
|
| 152 |
-
|
|
| 153 |
-
|
|
| 154 |
-
|
|
| 155 |
-
|
|
| 156 |
-
|
|
| 157 |
-
|
|
| 158 |
-
|
|
| 159 |
-
|
|
| 160 |
-
|
|
| 161 |
-
|
|
| 162 |
-
|
|
| 163 |
-
|
|
| 164 |
-
|
|
| 165 |
-
|
|
| 166 |
-
|
|
| 167 |
-
|
|
| 168 |
-
|
|
| 169 |
-
|
|
| 170 |
-
|
|
| 171 |
-
|
|
| 172 |
-
|
| 173 |
-
|
|
| 174 |
-
|
|
| 175 |
-
|
|
| 176 |
-
|
|
| 177 |
-
|
|
| 178 |
-
|
|
| 179 |
-
|
| 180 |
-
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
|
| 184 |
-
| hermes_tools | 0.704 / 0.067 | 0.702 / 0.160 | 0.737 / 0.155 |
|
| 185 |
-
| massive_scenario | 0.706 / 0.094 | 0.707 / 0.032 | 0.815 / 0.023 |
|
| 186 |
-
| paws | 0.759 / 0.123 | 0.834 / 0.018 | 0.691 / 0.221 |
|
| 187 |
-
| pubmedqa | 0.728 / 0.042 | 0.768 / 0.082 | 0.790 / 0.063 |
|
| 188 |
-
| quality | 0.457 / 0.205 | 0.519 / 0.184 | 0.513 / 0.137 |
|
| 189 |
-
| reward_bench | 0.624 / 0.074 | 0.772 / 0.045 | 0.799 / 0.043 |
|
| 190 |
-
| sciq | 0.978 / 0.011 | 0.988 / 0.019 | 0.982 / 0.017 |
|
| 191 |
-
| social_iqa | 0.659 / 0.089 | 0.739 / 0.053 | 0.712 / 0.060 |
|
| 192 |
-
| strategyqa | 0.566 / 0.029 | 0.646 / 0.037 | 0.613 / 0.069 |
|
| 193 |
-
| student_questions | 0.903 / 0.059 | 0.933 / 0.021 | 0.927 / 0.030 |
|
| 194 |
-
| trec | 0.696 / 0.062 | 0.822 / 0.050 | 0.766 / 0.036 |
|
| 195 |
-
| truthfulqa | 0.460 / 0.111 | 0.591 / 0.113 | 0.497 / 0.091 |
|
| 196 |
-
| tweet_irony | 0.511 / 0.158 | 0.676 / 0.073 | 0.779 / 0.059 |
|
| 197 |
-
| xstory_cloze | 0.941 / 0.061 | 0.981 / 0.041 | 0.965 / 0.028 |
|
| 198 |
-
|
| 199 |
-
| Task | Qwen3.5-2B-Base, zero-shot | Qwen3.5-4B-Base, zero-shot | this model |
|
| 200 |
-
|---|---|---|---|
|
| 201 |
-
| ade | 0.794 / 0.117 | 0.746 / 0.101 | 0.827 / 0.023 |
|
| 202 |
-
| bbc_news | 0.910 / 0.010 | 0.927 / 0.024 | 0.919 / 0.025 |
|
| 203 |
-
| cr_reviews | 0.882 / 0.073 | 0.923 / 0.015 | 0.911 / 0.019 |
|
| 204 |
-
| dolly_category | 0.269 / 0.137 | 0.351 / 0.149 | 0.316 / 0.212 |
|
| 205 |
-
| fin_phrasebank | 0.560 / 0.032 | 0.713 / 0.050 | 0.640 / 0.125 |
|
| 206 |
-
| fin_sentiment | 0.345 / 0.335 | 0.437 / 0.303 | 0.773 / 0.029 |
|
| 207 |
-
| massive_scenario | 0.706 / 0.094 | 0.707 / 0.032 | 0.822 / 0.017 |
|
| 208 |
-
| paws | 0.759 / 0.123 | 0.834 / 0.018 | 0.693 / 0.189 |
|
| 209 |
-
| pubmedqa | 0.728 / 0.042 | 0.768 / 0.082 | 0.768 / 0.043 |
|
| 210 |
-
| sciq | 0.978 / 0.011 | 0.988 / 0.019 | 0.985 / 0.016 |
|
| 211 |
-
| social_iqa | 0.659 / 0.089 | 0.739 / 0.053 | 0.712 / 0.055 |
|
| 212 |
-
| strategyqa | 0.566 / 0.029 | 0.646 / 0.037 | 0.594 / 0.095 |
|
| 213 |
-
| student_questions | 0.903 / 0.059 | 0.933 / 0.021 | 0.930 / 0.017 |
|
| 214 |
-
| trec | 0.696 / 0.062 | 0.822 / 0.050 | 0.772 / 0.044 |
|
| 215 |
-
| truthfulqa | 0.460 / 0.111 | 0.591 / 0.113 | 0.541 / 0.062 |
|
| 216 |
-
| tweet_irony | 0.511 / 0.158 | 0.676 / 0.073 | 0.754 / 0.054 |
|
| 217 |
-
|
| 218 |
-
| Task | Qwen3.5-2B-Base, zero-shot | Qwen3.5-4B-Base, zero-shot | this model (200k-example run) |
|
| 219 |
|---|---|---|---|
|
| 220 |
-
|
|
| 221 |
-
|
|
| 222 |
-
|
|
| 223 |
-
|
|
| 224 |
-
|
|
| 225 |
-
|
|
| 226 |
-
|
|
| 227 |
-
|
|
| 228 |
-
|
|
| 229 |
-
|
|
| 230 |
-
|
|
| 231 |
-
|
| 232 |
-
|
| 233 |
-
|
| 234 |
-
|
| 235 |
-
|
| 236 |
-
|
| 237 |
-
|
| 238 |
-
|
| 239 |
-
*In-task* = test splits of the training datasets (in-task rows for the zero-shot baselines cover the original 64). *Held-out* = 23 datasets never
|
| 240 |
-
seen in training: TREC, BBC news, PAWS, SciQ, Social IQa, StrategyQA, PubMedQA,
|
| 241 |
-
TruthfulQA, tweet irony, financial sentiment, ADE, MASSIVE scenario, student
|
| 242 |
-
question categories, Dolly categories, CR reviews, Financial PhraseBank,
|
| 243 |
-
CommitmentBank, QuALITY, XStoryCloze, RewardBench, Arena preferences (3-way),
|
| 244 |
-
Hermes tool selection, and an abstention probe (held-out classification tasks
|
| 245 |
-
where in half the cases the correct option is absent and "none of the above" is
|
| 246 |
-
right). Chance accuracy is 0.33 on both sets. ECE = expected calibration error
|
| 247 |
-
(15 bins), AURC = area under the risk-coverage curve, acc@80 = accuracy on
|
| 248 |
-
the 80% most confident decisions.
|
| 249 |
|
| 250 |
## Speed
|
| 251 |
|
| 252 |
-
One NVIDIA GH200, bf16. `decider.infer.Decider` uses
|
| 253 |
-
|
| 254 |
-
|
| 255 |
-
questions each:
|
| 256 |
|
| 257 |
| setting | p50 latency | throughput |
|
| 258 |
|---|---|---|
|
| 259 |
| single request, eager PyTorch | 49 ms | |
|
| 260 |
| single request, CUDA graphs + torch.compile (helper default) | 4.0 ms | |
|
| 261 |
-
| batch of 32, in-process, bf16 | 70 ms |
|
| 262 |
-
| batch of 32, in-process, FP8 linears | 58 ms |
|
| 263 |
| HTTP server (FP8), 1 client | 6.8 ms | 134 req/s |
|
| 264 |
-
| HTTP server (FP8), 64 clients | 126 ms | 431 req/s,
|
| 265 |
|
| 266 |
-
|
| 267 |
-
|
|
|
|
| 268 |
|
| 269 |
## Limitations
|
| 270 |
|
| 271 |
-
*
|
| 272 |
-
|
| 273 |
-
|
| 274 |
-
|
| 275 |
-
*
|
| 276 |
-
|
| 277 |
-
|
| 278 |
-
|
| 279 |
-
|
| 280 |
-
|
| 281 |
-
|
| 282 |
-
|
| 283 |
-
|
| 284 |
-
*
|
| 285 |
-
|
| 286 |
-
|
| 287 |
-
|
| 288 |
-
|
| 289 |
-
|
| 290 |
-
*
|
| 291 |
-
|
| 292 |
-
nothing on offer fits the situation, not when the exact fine-grained label is merely absent
|
| 293 |
-
(it then takes the best available option). Trained with twelve abstain wordings and
|
| 294 |
-
off-topic option lists; on a held-out probe with off-topic option lists it scores 0.83
|
| 295 |
-
(v4: 0.68). Earlier versions (v4 and before) had learned the literal phrase as an abstain
|
| 296 |
-
signal; the bundled helper's rewrite for that is disabled for v5 via `decider_config.json`.
|
| 297 |
-
* Catch-all options next to generic ones ("support" vs "other"): v6 sent in-scope messages that fit only the generic option to
|
| 298 |
-
the catch-all (0.60 on a hand-written battery, 0.50 on held-out teacher-written routing messages). v8: 0.85 and 0.94, with the
|
| 299 |
-
catch-all cases at 0.95 and 0.90. Question wordings far from the training data (public datasets plus 24k teacher-written
|
| 300 |
-
questions) remain the main risk; verify on your own examples.
|
| 301 |
-
* The catch-all fix depends on the generic option looking generic (`general IT help`, `customer_service`, `general_query`). With the bare
|
| 302 |
-
label `support` next to `other`, a plain app complaint still goes to `other` at 0.99. Name or describe the generic option as a bucket.
|
| 303 |
-
* Isolated Score levels match listwise scoring within about a point (LIAR2: 3 points lower). Levels should describe situations,
|
| 304 |
-
not degrees.
|
| 305 |
-
* One in-task dataset, `tweet_hate` (SemEval-2019 HatEval), stays near chance on its
|
| 306 |
-
test split. That split is known to differ from its training split in collection
|
| 307 |
-
and label definition; the number is reported as measured.
|
| 308 |
|
| 309 |
## Reproduction
|
| 310 |
|
| 311 |
-
Code, data registry, training and evaluation scripts
|
| 312 |
-
|
|
|
|
|
|
| 6 |
tags: [decision-model, calibrated, structured-output, multi-task, system-one, one-pass]
|
| 7 |
---
|
| 8 |
|
| 9 |
+
# decider-2b: typed decisions with calibrated probabilities in one forward pass
|
| 10 |
+
|
| 11 |
+
A language model that does not generate text. It reads a state and one or more typed questions, each with an explicit option
|
| 12 |
+
list, and returns a probability distribution over the options for every question from one forward pass. There is no decoding,
|
| 13 |
+
no parsing and no output outside the options you defined. It is called from software, not chatted with. It is an open
|
| 14 |
+
reproduction of the "System One" model class (TypeSafe AI's Jev).
|
| 15 |
+
|
| 16 |
+
Base model: [Qwen/Qwen3.5-2B-Base](https://huggingface.co/Qwen/Qwen3.5-2B-Base) (1.9B parameters). The supervised stages
|
| 17 |
+
(v1 to v8) fine-tune it with cross-entropy, a proper scoring rule, on a mixture of about 95 public decision datasets, agent
|
| 18 |
+
trajectories, web element choice, game states and teacher-written custom questions, in two prompt layouts and with isolated
|
| 19 |
+
Score levels. **This repository holds v10**: the v8 weights continued for 384 steps of calibration-aware reinforcement learning
|
| 20 |
+
whose only rewards are outcomes (live browser task checkers and the exact probability laws of games), with a hard KL limit to
|
| 21 |
+
the v8 weights on replayed training rows. Code, data registry, training scripts and the recipe are at
|
| 22 |
+
https://github.com/Mapika/decider; `decider/` in this repository is the inference subset of that package.
|
| 23 |
+
|
| 24 |
+
What changed from v8, measured on the same rows: live browser click tasks 83% to 93% sampled success (held-out tasks 73% to
|
| 25 |
+
92%), stated beliefs about action outcomes 0.47 to 0.22 nats above the exact law, Mind2Web +1.5 points, general accuracy and
|
| 26 |
+
Bespoke's public suite unchanged, OpenJev −0.8 points. Details under Evaluation.
|
| 27 |
|
| 28 |
## Usage
|
| 29 |
|
| 30 |
```python
|
| 31 |
from decider.infer import Decider # decider/ is included in this repo
|
| 32 |
+
d = Decider("Mapika/decider-2b")
|
| 33 |
d.decide("My card was charged twice for the same purchase.",
|
| 34 |
[{"question": "Which department should handle this?", "options": ["billing", "technical support", "sales"]},
|
| 35 |
{"question": "Does this need a refund action?", "options": ["no", "yes"]}])
|
| 36 |
# [{'choice': 'billing', 'confidence': 0.99, 'probs': {...}}, {'choice': 'yes', 'confidence': 0.99, 'probs': {...}}]
|
| 37 |
```
|
| 38 |
|
| 39 |
+
`decide_batch` scores many states, each with many questions, in one call. `abstain_below=t` returns `None` for decisions with
|
| 40 |
+
confidence under `t`. A question can have 2 to 255 options (more than 10 options use one label token per option, see
|
| 41 |
+
`decider/prompt.py`).
|
|
|
|
| 42 |
|
| 43 |
The same request shape as TypeSafe's Jev (`POST /v1/systemone`), in process or over HTTP:
|
| 44 |
|
|
|
|
| 50 |
"billing": {"what": "Charges, invoices", "not_for": "delivery"}, "other": None}},
|
| 51 |
"refund_requested": {"type": "noul", "instructions": "Does `ticket.messages[0].text` request a refund?"},
|
| 52 |
"frustration": {"type": "score", "instructions": "How frustrated is the customer?", "criteria": ["calm", "frustrated", "very frustrated"]}})
|
| 53 |
+
# {"model": "decider-v10", "answers": {"department": {"type": "choice", "choice": "billing", "confidence": ..., "certainty": ..., "probabilities": {...}},
|
| 54 |
# "refund_requested": {"type": "noul", "noul": ...}, "frustration": {"type": "score", "score": ..., "legend": {...}, ...}}, "usage": {...}}
|
| 55 |
```
|
| 56 |
|
| 57 |
+
The state may be a string, object or array (up to 32k tokens with the questions). `instructions` and every option
|
| 58 |
+
description may be a string or any JSON value. Question ids are never shown to the model. Each question is scored in its own
|
| 59 |
+
row, so an answer does not depend on which other questions are asked (`independent=False` packs them into one row, about half
|
| 60 |
+
the latency for short states). Each Score level is likewise judged in its own row, without its number or its neighbours, and the
|
| 61 |
+
per-level fits are normalised (`"isolated": false` restores listwise scoring). The answer also reports `level_fit` and their
|
| 62 |
+
sum `fit_mass`, which is near 1 when exactly one level fits.
|
| 63 |
|
| 64 |
For a fixed set of questions, `s = d.schema(questions)` computes the question prefix once and `s(state)` / `s.batch(states)`
|
| 65 |
+
then run only the state (1.2 to 2.4x faster per request, up to 19x per batch). It uses a questions-first prompt layout that
|
| 66 |
+
costs accuracy: about 1.5 points on fixed label sets, 5 on per-example options, more on 50 or more options and on states of
|
| 67 |
+
several thousand tokens. `decider.serve` exposes the same thing as `POST /v1/systemone`; the official `typesafe-sdk` works
|
| 68 |
+
against it unchanged with `TYPESAFE_BASE_URL` pointing at the server.
|
| 69 |
|
| 70 |
+
Requirements: `torch`, `transformers>=5`, and `flash-linear-attention` (Triton kernels for the Qwen3.5 linear-attention
|
| 71 |
+
layers; the model runs without it but several times slower). Python 3.11 or newer lets those kernels use `torch.compile`.
|
|
|
|
|
|
|
| 72 |
|
| 73 |
Without the helper package, the same computation in plain `transformers`:
|
| 74 |
|
|
|
|
| 82 |
with torch.no_grad():
|
| 83 |
logits = m(**ids).logits[0, -1]
|
| 84 |
letters = [tok.encode(L, add_special_tokens=False)[0] for L in "ABC"]
|
| 85 |
+
probs = torch.softmax(logits[letters].float() / 1.30, -1) # -> P(billing), P(technical support), P(sales); 1.30 is the stored temperature
|
| 86 |
```
|
| 87 |
|
| 88 |
+
For several questions in one pass, append further `Question k: ... Answer k: (` blocks and read the logits at each `(`
|
| 89 |
+
position (see `decider/prompt.py`).
|
| 90 |
|
| 91 |
## How it works
|
| 92 |
|
| 93 |
+
The prompt is `Context: ...` followed by, for each question, the question text, the lettered options `(A) ... (B) ...` and an
|
| 94 |
+
answer slot `Answer k: (`. The hidden state at each slot is projected with the option-letter rows of the LM head and softmaxed
|
| 95 |
+
over the valid letters, divided by the temperature in `decider_config.json`. Letters are never generated, so all slots are read
|
| 96 |
+
from one pass. Large label sets were sub-sampled to at most 10 options per training example (gold always kept, order shuffled),
|
| 97 |
+
so the model conditions on the supplied candidates rather than on a fixed head.
|
|
|
|
|
|
|
| 98 |
|
| 99 |
## Field types
|
| 100 |
|
| 101 |
+
* **noul**: probability of "yes".
|
| 102 |
+
* **choice** with `criteria` {name: description | JSON | null}: the argmax option, its probability (`confidence`, the calibrated
|
| 103 |
+
number), `certainty` (1 minus the normalised entropy) and the full distribution.
|
| 104 |
+
* **score** with `criteria` [level descriptions]: the expected level, the probability of the most likely level, the
|
| 105 |
+
distribution, and the per-level fits.
|
| 106 |
+
|
| 107 |
+
## Training
|
| 108 |
+
|
| 109 |
+
**Supervised stages (v1 to v8).** One epoch on a mixture of public decision datasets (intent detection, ticket routing, topic
|
| 110 |
+
classification, sentiment, emotion, moderation, NLI, paraphrase, fact verification, passage relevance, reading comprehension,
|
| 111 |
+
multiple-choice QA, ordinal rating scales, pairwise response preference, tool selection), then continuation epochs that added
|
| 112 |
+
next-action choice from agent trajectories (AgentGym), web element choice (Mind2Web), teacher-written situations and game states,
|
| 113 |
+
the input shapes of the Jev API (described options, up to 255 options, JSON states with path references, long inputs), teacher-
|
| 114 |
+
written custom questions with a generic option next to a catch-all, a second cacheable prompt layout, and isolated Score levels.
|
| 115 |
+
In 10% of questions with three or more options an abstain option is added; in a quarter of those the option list is replaced by
|
| 116 |
+
labels from an unrelated task so that the abstain option is correct. The full list of components with sizes is in
|
| 117 |
+
`decider/data/mixture.py` of the GitHub repository; `scripts/train.sh full` reproduces the supervised stages in one run.
|
| 118 |
+
|
| 119 |
+
**Reinforcement learning stage (v8 to v10).** 384 optimizer steps at a peak learning rate of 1e-6 (cosine, 16 warm-up steps),
|
| 120 |
+
selected among the checkpoints of a 576-step run. Each of the 48 iterations plays 4 live MiniWoB++ click tasks, 4 minesweeper
|
| 121 |
+
boards and 4 game boards (a 5x5 grid with a slippery move, draws from bags of known composition), 4 repeats each, through the
|
| 122 |
+
same one-pass readout that serves requests. Three loss terms use those rollouts: a PPO clipped surrogate (clip 0.2) on the
|
| 123 |
+
terminal outcome with a leave-one-replicate-out baseline; a proper log score of the model's stated belief about the immediate
|
| 124 |
+
outcome of its action against the exact law (games, minesweeper) or the realised outcome (browser); and a rendering-consistency
|
| 125 |
+
term that pulls the model's answer in the other prompt layout and the reversed option order toward its served answer. A fourth
|
| 126 |
+
term keeps the model where it was: on 8 replayed supervised rows per step, KL(v8 ‖ student) on the served distribution must
|
| 127 |
+
stay under 0.01 nats on average and 0.05 on any row, otherwise the step drops the reward terms and follows only the KL
|
| 128 |
+
gradient. Six browser tasks were held out from reward and used for validation only. No gold labels were used. The recipe and
|
| 129 |
+
every measurement are in `docs/RL.md` of the GitHub repository.
|
| 130 |
|
| 131 |
## Evaluation
|
| 132 |
|
| 133 |
+
**94 public tasks, original protocol.** Large label sets sub-sampled to 10 options; one temperature fitted on in-task data
|
| 134 |
+
and stored in `decider_config.json`. "In-task" means the test splits of the training datasets; "held-out" means datasets never
|
| 135 |
+
seen in training (TREC, BBC news, PAWS, SciQ, Social IQa, StrategyQA, PubMedQA, TruthfulQA, tweet irony, financial sentiment,
|
| 136 |
+
ADE, MASSIVE scenario, student question categories, Dolly categories, CR reviews, Financial PhraseBank, CommitmentBank,
|
| 137 |
+
QuALITY, XStoryCloze, RewardBench, Arena preferences, Hermes tool selection, and an abstention probe). ECE is the expected
|
| 138 |
+
calibration error with 15 bins.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 139 |
|
| 140 |
+
| model | in-task (69 tasks) acc / NLL / ECE | held-out (24 tasks) acc / NLL / ECE |
|
| 141 |
+
|---|---|---|
|
| 142 |
+
| Qwen3.5-2B-Base, zero-shot | 0.620 / 0.908 / 0.121 | 0.642 / 0.853 / 0.105 |
|
| 143 |
+
| decider-2b v8, T=1.30 | 0.811 / 0.460 / 0.037 | 0.741 / 0.655 / 0.088 |
|
| 144 |
+
| decider-2b v9, T=1.36 | 0.812 / 0.464 / 0.041 | 0.741 / 0.655 / 0.087 |
|
| 145 |
+
| decider-2b v8, rebuilt set (67 / 28 tasks, see note), T=1.30 | 0.806 / 0.473 / 0.038 | 0.757 / 0.622 / 0.083 |
|
| 146 |
+
| **decider-2b v10 (this repository), rebuilt set, T=1.30** | 0.805 / 0.474 / 0.037 | 0.755 / 0.622 / 0.084 |
|
| 147 |
+
| v8, questions-first layout (schema cache), T=1.18 | 0.790 / 0.500 / 0.038 | 0.707 / 0.757 / 0.104 |
|
| 148 |
|
| 149 |
+
The two "rebuilt set" rows were measured after the data pipeline was rebuilt on another machine: two datasets no longer download
|
| 150 |
+
(TREC-fine, the game states) and the current mixture adds held-out probes, so that set has 67 in-task and 28 held-out tasks. Its
|
| 151 |
+
numbers are comparable to each other, not to the rows above. v10 matches v8 on it.
|
| 152 |
|
| 153 |
+
Per-task accuracy / ECE on the held-out datasets of the rebuilt set, v8 against v10:
|
| 154 |
+
|
| 155 |
+
| task | v8 acc / ECE | v10 acc / ECE |
|
| 156 |
+
|---|---|---|
|
| 157 |
+
| abstain_probe | 0.633 / 0.112 | 0.606 / 0.134 |
|
| 158 |
+
| ade | 0.811 / 0.044 | 0.817 / 0.038 |
|
| 159 |
+
| arena_pref | 0.487 / 0.173 | 0.483 / 0.189 |
|
| 160 |
+
| bbc_news | 0.924 / 0.014 | 0.927 / 0.013 |
|
| 161 |
+
| cb | 0.911 / 0.090 | 0.857 / 0.093 |
|
| 162 |
+
| cr_reviews | 0.900 / 0.027 | 0.903 / 0.031 |
|
| 163 |
+
| dbpedia_l2 | 0.948 / 0.017 | 0.950 / 0.018 |
|
| 164 |
+
| dbpedia_l3 | 0.989 / 0.007 | 0.987 / 0.005 |
|
| 165 |
+
| dolly_category | 0.291 / 0.209 | 0.299 / 0.203 |
|
| 166 |
+
| fin_phrasebank | 0.684 / 0.043 | 0.694 / 0.042 |
|
| 167 |
+
| fin_sentiment | 0.794 / 0.069 | 0.793 / 0.058 |
|
| 168 |
+
| hermes_tools | 0.718 / 0.209 | 0.723 / 0.208 |
|
| 169 |
+
| hwu64 | 0.964 / 0.031 | 0.961 / 0.030 |
|
| 170 |
+
| massive_scenario | 0.766 / 0.040 | 0.756 / 0.041 |
|
| 171 |
+
| offtopic_probe | 0.841 / 0.033 | 0.841 / 0.027 |
|
| 172 |
+
| paws | 0.707 / 0.169 | 0.724 / 0.145 |
|
| 173 |
+
| pubmedqa | 0.752 / 0.083 | 0.756 / 0.085 |
|
| 174 |
+
| quality | 0.495 / 0.236 | 0.494 / 0.233 |
|
| 175 |
+
| quality_full | 0.505 / 0.205 | 0.508 / 0.198 |
|
| 176 |
+
| reward_bench | 0.825 / 0.042 | 0.819 / 0.045 |
|
| 177 |
+
| sciq | 0.982 / 0.022 | 0.982 / 0.024 |
|
| 178 |
+
| social_iqa | 0.698 / 0.072 | 0.708 / 0.077 |
|
| 179 |
+
| strategyqa | 0.559 / 0.123 | 0.552 / 0.138 |
|
| 180 |
+
| student_questions | 0.927 / 0.036 | 0.925 / 0.045 |
|
| 181 |
+
| trec | 0.792 / 0.057 | 0.784 / 0.066 |
|
| 182 |
+
| truthfulqa | 0.529 / 0.102 | 0.537 / 0.090 |
|
| 183 |
+
| tweet_irony | 0.801 / 0.048 | 0.795 / 0.052 |
|
| 184 |
+
| xstory_cloze | 0.962 / 0.017 | 0.962 / 0.017 |
|
| 185 |
+
|
| 186 |
+
**v10 against v8 on the same rows.** Every row below is scored by both models on identical inputs and seeds. Intervals are
|
| 187 |
+
95% bootstrap or paired intervals.
|
| 188 |
+
|
| 189 |
+
| | v8 | v10 | difference |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 190 |
|---|---|---|---|
|
| 191 |
+
| live MiniWoB++ click tasks, 22 tasks x 8 seeds, sampled play | 83.0% | 93.2% | +10.2 (+5.1 to +15.9) |
|
| 192 |
+
| the 6 tasks never used for reward | 72.9% | 91.7% | +18.8 (+6.2 to +31.2) |
|
| 193 |
+
| same tasks, greedy play | 90.3% | 90.9% | +0.6 |
|
| 194 |
+
| Mind2Web element and action choice, 1,770 rows | 81.1% | 82.7% | +1.5 (+0.7 to +2.4) |
|
| 195 |
+
| bag-draw games, win rate | | | +6.2 (+0.8 to +12.1) |
|
| 196 |
+
| stated belief, nats above the exact law (lower is better) | 0.473 | 0.219 | |
|
| 197 |
+
| click-outcome prediction, log score (higher is better) | −0.349 | −0.034 | |
|
| 198 |
+
| TypeSafe workflow decisions, 102 rows, accuracy / NLL | 78.4% / 0.594 | 80.4% / 0.585 | +2.0 (−2.0 to +5.9) |
|
| 199 |
+
| 847 in-task validation rows, accuracy / NLL | 83.6% / 0.443 | 83.2% / 0.444 | −0.4 (−1.3 to +0.6) |
|
| 200 |
+
| Bespoke's public suite, 13 subsets, macro accuracy | 0.706 | 0.704 | |
|
| 201 |
+
| OpenJev, 5,252 rows, accuracy / NLL | 64.1% / 0.906 | 63.3% / 0.916 | −0.8 (−1.3 to −0.3) |
|
| 202 |
+
|
| 203 |
+
The browser gain is in the served distribution rather than in the argmax: sampled play improves by ten points, greedy play by
|
| 204 |
+
under one. Tic-tac-toe, grid and minesweeper play did not change; a 2B model without search loses most of those games either
|
| 205 |
+
way. The one measured regression is OpenJev, under one point.
|
| 206 |
+
|
| 207 |
+
**Bespoke's public suite** (13 human-labelled subsets, 3,880 records in Jev's wire format, answered through `system_one` as
|
| 208 |
+
shipped). decider-2b v10 macro 0.704 / micro 0.711; v9 0.701 / 0.711; Nimble-9B 0.748 / 0.759; Jev 1.13.0 0.760 / 0.773
|
| 209 |
+
(the last two copied from Bespoke's report). Per-subset numbers are in the GitHub README.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 210 |
|
| 211 |
## Speed
|
| 212 |
|
| 213 |
+
One NVIDIA GH200, bf16, unchanged from v8 (same architecture, readout and temperature). `decider.infer.Decider` uses
|
| 214 |
+
shape-bucketed CUDA graphs; the batching server is `decider/serve.py`. Support-ticket states of about 230 tokens with 3 to 5
|
| 215 |
+
typed questions each:
|
|
|
|
| 216 |
|
| 217 |
| setting | p50 latency | throughput |
|
| 218 |
|---|---|---|
|
| 219 |
| single request, eager PyTorch | 49 ms | |
|
| 220 |
| single request, CUDA graphs + torch.compile (helper default) | 4.0 ms | |
|
| 221 |
+
| batch of 32, in-process, bf16 | 70 ms | about 1,370 decisions/s |
|
| 222 |
+
| batch of 32, in-process, FP8 linears | 58 ms | about 1,670 decisions/s |
|
| 223 |
| HTTP server (FP8), 1 client | 6.8 ms | 134 req/s |
|
| 224 |
+
| HTTP server (FP8), 64 clients | 126 ms | 431 req/s, 2,152 decisions/s |
|
| 225 |
|
| 226 |
+
With the schema cache (`Decider.schema`), 10 described questions on short chat messages run at 11,180 decisions/s in a batch,
|
| 227 |
+
and one question with 151 options at 19x the full-forward rate. FP8 (e4m3 weights, per-token activation scales) changes
|
| 228 |
+
accuracy and calibration by less than the evaluation noise.
|
| 229 |
|
| 230 |
## Limitations
|
| 231 |
|
| 232 |
+
* A 2B model without reasoning. Knowledge-heavy multiple choice (MMLU, MedQA, ARC) improves little over the base model, and a
|
| 233 |
+
judgment that needs several steps should be split into several questions.
|
| 234 |
+
* English only. Calibration is measured on public datasets and teacher-labelled probes, not on your traffic. Check it on your
|
| 235 |
+
own labels before using confidence for routing.
|
| 236 |
+
* v10 continues the v8 weights. The v9 data for terse bucket names (`support`, `help`, `account` next to `other`) is not in it:
|
| 237 |
+
on held-out terse-bucket messages v8 chose the generic bucket correctly 59% of the time where v9 reached 86%. Name or
|
| 238 |
+
describe the generic option as a bucket (`general_support`, or a description).
|
| 239 |
+
* Rules written into the question ("fill if empty, otherwise skip") are not followed at this size. State the decision as a
|
| 240 |
+
plain question with described options.
|
| 241 |
+
* Picking one record out of a long JSON array by position is the least accurate input shape (0.51 with 64 records against
|
| 242 |
+
0.70 with one). Address records by key, or let the helper write the index into the array (0.62).
|
| 243 |
+
* Full label sets cost accuracy against 10 sampled options: CLINC 151-way 0.88 against 0.98; DBpedia level 2 with 70 labels
|
| 244 |
+
is the least calibrated case (ECE 0.14).
|
| 245 |
+
* Questions packed into one row (`independent=False`) see the earlier question texts, and reversing their order changes up to
|
| 246 |
+
12% of answers. The default path scores each question alone.
|
| 247 |
+
* The v10 browser results are on 22 click-only MiniWoB++ tasks: small synthetic pages with the elements listed as text. Typing,
|
| 248 |
+
scrolling and real websites were not tested. OpenJev accuracy is 0.8 points lower than v8.
|
| 249 |
+
* Abstention: a catch-all option ("none of the above", "other", "unsure") is chosen when nothing on offer fits, not when the
|
| 250 |
+
exact fine-grained label is merely absent. Wordings far from the training data remain the main risk.
|
| 251 |
+
* One in-task dataset, `tweet_hate` (SemEval-2019 HatEval), stays near chance on its test split, whose collection and label
|
| 252 |
+
definition differ from the training split. The number is reported as measured.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 253 |
|
| 254 |
## Reproduction
|
| 255 |
|
| 256 |
+
Code, data registry, training and evaluation scripts, the RL recipe and the per-version history:
|
| 257 |
+
https://github.com/Mapika/decider. Each release is staged with `scripts/stage_release.py` and uploaded with
|
| 258 |
+
`scripts/upload_hf.py`; the previous weights are kept under the tag `v8` in this repository.
|
decider_config.json
CHANGED
|
@@ -1 +1 @@
|
|
| 1 |
-
{"temperature": 1.3, "temperature_schema_first": 1.18, "neutralize_none": false, "version": "
|
|
|
|
| 1 |
+
{"temperature": 1.3, "temperature_schema_first": 1.18, "neutralize_none": false, "version": "v10", "base": "Qwen/Qwen3.5-2B-Base", "max_options": 255, "max_state_tokens": 32768, "schema_first": false, "schema_first_trained": true, "isolated_levels": true, "release_date": "2026-09-19", "parent": "decider-2b v8 (Mapika/decider-2b, tag v8)", "stage": "calibration-aware RL, 384 steps, outcome rewards from live MiniWoB++ click tasks and exact games, KL retention to v8 (docs/RL.md)"}
|
eval_results.json
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|
model.safetensors
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
size 3763692048
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:1bf79b6aa6966a0faf930940799b1f54a831368d9738123722d483597c0ac2e7
|
| 3 |
size 3763692048
|