Task
Each variable is posed as one of three question types:
Table with columns: Type, Answer, Example| Type | Answer | Example |
|---|
noul | yes/no, as a probability | hospital_admission — was the patient admitted? |
choice | one of 2–255 named options | primary_diagnostic_modality — imaging, histopathology, laboratory, … |
score | an ordered level | symptom_severity — mild / moderate / severe |
The 11 variables were selected so they are not solvable by regular expressions: each candidate was
screened against a hand-written regex baseline and rejected if the regex nearly solved it. Sex and age,
for example, were dropped because a regex matches the label 98.9% of the time.
Results
Micro accuracy on the held-out test split (2,895 notes, 26,286 labelled questions):
Table with columns: system, micro accuracy, p50 latency / note| system | micro accuracy | p50 latency / note |
|---|
| MedJev-0.8B | 0.878 | 62 ms (bf16) |
| Regex / counting rules | 0.667 | 3.6 ms (CPU) |
Hosted Jev (jev-1.13.0) | 0.602 | 284 ms |
| Majority class per question | 0.602 | — |
| Qwen3.5-0.8B-Instruct, chat prompt | 0.517 | — |
By question type on test: noul 0.941, choice 0.793, score 0.810.
Per variable (test split):
Table with columns: variable, type, n, majority, MedJev, macro-F1, Brier| variable | type | n | majority | MedJev | macro-F1 | Brier |
|---|
surgical_management | noul | 2,895 | 0.709 | 0.954 | 0.944 | 0.073 |
follow_up_planned | noul | 2,895 | 0.889 |
Accuracy is fp32; latency is bf16, which costs no measurable accuracy and is ~3× faster.
Model selection was done on development; the test split was read once, after selection.
Usage
MedJev needs the medjev package (the adapter alone is not enough — the pointer head lives in
head.pt and the input format is specific):
git clone https://github.com/<your-org>/MedJev && cd MedJevpip install torch --index-url https://download.pytorch.org/whl/cu130pip install -e '.[cuda]'
import torchfrom huggingface_hub import snapshot_downloadfrom medjev.checkpoint import loadfrom medjev.model import MAX_BRANCH, MAX_STATEfrom medjev.records import materialize path = snapshot_download("junma/MedJev-Qwen3.5-0.8B")tok, model = load(path, "cuda", dtype=torch.bfloat16)model.lm.config.use_cache = True request = { "state": "A 36-year-old woman was admitted with severe left hip pain. MRI showed a lesion; " "biopsy confirmed osteosarcoma. She underwent resection and received chemotherapy, " "with complete resolution at 6 months.", "questions": { # `label` and `src` are required by materialize(); the label is ignored at inference "hospital_admission": { "type": "noul", "instructions": "Was this patient admitted to a hospital or other care centre?", "criteria": {"true": "Admitted as an inpatient", "false": "Outpatient visit only"}, "label": True, "src": "demo", }, "symptom_severity": { "type": "score", "instructions": "How severe is the patient's presentation overall?", "criteria": ["Mild", "Moderate", "Severe"], "label": 0, "src": "demo", }, },} enc = model.encode(tok, materialize(request), max_state=MAX_STATE, max_branch=MAX_BRANCH)with torch.no_grad(): probs, _ = model.probs_and_prefix(enc) # state encoded once; branches read its cache for p, (qid, q) in zip(probs, request["questions"].items()): print(qid, [round(float(x), 3) for x in p]) # hospital_admission [0.0, 1.0] noul: [P(false), P(true)]# symptom_severity [0.0, 0.0, 1.0] score: one entry per level
The schema is free-form — reuse the 11 specs in medjev.labels.QUESTIONS or pass your own
instructions and criteria in the same shape. Option order is shuffled during training, so choice
answers are order-robust, but the model is fine-tuned on this corpus's vocabulary; new option sets
work best after a short further fine-tune.
How it works
The backbone is hybrid — 12 Gated DeltaNet + 12 attention layers. Because the DeltaNet layers are
recurrent and ignore attention masks, each question runs as its own causal row with the state
repeated, which makes question isolation exact by construction: questions cannot read each other.
At serving time the state is encoded once and every question branch reads its cache, so answering
all 11 variables costs about as much as answering one. That is where the speed comes from, and why
the reported latency is per note, not per question.
The pointer head scores each option's boundary token against a <decide> position; a softmax over
those scores is the answer. Training is cross-entropy, plus a ranked probability score term for the
three genuinely ordered score variables.
Training
Table | |
|---|
| Base | Qwen3.5-0.8B-Base (frozen) |
| Adapter | LoRA r=16, α=32, dropout 0.05, on attention + MLP + DeltaNet projections |
| Head | Pointer head, 256-dim, trained from scratch |
| Trainable | 11.3 M parameters (adapter ≈ 43 MB) |
| Data | 23,719 notes / 215,425 labelled questions |
| Schedule | 2 epochs, all ~9 questions per record, 431,124 question rows, 5,272 steps |
| Optimizer | AdamW, OneCycle, lr 1e-4, weight decay 0.01, effective batch 9 |
| State budget |
Training data and label provenance
Derived from Augmented Clinical Notes
(Bonnet & Boulenger, EPFL; MIT), whose notes come from
PMC-Patients — open-access PubMed Central case reports.
Labels are silver, not gold. They are normalised from that corpus's structured patient summaries,
which were themselves generated by GPT-4 against a medical template. MedJev is therefore trained to
reproduce a GPT-4 extraction, not clinician adjudication. Accuracy figures here measure agreement with
those silver labels.
Input is full_note only; the corpus's note, conversation and summary fields are never model
input. Splits are 80/10/10 by sha1(idx), so they are stable across rebuilds, with no note overlap.
Limitations and intended use
Not for clinical use. This is a research artifact. It has not been validated against clinician
adjudication, has no regulatory clearance, and is not a medical device. Do not use it to inform care.
- Silver labels. Ceiling accuracy is agreement with a GPT-4 extraction, which carries its own
errors, especially on the harder aggregation variables.
- Domain. Published, English-language, single-patient case reports — typically short, curated and
unusually complete. Real EHR notes are longer, messier, more abbreviated and more templated;
expect degradation.
- Population. Case reports over-represent rare and severe presentations. Base rates here are not
clinical base rates.
- Long notes. The state budget is 2,048 tokens, truncated from the beginning of the note.
~1% of notes in this corpus exceed it.
- Calibration. Brier scores are good in-domain; they are not validated out of domain. Test any
probability threshold on your own data.
- Schema drift. The model is tuned to these 11 variables' wording. Substantially different
questions warrant a short further fine-tune.
Citation
The architecture (LoRA + pointer head, question isolation, the System One request format) is from
kev by Jared Palmer, Apache-2.0. MedJev vendors and adapts it;
the training data and all weights here are MedJev's own.
@software{medjev2026, title = {MedJev: ultra-fast clinical variable extraction with a small decision model}, author = {Ma, Jun}, year = {2026}, url = {https://huggingface.co/junma/MedJev-Qwen3.5-0.8B}}
License
Apache-2.0, matching kev and the Qwen3.5 base model. The corpus is MIT; the base model carries its
own licence. Review both before redistributing anything derived from this.
Framework versions
- PEFT 0.21.0
- transformers 5.17.0
- torch 2.14.0+cu130