Skip to main content

vernier

PyPI Python Crates.io License

Fast, auditable evaluation for 2D vision models. Detection, instance and panoptic segmentation, semantic segmentation, keypoints, and LVIS, all in one package with a Rust core, a Python API, and a standalone CLI.

  • Bit-exact with pycocotools==2.0.11, panopticapi, lvis-api and boundary-iou-api in strict mode. Every upstream quirk has a documented disposition (quirks survey).
  • Drop-in for pycocotools.cocoeval.COCOeval: change one import, or none. Same constructor, same params mutations, same eval / evalImgs / ious / stats read back off the instance (what carries over).
  • 7–47× faster than faster-coco-eval and pycocotools at equal CPU budget, measured on real detector output rather than jittered ground truth (benchmarks).
  • Built for real pipelines: training-loop evaluation, multi-rank gathering, per-image tables, error decomposition, calibration, scenario slicing.

Install

pip install vernier               # Python ≥ 3.10, abi3 wheels
cargo binstall vernier-cli        # standalone `vernier` binary, no Python needed
cargo add vernier                 # Rust library

Quickstart: the COCO API you already know

vernier.COCOeval has the same constructor, the same evaluate() / accumulate() / summarize() sequence, and the same .stats as pycocotools. It defaults to parity_mode="strict", so the output is bit-identical (see Status & validation for what that is measured against).

from pycocotools.coco import COCO
from vernier import COCOeval  # was: from pycocotools.cocoeval import COCOeval

coco_gt = COCO("instances_val2017.json")
coco_dt = coco_gt.loadRes("detections.json")

E = COCOeval(coco_gt, coco_dt, iouType="bbox")  # "segm" | "keypoints" | "boundary"
E.evaluate()
E.accumulate()
E.summarize()

Code you can't edit (mmdetection, detectron2, ultralytics, …): patch the symbol before anything imports pycocotools.cocoeval.

import vernier

unpatch = vernier.patch_pycocotools()  # pycocotools.cocoeval.COCOeval -> vernier
run_existing_eval()
unpatch()

The patch is explicit, reversible, and never happens on import. A context manager (vernier.adapters.patched_pycocotools) and a one-fixture pytest recipe are in the pycocotools migration guide.

TorchMetrics' MeanAveragePrecision runs under the patch unchanged, including class_metrics=True and extended_summary=True (tests/python/test_compat_torchmetrics.py asserts the patched and unpatched results are equal). Two params fields are the exception and raise rather than diverge quietly: imgIds subsetting, and areaRng (custom area ranges are a native-Evaluator feature, ADR-0040). The migration guide has the field-by-field table.

The shim exists for migration. New code should use the native Evaluator: immutable configuration, typed results, no pycocotools dependency, and access to everything below.

from pathlib import Path
from vernier.instance import Bbox, CocoDataset, Evaluator

gt = CocoDataset.from_json(Path("instances_val2017.json").read_bytes())
dt = Path("detections.json").read_bytes()

evaluator = Evaluator(iou=Bbox(), parity_mode="strict")
summary = evaluator.evaluate(gt, dt, num_threads=8)

print("\n".join(summary.pretty_lines()))  # the familiar 12-line table
ap = summary.stats[0]

The native Evaluator defaults to parity_mode="corrected", which applies the itemized fixes to upstream bugs. Pass "strict" when your numbers must match published pycocotools results.

Inside a training loop, evaluate on a background worker and feed it tensors directly (torch, JAX, CuPy, NumPy via DLPack, zero-copy):

with evaluator.background(gt) as bg:
    for images, targets in val_loader:
        preds = model(images)
        bg.submit([{"image_id": int(t["image_id"]), **p} for t, p in zip(targets, preds)])
    summary = bg.finalize()

Per-image and per-class diagnostics as Polars DataFrames (pip install "vernier[tables]"):

result = evaluator.evaluate(gt, dt, tables="all")
result.per_class

Paradigms

Pick the submodule that matches your model's output. They have different data models and matching rules, so they are separate evaluators rather than one class with a mode switch (why).

Submodule Input Metrics
vernier.instance Scored detections: boxes, masks, keypoints AP / AR (bbox, segm, boundary, OKS), LVIS federated AP
vernier.panoptic Panoptic PNGs + segments_info PQ / SQ / RQ, boundary PQ
vernier.semantic Class-id label maps mIoU, FWIoU, pixel accuracy, mean accuracy

