CoolFace
Apppublic

iyedjb/self-forcing

sourceHugging Faceupdated 1y agoView on Hugging Face
0likes
dataset.py221 linesDownload Raw Back to utils
1from utils.lmdb import get_array_shape_from_lmdb, retrieve_row_from_lmdb2from torch.utils.data import Dataset3import numpy as np4import torch5import lmdb6import json7from pathlib import Path8from PIL import Image9import os10 11 12class TextDataset(Dataset):13    def __init__(self, prompt_path, extended_prompt_path=None):14        with open(prompt_path, encoding="utf-8") as f:15            self.prompt_list = [line.rstrip() for line in f]16 17        if extended_prompt_path is not None:18            with open(extended_prompt_path, encoding="utf-8") as f:19                self.extended_prompt_list = [line.rstrip() for line in f]20            assert len(self.extended_prompt_list) == len(self.prompt_list)21        else:22            self.extended_prompt_list = None23 24    def __len__(self):25        return len(self.prompt_list)26 27    def __getitem__(self, idx):28        batch = {29            "prompts": self.prompt_list[idx],30            "idx": idx,31        }32        if self.extended_prompt_list is not None:33            batch["extended_prompts"] = self.extended_prompt_list[idx]34        return batch35 36 37class ODERegressionLMDBDataset(Dataset):38    def __init__(self, data_path: str, max_pair: int = int(1e8)):39        self.env = lmdb.open(data_path, readonly=True,40                             lock=False, readahead=False, meminit=False)41 42        self.latents_shape = get_array_shape_from_lmdb(self.env, 'latents')43        self.max_pair = max_pair44 45    def __len__(self):46        return min(self.latents_shape[0], self.max_pair)47 48    def __getitem__(self, idx):49        """50        Outputs:51            - prompts: List of Strings52            - latents: Tensor of shape (num_denoising_steps, num_frames, num_channels, height, width). It is ordered from pure noise to clean image.53        """54        latents = retrieve_row_from_lmdb(55            self.env,56            "latents", np.float16, idx, shape=self.latents_shape[1:]57        )58 59        if len(latents.shape) == 4:60            latents = latents[None, ...]61 62        prompts = retrieve_row_from_lmdb(63            self.env,64            "prompts", str, idx65        )66        return {67            "prompts": prompts,68            "ode_latent": torch.tensor(latents, dtype=torch.float32)69        }70 71 72class ShardingLMDBDataset(Dataset):73    def __init__(self, data_path: str, max_pair: int = int(1e8)):74        self.envs = []75        self.index = []76 77        for fname in sorted(os.listdir(data_path)):78            path = os.path.join(data_path, fname)79            env = lmdb.open(path,80                            readonly=True,81                            lock=False,82                            readahead=False,83                            meminit=False)84            self.envs.append(env)85 86        self.latents_shape = [None] * len(self.envs)87        for shard_id, env in enumerate(self.envs):88            self.latents_shape[shard_id] = get_array_shape_from_lmdb(env, 'latents')89            for local_i in range(self.latents_shape[shard_id][0]):90                self.index.append((shard_id, local_i))91 92            # print("shard_id ", shard_id, " local_i ", local_i)93 94        self.max_pair = max_pair95 96    def __len__(self):97        return len(self.index)98 99    def __getitem__(self, idx):100        """101            Outputs:102                - prompts: List of Strings103                - latents: Tensor of shape (num_denoising_steps, num_frames, num_channels, height, width). It is ordered from pure noise to clean image.104        """105        shard_id, local_idx = self.index[idx]106 107        latents = retrieve_row_from_lmdb(108            self.envs[shard_id],109            "latents", np.float16, local_idx,110            shape=self.latents_shape[shard_id][1:]111        )112 113        if len(latents.shape) == 4:114            latents = latents[None, ...]115 116        prompts = retrieve_row_from_lmdb(117            self.envs[shard_id],118            "prompts", str, local_idx119        )120 121        return {122            "prompts": prompts,123            "ode_latent": torch.tensor(latents, dtype=torch.float32)124        }125 126 127class TextImagePairDataset(Dataset):128    def __init__(129        self,130        data_dir,131        transform=None,132        eval_first_n=-1,133        pad_to_multiple_of=None134    ):135        """136        Args:137            data_dir (str): Path to the directory containing:138                - target_crop_info_*.json (metadata file)139                - */ (subdirectory containing images with matching aspect ratio)140            transform (callable, optional): Optional transform to be applied on the image141        """142        self.transform = transform143        data_dir = Path(data_dir)144 145        # Find the metadata JSON file146        metadata_files = list(data_dir.glob('target_crop_info_*.json'))147        if not metadata_files:148            raise FileNotFoundError(f"No metadata file found in {data_dir}")149        if len(metadata_files) > 1:150            raise ValueError(f"Multiple metadata files found in {data_dir}")151 152        metadata_path = metadata_files[0]153        # Extract aspect ratio from metadata filename (e.g. target_crop_info_26-15.json -> 26-15)154        aspect_ratio = metadata_path.stem.split('_')[-1]155 156        # Use aspect ratio subfolder for images157        self.image_dir = data_dir / aspect_ratio158        if not self.image_dir.exists():159            raise FileNotFoundError(f"Image directory not found: {self.image_dir}")160 161        # Load metadata162        with open(metadata_path, 'r') as f:163            self.metadata = json.load(f)164 165        eval_first_n = eval_first_n if eval_first_n != -1 else len(self.metadata)166        self.metadata = self.metadata[:eval_first_n]167 168        # Verify all images exist169        for item in self.metadata:170            image_path = self.image_dir / item['file_name']171            if not image_path.exists():172                raise FileNotFoundError(f"Image not found: {image_path}")173 174        self.dummy_prompt = "DUMMY PROMPT"175        self.pre_pad_len = len(self.metadata)176        if pad_to_multiple_of is not None and len(self.metadata) % pad_to_multiple_of != 0:177            # Duplicate the last entry178            self.metadata += [self.metadata[-1]] * (179                pad_to_multiple_of - len(self.metadata) % pad_to_multiple_of180            )181 182    def __len__(self):183        return len(self.metadata)184 185    def __getitem__(self, idx):186        """187        Returns:188            dict: A dictionary containing:189                - image: PIL Image190                - caption: str191                - target_bbox: list of int [x1, y1, x2, y2]192                - target_ratio: str193                - type: str194                - origin_size: tuple of int (width, height)195        """196        item = self.metadata[idx]197 198        # Load image199        image_path = self.image_dir / item['file_name']200        image = Image.open(image_path).convert('RGB')201 202        # Apply transform if specified203        if self.transform:204            image = self.transform(image)205 206        return {207            'image': image,208            'prompts': item['caption'],209            'target_bbox': item['target_crop']['target_bbox'],210            'target_ratio': item['target_crop']['target_ratio'],211            'type': item['type'],212            'origin_size': (item['origin_width'], item['origin_height']),213            'idx': idx214        }215 216 217def cycle(dl):218    while True:219        for data in dl:220            yield data221