Instructions to use mchen04/jev-local-lab-decision-heads with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- MLX
How to use mchen04/jev-local-lab-decision-heads with MLX:
# Download the model from the Hub pip install huggingface_hub[hf_xet] huggingface-cli download --local-dir jev-local-lab-decision-heads mchen04/jev-local-lab-decision-heads
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- LM Studio
- Atomic Chat
- jev-local-lab decision heads (phase 3)
jev-local-lab decision heads (phase 3)
Hi β this is for-fun side-project stuff. I tried seeing how well a small local model on a 24 GB Mac mini could read structured decisions out of documents, and these are the tiny trained heads that came out of it. The work runs from 2026-09-19 to 2026-09-22 in the project's own commit history; I am not going to round that into a tidier story than it was. They are not production-ready, they are not a reproduction of any commercial product, and they do not reach parity with the published "Jev" numbers I was comparing against. Two of the most interesting things in here are failures, and I've left them in on purpose.
tl;dr of the honest result: on the task families these heads were trained on they beat their own backbone's zero-shot read-out by +14.8 points. On a fresh, never-touched set of six different task families they LOST to it by 3.25 points (exact paired McNemar p = 0.0167), and on an external workflow suite they lost again. If you want a small local decision reader, the plain zero-shot read-out on the same backbone was better than these heads on everything unseen.
Table of contents
- Model details
- What is actually in this repo
- Uses
- Bias, risks and limitations
- Training details
- Evaluation
- What was NOT evaluated
- Technical specifications
- How to get started
- Licence and upstream attribution
Model details
Model description
Ten decision heads: small trained modules that sit on top of a frozen, unmodified 4-bit Qwen2.5-1.5B-Instruct and turn one hidden state into a probability distribution over a label set supplied at call time. They are not language models and they do not generate text. Each head is 0.20β1.32 M parameters (0.8β5.3 MB), i.e. roughly 0.01β0.09 % of the backbone.
The scoring function is a cosine-bilinear form between the backbone's hidden state at the read position and the mean-pooled input embeddings of each candidate label, so the same head works for any label set without retraining. Seven heads are a straight hyper-parameter sweep (rank, head shape, distillation weight); three are deliberate held-out-task probes trained with some task families removed, to test whether the head generalises. It does not β see Evaluation.
- Developed by: Michael Chen (solo side project)
- Model type: trained classification head / adapter over a frozen quantised LLM; supervised cross-entropy, some variants with knowledge distillation from a larger local model
- Language(s): English
- License: see Licence and upstream attribution β this is the one thing I have deliberately not guessed
- Adapter for:
mlx-community/Qwen2.5-1.5B-Instruct-4bitat revision8b403126fc14f14cfc99bb4cfa72ecbc129ea677(Apache-2.0)
Model sources
There is no public code repository. The engine that produces the hidden state these heads consume
(jevlocal) lives in a private local checkout, so this card documents the head's maths in full
instead of pointing at an import. See How to get started β I would rather
give you the equations than imply a turnkey download that does not exist.
What is actually in this repo
Weights are supplied. Every file below is a real trained artifact, not a recipe. Each directory
holds head.safetensors (the weights) and record.json (full recipe, per-epoch history, the
selected epoch, and the sha256 the weights must match).
| directory | head | rank | distil Ξ± | Ο | params | bytes | dev3 macro |
note |
|---|---|---|---|---|---|---|---|---|
p3h-kd-a05 |
bilinear | 256 | 0.5 | 2.0 | 791 042 | 3 164 652 | 0.6885 | best on dev3; the one carried to the untouched split, where it lost |
p3h-ce-r256 |
bilinear | 256 | 0.0 | β | 791 042 | 3 164 652 | 0.6819 | no distillation |
p3h-kd-a05-t4 |
bilinear | 256 | 0.5 | 4.0 | 791 042 | 3 164 652 | 0.6812 | hotter teacher |
p3h-ce-r64 |
bilinear | 64 | 0.0 | β | 201 218 | 805 347 | 0.6774 | smallest head here |
p3h-ce-mlp |
mlp | 256 | 0.0 | β | 1 315 842 | 5 263 986 | 0.6632 | nonlinear projection |
p3h-kd-mlp-a05 |
mlp | 256 | 0.5 | 2.0 | 1 315 842 | 5 263 986 | 0.6583 | |
p3h-kd-a09 |
bilinear | 256 | 0.9 | 2.0 | 791 042 | 3 164 652 | 0.6410 | mostly-teacher loss; worse |
p3h-holdout-small |
bilinear | 256 | 0.0 | β | 791 042 | 3 164 652 | 0.6712 | held out scicite_intent, winogrande_coref |
p3h-holdout-mixed |
bilinear | 256 | 0.0 | β | 791 042 | 3 164 652 | 0.6170 | held out clinc_intent, openbookqa_science |
p3h-holdout |
bilinear | 256 | 0.0 | β | 791 042 | 3 164 652 | 0.5590 | held out clinc_intent, ledgar_provision |
dev3 macro is the mean per-task accuracy over the nine development task families, 960 questions.
It is development data β it was looked at repeatedly and used to pick things. Treat it as
selection evidence, not as a performance claim.
Also included: manifest.json (this table, machine-readable, with sha256 per file).
Uses
Direct use
Reproducing or poking at the experiment: attach a head to the frozen backbone, feed it a hidden state and a label set, get a distribution. Useful if you want to see what a ~0.8 M-parameter cosine-bilinear head can and cannot learn on top of a small quantised model, or to check my numbers.
Out-of-scope use
- Anything real. No safety evaluation, no fairness evaluation, no robustness testing, no red-teaming was done. Do not put this in a product, a pipeline that affects people, or any decision that matters.
- Unseen task families. This is the measured failure mode, not a hypothetical: the heads transfer badly to task families they were not trained on. See Evaluation.
- Medical, legal or financial decisions. Some training families are medical (PubMedQA) and legal (LEDGAR) in topic. That is a topic, not a qualification.
- Claiming these match a commercial product. They do not, and the numbers below show the gap.
Bias, risks and limitations
- Transfer failure is the headline limitation. A head trained on nine task families beat its
backbone's zero-shot read-out on those families and lost to it on six unseen ones. The
held-out-task probes show why: with
clinc_intent(150 labels) andledgar_provision(100 labels) removed from training,p3h-holdoutscores 0.7170 on the task families it did see and 0.0063 on the two it did not. That is not a degradation, it is a collapse. - Large label sets are where it breaks. The probe above is the extreme case; the milder one
(
p3h-holdout-small, holding out two small-label tasks) reaches 0.5938 on held-out tasks against 0.6933 on seen ones. Transfer degrades with the size of the unseen label set. - Inherited bias. The heads read a frozen Qwen2.5-1.5B-Instruct. Whatever social, topical or linguistic bias that model carries is passed straight through, and I did not measure any of it.
- English only, and only on academic classification-style data.
- The training data is a mixture with heterogeneous and partly unclear licences β see Licence and upstream attribution.
- Tiny sample sizes. The untouched final evaluation is 1200 questions over six tasks; the external suite is 348. Per-task numbers below are unadjusted and exploratory.
Recommendations
If you want a small local decision reader for unseen tasks, use the plain zero-shot restricted read-out on the same backbone instead. That is what my own measurements say, and it is why I am publishing these heads as an experiment record rather than as a recommendation.
Training details
Training data
train3: 3405 items drawn from the train splits of nine public datasets, at row indices the
development split does not use, deduplicated by a sha256 of the normalised input text against every
other split in the project. The nine families:
| family | source dataset | published licence (as tagged on the Hub) |
|---|---|---|
pubmedqa_decision |
qiaojin/PubMedQA |
mit |
rte_entailment |
nyu-mll/glue (RTE) |
other |
scicite_intent |
allenai/scicite |
unknown |
climatefever_claim |
tdiggelm/climate_fever |
unknown |
openbookqa_science |
allenai/openbookqa |
unknown |
ledgar_provision |
coastalcph/lex_glue (LEDGAR) |
cc-by-4.0 |
clinc_intent |
clinc/clinc_oos |
cc-by-3.0 |
winogrande_coref |
allenai/winogrande |
no licence tag published |
race_middle_multi |
ehovy/race |
other β RACE's own terms restrict use to research |
No dataset text is included in this repo, and none was uploaded anywhere β the built task files stay on the machine that made them.
What that does NOT establish: I have not run any extraction, memorisation or privacy evaluation on these heads, so I cannot tell you what, if anything, is recoverable from the weights. A small parameter count makes verbatim memorisation less likely a priori, but "unlikely a priori" is not a measurement and I am not going to present it as one. If that matters for your use case, treat it as an open question and test it.
Training procedure
The backbone is frozen and unmodified throughout β only the head trains.
- Hidden states are cached once: for each item, the backbone's prefix is run, a per-question branch row is appended, and the hidden state at the final branch position is kept (float16).
- Label embeddings are the backbone's own input embeddings for each label string encoded with a leading space, mean-pooled over the label's tokens (float32).
- The head trains on those cached vectors. Nothing backpropagates into the backbone.
- Loss:
(1 β Ξ±) Β· CE(student, gold) + Ξ± Β· ΟΒ² Β· KL(teacher β student), both at temperature Ο.Ξ± = 0for thece-variants. The KL is the standard soft-target direction β teacher first β computed asΞ£ p_teacher Β· (log p_teacher β log p_student). - Teacher (the
kd-variants): a local 4-bit Qwen3.8-27B read-out (lmstudio-community/Qwen3.8-27B-MLX-4bit@6067b15cf581666a4aecf6af3afaba4bb5efc20c) producing soft label distributions. Coverage was 1499 of 3405 items (44 %) β the teacher pass was time-bounded at β€150 rows per flat task. So the distillation gain is a gain at 44 % coverage, not at saturation, and it was small: +0.66 pp macro over the best non-distilled head ondev3. - Optimiser: AdamW, lr 1e-3, weight decay default, batch 256, 60 epochs, seed 20260921.
Model selection is the best
dev3macro epoch, recorded per head inrecord.json. - Numerical choices that were forced by observed failures (all in
record.json's lineage): both sides RMS-normalised before projection; the bilinear form cosine-normalised (a raw dot product diverged β cross-entropy went 0.70 β 1.25 β 185.3 in three steps at lr 1e-3); the logit scale learned but clipped to [1, 50].
Speeds, sizes, times
Training a head is seconds to a couple of minutes on cached hidden states. Caching the hidden states for 3405 train + 960 dev items took about 4 minutes on the hardware below. The 27B teacher pass took 1 h 34 min. Checkpoints are 0.8β5.3 MB.
Evaluation
Testing data, factors and metrics
Three evaluations, all with the same head (p3h-kd-a05, the one dev3 selected):
final3β a fresh split of six task families disjoint from training, frozen before any training and opened exactly once. 1200 questions. Families:sciq_support,qnli_entailment,piqa_physical,medmcqa_choice,paws_paraphrase,snli_entailment.- An external workflow suite (TypeSafe's public evals) β 348 (case, question) pairs of real workflow decisions, scored as agreement with the published reference answers.
- Held-out-task probes β three heads trained with task families removed, scored on
dev3split into seen vs unseen families.
Metric: accuracy, and macro accuracy = mean of per-task accuracies. Comparisons use the exact paired McNemar test on per-item outcomes keyed by (item, question).
Results
The untouched split (final3, n = 1200, 6 unseen families):
| system | macro accuracy |
|---|---|
| plain zero-shot read-out, same frozen 1.5B backbone | 0.6867 |
p3h-kd-a05 head on the same backbone |
0.6542 |
β3.25 pp for the head, exact paired McNemar p = 0.0167. The head is behind on all six tasks
(medmcqa β5.50, snli β5.50, piqa β4.00, qnli β2.50, sciq β1.50, paws β0.50 pp). No single
per-task difference reaches significance β those six p-values are unadjusted and exploratory β but
the overall paired test on all 1200 items, which is the confirmatory one, does.
The external workflow suite (n = 348): the head agreed with the published reference on 0.5816 of pairs against 0.6499 for the plain read-out on the same backbone. Third independent measurement, same direction.
Held-out-task probes (dev3, seen vs unseen families):
| head | families held out | macro on seen | macro on held out |
|---|---|---|---|
p3h-holdout |
clinc_intent (150 labels), ledgar_provision (100) |
0.7170 | 0.0063 |
p3h-holdout-mixed |
clinc_intent (150), openbookqa_science (4) |
0.6987 | 0.3312 |
p3h-holdout-small |
scicite_intent (3), winogrande_coref (2) |
0.6933 | 0.5938 |
Development numbers, for completeness and not as a performance claim: on dev3 (nine training
families, 960 questions) p3h-kd-a05 reaches macro 0.6885 against the same backbone's zero-shot
read-out at 0.5410 β +14.8 pp. That is the number that did not survive contact with unseen
tasks, and it is exactly why the fresh split existed.
Summary
The head learned the task families it was trained on, not "how to read a decision". On dev it looked like the bargain of the project; on anything unseen it is worse than not using it. I am publishing it because a clean, reproducible negative result is worth more than a quiet deletion.
About the "Jev" comparison
The project compared against published numbers for a commercial product (agreement 0.9110 on a 337-pair frozen subset). Those answers were published by the benchmark's authors and were never run on my hardware β closed weights, no local execution. Nothing here reproduces, approximates or matches that system. The best non-head configuration in the project reached 0.8398 agreement on that subset, which was still significantly behind (p = 0.000536); the head reached 0.5816. Agreement with a published two-model consensus is also not ground-truth accuracy.
What was NOT evaluated
Listed because their absence matters:
- No safety, toxicity, fairness or bias evaluation of any kind.
- No robustness testing β no adversarial inputs, no prompt perturbation, no distribution shift beyond the unseen-family test above.
- No calibration claim. ECE and reliability bins were computed during the project but no calibration was fitted for these heads; they ran at temperature 1.0.
- No non-English evaluation.
- No multi-label, regression, extraction or generation evaluation. These heads only pick one label from a supplied set.
- No human evaluation.
- No evaluation of the three held-out probe heads on
final3β they were diagnostic only. - No carbon measurement. I did not instrument power draw; I only have wall-clock.
Technical specifications
Model architecture and objective
For a hidden state h (shape [hidden]) and label embedding matrix E (shape
[n_labels, hidden]), with rms(x) = x / sqrt(mean(xΒ²) + 1e-6):
hn = rms(h) * g # g: [hidden]
En = rms(E) * ge # ge: [hidden]
a = hn @ Wh # Wh: [hidden, rank] -> [rank]
B = En @ We # We: [hidden, rank] -> [n_labels, rank]
a = a / max(||a||, 1e-6)
B = B / max(||B||_rowwise, 1e-6)
s = clip(exp(logit_scale), 1, 50) * (a @ B.T) + (En @ b) + c
P = softmax(s)
Tensors in head.safetensors: g, ge, Wh, We, b, c, logit_scale (all float32). For the
two mlp variants, a = gelu(hn @ W1 + b1) @ W2 replaces a = hn @ Wh.
hidden = 1536 for this backbone. E[i] is the mean over the backbone's input embeddings of the
tokens of " " + label[i].
Compute infrastructure
- Hardware: one Apple M4 Mac mini, 24 GB unified memory, macOS 26.2. No GPU cluster, no cloud.
- Software: MLX (
mlx0.32.x,mlx-lm0.31.3), Python 3.12. - Hours: the project's commit history spans 2026-09-19 to 2026-09-22 on one machine. I did not instrument total occupancy, so I am not quoting a machine-hours figure. Head training itself is seconds to minutes on cached hidden states.
- Carbon emitted: not measured.
How to get started
Be honest about what this is: the head is a plain safetensors dict, and the surrounding
engine (prefill β KV-cache broadcast β batched branch pass β restricted read-out) is not published.
So this is not a one-line from_pretrained. What you get is the exact maths above plus a runnable
reference implementation of the head itself.
# pip install safetensors numpy
import math
import numpy as np
from safetensors.numpy import load_file
W = load_file("p3h-kd-a05/head.safetensors") # or p3h-ce-mlp / p3h-kd-mlp-a05 for the mlp heads
def rms(x, eps=1e-6):
return x / np.sqrt((x * x).mean(axis=-1, keepdims=True) + eps)
# the two `mlp` heads in this repo were trained with EXACT GELU, x * Phi(x) -- not the tanh
# approximation, not ReLU. numpy has no erf, so vectorise math.erf rather than substitute.
_erf = np.vectorize(math.erf)
def gelu(x):
return x * (1.0 + _erf(x / math.sqrt(2.0))) / 2.0
def head_scores(h, E, W):
"""h: [hidden] backbone hidden state. E: [n_labels, hidden] mean-pooled label embeddings."""
hn = rms(h.astype(np.float32)) * W["g"]
En = rms(E.astype(np.float32)) * W["ge"]
a = hn @ W["Wh"] if "Wh" in W else gelu(hn @ W["W1"] + W["b1"]) @ W["W2"]
B = En @ W["We"]
a = a / max(np.linalg.norm(a), 1e-6)
B = B / np.maximum(np.linalg.norm(B, axis=-1, keepdims=True), 1e-6)
scale = float(np.clip(np.exp(W["logit_scale"][0]), 1.0, 50.0))
return scale * (a @ B.T) + (En @ W["b"]) + W["c"]
# sanity check against the published metadata rather than trusting the file
import json, hashlib
man = {m["version"]: m for m in json.load(open("manifest.json"))}
blob = open("p3h-kd-a05/head.safetensors", "rb").read()
assert hashlib.sha256(blob).hexdigest() == man["p3h-kd-a05"]["sha256"]
print("shapes:", {k: v.shape for k, v in W.items()})
This is the real scorer, not a paraphrase of it. Both branches were run against the trained MLX modules that produced these weights, on fixed deterministic inputs, and agree to under 1e-5:
| head | weights | max abs difference vs the MLX scorer |
|---|---|---|
bilinear |
p3h-kd-a05 |
1.431e-06 |
bilinear |
p3h-ce-r64 |
1.907e-06 |
mlp |
p3h-ce-mlp |
1.631e-06 |
mlp |
p3h-kd-mlp-a05 |
2.891e-06 |
Full method and inputs: REFERENCE_CHECK.md in this repo.
To get h and E you need the backbone. E is straightforward (embed " " + label, mean-pool).
h is whatever hidden state you choose to read at β the numbers in this card come from a specific
read position produced by unpublished code, so your numbers will differ if you read elsewhere,
and I would not expect to reproduce the table above without reimplementing that pipeline.
Licence and upstream attribution
Upstream, clear:
- Backbone:
mlx-community/Qwen2.5-1.5B-Instruct-4bit, revision8b403126fc14f14cfc99bb4cfa72ecbc129ea677, Apache-2.0, derived fromQwen/Qwen2.5-1.5B. Its weights are not redistributed here β download it from its own repo. - Distillation teacher:
lmstudio-community/Qwen3.8-27B-MLX-4bit, revision6067b15cf581666a4aecf6af3afaba4bb5efc20c, Apache-2.0. Not redistributed here either, and not a model I made β I only evaluated it and used its outputs as soft targets. - Training datasets and their published licences: the table in
Training data. Two are restrictive or unclear in ways that matter:
ehovy/racepublishes terms restricting use to research, andallenai/scicite,tdiggelm/climate_feverandallenai/openbookqacarry no resolvable licence (unknown), whileallenai/winograndecarries no licence tag at all.
These head weights: I have not selected an open-source licence for them, so the default applies β copyright retained by the author, published here so the experiment can be read, checked and reproduced. I am not granting broader rights in this card because I do not want to guess, and because anyone using these weights still has to satisfy the upstream dataset terms above independently. If you want a specific licence, open a discussion and ask.
See LICENSE.md in this repo for the same statement in one place.
Model card authors and contact
Michael Chen. Questions or corrections: the Community tab of this repo.
Citation
No paper. If you refer to this, please describe it as what it is: a personal side-project experiment, including its negative transfer result.
Quantized
Model tree for mchen04/jev-local-lab-decision-heads
Base model
Qwen/Qwen2.5-1.5B