Beyond the COCO API

Need Feature Guide
Evaluate without blocking training Evaluator.background(...) how-to
Evaluate across DDP ranks evaluate_to_partial / from_partials how-to
Find which images/classes regressed tables="all" how-to
Explain an AP gap TIDE error decomposition, oLRP tutorial
Check score calibration ECE / MCE / reliability (calibration=True) how-to
Metrics per weather, time of day, … Manifest slicing, vernier aggregate (mPC / rPC) how-to
Non-standard IoU / recall / area grids iou_thresholds=, recall_thresholds=, area_ranges= how-to

CLI

A static binary for CI gates and robotics replay pipelines. Output is byte-deterministic (sorted keys, no timestamps), so artifacts diff cleanly.

vernier eval --gt gt.json --dt dt.json --iou-type bbox                  # pycocotools-identical stdout
vernier eval --gt gt.json --dt dt.json --iou-type segm --emit json=result.json --threads 8

Exit codes: 0 success, 1 evaluation error, 2 invalid arguments. Full reference: crates/vernier-cli.

Status & validation

Every row is checked by a parity harness that runs the reference implementation and vernier on the same inputs. "Bit-exact" means parity_mode="strict", against the reference as published on PyPI — vernier's own output is identical on x86-64 and ARM. (A pycocotools you recompile from source can round bbox IoU 1-2 ULP differently on ARM; see ADR-0056 and the migration guide.)

Metric Reference Parity Notes
bbox / segm / keypoints AP pycocotools==2.0.11 bit-exact
Boundary AP boundary-iou-api bit-exact
LVIS federated AP lvis-api 0.5.3 bit-exact full v1 val, bbox
Panoptic PQ, boundary PQ panopticapi (single-core path) bit-exact Cityscapes panoptic deferred
Semantic mIoU / FWIoU / pAcc / mAcc mmseg.IoUMetric v1.2.2 (vendored) bit-exact on class marginals ADR-0036 proposed; ADE20K-scale check pending
oLRP clean-room NumPy oracle ≤ 1e-9 panoptic not supported
Calibration (ECE / MCE) clean-room NumPy oracle bit-exact detection family only
TIDE thresholds (segm, boundary) none corrected only ADR-0022 proposed

Parity model: ADR-0002. Library-by-library comparison: docs/comparison.md.

Performance

Median wall time at a one-CPU budget (CPU/wall is 1.00 in every cell). COCO val2017 throughout, except the LVIS row, which is LVIS v1 val. Speedup is the other library's time divided by vernier's.

The DT source column is load-bearing. A jittered workload perturbs the ground truth to synthesise detections, which inherits the GT's per-image class distribution — not the distribution a detector actually produces. The bbox and segm rows are measured on real RF-DETR predictions on val2017 (513,808 and 430,516 detections) and the keypoints row on real ViTPose output; the remaining rows still run against synthetic DT, and are labelled as such rather than presented as equivalent.

Workload DT source vernier vs pycocotools vs faster-coco-eval vs hotcoco vs ufcoco
bbox AP RF-DETR Nano 492 ms 47.4× 11.2× 4.7× 1.09×
segm AP RF-DETR Seg-Nano 1.43 s 16.1× 7.1× 3.4× 1.25×
keypoints AP ViTPose-B ⁵ 129 ms 18.6× 6.1× 1.6× —
boundary AP jittered GT 2.76 s 21.6× ¹ 19.3× — 77.6×
Panoptic PQ perfect DT 10.6 s 3.4× ² — — —
Semantic mIoU perfect DT 2.89 s 14.3× ³ — — —
LVIS v1 bbox AP jittered GT 1.28 s 171.5× ⁴ — 3.2× —

¹ boundary-iou-api · ² panopticapi · ³ mmsegmentation · ⁴ lvis-api, with 20× lower peak memory (771 MiB vs 15.08 GiB); lvis-api's reps failed the 5% IQR gate (9.4%), so read the ratio as approximate · ⁵ from the 2026-09 real-predictions snapshot, not re-run in this round

A second real detector on the same kernel and GT gives a different point estimate: RF-DETR Seg-Nano's bbox output (16% fewer detections, higher AP) measures 37.2× / 9.5× / 4.5× / 1.10×. Treat a single-workload speedup as a point estimate, not a property of the library — the release snapshot gives per-stage breakdowns. ufcoco is the closest competitor: vernier leads it on every real-prediction cell, but on one thread its matching kernel is the faster one, and it wins the synthetic jittered bbox cell (157 ms against 165 ms, see the thread table).

