Feature Extraction
Transformers
Safetensors
pivot
decision-making
classification
scoring
custom_code
Instructions to use Q1z/Pivot with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use Q1z/Pivot with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("feature-extraction", model="Q1z/Pivot", trust_remote_code=True)# pip install -U transformers accelerate # Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("Q1z/Pivot", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
Expand Pivot model card, benchmarks, CPU tools and charts
Browse files- .gitattributes +1 -0
- README.md +70 -13
- benchmarks/README.md +14 -0
- benchmarks/jevbench_public.py +296 -0
- benchmarks/requirements.txt +5 -0
- config.json +2 -2
- cpu-speed/README.md +14 -0
- cpu-speed/benchmark.py +9 -0
- docs/BENCHMARK.md +26 -0
- docs/INFERENCE.md +72 -0
- docs/PERFORMANCE.md +32 -0
- docs/UPDATE_NOTES.md +9 -0
- evaluation/2026-09-24/README.md +14 -0
- evaluation/2026-09-24/accuracy.png +0 -0
- evaluation/2026-09-24/cpu_speed.json +39 -0
- evaluation/2026-09-24/jevbench_public.json +585 -0
- evaluation/2026-09-24/latency_throughput.png +0 -0
- evaluation/2026-09-24/performance.json +96 -0
- evaluation/2026-09-24/performance_overview.png +3 -0
- evaluation/render_charts.py +94 -0
- examples/cached_candidates.py +21 -0
- examples/native_decision.py +20 -0
- examples/quickstart.py +16 -0
- manifest.json +103 -6
- notebooks/Pivot_CPU_Speed.ipynb +101 -0
- serving/README.md +11 -0
- serving/typed_decisions.py +20 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
evaluation/2026-09-24/performance_overview.png filter=lfs diff=lfs merge=lfs -text
|
README.md
CHANGED
|
@@ -12,28 +12,85 @@ tags:
|
|
| 12 |
|
| 13 |
# Pivot
|
| 14 |
|
| 15 |
-
|
| 16 |
|
| 17 |
-
|
| 18 |
-
The training recipe uses two CE warmup epochs followed by live multiclass Brier + PCGrad.
|
| 19 |
-
Probabilities are computed as `softmax(logits.float())`.
|
| 20 |
|
| 21 |
-
|
| 22 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
|
| 24 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
|
| 26 |
```python
|
|
|
|
| 27 |
from transformers import AutoModel, AutoTokenizer
|
| 28 |
|
| 29 |
-
|
| 30 |
-
model = AutoModel.from_pretrained(
|
| 31 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
"route to billing support",
|
| 33 |
"route to technical support",
|
| 34 |
"route to sales",
|
| 35 |
-
]
|
| 36 |
-
|
|
|
|
| 37 |
```
|
| 38 |
|
| 39 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
|
| 13 |
# Pivot
|
| 14 |
|
| 15 |
+
### Fast closed-set decisions from context and candidate actions
|
| 16 |
|
| 17 |
+
Pivot is a **357.6M-parameter** bidirectional decision encoder. Give it a context and two or more candidate answers; it scores the set in one forward pass and returns the chosen answer, its position, and a probability for every candidate. It does not generate free-form text. The full FP32 checkpoint, tokenizer and Transformers custom runtime are stored in this model repository.
|
|
|
|
|
|
|
| 18 |
|
| 19 |
+
| Measured result | Pivot |
|
| 20 |
+
|---|---:|
|
| 21 |
+
| JevBench v1.4.1 public accuracy | **46.32%** (107 / 231) |
|
| 22 |
+
| NVIDIA H200 warm single-decision p50 / p95 | **15.8 / 19.9 ms** |
|
| 23 |
+
| NVIDIA H200 throughput, batch 32 | **545.3 decisions/s** |
|
| 24 |
+
| 4-thread Xeon CPU warm single-decision p50 / p95 | **797.6 / 1,089.0 ms** |
|
| 25 |
+
| 4-thread Xeon CPU throughput, batch 4 | **3.77 decisions/s** |
|
| 26 |
|
| 27 |
+
These are measurements on the pinned checkpoint, in FP32, including tokenization and scoring. GPU and CPU throughput used **different batch sizes**. The 46.32% figure is public-task accuracy; the **official JevBench v1.4 composite score has not been measured** because the sealed/judge portion and cost input are unavailable. [Protocol and limitations](docs/BENCHMARK.md) · [Full measurement details](docs/PERFORMANCE.md)
|
| 28 |
+
|
| 29 |
+

