evaluators 2.1.4__tar.gz → 3.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. evaluators-3.2.0/PKG-INFO +432 -0
  2. evaluators-3.2.0/README.md +388 -0
  3. evaluators-3.2.0/pyproject.toml +248 -0
  4. evaluators-2.1.4/pyproject.toml → evaluators-3.2.0/pyproject.toml.orig +31 -4
  5. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/_engine.py +19 -5
  6. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/_streams.py +1 -3
  7. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/benchmarks/sys_info.py +11 -7
  8. evaluators-3.2.0/sources/evaluators/cli/__init__.py +8 -0
  9. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/cli/compute.py +8 -5
  10. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/cli/memory.py +8 -4
  11. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/cli/third_party.py +1 -1
  12. evaluators-3.2.0/sources/evaluators/integrations/__init__.py +7 -0
  13. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/integrations/lightning.py +127 -8
  14. evaluators-3.2.0/sources/evaluators/io/__init__.py +7 -0
  15. evaluators-3.2.0/sources/evaluators/io/mot_challenge.py +136 -0
  16. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/memory/backends/_registry.py +3 -0
  17. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/memory/backends/gds/writer.py +1 -1
  18. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/memory/backends/lmdb/_writer.py +17 -7
  19. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/memory/backends/memmap/_buffers.py +2 -2
  20. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/memory/backends/memmap/_reader.py +11 -0
  21. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/memory/backends/memmap/_writer.py +110 -22
  22. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/memory/codecs/_blosc.py +15 -2
  23. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/memory/schema.py +4 -0
  24. evaluators-3.2.0/sources/evaluators/metrics/domain/__init__.py +19 -0
  25. evaluators-3.2.0/sources/evaluators/metrics/domain/_ap.py +171 -0
  26. evaluators-3.2.0/sources/evaluators/metrics/domain/_greedy_match.py +106 -0
  27. evaluators-3.2.0/sources/evaluators/metrics/domain/_keys.py +105 -0
  28. evaluators-3.2.0/sources/evaluators/metrics/domain/_matching.py +105 -0
  29. evaluators-3.2.0/sources/evaluators/metrics/domain/box3d/__init__.py +16 -0
  30. evaluators-3.2.0/sources/evaluators/metrics/domain/box3d/_ap_metric.py +318 -0
  31. evaluators-3.2.0/sources/evaluators/metrics/domain/box3d/_similarity.py +163 -0
  32. evaluators-3.2.0/sources/evaluators/metrics/domain/box3d/_types.py +72 -0
  33. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/metrics/domain/depth.py +230 -12
  34. evaluators-3.2.0/sources/evaluators/metrics/domain/dvps.py +1346 -0
  35. evaluators-3.2.0/sources/evaluators/metrics/domain/occupancy.py +196 -0
  36. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/metrics/domain/segmentation/__init__.py +6 -0
  37. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/metrics/domain/segmentation/_utils.py +1 -0
  38. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/metrics/domain/segmentation/panoptic.py +503 -81
  39. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/metrics/domain/segmentation/semantic.py +149 -53
  40. evaluators-3.2.0/sources/evaluators/metrics/domain/segmentation/vendor/__init__.py +7 -0
  41. evaluators-3.2.0/sources/evaluators/metrics/domain/segmentation/vendor/panopticapi.py +252 -0
  42. evaluators-3.2.0/sources/evaluators/metrics/domain/sensorsim/__init__.py +26 -0
  43. evaluators-3.2.0/sources/evaluators/metrics/domain/sensorsim/_cross_modal_alignment.py +106 -0
  44. evaluators-3.2.0/sources/evaluators/metrics/domain/sensorsim/_image_quality.py +113 -0
  45. evaluators-3.2.0/sources/evaluators/metrics/domain/sensorsim/_point_cloud_quality.py +151 -0
  46. evaluators-3.2.0/sources/evaluators/metrics/domain/sensorsim/_radar_quality.py +156 -0
  47. evaluators-3.2.0/sources/evaluators/metrics/domain/sensorsim/_temporal_consistency.py +117 -0
  48. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/metrics/domain/step.py +180 -93
  49. evaluators-3.2.0/sources/evaluators/metrics/domain/tracking/__init__.py +16 -0
  50. evaluators-3.2.0/sources/evaluators/metrics/domain/tracking/_base.py +806 -0
  51. evaluators-3.2.0/sources/evaluators/metrics/domain/tracking/_classcomb.py +73 -0
  52. evaluators-3.2.0/sources/evaluators/metrics/domain/tracking/_clear.py +132 -0
  53. evaluators-3.2.0/sources/evaluators/metrics/domain/tracking/_combine.py +38 -0
  54. evaluators-3.2.0/sources/evaluators/metrics/domain/tracking/_hota.py +125 -0
  55. evaluators-3.2.0/sources/evaluators/metrics/domain/tracking/_identity.py +81 -0
  56. evaluators-3.2.0/sources/evaluators/metrics/domain/tracking/_preprocess.py +263 -0
  57. evaluators-3.2.0/sources/evaluators/metrics/domain/tracking/_seqdata.py +119 -0
  58. evaluators-3.2.0/sources/evaluators/metrics/domain/tracking/_similarity.py +208 -0
  59. evaluators-3.2.0/sources/evaluators/metrics/domain/tracking/_torchmatch_adapter.py +40 -0
  60. evaluators-3.2.0/sources/evaluators/metrics/domain/trajectory/__init__.py +15 -0
  61. evaluators-3.2.0/sources/evaluators/metrics/domain/trajectory/_types.py +79 -0
  62. evaluators-3.2.0/sources/evaluators/metrics/domain/vectormap/__init__.py +21 -0
  63. evaluators-3.2.0/sources/evaluators/metrics/domain/vectormap/_ap_metric.py +326 -0
  64. evaluators-3.2.0/sources/evaluators/metrics/domain/vectormap/_similarity.py +112 -0
  65. evaluators-3.2.0/sources/evaluators/metrics/domain/vectormap/_types.py +89 -0
  66. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/metrics/stats.py +1 -1
  67. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/presets/__init__.py +3 -2
  68. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/presets/cityscapes.py +28 -34
  69. evaluators-3.2.0/sources/evaluators/presets/mot.py +228 -0
  70. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/presets/semkitti.py +28 -31
  71. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/third_party/adapters/coco.py +3 -4
  72. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/types.py +27 -1
  73. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/utils/tensor_ops.py +2 -4
  74. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/visuals/tools/_visualizer.py +12 -9
  75. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/visuals/tools/transform.py +1 -1
  76. evaluators-2.1.4/PKG-INFO +0 -312
  77. evaluators-2.1.4/README.md +0 -271
  78. evaluators-2.1.4/sources/evaluators/metrics/domain/dvps.py +0 -804
  79. evaluators-2.1.4/sources/evaluators/metrics/domain/tracking.py +0 -0
  80. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/__init__.py +0 -0
  81. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/benchmarks/__init__.py +0 -0
  82. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/benchmarks/coordinator.py +0 -0
  83. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/benchmarks/scenarios.py +0 -0
  84. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/benchmarks/worker.py +0 -0
  85. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/cli/__main__.py +0 -0
  86. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/constants.py +0 -0
  87. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/memory/__init__.py +0 -0
  88. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/memory/backends/__init__.py +0 -0
  89. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/memory/backends/filesystem/__init__.py +0 -0
  90. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/memory/backends/filesystem/_reader.py +0 -0
  91. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/memory/backends/filesystem/_writer.py +0 -0
  92. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/memory/backends/gds/__init__.py +0 -0
  93. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/memory/backends/gds/reader.py +0 -0
  94. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/memory/backends/gds/utils.py +0 -0
  95. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/memory/backends/lmdb/__init__.py +0 -0
  96. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/memory/backends/lmdb/_reader.py +0 -0
  97. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/memory/backends/memmap/__init__.py +0 -0
  98. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/memory/codecs/__init__.py +0 -0
  99. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/memory/codecs/_png.py +0 -0
  100. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/memory/codecs/_raw.py +0 -0
  101. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/memory/codecs/_tiff.py +0 -0
  102. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/memory/config.py +0 -0
  103. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/memory/interfaces.py +0 -0
  104. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/metrics/__init__.py +0 -0
  105. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/metrics/adapters/coco.py +0 -0
  106. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/metrics/adapters/trackeval.py +0 -0
  107. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/presets/kitti.py +0 -0
  108. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/scheduling/__init__.py +0 -0
  109. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/scheduling/_catalog.py +0 -0
  110. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/scheduling/_partitioner.py +0 -0
  111. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/third_party/__init__.py +0 -0
  112. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/third_party/__main__.py +0 -0
  113. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/third_party/adapters/__init__.py +0 -0
  114. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/third_party/adapters/dvpq.py +0 -0
  115. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/third_party/adapters/pq.py +0 -0
  116. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/utils/comms.py +0 -0
  117. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/utils/configs.py +0 -0
  118. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/visuals/__init__.py +0 -0
  119. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/visuals/metric.py +0 -0
  120. {evaluators-2.1.4 → evaluators-3.2.0}/sources/evaluators/visuals/tools/__init__.py +0 -0