Peak RSS on the real bbox cell is 257 MiB, against 997 MiB (hotcoco), 1384 MiB (faster-coco-eval) and 1429 MiB (pycocotools) — a 3.9–5.6× advantage — and 225 MiB for ufcoco, which is the leanest. Every implementation's working set grows with real detection density, but not by the same factor: against hotcoco the gap widens from 1.7× on the synthetic cell to 3.9× here, because hotcoco's per-detection Python-object overhead scales with detection count while vernier's columnar ingest does not.

Thread scaling (num_threads, 8-vCPU host)

faster-coco-eval ≥ 1.8, hotcoco and ufcoco are multi-threaded by default, so each column compares equal CPU budgets.

Workload 1 2 4 8 vs hotcoco @ 8 vs faster-coco-eval @ 8 vs ufcoco @ 1 / 8
bbox 164 ms 117 ms 79 ms 78 ms 4.7× 19.2× 0.94× / 1.40×
segm 507 ms 293 ms 174 ms 141 ms 3.9× 25.1× 1.45× / 1.60×
boundary 2.76 s 1.41 s 758 ms 634 ms — 26.9× 82.1× / 79.6×
keypoints 113 ms 75 ms 46 ms 39 ms 4.1× 20.2× 1.06× / 1.80×
bbox, Objects365 (1.06M dets) † 2.9 s — — 1.2 s 7.1× OOM at ~30 GiB 1.21× / 1.62×

Strict-mode results are bit-identical across thread counts. † Single-rep dev run; pycocotools takes ~6 min per rep at this size. The faster-coco-eval OOM is carried forward from the previous round rather than re-measured — reproducing a 30 GiB OOM destabilises the host mid-round.

AMD EPYC-Milan KVM VPS (4 cores x 2 threads = 8 logical CPUs), harness mode release (N=10 measurement reps + 2 warmup, randomised impl order, 5% relative-IQR gate), against hotcoco==1.0.1, ultrafast-pycocotools==0.1.14, faster-coco-eval==1.8.0 and pycocotools==2.0.11. Full methodology, every baseline pin and the complete results: docs/benchmarks.md for every timed row except keypoints, the release snapshot for the round's narrative.

Documentation

Contributing

just lint && just test && just audit

See CONTRIBUTING.md for the ADR workflow, vendoring policy, and code style.

License

Licensed under either of Apache-2.0 or MIT at your option. Test-only reference implementations used for parity checks are listed in THIRD_PARTY_NOTICES.md. They are not shipped in wheels or binaries.

Metadata

Release files for vernier 0.6.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for vernier 0.6.0
File Size Uploaded Provenance Actions
vernier-0.6.0.tar.gz 874.6 kB With provenance Details for vernier-0.6.0.tar.gz

Built distributions (wheels)

Table of built distributions (wheels) for vernier 0.6.0
File Actions
vernier-0.6.0-cp310-abi3-win_amd64.whl CPython 3.10 abi3 Windows x86-64 Details for vernier-0.6.0-cp310-abi3-win_amd64.whl
vernier-0.6.0-cp310-abi3-musllinux_1_2_x86_64.whl CPython 3.10 abi3 Linux musl 1.2+ x86-64 Details for vernier-0.6.0-cp310-abi3-musllinux_1_2_x86_64.whl
vernier-0.6.0-cp310-abi3-musllinux_1_2_aarch64.whl CPython 3.10 abi3 Linux musl 1.2+ ARM64 Details for vernier-0.6.0-cp310-abi3-musllinux_1_2_aarch64.whl
vernier-0.6.0-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl CPython 3.10 abi3 Linux glibc 2.17+ x86-64 Details for vernier-0.6.0-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
vernier-0.6.0-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl CPython 3.10 abi3 Linux glibc 2.17+ ARM64 Details for vernier-0.6.0-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl
vernier-0.6.0-cp310-abi3-macosx_11_0_arm64.whl CPython 3.10 abi3 macOS 11.0+ ARM64 Details for vernier-0.6.0-cp310-abi3-macosx_11_0_arm64.whl
vernier-0.6.0-cp310-abi3-macosx_10_12_x86_64.whl CPython 3.10 abi3 macOS 10.12+ x86-64 Details for vernier-0.6.0-cp310-abi3-macosx_10_12_x86_64.whl

Total release size: 17.7 MB

