euler-loading 2.26.0__tar.gz → 2.28.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_loading-2.26.0 → euler_loading-2.28.0}/.gitignore +5 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/CHANGELOG.md +16 -1
- {euler_loading-2.26.0 → euler_loading-2.28.0}/PKG-INFO +32 -1
- {euler_loading-2.26.0 → euler_loading-2.28.0}/README.md +31 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/docs/README.md +1 -1
- {euler_loading-2.26.0 → euler_loading-2.28.0}/docs/loaders.md +97 -0
- euler_loading-2.28.0/euler_loading/__main__.py +10 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/_ds_crawler_utils.py +18 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/_resolution.py +33 -8
- euler_loading-2.28.0/euler_loading/cli.py +320 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/dataset.py +6 -6
- euler_loading-2.28.0/euler_loading/dry_run.py +723 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/pyproject.toml +4 -1
- euler_loading-2.28.0/tests/test_dry_run.py +592 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/LICENSE +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/docs/dataset.md +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/docs/materialization.md +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/docs/preprocessing.md +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/docs/transform-descriptors.md +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/docs/writing.md +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/__init__.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/_dataset_contract.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/_metadata.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/_writing.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/geometry.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/indexing.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/loaders/__init__.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/loaders/_annotations.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/loaders/_princeton_dense.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/loaders/_writer_utils.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/loaders/contracts.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/loaders/cpu/__init__.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/loaders/cpu/generic.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/loaders/cpu/generic_dense_depth.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/loaders/cpu/muses.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/loaders/cpu/princeton_dense.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/loaders/cpu/real_drive_sim.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/loaders/cpu/synscapes.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/loaders/cpu/vkitti2.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/loaders/generate/__init__.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/loaders/generate/__main__.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/loaders/generate/loaders.json +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/loaders/generic.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/loaders/gpu/__init__.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/loaders/gpu/generic.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/loaders/gpu/generic_dense_depth.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/loaders/gpu/muses.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/loaders/gpu/princeton_dense.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/loaders/gpu/real_drive_sim.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/loaders/gpu/synscapes.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/loaders/gpu/vkitti2.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/loaders/materialized.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/loaders/muses.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/loaders/princeton_dense.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/loaders/real_drive_sim.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/loaders/synscapes.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/loaders/vkitti2.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/materialization.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/output_encoding.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/preprocessing.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/receipts.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/euler_loading/transform_descriptors.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/examples/README.md +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/examples/real_drive_sim_preview.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/examples/vkitti2_sample.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/tests/__init__.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/tests/conftest.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/tests/example_rds_calib.json +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/tests/test_dataset.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/tests/test_id_schema.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/tests/test_indexing.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/tests/test_loaders.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/tests/test_materialization.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/tests/test_preprocessing.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/tests/test_python_compat.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/tests/test_real_dataset.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/tests/test_synscapes.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/tests/test_transform_descriptors.py +0 -0
- {euler_loading-2.26.0 → euler_loading-2.28.0}/tests/test_writing.py +0 -0
|
@@ -42,3 +42,8 @@ TASK.md
|
|
|
42
42
|
|
|
43
43
|
# uv
|
|
44
44
|
uv.lock
|
|
45
|
+
|
|
46
|
+
# Stray npm lockfile. Nothing in this package is built with npm, and worktree
|
|
47
|
+
# tooling rewrites its "name" field to the branch directory on every branch,
|
|
48
|
+
# so tracking it produced a merge conflict on every quick-merge.
|
|
49
|
+
package-lock.json
|
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## 2.27.0 (unreleased)
|
|
4
|
+
|
|
5
|
+
- Add a dry-run command: `euler-loading <path>` (also `python -m
|
|
6
|
+
euler_loading <path>`) walks the ds-crawler artifact sets at or below one
|
|
7
|
+
folder, resolves the loader each dataset head declares in
|
|
8
|
+
`addons.euler_loading`, decodes a sample of the indexed files with it, and
|
|
9
|
+
reports shapes, dtypes and value ranges. Directories and `.zip` archives
|
|
10
|
+
are treated alike, nothing is written, and the exit status is non-zero when
|
|
11
|
+
a modality fails to resolve or decode. `euler_loading.dry_run.dry_run()`
|
|
12
|
+
exposes the same report to Python.
|
|
13
|
+
- `resolve_loader_module` and `resolve_writer_module` take a
|
|
14
|
+
`variant="gpu"|"cpu"` keyword, so the CPU modules can be resolved through
|
|
15
|
+
the same contract pathway as the torch ones. This is what the dry run's
|
|
16
|
+
`--cpu` uses to check archives on a torch-free install.
|
|
17
|
+
|
|
18
|
+
## 2.26.0
|
|
4
19
|
|
|
5
20
|
- Add `read_extrinsics` to the Synscapes loaders, building a 4x4 rigid
|
|
6
21
|
transform from the six `camera.extrinsic` scalars. `transform_direction`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: euler-loading
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.28.0
|
|
4
4
|
Summary: Multi-modal PyTorch dataloader using ds-crawler indices
|
|
5
5
|
Project-URL: Homepage, https://github.com/d-rothen/euler-loading
|
|
6
6
|
Project-URL: Repository, https://github.com/d-rothen/euler-loading
|
|
@@ -174,6 +174,36 @@ when you want the CPU variant or a custom callable. See
|
|
|
174
174
|
[Automatic loader resolution](docs/loaders.md#automatic-loader-resolution) for
|
|
175
175
|
the full contract and writer rules.
|
|
176
176
|
|
|
177
|
+
## Checking a dataset
|
|
178
|
+
|
|
179
|
+
Before any of that runs, point the bundled command at a folder to see what
|
|
180
|
+
euler-loading would make of it:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
euler-loading /data/vkitti2
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
For every ds-crawler artifact set below that path it resolves the loader the
|
|
187
|
+
dataset declares, decodes a sample of the indexed files with it, and prints
|
|
188
|
+
the shape, dtype and value range that came back:
|
|
189
|
+
|
|
190
|
+
```text
|
|
191
|
+
vkitti_2.0.3_rgb [ok]
|
|
192
|
+
path /data/vkitti2/vkitti_2.0.3_rgb
|
|
193
|
+
contract vkitti2_rgb, "Virtual KITTI 2 RGB", modality key: rgb
|
|
194
|
+
loader vkitti2.rgb -> euler_loading.loaders.gpu.vkitti2.rgb
|
|
195
|
+
index 21260 files; available splits: train, val
|
|
196
|
+
decoded 1/1
|
|
197
|
+
Scene01/clone/frames/rgb/Camera_0/rgb_00000.jpg -> Tensor (3, 375, 1242) float32 in [0, 1] (11.4 ms)
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Nothing is written, directories and `.zip` archives are treated alike, and the
|
|
201
|
+
exit status is non-zero if any modality failed to resolve or decode — so it
|
|
202
|
+
also works as a CI step. `--all` decodes every file instead of a sample,
|
|
203
|
+
`--cpu` checks the NumPy loaders on a torch-free install, and `--json` prints
|
|
204
|
+
the same report for a machine. See
|
|
205
|
+
[Dry-running loaders](docs/loaders.md#dry-running-loaders).
|
|
206
|
+
|
|
177
207
|
## What you get
|
|
178
208
|
|
|
179
209
|
| | |
|
|
@@ -186,6 +216,7 @@ the full contract and writer rules.
|
|
|
186
216
|
| **Loader resolution** | Loaders and writers resolve from the `dataset-head.json` `addons.euler_loading` contract, so datasets describe how to read themselves. |
|
|
187
217
|
| **Writing back** | Resolved writers put inference outputs back in dataset-native formats, re-indexable with matching IDs. |
|
|
188
218
|
| **Spatial preprocessing** | `SamplePreprocessor` resizes and crops consistently across images, depth, masks, ray maps *and* intrinsics. |
|
|
219
|
+
| **Dry runs** | `euler-loading <folder>` resolves and exercises every loader a dataset declares, without writing anything. |
|
|
189
220
|
|
|
190
221
|
## Built-in loaders
|
|
191
222
|
|
|
@@ -135,6 +135,36 @@ when you want the CPU variant or a custom callable. See
|
|
|
135
135
|
[Automatic loader resolution](docs/loaders.md#automatic-loader-resolution) for
|
|
136
136
|
the full contract and writer rules.
|
|
137
137
|
|
|
138
|
+
## Checking a dataset
|
|
139
|
+
|
|
140
|
+
Before any of that runs, point the bundled command at a folder to see what
|
|
141
|
+
euler-loading would make of it:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
euler-loading /data/vkitti2
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
For every ds-crawler artifact set below that path it resolves the loader the
|
|
148
|
+
dataset declares, decodes a sample of the indexed files with it, and prints
|
|
149
|
+
the shape, dtype and value range that came back:
|
|
150
|
+
|
|
151
|
+
```text
|
|
152
|
+
vkitti_2.0.3_rgb [ok]
|
|
153
|
+
path /data/vkitti2/vkitti_2.0.3_rgb
|
|
154
|
+
contract vkitti2_rgb, "Virtual KITTI 2 RGB", modality key: rgb
|
|
155
|
+
loader vkitti2.rgb -> euler_loading.loaders.gpu.vkitti2.rgb
|
|
156
|
+
index 21260 files; available splits: train, val
|
|
157
|
+
decoded 1/1
|
|
158
|
+
Scene01/clone/frames/rgb/Camera_0/rgb_00000.jpg -> Tensor (3, 375, 1242) float32 in [0, 1] (11.4 ms)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Nothing is written, directories and `.zip` archives are treated alike, and the
|
|
162
|
+
exit status is non-zero if any modality failed to resolve or decode — so it
|
|
163
|
+
also works as a CI step. `--all` decodes every file instead of a sample,
|
|
164
|
+
`--cpu` checks the NumPy loaders on a torch-free install, and `--json` prints
|
|
165
|
+
the same report for a machine. See
|
|
166
|
+
[Dry-running loaders](docs/loaders.md#dry-running-loaders).
|
|
167
|
+
|
|
138
168
|
## What you get
|
|
139
169
|
|
|
140
170
|
| | |
|
|
@@ -147,6 +177,7 @@ the full contract and writer rules.
|
|
|
147
177
|
| **Loader resolution** | Loaders and writers resolve from the `dataset-head.json` `addons.euler_loading` contract, so datasets describe how to read themselves. |
|
|
148
178
|
| **Writing back** | Resolved writers put inference outputs back in dataset-native formats, re-indexable with matching IDs. |
|
|
149
179
|
| **Spatial preprocessing** | `SamplePreprocessor` resizes and crops consistently across images, depth, masks, ray maps *and* intrinsics. |
|
|
180
|
+
| **Dry runs** | `euler-loading <folder>` resolves and exercises every loader a dataset declares, without writing anything. |
|
|
150
181
|
|
|
151
182
|
## Built-in loaders
|
|
152
183
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
| Guide | Covers |
|
|
4
4
|
|---|---|
|
|
5
5
|
| [Dataset & modalities](dataset.md) | `Modality` and `MultiModalDataset` reference, the sample dict, hierarchical modalities, splits, scoped metadata, zip archives, layout-aware loading |
|
|
6
|
-
| [Loaders & writers](loaders.md) | The loader contract, per-file attributes, automatic resolution, protocols, and the full built-in loader inventory |
|
|
6
|
+
| [Loaders & writers](loaders.md) | The loader contract, per-file attributes, automatic resolution, the `euler-loading` dry run, protocols, and the full built-in loader inventory |
|
|
7
7
|
| [Preprocessing & transforms](preprocessing.md) | Cross-modal transforms, `SamplePreprocessor`, field kinds, calibration-aware resize and crop |
|
|
8
8
|
| [Writing outputs](writing.md) | Writing predictions back in dataset-native formats and re-indexing them |
|
|
9
9
|
|
|
@@ -7,6 +7,7 @@ that file means.
|
|
|
7
7
|
- [The contract](#the-contract)
|
|
8
8
|
- [Per-file attributes](#per-file-attributes)
|
|
9
9
|
- [Automatic loader resolution](#automatic-loader-resolution)
|
|
10
|
+
- [Dry-running loaders](#dry-running-loaders)
|
|
10
11
|
- [Loader protocols](#loader-protocols)
|
|
11
12
|
- [Built-in loaders](#built-in-loaders)
|
|
12
13
|
|
|
@@ -129,6 +130,102 @@ Writers resolve from the same `addons.euler_loading` entry, in this order:
|
|
|
129
130
|
2. for `function: "read_<suffix>"`, `write_<suffix>`,
|
|
130
131
|
3. `write_<function>`.
|
|
131
132
|
|
|
133
|
+
## Dry-running loaders
|
|
134
|
+
|
|
135
|
+
Resolution only pays off if the loader a dataset names can really read its
|
|
136
|
+
files. Point the bundled command at a path to find out, before a training run
|
|
137
|
+
depends on it:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
euler-loading /data/vkitti2
|
|
141
|
+
python -m euler_loading /data/vkitti2 # same thing, no console script needed
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
It takes one path — a modality root, a `.zip` archive, or a folder holding
|
|
145
|
+
several of them — and for every ds-crawler artifact set below it:
|
|
146
|
+
|
|
147
|
+
1. loads the index, or a named split,
|
|
148
|
+
2. resolves the loader its `addons.euler_loading` entry declares,
|
|
149
|
+
3. decodes a sample of the indexed files with that loader,
|
|
150
|
+
4. reports the shape, dtype and value range of what came back.
|
|
151
|
+
|
|
152
|
+
Nothing is written and no dataset is constructed. A modality that cannot be
|
|
153
|
+
read is reported, not raised, so one broken archive does not hide the rest.
|
|
154
|
+
|
|
155
|
+
```text
|
|
156
|
+
euler-loading dry-run: /data/vkitti2
|
|
157
|
+
loader variant: gpu (torch tensors)
|
|
158
|
+
|
|
159
|
+
vkitti_2.0.3_rgb [ok]
|
|
160
|
+
path /data/vkitti2/vkitti_2.0.3_rgb
|
|
161
|
+
contract vkitti2_rgb, "Virtual KITTI 2 RGB", modality key: rgb
|
|
162
|
+
loader vkitti2.rgb -> euler_loading.loaders.gpu.vkitti2.rgb
|
|
163
|
+
writer write_rgb
|
|
164
|
+
index 21260 files; available splits: train, val
|
|
165
|
+
decoded 1/1
|
|
166
|
+
Scene01/clone/frames/rgb/Camera_0/rgb_00000.jpg -> Tensor (3, 375, 1242) float32 in [0, 1] (11.4 ms)
|
|
167
|
+
|
|
168
|
+
vkitti_2.0.3_textgt [ok]
|
|
169
|
+
path /data/vkitti2/vkitti_2.0.3_textgt
|
|
170
|
+
contract vkitti2_intrinsics, "Virtual KITTI 2 intrinsics", modality key: camera_intrinsics
|
|
171
|
+
loader vkitti2.read_intrinsics -> euler_loading.loaders.gpu.vkitti2.read_intrinsics (hierarchical)
|
|
172
|
+
writer write_intrinsics
|
|
173
|
+
index 50 files
|
|
174
|
+
decoded 1/1
|
|
175
|
+
Scene01/clone/intrinsic.txt -> Tensor (3, 3) float32 in [0, 725] (0.6 ms)
|
|
176
|
+
|
|
177
|
+
2 modalities checked: 2 ok, 0 failed; 2/2 files decoded
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
The exit status is 0 when every modality resolved a loader and decoded every
|
|
181
|
+
file it was asked to, and 1 otherwise, so the command works as a CI step or a
|
|
182
|
+
job prologue.
|
|
183
|
+
|
|
184
|
+
| Flag | Effect |
|
|
185
|
+
|---|---|
|
|
186
|
+
| `-n, --samples N` | Files to decode per modality, spread evenly across the index (default 1). `0` resolves loaders without decoding anything. |
|
|
187
|
+
| `--all` | Decode every indexed file. Slow, but checks the whole archive. |
|
|
188
|
+
| `--split NAME` | Dry-run a named ds-crawler split instead of the canonical index. |
|
|
189
|
+
| `--scope SCOPE` | Read `.ds_crawler/SCOPE/` only, instead of every artifact set a root carries. |
|
|
190
|
+
| `--cpu` | Resolve the NumPy loaders instead of the torch ones. Works on an install without PyTorch. |
|
|
191
|
+
| `--max-depth N` | Directory levels below the path to search for dataset roots (default 3). |
|
|
192
|
+
| `--json` | Print the report as JSON instead of text. |
|
|
193
|
+
| `-v, --verbose` | Log debug output, including a traceback for every failed load. |
|
|
194
|
+
|
|
195
|
+
The path takes the same inline selectors as `Modality`, so
|
|
196
|
+
`euler-loading /data/muses.zip:train#scope=rgb` checks one split of one scope.
|
|
197
|
+
|
|
198
|
+
Discovery stops at the first dataset root down each branch: a directory
|
|
199
|
+
carrying its own `.ds_crawler/` is checked, never descended into, so a
|
|
200
|
+
dataset's own scene directories are never walked. A root with several
|
|
201
|
+
metadata scopes contributes one entry per scope, labelled with the selector
|
|
202
|
+
that addresses it.
|
|
203
|
+
|
|
204
|
+
### Reading the report
|
|
205
|
+
|
|
206
|
+
| Line | What it is telling you |
|
|
207
|
+
|---|---|
|
|
208
|
+
| `error loader: ... no 'addons.euler_loading' entry` | the dataset head declares no loader, so only an explicit `Modality(..., loader=...)` can read it |
|
|
209
|
+
| `loader vkitti2.rgb (unresolved)` plus an `error` | the contract names a loader that is unknown, misspelled, or needs a dependency this install lacks — `--cpu` resolves the torch-free variant |
|
|
210
|
+
| `decoded 0/2` with per-file `FAILED` | the files are indexed and present, but the declared loader cannot decode them |
|
|
211
|
+
| `(hierarchical)` after the loader | the declared function reads per-scene data; pass that modality as `hierarchical_modalities`, not `modalities` |
|
|
212
|
+
| `error index: ...` | ds-crawler could not produce an index — a missing split, an unreadable archive, or a dataset head the contract rejects |
|
|
213
|
+
| a warning about shared file IDs | the modalities below the path have no file ID in common, so they cannot be intersected into one `MultiModalDataset` |
|
|
214
|
+
|
|
215
|
+
The same report is available as an API, which is what the command is a thin
|
|
216
|
+
shell around:
|
|
217
|
+
|
|
218
|
+
```python
|
|
219
|
+
from euler_loading.dry_run import dry_run
|
|
220
|
+
|
|
221
|
+
report = dry_run("/data/vkitti2", samples=3)
|
|
222
|
+
if not report.ok:
|
|
223
|
+
for modality in report.modalities:
|
|
224
|
+
print(modality.label, modality.errors)
|
|
225
|
+
|
|
226
|
+
report.to_dict() # the same structure --json prints
|
|
227
|
+
```
|
|
228
|
+
|
|
132
229
|
## Loader protocols
|
|
133
230
|
|
|
134
231
|
`DenseDepthLoader` is a `runtime_checkable` Protocol defining the loader
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import io
|
|
4
|
+
import zipfile
|
|
3
5
|
from collections.abc import Mapping
|
|
4
6
|
from pathlib import Path
|
|
5
7
|
from typing import Any
|
|
@@ -22,6 +24,22 @@ from ds_crawler.zip_utils import (
|
|
|
22
24
|
)
|
|
23
25
|
|
|
24
26
|
|
|
27
|
+
def read_zip_member(
|
|
28
|
+
archive: zipfile.ZipFile,
|
|
29
|
+
prefix: str,
|
|
30
|
+
relative_path: str,
|
|
31
|
+
) -> io.BytesIO:
|
|
32
|
+
"""Read one member of a zip-backed modality into an in-memory buffer.
|
|
33
|
+
|
|
34
|
+
The buffer carries the modality-relative path as its ``name`` so loaders
|
|
35
|
+
that branch on the file extension behave the same as for a filesystem
|
|
36
|
+
path.
|
|
37
|
+
"""
|
|
38
|
+
buffer = io.BytesIO(archive.read(prefix + relative_path))
|
|
39
|
+
buffer.name = relative_path
|
|
40
|
+
return buffer
|
|
41
|
+
|
|
42
|
+
|
|
25
43
|
def as_non_empty_str(value: Any) -> str | None:
|
|
26
44
|
if value is None:
|
|
27
45
|
return None
|
|
@@ -18,6 +18,10 @@ if TYPE_CHECKING:
|
|
|
18
18
|
logger = logging.getLogger(__name__)
|
|
19
19
|
|
|
20
20
|
|
|
21
|
+
#: Built-in loader variants. ``gpu`` returns torch tensors, ``cpu`` NumPy
|
|
22
|
+
#: arrays; automatic resolution from a dataset contract uses ``gpu``.
|
|
23
|
+
LOADER_VARIANTS = ("gpu", "cpu")
|
|
24
|
+
|
|
21
25
|
_LOADER_MODULES: dict[str, str] = {
|
|
22
26
|
"materialized": "euler_loading.loaders.materialized",
|
|
23
27
|
"vkitti2": "euler_loading.loaders.gpu.vkitti2",
|
|
@@ -46,30 +50,45 @@ def _get_euler_loading_meta(index: Mapping[str, Any]) -> Mapping[str, Any] | Non
|
|
|
46
50
|
return None
|
|
47
51
|
|
|
48
52
|
|
|
49
|
-
def resolve_loader_module(name: str) -> ModuleType:
|
|
50
|
-
"""Import and return the
|
|
53
|
+
def resolve_loader_module(name: str, *, variant: str = "gpu") -> ModuleType:
|
|
54
|
+
"""Import and return the loader module for *name*.
|
|
51
55
|
|
|
52
56
|
Example::
|
|
53
57
|
|
|
54
58
|
module = resolve_loader_module("vkitti2")
|
|
55
59
|
sky_fn = module.sky_mask # get a specific function
|
|
56
60
|
|
|
61
|
+
Args:
|
|
62
|
+
name: Loader name, as declared by ``addons.euler_loading.loader``.
|
|
63
|
+
variant: ``"gpu"`` for the torch loaders (the default, and what
|
|
64
|
+
automatic resolution uses) or ``"cpu"`` for the NumPy ones.
|
|
65
|
+
|
|
57
66
|
Raises:
|
|
58
|
-
ValueError: If *name* does not match any known loader
|
|
67
|
+
ValueError: If *name* does not match any known loader, or *variant*
|
|
68
|
+
is neither ``"gpu"`` nor ``"cpu"``.
|
|
59
69
|
"""
|
|
70
|
+
if variant not in LOADER_VARIANTS:
|
|
71
|
+
available = ", ".join(LOADER_VARIANTS)
|
|
72
|
+
raise ValueError(
|
|
73
|
+
f"Unknown loader variant {variant!r}. Available variants: {available}"
|
|
74
|
+
)
|
|
60
75
|
module_path = _LOADER_MODULES.get(name)
|
|
61
76
|
if module_path is None:
|
|
62
77
|
available = ", ".join(sorted(_LOADER_MODULES))
|
|
63
78
|
raise ValueError(f"Unknown loader {name!r}. Available loaders: {available}")
|
|
79
|
+
if variant == "cpu":
|
|
80
|
+
# Loaders that exist in one variant only (``materialized``) are not
|
|
81
|
+
# registered under ``.gpu.`` and therefore stay as they are.
|
|
82
|
+
module_path = module_path.replace(".loaders.gpu.", ".loaders.cpu.")
|
|
64
83
|
return importlib.import_module(module_path)
|
|
65
84
|
|
|
66
85
|
|
|
67
|
-
def resolve_writer_module(name: str) -> ModuleType:
|
|
86
|
+
def resolve_writer_module(name: str, *, variant: str = "gpu") -> ModuleType:
|
|
68
87
|
"""Import and return the writer module for *name*.
|
|
69
88
|
|
|
70
89
|
Writers live next to loader functions in the same modules.
|
|
71
90
|
"""
|
|
72
|
-
return resolve_loader_module(name)
|
|
91
|
+
return resolve_loader_module(name, variant=variant)
|
|
73
92
|
|
|
74
93
|
|
|
75
94
|
def _builtin_loader_id(loader: Callable[..., Any]) -> str | None:
|
|
@@ -119,8 +138,13 @@ def _resolve_loader(
|
|
|
119
138
|
modality_name: str,
|
|
120
139
|
modality: Modality,
|
|
121
140
|
index: dict[str, Any],
|
|
141
|
+
variant: str = "gpu",
|
|
122
142
|
) -> Callable[..., Any]:
|
|
123
|
-
"""Return the effective loader for a modality.
|
|
143
|
+
"""Return the effective loader for a modality.
|
|
144
|
+
|
|
145
|
+
An explicit ``Modality.loader`` always wins; *variant* only selects
|
|
146
|
+
between the built-in GPU and CPU modules during automatic resolution.
|
|
147
|
+
"""
|
|
124
148
|
if modality.loader is not None:
|
|
125
149
|
return modality.loader
|
|
126
150
|
|
|
@@ -143,7 +167,7 @@ def _resolve_loader(
|
|
|
143
167
|
module_name: str = euler_loading_meta["loader"]
|
|
144
168
|
func_name: str = euler_loading_meta["function"]
|
|
145
169
|
|
|
146
|
-
module = resolve_loader_module(module_name)
|
|
170
|
+
module = resolve_loader_module(module_name, variant=variant)
|
|
147
171
|
|
|
148
172
|
func = getattr(module, func_name, None)
|
|
149
173
|
if func is None or not callable(func):
|
|
@@ -185,6 +209,7 @@ def _resolve_writer(
|
|
|
185
209
|
modality_name: str,
|
|
186
210
|
modality: Modality,
|
|
187
211
|
index: dict[str, Any],
|
|
212
|
+
variant: str = "gpu",
|
|
188
213
|
) -> Callable[..., Any] | None:
|
|
189
214
|
"""Return the effective writer for a modality, if available."""
|
|
190
215
|
if modality.writer is not None:
|
|
@@ -200,7 +225,7 @@ def _resolve_writer(
|
|
|
200
225
|
return None
|
|
201
226
|
|
|
202
227
|
try:
|
|
203
|
-
module = resolve_writer_module(module_name)
|
|
228
|
+
module = resolve_writer_module(module_name, variant=variant)
|
|
204
229
|
except ValueError:
|
|
205
230
|
logger.warning(
|
|
206
231
|
"Modality '%s': cannot resolve writer module %r.",
|