|
| 30 |
+
|
| 31 |
+
## Start with one decision
|
| 32 |
+
|
| 33 |
+
Install a suitable PyTorch build and the runtime packages:
|
| 34 |
+
|
| 35 |
+
```bash
|
| 36 |
+
python -m pip install "transformers==5.17.0" "safetensors==0.8.0"
|
| 37 |
+
```
|
| 38 |
|
| 39 |
```python
|
| 40 |
+
import torch
|
| 41 |
from transformers import AutoModel, AutoTokenizer
|
| 42 |
|
| 43 |
+
tokenizer = AutoTokenizer.from_pretrained("Q1z/Pivot", trust_remote_code=True)
|
| 44 |
+
model = AutoModel.from_pretrained(
|
| 45 |
+
"Q1z/Pivot", trust_remote_code=True, dtype=torch.float32
|
| 46 |
+
).eval()
|
| 47 |
+
|
| 48 |
+
context = "CONTEXT:\nA customer disputes an invoice and asks for a correction."
|
| 49 |
+
options = [
|
| 50 |
"route to billing support",
|
| 51 |
"route to technical support",
|
| 52 |
"route to sales",
|
| 53 |
+
]
|
| 54 |
+
decision = model.choose(tokenizer, context, options)
|
| 55 |
+
print(decision) # {"choice": ..., "index": ..., "probs": [...]}
|
| 56 |
```
|
| 57 |
|
| 58 |
+
The serving configuration now defaults to **512 context tokens and 128 option tokens**, matching the published public evaluation. It does not change the checkpoint weights. Run on CUDA with `model.to("cuda")` if your PyTorch build supports it. Review the repository's custom model code before enabling `trust_remote_code=True`.
|
| 59 |
+
|
| 60 |
+
## Three ways to use Pivot
|
| 61 |
+
|
| 62 |
+
| Method | Input | Output |
|
| 63 |
+
|---|---|---|
|
| 64 |
+
| `model.choose(tokenizer, context, options)` | Context and ordered answer strings | Chosen answer, index, probability vector |
|
| 65 |
+
| `model.decide_native(tokenizer, context, candidates)` | Candidate IDs, semantic text, optional abstain action | Selected ID, relative confidence, per-candidate probabilities |
|
| 66 |
+
| `model.decide(tokenizer, state, questions)` | Several typed choice / yes-no / score questions | Typed decision response |
|
| 67 |
+
|
| 68 |
+
For repeated decisions using the same options, `encode_candidates`, `encode_context`, and `choose_cached` reuse candidate representations. This can avoid repeated candidate encoding; the measured throughput above uses the **uncached** path. Examples: [basic](examples/quickstart.py), [structured decisions](examples/native_decision.py), [cached candidates](examples/cached_candidates.py), and [full inference guide](docs/INFERENCE.md).
|
| 69 |
+
|
| 70 |
+
Pivot's probabilities are **relative to the supplied candidate set**. Give each candidate a clear, distinct meaning. An abstain route must be an explicit candidate; a high relative probability alone does not establish real-world correctness or safety.
|
| 71 |
+
|
| 72 |
+
## Evaluated performance
|
| 73 |
+
|
| 74 |
+
The official JevBench v1.4.1 **public tasks** were scored with the official per-task scorer at commit `24b9b5c1609a7a9e8fa14f49e5985a836c9dc842`. The exact evaluated model commit was `14bf8c26bf344ebdf88e22a4b6152dc5f75f3578`.
|
| 75 |
+
|
| 76 |
+
| Public tier | Correct / tasks | Accuracy | ECE, 10 bins |
|
| 77 |
+
|---|---:|---:|---:|
|
| 78 |
+
| Original | 27 / 72 | 37.50% | 0.525 |
|
| 79 |
+
| Easy | 39 / 48 | 81.25% | 0.114 |
|
| 80 |
+
| Hard | 41 / 111 | 36.94% | 0.379 |
|
| 81 |
+
| **All public tasks** | **107 / 231** | **46.32%** | — |
|
| 82 |
+
|
| 83 |
+
The frozen evaluation format is a `CONTEXT:` prefix, task rubric descriptions where provided (otherwise humanized labels) in official label order, right truncation, 512 context tokens and 128 option tokens. Public accuracy is not an official leaderboard score. [Reproduce public results](benchmarks/README.md) or [run the CPU speed entry point](cpu-speed/README.md). The [CPU notebook](notebooks/Pivot_CPU_Speed.ipynb) provides an interactive alternative.
|
| 84 |
+
|
| 85 |
+
## Repository guide
|
| 86 |
+
|
| 87 |
+
- [Inference methods and examples](docs/INFERENCE.md)
|
| 88 |
+
- [Serving interfaces and request formats](serving/README.md)
|
| 89 |
+
- [JevBench protocol, revision, and score scope](docs/BENCHMARK.md)
|
| 90 |
+
- [Results, hardware, charts, and caveats](docs/PERFORMANCE.md)
|
| 91 |
+
- [Reproducible public benchmark script](benchmarks/jevbench_public.py)
|
| 92 |
+
- [Standalone CPU speed script](cpu-speed/benchmark.py)
|
| 93 |
+
- [Pinned result files and chart](evaluation/2026-09-24/README.md)
|
| 94 |
+
- [What changed in this update](docs/UPDATE_NOTES.md)
|
| 95 |
+
|
| 96 |
+
The files `model.safetensors`, `modeling_pivot.py`, `modeling_lfm2_bidirectional.py`, `pivot_model.py` and `pivot_infer.py` contain the checkpoint and model runtime. [Package manifest](manifest.json) records file hashes. The original checkpoint and evaluated metrics remain anchored to the exact revision above.
|
benchmarks/README.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Reproduce Pivot's public results
|
| 2 |
+
|
| 3 |
+
Run the standalone `jevbench_public.py` script from this repository. It checks out the official JevBench v1.4.1 source at commit `24b9b5c1609a7a9e8fa14f49e5985a836c9dc842`, verifies a clean checkout, and uses its public tasks and official per-task scorer.
|
| 4 |
+
|
| 5 |
+
Install Python, Git, and a PyTorch build for your hardware. The requirements file records the versions used for the reported run. On Windows PowerShell:
|
| 6 |
+
|
| 7 |
+
```powershell
|
| 8 |
+
py -m pip install -r benchmarks/requirements.txt
|
| 9 |
+
py benchmarks/jevbench_public.py --device cpu --threads 4 --batch-size 4 --output pivot_cpu_results.json
|
| 10 |
+
```
|
| 11 |
+
|
| 12 |
+
On a CUDA machine use `--device cuda --batch-size 32`. If you only need timings, add `--mode speed`. For public task accuracy only, add `--mode accuracy`. The model is pinned to commit `14bf8c26bf344ebdf88e22a4b6152dc5f75f3578` unless you deliberately provide another full SHA via `--revision`. Allow time and disk space for the approximately 1.43 GB checkpoint.
|
| 13 |
+
|
| 14 |
+
The script uses the same candidate wording, input rendering, token limits, FP32 scoring, warmup count, and timing protocol as the published run. Timings still vary with hardware, software and background load. Only public JevBench tasks are available here; `official_jevbench_score` is always null. The full official score requires organizer-held sealed and judge tasks and cost measurement. See [the benchmark protocol](../docs/BENCHMARK.md).
|
benchmarks/jevbench_public.py
ADDED
|
@@ -0,0 +1,296 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Standalone Pivot evaluation on the pinned official JevBench public tasks.
|
| 2 |
+
|
| 3 |
+
The sealed benchmark and cost component are unavailable here. This script only
|
| 4 |
+
reports public accuracy and local warm FP32 speed; it never fabricates a score.
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
from __future__ import annotations
|
| 8 |
+
|
| 9 |
+
import argparse
|
| 10 |
+
import json
|
| 11 |
+
import math
|
| 12 |
+
import os
|
| 13 |
+
import platform
|
| 14 |
+
import statistics
|
| 15 |
+
import subprocess
|
| 16 |
+
import sys
|
| 17 |
+
import time
|
| 18 |
+
from pathlib import Path
|
| 19 |
+
|
| 20 |
+
MODEL_ID = "Q1z/Pivot"
|
| 21 |
+
MODEL_REVISION = "14bf8c26bf344ebdf88e22a4b6152dc5f75f3578"
|
| 22 |
+
JEVBENCH_REVISION = "24b9b5c1609a7a9e8fa14f49e5985a836c9dc842" # v1.4.1
|
| 23 |
+
CONTRACT = {
|
| 24 |
+
"context_arm": "context_header",
|
| 25 |
+
"option_arm": "original",
|
| 26 |
+
"context_tokens": 512,
|
| 27 |
+
"option_tokens": 128,
|
| 28 |
+
"truncation": "right",
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def _run(*args: str) -> str:
|
| 33 |
+
return subprocess.check_output(args, text=True).strip()
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def checkout_jevbench(cache: Path) -> Path:
|
| 37 |
+
repo = cache / "jevbench"
|
| 38 |
+
created = not repo.exists()
|
| 39 |
+
if created:
|
| 40 |
+
repo.parent.mkdir(parents=True, exist_ok=True)
|
| 41 |
+
subprocess.run(
|
| 42 |
+
["git", "clone", "--filter=blob:none", "--no-checkout",
|
| 43 |
+
"https://github.com/fstandhartinger/jevbench.git", str(repo)],
|
| 44 |
+
check=True,
|
| 45 |
+
)
|
| 46 |
+
if not (repo / ".git").exists():
|
| 47 |
+
raise RuntimeError(f"Expected a clean git checkout at {repo}")
|
| 48 |
+
if not created and _run("git", "-C", str(repo), "status", "--porcelain", "--untracked-files=all"):
|
| 49 |
+
raise RuntimeError("JevBench checkout has local changes; choose a clean cache")
|
| 50 |
+
if _run("git", "-C", str(repo), "rev-parse", "HEAD") != JEVBENCH_REVISION:
|
| 51 |
+
subprocess.run(["git", "-C", str(repo), "fetch", "--depth", "1", "origin", JEVBENCH_REVISION], check=True)
|
| 52 |
+
subprocess.run(["git", "-C", str(repo), "checkout", "--detach", JEVBENCH_REVISION], check=True)
|
| 53 |
+
required = [repo / "jevbench" / "tasks.py"] + [
|
| 54 |
+
repo / "datasets" / "public" / f"{tier}.jsonl"
|
| 55 |
+
for tier in ("original", "easy", "hard")
|
| 56 |
+
]
|
| 57 |
+
if (_run("git", "-C", str(repo), "rev-parse", "HEAD") != JEVBENCH_REVISION
|
| 58 |
+
or _run("git", "-C", str(repo), "status", "--porcelain", "--untracked-files=all")
|
| 59 |
+
or not all(path.is_file() for path in required)):
|
| 60 |
+
raise RuntimeError("Official JevBench revision or public files differ")
|
| 61 |
+
for name in ("jevbench", "jevbench.tasks", "jevbench.scoring", "jevbench.metrics"):
|
| 62 |
+
module = sys.modules.get(name)
|
| 63 |
+
if module is not None and Path(getattr(module, "__file__", "") or "").resolve().is_relative_to(repo.resolve()) is False:
|
| 64 |
+
raise RuntimeError(f"{name} was imported from a different checkout")
|
| 65 |
+
sys.path.insert(0, str(repo))
|
| 66 |
+
return repo
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
def _clean(value: object) -> str:
|
| 70 |
+
return " ".join(str(value).split())
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
def _humanize(label: object) -> str:
|
| 74 |
+
return _clean(str(label).replace("_", " ").replace("-", " "))
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
def _render_state(value: object) -> str:
|
| 78 |
+
if isinstance(value, str):
|
| 79 |
+
return value.strip()
|
| 80 |
+
if value is None:
|
| 81 |
+
return "null"
|
| 82 |
+
if isinstance(value, (bool, int, float)):
|
| 83 |
+
return str(value)
|
| 84 |
+
if isinstance(value, list):
|
| 85 |
+
return "\n".join(f"- {_render_state(item)}" for item in value)
|
| 86 |
+
if isinstance(value, dict):
|
| 87 |
+
parts = []
|
| 88 |
+
for key, child in value.items():
|
| 89 |
+
rendered = _render_state(child)
|
| 90 |
+
if rendered:
|
| 91 |
+
parts.append(f"{_humanize(key).title()}: {rendered}")
|
| 92 |
+
return "\n\n".join(parts)
|
| 93 |
+
return json.dumps(value, ensure_ascii=False, sort_keys=True)
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
def prepare_rows(tasks: list) -> tuple[list[dict], list]:
|
| 97 |
+
"""Same rendering and exclusions as the evaluated Pivot_test public run."""
|
| 98 |
+
rows, kept = [], []
|
| 99 |
+
for task in tasks:
|
| 100 |
+
if task.expected is None or task.provenance.get("exclude_reason"):
|
| 101 |
+
continue
|
| 102 |
+
labels = [str(item) for item in task.labels]
|
| 103 |
+
gold = str(task.expected)
|
| 104 |
+
if gold not in labels:
|
| 105 |
+
continue
|
| 106 |
+
criteria = task.question.get("criteria")
|
| 107 |
+
kind = str(task.question["type"])
|
| 108 |
+
options = []
|
| 109 |
+
for label in labels:
|
| 110 |
+
description = None
|
| 111 |
+
if isinstance(criteria, dict):
|
| 112 |
+
key = {"no": "false", "yes": "true"}.get(label.strip().lower(), label)
|
| 113 |
+
description = criteria.get(key)
|
| 114 |
+
if description is None:
|
| 115 |
+
description = criteria.get(label)
|
| 116 |
+
elif isinstance(criteria, list) and kind == "score":
|
| 117 |
+
try:
|
| 118 |
+
description = criteria[int(label)]
|
| 119 |
+
except (ValueError, IndexError, TypeError):
|
| 120 |
+
pass
|
| 121 |
+
text = _clean(description) if description is not None else _humanize(label)
|
| 122 |
+
if not text:
|
| 123 |
+
raise ValueError(f"Empty option for {label!r}")
|
| 124 |
+
options.append(text)
|
| 125 |
+
focus = str(task.question.get("instructions") or "").strip()
|
| 126 |
+
evidence = _render_state(task.state)
|
| 127 |
+
body = f"{focus}\n\n{evidence}".strip() if focus else evidence
|
| 128 |
+
rows.append({"context": "CONTEXT:\n" + body, "options": options})
|
| 129 |
+
kept.append(task)
|
| 130 |
+
return rows, kept
|
| 131 |
+
|
| 132 |
+
|
| 133 |
+
def score_rows(model, tokenizer, rows: list[dict], device: str, batch_size: int) -> list[list[float]]:
|
| 134 |
+
"""Encode each context and option in FP32, then score the original set."""
|
| 135 |
+
import torch
|
| 136 |
+
|
| 137 |
+
output: list[list[float]] = []
|
| 138 |
+
previous = tokenizer.truncation_side
|
| 139 |
+
tokenizer.truncation_side = "right"
|
| 140 |
+
try:
|
| 141 |
+
with torch.inference_mode():
|
| 142 |
+
for start in range(0, len(rows), batch_size):
|
| 143 |
+
batch = rows[start:start + batch_size]
|
| 144 |
+
ctx = tokenizer([row["context"] for row in batch], padding=True,
|
| 145 |
+
truncation=True, max_length=512, return_tensors="pt")
|
| 146 |
+
opt = tokenizer([text for row in batch for text in row["options"]],
|
| 147 |
+
padding=True, truncation=True, max_length=128,
|
| 148 |
+
return_tensors="pt")
|
| 149 |
+
dev = torch.device(device)
|
| 150 |
+
h_ctx = model.network.encode(ctx["input_ids"].to(dev), ctx["attention_mask"].to(dev))
|
| 151 |
+
h_opt = model.network.encode(opt["input_ids"].to(dev), opt["attention_mask"].to(dev))
|
| 152 |
+
width = max(len(row["options"]) for row in batch)
|
| 153 |
+
pieces, masks, offset = [], [], 0
|
| 154 |
+
for row in batch:
|
| 155 |
+
count = len(row["options"])
|
| 156 |
+
part = h_opt[offset:offset + count]
|
| 157 |
+
offset += count
|
| 158 |
+
if count < width:
|
| 159 |
+
part = torch.cat([part, part.new_zeros(width - count, part.shape[-1])])
|
| 160 |
+
pieces.append(part)
|
| 161 |
+
mask = torch.zeros(width, dtype=torch.bool, device=dev)
|
| 162 |
+
mask[:count] = True
|
| 163 |
+
masks.append(mask)
|
| 164 |
+
result = model.network.score_preencoded(h_ctx, torch.stack(pieces), torch.stack(masks))
|
| 165 |
+
for idx, row in enumerate(batch):
|
| 166 |
+
probabilities = result.probs[idx, :len(row["options"])].float().cpu().tolist()
|
| 167 |
+
if (not all(math.isfinite(x) for x in probabilities)
|
| 168 |
+
or abs(sum(probabilities) - 1.0) > 1e-5):
|
| 169 |
+
raise ValueError(f"Invalid probabilities at row {start + idx}")
|
| 170 |
+
output.append(probabilities)
|
| 171 |
+
finally:
|
| 172 |
+
tokenizer.truncation_side = previous
|
| 173 |
+
return output
|
| 174 |
+
|
| 175 |
+
|
| 176 |
+
def speed(model, tokenizer, rows: list[dict], device: str, batch_size: int) -> dict:
|
| 177 |
+
"""Mirror the original run: 5+2 warmups; 32 singles; 3x64 bulk."""
|
| 178 |
+
import torch
|
| 179 |
+
|
| 180 |
+
def timed(subset: list[dict], size: int) -> float:
|
| 181 |
+
if device == "cuda":
|
| 182 |
+
torch.cuda.synchronize()
|
| 183 |
+
start = time.perf_counter()
|
| 184 |
+
score_rows(model, tokenizer, subset, device, size)
|
| 185 |
+
if device == "cuda":
|
| 186 |
+
torch.cuda.synchronize()
|
| 187 |
+
return time.perf_counter() - start
|
| 188 |
+
|
| 189 |
+
samples = rows[:32]
|
| 190 |
+
for row in samples[:5]:
|
| 191 |
+
timed([row], 1)
|
| 192 |
+
latencies = [timed([row], 1) for row in samples]
|
| 193 |
+
bulk = rows[:64]
|
| 194 |
+
for _ in range(2):
|
| 195 |
+
timed(bulk, batch_size)
|
| 196 |
+
repeats = [timed(bulk, batch_size) for _ in range(3)]
|
| 197 |
+
return {
|
| 198 |
+
"measurement": "warm local FP32; includes tokenization, inference and scoring",
|
| 199 |
+
"hardware": torch.cuda.get_device_name(0) if device == "cuda" else platform.processor(),
|
| 200 |
+
"threads": torch.get_num_threads() if device == "cpu" else None,
|
| 201 |
+
"single_decision": {
|
| 202 |
+
"n": len(latencies), "batch_size": 1,
|
| 203 |
+
"p50_ms": 1000 * statistics.median(latencies),
|
| 204 |
+
"p95_ms": 1000 * sorted(latencies)[math.ceil(.95 * len(latencies)) - 1],
|
| 205 |
+
"mean_ms": 1000 * statistics.mean(latencies),
|
| 206 |
+
},
|
| 207 |
+
"throughput": {
|
| 208 |
+
"batch_size": batch_size, "decisions_per_repeat": len(bulk),
|
| 209 |
+
"repeats": 3, "repeat_seconds": repeats,
|
| 210 |
+
"decisions_per_second": len(bulk) / statistics.median(repeats),
|
| 211 |
+
},
|
| 212 |
+
}
|
| 213 |
+
|
| 214 |
+
|
| 215 |
+
def main(argv: list[str] | None = None) -> dict:
|
| 216 |
+
parser = argparse.ArgumentParser(description=__doc__)
|
| 217 |
+
parser.add_argument("--mode", choices=("speed", "accuracy", "all"), default="all")
|
| 218 |
+
parser.add_argument("--device", choices=("auto", "cpu", "cuda"), default="auto")
|
| 219 |
+
parser.add_argument("--batch-size", type=int, default=None)
|
| 220 |
+
parser.add_argument("--threads", type=int, default=0)
|
| 221 |
+
parser.add_argument("--revision", default=MODEL_REVISION)
|
| 222 |
+
parser.add_argument("--cache", type=Path, default=Path.home() / ".cache" / "pivot_jevbench")
|
| 223 |
+
parser.add_argument("--output", type=Path, default=Path("pivot_public_results.json"))
|
| 224 |
+
args = parser.parse_args(argv)
|
| 225 |
+
if args.batch_size is not None and args.batch_size < 1 or args.threads < 0:
|
| 226 |
+
parser.error("batch-size must be positive and threads nonnegative")
|
| 227 |
+
if len(args.revision) != 40 or any(ch not in "0123456789abcdef" for ch in args.revision):
|
| 228 |
+
parser.error("revision must be a full lowercase commit SHA")
|
| 229 |
+
|
| 230 |
+
import torch
|
| 231 |
+
from transformers import AutoModel, AutoTokenizer
|
| 232 |
+
|
| 233 |
+
if args.threads:
|
| 234 |
+
torch.set_num_threads(args.threads)
|
| 235 |
+
device = ("cuda" if torch.cuda.is_available() else "cpu") if args.device == "auto" else args.device
|
| 236 |
+
if device == "cuda" and not torch.cuda.is_available():
|
| 237 |
+
parser.error("CUDA is unavailable")
|
| 238 |
+
batch_size = args.batch_size or (32 if device == "cuda" else 4)
|
| 239 |
+
checkout = checkout_jevbench(args.cache)
|
| 240 |
+
from jevbench.tasks import load_jsonl
|
| 241 |
+
from jevbench.scoring import score_task
|
| 242 |
+
from jevbench.metrics import ece_top_label
|
| 243 |
+
|
| 244 |
+
torch.backends.cuda.matmul.allow_tf32 = False
|
| 245 |
+
torch.backends.cudnn.allow_tf32 = False
|
| 246 |
+
torch.manual_seed(42)
|
| 247 |
+
print("Loading checkpoint and tokenizer...", flush=True)
|
| 248 |
+
model = AutoModel.from_pretrained(MODEL_ID, revision=args.revision,
|
| 249 |
+
trust_remote_code=True, dtype=torch.float32)
|
| 250 |
+
model.to(device=torch.device(device), dtype=torch.float32).eval()
|
| 251 |
+
tokenizer = AutoTokenizer.from_pretrained(MODEL_ID, revision=args.revision)
|
| 252 |
+
root = checkout / "datasets" / "public"
|
| 253 |
+
results = {
|
| 254 |
+
"model": MODEL_ID, "model_revision": args.revision,
|
| 255 |
+
"benchmark_release": "v1.4.1", "benchmark_commit": JEVBENCH_REVISION,
|
| 256 |
+
"scope": "public tasks only", "official_jevbench_score": None,
|
| 257 |
+
"contract": CONTRACT, "device": device,
|
| 258 |
+
}
|
| 259 |
+
if args.mode in ("accuracy", "all"):
|
| 260 |
+
cohorts = {}
|
| 261 |
+
for name in ("original", "easy", "hard"):
|
| 262 |
+
tasks = load_jsonl(str(root / f"{name}.jsonl"))
|
| 263 |
+
rows, kept = prepare_rows(tasks)
|
| 264 |
+
scored = score_rows(model, tokenizer, rows, device, batch_size)
|
| 265 |
+
official = [score_task(dict(zip(map(str, task.labels), probs)), task)
|
| 266 |
+
for task, probs in zip(kept, scored)]
|
| 267 |
+
valid = [item for item in official if item["valid"]]
|
| 268 |
+
correct = sum(item["correct"] is True for item in official)
|
| 269 |
+
cohorts[name] = {
|
| 270 |
+
"n": len(official), "correct": correct,
|
| 271 |
+
"invalid": len(official) - len(valid),
|
| 272 |
+
"accuracy": correct / len(official) if official else None,
|
| 273 |
+
"ece_10": ece_top_label([(max(item["probs"].values()), item["correct"])
|
| 274 |
+
for item in valid])["ece"] if valid else None,
|
| 275 |
+
}
|
| 276 |
+
print(f"{name}: {correct}/{len(official)}", flush=True)
|
| 277 |
+
total = sum(item["n"] for item in cohorts.values())
|
| 278 |
+
results.update(cohorts=cohorts, public_n=total,
|
| 279 |
+
public_correct=sum(item["correct"] for item in cohorts.values()),
|
| 280 |
+
public_accuracy=sum(item["correct"] for item in cohorts.values()) / total)
|
| 281 |
+
if args.mode in ("speed", "all"):
|
| 282 |
+
tasks = load_jsonl(str(root / "original.jsonl"))
|
| 283 |
+
rows, _ = prepare_rows(tasks)
|
| 284 |
+
results["speed"] = speed(model, tokenizer, rows, device, batch_size)
|
| 285 |
+
print(json.dumps({"p50_ms": results["speed"]["single_decision"]["p50_ms"],
|
| 286 |
+
"p95_ms": results["speed"]["single_decision"]["p95_ms"],
|
| 287 |
+
"decisions_per_second": results["speed"]["throughput"]["decisions_per_second"]},
|
| 288 |
+
indent=2), flush=True)
|
| 289 |
+
args.output.parent.mkdir(parents=True, exist_ok=True)
|
| 290 |
+
args.output.write_text(json.dumps(results, indent=2, allow_nan=False) + "\n", encoding="utf-8")
|
| 291 |
+
print(f"Saved {args.output.resolve()}", flush=True)
|
| 292 |
+
return results
|
| 293 |
+
|
| 294 |
+
|
| 295 |
+
if __name__ == "__main__":
|
| 296 |
+
main()
|
benchmarks/requirements.txt
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
torch==2.8.0
|
| 2 |
+
transformers==5.17.0
|
| 3 |
+
safetensors==0.8.0
|
| 4 |
+
numpy==1.26.4
|
| 5 |
+
huggingface_hub>=0.26.0
|
config.json
CHANGED
|
@@ -73,7 +73,7 @@
|
|
| 73 |
},
|
| 74 |
"serving": {
|
| 75 |
"max_context_tokens": 512,
|
| 76 |
-
"max_option_tokens":
|
| 77 |
}
|
| 78 |
},
|
| 79 |
"encoder_config": {
|
|
@@ -162,4 +162,4 @@
|
|
| 162 |
"method": "CE warmup -> live multiclass Brier + PCGrad",
|
| 163 |
"probability_contract": "softmax(logits.float())"
|
| 164 |
}
|
| 165 |
-
}
|
|
|
|
| 73 |
},
|
| 74 |
"serving": {
|
| 75 |
"max_context_tokens": 512,
|
| 76 |
+
"max_option_tokens": 128
|
| 77 |
}
|
| 78 |
},
|
| 79 |
"encoder_config": {
|
|
|
|
| 162 |
"method": "CE warmup -> live multiclass Brier + PCGrad",
|
| 163 |
"probability_contract": "softmax(logits.float())"
|
| 164 |
}
|
| 165 |
+
}
|
cpu-speed/README.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Pivot CPU speed
|
| 2 |
+
|
| 3 |
+
This folder is a CPU-only entry point to the standalone public JevBench runner. It downloads the exact measured Pivot checkpoint and the pinned official public JevBench source; no private account or token is needed for the public files.
|
| 4 |
+
|
| 5 |
+
From the model repository root on Windows PowerShell:
|
| 6 |
+
|
| 7 |
+
```powershell
|
| 8 |
+
py -m pip install -r benchmarks/requirements.txt
|
| 9 |
+
py cpu-speed/benchmark.py --threads 4 --batch-size 4 --output pivot_cpu_results.json
|
| 10 |
+
```
|
| 11 |
+
|
| 12 |
+
The run measures warm FP32 latency for 32 individual decisions and throughput over three sets of 64 decisions. It includes tokenization, inference, and scoring. It reports p50, p95, mean, decisions per second, thread count, hardware, pinned revisions, and the contract. To evaluate public accuracy too, run `py benchmarks/jevbench_public.py --device cpu --threads 4 --mode all`.
|
| 13 |
+
|
| 14 |
+
The published 4-thread Xeon result is p50 **797.6 ms**, p95 **1,089.0 ms**, and **3.77 decisions/s** at batch 4. Your CPU result will differ. GPU throughput used batch 32, so these throughput values are not a matched batch comparison. See [archived measurements](../evaluation/2026-09-24/).
|
cpu-speed/benchmark.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""CPU-only wrapper for the pinned public JevBench speed protocol."""
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
import sys
|
| 4 |
+
|
| 5 |
+
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "benchmarks"))
|
| 6 |
+
from jevbench_public import main
|
| 7 |
+
|
| 8 |
+
if __name__ == "__main__":
|
| 9 |
+
main([*sys.argv[1:], "--device", "cpu", "--mode", "speed"])
|
docs/BENCHMARK.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# JevBench public evaluation
|
| 2 |
+
|
| 3 |
+
## Exact identity
|
| 4 |
+
|
| 5 |
+
| Item | Pinned value |
|
| 6 |
+
|---|---|
|
| 7 |
+
| Model | `Q1z/Pivot` |
|
| 8 |
+
| Evaluated model commit | `14bf8c26bf344ebdf88e22a4b6152dc5f75f3578` |
|
| 9 |
+
| Official JevBench release | v1.4.1 |
|
| 10 |
+
| JevBench commit | `24b9b5c1609a7a9e8fa14f49e5985a836c9dc842` |
|
| 11 |
+
| Tasks | Public original, easy, hard; 72 + 48 + 111 |
|
| 12 |
+
| Precision | FP32 |
|
| 13 |
+
| Rendering | `CONTEXT:` prefix, rubric text where present, official label order |
|
| 14 |
+
| Limits | 512 context and 128 option tokens, right truncation |
|
| 15 |
+
|
| 16 |
+
Pivot encodes every context and candidate, scores the candidate set, then passes probabilities indexed by each official task's labels to JevBench's `score_task`. The candidate text is the task rubric description when available, otherwise a humanized label. The published public accuracy is 107 / 231 = **46.32%**. Use [the standalone script](../benchmarks/jevbench_public.py) to repeat the calculation. It checks out the pinned official source, refuses a modified benchmark checkout, and writes results including both revisions and the frozen input contract.
|
| 17 |
+
|
| 18 |
+
## Meaning of the score
|
| 19 |
+
|
| 20 |
+
The **official JevBench v1.4 composite score is unavailable**. Public tasks do not include the organizer-held sealed and judge components or an official cost input. The 46.32% figure is a measured public accuracy, not a held-out score, official composite, rank, or cost-adjusted value. No such missing numbers are estimated in the result files.
|
| 21 |
+
|
| 22 |
+
The scripts also measure **local** warm single-decision latency and batched throughput on the public original tasks. These timings include tokenization, model inference and scoring, and depend on CPU/GPU, batch size, software and load. They are not the benchmark's adjusted speed/cost metric.
|
| 23 |
+
|
| 24 |
+
The runtime serving option limit in this update is now 128, matching the frozen benchmark. This is a default inference setting change, while checkpoint weights and the original evaluated commit remain intact. The original measurements cannot automatically predict the speed of every serving input.
|
| 25 |
+
|
| 26 |
+
See [results and charts](../evaluation/2026-09-24/README.md) and [reproduction instructions](../benchmarks/README.md).
|
docs/INFERENCE.md
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Using Pivot
|
| 2 |
+
|
| 3 |
+
Pivot evaluates a **supplied set of options** for each context. It is a bidirectional encoder with a set scorer, so its answer is an index into your options, not generated text. Use 2–16 distinct candidate meanings for the structured native interface. A single plain `choose()` call accepts two or more options; large candidate lists cost more memory and time.
|
| 4 |
+
|
| 5 |
+
## Load once
|
| 6 |
+
|
| 7 |
+
```python
|
| 8 |
+
import torch
|
| 9 |
+
from transformers import AutoModel, AutoTokenizer
|
| 10 |
+
|
| 11 |
+
repo = "Q1z/Pivot"
|
| 12 |
+
tokenizer = AutoTokenizer.from_pretrained(repo, trust_remote_code=True)
|
| 13 |
+
model = AutoModel.from_pretrained(repo, trust_remote_code=True, dtype=torch.float32).eval()
|
| 14 |
+
```
|
| 15 |
+
|
| 16 |
+
This repository ships custom Transformers code. Inspect it before loading with `trust_remote_code=True` in a production environment. A CPU-only PyTorch build works. For CUDA, call `model.to("cuda")`. Keep the tokenizer and model loaded across requests.
|
| 17 |
+
|
| 18 |
+
## Plain choice
|
| 19 |
+
|
| 20 |
+
```python
|
| 21 |
+
context = "CONTEXT:\nA user requests a refund for an incorrect charge."
|
| 22 |
+
options = ["route to billing", "route to technical support", "route to sales"]
|
| 23 |
+
result = model.choose(tokenizer, context, options)
|
| 24 |
+
assert result["choice"] == options[result["index"]]
|
| 25 |
+
assert len(result["probs"]) == len(options)
|
| 26 |
+
```
|
| 27 |
+
|
| 28 |
+
The probability vector follows the original option order and sums to approximately one. Changing the option wording or adding an option changes the set being scored. The public benchmark uses the `CONTEXT:` prefix, a 512-token context limit and a 128-token option limit.
|
| 29 |
+
|
| 30 |
+
## Native structured choice
|
| 31 |
+
|
| 32 |
+
`decide_native()` accepts a nonempty context and 2–16 objects with unique `id` and distinct `text` values. Optional `kind: "abstain"` is allowed on at most one candidate. Machine IDs stay outside the option encoder.
|
| 33 |
+
|
| 34 |
+
```python
|
| 35 |
+
result = model.decide_native(
|
| 36 |
+
tokenizer,
|
| 37 |
+
"A customer disputes an invoice.",
|
| 38 |
+
[
|
| 39 |
+
{"id": "billing", "text": "route to billing"},
|
| 40 |
+
{"id": "technical", "text": "route to technical support"},
|
| 41 |
+
{"id": "unknown", "text": "none of the routes fits", "kind": "abstain"},
|
| 42 |
+
],
|
| 43 |
+
)
|
| 44 |
+
print(result["selected"]["id"], result["prob_vector"])
|
| 45 |
+
```
|
| 46 |
+
|
| 47 |
+
The abstain option competes with the other supplied options; it is not an independently calibrated refusal threshold.
|
| 48 |
+
|
| 49 |
+
## Several typed decisions
|
| 50 |
+
|
| 51 |
+
```python
|
| 52 |
+
result = model.decide(tokenizer, "Customer invoice disputed", [
|
| 53 |
+
{"id": "route", "primitive": "choice", "options": ["billing", "tech", "sales"]},
|
| 54 |
+
{"id": "approve", "primitive": "noul", "options": ["true", "false"]},
|
| 55 |
+
{"id": "severity", "primitive": "score", "options": ["0", "1", "2", "3"]},
|
| 56 |
+
])
|
| 57 |
+
```
|
| 58 |
+
|
| 59 |
+
The typed method scores each question in turn. The examples under [`serving/`](../serving/) show request and response shapes.
|
| 60 |
+
|
| 61 |
+
## Cache repeated candidates
|
| 62 |
+
|
| 63 |
+
For repeated contexts against an unchanged option set:
|
| 64 |
+
|
| 65 |
+
```python
|
| 66 |
+
options = ["billing support", "technical support", "sales"]
|
| 67 |
+
candidate_vectors = model.encode_candidates(tokenizer, options)
|
| 68 |
+
context_vector = model.encode_context(tokenizer, "Invoice is incorrect")
|
| 69 |
+
result = model.choose_cached(context_vector, candidate_vectors, options)
|
| 70 |
+
```
|
| 71 |
+
|
| 72 |
+
Cache embeddings only with the same model, tokenizer, precision and option text. This path can avoid repeated option encoding. Published speed measurements instead use the uncached end-to-end path. [Runnable examples](../examples/cached_candidates.py).
|
docs/PERFORMANCE.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Pivot performance
|
| 2 |
+
|
| 3 |
+
All figures here refer to checkpoint `14bf8c26bf344ebdf88e22a4b6152dc5f75f3578`, public JevBench v1.4.1 commit `24b9b5c1609a7a9e8fa14f49e5985a836c9dc842`, FP32 and the same frozen 512/128-token input contract.
|
| 4 |
+
|
| 5 |
+
## Accuracy on public tasks
|
| 6 |
+
|
| 7 |
+
| Tier | Correct | Tasks | Accuracy | Top-label ECE, 10 bins |
|
| 8 |
+
|---|---:|---:|---:|---:|
|
| 9 |
+
| Original | 27 | 72 | 37.50% | 0.5247 |
|
| 10 |
+
| Easy | 39 | 48 | 81.25% | 0.1139 |
|
| 11 |
+
| Hard | 41 | 111 | 36.94% | 0.3792 |
|
| 12 |
+
| **Total** | **107** | **231** | **46.32%** | — |
|
| 13 |
+
|
| 14 |
+

|
| 15 |
+
|
| 16 |
+
The official JevBench composite score is **unavailable** because the sealed and judge tasks and official cost input were not measured.
|
| 17 |
+
|
| 18 |
+
## Local speed
|
| 19 |
+
|
| 20 |
+
| Warm local FP32 measure | H200 GPU | Xeon CPU, 4 threads |
|
| 21 |
+
|---|---:|---:|
|
| 22 |
+
| Single decision p50, 32 measured | 15.7668 ms | 797.5558 ms |
|
| 23 |
+
| Single decision p95, 32 measured | 19.8708 ms | 1089.0266 ms |
|
| 24 |
+
| Single decision mean | 16.1614 ms | 770.7159 ms |
|
| 25 |
+
| Batch size for throughput | 32 | 4 |
|
| 26 |
+
| Throughput, median of 3 × 64 decisions | 545.2833 decisions/s | 3.7708 decisions/s |
|
| 27 |
+
|
| 28 |
+

|
| 29 |
+
|
| 30 |
+
The CPU p50 single-decision time is **50.6×** the H200 p50 for these two machines. CPU and GPU batch throughput used different batch sizes and should not be read as a same-batch comparison. The timings cover tokenizer + inference + scoring with 5 warmup singles and 2 warmup bulk passes. Reproduce them on your own hardware using the [CPU script](../cpu-speed/README.md) or [full public runner](../benchmarks/README.md).
|
| 31 |
+
|
| 32 |
+
Source: [full structured summary](../evaluation/2026-09-24/performance.json), [original public benchmark result](../evaluation/2026-09-24/jevbench_public.json), and [original CPU measurement](../evaluation/2026-09-24/cpu_speed.json).
|
docs/UPDATE_NOTES.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Model repository update — 2026-09-24
|
| 2 |
+
|
| 3 |
+
This upload replaces the short model card with a full model overview, measured public accuracy, CPU/GPU timing, usage methods and reproducibility links. It adds inference examples, a serving guide, a standalone public JevBench v1.4.1 runner, a CPU-specific entry point, a CPU notebook, two focused charts, a combined chart, and the exact results in JSON.
|
| 4 |
+
|
| 5 |
+
The `config.json` serving option limit changes from **64 to 128** tokens to align the default API with the measured evaluation input limit. The checkpoint and runtime source files are not modified. `manifest.json` is regenerated for every changed or new repository file; existing weight and runtime hashes are preserved.
|
| 6 |
+
|
| 7 |
+
The reported public accuracy is **107 / 231 = 46.32%** at the pinned model revision `14bf8c26bf344ebdf88e22a4b6152dc5f75f3578`. The official JevBench composite score is unavailable because the sealed/judge portion and cost input are not included. Local CPU and GPU speeds are measured at distinct batch sizes and are identified as such.
|
| 8 |
+
|
| 9 |
+
Upload the contents of this package to the **root** of `Q1z/Pivot`, replacing the names it contains. No delete operation is required. Model weight files, tokenizer files, and pre-existing serving request/response examples stay in the Hub repository.
|
evaluation/2026-09-24/README.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Evaluated checkpoint and measured results
|
| 2 |
+
|
| 3 |
+
Checkpoint: `14bf8c26bf344ebdf88e22a4b6152dc5f75f3578`. Official JevBench public tasks: v1.4.1, commit `24b9b5c1609a7a9e8fa14f49e5985a836c9dc842`.
|
| 4 |
+
|
| 5 |
+
- [`performance.json`](performance.json): compact accuracy, speed, hardware, revisions, and limitations.
|
| 6 |
+
- [`jevbench_public.json`](jevbench_public.json): original GPU public JevBench result with official per-task scoring.
|
| 7 |
+
- [`cpu_speed.json`](cpu_speed.json): original four-thread CPU timing result.
|
| 8 |
+
- [`performance_overview.png`](performance_overview.png): combined chart.
|
| 9 |
+
- [`accuracy.png`](accuracy.png): public task accuracy.
|
| 10 |
+
- [`latency_throughput.png`](latency_throughput.png): GPU and CPU speed.
|
| 11 |
+
|
| 12 |
+
Public accuracy: **107 / 231 = 46.32%**. Warm single-decision p50: **15.8 ms** on H200, **797.6 ms** on Xeon CPU. GPU throughput uses batch 32, CPU throughput batch 4. The official sealed JevBench composite score and cost metric were not measured.
|
| 13 |
+
|
| 14 |
+
This update changes the default serving option limit from 64 to 128, while the checkpoint and archived measurements remain anchored to the prior exact commit. See [the full protocol](../../docs/BENCHMARK.md).
|
evaluation/2026-09-24/accuracy.png
ADDED
|
evaluation/2026-09-24/cpu_speed.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"scope": "public original tasks; warm local inference including tokenization and scoring",
|
| 3 |
+
"device": "cpu",
|
| 4 |
+
"hardware": "x86_64",
|
| 5 |
+
"dtype": "float32",
|
| 6 |
+
"single_decision": {
|
| 7 |
+
"batch_size": 1,
|
| 8 |
+
"n": 32,
|
| 9 |
+
"p50_ms": 797.5558204999516,
|
| 10 |
+
"p95_ms": 1089.0265890000137,
|
| 11 |
+
"mean_ms": 770.7159108749977
|
| 12 |
+
},
|
| 13 |
+
"throughput": {
|
| 14 |
+
"batch_size": 4,
|
| 15 |
+
"decisions_per_repeat": 64,
|
| 16 |
+
"repeats": 3,
|
| 17 |
+
"decisions_per_second": 3.7708397043400965,
|
| 18 |
+
"repeat_seconds": [
|
| 19 |
+
16.58172093600001,
|
| 20 |
+
17.219981521999898,
|
| 21 |
+
16.97234701499997
|
| 22 |
+
]
|
| 23 |
+
},
|
| 24 |
+
"note": "Local warm FP32 timing; not official adjusted JevBench Speed. No cost estimate without a specified hardware price.",
|
| 25 |
+
"cpu_model": "Intel(R) Xeon(R) CPU @ 2.60GHz",
|
| 26 |
+
"cpu_threads": 4,
|
| 27 |
+
"logical_cpu_count": 4,
|
| 28 |
+
"model_revision": "14bf8c26bf344ebdf88e22a4b6152dc5f75f3578",
|
| 29 |
+
"benchmark_commit": "24b9b5c1609a7a9e8fa14f49e5985a836c9dc842",
|
| 30 |
+
"benchmark_release": "v1.4.1",
|
| 31 |
+
"contract": {
|
| 32 |
+
"context_arm": "context_header",
|
| 33 |
+
"option_arm": "original",
|
| 34 |
+
"context_tokens": 512,
|
| 35 |
+
"option_tokens": 128,
|
| 36 |
+
"truncation": "right"
|
| 37 |
+
},
|
| 38 |
+
"test_scope": "speed only; no accuracy or official composite score computed"
|
| 39 |
+
}
|
evaluation/2026-09-24/jevbench_public.json
ADDED
|
@@ -0,0 +1,585 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"benchmark_commit": "24b9b5c1609a7a9e8fa14f49e5985a836c9dc842",
|
| 3 |
+
"benchmark_release": "v1.4.1",
|
| 4 |
+
"scope": "public_subset_only",
|
| 5 |
+
"official_held_out": null,
|
| 6 |
+
"official_jevbench_score": null,
|
| 7 |
+
"public_accuracy": 0.46320346320346323,
|
| 8 |
+
"public_n": 231,
|
| 9 |
+
"speed": {
|
| 10 |
+
"scope": "public original tasks; warm local inference including tokenization and scoring",
|
| 11 |
+
"device": "cuda",
|
| 12 |
+
"hardware": "NVIDIA H200",
|
| 13 |
+
"dtype": "float32",
|
| 14 |
+
"single_decision": {
|
| 15 |
+
"batch_size": 1,
|
| 16 |
+
"n": 32,
|
| 17 |
+
"p50_ms": 15.766771499897914,
|
| 18 |
+
"p95_ms": 19.87079100013034,
|
| 19 |
+
"mean_ms": 16.16144687499599
|
| 20 |
+
},
|
| 21 |
+
"throughput": {
|
| 22 |
+
"batch_size": 32,
|
| 23 |
+
"decisions_per_repeat": 64,
|
| 24 |
+
"repeats": 3,
|
| 25 |
+
"decisions_per_second": 545.2832753857399,
|
| 26 |
+
"repeat_seconds": [
|
| 27 |
+
0.12318335300005856,
|
| 28 |
+
0.1173701870000059,
|
| 29 |
+
0.11606121599993457
|
| 30 |
+
]
|
| 31 |
+
},
|
| 32 |
+
"note": "Local warm FP32 timing; not official adjusted JevBench Speed. No cost estimate without a specified hardware price."
|
| 33 |
+
},
|
| 34 |
+
"contract": {
|
| 35 |
+
"context_arm": "context_header",
|
| 36 |
+
"option_arm": "original",
|
| 37 |
+
"context_tokens": 512,
|
| 38 |
+
"option_tokens": 128,
|
| 39 |
+
"truncation": "right",
|
| 40 |
+
"selection_arm": "option_len:128",
|
| 41 |
+
"dev_sample_macro_accuracy": 0.7741666666666666,
|
| 42 |
+
"dev_sample_macro_nll": 0.9652628596545907,
|
| 43 |
+
"verified_as_scored": true,
|
| 44 |
+
"run_id": "f9f472314d223516818433b6f731ed3a05c999bd0be412134ad671d5ddc7808c"
|
| 45 |
+
},
|
| 46 |
+
"cohorts": {
|
| 47 |
+
"original": {
|
| 48 |
+
"n_tasks_file": 72,
|
| 49 |
+
"n_scored": 72,
|
| 50 |
+
"official_public": {
|
| 51 |
+
"n": 72,
|
| 52 |
+
"correct": 27,
|
| 53 |
+
"invalid": 0,
|
| 54 |
+
"accuracy": 0.375,
|
| 55 |
+
"ece_10": 0.5247104664643605
|
| 56 |
+
},
|
| 57 |
+
"metrics": {
|
| 58 |
+
"macro_accuracy": 0.375,
|
| 59 |
+
"macro_nll": 5.007958399361118,
|
| 60 |
+
"micro": {
|
| 61 |
+
"n": 72,
|
| 62 |
+
"accuracy": 0.375,
|
| 63 |
+
"brier_mean": 0.30594551421877425,
|
| 64 |
+
"brier_sum": 1.1185596241362858,
|
| 65 |
+
"ece_15": 0.5325825545522902,
|
| 66 |
+
"nll": 5.007958399361118,
|
| 67 |
+
"entropy": 0.23031783027727182,
|
| 68 |
+
"margin": 4.621087094148,
|
| 69 |
+
"predicted_positions": {
|
| 70 |
+
"0": 23,
|
| 71 |
+
"1": 19,
|
| 72 |
+
"3": 14,
|
| 73 |
+
"4": 2,
|
| 74 |
+
"2": 14
|
| 75 |
+
},
|
| 76 |
+
"gold_positions": {
|
| 77 |
+
"0": 24,
|
| 78 |
+
"1": 20,
|
| 79 |
+
"2": 12,
|
| 80 |
+
"3": 10,
|
| 81 |
+
"4": 4,
|
| 82 |
+
"5": 2
|
| 83 |
+
}
|
| 84 |
+
},
|
| 85 |
+
"by_family": {
|
| 86 |
+
"adequacy": {
|
| 87 |
+
"n": 12,
|
| 88 |
+
"accuracy": 0.3333333333333333,
|
| 89 |
+
"brier_mean": 0.6032912907957645,
|
| 90 |
+
"brier_sum": 1.206582581591529,
|
| 91 |
+
"ece_15": 0.674643059571584,
|
| 92 |
+
"nll": 2.811368828710537,
|
| 93 |
+
"entropy": 0.35683153857926314,
|
| 94 |
+
"margin": 2.7182071606318154,
|
| 95 |
+
"predicted_positions": {
|
| 96 |
+
"1": 8,
|
| 97 |
+
"0": 4
|
| 98 |
+
},
|
| 99 |
+
"gold_positions": {
|
| 100 |
+
"1": 6,
|
| 101 |
+
"0": 6
|
| 102 |
+
}
|
| 103 |
+
},
|
| 104 |
+
"extraction": {
|
| 105 |
+
"n": 12,
|
| 106 |
+
"accuracy": 0.16666666666666666,
|
| 107 |
+
"brier_mean": 0.33462631759767253,
|
| 108 |
+
"brier_sum": 1.3385052703906901,
|
| 109 |
+
"ece_15": 0.7197072158257167,
|
| 110 |
+
"nll": 5.611249398437437,
|
| 111 |
+
"entropy": 0.25773084664473744,
|
| 112 |
+
"margin": 3.4950687090555825,
|
| 113 |
+
"predicted_positions": {
|
| 114 |
+
"0": 9,
|
| 115 |
+
"1": 3
|
| 116 |
+
},
|
| 117 |
+
"gold_positions": {
|
| 118 |
+
"1": 2,
|
| 119 |
+
"3": 4,
|
| 120 |
+
"0": 4,
|
| 121 |
+
"2": 2
|
| 122 |
+
}
|
| 123 |
+
},
|
| 124 |
+
"intent": {
|
| 125 |
+
"n": 12,
|
| 126 |
+
"accuracy": 0.5,
|
| 127 |
+
"brier_mean": 0.193049684303942,
|
| 128 |
+
"brier_sum": 0.9652484215197101,
|
| 129 |
+
"ece_15": 0.49123724798361457,
|
| 130 |
+
"nll": 6.693062391390858,
|
| 131 |
+
"entropy": 0.16276790362346089,
|
| 132 |
+
"margin": 5.134465376536052,
|
| 133 |
+
"predicted_positions": {
|
| 134 |
+
"1": 4,
|
| 135 |
+
"3": 4,
|
| 136 |
+
"4": 2,
|
| 137 |
+
"0": 2
|
| 138 |
+
},
|
| 139 |
+
"gold_positions": {
|
| 140 |
+
"1": 2,
|
| 141 |
+
"2": 4,
|
| 142 |
+
"3": 2,
|
| 143 |
+
"0": 2,
|
| 144 |
+
"4": 2
|
| 145 |
+
}
|
| 146 |
+
},
|
| 147 |
+
"ordinal": {
|
| 148 |
+
"n": 12,
|
| 149 |
+
"accuracy": 0.25,
|
| 150 |
+
"brier_mean": 0.3469416665898746,
|
| 151 |
+
"brier_sum": 1.3877666663594983,
|
| 152 |
+
"ece_15": 0.7055613746245701,
|
| 153 |
+
"nll": 5.438651597684344,
|
| 154 |
+
"entropy": 0.1746427791074148,
|
| 155 |
+
"margin": 5.965866764386495,
|
| 156 |
+
"predicted_positions": {
|
| 157 |
+
"3": 10,
|
| 158 |
+
"2": 2
|
| 159 |
+
},
|
| 160 |
+
"gold_positions": {
|
| 161 |
+
"0": 4,
|
| 162 |
+
"1": 2,
|
| 163 |
+
"2": 4,
|
| 164 |
+
"3": 2
|
| 165 |
+
}
|
| 166 |
+
},
|
| 167 |
+
"policy": {
|
| 168 |
+
"n": 12,
|
| 169 |
+
"accuracy": 0.8333333333333334,
|
| 170 |
+
"brier_mean": 0.08333248779901603,
|
| 171 |
+
"brier_sum": 0.16666497559803206,
|
| 172 |
+
"ece_15": 0.16530502339204153,
|
| 173 |
+
"nll": 0.2814556436290131,
|
| 174 |
+
"entropy": 0.40680371489783257,
|
| 175 |
+
"margin": 1.9209110339482625,
|
| 176 |
+
"predicted_positions": {
|
| 177 |
+
"0": 8,
|
| 178 |
+
"1": 4
|
| 179 |
+
},
|
| 180 |
+
"gold_positions": {
|
| 181 |
+
"0": 6,
|
| 182 |
+
"1": 6
|
| 183 |
+
}
|
| 184 |
+
},
|
| 185 |
+
"routing": {
|
| 186 |
+
"n": 12,
|
| 187 |
+
"accuracy": 0.16666666666666666,
|
| 188 |
+
"brier_mean": 0.27443163822637595,
|
| 189 |
+
"brier_sum": 1.6465898293582557,
|
| 190 |
+
"ece_15": 0.8280483782291412,
|
| 191 |
+
"nll": 9.211962536314518,
|
| 192 |
+
"entropy": 0.023130198810922015,
|
| 193 |
+
"margin": 8.492003520329794,
|
| 194 |
+
"predicted_positions": {
|
| 195 |
+
"2": 12
|
| 196 |
+
},
|
| 197 |
+
"gold_positions": {
|
| 198 |
+
"0": 2,
|
| 199 |
+
"1": 2,
|
| 200 |
+
"2": 2,
|
| 201 |
+
"3": 2,
|
| 202 |
+
"4": 2,
|
| 203 |
+
"5": 2
|
| 204 |
+
}
|
| 205 |
+
}
|
| 206 |
+
}
|
| 207 |
+
}
|
| 208 |
+
},
|
| 209 |
+
"easy": {
|
| 210 |
+
"n_tasks_file": 48,
|
| 211 |
+
"n_scored": 48,
|
| 212 |
+
"official_public": {
|
| 213 |
+
"n": 48,
|
| 214 |
+
"correct": 39,
|
| 215 |
+
"invalid": 0,
|
| 216 |
+
"accuracy": 0.8125,
|
| 217 |
+
"ece_10": 0.1139311231672764
|
| 218 |
+
},
|
| 219 |
+
"metrics": {
|
| 220 |
+
"macro_accuracy": 0.8125,
|
| 221 |
+
"macro_nll": 1.0037392714069566,
|
| 222 |
+
"micro": {
|
| 223 |
+
"n": 48,
|
| 224 |
+
"accuracy": 0.8125,
|
| 225 |
+
"brier_mean": 0.08969436292922732,
|
| 226 |
+
"brier_sum": 0.3277746810853164,
|
| 227 |
+
"ece_15": 0.17484351620078087,
|
| 228 |
+
"nll": 1.0037392714069566,
|
| 229 |
+
"entropy": 0.27674493139652984,
|
| 230 |
+
"margin": 5.322023505965869,
|
| 231 |
+
"predicted_positions": {
|
| 232 |
+
"0": 13,
|
| 233 |
+
"1": 16,
|
| 234 |
+
"2": 9,
|
| 235 |
+
"3": 7,
|
| 236 |
+
"4": 3
|
| 237 |
+
},
|
| 238 |
+
"gold_positions": {
|
| 239 |
+
"0": 15,
|
| 240 |
+
"1": 12,
|
| 241 |
+
"2": 8,
|
| 242 |
+
"3": 8,
|
| 243 |
+
"4": 5
|
| 244 |
+
}
|
| 245 |
+
},
|
| 246 |
+
"by_family": {
|
| 247 |
+
"extraction": {
|
| 248 |
+
"n": 12,
|
| 249 |
+
"accuracy": 0.5,
|
| 250 |
+
"brier_mean": 0.20218808597619678,
|
| 251 |
+
"brier_sum": 0.8518348596262159,
|
| 252 |
+
"ece_15": 0.4715841561555862,
|
| 253 |
+
"nll": 3.1491165426466026,
|
| 254 |
+
"entropy": 0.32298662421478147,
|
| 255 |
+
"margin": 3.7243812878926597,
|
| 256 |
+
"predicted_positions": {
|
| 257 |
+
"1": 3,
|
| 258 |
+
"2": 3,
|
| 259 |
+
"3": 3,
|
| 260 |
+
"0": 3
|
| 261 |
+
},
|
| 262 |
+
"gold_positions": {
|
| 263 |
+
"1": 2,
|
| 264 |
+
"3": 4,
|
| 265 |
+
"2": 2,
|
| 266 |
+
"0": 3,
|
| 267 |
+
"4": 1
|
| 268 |
+
}
|
| 269 |
+
},
|
| 270 |
+
"fact": {
|
| 271 |
+
"n": 12,
|
| 272 |
+
"accuracy": 0.8333333333333334,
|
| 273 |
+
"brier_mean": 0.10789432132950423,
|
| 274 |
+
"brier_sum": 0.21578864265900846,
|
| 275 |
+
"ece_15": 0.21092924475669866,
|
| 276 |
+
"nll": 0.3680396559776326,
|
| 277 |
+
"entropy": 0.5416488102436233,
|
| 278 |
+
"margin": 1.0842649737993877,
|
| 279 |
+
"predicted_positions": {
|
| 280 |
+
"1": 8,
|
| 281 |
+
"0": 4
|
| 282 |
+
},
|
| 283 |
+
"gold_positions": {
|
| 284 |
+
"1": 6,
|
| 285 |
+
"0": 6
|
| 286 |
+
}
|
| 287 |
+
},
|
| 288 |
+
"intent": {
|
| 289 |
+
"n": 12,
|
| 290 |
+
"accuracy": 0.9166666666666666,
|
| 291 |
+
"brier_mean": 0.04868382763629129,
|
| 292 |
+
"brier_sum": 0.24341913818145647,
|
| 293 |
+
"ece_15": 0.18598496417204538,
|
| 294 |
+
"nll": 0.49580653492545496,
|
| 295 |
+
"entropy": 0.23149866629527152,
|
| 296 |
+
"margin": 5.446817874908447,
|
| 297 |
+
"predicted_positions": {
|
| 298 |
+
"0": 4,
|
| 299 |
+
"1": 3,
|
| 300 |
+
"2": 2,
|
| 301 |
+
"3": 2,
|
| 302 |
+
"4": 1
|
| 303 |
+
},
|
| 304 |
+
"gold_positions": {
|
| 305 |
+
"0": 4,
|
| 306 |
+
"1": 2,
|
| 307 |
+
"2": 2,
|
| 308 |
+
"3": 2,
|
| 309 |
+
"4": 2
|
| 310 |
+
}
|
| 311 |
+
},
|
| 312 |
+
"tool_selection": {
|
| 313 |
+
"n": 12,
|
| 314 |
+
"accuracy": 1.0,
|
| 315 |
+
"brier_mean": 1.1216774916947182e-05,
|
| 316 |
+
"brier_sum": 5.6083874584735916e-05,
|
| 317 |
+
"ece_15": 0.0019801706075668335,
|
| 318 |
+
"nll": 0.0019943520781363655,
|
| 319 |
+
"entropy": 0.010845624832442837,
|
| 320 |
+
"margin": 11.03262988726298,
|
| 321 |
+
"predicted_positions": {
|
| 322 |
+
"0": 2,
|
| 323 |
+
"1": 2,
|
| 324 |
+
"2": 4,
|
| 325 |
+
"3": 2,
|
| 326 |
+
"4": 2
|
| 327 |
+
},
|
| 328 |
+
"gold_positions": {
|
| 329 |
+
"0": 2,
|
| 330 |
+
"1": 2,
|
| 331 |
+
"2": 4,
|
| 332 |
+
"3": 2,
|
| 333 |
+
"4": 2
|
| 334 |
+
}
|
| 335 |
+
}
|
| 336 |
+
}
|
| 337 |
+
}
|
| 338 |
+
},
|
| 339 |
+
"hard": {
|
| 340 |
+
"n_tasks_file": 111,
|
| 341 |
+
"n_scored": 111,
|
| 342 |
+
"official_public": {
|
| 343 |
+
"n": 111,
|
| 344 |
+
"correct": 41,
|
| 345 |
+
"invalid": 0,
|
| 346 |
+
"accuracy": 0.36936936936936937,
|
| 347 |
+
"ece_10": 0.3791593909263611
|
| 348 |
+
},
|
| 349 |
+
"metrics": {
|
| 350 |
+
"macro_accuracy": 0.38833493046341344,
|
| 351 |
+
"macro_nll": 2.1149551345876114,
|
| 352 |
+
"micro": {
|
| 353 |
+
"n": 111,
|
| 354 |
+
"accuracy": 0.36936936936936937,
|
| 355 |
+
"brier_mean": 0.3142712859450615,
|
| 356 |
+
"brier_sum": 0.951039241082317,
|
| 357 |
+
"ece_15": 0.37663869814829787,
|
| 358 |
+
"nll": 2.2420954526317662,
|
| 359 |
+
"entropy": 0.6359462567449854,
|
| 360 |
+
"margin": 1.9191036170667357,
|
| 361 |
+
"predicted_positions": {
|
| 362 |
+
"4": 5,
|
| 363 |
+
"3": 11,
|
| 364 |
+
"1": 50,
|
| 365 |
+
"0": 34,
|
| 366 |
+
"2": 11
|
| 367 |
+
},
|
| 368 |
+
"gold_positions": {
|
| 369 |
+
"3": 12,
|
| 370 |
+
"1": 46,
|
| 371 |
+
"2": 20,
|
| 372 |
+
"0": 31,
|
| 373 |
+
"4": 2
|
| 374 |
+
}
|
| 375 |
+
},
|
| 376 |
+
"by_family": {
|
| 377 |
+
"adversarial": {
|
| 378 |
+
"n": 6,
|
| 379 |
+
"accuracy": 0.3333333333333333,
|
| 380 |
+
"brier_mean": 0.329005561541213,
|
| 381 |
+
"brier_sum": 1.0360720430251906,
|
| 382 |
+
"ece_15": 0.6766607860724131,
|
| 383 |
+
"nll": 2.9314609134083995,
|
| 384 |
+
"entropy": 0.524170048996028,
|
| 385 |
+
"margin": 1.9538231293360393,
|
| 386 |
+
"predicted_positions": {
|
| 387 |
+
"0": 3,
|
| 388 |
+
"1": 2,
|
| 389 |
+
"2": 1
|
| 390 |
+
},
|
| 391 |
+
"gold_positions": {
|
| 392 |
+
"1": 2,
|
| 393 |
+
"0": 3,
|
| 394 |
+
"2": 1
|
| 395 |
+
}
|
| 396 |
+
},
|
| 397 |
+
"ambiguous": {
|
| 398 |
+
"n": 7,
|
| 399 |
+
"accuracy": 0.2857142857142857,
|
| 400 |
+
"brier_mean": 0.35496685184985993,
|
| 401 |
+
"brier_sum": 1.1069028860902297,
|
| 402 |
+
"ece_15": 0.523924435888018,
|
| 403 |
+
"nll": 2.373063987899727,
|
| 404 |
+
"entropy": 0.601728218515645,
|
| 405 |
+
"margin": 1.9064587184361048,
|
| 406 |
+
"predicted_positions": {
|
| 407 |
+
"2": 2,
|
| 408 |
+
"1": 3,
|
| 409 |
+
"0": 2
|
| 410 |
+
},
|
| 411 |
+
"gold_positions": {
|
| 412 |
+
"1": 2,
|
| 413 |
+
"0": 4,
|
| 414 |
+
"2": 1
|
| 415 |
+
}
|
| 416 |
+
},
|
| 417 |
+
"judge_hard": {
|
| 418 |
+
"n": 17,
|
| 419 |
+
"accuracy": 0.47058823529411764,
|
| 420 |
+
"brier_mean": 0.4486379756320042,
|
| 421 |
+
"brier_sum": 0.8972759512640084,
|
| 422 |
+
"ece_15": 0.48566271978266107,
|
| 423 |
+
"nll": 2.037071307444988,
|
| 424 |
+
"entropy": 0.3662706503467713,
|
| 425 |
+
"margin": 2.5419286559609806,
|
| 426 |
+
"predicted_positions": {
|
| 427 |
+
"1": 12,
|
| 428 |
+
"0": 5
|
| 429 |
+
},
|
| 430 |
+
"gold_positions": {
|
| 431 |
+
"1": 7,
|
| 432 |
+
"0": 10
|
| 433 |
+
}
|
| 434 |
+
},
|
| 435 |
+
"long_policy": {
|
| 436 |
+
"n": 19,
|
| 437 |
+
"accuracy": 0.2631578947368421,
|
| 438 |
+
"brier_mean": 0.27236642425885704,
|
| 439 |
+
"brier_sum": 0.9291074031175274,
|
| 440 |
+
"ece_15": 0.5016953207944569,
|
| 441 |
+
"nll": 2.2953665892409245,
|
| 442 |
+
"entropy": 0.8144000351229689,
|
| 443 |
+
"margin": 1.7862926752943742,
|
| 444 |
+
"predicted_positions": {
|
| 445 |
+
"4": 2,
|
| 446 |
+
"3": 4,
|
| 447 |
+
"1": 8,
|
| 448 |
+
"0": 3,
|
| 449 |
+
"2": 2
|
| 450 |
+
},
|
| 451 |
+
"gold_positions": {
|
| 452 |
+
"3": 4,
|
| 453 |
+
"1": 9,
|
| 454 |
+
"2": 3,
|
| 455 |
+
"0": 2,
|
| 456 |
+
"4": 1
|
| 457 |
+
}
|
| 458 |
+
},
|
| 459 |
+
"multi_hop": {
|
| 460 |
+
"n": 18,
|
| 461 |
+
"accuracy": 0.3888888888888889,
|
| 462 |
+
"brier_mean": 0.2834510893430854,
|
| 463 |
+
"brier_sum": 1.0717193129324514,
|
| 464 |
+
"ece_15": 0.5134819232755237,
|
| 465 |
+
"nll": 2.763476913613433,
|
| 466 |
+
"entropy": 0.5936464927522234,
|
| 467 |
+
"margin": 2.359899971220228,
|
| 468 |
+
"predicted_positions": {
|
| 469 |
+
"3": 7,
|
| 470 |
+
"0": 7,
|
| 471 |
+
"2": 2,
|
| 472 |
+
"1": 2
|
| 473 |
+
},
|
| 474 |
+
"gold_positions": {
|
| 475 |
+
"2": 7,
|
| 476 |
+
"0": 2,
|
| 477 |
+
"1": 4,
|
| 478 |
+
"3": 5
|
| 479 |
+
}
|
| 480 |
+
},
|
| 481 |
+
"probability": {
|
| 482 |
+
"n": 10,
|
| 483 |
+
"accuracy": 0.1,
|
| 484 |
+
"brier_mean": 0.4951685533837183,
|
| 485 |
+
"brier_sum": 1.3519257679233312,
|
| 486 |
+
"ece_15": 0.7558035969734191,
|
| 487 |
+
"nll": 3.180345622394031,
|
| 488 |
+
"entropy": 0.4637652637685445,
|
| 489 |
+
"margin": 2.383845841884613,
|
| 490 |
+
"predicted_positions": {
|
| 491 |
+
"1": 4,
|
| 492 |
+
"0": 4,
|
| 493 |
+
"2": 2
|
| 494 |
+
},
|
| 495 |
+
"gold_positions": {
|
| 496 |
+
"1": 6,
|
| 497 |
+
"0": 1,
|
| 498 |
+
"2": 3
|
| 499 |
+
}
|
| 500 |
+
},
|
| 501 |
+
"routing_hard": {
|
| 502 |
+
"n": 5,
|
| 503 |
+
"accuracy": 0.6,
|
| 504 |
+
"brier_mean": 0.09874917209342585,
|
| 505 |
+
"brier_sum": 0.4937458604671292,
|
| 506 |
+
"ece_15": 0.3892843127250671,
|
| 507 |
+
"nll": 0.7523306657503555,
|
| 508 |
+
"entropy": 0.7205350702007266,
|
| 509 |
+
"margin": 1.654204750061035,
|
| 510 |
+
"predicted_positions": {
|
| 511 |
+
"1": 3,
|
| 512 |
+
"0": 2
|
| 513 |
+
},
|
| 514 |
+
"gold_positions": {
|
| 515 |
+
"1": 5
|
| 516 |
+
}
|
| 517 |
+
},
|
| 518 |
+
"temporal_numeric": {
|
| 519 |
+
"n": 15,
|
| 520 |
+
"accuracy": 0.4,
|
| 521 |
+
"brier_mean": 0.22509232850928135,
|
| 522 |
+
"brier_sum": 0.8210278367875746,
|
| 523 |
+
"ece_15": 0.266293736298879,
|
| 524 |
+
"nll": 1.984593750841293,
|
| 525 |
+
"entropy": 0.95446657543888,
|
| 526 |
+
"margin": 1.2332109769185384,
|
| 527 |
+
"predicted_positions": {
|
| 528 |
+
"1": 8,
|
| 529 |
+
"0": 3,
|
| 530 |
+
"2": 2,
|
| 531 |
+
"4": 2
|
| 532 |
+
},
|
| 533 |
+
"gold_positions": {
|
| 534 |
+
"1": 5,
|
| 535 |
+
"0": 4,
|
| 536 |
+
"2": 3,
|
| 537 |
+
"3": 3
|
| 538 |
+
}
|
| 539 |
+
},
|
| 540 |
+
"tradeoff": {
|
| 541 |
+
"n": 6,
|
| 542 |
+
"accuracy": 0.6666666666666666,
|
| 543 |
+
"brier_mean": 0.11440804834587807,
|
| 544 |
+
"brier_sum": 0.395298481023521,
|
| 545 |
+
"ece_15": 0.3396676282087962,
|
| 546 |
+
"nll": 0.6505642991908996,
|
| 547 |
+
"entropy": 0.5314685338007524,
|
| 548 |
+
"margin": 1.6512227058410645,
|
| 549 |
+
"predicted_positions": {
|
| 550 |
+
"0": 2,
|
| 551 |
+
"1": 3,
|
| 552 |
+
"4": 1
|
| 553 |
+
},
|
| 554 |
+
"gold_positions": {
|
| 555 |
+
"2": 1,
|
| 556 |
+
"1": 4,
|
| 557 |
+
"4": 1
|
| 558 |
+
}
|
| 559 |
+
},
|
| 560 |
+
"trap": {
|
| 561 |
+
"n": 8,
|
| 562 |
+
"accuracy": 0.375,
|
| 563 |
+
"brier_mean": 0.37663994260610417,
|
| 564 |
+
"brier_sum": 1.0909660520406792,
|
| 565 |
+
"ece_15": 0.685746856033802,
|
| 566 |
+
"nll": 2.1812772960920648,
|
| 567 |
+
"entropy": 0.6376175324074207,
|
| 568 |
+
"margin": 0.9758526459336281,
|
| 569 |
+
"predicted_positions": {
|
| 570 |
+
"1": 5,
|
| 571 |
+
"0": 3
|
| 572 |
+
},
|
| 573 |
+
"gold_positions": {
|
| 574 |
+
"0": 5,
|
| 575 |
+
"1": 2,
|
| 576 |
+
"2": 1
|
| 577 |
+
}
|
| 578 |
+
}
|
| 579 |
+
}
|
| 580 |
+
}
|
| 581 |
+
}
|
| 582 |
+
},
|
| 583 |
+
"note": "The public-only result is not an official JevBench v1.4 score. Sealed and judge tasks are unavailable; cost is not measured.",
|
| 584 |
+
"run_id": "f9f472314d223516818433b6f731ed3a05c999bd0be412134ad671d5ddc7808c"
|
| 585 |
+
}
|
evaluation/2026-09-24/latency_throughput.png
ADDED
|
evaluation/2026-09-24/performance.json
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"model": "Q1z/Pivot",
|
| 3 |
+
"model_revision": "14bf8c26bf344ebdf88e22a4b6152dc5f75f3578",
|
| 4 |
+
"benchmark": {
|
| 5 |
+
"name": "JevBench",
|
| 6 |
+
"release": "v1.4.1",
|
| 7 |
+
"commit": "24b9b5c1609a7a9e8fa14f49e5985a836c9dc842",
|
| 8 |
+
"scope": "public tasks only",
|
| 9 |
+
"official_v1_4_score": null,
|
| 10 |
+
"public_accuracy": 0.46320346320346323,
|
| 11 |
+
"public_correct": 107,
|
| 12 |
+
"public_n": 231,
|
| 13 |
+
"cohorts": {
|
| 14 |
+
"original": {
|
| 15 |
+
"n": 72,
|
| 16 |
+
"accuracy": 0.375,
|
| 17 |
+
"ece_10": 0.5247104664643605,
|
| 18 |
+
"invalid": 0
|
| 19 |
+
},
|
| 20 |
+
"easy": {
|
| 21 |
+
"n": 48,
|
| 22 |
+
"accuracy": 0.8125,
|
| 23 |
+
"ece_10": 0.1139311231672764,
|
| 24 |
+
"invalid": 0
|
| 25 |
+
},
|
| 26 |
+
"hard": {
|
| 27 |
+
"n": 111,
|
| 28 |
+
"accuracy": 0.36936936936936937,
|
| 29 |
+
"ece_10": 0.3791593909263611,
|
| 30 |
+
"invalid": 0
|
| 31 |
+
}
|
| 32 |
+
},
|
| 33 |
+
"input_contract": {
|
| 34 |
+
"context_arm": "context_header",
|
| 35 |
+
"option_arm": "original",
|
| 36 |
+
"context_tokens": 512,
|
| 37 |
+
"option_tokens": 128,
|
| 38 |
+
"truncation": "right"
|
| 39 |
+
}
|
| 40 |
+
},
|
| 41 |
+
"speed": {
|
| 42 |
+
"precision": "float32",
|
| 43 |
+
"measurement": "warm local end-to-end; includes tokenization, inference, and scoring",
|
| 44 |
+
"h200": {
|
| 45 |
+
"hardware": "NVIDIA H200",
|
| 46 |
+
"single_decision": {
|
| 47 |
+
"batch_size": 1,
|
| 48 |
+
"n": 32,
|
| 49 |
+
"p50_ms": 15.766771499897914,
|
| 50 |
+
"p95_ms": 19.87079100013034,
|
| 51 |
+
"mean_ms": 16.16144687499599
|
| 52 |
+
},
|
| 53 |
+
"throughput": {
|
| 54 |
+
"batch_size": 32,
|
| 55 |
+
"decisions_per_repeat": 64,
|
| 56 |
+
"repeats": 3,
|
| 57 |
+
"decisions_per_second": 545.2832753857399,
|
| 58 |
+
"repeat_seconds": [
|
| 59 |
+
0.12318335300005856,
|
| 60 |
+
0.1173701870000059,
|
| 61 |
+
0.11606121599993457
|
| 62 |
+
]
|
| 63 |
+
}
|
| 64 |
+
},
|
| 65 |
+
"cpu": {
|
| 66 |
+
"hardware": "Intel(R) Xeon(R) CPU @ 2.60GHz",
|
| 67 |
+
"threads": 4,
|
| 68 |
+
"single_decision": {
|
| 69 |
+
"batch_size": 1,
|
| 70 |
+
"n": 32,
|
| 71 |
+
"p50_ms": 797.5558204999516,
|
| 72 |
+
"p95_ms": 1089.0265890000137,
|
| 73 |
+
"mean_ms": 770.7159108749977
|
| 74 |
+
},
|
| 75 |
+
"throughput": {
|
| 76 |
+
"batch_size": 4,
|
| 77 |
+
"decisions_per_repeat": 64,
|
| 78 |
+
"repeats": 3,
|
| 79 |
+
"decisions_per_second": 3.7708397043400965,
|
| 80 |
+
"repeat_seconds": [
|
| 81 |
+
16.58172093600001,
|
| 82 |
+
17.219981521999898,
|
| 83 |
+
16.97234701499997
|
| 84 |
+
]
|
| 85 |
+
}
|
| 86 |
+
}
|
| 87 |
+
},
|
| 88 |
+
"comparison": {
|
| 89 |
+
"cpu_to_h200_single_decision_p50_ratio": 50.584599421962544,
|
| 90 |
+
"throughput_batches_differ": true
|
| 91 |
+
},
|
| 92 |
+
"limits": {
|
| 93 |
+
"official_score": "Requires organizer-held sealed evaluation and cost; not available from public tasks.",
|
| 94 |
+
"latency": "These are local timings on specific machines. Batch 32 GPU and batch 4 CPU throughput should not be compared as equal configurations."
|
| 95 |
+
}
|
| 96 |
+
}
|
evaluation/2026-09-24/performance_overview.png
ADDED
|
Git LFS Details
|
evaluation/render_charts.py
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Render the published charts from evaluation/2026-09-24/performance.json.
|
| 2 |
+
|
| 3 |
+
Usage: python evaluation/render_charts.py
|
| 4 |
+
"""
|
| 5 |
+
import json
|
| 6 |
+
from pathlib import Path
|
| 7 |
+
|
| 8 |
+
import matplotlib
|
| 9 |
+
matplotlib.use("Agg")
|
| 10 |
+
import matplotlib.pyplot as plt
|
| 11 |
+
import numpy as np
|
| 12 |
+
|
| 13 |
+
RESULTS = Path(__file__).resolve().parent / "2026-09-24"
|
| 14 |
+
data = json.loads((RESULTS / "performance.json").read_text(encoding="utf-8"))
|
| 15 |
+
bench, speed = data["benchmark"], data["speed"]
|
| 16 |
+
cohorts = bench["cohorts"]
|
| 17 |
+
names = list(cohorts)
|
| 18 |
+
accuracies = [100 * cohorts[name]["accuracy"] for name in names]
|
| 19 |
+
ece = [cohorts[name]["ece_10"] for name in names]
|
| 20 |
+
palette = ["#2a58d7", "#129184", "#dc8240"]
|
| 21 |
+
|
| 22 |
+
plt.rcParams.update({
|
| 23 |
+
"font.family": "DejaVu Sans", "font.size": 11, "axes.spines.top": False,
|
| 24 |
+
"axes.spines.right": False, "axes.edgecolor": "#c8d3e4",
|
| 25 |
+
"axes.facecolor": "#f5f7fb", "text.color": "#182640",
|
| 26 |
+
})
|
| 27 |
+
|
| 28 |
+
def public_chart(ax):
|
| 29 |
+
bars = ax.barh(names[::-1], accuracies[::-1], color=palette[::-1], height=.58)
|
| 30 |
+
ax.set_xlim(0, 105)
|
| 31 |
+
ax.set_xlabel("Accuracy (%)")
|
| 32 |
+
ax.set_title("JevBench v1.4.1 public tasks", loc="left", fontweight="bold")
|
| 33 |
+
for bar, name, value in zip(bars, names[::-1], accuracies[::-1]):
|
| 34 |
+
ax.text(value + 2, bar.get_y() + bar.get_height() / 2,
|
| 35 |
+
f"{value:.2f}% (n={cohorts[name]['n']})", va="center", fontsize=10)
|
| 36 |
+
ax.text(.02, -.18, f"Total {bench['public_correct']} / {bench['public_n']} = {100*bench['public_accuracy']:.2f}%",
|
| 37 |
+
transform=ax.transAxes, fontweight="bold")
|
| 38 |
+
|
| 39 |
+
def latency_chart(ax):
|
| 40 |
+
x = np.arange(2)
|
| 41 |
+
p50 = [speed[key]["single_decision"]["p50_ms"] for key in ("h200", "cpu")]
|
| 42 |
+
p95 = [speed[key]["single_decision"]["p95_ms"] for key in ("h200", "cpu")]
|
| 43 |
+
ax.bar(x - .18, p50, .35, color=palette[0], label="p50")
|
| 44 |
+
ax.bar(x + .18, p95, .35, color=palette[2], label="p95")
|
| 45 |
+
ax.set_yscale("log")
|
| 46 |
+
ax.set_ylim(5, 2100)
|
| 47 |
+
ax.set_xticks(x, ["H200 GPU", "Xeon CPU"])
|
| 48 |
+
ax.set_ylabel("Milliseconds (log scale)")
|
| 49 |
+
ax.set_title("Warm single-decision latency", loc="left", fontweight="bold")
|
| 50 |
+
ax.legend(frameon=False)
|
| 51 |
+
for pos, values, offset in ((0, p50, -.18), (1, p95, .18)):
|
| 52 |
+
for index, value in enumerate(values):
|
| 53 |
+
ax.text(index + offset, value * 1.15, f"{value:.1f} ms", ha="center", fontsize=9)
|
| 54 |
+
|
| 55 |
+
def throughput_chart(ax):
|
| 56 |
+
values = [speed[key]["throughput"]["decisions_per_second"] for key in ("h200", "cpu")]
|
| 57 |
+
batches = [speed[key]["throughput"]["batch_size"] for key in ("h200", "cpu")]
|
| 58 |
+
ax.bar([f"H200\nbatch {batches[0]}", f"Xeon CPU\nbatch {batches[1]}"],
|
| 59 |
+
values, color=palette[:2], width=.58)
|
| 60 |
+
ax.set_yscale("log")
|
| 61 |
+
ax.set_ylim(1, 2000)
|
| 62 |
+
ax.set_ylabel("Decisions/s (log scale)")
|
| 63 |
+
ax.set_title("Warm batched throughput", loc="left", fontweight="bold")
|
| 64 |
+
for index, value in enumerate(values):
|
| 65 |
+
ax.text(index, value * 1.15, f"{value:.2f}/s", ha="center", fontsize=10)
|
| 66 |
+
|
| 67 |
+
fig, ax = plt.subplots(figsize=(8.2, 4.8), layout="constrained")
|
| 68 |
+
public_chart(ax)
|
| 69 |
+
fig.savefig(RESULTS / "accuracy.png", dpi=180)
|
| 70 |
+
plt.close(fig)
|
| 71 |
+
|
| 72 |
+
fig, axes = plt.subplots(1, 2, figsize=(11, 4.7), layout="constrained")
|
| 73 |
+
latency_chart(axes[0])
|
| 74 |
+
throughput_chart(axes[1])
|
| 75 |
+
fig.suptitle("Pivot | local FP32 inference", fontsize=16, fontweight="bold")
|
| 76 |
+
fig.savefig(RESULTS / "latency_throughput.png", dpi=180)
|
| 77 |
+
plt.close(fig)
|
| 78 |
+
|
| 79 |
+
fig, axes = plt.subplots(2, 2, figsize=(12.6, 8.8), layout="constrained")
|
| 80 |
+
public_chart(axes[0, 0])
|
| 81 |
+
axes[0, 1].barh(names[::-1], ece[::-1], color=palette[::-1], height=.58)
|
| 82 |
+
axes[0, 1].set_xlim(0, .68)
|
| 83 |
+
axes[0, 1].set_xlabel("ECE, 10 bins (lower is better)")
|
| 84 |
+
axes[0, 1].set_title("Public calibration", loc="left", fontweight="bold")
|
| 85 |
+
for index, value in enumerate(ece[::-1]):
|
| 86 |
+
axes[0, 1].text(value + .01, index, f"{value:.3f}", va="center")
|
| 87 |
+
latency_chart(axes[1, 0])
|
| 88 |
+
throughput_chart(axes[1, 1])
|
| 89 |
+
fig.suptitle("Pivot | measured public performance", fontsize=19, fontweight="bold")
|
| 90 |
+
fig.text(.02, -.015, "Pinned checkpoint | warm local tokenization + inference + scoring | throughput batch sizes differ",
|
| 91 |
+
fontsize=9, color="#53637b")
|
| 92 |
+
fig.savefig(RESULTS / "performance_overview.png", dpi=180, bbox_inches="tight")
|
| 93 |
+
plt.close(fig)
|
| 94 |
+
print(f"Saved charts in {RESULTS}")
|
examples/cached_candidates.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Reuse candidate embeddings across multiple calls with the same options."""
|
| 2 |
+
import torch
|
| 3 |
+
from transformers import AutoModel, AutoTokenizer
|
| 4 |
+
|
| 5 |
+
MODEL = "Q1z/Pivot"
|
| 6 |
+
tokenizer = AutoTokenizer.from_pretrained(MODEL, trust_remote_code=True)
|
| 7 |
+
model = AutoModel.from_pretrained(MODEL, trust_remote_code=True, dtype=torch.float32).eval()
|
| 8 |
+
|
| 9 |
+
options = [
|
| 10 |
+
"route to billing support",
|
| 11 |
+
"route to technical support",
|
| 12 |
+
"route to sales",
|
| 13 |
+
]
|
| 14 |
+
candidate_vectors = model.encode_candidates(tokenizer, options)
|
| 15 |
+
|
| 16 |
+
for context in (
|
| 17 |
+
"A customer disputes an invoice amount.",
|
| 18 |
+
"A customer reports a failed software update.",
|
| 19 |
+
):
|
| 20 |
+
context_vector = model.encode_context(tokenizer, context)
|
| 21 |
+
print(model.choose_cached(context_vector, candidate_vectors, options))
|
examples/native_decision.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Structured decisions keep candidate IDs out of the option encoder."""
|
| 2 |
+
import torch
|
| 3 |
+
from transformers import AutoModel, AutoTokenizer
|
| 4 |
+
|
| 5 |
+
MODEL = "Q1z/Pivot"
|
| 6 |
+
tokenizer = AutoTokenizer.from_pretrained(MODEL, trust_remote_code=True)
|
| 7 |
+
model = AutoModel.from_pretrained(MODEL, trust_remote_code=True, dtype=torch.float32).eval()
|
| 8 |
+
|
| 9 |
+
decision = model.decide_native(
|
| 10 |
+
tokenizer,
|
| 11 |
+
"A customer disputes an invoice and asks for a billing correction.",
|
| 12 |
+
[
|
| 13 |
+
{"id": "billing", "text": "route to billing support"},
|
| 14 |
+
{"id": "technical", "text": "route to technical support"},
|
| 15 |
+
{"id": "sales", "text": "route to sales"},
|
| 16 |
+
{"id": "abstain", "text": "none of these routes is appropriate", "kind": "abstain"},
|
| 17 |
+
],
|
| 18 |
+
)
|
| 19 |
+
print(decision["selected"])
|
| 20 |
+
print(decision["prob_vector"])
|
examples/quickstart.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""One context, multiple candidate answers; no text generation."""
|
| 2 |
+
import torch
|
| 3 |
+
from transformers import AutoModel, AutoTokenizer
|
| 4 |
+
|
| 5 |
+
MODEL = "Q1z/Pivot"
|
| 6 |
+
tokenizer = AutoTokenizer.from_pretrained(MODEL, trust_remote_code=True)
|
| 7 |
+
model = AutoModel.from_pretrained(MODEL, trust_remote_code=True, dtype=torch.float32).eval()
|
| 8 |
+
|
| 9 |
+
context = "CONTEXT:\nA customer disputes an invoice and asks for a billing correction."
|
| 10 |
+
options = [
|
| 11 |
+
"route to billing support",
|
| 12 |
+
"route to technical support",
|
| 13 |
+
"route to sales",
|
| 14 |
+
]
|
| 15 |
+
decision = model.choose(tokenizer, context, options)
|
| 16 |
+
print(decision) # choice, index, probabilities in supplied candidate order
|
manifest.json
CHANGED
|
@@ -7,12 +7,12 @@
|
|
| 7 |
"encoder_runtime_sha256": "f171f518be2a07da48b17fdea5655cad0a2452ab548e90e8ae903143686647e2",
|
| 8 |
"files": {
|
| 9 |
"README.md": {
|
| 10 |
-
"sha256": "
|
| 11 |
-
"bytes":
|
| 12 |
},
|
| 13 |
"config.json": {
|
| 14 |
-
"sha256": "
|
| 15 |
-
"bytes":
|
| 16 |
},
|
| 17 |
"configuration_pivot.py": {
|
| 18 |
"sha256": "a65e6ef32f3483dd0015dbbd6faaf75f456c3641a4692764cee7c0b7e39c6628",
|
|
@@ -89,6 +89,103 @@
|
|
| 89 |
"training/train_report.json": {
|
| 90 |
"sha256": "d597894ba21c47a7c959fca8e4b8a65f901da7647517e3ae66661cedec0d1412",
|
| 91 |
"bytes": 4100
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 92 |
}
|
| 93 |
-
}
|
| 94 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
"encoder_runtime_sha256": "f171f518be2a07da48b17fdea5655cad0a2452ab548e90e8ae903143686647e2",
|
| 8 |
"files": {
|
| 9 |
"README.md": {
|
| 10 |
+
"sha256": "f9661656045863e2293a38b98d1b79c736ef4864c01bf419c47ede101a61c8f5",
|
| 11 |
+
"bytes": 5574
|
| 12 |
},
|
| 13 |
"config.json": {
|
| 14 |
+
"sha256": "225cf873bf254492dc6a791aeeb702149485b9df8902c43c056e5ae911b04b77",
|
| 15 |
+
"bytes": 3883
|
| 16 |
},
|
| 17 |
"configuration_pivot.py": {
|
| 18 |
"sha256": "a65e6ef32f3483dd0015dbbd6faaf75f456c3641a4692764cee7c0b7e39c6628",
|
|
|
|
| 89 |
"training/train_report.json": {
|
| 90 |
"sha256": "d597894ba21c47a7c959fca8e4b8a65f901da7647517e3ae66661cedec0d1412",
|
| 91 |
"bytes": 4100
|
| 92 |
+
},
|
| 93 |
+
"benchmarks/README.md": {
|
| 94 |
+
"sha256": "b8afec4eb9ef30b85f8fd1efe970ad7be707f1f749005eee38cec1c145283f29",
|
| 95 |
+
"bytes": 1427
|
| 96 |
+
},
|
| 97 |
+
"benchmarks/jevbench_public.py": {
|
| 98 |
+
"sha256": "de8bd8a3d867dcd1f9e443bc0820bcdda0ca7f0460832c076247c3e5745878ca",
|
| 99 |
+
"bytes": 13590
|
| 100 |
+
},
|
| 101 |
+
"benchmarks/requirements.txt": {
|
| 102 |
+
"sha256": "7397364a88101a1e34d246f1c4a828cf0a6a2a17e95da61afe9817ace943d7b1",
|
| 103 |
+
"bytes": 91
|
| 104 |
+
},
|
| 105 |
+
"cpu-speed/README.md": {
|
| 106 |
+
"sha256": "84157cf465febe80a4964c8dac0023e3f6b705bfc71470e5bc9c9ec0ddcbf68f",
|
| 107 |
+
"bytes": 1136
|
| 108 |
+
},
|
| 109 |
+
"cpu-speed/benchmark.py": {
|
| 110 |
+
"sha256": "22321de328e88fd646840f9266a9d092e72dddb290f6289926da24a72932aad0",
|
| 111 |
+
"bytes": 308
|
| 112 |
+
},
|
| 113 |
+
"docs/BENCHMARK.md": {
|
| 114 |
+
"sha256": "3bd6f3c535717c2f08378ec286a34cd83ded8b3920ad5ffda290f3f9d41394ba",
|
| 115 |
+
"bytes": 2151
|
| 116 |
+
},
|
| 117 |
+
"docs/INFERENCE.md": {
|
| 118 |
+
"sha256": "bc00ea8e2998072767208610a5062205ada4d1fe3bb0007d3318666933a2ea9f",
|
| 119 |
+
"bytes": 3349
|
| 120 |
+
},
|
| 121 |
+
"docs/PERFORMANCE.md": {
|
| 122 |
+
"sha256": "b2bdf733b584d9039b89d3301b1458f5cf5401c205405f8fc05ed6e9ea7be1e3",
|
| 123 |
+
"bytes": 1866
|
| 124 |
+
},
|
| 125 |
+
"docs/UPDATE_NOTES.md": {
|
| 126 |
+
"sha256": "bb3e44ddd2fc2f615034b9aa4b78cf90e0ec2cc51b57d36743100fe41355fa59",
|
| 127 |
+
"bytes": 1308
|
| 128 |
+
},
|
| 129 |
+
"evaluation/2026-09-24/README.md": {
|
| 130 |
+
"sha256": "9a1d611d964dd798b88d85e67a677943e25b240fb1a052a77193357421403959",
|
| 131 |
+
"bytes": 1156
|
| 132 |
+
},
|
| 133 |
+
"evaluation/2026-09-24/accuracy.png": {
|
| 134 |
+
"sha256": "0405c91c2408d049aac19940c30ff2db07a43ab605f9440645fd20d04643ecd1",
|
| 135 |
+
"bytes": 53007
|
| 136 |
+
},
|
| 137 |
+
"evaluation/2026-09-24/cpu_speed.json": {
|
| 138 |
+
"sha256": "b02c3c1f6b5ba01f0857ecbd6e3a6d50e9df2f4d0cfbbb34eb92b44f86b23697",
|
| 139 |
+
"bytes": 1203
|
| 140 |
+
},
|
| 141 |
+
"evaluation/2026-09-24/jevbench_public.json": {
|
| 142 |
+
"sha256": "b4c878e64a5c6f5203a5fe97e2b4b9c0e262ddd78feb7b634fe58ee88d1b9af7",
|
| 143 |
+
"bytes": 16603
|
| 144 |
+
},
|
| 145 |
+
"evaluation/2026-09-24/latency_throughput.png": {
|
| 146 |
+
"sha256": "fb50dfbb7c1e7a37f6da9636cdad56c14caff3b11685ea55c41bf9ce94400805",
|
| 147 |
+
"bytes": 89972
|
| 148 |
+
},
|
| 149 |
+
"evaluation/2026-09-24/performance.json": {
|
| 150 |
+
"sha256": "81642b8b7b85095d9758e3cc8fed1e595f23fe5744a3986c6c40ca2d397f61b2",
|
| 151 |
+
"bytes": 2644
|
| 152 |
+
},
|
| 153 |
+
"evaluation/2026-09-24/performance_overview.png": {
|
| 154 |
+
"sha256": "e91059540c6d0e03bcc855a2a009edb8672e61cf99fcd7081ef8dfd354342a04",
|
| 155 |
+
"bytes": 185988
|
| 156 |
+
},
|
| 157 |
+
"evaluation/render_charts.py": {
|
| 158 |
+
"sha256": "3b8bafdc9ddc7b86655238cf8d8378e57381308875cb13b2f68ac4054a3f3672",
|
| 159 |
+
"bytes": 4191
|
| 160 |
+
},
|
| 161 |
+
"examples/cached_candidates.py": {
|
| 162 |
+
"sha256": "892e6858506599da59a487b569559a94c23f253eb1ead1dbdfaf954f15c1559a",
|
| 163 |
+
"bytes": 751
|
| 164 |
+
},
|
| 165 |
+
"examples/native_decision.py": {
|
| 166 |
+
"sha256": "b9edf1839fb90426585908d0b702e7371d6b1b6d973e3fb3eb169fef9eea6a0c",
|
| 167 |
+
"bytes": 792
|
| 168 |
+
},
|
| 169 |
+
"examples/quickstart.py": {
|
| 170 |
+
"sha256": "355a0d2b5f12dc2016344bee7c8a24e27509911c7f9d1aa8d4501af71bcc48e1",
|
| 171 |
+
"bytes": 637
|
| 172 |
+
},
|
| 173 |
+
"notebooks/Pivot_CPU_Speed.ipynb": {
|
| 174 |
+
"sha256": "ee50b481a1fd841e06b91656e6febcc9422e7fcf9182de4192f19cbb761636d7",
|
| 175 |
+
"bytes": 3589
|
| 176 |
+
},
|
| 177 |
+
"serving/README.md": {
|
| 178 |
+
"sha256": "a23d3d61c64958bce4381a34c6308756edad918efc032741f59093d05cab68e5",
|
| 179 |
+
"bytes": 1081
|
| 180 |
+
},
|
| 181 |
+
"serving/typed_decisions.py": {
|
| 182 |
+
"sha256": "427cb1eac5a1e9bde56f592e6d5fefdb7d537d1aff6d374fd11d9cf1a7ae929d",
|
| 183 |
+
"bytes": 733
|
| 184 |
}
|
| 185 |
+
},
|
| 186 |
+
"documentation_release": "2026-09-24",
|
| 187 |
+
"evaluated_model_revision": "14bf8c26bf344ebdf88e22a4b6152dc5f75f3578",
|
| 188 |
+
"benchmark_release": "JevBench v1.4.1 public tasks",
|
| 189 |
+
"benchmark_commit": "24b9b5c1609a7a9e8fa14f49e5985a836c9dc842",
|
| 190 |
+
"serving_option_tokens_default": 128
|
| 191 |
+
}
|
notebooks/Pivot_CPU_Speed.ipynb
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"nbformat": 4,
|
| 3 |
+
"nbformat_minor": 5,
|
| 4 |
+
"metadata": {
|
| 5 |
+
"kernelspec": {
|
| 6 |
+
"display_name": "Python 3",
|
| 7 |
+
"language": "python",
|
| 8 |
+
"name": "python3"
|
| 9 |
+
},
|
| 10 |
+
"language_info": {
|
| 11 |
+
"name": "python"
|
| 12 |
+
}
|
| 13 |
+
},
|
| 14 |
+
"cells": [
|
| 15 |
+
{
|
| 16 |
+
"cell_type": "markdown",
|
| 17 |
+
"metadata": {},
|
| 18 |
+
"source": [
|
| 19 |
+
"# Pivot — CPU speed\n",
|
| 20 |
+
"\n",
|
| 21 |
+
"Run this notebook in a Python CPU environment with Git installed. It asks for a Hugging Face key only if you choose to use one; public model files do not need a key. It pins the measured Pivot checkpoint and the official JevBench v1.4.1 public source, then writes a JSON result, chart and ZIP. The result is local speed, not an official composite score.\n"
|
| 22 |
+
]
|
| 23 |
+
},
|
| 24 |
+
{
|
| 25 |
+
"cell_type": "code",
|
| 26 |
+
"metadata": {},
|
| 27 |
+
"source": [
|
| 28 |
+
"import sys, subprocess\n",
|
| 29 |
+
"subprocess.check_call([sys.executable, \"-m\", \"pip\", \"install\", \"-q\", \"torch==2.8.0\", \"transformers==5.17.0\", \"safetensors==0.8.0\", \"numpy==1.26.4\", \"huggingface_hub>=0.26.0\", \"matplotlib>=3.8,<4\"])\n"
|
| 30 |
+
],
|
| 31 |
+
"execution_count": null,
|
| 32 |
+
"outputs": []
|
| 33 |
+
},
|
| 34 |
+
{
|
| 35 |
+
"cell_type": "code",
|
| 36 |
+
"metadata": {},
|
| 37 |
+
"source": [
|
| 38 |
+
"from getpass import getpass\n",
|
| 39 |
+
"from huggingface_hub import login\n",
|
| 40 |
+
"if input(\"Use a private Hugging Face key? (y/N): \").strip().lower() == \"y\":\n",
|
| 41 |
+
" login(token=getpass(\"HF token (hidden): \"), add_to_git_credential=False)\n"
|
| 42 |
+
],
|
| 43 |
+
"execution_count": null,
|
| 44 |
+
"outputs": []
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
"cell_type": "code",
|
| 48 |
+
"metadata": {},
|
| 49 |
+
"source": [
|
| 50 |
+
"from pathlib import Path\n",
|
| 51 |
+
"from huggingface_hub import hf_hub_download\n",
|
| 52 |
+
"script = Path.cwd() / \"benchmarks\" / \"jevbench_public.py\"\n",
|
| 53 |
+
"if not script.is_file():\n",
|
| 54 |
+
" script = Path(hf_hub_download(\"Q1z/Pivot\", \"benchmarks/jevbench_public.py\"))\n",
|
| 55 |
+
"print(\"Benchmark runner:\", script)\n"
|
| 56 |
+
],
|
| 57 |
+
"execution_count": null,
|
| 58 |
+
"outputs": []
|
| 59 |
+
},
|
| 60 |
+
{
|
| 61 |
+
"cell_type": "code",
|
| 62 |
+
"metadata": {},
|
| 63 |
+
"source": [
|
| 64 |
+
"import json\n",
|
| 65 |
+
"outdir = Path.cwd() / \"pivot_cpu_run\"\n",
|
| 66 |
+
"outdir.mkdir(exist_ok=True)\n",
|
| 67 |
+
"result = outdir / \"cpu_speed.json\"\n",
|
| 68 |
+
"subprocess.check_call([sys.executable, str(script), \"--mode\", \"speed\", \"--device\", \"cpu\", \"--threads\", \"4\", \"--batch-size\", \"4\", \"--output\", str(result)])\n",
|
| 69 |
+
"report = json.loads(result.read_text(encoding=\"utf-8\"))\n",
|
| 70 |
+
"report[\"speed\"]\n"
|
| 71 |
+
],
|
| 72 |
+
"execution_count": null,
|
| 73 |
+
"outputs": []
|
| 74 |
+
},
|
| 75 |
+
{
|
| 76 |
+
"cell_type": "code",
|
| 77 |
+
"metadata": {},
|
| 78 |
+
"source": [
|
| 79 |
+
"import matplotlib.pyplot as plt\n",
|
| 80 |
+
"from zipfile import ZipFile, ZIP_DEFLATED\n",
|
| 81 |
+
"from IPython.display import display, FileLink\n",
|
| 82 |
+
"s = report[\"speed\"]\n",
|
| 83 |
+
"fig, axes = plt.subplots(1, 2, figsize=(9, 3.5), layout=\"constrained\")\n",
|
| 84 |
+
"axes[0].bar([\"p50\", \"p95\"], [s[\"single_decision\"][\"p50_ms\"], s[\"single_decision\"][\"p95_ms\"]], color=[\"#2959db\", \"#139684\"])\n",
|
| 85 |
+
"axes[0].set(title=\"CPU single-decision latency\", ylabel=\"ms\")\n",
|
| 86 |
+
"axes[1].bar([f\"batch {s['throughput']['batch_size']}\"], [s[\"throughput\"][\"decisions_per_second\"]], color=\"#2959db\")\n",
|
| 87 |
+
"axes[1].set(title=\"CPU throughput\", ylabel=\"decisions/s\")\n",
|
| 88 |
+
"chart = outdir / \"cpu_speed_chart.png\"\n",
|
| 89 |
+
"fig.savefig(chart, dpi=170)\n",
|
| 90 |
+
"plt.show()\n",
|
| 91 |
+
"archive = outdir / \"pivot_cpu_speed.zip\"\n",
|
| 92 |
+
"with ZipFile(archive, \"w\", ZIP_DEFLATED) as z:\n",
|
| 93 |
+
" z.write(result, result.name)\n",
|
| 94 |
+
" z.write(chart, chart.name)\n",
|
| 95 |
+
"display(FileLink(str(archive)))\n"
|
| 96 |
+
],
|
| 97 |
+
"execution_count": null,
|
| 98 |
+
"outputs": []
|
| 99 |
+
}
|
| 100 |
+
]
|
| 101 |
+
}
|
serving/README.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Pivot serving interfaces
|
| 2 |
+
|
| 3 |
+
The model exposes three synchronous methods after loading `AutoModel` and `AutoTokenizer` with `trust_remote_code=True`:
|
| 4 |
+
|
| 5 |
+
1. `choose(tokenizer, context, options)` returns a simple choice, index and probability vector.
|
| 6 |
+
2. `decide_native(tokenizer, context, candidates)` accepts stable machine IDs, semantic candidate text and at most one explicit abstain candidate.
|
| 7 |
+
3. `decide(tokenizer, state, questions)` returns a typed collection of choice, yes/no and score decisions.
|
| 8 |
+
|
| 9 |
+
The model operates on supplied options; it does not create new options or generate explanatory text. The default serving limits in this update are 512 context tokens and 128 tokens per option. Keep a stable option set if comparing scores between requests.
|
| 10 |
+
|
| 11 |
+
The pre-existing [typed request](example_request.json) and [response](example_response.json) and [native request](native_example_request.json) and [response](native_example_response.json) illustrate the wire shapes. Run [a typed Python example](typed_decisions.py) or read the [full inference guide](../docs/INFERENCE.md).
|
serving/typed_decisions.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""One context, three typed questions using Pivot's bundled runtime."""
|
| 2 |
+
import torch
|
| 3 |
+
from transformers import AutoModel, AutoTokenizer
|
| 4 |
+
|
| 5 |
+
repo = "Q1z/Pivot"
|
| 6 |
+
tokenizer = AutoTokenizer.from_pretrained(repo, trust_remote_code=True)
|
| 7 |
+
model = AutoModel.from_pretrained(repo, trust_remote_code=True, dtype=torch.float32).eval()
|
| 8 |
+
response = model.decide(
|
| 9 |
+
tokenizer,
|
| 10 |
+
"Customer dispute: invoice 120 vs PO 100, age=3d, region=US",
|
| 11 |
+
[
|
| 12 |
+
{"id": "route", "primitive": "choice",
|
| 13 |
+
"options": ["billing", "tech", "sales"]},
|
| 14 |
+
{"id": "approve", "primitive": "noul",
|
| 15 |
+
"options": ["true", "false"]},
|
| 16 |
+
{"id": "severity", "primitive": "score",
|
| 17 |
+
"options": ["0", "1", "2", "3"]},
|
| 18 |
+
],
|
| 19 |
+
)
|
| 20 |
+
print(response)
|