@@ -0,0 +1,432 @@
1
+ Metadata-Version: 2.3
2
+ Name: evaluators
3
+ Version: 3.2.0
4
+ Summary: Various scene understanding and perception evaluation metrics.
5
+ Author: Kurt Stolle
6
+ Author-email: Kurt Stolle <kurt@computer.org>
7
+ Classifier: Development Status :: 4 - Beta
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: Intended Audience :: Science/Research
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
12
+ Classifier: Topic :: Scientific/Engineering :: Image Recognition
13
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
14
+ Classifier: Programming Language :: Python
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Operating System :: OS Independent
19
+ Requires-Dist: torch>2.7
20
+ Requires-Dist: torchvision
21
+ Requires-Dist: torchmetrics
22
+ Requires-Dist: tensordict>=0.11.0
23
+ Requires-Dist: numpy>=2.0.0
24
+ Requires-Dist: matplotlib>=3.9.0
25
+ Requires-Dist: rich>=13.9.4
26
+ Requires-Dist: pydantic
27
+ Requires-Dist: opencv-python-headless>=4.13.0.92
28
+ Requires-Dist: omegaconf>=2.3.0
29
+ Requires-Dist: hydra-zen>=0.16.0
30
+ Requires-Dist: scipy>=1.14.0
31
+ Requires-Dist: shapely>=2.0.0
32
+ Requires-Dist: torchmatch>=1.0.4
33
+ Requires-Dist: blosc2>=4.1.2 ; extra == 'blosc2'
34
+ Requires-Dist: lightning>=2.6.1 ; extra == 'lightning'
35
+ Requires-Dist: lmdb>=2.2.0 ; extra == 'lmdb'
36
+ Requires-Dist: imagecodecs>=2026.3.6 ; extra == 'tiff'
37
+ Requires-Dist: tifffile>=2026.3.3 ; extra == 'tiff'
38
+ Requires-Python: >=3.13, <3.14
39
+ Provides-Extra: blosc2
40
+ Provides-Extra: lightning
41
+ Provides-Extra: lmdb
42
+ Provides-Extra: tiff
43
+ Description-Content-Type: text/markdown
44
+
45
+ # Scalable Distributed Evaluation for Computer Vision
46
+
47
+ [![PyPI](https://img.shields.io/pypi/v/evaluators)](https://pypi.org/project/evaluators/)
48
+ [![Python Version](https://img.shields.io/pypi/pyversions/evaluators)](https://pypi.org/project/evaluators/)
49
+ [![License](https://img.shields.io/pypi/l/evaluators)](https://github.com/khwstolle/evaluators/blob/main/LICENSE)
50
+ [![Build Status](https://img.shields.io/github/actions/workflow/status/khwstolle/evaluators/ci.yml)](https://github.com/khwstolle/evaluators/actions)
51
+
52
+ Metrics like panoptic quality over video (VPQ, DVPQ), depth-aware segmentation-and-tracking quality (DSTQ), and multi-object tracking metrics (HOTA, CLEAR, IDF1) are computed over whole sequences, not independent per-frame samples: window/tube matching across consecutive frames, or track-identity consistency across an entire video. A validation loop doesn't hand a metric a whole sequence at once. It hands it one batch at a time, and a given sequence's frames can land in different steps, different dataloader workers, and different distributed ranks depending on how the loader shards them. Standard online metric aggregation, `update()` per step, reduce across ranks at `compute()`, works when each sample's contribution reduces independently of order. It breaks down when a metric needs contiguous, ordered access to every frame of a sequence before it can produce a result.
53
+
54
+ The usual workaround is to write every prediction to disk during the validation epoch and run the official reference script by hand afterward, outside the training loop. Evaluators automates that instead. Predictions still stream to a storage backend (Memory Map or LMDB) during inference, with no metric computation in the hot path. Once the epoch or run ends, the pipeline reassembles complete, correctly-ordered sequences, regardless of how their frames were scattered across steps and ranks, and computes the metric against the whole sequence automatically. Dropping `DistributedEvaluationCallback` into a PyTorch Lightning `Trainer` is the common case: whole-sequence metrics get logged like any other validation metric, with no manual step in between.
55
+
56
+ Because predictions are persisted as a side effect, the same pipeline also supports deferred, offline re-evaluation: save the config during inference, then compute later, on a different machine, without re-running the model. That capability is real and useful, particularly for reproducibility, but it follows from the design; it isn't the reason the library exists.
57
+
58
+ The key features are:
59
+
60
+ - **Whole-sequence metrics, computed automatically.**
61
+ Handles metrics that standard per-step online aggregation cannot: window/tube-based video panoptic quality (VPQ, DVPQ, DSTQ) and identity-consistency tracking metrics (HOTA, CLEAR, IDF1), reassembled and computed correctly regardless of how a sequence's frames were split across steps and ranks.
62
+
63
+ - **Drops into a training loop.**
64
+ `DistributedEvaluationCallback` binds to a PyTorch Lightning `Trainer` and handles the write, reassembly, and compute stages automatically. Predictions are also written to disk, which supports deferred, offline re-evaluation on stored results.
65
+
66
+ - **Distributed by design.**
67
+ Synchronizes metric computation across multiple nodes and GPUs using `torchmetrics`, `torchmatch` (Hungarian assignment for the tracking metrics), and custom scheduling logic.
68
+
69
+ - **Explicit Memory Schemas.**
70
+ Uses Pydantic-based schemas to define data formats and encodings (PNG, TIFF, Raw) up front, ensuring type safety and storage efficiency.
71
+
72
+ - **Lazy loading.**
73
+ Supports referencing ground truth data from disk rather than duplicating it in memory caches, enabling evaluation of terabyte-scale datasets.
74
+
75
+ - **Multi-domain.**
76
+ Includes verified implementations for:
77
+ - Segmentation: Panoptic quality (PQ), semantic mIoU.
78
+ - DVPS: Video panoptic quality (VPQ), depth-aware video panoptic quality (DVPQ).
79
+ - Depth: Eigen et al. metrics (AbsRel, RMSE).
80
+ - Tracking: HOTA, CLEAR (MOTA/MOTP), identity F1 (IDF1).
81
+ - STEP: Segmentation and tracking quality (STQ), depth-aware STQ (DSTQ).
82
+ - Occupancy: per-class IoU/mIoU, occupied-vs-free precision/recall/F1.
83
+ - 3D detection: per-class/per-threshold AP and mAP (Shapely-based 3D IoU or center-distance matching), optional TP-error decomposition and AOS.
84
+ - Vector maps: per-class/per-threshold AP and mAP (Chamfer or Fréchet matching), optional topology accuracy.
85
+ - Sensor simulation: paired image/point-cloud/radar quality, plus single-stream self-consistency (temporal, cross-modal).
86
+
87
+ - **CLI.**
88
+ A command-line interface to inspect, index, and query saved inference results.
89
+
90
+ ---
91
+
92
+ ## Installation
93
+
94
+ ```shell
95
+ pip install evaluators
96
+ ```
97
+
98
+ ## Quick start
99
+
100
+ ### In the loop (PyTorch Lightning)
101
+
102
+ This is the common case: a whole-sequence metric (here `SemanticMetric`; see
103
+ `examples/03_video_dvps.py` for the DVPQ case this pipeline exists for) is
104
+ declared on the `LightningModule`, and `DistributedEvaluationCallback` handles
105
+ writing, sequence reassembly, and computation automatically at the end of
106
+ validation.
107
+
108
+ ```python
109
+ import lightning as L
110
+ from tensordict import TensorDict
111
+ from evaluators import MemorySchema, MetricStream, TensorField
112
+ from evaluators.integrations.lightning import DistributedEvaluationCallback
113
+ from evaluators.metrics.domain.segmentation import SemanticKeyMap, SemanticMetric
114
+
115
+
116
+ class SegmentationModel(L.LightningModule):
117
+ def __init__(self):
118
+ super().__init__()
119
+ self.layer = ... # the actual model
120
+
121
+ keys: SemanticKeyMap = {
122
+ "pred": "pred_sem",
123
+ "target": "target_sem",
124
+ "sequence_id": "sequence_id",
125
+ "frame_index": "frame_index",
126
+ }
127
+ self.metric = SemanticMetric(key_map=keys, num_classes=19, ignore_index=255)
128
+
129
+ # Both prediction and ground truth are written to storage here; see
130
+ # examples/02_lazy_loading.py for fetching ground truth from the
131
+ # dataset instead, via `target_source`.
132
+ schema = MemorySchema(fields={
133
+ "pred_sem": TensorField(dtype="int64", shape=(1024, 2048)),
134
+ "target_sem": TensorField(dtype="int64", shape=(1024, 2048)),
135
+ "sequence_id": TensorField(dtype="int64", shape=()),
136
+ "frame_index": TensorField(dtype="int64", shape=()),
137
+ })
138
+ self.eval_stream = MetricStream(metrics=[self.metric], name="semantic", schema=schema)
139
+
140
+ def validation_step(self, batch, batch_idx):
141
+ # `batch` already provides "target_sem", "sequence_id", and
142
+ # "frame_index" from the dataset.
143
+ preds = self.layer(batch["image"]).argmax(dim=1)
144
+ batch["pred_sem"] = preds
145
+ # A leading time dimension is required even for single-frame batches.
146
+ self.eval_stream.update(
147
+ TensorDict(batch, batch_size=[preds.shape[0]]).unsqueeze(1)
148
+ )
149
+
150
+
151
+ trainer = L.Trainer(callbacks=[DistributedEvaluationCallback(output_dir="./eval_cache")])
152
+ trainer.fit(SegmentationModel(), datamodule)
153
+ ```
154
+
155
+ Results are logged to the trainer's loggers like any other validation metric.
156
+ See `examples/01_getting_started.py` for a complete, runnable version.
157
+
158
+ ### Manual (without Lightning)
159
+
160
+ This is what `DistributedEvaluationCallback` does under the hood. Use it
161
+ directly outside a Lightning loop, or to re-evaluate predictions that were
162
+ already written to disk without re-running the model.
163
+
164
+ The core abstractions are `MetricStream` (for writing) and `run_offline_evaluation` (for computing).
165
+
166
+ #### Step 1: Inference (online)
167
+
168
+ ```python
169
+ import torch
170
+ from tensordict import TensorDict
171
+ from evaluators import MetricStream, MemorySchema, TensorField, MemmapTemporalWriter
172
+ from evaluators.metrics.domain.segmentation import SemanticKeyMap, SemanticMetric
173
+ ```
174
+
175
+ ##### 1. Configure metrics and schema
176
+
177
+ ```python
178
+ ### Define the source for ground truth (lazy loading)
179
+
180
+ dataset = CityscapesDataset(...)
181
+ keys: SemanticKeyMap = {
182
+ "pred": "pred_sem",
183
+ "target": "target_sem",
184
+ "sequence_id": "sequence_id",
185
+ "frame_index": "frame_index",
186
+ }
187
+ metric = SemanticMetric(
188
+ key_map=keys,
189
+ num_classes=19,
190
+ ignore_index=255,
191
+ target_source=dataset,
192
+ )
193
+
194
+ ### Define the explicit memory schema
195
+ ### Only the prediction and metadata are written; ground truth is fetched
196
+ ### from `dataset` during the Compute stage.
197
+
198
+ schema = MemorySchema(fields={
199
+ "pred_sem": TensorField(dtype="int64", shape=(1024, 2048)),
200
+ "sequence_id": TensorField(dtype="int64", shape=()),
201
+ "frame_index": TensorField(dtype="int64", shape=()),
202
+ })
203
+ ```
204
+
205
+ ##### 2. Initialize stream and writer
206
+
207
+ ```python
208
+ # Create a writer (backend)
209
+ writer = MemmapTemporalWriter(output_dir="./inference_cache/semantic", schema=schema)
210
+
211
+ # Create a stream and bind the writer
212
+ stream = MetricStream(
213
+ metrics=[metric],
214
+ name="semantic",
215
+ schema=schema
216
+ )
217
+ stream.bind(writer)
218
+ ```
219
+
220
+ ##### 3. Run inference loop
221
+
222
+ ```python
223
+ for batch in dataloader: # Model forward pass
224
+ preds = model(batch["image"])
225
+ batch_size = preds.shape[0]
226
+
227
+ # Push to stream (non-blocking). A TensorDict is required, with a
228
+ # leading time dimension even for single-frame batches.
229
+ stream.update(
230
+ TensorDict(
231
+ {
232
+ "pred_sem": preds,
233
+ "sequence_id": batch["sequence_id"],
234
+ "frame_index": batch["frame_index"],
235
+ },
236
+ batch_size=[batch_size],
237
+ ).unsqueeze(1)
238
+ )
239
+
240
+ # Finalize
241
+ writer.close()
242
+ ```
243
+
244
+ > Note: `sequence_id` and `frame_index` must be `torch.int64`.
245
+
246
+ ##### 4. Finalize and compute
247
+
248
+ ```python
249
+ from evaluators import run_offline_evaluation
250
+
251
+ # Syncs workers, builds catalog, and runs metrics
252
+ results = run_offline_evaluation(
253
+ metrics=[metric],
254
+ artifact_dir="./inference_cache/semantic"
255
+ )
256
+ print(results["SemanticMetric"]["mIoU"])
257
+ ```
258
+
259
+ #### Step 2: Re-evaluation (offline)
260
+
261
+ Because predictions are persisted, metrics can be re-calculated or added without re-running the model.
262
+
263
+ ```python
264
+ # Run evaluation on existing artifacts
265
+ results = run_offline_evaluation(
266
+ metrics=[new_metric],
267
+ artifact_dir="./inference_cache/semantic"
268
+ )
269
+ ```
270
+
271
+ ### CLI tools
272
+
273
+ The library includes a CLI for managing the inference cache.
274
+
275
+ _List stored sequences._
276
+
277
+ ```shell
278
+ evaluators memory ls ./inference_cache
279
+ ```
280
+
281
+ _Inspect specific tensor shapes._
282
+
283
+ ```shell
284
+ evaluators memory inspect ./inference_cache frankfurt_000001
285
+ ```
286
+
287
+ _Export to standard PyTorch file._
288
+
289
+ ```shell
290
+ evaluators memory export ./inference_cache frankfurt_000001 --out my_video.pt
291
+ ```
292
+
293
+ ---
294
+
295
+ ## Supported metrics
296
+
297
+ ### Depth estimation
298
+
299
+ Implements standard error metrics (AbsRel, SqRel, RMSE, RMSElog) and threshold accuracies ($\delta < 1.25^n$).
300
+
301
+ ### Segmentation
302
+
303
+ - _Semantic:_ Mean intersection over union (mIoU).
304
+ - _Panoptic:_ Panoptic quality (PQ), segmentation quality (SQ), recognition quality (RQ). Supports "Thing" and "Stuff" splits.
305
+
306
+ ### Depth-aware video panoptic segmentation (DVPS)
307
+
308
+ Implements VPQ (video panoptic quality) and its depth-aware extension, DVPQ. Both evaluate spatio-temporal consistency using sliding window tubes over consecutive frames; DVPQ additionally gates matches by pixel-wise depth accuracy against one or more relative-error thresholds.
309
+
310
+ ### Tracking
311
+
312
+ Multi-object tracking metrics: HOTA, CLEAR (MOTA/MOTP), and identity F1 (IDF1). Assignment (frame-level detection-to-track matching) is solved by `torchmatch` rather than `scipy.optimize.linear_sum_assignment`; see [OFFLINE_EVALUATION.md](OFFLINE_EVALUATION.md) for the migration note.
313
+
314
+ ### STEP
315
+
316
+ Segmentation and tracking quality (STQ), and its depth-aware variant (DSTQ).
317
+
318
+ ### Occupancy
319
+
320
+ Per-class IoU/mIoU and occupied-vs-free precision/recall/F1 over voxel-grid occupancy predictions, reusing the same statistics as `SemanticMetric`. `OccupancyMetric` (`evaluators.metrics.domain.occupancy`).
321
+
322
+ ### 3D detection
323
+
324
+ Per-class, per-threshold average precision (AP) and mAP over 3D bounding boxes. Matching is a pluggable strategy (`IoU3DSimilarity`, backed by Shapely polygon intersection, or `CenterDistanceSimilarity`, the nuScenes convention), and curve integration is a pluggable rule (COCO's 101-point, KITTI's 40-point, or nuScenes' clipped-recall convention). Optional true-positive error decomposition (mATE, mAOE) and an orientation-aware AOS aggregate. `Box3DAveragePrecisionMetric` (`evaluators.metrics.domain.box3d`).
325
+
326
+ ### Vector maps
327
+
328
+ Per-class, per-threshold AP and mAP over polylines (lane/vector-map elements), matched by a pluggable similarity strategy (`ChamferSimilarity` or `FrechetSimilarity`) and integrated by the same curve-integration rules as 3D detection. Optional topology accuracy over the matched polyline graph. `PolylineAveragePrecisionMetric` (`evaluators.metrics.domain.vectormap`).
329
+
330
+ ### Sensor simulation
331
+
332
+ Paired reference-vs-simulated quality for images, point clouds, and radar (`SensorImageQualityMetric`, `PointCloudQualityMetric`, `RadarQualityMetric`), plus single-stream self-consistency metrics that need no paired reference (`TemporalConsistencyMetric`, `CrossModalAlignmentMetric`). All five live under `evaluators.metrics.domain.sensorsim`.
333
+
334
+ > As with `SemanticMetric`/`PanopticQualityMetric`, none of the classes above are re-exported from the top-level `evaluators` package; import them from their domain submodule as shown.
335
+
336
+ ---
337
+
338
+ ## Architecture
339
+
340
+ Reassembling whole sequences out of frames scattered across steps and ranks
341
+ takes three stages, run automatically by `DistributedEvaluationCallback`
342
+ during validation, or manually via the CLI.
343
+
344
+ 1. **Write.**
345
+ Each GPU writes predictions to locally sharded files (e.g. `.memmap` or `.lmdb`). No communication occurs.
346
+ 2. **Schedule.**
347
+ A synchronization barrier is reached. The main process aggregates metadata manifests from all shards to build a Global Catalog. It partitions the workload (videos, not individual frames) among workers using a greedy strategy to balance duration, so each worker gets complete, ordered sequences.
348
+ 3. **Compute.**
349
+ Workers iterate through their assigned Virtual Sequences. Data is streamed from disk, processed by torchmetrics, and reduced globally.
350
+
351
+ See [OFFLINE_EVALUATION.md](OFFLINE_EVALUATION.md) for driving this manually via the CLI (`compute`, plus `results`, `memory`, and `visualize` for reading, inspecting, and rendering stored predictions), and detailed design principles.
352
+
353
+ ---
354
+
355
+ ## Performance
356
+
357
+ `evaluators` is built for high-throughput I/O. The following benchmarks were conducted using the **Comprehensive Memory Evaluation Suite (CMES)** on a mobile workstation (i7-12700H, NVMe SSD).
358
+
359
+ ### Throughput (FPS)
360
+
361
+ | Backend | Codec | Resolution | Write FPS | Read FPS | Compression |
362
+ | :--- | :--- | :--- | :--- | :--- | :--- |
363
+ | **Memmap** | Raw | 512x1024 | 250.8 | 501.6 | 1.0x |
364
+ | **Memmap** | Blosc | 512x1024 | 59.7 | 119.3 | 0.85x |
365
+ | **LMDB** | Raw | 512x1024 | 13.3 | 26.7 | 1.0x |
366
+ | **LMDB** | PNG | 512x1024 | 27.2 | 13.6 | 0.62x |
367
+ | **Filesystem**| TIFF | 512x1024 | 124.9 | 249.7 | 0.89x |
368
+
369
+ ### Insights
370
+
371
+ - **Memmap is king for raw throughput:** The `MemmapTemporalWriter` achieves >500 FPS for read operations on mid-resolution video frames, making it ideal for fast metric computation.
372
+ - **Blosc provides the best balance:** Using `BloscCodec` with `Memmap` offers significant storage savings with minimal CPU overhead compared to PNG/TIFF.
373
+ - **LMDB for stability:** While slower for sequential video access, LMDB provides robust ACID compliance and is preferred for random-access metadata or small feature vectors.
374
+
375
+ > Full benchmark reports, including memory usage (Peak RSS) and CPU overhead plots, are available in `docs-assets/benchmarks/` (published at `/benchmarks/` on the docs site).
376
+
377
+ ---
378
+
379
+ ## Development
380
+
381
+ This project uses modern Python tooling for dependency management and quality assurance.
382
+
383
+ ### Setup
384
+
385
+ We use `uv` for fast dependency management.
386
+
387
+ ```shell
388
+ # Install dependencies
389
+ uv sync --all-extras
390
+ ```
391
+
392
+ ### Testing
393
+
394
+ Tests are managed by `pytest`.
395
+
396
+ ```shell
397
+ # Run all tests
398
+ uv run pytest
399
+
400
+ # Run with coverage
401
+ uv run pytest --cov=evaluators
402
+ ```
403
+
404
+ ### Linting & Formatting
405
+
406
+ We use `ruff` for all linting and formatting needs.
407
+
408
+ ```shell
409
+ # Check code style
410
+ uv run ruff check .
411
+
412
+ # Format code
413
+ uv run ruff format .
414
+ ```
415
+
416
+ ---
417
+
418
+ ## Contributing
419
+
420
+ Contributions are welcome. Please ensure that:
421
+
422
+ 1. New features are covered by tests.
423
+ 2. Code passes all static analysis checks (`ruff`).
424
+ 3. Architecture changes are discussed in an issue first.
425
+
426
+ ## Acknowledgements
427
+
428
+ This work was developed at the Mobile Perception Systems (MPS) lab at Eindhoven University of Technology.
429
+
430
+ ## License
431
+
432
+ This project is licensed under the MIT License.