Text Classification
Transformers
Safetensors
English
qwen3_5_text
text-generation
system-one
typed-decisions
decision-model
calibrated-probabilities
knowledge-distillation
jev
noul
choice
score
lora
qwen3_5
dual-head
vllm
Eval Results (legacy)
Instructions to use autotrust/JEV with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use autotrust/JEV with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-classification", model="autotrust/JEV")# Load model directly from transformers import AutoTokenizer, AutoModelForCausalLM tokenizer = AutoTokenizer.from_pretrained("autotrust/JEV") model = AutoModelForCausalLM.from_pretrained("autotrust/JEV", device_map="auto") - Notebooks
- Google Colab
- Kaggle
| #!/usr/bin/env python3 | |
| """Decision path through vLLM: accuracy vs. the HF/PyTorch reference, throughput, and a mixed AR+decision call. | |
| python3 scripts/vllm_decisions.py --bundle exports/jev-judge-qwen35-9b-v0.8 --hf-ref reports/hf_probs_9b_t30k.npz \ | |
| --out reports/vllm_decisions_9b.json | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import json | |
| import os | |
| import sys | |
| import time | |
| import numpy as np | |
| sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "src")) | |
| from jev_judge.data import load_split, target_to_slots # noqa: E402 | |
| from jev_judge.metrics import fmt_summary, per_sample_table, summarize # noqa: E402 | |
| from jev_judge.template import SLOT_RANGES, n_options_for # noqa: E402 | |
| def slot_mask_np(df) -> np.ndarray: | |
| m = np.zeros((len(df), 24), dtype=bool) | |
| for i, (k, o) in enumerate(zip(df["kind"], df["options"])): | |
| s, _ = SLOT_RANGES[k] | |
| m[i, s : s + n_options_for(k, list(o))] = True | |
| return m | |
| def main() -> None: | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("--bundle", required=True) | |
| ap.add_argument("--data", default="data") | |
| ap.add_argument("--split", default="test_set_30k") | |
| ap.add_argument("--hf-ref", default=None, help="npz with `probs` [N,24] from the PyTorch path on the same split") | |
| ap.add_argument("--out", required=True) | |
| ap.add_argument("--gpu-mem", type=float, default=0.85) | |
| args = ap.parse_args() | |
| from jev_judge.vllm_engine import VllmJudge | |
| df = load_split(args.data, args.split) | |
| rows = [{"kind": k, "state": s, "question": q, "options": list(o), "family": f} | |
| for k, s, q, o, f in zip(df["kind"], df["state"], df["question"], df["options"], df["family"])] | |
| t0 = time.time() | |
| judge = VllmJudge(args.bundle, gpu_memory_utilization=args.gpu_mem) | |
| load_s = time.time() - t0 | |
| judge.decide(rows[:256]) # warm-up (LoRA load, graph capture for these shapes) | |
| t0 = time.time() | |
| p = judge.decide(rows) | |
| dt = time.time() - t0 | |
| n_tok = int(df["n_tokens"].sum()) | |
| q = np.stack([target_to_slots(k, t) for k, t in zip(df["kind"], df["target"])]) | |
| mask = slot_mask_np(df) | |
| s = summarize(per_sample_table(p, q, mask, df)) | |
| res = {"bundle": args.bundle, "split": args.split, "n": len(df), "load_s": load_s, "decide_s": dt, | |
| "rows_per_s": len(df) / dt, "prompt_tok_per_s": n_tok / dt, "metrics": s} | |
| print(f"[vLLM decisions] {fmt_summary(s)}") | |
| print(f"[vLLM decisions] {len(df)} rows in {dt:.1f}s -> {len(df)/dt:.0f} rows/s, {n_tok/dt:.0f} prompt tok/s (load {load_s:.0f}s)") | |
| if args.hf_ref and os.path.exists(args.hf_ref): | |
| ref = np.load(args.hf_ref)["probs"] | |
| d = np.abs(p - ref)[mask] | |
| agree = (np.where(mask, p, -1).argmax(1) == np.where(mask, ref, -1).argmax(1)).mean() | |
| res["vs_hf"] = {"max_abs_dp": float(d.max()), "mean_abs_dp": float(d.mean()), "p99_abs_dp": float(np.percentile(d, 99)), | |
| "argmax_agreement": float(agree)} | |
| print(f"[vs PyTorch path] max|Δp| {d.max():.4f} · mean|Δp| {d.mean():.5f} · p99 {np.percentile(d, 99):.4f} · argmax agreement {agree:.4f}") | |
| # one engine call, both heads | |
| from vllm import SamplingParams | |
| msgs = [[{"role": "user", "content": x}] for x in ["In one sentence, what is safety stock?", | |
| "Write a Python one-liner that reverses a string."]] | |
| gen_prompts = [judge.tok.apply_chat_template(m, tokenize=False, add_generation_prompt=True) for m in msgs] | |
| t0 = time.time() | |
| gen_outs, dec = judge.mixed(gen_prompts, SamplingParams(temperature=0.0, max_tokens=48), rows[:64]) | |
| res["mixed_call_s"] = time.time() - t0 | |
| res["mixed_decisions_match"] = float(np.abs(dec - p[:64]).max()) | |
| res["mixed_generation_sample"] = [o.outputs[0].text[:160] for o in gen_outs] | |
| print(f"[mixed] 2 AR generations + 64 decisions in one call: {res['mixed_call_s']:.2f}s; " | |
| f"decisions max|Δp| vs decision-only run {res['mixed_decisions_match']:.2e}") | |
| for t in res["mixed_generation_sample"]: | |
| print(" gen:", t.replace("\n", " ")[:140]) | |
| with open(args.out, "w") as f: | |
| json.dump(res, f, indent=1) | |
| print("->", args.out) | |
| if __name__ == "__main__": | |
| main() | |