2Xplat / src /datasets /base_dataset.py
99hwasikk
init.
e7bcdd2
Raw
History Blame Contribute Delete
5.27 kB
import numpy as np
from src.datasets.batched_sampler import DynamicBatchedMultiFeatureRandomSampler
class BaseDataset:
"""Abstract base class for multi-resolution training datasets."""
def __init__(self, config):
"""
Args:
config: OmegaConf config containing training and data settings.
"""
self.num_views = config.training.num_views
self._set_resolutions(config.training.res_dict)
self._set_input_views(config.training.num_views)
self._set_target_views(config.training.target_views)
self.seed = config.data.seed
self.max_num_retries = 10
def set_epoch(self, epoch):
"""Hook for epoch-level state updates; subclasses may override.
Args:
epoch: The current training epoch index.
"""
pass
def make_sampler(
self,
batch_size_per_gpu,
shuffle: bool = True,
world_size: int = 1,
rank: int = 0,
drop_last: bool = True
):
"""Construct a DynamicBatchedMultiFeatureRandomSampler for this dataset.
Args:
batch_size_per_gpu: List of per-GPU batch sizes, one per view-count bucket.
shuffle: Must be True; non-shuffled iteration is not implemented.
world_size: Total number of distributed processes.
rank: This process's distributed rank.
drop_last: Whether to drop the final incomplete batch.
Returns:
A DynamicBatchedMultiFeatureRandomSampler instance.
"""
if not shuffle:
raise NotImplementedError("Only shuffle=True is supported for now.")
num_of_num_views = len(self.num_views)
feature_to_batch_size_map = {i: bs for i, bs in enumerate(batch_size_per_gpu)}
return DynamicBatchedMultiFeatureRandomSampler(
dataset=self,
pool_sizes=[num_of_num_views],
scaling_feature_idx=0,
feature_to_batch_size_map=feature_to_batch_size_map,
world_size=world_size,
rank=rank,
drop_last=drop_last,
)
def _scene_len(self):
"""Initialize num_of_scenes from data_path; subclasses must set data_path first."""
self.data_path = [] # set in subclass
self.num_of_scenes = len(self.data_path)
def __len__(self):
"""Return the total number of scenes in the dataset."""
return self.num_of_scenes
def _get_views(self, idx, resolution, num_views_to_input, num_views_to_target):
"""Load and return a scene sample. Must be implemented by subclasses.
Args:
idx: Scene index into data_path.
resolution: (height, width) tuple for image loading.
num_views_to_input: Number of input views to select.
num_views_to_target: Number of target views to select.
Returns:
A dict containing image tensors, intrinsics, and pose tensors.
"""
raise NotImplementedError()
def _set_resolutions(self, resolutions):
"""Build an index-keyed dict of (height, width) resolution tuples.
Args:
resolutions: List of [height, width] pairs from config.
"""
self._resolutions = {i: tuple(res) for i, res in enumerate(resolutions)}
def _set_input_views(self, num_views):
"""Build an index-keyed dict of input view counts.
Args:
num_views: List of input view counts from config.
"""
self._input_views = dict(enumerate(num_views))
def _set_target_views(self, target_views):
"""Build an index-keyed dict of target view counts.
Args:
target_views: List of target view counts from config.
"""
self._target_views = dict(enumerate(target_views))
def _getitem_fn(self, idx):
"""Dispatch a sampler-produced index tuple to _get_views.
Args:
idx: A tuple of (sample_idx, dict_idx) where dict_idx selects
the resolution/view-count bucket.
Returns:
The result of _get_views for the resolved parameters.
"""
idx, dict_idx = idx
resolution = self._resolutions[dict_idx]
input_view = self._input_views[dict_idx]
target_view = self._target_views[dict_idx]
return self._get_views(idx, resolution, input_view, target_view)
def __getitem__(self, idx):
"""Return a dataset sample, retrying with a random index on failure.
Args:
idx: A (sample_idx, dict_idx) tuple as yielded by the sampler.
Returns:
A valid sample dict from _getitem_fn.
Raises:
RuntimeError: If all retries are exhausted.
"""
for _ in range(self.max_num_retries + 1):
try:
return self._getitem_fn(idx)
except Exception:
if isinstance(idx, tuple):
idx_list = list(idx)
idx_list[0] = np.random.randint(0, len(self))
idx = tuple(idx_list)
else:
idx = np.random.randint(0, len(self))
raise RuntimeError(f"Failed to load a valid sample after {self.max_num_retries} retries.")