Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Recipe: torch Dataset over a SpatialPatcher

geopatcher ships primitives, not adapters — there is no PatchDataset or PatchLoader class. This page shows how to wire the primitives into a torch Dataset in ~30 lines so the framework choice stays in user code and the patcher stays framework-free.

Install requirements (not pulled in by geopatcher):

pip install torch

The three primitives this recipe uses:

PrimitiveRole
patcher.anchors(field)Dataset.__len__ + indexable lookup
patcher.patch_at(field, anchor)Dataset.__getitem__(i)
patcher.merge(patches, domain)Stitch model outputs back into a field

Map-style Dataset (lazy patch_at)

patch_at reads one patch per __getitem__ — right for huge fields that don’t fit in RAM. Anchors are deterministic given the sampler’s seed (or trivially so for SpatialRegularStride), so the dataset is replayable across runs.

dataset length: 225
first item shape: torch.Size([32, 32]), anchor=(0, 0)

DataLoader with a custom collate

The default torch.utils.data.default_collate doesn’t handle tuple anchors gracefully, so we provide one. Workers are safe because patcher.patch_at only reads the field — no shared state is mutated.

torch.Size([8, 32, 32]) 8

Stitching model outputs back

Run the model per batch, wrap each output as a Patch, and feed the whole sequence to patcher.merge. The patcher’s OverlapAdd aggregation does the windowed stitch.

stitched shape: (256, 256)
identity model → interior reconstructs exactly ✔

When to materialise instead

For small fields (≲ a few thousand patches), the lazy patch_at-per-__getitem__ form pays the per-item read overhead repeatedly. The materialise-once form is faster:

class MaterializedPatcherDataset(Dataset):
    def __init__(self, patcher, field):
        self.patches = list(patcher.split(field))

    def __len__(self):
        return len(self.patches)

    def __getitem__(self, idx):
        p = self.patches[idx]
        return {"data": torch.from_numpy(np.asarray(p.data).copy()),
                "anchor": p.anchor}

Rule of thumb: pick the lazy form for cloud-hosted readers (AsyncRasterField, RioXarrayField on remote zarr) and the materialised form for in-RAM GeoTensor data.