euler-eval 2.10.0__tar.gz → 2.11.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.10.0 → euler_eval-2.11.0}/PKG-INFO +1 -1
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/cli.py +5 -25
- euler_eval-2.11.0/euler_eval/config_paths.py +125 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/data.py +3 -3
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval.egg-info/PKG-INFO +1 -1
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval.egg-info/SOURCES.txt +1 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/pyproject.toml +1 -1
- {euler_eval-2.10.0 → euler_eval-2.11.0}/tests/test_config.py +19 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/tests/test_data_builders.py +11 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/tests/test_save_results.py +15 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/README.md +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/__init__.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/evaluate.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/__init__.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/absrel.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/daniel_error.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/depth_binned_error.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/depth_edge_f1.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/depth_standard.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/fid_kid.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/gpu_depth_batch.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/gpu_image_batch.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/high_freq_energy.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/lpips_metric.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/normal_consistency.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/psnr.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/rgb_edge_f1.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/rgb_lpips.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/rgb_psnr_ssim.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/rho_a.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/rmse.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/scale_invariant_log.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/ssim.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/tail_errors.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/utils.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/sanity_checker.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/utils/hierarchy_parser.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval.egg-info/dependency_links.txt +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval.egg-info/entry_points.txt +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval.egg-info/requires.txt +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval.egg-info/top_level.txt +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/init_cache.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/setup.cfg +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/tests/test_alignment.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/tests/test_cli_device.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/tests/test_data.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/tests/test_depth_alignment_output.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/tests/test_depth_standard.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/tests/test_evaluate_helpers.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/tests/test_init_cache.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/tests/test_integration.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/tests/test_meta_output.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/tests/test_metrics_utils.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/tests/test_rgb_fid_output.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/tests/test_rho_a.py +0 -0
- {euler_eval-2.10.0 → euler_eval-2.11.0}/tests/test_sparse_depth.py +0 -0
|
@@ -13,8 +13,8 @@ import zipfile
|
|
|
13
13
|
from pathlib import Path
|
|
14
14
|
|
|
15
15
|
import torch
|
|
16
|
-
from euler_loading import Modality
|
|
17
16
|
|
|
17
|
+
from .config_paths import normalize_modality_path
|
|
18
18
|
from .data import (
|
|
19
19
|
build_depth_eval_dataset,
|
|
20
20
|
build_rays_eval_dataset,
|
|
@@ -41,22 +41,6 @@ except ImportError:
|
|
|
41
41
|
from euler_metric_naming import AxisDeclaration, MetricDescription, MetricNamespace
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
def _normalize_modality_path(
|
|
45
|
-
path: str | Path,
|
|
46
|
-
*,
|
|
47
|
-
modality_key: str,
|
|
48
|
-
split: str | None = None,
|
|
49
|
-
) -> Path:
|
|
50
|
-
"""Return the filesystem/archive root for an euler-loading modality path."""
|
|
51
|
-
modality = Modality(
|
|
52
|
-
str(path),
|
|
53
|
-
modality_type=modality_key,
|
|
54
|
-
metadata_scope=modality_key,
|
|
55
|
-
split=split,
|
|
56
|
-
)
|
|
57
|
-
return Path(modality.path)
|
|
58
|
-
|
|
59
|
-
|
|
60
44
|
# ── Eval namespace ──────────────────────────────────────────────────────────
|
|
61
45
|
# MetricNamespace subclass for eval context with custom axis declarations,
|
|
62
46
|
# following the Normed Metric Namespacing convention (§3.6, §4, §5.2).
|
|
@@ -616,9 +600,8 @@ def validate_gt_config(gt: dict) -> None:
|
|
|
616
600
|
"camera_extrinsics",
|
|
617
601
|
):
|
|
618
602
|
if modality in gt and "path" in gt[modality]:
|
|
619
|
-
p =
|
|
603
|
+
p = normalize_modality_path(
|
|
620
604
|
gt[modality]["path"],
|
|
621
|
-
modality_key=modality,
|
|
622
605
|
split=gt[modality].get("split"),
|
|
623
606
|
)
|
|
624
607
|
if not p.exists():
|
|
@@ -645,9 +628,8 @@ def validate_dataset_entry(entry: dict, index: int) -> None:
|
|
|
645
628
|
|
|
646
629
|
for modality in ("rgb", "depth", "rays"):
|
|
647
630
|
if modality in entry and "path" in entry[modality]:
|
|
648
|
-
p =
|
|
631
|
+
p = normalize_modality_path(
|
|
649
632
|
entry[modality]["path"],
|
|
650
|
-
modality_key=modality,
|
|
651
633
|
split=entry[modality].get("split"),
|
|
652
634
|
)
|
|
653
635
|
if not p.exists():
|
|
@@ -775,9 +757,8 @@ def save_results(
|
|
|
775
757
|
and "path" in dataset_config[modality]
|
|
776
758
|
):
|
|
777
759
|
output_file = (
|
|
778
|
-
|
|
760
|
+
normalize_modality_path(
|
|
779
761
|
dataset_config[modality]["path"],
|
|
780
|
-
modality_key=modality,
|
|
781
762
|
split=dataset_config[modality].get("split"),
|
|
782
763
|
)
|
|
783
764
|
/ "eval.json"
|
|
@@ -787,9 +768,8 @@ def save_results(
|
|
|
787
768
|
for mod in ("depth", "rgb", "rays"):
|
|
788
769
|
if mod in dataset_config and "path" in dataset_config[mod]:
|
|
789
770
|
output_file = (
|
|
790
|
-
|
|
771
|
+
normalize_modality_path(
|
|
791
772
|
dataset_config[mod]["path"],
|
|
792
|
-
modality_key=mod,
|
|
793
773
|
split=dataset_config[mod].get("split"),
|
|
794
774
|
)
|
|
795
775
|
/ "eval.json"
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"""Helpers for euler-loading modality path selectors in config files."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from urllib.parse import parse_qsl
|
|
8
|
+
|
|
9
|
+
from ds_crawler import validate_metadata_scope
|
|
10
|
+
from ds_crawler.zip_utils import validate_split_name
|
|
11
|
+
from euler_loading import Modality
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass(frozen=True)
|
|
15
|
+
class ModalityPath:
|
|
16
|
+
path: str
|
|
17
|
+
split: str | None = None
|
|
18
|
+
metadata_scope: str | None = None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _parse_inline_scope(path: str) -> tuple[str, str | None]:
|
|
22
|
+
candidate_path, sep, fragment = path.rpartition("#")
|
|
23
|
+
if not sep:
|
|
24
|
+
return path, None
|
|
25
|
+
|
|
26
|
+
params = parse_qsl(fragment, keep_blank_values=True)
|
|
27
|
+
scope_values = [value for key, value in params if key == "scope"]
|
|
28
|
+
if not scope_values:
|
|
29
|
+
return path, None
|
|
30
|
+
|
|
31
|
+
unsupported = [key for key, _ in params if key != "scope"]
|
|
32
|
+
if unsupported:
|
|
33
|
+
raise ValueError(
|
|
34
|
+
"Unsupported modality path fragment parameter(s): "
|
|
35
|
+
f"{', '.join(sorted(set(unsupported)))}. "
|
|
36
|
+
"Only '#scope=<metadata_scope>' is supported."
|
|
37
|
+
)
|
|
38
|
+
if len(scope_values) > 1:
|
|
39
|
+
raise ValueError("Modality path may contain at most one '#scope=' selector.")
|
|
40
|
+
|
|
41
|
+
return candidate_path, validate_metadata_scope(scope_values[0])
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _parse_inline_split(path: str) -> tuple[str, str | None]:
|
|
45
|
+
colon_pos = path.rfind(":")
|
|
46
|
+
if colon_pos <= 1:
|
|
47
|
+
return path, None
|
|
48
|
+
|
|
49
|
+
candidate_split = path[colon_pos + 1 :]
|
|
50
|
+
candidate_path = path[:colon_pos]
|
|
51
|
+
|
|
52
|
+
try:
|
|
53
|
+
split = validate_split_name(candidate_split)
|
|
54
|
+
except ValueError:
|
|
55
|
+
return path, None
|
|
56
|
+
|
|
57
|
+
return candidate_path, split
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def parse_modality_path(
|
|
61
|
+
path: str | Path,
|
|
62
|
+
*,
|
|
63
|
+
split: str | None = None,
|
|
64
|
+
metadata_scope: str | None = None,
|
|
65
|
+
) -> ModalityPath:
|
|
66
|
+
"""Parse euler-loading inline split/scope selectors from a config path."""
|
|
67
|
+
raw_path = str(path)
|
|
68
|
+
parsed_path, inline_scope = _parse_inline_scope(raw_path)
|
|
69
|
+
parsed_path, inline_split = _parse_inline_split(parsed_path)
|
|
70
|
+
|
|
71
|
+
if inline_split is not None and split is not None:
|
|
72
|
+
raise ValueError(
|
|
73
|
+
f"Modality path {raw_path!r} contains an inline split "
|
|
74
|
+
f"({inline_split!r}) but an explicit split={split!r} was also "
|
|
75
|
+
"provided. Use one or the other, not both."
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
normalized_scope = (
|
|
79
|
+
validate_metadata_scope(metadata_scope)
|
|
80
|
+
if metadata_scope is not None
|
|
81
|
+
else None
|
|
82
|
+
)
|
|
83
|
+
if inline_scope is not None:
|
|
84
|
+
if normalized_scope is not None and normalized_scope != inline_scope:
|
|
85
|
+
raise ValueError(
|
|
86
|
+
f"Modality path {raw_path!r} contains an inline metadata scope "
|
|
87
|
+
f"({inline_scope!r}) but an explicit "
|
|
88
|
+
f"metadata_scope={metadata_scope!r} was also provided. Use one "
|
|
89
|
+
"metadata scope selector."
|
|
90
|
+
)
|
|
91
|
+
normalized_scope = inline_scope
|
|
92
|
+
|
|
93
|
+
return ModalityPath(
|
|
94
|
+
path=parsed_path,
|
|
95
|
+
split=split if split is not None else inline_split,
|
|
96
|
+
metadata_scope=normalized_scope,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def normalize_modality_path(path: str | Path, *, split: str | None = None) -> Path:
|
|
101
|
+
"""Return the filesystem/archive root for a config modality path."""
|
|
102
|
+
return Path(parse_modality_path(path, split=split).path)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def build_modality(
|
|
106
|
+
*,
|
|
107
|
+
path: str | Path,
|
|
108
|
+
modality_key: str,
|
|
109
|
+
split: str | None = None,
|
|
110
|
+
loader=None,
|
|
111
|
+
used_as: str | None = None,
|
|
112
|
+
) -> Modality:
|
|
113
|
+
"""Create a Modality after parsing inline config selectors locally."""
|
|
114
|
+
parsed = parse_modality_path(
|
|
115
|
+
path,
|
|
116
|
+
split=split,
|
|
117
|
+
)
|
|
118
|
+
return Modality(
|
|
119
|
+
path=parsed.path,
|
|
120
|
+
loader=loader,
|
|
121
|
+
used_as=used_as,
|
|
122
|
+
modality_type=modality_key,
|
|
123
|
+
metadata_scope=parsed.metadata_scope or modality_key,
|
|
124
|
+
split=parsed.split,
|
|
125
|
+
)
|
|
@@ -13,6 +13,7 @@ import torch
|
|
|
13
13
|
from ds_crawler import get_dataset_contract, index_dataset_from_path
|
|
14
14
|
from euler_loading import Modality, MultiModalDataset, resolve_loader_module
|
|
15
15
|
|
|
16
|
+
from .config_paths import build_modality
|
|
16
17
|
from .metrics.utils import convert_planar_to_radial
|
|
17
18
|
|
|
18
19
|
# ---------------------------------------------------------------------------
|
|
@@ -574,12 +575,11 @@ def _modality(
|
|
|
574
575
|
used_as: Optional[str] = None,
|
|
575
576
|
) -> Modality:
|
|
576
577
|
"""Create an euler-loading modality with an explicit metadata selector."""
|
|
577
|
-
return
|
|
578
|
+
return build_modality(
|
|
578
579
|
path=path,
|
|
579
580
|
loader=loader,
|
|
580
581
|
used_as=used_as,
|
|
581
|
-
|
|
582
|
-
metadata_scope=modality_key,
|
|
582
|
+
modality_key=modality_key,
|
|
583
583
|
split=split,
|
|
584
584
|
)
|
|
585
585
|
|
|
@@ -65,6 +65,25 @@ class TestValidateGtConfig:
|
|
|
65
65
|
gt = {"rgb": {"path": f"{rgb_path}#scope=rgb"}}
|
|
66
66
|
validate_gt_config(gt)
|
|
67
67
|
|
|
68
|
+
def test_inline_scope_intrinsics_gt_path_is_valid(self, tmp_path):
|
|
69
|
+
depth_path = tmp_path / "depth"
|
|
70
|
+
depth_path.mkdir()
|
|
71
|
+
intrinsics_path = tmp_path / "frame_camera_trainvaltest.zip"
|
|
72
|
+
with zipfile.ZipFile(intrinsics_path, "w") as zf:
|
|
73
|
+
zf.writestr("dummy.txt", "x")
|
|
74
|
+
gt = {
|
|
75
|
+
"depth": {"path": str(depth_path)},
|
|
76
|
+
"intrinsics": {"path": f"{intrinsics_path}#scope=intrinsics"},
|
|
77
|
+
}
|
|
78
|
+
validate_gt_config(gt)
|
|
79
|
+
|
|
80
|
+
def test_inline_split_and_scope_gt_path_is_valid(self, tmp_path):
|
|
81
|
+
rgb_path = tmp_path / "reference.zip"
|
|
82
|
+
with zipfile.ZipFile(rgb_path, "w") as zf:
|
|
83
|
+
zf.writestr("dummy.txt", "x")
|
|
84
|
+
gt = {"rgb": {"path": f"{rgb_path}:fog_day#scope=rgb"}}
|
|
85
|
+
validate_gt_config(gt)
|
|
86
|
+
|
|
68
87
|
def test_sparse_depth_requires_projection_modalities(self, tmp_path):
|
|
69
88
|
sparse_path = tmp_path / "sparse_depth"
|
|
70
89
|
sparse_path.mkdir()
|
|
@@ -192,3 +192,14 @@ def test_sky_mask_loader_resolution_strips_inline_split(monkeypatch):
|
|
|
192
192
|
assert calls == [
|
|
193
193
|
("/datasets/shared.zip", {"metadata_scope": "segmentation"}),
|
|
194
194
|
]
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def test_modality_parses_inline_split_and_scope():
|
|
198
|
+
modality = data._modality(
|
|
199
|
+
path="/datasets/frame_camera_trainvaltest.zip:fog_day#scope=intrinsics",
|
|
200
|
+
modality_key="intrinsics",
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
assert modality.path == "/datasets/frame_camera_trainvaltest.zip"
|
|
204
|
+
assert modality.split == "fog_day"
|
|
205
|
+
assert modality.metadata_scope == "intrinsics"
|
|
@@ -229,6 +229,21 @@ class TestSaveResultsZip:
|
|
|
229
229
|
stored = json.loads(zf.read("eval.json"))
|
|
230
230
|
assert stored == results
|
|
231
231
|
|
|
232
|
+
def test_inline_zip_scope_writes_eval_json_into_zip(self, tmp_path):
|
|
233
|
+
zp = tmp_path / "dataset.zip"
|
|
234
|
+
with zipfile.ZipFile(zp, "w") as zf:
|
|
235
|
+
zf.writestr("image_001.png", b"\x89PNG")
|
|
236
|
+
|
|
237
|
+
results = {"rgb": {"psnr": 30.0}}
|
|
238
|
+
config = {"name": "model", "rgb": {"path": f"{zp}#scope=rgb"}}
|
|
239
|
+
out = save_results(results, config, modality="rgb")
|
|
240
|
+
|
|
241
|
+
assert out == zp / "eval.json"
|
|
242
|
+
with zipfile.ZipFile(zp, "r") as zf:
|
|
243
|
+
assert "eval.json" in zf.namelist()
|
|
244
|
+
stored = json.loads(zf.read("eval.json"))
|
|
245
|
+
assert stored == results
|
|
246
|
+
|
|
232
247
|
def test_preserves_existing_zip_contents(self, tmp_path):
|
|
233
248
|
zp = tmp_path / "dataset.zip"
|
|
234
249
|
with zipfile.ZipFile(zp, "w") as zf:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|