evaluators 1.0.3__tar.gz → 2.0.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.
- evaluators-2.0.0/PKG-INFO +279 -0
- evaluators-2.0.0/README.md +247 -0
- evaluators-2.0.0/pyproject.toml +123 -0
- evaluators-2.0.0/sources/evaluators/__init__.py +59 -0
- evaluators-2.0.0/sources/evaluators/_engine.py +329 -0
- evaluators-2.0.0/sources/evaluators/_streams.py +236 -0
- evaluators-2.0.0/sources/evaluators/cli/__main__.py +92 -0
- evaluators-2.0.0/sources/evaluators/cli/memory.py +371 -0
- evaluators-2.0.0/sources/evaluators/constants.py +19 -0
- evaluators-2.0.0/sources/evaluators/integrations/pl.py +198 -0
- evaluators-2.0.0/sources/evaluators/memory/__init__.py +43 -0
- evaluators-2.0.0/sources/evaluators/memory/encoded_memmap/__init__.py +13 -0
- evaluators-2.0.0/sources/evaluators/memory/encoded_memmap/_reader.py +176 -0
- evaluators-2.0.0/sources/evaluators/memory/encoded_memmap/_writer.py +196 -0
- evaluators-2.0.0/sources/evaluators/memory/interfaces.py +92 -0
- evaluators-2.0.0/sources/evaluators/memory/lmdb/__init__.py +13 -0
- evaluators-2.0.0/sources/evaluators/memory/lmdb/_reader.py +195 -0
- evaluators-2.0.0/sources/evaluators/memory/lmdb/_writer.py +180 -0
- evaluators-2.0.0/sources/evaluators/memory/memmap/__init__.py +13 -0
- evaluators-2.0.0/sources/evaluators/memory/memmap/_buffers.py +194 -0
- evaluators-2.0.0/sources/evaluators/memory/memmap/_reader.py +218 -0
- evaluators-2.0.0/sources/evaluators/memory/memmap/_writer.py +272 -0
- evaluators-2.0.0/sources/evaluators/memory/schema.py +60 -0
- evaluators-2.0.0/sources/evaluators/memory/utils/encoding.py +102 -0
- evaluators-2.0.0/sources/evaluators/metrics/__init__.py +0 -0
- evaluators-2.0.0/sources/evaluators/metrics/adapters/coco.py +0 -0
- evaluators-2.0.0/sources/evaluators/metrics/adapters/trackeval.py +0 -0
- evaluators-2.0.0/sources/evaluators/metrics/domain/depth.py +621 -0
- evaluators-2.0.0/sources/evaluators/metrics/domain/dvps.py +828 -0
- evaluators-2.0.0/sources/evaluators/metrics/domain/segmentation/__init__.py +33 -0
- evaluators-2.0.0/sources/evaluators/metrics/domain/segmentation/_utils.py +328 -0
- evaluators-2.0.0/sources/evaluators/metrics/domain/segmentation/panoptic.py +829 -0
- evaluators-2.0.0/sources/evaluators/metrics/domain/segmentation/semantic.py +359 -0
- evaluators-2.0.0/sources/evaluators/metrics/domain/step.py +391 -0
- evaluators-2.0.0/sources/evaluators/metrics/domain/tracking.py +0 -0
- evaluators-2.0.0/sources/evaluators/metrics/stats.py +120 -0
- evaluators-2.0.0/sources/evaluators/presets/__init__.py +16 -0
- evaluators-2.0.0/sources/evaluators/presets/cityscapes.py +149 -0
- evaluators-2.0.0/sources/evaluators/presets/kitti.py +43 -0
- evaluators-2.0.0/sources/evaluators/presets/semkitti.py +139 -0
- evaluators-2.0.0/sources/evaluators/scheduling/__init__.py +25 -0
- evaluators-2.0.0/sources/evaluators/scheduling/_catalog.py +119 -0
- evaluators-2.0.0/sources/evaluators/scheduling/_partitioner.py +115 -0
- evaluators-2.0.0/sources/evaluators/types.py +318 -0
- evaluators-2.0.0/sources/evaluators/utils/comms.py +81 -0
- evaluators-2.0.0/sources/evaluators/utils/tensor_ops.py +130 -0
- evaluators-2.0.0/sources/evaluators/visuals/__init__.py +7 -0
- evaluators-2.0.0/sources/evaluators/visuals/metric.py +283 -0
- evaluators-2.0.0/sources/evaluators/visuals/tools/__init__.py +9 -0
- evaluators-2.0.0/sources/evaluators/visuals/tools/_visualizer.py +807 -0
- evaluators-2.0.0/sources/evaluators/visuals/tools/transform.py +177 -0
- evaluators-1.0.3/LICENSE +0 -21
- evaluators-1.0.3/PKG-INFO +0 -34
- evaluators-1.0.3/README.md +0 -17
- evaluators-1.0.3/pyproject.toml +0 -244
- evaluators-1.0.3/setup.cfg +0 -4
- evaluators-1.0.3/sources/evaluators/__init__.py +0 -11
- evaluators-1.0.3/sources/evaluators/_abc.py +0 -38
- evaluators-1.0.3/sources/evaluators/_shm.py +0 -132
- evaluators-1.0.3/sources/evaluators/_types.py +0 -6
- evaluators-1.0.3/sources/evaluators/_utils.py +0 -44
- evaluators-1.0.3/sources/evaluators/base_evaluator.py +0 -36
- evaluators-1.0.3/sources/evaluators/depth.py +0 -317
- evaluators-1.0.3/sources/evaluators/dvps.py +0 -500
- evaluators-1.0.3/sources/evaluators/panseg.py +0 -409
- evaluators-1.0.3/sources/evaluators/step.py +0 -573
- evaluators-1.0.3/sources/evaluators.egg-info/PKG-INFO +0 -34
- evaluators-1.0.3/sources/evaluators.egg-info/SOURCES.txt +0 -21
- evaluators-1.0.3/sources/evaluators.egg-info/dependency_links.txt +0 -1
- evaluators-1.0.3/sources/evaluators.egg-info/requires.txt +0 -26
- evaluators-1.0.3/sources/evaluators.egg-info/top_level.txt +0 -1
- evaluators-1.0.3/tests/test_depth.py +0 -12
- evaluators-1.0.3/tests/test_dvps.py +0 -128
- evaluators-1.0.3/tests/test_step.py +0 -170
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: evaluators
|
|
3
|
+
Version: 2.0.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 :: 5 - Production/Stable
|
|
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: lmdb
|
|
27
|
+
Requires-Dist: tifffile
|
|
28
|
+
Requires-Dist: pydantic
|
|
29
|
+
Requires-Dist: opencv-python>=4.13.0.92
|
|
30
|
+
Requires-Python: >=3.13, <3.14
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
|
|
33
|
+
# Scalable Distributed Evaluation for Computer Vision
|
|
34
|
+
|
|
35
|
+
[](https://pypi.org/project/evaluators/)
|
|
36
|
+
[](https://pypi.org/project/evaluators/)
|
|
37
|
+
[](https://github.com/khwstolle/evaluators/blob/main/LICENSE)
|
|
38
|
+
[](https://github.com/khwstolle/evaluators/actions)
|
|
39
|
+
|
|
40
|
+
Evaluators is a high-throughput evaluation framework designed for large-scale computer vision research. It specializes in handling video tasks by decoupling inference I/O from metric computation.
|
|
41
|
+
|
|
42
|
+
This architecture enables offline evaluation workflows: models stream predictions to efficient storage backends (Memory Map or LMDB) during inference, and metrics are computed in a decoupled stage using distributed map-reduce logic. This approach prevents CPU-bound metric calculation from throttling GPU inference.
|
|
43
|
+
|
|
44
|
+
The key features are:
|
|
45
|
+
|
|
46
|
+
- **Zero-overhead inference.**
|
|
47
|
+
Writes predictions to disk using non-blocking I/O, allowing the training loop to run at full GPU utilization.
|
|
48
|
+
|
|
49
|
+
- **Distributed by design.**
|
|
50
|
+
Automatically handles synchronization across multiple nodes and GPUs using `torchmetrics` and custom scheduling logic.
|
|
51
|
+
|
|
52
|
+
- **Explicit Memory Schemas.**
|
|
53
|
+
Uses Pydantic-based schemas to define data formats and encodings (PNG, TIFF, Raw) up front, ensuring type safety and storage efficiency.
|
|
54
|
+
|
|
55
|
+
- **Lazy loading.**
|
|
56
|
+
Supports referencing ground truth data from disk rather than duplicating it in memory caches, enabling evaluation of terabyte-scale datasets.
|
|
57
|
+
|
|
58
|
+
- **Multi-domain.**
|
|
59
|
+
Includes verified implementations for:
|
|
60
|
+
- Segmentation: Panoptic quality (PQ), semantic mIoU.
|
|
61
|
+
- DVPS: Depth-aware video panoptic quality (DVPQ).
|
|
62
|
+
- Depth: Eigen et al. metrics (AbsRel, RMSE).
|
|
63
|
+
|
|
64
|
+
- **CLI.**
|
|
65
|
+
A command-line interface to inspect, index, and query saved inference results.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Installation
|
|
70
|
+
|
|
71
|
+
```shell
|
|
72
|
+
pip install evaluators
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Quick start
|
|
76
|
+
|
|
77
|
+
### Python API
|
|
78
|
+
|
|
79
|
+
The core abstractions are `MetricStream` (for writing) and `run_offline_evaluation` (for computing).
|
|
80
|
+
|
|
81
|
+
#### Step 1: Inference (online)
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
import torch
|
|
85
|
+
from evaluators import MetricStream, MemorySchema, TensorField, DynamicTemporalWriter
|
|
86
|
+
from evaluators.metrics.domain.segmentation import SemanticMetric
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
##### 1. Configure metrics and schema
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
### Define the source for ground truth (lazy loading)
|
|
93
|
+
|
|
94
|
+
dataset = CityscapesDataset(...)
|
|
95
|
+
metric = SemanticMetric(
|
|
96
|
+
num_classes=19,
|
|
97
|
+
target_source=dataset,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
### Define the explicit memory schema
|
|
101
|
+
|
|
102
|
+
schema = MemorySchema(fields={
|
|
103
|
+
"sem_seg": TensorField(dtype="int64", shape=(1024, 2048)),
|
|
104
|
+
"sequence_id": TensorField(dtype="int64", shape=()),
|
|
105
|
+
"frame_index": TensorField(dtype="int64", shape=()),
|
|
106
|
+
})
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
##### 2. Initialize stream and writer
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
# Create a writer (backend)
|
|
113
|
+
writer = DynamicTemporalWriter(output_dir="./inference_cache/stream_1", schema=schema)
|
|
114
|
+
|
|
115
|
+
# Create a stream and bind the writer
|
|
116
|
+
stream = MetricStream(
|
|
117
|
+
metrics=[metric],
|
|
118
|
+
name="semantic",
|
|
119
|
+
schema=schema
|
|
120
|
+
)
|
|
121
|
+
stream.bind(writer)
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
##### 3. Run inference loop
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
for batch in dataloader: # Model forward pass
|
|
128
|
+
preds = model(batch["image"])
|
|
129
|
+
|
|
130
|
+
# Push to stream (non-blocking)
|
|
131
|
+
stream.update(
|
|
132
|
+
batch={
|
|
133
|
+
"sem_seg": preds,
|
|
134
|
+
"sequence_id": batch["sequence_id"],
|
|
135
|
+
"frame_index": batch["frame_index"]
|
|
136
|
+
}
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
# Finalize
|
|
140
|
+
writer.close()
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
> Note: `sequence_id` and `frame_index` must be `torch.int64`.
|
|
144
|
+
|
|
145
|
+
##### 4. Finalize and compute
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
from evaluators import run_offline_evaluation
|
|
149
|
+
|
|
150
|
+
# Syncs workers, builds catalog, and runs metrics
|
|
151
|
+
results = run_offline_evaluation(
|
|
152
|
+
metrics=[metric],
|
|
153
|
+
artifact_dir="./inference_cache/semantic"
|
|
154
|
+
)
|
|
155
|
+
print(results["SemanticMetric"]["mIoU"])
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
#### Step 2: Re-evaluation (offline)
|
|
159
|
+
|
|
160
|
+
Because predictions are persisted, metrics can be re-calculated or added without re-running the model.
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
# Run evaluation on existing artifacts
|
|
164
|
+
results = run_offline_evaluation(
|
|
165
|
+
metrics=[new_metric],
|
|
166
|
+
artifact_dir="./inference_cache/semantic"
|
|
167
|
+
)
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### CLI tools
|
|
171
|
+
|
|
172
|
+
The library includes a CLI for managing the inference cache.
|
|
173
|
+
|
|
174
|
+
_List stored sequences._
|
|
175
|
+
|
|
176
|
+
```shell
|
|
177
|
+
evaluators memory ls ./inference_cache
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
_Inspect specific tensor shapes._
|
|
181
|
+
|
|
182
|
+
```shell
|
|
183
|
+
evaluators memory inspect ./inference_cache --sequence_id frankfurt_000001
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
_Export to standard PyTorch file._
|
|
187
|
+
|
|
188
|
+
```shell
|
|
189
|
+
evaluators memory export ./inference_cache --sequence_id frankfurt_000001 --out my_video.pt
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## Supported metrics
|
|
195
|
+
|
|
196
|
+
### Depth estimation
|
|
197
|
+
|
|
198
|
+
Implements standard error metrics (AbsRel, SqRel, RMSE, RMSElog) and threshold accuracies ($\delta < 1.25^n$).
|
|
199
|
+
|
|
200
|
+
### Segmentation
|
|
201
|
+
|
|
202
|
+
- _Semantic:_ Mean intersection over union (mIoU).
|
|
203
|
+
- _Panoptic:_ Panoptic quality (PQ), segmentation quality (SQ), recognition quality (RQ). Supports "Thing" and "Stuff" splits.
|
|
204
|
+
|
|
205
|
+
### Depth-aware video panoptic segmentation (DVPS)
|
|
206
|
+
|
|
207
|
+
Implements DVPQ (Depth-aware video panoptic quality). This metric evaluates spatio-temporal consistency using sliding window tubes, gated by pixel-wise depth accuracy.
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Architecture
|
|
212
|
+
|
|
213
|
+
The evaluation pipeline consists of three stages.
|
|
214
|
+
|
|
215
|
+
1. **Write.**
|
|
216
|
+
Each GPU writes predictions to locally sharded files (e.g. `.memmap` or `.lmdb`). No communication occurs.
|
|
217
|
+
2. **Schedule.**
|
|
218
|
+
A synchronization barrier is reached. The main process aggregates metadata manifests from all shards to build a Global Catalog. It partitions the workload (videos) among workers using a greedy strategy to balance duration.
|
|
219
|
+
3. **Compute.**
|
|
220
|
+
Workers iterate through their assigned Virtual Sequences. Data is streamed from disk, processed by torchmetrics, and reduced globally.
|
|
221
|
+
|
|
222
|
+
See [ARCHITECTURE.md](ARCHITECTURE.md) for detailed diagrams and design principles.
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## Development
|
|
227
|
+
|
|
228
|
+
This project uses modern Python tooling for dependency management and quality assurance.
|
|
229
|
+
|
|
230
|
+
### Setup
|
|
231
|
+
|
|
232
|
+
We use `uv` for fast dependency management.
|
|
233
|
+
|
|
234
|
+
```shell
|
|
235
|
+
# Install dependencies
|
|
236
|
+
uv sync --all-extras
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Testing
|
|
240
|
+
|
|
241
|
+
Tests are managed by `pytest`.
|
|
242
|
+
|
|
243
|
+
```shell
|
|
244
|
+
# Run all tests
|
|
245
|
+
uv run pytest
|
|
246
|
+
|
|
247
|
+
# Run with coverage
|
|
248
|
+
uv run pytest --cov=evaluators
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Linting & Formatting
|
|
252
|
+
|
|
253
|
+
We use `ruff` for all linting and formatting needs.
|
|
254
|
+
|
|
255
|
+
```shell
|
|
256
|
+
# Check code style
|
|
257
|
+
uv run ruff check .
|
|
258
|
+
|
|
259
|
+
# Format code
|
|
260
|
+
uv run ruff format .
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## Contributing
|
|
266
|
+
|
|
267
|
+
Contributions are welcome. Please ensure that:
|
|
268
|
+
|
|
269
|
+
1. New features are covered by tests.
|
|
270
|
+
2. Code passes all static analysis checks (`ruff`).
|
|
271
|
+
3. Architecture changes are discussed in an issue first.
|
|
272
|
+
|
|
273
|
+
## Acknowledgements
|
|
274
|
+
|
|
275
|
+
This work was developed at the Mobile Perception Systems (MPS) lab at Eindhoven University of Technology.
|
|
276
|
+
|
|
277
|
+
## License
|
|
278
|
+
|
|
279
|
+
This project is licensed under the MIT License.
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
# Scalable Distributed Evaluation for Computer Vision
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/evaluators/)
|
|
4
|
+
[](https://pypi.org/project/evaluators/)
|
|
5
|
+
[](https://github.com/khwstolle/evaluators/blob/main/LICENSE)
|
|
6
|
+
[](https://github.com/khwstolle/evaluators/actions)
|
|
7
|
+
|
|
8
|
+
Evaluators is a high-throughput evaluation framework designed for large-scale computer vision research. It specializes in handling video tasks by decoupling inference I/O from metric computation.
|
|
9
|
+
|
|
10
|
+
This architecture enables offline evaluation workflows: models stream predictions to efficient storage backends (Memory Map or LMDB) during inference, and metrics are computed in a decoupled stage using distributed map-reduce logic. This approach prevents CPU-bound metric calculation from throttling GPU inference.
|
|
11
|
+
|
|
12
|
+
The key features are:
|
|
13
|
+
|
|
14
|
+
- **Zero-overhead inference.**
|
|
15
|
+
Writes predictions to disk using non-blocking I/O, allowing the training loop to run at full GPU utilization.
|
|
16
|
+
|
|
17
|
+
- **Distributed by design.**
|
|
18
|
+
Automatically handles synchronization across multiple nodes and GPUs using `torchmetrics` and custom scheduling logic.
|
|
19
|
+
|
|
20
|
+
- **Explicit Memory Schemas.**
|
|
21
|
+
Uses Pydantic-based schemas to define data formats and encodings (PNG, TIFF, Raw) up front, ensuring type safety and storage efficiency.
|
|
22
|
+
|
|
23
|
+
- **Lazy loading.**
|
|
24
|
+
Supports referencing ground truth data from disk rather than duplicating it in memory caches, enabling evaluation of terabyte-scale datasets.
|
|
25
|
+
|
|
26
|
+
- **Multi-domain.**
|
|
27
|
+
Includes verified implementations for:
|
|
28
|
+
- Segmentation: Panoptic quality (PQ), semantic mIoU.
|
|
29
|
+
- DVPS: Depth-aware video panoptic quality (DVPQ).
|
|
30
|
+
- Depth: Eigen et al. metrics (AbsRel, RMSE).
|
|
31
|
+
|
|
32
|
+
- **CLI.**
|
|
33
|
+
A command-line interface to inspect, index, and query saved inference results.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Installation
|
|
38
|
+
|
|
39
|
+
```shell
|
|
40
|
+
pip install evaluators
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Quick start
|
|
44
|
+
|
|
45
|
+
### Python API
|
|
46
|
+
|
|
47
|
+
The core abstractions are `MetricStream` (for writing) and `run_offline_evaluation` (for computing).
|
|
48
|
+
|
|
49
|
+
#### Step 1: Inference (online)
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
import torch
|
|
53
|
+
from evaluators import MetricStream, MemorySchema, TensorField, DynamicTemporalWriter
|
|
54
|
+
from evaluators.metrics.domain.segmentation import SemanticMetric
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
##### 1. Configure metrics and schema
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
### Define the source for ground truth (lazy loading)
|
|
61
|
+
|
|
62
|
+
dataset = CityscapesDataset(...)
|
|
63
|
+
metric = SemanticMetric(
|
|
64
|
+
num_classes=19,
|
|
65
|
+
target_source=dataset,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
### Define the explicit memory schema
|
|
69
|
+
|
|
70
|
+
schema = MemorySchema(fields={
|
|
71
|
+
"sem_seg": TensorField(dtype="int64", shape=(1024, 2048)),
|
|
72
|
+
"sequence_id": TensorField(dtype="int64", shape=()),
|
|
73
|
+
"frame_index": TensorField(dtype="int64", shape=()),
|
|
74
|
+
})
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
##### 2. Initialize stream and writer
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
# Create a writer (backend)
|
|
81
|
+
writer = DynamicTemporalWriter(output_dir="./inference_cache/stream_1", schema=schema)
|
|
82
|
+
|
|
83
|
+
# Create a stream and bind the writer
|
|
84
|
+
stream = MetricStream(
|
|
85
|
+
metrics=[metric],
|
|
86
|
+
name="semantic",
|
|
87
|
+
schema=schema
|
|
88
|
+
)
|
|
89
|
+
stream.bind(writer)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
##### 3. Run inference loop
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
for batch in dataloader: # Model forward pass
|
|
96
|
+
preds = model(batch["image"])
|
|
97
|
+
|
|
98
|
+
# Push to stream (non-blocking)
|
|
99
|
+
stream.update(
|
|
100
|
+
batch={
|
|
101
|
+
"sem_seg": preds,
|
|
102
|
+
"sequence_id": batch["sequence_id"],
|
|
103
|
+
"frame_index": batch["frame_index"]
|
|
104
|
+
}
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
# Finalize
|
|
108
|
+
writer.close()
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
> Note: `sequence_id` and `frame_index` must be `torch.int64`.
|
|
112
|
+
|
|
113
|
+
##### 4. Finalize and compute
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
from evaluators import run_offline_evaluation
|
|
117
|
+
|
|
118
|
+
# Syncs workers, builds catalog, and runs metrics
|
|
119
|
+
results = run_offline_evaluation(
|
|
120
|
+
metrics=[metric],
|
|
121
|
+
artifact_dir="./inference_cache/semantic"
|
|
122
|
+
)
|
|
123
|
+
print(results["SemanticMetric"]["mIoU"])
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
#### Step 2: Re-evaluation (offline)
|
|
127
|
+
|
|
128
|
+
Because predictions are persisted, metrics can be re-calculated or added without re-running the model.
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
# Run evaluation on existing artifacts
|
|
132
|
+
results = run_offline_evaluation(
|
|
133
|
+
metrics=[new_metric],
|
|
134
|
+
artifact_dir="./inference_cache/semantic"
|
|
135
|
+
)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### CLI tools
|
|
139
|
+
|
|
140
|
+
The library includes a CLI for managing the inference cache.
|
|
141
|
+
|
|
142
|
+
_List stored sequences._
|
|
143
|
+
|
|
144
|
+
```shell
|
|
145
|
+
evaluators memory ls ./inference_cache
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
_Inspect specific tensor shapes._
|
|
149
|
+
|
|
150
|
+
```shell
|
|
151
|
+
evaluators memory inspect ./inference_cache --sequence_id frankfurt_000001
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
_Export to standard PyTorch file._
|
|
155
|
+
|
|
156
|
+
```shell
|
|
157
|
+
evaluators memory export ./inference_cache --sequence_id frankfurt_000001 --out my_video.pt
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Supported metrics
|
|
163
|
+
|
|
164
|
+
### Depth estimation
|
|
165
|
+
|
|
166
|
+
Implements standard error metrics (AbsRel, SqRel, RMSE, RMSElog) and threshold accuracies ($\delta < 1.25^n$).
|
|
167
|
+
|
|
168
|
+
### Segmentation
|
|
169
|
+
|
|
170
|
+
- _Semantic:_ Mean intersection over union (mIoU).
|
|
171
|
+
- _Panoptic:_ Panoptic quality (PQ), segmentation quality (SQ), recognition quality (RQ). Supports "Thing" and "Stuff" splits.
|
|
172
|
+
|
|
173
|
+
### Depth-aware video panoptic segmentation (DVPS)
|
|
174
|
+
|
|
175
|
+
Implements DVPQ (Depth-aware video panoptic quality). This metric evaluates spatio-temporal consistency using sliding window tubes, gated by pixel-wise depth accuracy.
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## Architecture
|
|
180
|
+
|
|
181
|
+
The evaluation pipeline consists of three stages.
|
|
182
|
+
|
|
183
|
+
1. **Write.**
|
|
184
|
+
Each GPU writes predictions to locally sharded files (e.g. `.memmap` or `.lmdb`). No communication occurs.
|
|
185
|
+
2. **Schedule.**
|
|
186
|
+
A synchronization barrier is reached. The main process aggregates metadata manifests from all shards to build a Global Catalog. It partitions the workload (videos) among workers using a greedy strategy to balance duration.
|
|
187
|
+
3. **Compute.**
|
|
188
|
+
Workers iterate through their assigned Virtual Sequences. Data is streamed from disk, processed by torchmetrics, and reduced globally.
|
|
189
|
+
|
|
190
|
+
See [ARCHITECTURE.md](ARCHITECTURE.md) for detailed diagrams and design principles.
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## Development
|
|
195
|
+
|
|
196
|
+
This project uses modern Python tooling for dependency management and quality assurance.
|
|
197
|
+
|
|
198
|
+
### Setup
|
|
199
|
+
|
|
200
|
+
We use `uv` for fast dependency management.
|
|
201
|
+
|
|
202
|
+
```shell
|
|
203
|
+
# Install dependencies
|
|
204
|
+
uv sync --all-extras
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Testing
|
|
208
|
+
|
|
209
|
+
Tests are managed by `pytest`.
|
|
210
|
+
|
|
211
|
+
```shell
|
|
212
|
+
# Run all tests
|
|
213
|
+
uv run pytest
|
|
214
|
+
|
|
215
|
+
# Run with coverage
|
|
216
|
+
uv run pytest --cov=evaluators
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Linting & Formatting
|
|
220
|
+
|
|
221
|
+
We use `ruff` for all linting and formatting needs.
|
|
222
|
+
|
|
223
|
+
```shell
|
|
224
|
+
# Check code style
|
|
225
|
+
uv run ruff check .
|
|
226
|
+
|
|
227
|
+
# Format code
|
|
228
|
+
uv run ruff format .
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## Contributing
|
|
234
|
+
|
|
235
|
+
Contributions are welcome. Please ensure that:
|
|
236
|
+
|
|
237
|
+
1. New features are covered by tests.
|
|
238
|
+
2. Code passes all static analysis checks (`ruff`).
|
|
239
|
+
3. Architecture changes are discussed in an issue first.
|
|
240
|
+
|
|
241
|
+
## Acknowledgements
|
|
242
|
+
|
|
243
|
+
This work was developed at the Mobile Perception Systems (MPS) lab at Eindhoven University of Technology.
|
|
244
|
+
|
|
245
|
+
## License
|
|
246
|
+
|
|
247
|
+
This project is licensed under the MIT License.
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["uv_build>=0.9.28,<0.10.0"]
|
|
3
|
+
build-backend = "uv_build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "evaluators"
|
|
7
|
+
version = "2.0.0"
|
|
8
|
+
description = "Various scene understanding and perception evaluation metrics."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.13, <3.14"
|
|
11
|
+
authors = [{ name = "Kurt Stolle", email = "kurt@computer.org" }]
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Development Status :: 5 - Production/Stable",
|
|
14
|
+
"Intended Audience :: Developers",
|
|
15
|
+
"Intended Audience :: Science/Research",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
18
|
+
"Topic :: Scientific/Engineering :: Image Recognition",
|
|
19
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
20
|
+
"Programming Language :: Python",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Programming Language :: Python :: 3.13",
|
|
24
|
+
"Operating System :: OS Independent",
|
|
25
|
+
]
|
|
26
|
+
dependencies = [
|
|
27
|
+
"torch>2.7",
|
|
28
|
+
"torchvision",
|
|
29
|
+
"torchmetrics",
|
|
30
|
+
"tensordict>=0.11.0",
|
|
31
|
+
"numpy>=2.0.0",
|
|
32
|
+
"matplotlib>=3.9.0",
|
|
33
|
+
"rich>=13.9.4",
|
|
34
|
+
"lmdb",
|
|
35
|
+
"tifffile",
|
|
36
|
+
"pydantic",
|
|
37
|
+
"opencv-python>=4.13.0.92",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[dependency-groups]
|
|
41
|
+
dev = [
|
|
42
|
+
"hypothesis>=6.140.2",
|
|
43
|
+
"nbstripout>=0.9.0",
|
|
44
|
+
"pre-commit>=4.5.1",
|
|
45
|
+
"pytest>=8.4.2",
|
|
46
|
+
"pytest-benchmark>=5.1.0",
|
|
47
|
+
"pytest-cov>=7.0.0",
|
|
48
|
+
"pytest-mock>=3.15.1",
|
|
49
|
+
"pytest-runner>=6.0.1",
|
|
50
|
+
"pytest-sugar>=1.1.1",
|
|
51
|
+
"pytest-xdist>=3.8.0",
|
|
52
|
+
"ruff>=0.9.0",
|
|
53
|
+
"ipdb>=0.13.13",
|
|
54
|
+
"ty>=0.0.17",
|
|
55
|
+
"pytest-timeout>=2.4.0",
|
|
56
|
+
"uv-build>=0.10.9",
|
|
57
|
+
]
|
|
58
|
+
docs = ["numpydoc>=1.9.0", "sphinx>=8.2.3", "sphinx-rtd-theme>=3.0.2"]
|
|
59
|
+
notebooks = ["ipykernel>=6.30.1", "ipywidgets>=8.1.7", "jupyterlab>=4.4.9"]
|
|
60
|
+
|
|
61
|
+
[tool.ruff]
|
|
62
|
+
target-version = 'py313'
|
|
63
|
+
line-length = 88
|
|
64
|
+
|
|
65
|
+
[tool.ruff.lint]
|
|
66
|
+
select = [
|
|
67
|
+
"ARG", # flake8-unused-arguments
|
|
68
|
+
"B", # flake8-bugbear
|
|
69
|
+
"C", # mccabe
|
|
70
|
+
"C4", # flake8-comprehensions
|
|
71
|
+
#"DOC", # doclint
|
|
72
|
+
"D", # pydocstyle
|
|
73
|
+
"E", # pycodestyle
|
|
74
|
+
"EM", # flake8-errmsg
|
|
75
|
+
"F", # pyflakes
|
|
76
|
+
"FURB", # refurb
|
|
77
|
+
"G", # flake8-logging-format
|
|
78
|
+
"I", # isort
|
|
79
|
+
"ICN", # flake8-import-conventions
|
|
80
|
+
"N", # pep8-naming
|
|
81
|
+
"NPY", # NumPy specific rules
|
|
82
|
+
"PERF", # Perflint
|
|
83
|
+
"PGH", # pygrep-hooks
|
|
84
|
+
"PIE", # flake8-pie
|
|
85
|
+
"PL", # pylint
|
|
86
|
+
"PT", # flake8-pytest-style
|
|
87
|
+
"PTH", # flake8-use-pathlib
|
|
88
|
+
"PYI", # flake8-pyi
|
|
89
|
+
"RUF", # Ruff-specific rules
|
|
90
|
+
"RET", # flake8-return
|
|
91
|
+
"SIM", # flake8-simplify
|
|
92
|
+
"T20", # flake8-print
|
|
93
|
+
"TRY", # Tryceratops
|
|
94
|
+
"UP", # pyupgrade
|
|
95
|
+
]
|
|
96
|
+
ignore = [
|
|
97
|
+
"PLR2004", # magic numbers
|
|
98
|
+
"PLW2901", # for loop variable overwritten
|
|
99
|
+
"D212",
|
|
100
|
+
"D203",
|
|
101
|
+
"D107", # docstring on __init__
|
|
102
|
+
]
|
|
103
|
+
|
|
104
|
+
[tool.ruff.lint.per-file-ignores]
|
|
105
|
+
"tests/*" = ["D", "T"]
|
|
106
|
+
|
|
107
|
+
[tool.ruff.format]
|
|
108
|
+
docstring-code-format = true
|
|
109
|
+
docstring-code-line-length = "dynamic"
|
|
110
|
+
|
|
111
|
+
[tool.uv.build-backend]
|
|
112
|
+
module-root = "sources"
|
|
113
|
+
module-name = ["evaluators"]
|
|
114
|
+
namespace = true
|
|
115
|
+
|
|
116
|
+
[tool.ty.environment]
|
|
117
|
+
root = ["./sources"]
|
|
118
|
+
|
|
119
|
+
[tool.ty.src]
|
|
120
|
+
include = ["sources", "tests", "notebooks", "scripts"]
|
|
121
|
+
|
|
122
|
+
[tool.pytest.ini_options]
|
|
123
|
+
timeout = 10
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Scalable Distributed Evaluation Library.
|
|
3
|
+
========================================
|
|
4
|
+
|
|
5
|
+
A high-throughput evaluation framework designed for modern Computer Vision
|
|
6
|
+
research. It specializes in handling large-scale video tasks (Tracking,
|
|
7
|
+
STEP, DVPS) by decoupling inference I/O from metric computation.
|
|
8
|
+
|
|
9
|
+
This library orchestrates a three-stage pipeline:
|
|
10
|
+
|
|
11
|
+
1. **Write:** High-speed, potentially sharded writing of inference outputs
|
|
12
|
+
to disk using memory-mapped buffers.
|
|
13
|
+
2. **Schedule:** Global indexing and load-balancing of video sequences
|
|
14
|
+
across distributed workers.
|
|
15
|
+
3. **Compute:** Lazy, streaming read access for standard metrics (HOTA, VPQ)
|
|
16
|
+
via virtual sequence views.
|
|
17
|
+
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from typing import TYPE_CHECKING
|
|
21
|
+
|
|
22
|
+
from ._engine import run_offline_evaluation
|
|
23
|
+
from ._streams import BackendInterface, MetricStream, UnboundStreamWarning
|
|
24
|
+
from .memory import (
|
|
25
|
+
EncodedMemmapTemporalWriter,
|
|
26
|
+
LMDBTemporalWriter,
|
|
27
|
+
MemorySchema,
|
|
28
|
+
MemmapTemporalWriter,
|
|
29
|
+
TensorField,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
if TYPE_CHECKING:
|
|
33
|
+
__version__: str
|
|
34
|
+
__all__ = [
|
|
35
|
+
"BackendInterface",
|
|
36
|
+
"EncodedMemmapTemporalWriter",
|
|
37
|
+
"LMDBTemporalWriter",
|
|
38
|
+
"MemorySchema",
|
|
39
|
+
"MemmapTemporalWriter",
|
|
40
|
+
"MetricStream",
|
|
41
|
+
"TensorField",
|
|
42
|
+
"UnboundStreamWarning",
|
|
43
|
+
"__version__",
|
|
44
|
+
"run_offline_evaluation",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# 2. Runtime Lazy Loader
|
|
49
|
+
def __getattr__(name: str) -> str:
|
|
50
|
+
if name == "__version__":
|
|
51
|
+
from importlib.metadata import PackageNotFoundError, version # noqa: PLC0415
|
|
52
|
+
|
|
53
|
+
try:
|
|
54
|
+
return version("evaluators")
|
|
55
|
+
except PackageNotFoundError:
|
|
56
|
+
return "unknown"
|
|
57
|
+
|
|
58
|
+
msg = f"module {__name__!r} has no attribute {name!r}"
|
|
59
|
+
raise AttributeError(msg)
|