euler-eval 2.29.0__tar.gz → 2.31.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.
- {euler_eval-2.29.0/euler_eval.egg-info → euler_eval-2.31.0}/PKG-INFO +4 -3
- {euler_eval-2.29.0 → euler_eval-2.31.0}/README.md +2 -1
- {euler_eval-2.29.0 → euler_eval-2.31.0}/docs/README.md +6 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/docs/alignment.md +2 -1
- {euler_eval-2.29.0 → euler_eval-2.31.0}/docs/cli.md +16 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/docs/configuration.md +77 -14
- euler_eval-2.31.0/docs/feature-request-unified-evaluation-framework.md +381 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/docs/metrics.md +82 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/docs/output.md +59 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/cli.py +430 -101
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/config_paths.py +78 -2
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/data.py +72 -46
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/evaluate.py +407 -10
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/metrics/__init__.py +18 -0
- euler_eval-2.31.0/euler_eval/metrics/sky_iou.py +167 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0/euler_eval.egg-info}/PKG-INFO +4 -3
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval.egg-info/SOURCES.txt +6 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval.egg-info/requires.txt +1 -1
- {euler_eval-2.29.0 → euler_eval-2.31.0}/pyproject.toml +2 -2
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/conftest.py +2 -2
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/test_config.py +148 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/test_data_builders.py +10 -5
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/test_depth_alignment_output.py +20 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/test_evaluate_helpers.py +48 -6
- euler_eval-2.31.0/tests/test_mask_sky_pairing.py +197 -0
- euler_eval-2.31.0/tests/test_mask_sky_prediction.py +239 -0
- euler_eval-2.31.0/tests/test_sky_iou.py +550 -0
- euler_eval-2.31.0/tests/test_sky_iou_cli.py +497 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/LICENSE +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/MANIFEST.in +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/docs/distributions.md +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/docs/validation.md +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/THIRD_PARTY_NOTICES.md +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/__init__.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/calibration.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/distribution_contract.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/distributions.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/metric_sets.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/metrics/_natural_scene_models.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/metrics/absrel.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/metrics/daniel_error.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/metrics/depth_binned_error.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/metrics/depth_edge_f1.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/metrics/depth_standard.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/metrics/fade.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/metrics/fid_kid.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/metrics/gpu_depth_batch.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/metrics/gpu_image_batch.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/metrics/high_freq_energy.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/metrics/lpips_metric.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/metrics/niqe.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/metrics/normal_consistency.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/metrics/points3d_cloud.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/metrics/points3d_decomposition.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/metrics/points3d_distance.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/metrics/points3d_geometry.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/metrics/psnr.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/metrics/rgb_edge_f1.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/metrics/rgb_lpips.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/metrics/rgb_psnr_ssim.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/metrics/rho_a.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/metrics/rmse.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/metrics/scale_invariant_log.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/metrics/ssim.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/metrics/tail_errors.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/metrics/utils.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/sanity_checker.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/schemas/distribution-v1.schema.json +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/utils/hierarchy_parser.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval/validation.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval.egg-info/dependency_links.txt +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval.egg-info/entry_points.txt +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/euler_eval.egg-info/top_level.txt +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/init_cache.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/scripts/generate_distribution_fixtures.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/setup.cfg +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/__init__.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/distribution_contract_utils.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/fixtures/distributions/README.md +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/fixtures/distributions/counts-depth.eval.json +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/fixtures/distributions/counts-points3d.eval.json +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/fixtures/distributions/counts-sparsedepth.eval.json +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/fixtures/distributions/future-sum-by-depth.eval.json +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/fixtures/distributions/histogram-only.eval.json +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/fixtures/distributions/per-file-only.eval.json +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/fixtures/distributions/scalar-only.eval.json +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/mock_files/calibration_output.json +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/mock_files/depth_output.json +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/mock_files/rgb_output.json +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/mock_files/segmentation_output.json +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/test_alignment.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/test_cli_device.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/test_cli_sparse_outputs.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/test_data.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/test_depth_standard.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/test_distribution_contract.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/test_distributions.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/test_domain_metrics.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/test_init_cache.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/test_integration.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/test_meta_output.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/test_metrics_utils.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/test_normal_consistency.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/test_points_3d.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/test_points_3d_sparse.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/test_rgb_fid_output.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/test_rho_a.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/test_save_results.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/test_sparse_depth.py +0 -0
- {euler_eval-2.29.0 → euler_eval-2.31.0}/tests/test_validation.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: euler-eval
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.31.0
|
|
4
4
|
Summary: Evaluation toolkit for depth, RGB, ray and 3D point-map predictions
|
|
5
5
|
Author-email: Daniel Rothenpieler <rothenpielerdaniel@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -33,7 +33,7 @@ Requires-Dist: opencv-python-headless>=4.5.0
|
|
|
33
33
|
Requires-Dist: lpips>=0.1.4
|
|
34
34
|
Requires-Dist: torchmetrics>=1.0
|
|
35
35
|
Requires-Dist: tqdm>=4.62.0
|
|
36
|
-
Requires-Dist: euler-loading>=2.
|
|
36
|
+
Requires-Dist: euler-loading>=2.29
|
|
37
37
|
Requires-Dist: ds-crawler>=2.10
|
|
38
38
|
Requires-Dist: euler-metric-naming>=0.2
|
|
39
39
|
Provides-Extra: logging
|
|
@@ -176,7 +176,8 @@ metric is written under, is in [Metrics](docs/metrics.md).
|
|
|
176
176
|
| **Metadata-driven decoding** | Radial vs planar depth, value ranges, point-cloud column layout and loader choice all come from the dataset index — no per-dataset flags. |
|
|
177
177
|
| **Honest spaces** | Relative models are scored `native` *and* `metric` (after scale/shift or a similarity gauge), so a scale failure never reads as a geometry failure. |
|
|
178
178
|
| **Benchmark depth bins** | `--benchmark-depth-range MIN MAX` adds near/mid/far bins in square-root depth space, additive to the regular metrics. |
|
|
179
|
-
| **Sky masking** | `--mask-sky` drops sky pixels using GT segmentation — from the metrics *and* from the alignment fit. |
|
|
179
|
+
| **Sky masking** | `--mask-sky` drops sky pixels using GT segmentation — from the metrics *and* from the alignment fit. `--mask-sky-prediction` does the same with each prediction's own `sky_mask`. |
|
|
180
|
+
| **Sky IoU** | `--sky-iou` scores predicted sky — a `sky_mask`, or depth reaching a fixed cap — against GT segmentation, without changing any depth metric. |
|
|
180
181
|
| **Per-file + aggregate** | Dataset-level numbers plus per-image metrics in dataset-hierarchy order, in the same file. |
|
|
181
182
|
| **Sanity checks** | Results are validated against configurable thresholds; implausible ranges, degenerate inputs and scale mismatches are reported instead of quietly scored. |
|
|
182
183
|
| **Structured metric names** | Each result carries a `metricSet` envelope declaring its namespace, axes, units and metric directions. |
|
|
@@ -126,7 +126,8 @@ metric is written under, is in [Metrics](docs/metrics.md).
|
|
|
126
126
|
| **Metadata-driven decoding** | Radial vs planar depth, value ranges, point-cloud column layout and loader choice all come from the dataset index — no per-dataset flags. |
|
|
127
127
|
| **Honest spaces** | Relative models are scored `native` *and* `metric` (after scale/shift or a similarity gauge), so a scale failure never reads as a geometry failure. |
|
|
128
128
|
| **Benchmark depth bins** | `--benchmark-depth-range MIN MAX` adds near/mid/far bins in square-root depth space, additive to the regular metrics. |
|
|
129
|
-
| **Sky masking** | `--mask-sky` drops sky pixels using GT segmentation — from the metrics *and* from the alignment fit. |
|
|
129
|
+
| **Sky masking** | `--mask-sky` drops sky pixels using GT segmentation — from the metrics *and* from the alignment fit. `--mask-sky-prediction` does the same with each prediction's own `sky_mask`. |
|
|
130
|
+
| **Sky IoU** | `--sky-iou` scores predicted sky — a `sky_mask`, or depth reaching a fixed cap — against GT segmentation, without changing any depth metric. |
|
|
130
131
|
| **Per-file + aggregate** | Dataset-level numbers plus per-image metrics in dataset-hierarchy order, in the same file. |
|
|
131
132
|
| **Sanity checks** | Results are validated against configurable thresholds; implausible ranges, degenerate inputs and scale mismatches are reported instead of quietly scored. |
|
|
132
133
|
| **Structured metric names** | Each result carries a `metricSet` envelope declaring its namespace, axes, units and metric directions. |
|
|
@@ -10,6 +10,12 @@
|
|
|
10
10
|
| [Results & output](output.md) | Where files land, the anatomy of `eval.json`, per-file metrics, the sanity-check report |
|
|
11
11
|
| [In-training validation](validation.md) | The programmatic API for scoring in-memory predictions during training |
|
|
12
12
|
|
|
13
|
+
## Proposed features
|
|
14
|
+
|
|
15
|
+
- [Unified evaluation framework](feature-request-unified-evaluation-framework.md):
|
|
16
|
+
a shared evaluation lifecycle with explicit modality-specific preparation,
|
|
17
|
+
metric dependencies, populations, aggregation and output compatibility.
|
|
18
|
+
|
|
13
19
|
## Concepts in one page
|
|
14
20
|
|
|
15
21
|
**A dataset is an indexed root, not a folder of files.** Every path in the
|
|
@@ -32,7 +32,8 @@ map `d_aligned = s · d_pred + t` by least squares over valid pixels.
|
|
|
32
32
|
|
|
33
33
|
The fit uses pixels where GT and prediction are finite and GT > 0. With
|
|
34
34
|
`--mask-sky`, sky pixels are excluded and the fit is trimmed to `gt ≤ P95(gt)`
|
|
35
|
-
so residual sky outliers do not dominate.
|
|
35
|
+
so residual sky outliers do not dominate. Pixels in a prediction's `sky_mask`
|
|
36
|
+
are excluded from the fit with `--sky-depth` or `--mask-sky-prediction`.
|
|
36
37
|
|
|
37
38
|
Declaring the prediction with the `relative_depth` or `affine_depth` config key
|
|
38
39
|
(instead of `depth`) tells the evaluator the model is not metric, so
|
|
@@ -23,7 +23,9 @@ validation exits with status `1` before any dataset is opened.
|
|
|
23
23
|
| `--skip-rays` | flag | off | Skip rays (spherical direction map) evaluation |
|
|
24
24
|
| `--skip-points-3d` | flag | off | Skip points_3d (per-pixel 3D point map) evaluation |
|
|
25
25
|
| `--mask-sky` | flag | off | Mask sky regions from metrics using GT segmentation |
|
|
26
|
+
| `--mask-sky-prediction` | flag | off | Exclude pixels in a prediction's `datasets[].sky_mask` from dense and sparse depth metrics and the alignment fit; predictions without a `sky_mask` are scored in full ([details](configuration.md#masking-predicted-sky)) |
|
|
26
27
|
| `--sky-depth` | `float` | none | Cap GT and predicted depths in meters and fill predicted `sky_mask` pixels with this value; must be finite and positive |
|
|
28
|
+
| `--sky-iou` | flag | off | Score predicted sky against GT segmentation sky: IoU, precision and recall for the `explicit` (`datasets[].sky_mask`) and `implicit` (`depth >= --sky-depth`, metric predictions only) variants. Requires `gt.segmentation`; depth metrics are unchanged ([details](metrics.md#sky-segmentation)) |
|
|
27
29
|
| `--no-sanity-check` | flag | off | Disable sanity checking of metric configurations |
|
|
28
30
|
| `--metrics-config` | `str` | auto-detect | Path to `metrics_config.json` for sanity checking |
|
|
29
31
|
| `--depth-alignment` | `{none,auto_affine,affine}` | `auto_affine` | Depth calibration mode ([details](alignment.md#depth-alignment)) |
|
|
@@ -54,9 +56,16 @@ euler-eval config.json --batch-size 32
|
|
|
54
56
|
# Sky masking (requires gt.segmentation)
|
|
55
57
|
euler-eval config.json --mask-sky -v
|
|
56
58
|
|
|
59
|
+
# Exclude each prediction's own sky (datasets[].sky_mask) from depth metrics
|
|
60
|
+
euler-eval config.json --mask-sky-prediction
|
|
61
|
+
|
|
57
62
|
# Cap depth at 100 m and fill predicted sky at 100 m (optional datasets[].sky_mask)
|
|
58
63
|
euler-eval config.json --sky-depth 100
|
|
59
64
|
|
|
65
|
+
# Sky IoU: explicit from datasets[].sky_mask, implicit at depth >= 100 m
|
|
66
|
+
# (requires gt.segmentation; the threshold is also the depth cap)
|
|
67
|
+
euler-eval config.json --sky-iou --sky-depth 100
|
|
68
|
+
|
|
60
69
|
# Only depth evaluation
|
|
61
70
|
euler-eval config.json --skip-rgb --skip-rays --skip-points-3d
|
|
62
71
|
|
|
@@ -109,6 +118,13 @@ per prediction dataset and modality with the GT and prediction paths, the
|
|
|
109
118
|
resolved modality metadata (such as `radial_depth`), and the number of matched
|
|
110
119
|
pairs.
|
|
111
120
|
|
|
121
|
+
With `--sky-iou`, each depth block ends with one line holding the pooled
|
|
122
|
+
(`pixel_pool`) sky IoU, precision and recall of every computed variant, for
|
|
123
|
+
example `Sky IoU, pixel_pool, 'model': explicit 0.9120 (precision 0.9500,
|
|
124
|
+
recall 0.9580); implicit (depth >= 100 m) 0.4410 (precision 0.9800, recall
|
|
125
|
+
0.4450)`. Skipped variants, GT segmentation without sky and an empty implicit
|
|
126
|
+
sky are reported as warnings above it.
|
|
127
|
+
|
|
112
128
|
A matched-pair count that is much lower than expected is the first sign that GT
|
|
113
129
|
and predictions are not indexed consistently — see
|
|
114
130
|
[Loader resolution & dataset metadata](configuration.md#loader-resolution--dataset-metadata).
|
|
@@ -71,7 +71,8 @@ required.
|
|
|
71
71
|
| `gt.sparse_depth.path` | no\* | Sparse pointcloud GT, `(N,C)` points whose first columns are `x,y,z` in metres |
|
|
72
72
|
| `gt.rays.path` | no\* | GT ray direction map dataset |
|
|
73
73
|
| `gt.points_3d.path` | no\* | GT per-pixel 3D point map `(H,W,3)` in camera-frame metres |
|
|
74
|
-
| `gt.segmentation.path` | no | GT segmentation (needed for `--mask-sky`) |
|
|
74
|
+
| `gt.segmentation.path` | no | GT segmentation (needed for `--mask-sky` and `--sky-iou`); see [GT segmentation](#gt-segmentation) |
|
|
75
|
+
| `gt.semantic_segmentation.path` | no | Alias of `gt.segmentation`; configure only one of the two |
|
|
75
76
|
| `gt.calibration.path` | no | Calibration data (camera intrinsics); enables true camera-frame [surface normals](metrics.md#surface-normals-and-calibration) |
|
|
76
77
|
| `gt.intrinsics.path` | with `gt.sparse_depth` | Camera intrinsics for pointcloud projection |
|
|
77
78
|
| `gt.camera_extrinsics.path` | with `gt.sparse_depth` | Source-to-camera extrinsics (e.g. MUSES `lidar2rgb`) |
|
|
@@ -80,6 +81,35 @@ required.
|
|
|
80
81
|
|
|
81
82
|
\* At least one of the five modality entries must be present.
|
|
82
83
|
|
|
84
|
+
### GT segmentation
|
|
85
|
+
|
|
86
|
+
`gt.segmentation` is the canonical key. `gt.semantic_segmentation` is accepted
|
|
87
|
+
as an alias, for archives whose segmentation scope carries that name (MUSES,
|
|
88
|
+
for example); configuring both keys is an error. The segmentation is read only
|
|
89
|
+
when `--mask-sky` or `--sky-iou` needs it. `--mask-sky` without it warns and
|
|
90
|
+
disables itself, while `--sky-iou` without it exits with an error.
|
|
91
|
+
|
|
92
|
+
The dataset head's loader module must expose a `sky_mask` function, and the
|
|
93
|
+
head must declare the sky label as `skyclass` (euler-loading 2.29 or later).
|
|
94
|
+
euler-eval contains no label IDs.
|
|
95
|
+
|
|
96
|
+
Segmentation is per frame, so it is paired with the evaluated frames by
|
|
97
|
+
hierarchy path and file ID, like depth: its index must use the same folder
|
|
98
|
+
structure and IDs as the frames it masks. A frame without its own segmentation
|
|
99
|
+
file is not evaluated, and the run prints how many pairs the segmentation
|
|
100
|
+
dropped. When segmentation is read only for `--sky-iou`, it must not change
|
|
101
|
+
the evaluated pairs, so a segmentation that lacks frames is not loaded; the run
|
|
102
|
+
warns and the sky IoU is skipped. A segmentation whose IDs match no frame
|
|
103
|
+
stops the run with euler-loading's "No common IDs" error and per-modality file
|
|
104
|
+
counts.
|
|
105
|
+
|
|
106
|
+
The config key is also the default metadata scope. If the path has no
|
|
107
|
+
`#scope=` selector, no root-level metadata, and no scope of that name, the
|
|
108
|
+
scope is chosen among the archive's scopes: the one whose name or
|
|
109
|
+
`dataset-head.json` modality key is `segmentation` or `semantic_segmentation`
|
|
110
|
+
(both names are candidates under either key), or the only scope. If several
|
|
111
|
+
scopes match, or none among several, the run stops and asks for `#scope=`.
|
|
112
|
+
|
|
83
113
|
## `datasets` section
|
|
84
114
|
|
|
85
115
|
Each entry needs a `name` and at least one prediction modality. Use only **one**
|
|
@@ -94,7 +124,7 @@ would be ambiguous.
|
|
|
94
124
|
| `depth.path` | no\* | Predicted dense metric depth; also used against sparse pointcloud GT |
|
|
95
125
|
| `relative_depth.path` | no\* | Predicted dense relative depth (scale/shift alignment supported) |
|
|
96
126
|
| `affine_depth.path` | no\* | Predicted dense affine depth (scale/shift alignment supported) |
|
|
97
|
-
| `sky_mask.path` | no | Auxiliary predicted sky mask for a dense depth entry; used with `--sky-depth` |
|
|
127
|
+
| `sky_mask.path` | no | Auxiliary predicted sky mask for a dense depth entry; used with `--sky-depth`, `--mask-sky-prediction` and `--sky-iou` |
|
|
98
128
|
| `rays.path` | no\* | Predicted ray direction map dataset |
|
|
99
129
|
| `points_3d.path` | no\* | Predicted per-pixel 3D point map `(H,W,3)` |
|
|
100
130
|
| `output_file` | no | Custom results path (default: `eval.json` in the first modality path) |
|
|
@@ -123,8 +153,8 @@ The sky mask is paired with GT and predicted depth by sample ID and hierarchy.
|
|
|
123
153
|
It supports the same archive, split, and `#scope=` selectors as depth, defaulting
|
|
124
154
|
to the `sky_mask` metadata scope. Its loader must return a boolean mask with
|
|
125
155
|
**True meaning sky**. For example, `generic_dense_depth.sky_mask` uses the RGB
|
|
126
|
-
sky color in the mask dataset's `meta.
|
|
127
|
-
`(1, H, W)` tensor. Masks at another resolution follow the depth grid's crop
|
|
156
|
+
sky color in the mask dataset's `meta.skyclass` (`[R, G, B]`; the older
|
|
157
|
+
`meta.sky_mask` key is deprecated) and returns a `(1, H, W)` tensor. Masks at another resolution follow the depth grid's crop
|
|
128
158
|
rule or use nearest-neighbor resizing.
|
|
129
159
|
|
|
130
160
|
`--sky-depth` applies to dense and sparse depth evaluation. GT and both native
|
|
@@ -139,9 +169,37 @@ contributes only at projected points. Predicted sky stays in the scores where
|
|
|
139
169
|
GT is valid; `--mask-sky` separately excludes pixels using GT segmentation and
|
|
140
170
|
can be combined with `--sky-depth`.
|
|
141
171
|
|
|
142
|
-
Without `--sky-depth`,
|
|
143
|
-
|
|
144
|
-
|
|
172
|
+
Without `--sky-depth`, `--mask-sky-prediction` or `--sky-iou`, the predicted
|
|
173
|
+
mask is not loaded and depth evaluation uses the usual uncapped values.
|
|
174
|
+
`--sky-iou` loads the mask
|
|
175
|
+
even without `--sky-depth`, but only to score it against GT sky
|
|
176
|
+
([Sky segmentation](metrics.md#sky-segmentation)); the depth fill and the
|
|
177
|
+
affine-fit exclusion stay tied to `--sky-depth` (and `--mask-sky-prediction`),
|
|
178
|
+
so depth values do not change.
|
|
179
|
+
Because the mask is paired by sample ID, a mask that lacks some depth frames
|
|
180
|
+
also drops them from the depth metrics; the run prints how many. When the mask
|
|
181
|
+
is loaded only for `--sky-iou`, such a mask is not loaded at all: the run
|
|
182
|
+
warns, keeps every depth pair and skips the explicit variant. The effective cap and mask
|
|
183
|
+
source are recorded in `eval.json` under `meta.eval_params.sky_depth` and
|
|
184
|
+
`meta.pred.sky_mask`.
|
|
185
|
+
|
|
186
|
+
### Masking predicted sky
|
|
187
|
+
|
|
188
|
+
`--mask-sky-prediction` excludes the pixels of a prediction's `sky_mask` from
|
|
189
|
+
dense and sparse depth evaluation, as `--mask-sky` does for GT sky: from every
|
|
190
|
+
metric, benchmark bin and histogram, and from the scale/shift fit. For sparse
|
|
191
|
+
depth, lidar points that project into predicted sky are not scored. A dataset
|
|
192
|
+
without a `sky_mask` is scored in full and the run warns. The flag loads the
|
|
193
|
+
mask without `--sky-depth`, combines with `--mask-sky` (the union of both skies
|
|
194
|
+
is excluded) and with `--sky-depth` (the cap still applies to the remaining
|
|
195
|
+
pixels). It does not change `--sky-iou`, which scores the masks themselves.
|
|
196
|
+
|
|
197
|
+
The excluded pixels come from the evaluated model, so two models are scored on
|
|
198
|
+
different pixel sets, and a model can lower its error by calling hard pixels
|
|
199
|
+
sky. Each result records how much it excluded under `meta.pred_sky_masking`
|
|
200
|
+
([Results & output](output.md#predicted-sky-masking)); compare models with
|
|
201
|
+
this flag only alongside that fraction, or prefer `--mask-sky`, whose GT sky is
|
|
202
|
+
the same for every model.
|
|
145
203
|
|
|
146
204
|
## Sparse depth (pointcloud GT)
|
|
147
205
|
|
|
@@ -162,8 +220,9 @@ depth and `points_3d`, each prediction modality gets its own `eval.json` at its
|
|
|
162
220
|
own path.
|
|
163
221
|
|
|
164
222
|
Sparse depth does not require segmentation GT. `gt.segmentation` is loaded only
|
|
165
|
-
when `--mask-sky` is set
|
|
166
|
-
metrics and from scale/shift fitting
|
|
223
|
+
when `--mask-sky` or `--sky-iou` is set. `--mask-sky` excludes sky pixels from
|
|
224
|
+
projected-point metrics and from scale/shift fitting; `--sky-iou` scores the
|
|
225
|
+
dense prediction's sky against it without changing any depth metric.
|
|
167
226
|
|
|
168
227
|
```json
|
|
169
228
|
{
|
|
@@ -239,11 +298,15 @@ The scope defaults to the configuration key name, so the common case is compact:
|
|
|
239
298
|
|
|
240
299
|
Use `#scope=<scope>` when an artifact scope is not named exactly like the config
|
|
241
300
|
key, e.g. `"sparse_depth": { "path": "/data/capture.zip:test#scope=lidar" }`.
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
`
|
|
246
|
-
|
|
301
|
+
GT segmentation is the exception: under either of its keys it also finds a
|
|
302
|
+
scope named after the other key, as described in [GT segmentation](#gt-segmentation).
|
|
303
|
+
|
|
304
|
+
Regular modalities (`rgb`, `depth`, `rays`, `points_3d`, `sparse_depth`, GT
|
|
305
|
+
segmentation and a predicted `sky_mask`) participate in file-ID intersection;
|
|
306
|
+
calibration and pose data (`intrinsics`, `calibration`, `camera_extrinsics`,
|
|
307
|
+
`lidar_extrinsics`) are loaded hierarchically and do not. A hierarchical file
|
|
308
|
+
applies to every frame at or below its folder, which suits one calibration per
|
|
309
|
+
scene but not per-frame data.
|
|
247
310
|
|
|
248
311
|
## `metrics_config.json`
|
|
249
312
|
|
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
# Feature request: a unified evaluation framework
|
|
2
|
+
|
|
3
|
+
Status: proposed for a future release. This document specifies an architectural
|
|
4
|
+
change; it does not introduce a new API or change evaluation behavior.
|
|
5
|
+
|
|
6
|
+
## Recommendation
|
|
7
|
+
|
|
8
|
+
Use a **modality-agnostic evaluation lifecycle with modality-aware preparation,
|
|
9
|
+
observations and metric definitions**. Represent each evaluation as an explicit
|
|
10
|
+
plan of typed steps and dependencies. The same plan should drive computation,
|
|
11
|
+
aggregation, explanations and output metadata.
|
|
12
|
+
|
|
13
|
+
Depth, RGB, rays and point clouds can share this lifecycle without sharing one
|
|
14
|
+
preprocessing function, validity mask or mathematical reduction. A metric may
|
|
15
|
+
consume several modalities, a whole image, two point sets, a group of frames or
|
|
16
|
+
dataset-wide features. Those requirements belong in its definition.
|
|
17
|
+
|
|
18
|
+
Start with ordinary Python data classes, protocols and a small dependency
|
|
19
|
+
executor. Keep the current CLI and library entry points as compatibility
|
|
20
|
+
wrappers while moving their computation into the shared framework.
|
|
21
|
+
|
|
22
|
+
## Problem and motivation
|
|
23
|
+
|
|
24
|
+
Today, adding a core metric requires wiring computation and storage in
|
|
25
|
+
[`evaluate.py`](../euler_eval/evaluate.py), descriptions and paths in
|
|
26
|
+
[`cli.py`](../euler_eval/cli.py), and sometimes separate per-file and dataset
|
|
27
|
+
serialization logic. Deferred CPU/GPU batch results also patch mutable output
|
|
28
|
+
dictionaries. The distribution contract is attached through a later tree walk
|
|
29
|
+
in [`distribution_contract.py`](../euler_eval/distribution_contract.py).
|
|
30
|
+
|
|
31
|
+
This makes several questions difficult to answer from one place:
|
|
32
|
+
|
|
33
|
+
- Which transformed prediction and GT does a metric consume?
|
|
34
|
+
- Which observations are included, and when is that selection applied?
|
|
35
|
+
- Is a dataset result a mean of image scores, a pooled observation statistic,
|
|
36
|
+
or a computation over the dataset as a whole?
|
|
37
|
+
- Do a scalar and its associated distribution describe the same population?
|
|
38
|
+
- When is a deferred result complete, and which accumulators receive it?
|
|
39
|
+
|
|
40
|
+
The recent depth benchmark-range fix is a concrete example: the default
|
|
41
|
+
distribution needed its selection explicitly connected to the benchmark
|
|
42
|
+
population after sky-depth processing. Shared population definitions should
|
|
43
|
+
make that relationship part of the plan.
|
|
44
|
+
|
|
45
|
+
As a metric author, I should be able to declare inputs, computation, supported
|
|
46
|
+
reductions and result semantics once. As a user, I should be able to inspect
|
|
47
|
+
how any emitted result was produced. As a consumer, euler-view should receive
|
|
48
|
+
stable output with enough provenance to distinguish incompatible evaluations.
|
|
49
|
+
|
|
50
|
+
## Unified flow
|
|
51
|
+
|
|
52
|
+
```mermaid
|
|
53
|
+
flowchart TD
|
|
54
|
+
C[Configuration and selected metric sets] --> P[Build and validate evaluation plan]
|
|
55
|
+
M[Input metadata and available capabilities] --> P
|
|
56
|
+
P --> S[Resolve required inputs and sample or group identities]
|
|
57
|
+
S --> A[Prepare typed artifacts through declared adapter steps]
|
|
58
|
+
A --> V[Resolve views, populations and correspondences]
|
|
59
|
+
V --> K[Compute declared observations, scores or features]
|
|
60
|
+
K --> I[Completed item contributions]
|
|
61
|
+
I --> R[Reducers or retained dataset inputs]
|
|
62
|
+
R --> F[Finalize dataset or group computations]
|
|
63
|
+
K --> N[Optional dependent stages]
|
|
64
|
+
F --> N
|
|
65
|
+
N --> O[Typed result collection]
|
|
66
|
+
I --> O
|
|
67
|
+
F --> O
|
|
68
|
+
O --> E[Compatibility output adapter]
|
|
69
|
+
P -.-> X[Plan explanation and execution provenance]
|
|
70
|
+
O -.-> X
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
This is a lifecycle overview. An individual plan is a directed acyclic graph:
|
|
74
|
+
preparation may itself require correspondence construction before alignment,
|
|
75
|
+
and later metrics may consume artifacts or results from earlier stages. The
|
|
76
|
+
diagram does not mandate that every metric executes every box.
|
|
77
|
+
|
|
78
|
+
For example, RGB plus GT depth can produce depth-binned photometric scores;
|
|
79
|
+
depth plus calibration can produce a point map; a future reconstruction stage
|
|
80
|
+
can consume several frames and produce a cloud for geometric evaluation.
|
|
81
|
+
Each dependency must be explicit, including its coordinate system and scope.
|
|
82
|
+
|
|
83
|
+
## Responsibilities and contracts
|
|
84
|
+
|
|
85
|
+
The initial implementation should formalize these concepts. Names below are
|
|
86
|
+
design suggestions, not a promised public Python API.
|
|
87
|
+
|
|
88
|
+
| Concept | Required responsibility |
|
|
89
|
+
|---|---|
|
|
90
|
+
| `EvaluationPlan` and step definitions | Requested outputs, typed dependencies, execution scope, effective policies and implementation versions. Validate unsupported combinations and cycles before expensive work. |
|
|
91
|
+
| Artifact specification and reference | Payload kind, GT/prediction role, source identity, units, coordinate frame, spatial layout, transformation lineage and ownership. A reference may point to memory or managed storage. |
|
|
92
|
+
| View and population definitions | Evaluated representation, eligibility predicates, selection order, correspondence policy and observation unit. Record distinct source and target populations where needed. |
|
|
93
|
+
| `MetricSpec` | Required artifacts or observations, computation, validity requirements, parameters, supported scopes/reducers and semantic descriptions. Metric sets select these definitions. |
|
|
94
|
+
| `ReducerSpec` | Accepted contribution type, state, update/finalize operations, merge capability, weighting, precision and retention requirements. |
|
|
95
|
+
| Contribution and result records | Stable request/item identity, payload, status, counts and provenance references. Results are completed values; pending work belongs to execution state. |
|
|
96
|
+
|
|
97
|
+
The shared core owns planning, dependency resolution, resource lifetime,
|
|
98
|
+
batch completion, aggregation and result collection. It dispatches by declared
|
|
99
|
+
capabilities and contracts. Modality-specific adapters and metric kernels own
|
|
100
|
+
geometry, image preprocessing, feature extraction and domain-specific math.
|
|
101
|
+
|
|
102
|
+
Metric definitions should supply descriptions, units and allowed reductions to
|
|
103
|
+
the exporter. Adding a metric using existing capabilities should not require
|
|
104
|
+
new modality conditionals in the executor or manual CLI output-tree assembly.
|
|
105
|
+
|
|
106
|
+
### Inputs and execution scope
|
|
107
|
+
|
|
108
|
+
Treat the required inputs as named roles, rather than assuming every operation
|
|
109
|
+
takes a `(prediction, GT)` array pair. Support declarations for:
|
|
110
|
+
|
|
111
|
+
- One item: paired images, predicted image alone, ray maps, or two point sets.
|
|
112
|
+
- A group: a scene, sequence, temporal window or another explicitly identified
|
|
113
|
+
collection, including any ordering requirement.
|
|
114
|
+
- A dataset: feature collections, accumulated statistics or other retained
|
|
115
|
+
inputs needed after the item stream completes.
|
|
116
|
+
|
|
117
|
+
An execution batch is a performance choice, not a statistical grouping. A
|
|
118
|
+
batch size must not silently define a sample, population or dataset reducer.
|
|
119
|
+
|
|
120
|
+
Each request identifies its matching/join policy and required modalities. A
|
|
121
|
+
missing optional modality should affect the requests that need it; it should
|
|
122
|
+
not silently shrink unrelated evaluation populations. Preserve existing
|
|
123
|
+
matching behavior during migration, and make any change to that behavior an
|
|
124
|
+
explicit, separately tested semantic change.
|
|
125
|
+
|
|
126
|
+
NIQE/FADE kernels require predictions only, although today's RGB evaluation
|
|
127
|
+
workflow pairs GT and predictions. Express that kernel requirement now;
|
|
128
|
+
enabling a standalone prediction-only CLI workflow can be a separate feature.
|
|
129
|
+
|
|
130
|
+
### Artifacts, views and populations
|
|
131
|
+
|
|
132
|
+
An artifact must carry enough information to reject invalid combinations:
|
|
133
|
+
metres versus unspecified relative values, incompatible coordinate frames,
|
|
134
|
+
unaligned image grids, or sparse samples supplied to dense-neighbourhood
|
|
135
|
+
metrics. Calibration assumptions and inferred input spaces must be recorded.
|
|
136
|
+
|
|
137
|
+
A population is a named selection over a declared observation domain. It need
|
|
138
|
+
not be a dense Boolean mask: it may be projected correspondences, valid
|
|
139
|
+
directions, selected images, or a directed set of nearest-neighbour queries.
|
|
140
|
+
Two populations with the same display name are not automatically compatible.
|
|
141
|
+
|
|
142
|
+
Separate fitting and scoring populations. For depth, the current intended
|
|
143
|
+
order must remain explicit:
|
|
144
|
+
|
|
145
|
+
1. Spatial preparation, calibration handling and planar/radial conversion.
|
|
146
|
+
2. Alignment fitting on its declared fitting population, where requested.
|
|
147
|
+
3. GT/prediction sky-depth capping and predicted-sky filling under the existing
|
|
148
|
+
policy, with GT sky exclusion recorded separately.
|
|
149
|
+
4. Scoring validity and benchmark membership on evaluated GT. The benchmark
|
|
150
|
+
`all` interval includes both endpoints.
|
|
151
|
+
5. Scalar and distribution computations for the selected space/population.
|
|
152
|
+
|
|
153
|
+
An unrestricted scalar and a benchmark-filtered histogram may intentionally
|
|
154
|
+
coexist, as they currently do. Their internal identities must expose that
|
|
155
|
+
difference. Scalar and distribution requests for the *same* population must
|
|
156
|
+
consume the same selected observations.
|
|
157
|
+
|
|
158
|
+
Additional requirements such as positive inputs for logarithms or a valid
|
|
159
|
+
neighbourhood for normals belong to the relevant computation. Explicitly name
|
|
160
|
+
the resulting population or support policy. Likewise, RGB sky filling and
|
|
161
|
+
RGB pixel exclusion are different operations; the framework must preserve
|
|
162
|
+
that distinction and the current unfilled inputs used for NIQE/FADE.
|
|
163
|
+
|
|
164
|
+
## Mapping current modalities into the framework
|
|
165
|
+
|
|
166
|
+
| Evaluation family | Preparation and dependencies | Computation and scope |
|
|
167
|
+
|---|---|---|
|
|
168
|
+
| Dense depth | Spatial alignment, intrinsics, radial/planar conversion, optional affine fitting, sky policy and benchmark populations | Corresponding-pixel errors and standard reducers; dense geometry; image scores; dataset feature metrics |
|
|
169
|
+
| Sparse depth | Point-cloud transforms, projection, visibility/collision policy, depth preparation and alignment | Errors at evaluated projected correspondences; dense-neighbourhood metrics remain unavailable |
|
|
170
|
+
| RGB | Image layout/range handling, spatial alignment and metric-specific sky policy | Pixel errors, local/image scores, prediction-only quality kernels and dataset FID |
|
|
171
|
+
| RGB with depth | RGB inputs plus explicitly registered GT depth and calibration | Photometric observations selected by GT depth; demonstrates an existing metric with multiple modalities |
|
|
172
|
+
| Rays | Direction preparation, spatial alignment, validity and resolved FoV policy | Angular observations, thresholds and accuracy curves; declared exact/approximate summaries |
|
|
173
|
+
| Dense points-3D | Point maps or unprojected depth, coordinate-frame handling and optional gauge fitting | Correspondence errors, radial/lateral decomposition, dense geometry and separate cloud comparisons |
|
|
174
|
+
| Sparse points-3D | Sparse cloud visibility and projection plus predicted points or the existing programmatic depth conversion | Correspondence errors and cloud queries with explicitly declared directions |
|
|
175
|
+
|
|
176
|
+
Preserve current entry-point eligibility: representing an existing library
|
|
177
|
+
conversion in the plan does not automatically enable an additional CLI result
|
|
178
|
+
family. For point-map metrics, also preserve computations intentionally made in
|
|
179
|
+
the native frame even when aligned results are available.
|
|
180
|
+
|
|
181
|
+
Correspondence error and cloud distance require different observations.
|
|
182
|
+
Nearest-neighbour cloud queries must declare their source, target, direction
|
|
183
|
+
and subsampling policy. Current sparse fixed-threshold diagnostics are
|
|
184
|
+
GT-to-prediction completeness/recall, while optional F-score AUC also needs the
|
|
185
|
+
reverse direction. Keep those requirements separate. Do not pool points from
|
|
186
|
+
unrelated frames before nearest-neighbour matching; a scene-level comparison
|
|
187
|
+
would require an explicit scene artifact and common coordinate frame.
|
|
188
|
+
|
|
189
|
+
The ray evaluator already uses a histogram approximation for its pooled
|
|
190
|
+
median. Migrating it must preserve and disclose that approximation instead of
|
|
191
|
+
implicitly promising an exact quantile.
|
|
192
|
+
|
|
193
|
+
## Observations and aggregation
|
|
194
|
+
|
|
195
|
+
Share computations only when their full input, view, population and numerical
|
|
196
|
+
policies match. Reuse references or chunks where practical; the framework
|
|
197
|
+
must not require retaining all pixel errors in memory.
|
|
198
|
+
|
|
199
|
+
A scalar, histogram and curve are different outputs derived from declared
|
|
200
|
+
observations. A depth histogram associated with `rmse` bins absolute residuals;
|
|
201
|
+
the points-3D counterpart bins Euclidean correspondence errors. Neither is a
|
|
202
|
+
distribution of repeated estimates of dataset RMSE.
|
|
203
|
+
|
|
204
|
+
| Requested result | Contribution/state | Final computation |
|
|
205
|
+
|---|---|---|
|
|
206
|
+
| Pixel-pool depth RMSE | Squared-error sum and valid count | `sqrt(sum_sq / count)` |
|
|
207
|
+
| Mean per-image RMSE | Valid image RMSE sum and image count | Divide; preserve equal image weighting |
|
|
208
|
+
| Error-magnitude histogram | Fixed-bin counts | Elementwise sum |
|
|
209
|
+
| Error sum by GT-depth bin | Fixed-bin error sums | Elementwise sum |
|
|
210
|
+
| RMSE by GT-depth bin | Squared-error sums and counts for matching bins | Square root of each bin's mean squared error |
|
|
211
|
+
| Exact quantile | Retained values or another exact supported state | Quantile over the declared population |
|
|
212
|
+
| LPIPS dataset mean | Completed per-image scores and validity | Declared image-score reducer |
|
|
213
|
+
| FID | Compatible GT/prediction feature collections, or sufficient feature moments if supported by that backend | One dataset-level calculation after ingestion |
|
|
214
|
+
| KID | Feature collections plus declared subset selection/seed policy | Dataset-level estimator with its required retained state |
|
|
215
|
+
|
|
216
|
+
All reducers have `update` and `finalize`; only reducers declaring a compatible
|
|
217
|
+
merge operation may combine partial states. State may be sufficient statistics,
|
|
218
|
+
retained values or ordered/global inputs. Do not force all reducers into sums
|
|
219
|
+
or average finalized shard scores. In particular, per-shard FID values cannot
|
|
220
|
+
be averaged to obtain dataset FID. Backend-specific feature preprocessing,
|
|
221
|
+
model weights and covariance conventions are part of FID compatibility.
|
|
222
|
+
|
|
223
|
+
Define merge compatibility from the complete resolved semantics: observation,
|
|
224
|
+
units, view, population policy, reducer, bin edges/intervals, implementation
|
|
225
|
+
and estimator settings. Registry IDs and matching output paths alone are
|
|
226
|
+
insufficient. Check partition identity separately so overlapping inputs are
|
|
227
|
+
not double counted. Integer counts must remain exact; floating accumulation
|
|
228
|
+
and backend equivalence require declared tolerances.
|
|
229
|
+
|
|
230
|
+
For matching populations and fixed bins, dataset histogram counts must equal
|
|
231
|
+
the sum of item contributions. Benchmark subsets and canonical aliases must
|
|
232
|
+
not be accumulated again as additional observations. Exact RMSE continues to
|
|
233
|
+
use sufficient statistics, independently of histogram resolution.
|
|
234
|
+
|
|
235
|
+
## Execution and later stages
|
|
236
|
+
|
|
237
|
+
Compile selected requests into explicit dependencies. Resolve metadata-based
|
|
238
|
+
choices early; leave data-dependent choices marked unresolved until the
|
|
239
|
+
required input is available, then record the decision and its policy. Reject
|
|
240
|
+
missing required capabilities and incompatible artifacts with useful messages.
|
|
241
|
+
|
|
242
|
+
CPU kernels, GPU batches and dataset computations should emit typed completed
|
|
243
|
+
contributions into the same coordinator. Completion is tracked per logical
|
|
244
|
+
request and item/group; each contribution reaches its reducer once. A failed
|
|
245
|
+
or retried batch must not duplicate counts. Exported dictionaries must not be
|
|
246
|
+
used as pending-result storage.
|
|
247
|
+
|
|
248
|
+
Define `ok`, `no_observations`, `skipped`, `unavailable` and `failed` outcomes
|
|
249
|
+
with reasons and relevant counts. Empty or failed measurements must not enter
|
|
250
|
+
means as zero. The plan declares whether a failure stops the run or leaves a
|
|
251
|
+
result unavailable, preserving existing failure behavior during migration.
|
|
252
|
+
|
|
253
|
+
Use bounded queues and explicit artifact ownership. Release intermediates
|
|
254
|
+
after their consumers finish; declare temporary-file/feature retention and
|
|
255
|
+
clean it up on completion or failure. Expensive optional metrics should only
|
|
256
|
+
load models and compute features when selected. Shared preparation should not
|
|
257
|
+
force an entire dataset or all modalities into memory.
|
|
258
|
+
|
|
259
|
+
Allow a later stage to consume an earlier artifact or typed result through a
|
|
260
|
+
declared dependency. Examples include frame fusion followed by cloud scoring,
|
|
261
|
+
temporal metrics over ordered frame groups, and summaries derived from
|
|
262
|
+
completed dataset results. Specify group membership, ordering, frame transforms
|
|
263
|
+
and missing-input behavior. These examples are extension requirements, not
|
|
264
|
+
requests to implement reconstruction or temporal metrics in this refactor.
|
|
265
|
+
|
|
266
|
+
Initially, a local dependency executor is sufficient. A distributed scheduler,
|
|
267
|
+
plugin marketplace and user-authored workflow language are outside this
|
|
268
|
+
feature's scope. Merge contracts prepare suitable computations for later
|
|
269
|
+
parallel execution without making distribution a prerequisite.
|
|
270
|
+
|
|
271
|
+
## Transparency and output compatibility
|
|
272
|
+
|
|
273
|
+
Provide a proposed `--explain` mode and a programmatic plan description. They
|
|
274
|
+
should identify inputs, transforms, fitting/scoring populations, computation
|
|
275
|
+
dependencies, scope, reducer, approximation and requested output paths.
|
|
276
|
+
An explanation that does not evaluate data must mark inferred settings as
|
|
277
|
+
pending. Runtime provenance records resolved choices and contribution counts;
|
|
278
|
+
it should be possible to follow an output back to its plan definition without
|
|
279
|
+
dumping arrays or masks.
|
|
280
|
+
|
|
281
|
+
Use a structured internal result identity containing evaluation family, view,
|
|
282
|
+
population, measurement, reducer, scope/group and output kind, referencing the
|
|
283
|
+
resolved semantic definitions. A path is an export representation of that
|
|
284
|
+
identity. Canonical aliases reference existing results and perform no work.
|
|
285
|
+
|
|
286
|
+
Keep the current `eval.json` envelope, per-modality files, metric paths, aliases,
|
|
287
|
+
library return shapes, and distribution v1 leaves/registry during migration.
|
|
288
|
+
One serialization layer should translate typed results to those contracts.
|
|
289
|
+
Generate descriptions from metric definitions rather than rediscovering
|
|
290
|
+
semantics through dictionary names. Keep transport validation, including
|
|
291
|
+
JavaScript-safe integer counts and nonfinite-value handling, at that boundary.
|
|
292
|
+
|
|
293
|
+
Preserve existing `distributionPopulation` metadata. A later, separately
|
|
294
|
+
versioned provenance extension can describe per-result views and populations
|
|
295
|
+
for all output kinds, including scalar results. Distinguish evaluation
|
|
296
|
+
semantics versions from wire-schema versions: an internal refactor must not
|
|
297
|
+
silently change metric meaning, and a new meaning does not justify pretending
|
|
298
|
+
older results used the new policy.
|
|
299
|
+
|
|
300
|
+
euler-view should be able to ingest compatibility output without changes.
|
|
301
|
+
Future provenance can support richer explanations and comparison checks, but
|
|
302
|
+
this feature request contains no euler-view implementation work.
|
|
303
|
+
|
|
304
|
+
## Delivery plan
|
|
305
|
+
|
|
306
|
+
1. **Characterize existing behavior.** Inventory current metric definitions,
|
|
307
|
+
requirements, populations, reduction rules, aliases and exceptions. Capture
|
|
308
|
+
representative existing outputs and numerical behavior, including known
|
|
309
|
+
policy differences between CLI and training validation.
|
|
310
|
+
2. **Introduce the contracts through depth.** Extract prepared observations,
|
|
311
|
+
explicit populations and standard/distribution reducers. Reuse the
|
|
312
|
+
sufficient-statistic foundation in
|
|
313
|
+
[`depth_standard.py`](../euler_eval/metrics/depth_standard.py) and the typed
|
|
314
|
+
sample/aggregator approach in [`validation.py`](../euler_eval/validation.py).
|
|
315
|
+
Move dense and sparse depth plus training validation onto the same core
|
|
316
|
+
where semantics match. Keep heavyweight optional metrics outside the
|
|
317
|
+
lightweight validation API.
|
|
318
|
+
3. **Validate the design against different computations.** Migrate RGB image
|
|
319
|
+
and prediction-only kernels, LPIPS completion, dataset FID/KID paths where
|
|
320
|
+
supported, and RGB-with-depth metrics. This milestone must demonstrate
|
|
321
|
+
image, dataset and multiple-modality dependencies before treating the
|
|
322
|
+
abstraction as stable.
|
|
323
|
+
4. **Migrate rays and points.** Preserve frame choices, directional cloud
|
|
324
|
+
comparisons, sparse eligibility and approximation policies. Share declared
|
|
325
|
+
preparation where compatible and retain specialized kernels.
|
|
326
|
+
5. **Complete explanations and remove duplicate wiring.** Generate result
|
|
327
|
+
descriptions and compatibility output from definitions. Document how to
|
|
328
|
+
add a metric, adapter and reducer. Stabilize extension contracts only after
|
|
329
|
+
the current modalities exercise them.
|
|
330
|
+
|
|
331
|
+
Each milestone must leave the existing entry points usable. Numerical or
|
|
332
|
+
selection-policy corrections discovered during migration should be reviewed,
|
|
333
|
+
tested and release-noted separately from structural changes.
|
|
334
|
+
|
|
335
|
+
## Acceptance criteria
|
|
336
|
+
|
|
337
|
+
- All current evaluation families use the same planning, contribution and
|
|
338
|
+
result lifecycle while preserving modality-specific preparation.
|
|
339
|
+
- A metric using existing artifact and reducer types can be added through its
|
|
340
|
+
kernel and declaration without editing the executor or CLI tree-building
|
|
341
|
+
logic. Its descriptions and supported output forms come from that definition.
|
|
342
|
+
- Plans cover a pixel metric, an image metric, a prediction-only kernel, a
|
|
343
|
+
dataset feature metric and a metric requiring RGB plus depth. A small test
|
|
344
|
+
stage can consume an upstream artifact/result without adding a scheduler
|
|
345
|
+
branch for that modality.
|
|
346
|
+
- Depth parity cases cover dense/sparse inputs, native/aligned spaces,
|
|
347
|
+
planar/radial conversion, benchmark boundaries, sky capping/filling,
|
|
348
|
+
excluded/invalid inputs and empty populations. Fitting and scoring
|
|
349
|
+
populations are independently inspectable.
|
|
350
|
+
- Scalars and distributions requesting the same population agree on selected
|
|
351
|
+
observations. Fixed-bin dataset counts equal summed item counts, and
|
|
352
|
+
aliases/subset summaries do not double count.
|
|
353
|
+
- Reducer tests distinguish pooled RMSE from mean image RMSE, verify compatible
|
|
354
|
+
partition merging, reject incompatible state merges and preserve exact or
|
|
355
|
+
approximate quantile policies. Dataset metrics are finalized at their
|
|
356
|
+
declared scope instead of averaging arbitrary batch/shard scores.
|
|
357
|
+
- Cloud tests preserve coordinate frames, correspondence/nearest-neighbour
|
|
358
|
+
distinctions, sparse directions and subsampling. RGB tests preserve filled
|
|
359
|
+
versus unfilled inputs and dependencies on optional depth.
|
|
360
|
+
- CPU and batched implementations agree within metric-specific tolerances;
|
|
361
|
+
integer histograms agree exactly. Completion-order tests detect lost or
|
|
362
|
+
duplicated contributions, including failures and empty results. Stochastic
|
|
363
|
+
estimator checks use declared seed/subset policies.
|
|
364
|
+
- Public CLI/library compatibility fixtures retain result paths, aliases,
|
|
365
|
+
values within the existing tolerances, metadata and distribution v1 schema
|
|
366
|
+
validity. Changes in eligibility, weights or semantics are explicit changes.
|
|
367
|
+
- Explanation output identifies effective policies and unresolved choices;
|
|
368
|
+
result provenance includes resolved dependencies, counts and outcome reasons.
|
|
369
|
+
- Streaming checks demonstrate bounded intermediate memory for streaming
|
|
370
|
+
reducers and cleanup of retained resources. Existing tests remain usable
|
|
371
|
+
without datasets, network access or a GPU; backend stubs can exercise
|
|
372
|
+
scheduling and feature contracts.
|
|
373
|
+
|
|
374
|
+
## Design boundary
|
|
375
|
+
|
|
376
|
+
The framework should make the computation inspectable and extensible through
|
|
377
|
+
shared contracts. It should preserve specialized mathematical kernels and
|
|
378
|
+
make their differences visible. Its success is measured by fewer independent
|
|
379
|
+
places to wire a metric, demonstrable scalar/distribution population agreement,
|
|
380
|
+
and the ability to express the current non-pixel and dataset computations
|
|
381
|
+
within the same lifecycle.
|