Release files / vernier-0.6.0.tar.gz

Download URL vernier-0.6.0.tar.gz
Size 874.6 kB
Tags Source
SHA-256 checksum
How to use checksums
faf5120cac06ad853b04626c0412aef054ec36105f27aa12d8d00a7f70284aa7
BLAKE2b-256 checksum
How to use checksums
aeb9065929404367313ed479cfadd5af60568cb59de3dae5753e322e49c59397
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 30, 2026.

Transparency log

Release files / vernier-0.6.0-cp310-abi3-win_amd64.whl

Download URL vernier-0.6.0-cp310-abi3-win_amd64.whl
Size 2.5 MB
Tags CPython 3.10 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
baad1cf9bcd0d76981cdcd97994e2ced525668eee9196b0834f5b2c83fe5f32d
BLAKE2b-256 checksum
How to use checksums
150a1162a3943b7f83cf88461977484397b510abce10cbff0fa11fadd5239470
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 30, 2026.

Transparency log

Release files / vernier-0.6.0-cp310-abi3-musllinux_1_2_x86_64.whl

Download URL vernier-0.6.0-cp310-abi3-musllinux_1_2_x86_64.whl
Size 2.6 MB
Tags CPython 3.10 Linux musl 1.2+ x86-64 abi3
SHA-256 checksum
How to use checksums
d4acc8dca25d960ba140ebc5410ab33d10497caae13729d63135dc6356f55d2f
BLAKE2b-256 checksum
How to use checksums
e59f7a1d5ac83cdf71a7393e806cb0dda8ec6ce3b72665b947fd7b52041cbd5d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 30, 2026.

Transparency log

Release files / vernier-0.6.0-cp310-abi3-musllinux_1_2_aarch64.whl

Download URL vernier-0.6.0-cp310-abi3-musllinux_1_2_aarch64.whl
Size 2.4 MB
Tags CPython 3.10 Linux musl 1.2+ ARM64 abi3
SHA-256 checksum
How to use checksums
c4efde8e3956c14c32b288076ad542fd307b48561e6de2b006c861b2669c82a9
BLAKE2b-256 checksum
How to use checksums
6ea89321f4656cc0a1016f5c4de8bfd5569b4f6c6a26a0d4937d7b2bf3db2e62
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 30, 2026.

Transparency log

Release files / vernier-0.6.0-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl

Download URL vernier-0.6.0-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Size 2.4 MB
Tags CPython 3.10 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
74abe503db95044a757826a7e32aef070cdd20e3ae9fa2ae598e0ece429fc09d
BLAKE2b-256 checksum
How to use checksums
6d3062dff21a90b1465a97a865120856fffa50445d148873221c140ce97c2e7b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 30, 2026.

Transparency log

Release files / vernier-0.6.0-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl

Download URL vernier-0.6.0-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl
Size 2.3 MB
Tags CPython 3.10 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
630f5a7304f76295b2c6dc273b8ef0cf0b115108368d63549aec39f821bc32ca
BLAKE2b-256 checksum
How to use checksums
4df23fcf62b8e11e4f81213d29e63f17b7321008fef5dfd0d8591a78dfe687af
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 30, 2026.

Transparency log

Release files / vernier-0.6.0-cp310-abi3-macosx_11_0_arm64.whl

Download URL vernier-0.6.0-cp310-abi3-macosx_11_0_arm64.whl
Size 2.2 MB
Tags CPython 3.10 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
996c6acf75d89e0108df39245d87eedd7436fb90971cd9d7afb69b2092a504df
BLAKE2b-256 checksum
How to use checksums
7d007153956957d9ca4d6c07e0b86a2427f8e0f0f8ed0331b598c6760010d55a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 30, 2026.

Transparency log

Release files / vernier-0.6.0-cp310-abi3-macosx_10_12_x86_64.whl

Download URL vernier-0.6.0-cp310-abi3-macosx_10_12_x86_64.whl
Size 2.3 MB
Tags CPython 3.10 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
5d716fdb9198468764856c8174616947d44b5e49429726db8ae5662e4d6aa10f
BLAKE2b-256 checksum
How to use checksums
fed58205e53b7603ecb60ee21571a40de8cc80e908f13e71c590ad4459e27214
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 30, 2026.

Transparency log

Security for vernier 0.6.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 8 files in this release have been uploaded with provenance metadata.

Select from 8 files

Attestation for vernier-0.6.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 30, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page