Download src/data_loader.py from ThaiLearnCoding/Coco_caption_classification: direct link, hf CLI and curl.
- Browser
- Download file 4.39 kB
-
https://huggingface.co/spaces/ThaiLearnCoding/Coco_caption_classification/resolve/main/src/data_loader.py
- Command line
-
hf download hf://spaces/ThaiLearnCoding/Coco_caption_classification/src/data_loader.py
-
curl -L -o data_loader.py https://huggingface.co/spaces/ThaiLearnCoding/Coco_caption_classification/resolve/main/src/data_loader.py
4.39 kB
| import os | |
| import json | |
| import torch | |
| from torch.utils.data import Dataset, DataLoader | |
| from PIL import Image | |
| import random | |
| from collections import defaultdict | |
| from sklearn.model_selection import train_test_split | |
| class CocoCaptionDataset(Dataset): | |
| def __init__(self, data_list, image_dir, preprocess, n_captions=12): | |
| self.data_list = data_list | |
| self.image_dir = image_dir | |
| self.preprocess = preprocess | |
| self.n_captions = n_captions | |
| def __len__(self): | |
| return len(self.data_list) | |
| def __getitem__(self, idx): | |
| item = self.data_list[idx] | |
| image_id = item['image_id'] | |
| image_path = os.path.join(self.image_dir, f"{image_id}.jpg") | |
| image = self.preprocess(Image.open(image_path).convert("RGB")) | |
| # Get all choices and figure out ground truth & distractors | |
| choices = item['choices'] | |
| gt_idx_orig = item['ground_truth_idx'] | |
| gt_caption = choices[gt_idx_orig] | |
| distractors = [c for i, c in enumerate(choices) if i != gt_idx_orig] | |
| # Sample distractors to match n_captions - 1 | |
| num_distractors_needed = self.n_captions - 1 | |
| if len(distractors) >= num_distractors_needed: | |
| selected_distractors = random.sample(distractors, num_distractors_needed) | |
| else: | |
| # Handle edge case if not enough distractors | |
| selected_distractors = distractors + [distractors[0]] * (num_distractors_needed - len(distractors)) | |
| captions = [gt_caption] + selected_distractors | |
| # Shuffle captions | |
| shuffled_indices = list(range(self.n_captions)) | |
| random.shuffle(shuffled_indices) | |
| shuffled_captions = [captions[i] for i in shuffled_indices] | |
| gt_index = shuffled_indices.index(0) # Index of the ground truth in the shuffled list | |
| return image, shuffled_captions, gt_index, image_id, item['true_label'] | |
| def create_few_shot_splits(data, n_max_shots=32, seed=42): | |
| class_to_items = defaultdict(list) | |
| for item in data: | |
| class_to_items[item['true_label']].append(item) | |
| train_32_list = [] | |
| test_list = [] | |
| for cls, items in class_to_items.items(): | |
| if len(items) > n_max_shots: | |
| train_cls, test_cls = train_test_split(items, train_size=n_max_shots, random_state=seed) | |
| train_32_list.extend(train_cls) | |
| test_list.extend(test_cls) | |
| else: | |
| print(f"Warning: Class {cls} has only {len(items)} samples, which is less than {n_max_shots}.") | |
| test_list.extend(items) | |
| return train_32_list, test_list | |
| def create_dataloaders( | |
| train_data, | |
| test_data, | |
| image_dir, | |
| preprocess, | |
| batch_size=32, | |
| k=32, | |
| n_captions=12, | |
| num_workers=2, | |
| prev_k=None, | |
| seed=42, | |
| only_new=False, | |
| ): | |
| # Sample k shots from the max shots train set | |
| train_k_data = [] | |
| class_to_train_items = defaultdict(list) | |
| for item in train_data: | |
| class_to_train_items[item['true_label']].append(item) | |
| rng = random.Random(seed) | |
| for cls, items in class_to_train_items.items(): | |
| items_sorted = sorted(items, key=lambda x: x.get('image_id', 0)) | |
| if prev_k is None or prev_k <= 0: | |
| if len(items_sorted) >= k: | |
| train_k_data.extend(rng.sample(items_sorted, k)) | |
| else: | |
| train_k_data.extend(items_sorted) | |
| continue | |
| prev_k_eff = min(prev_k, len(items_sorted)) | |
| prev_samples = rng.sample(items_sorted, prev_k_eff) | |
| if k <= prev_k_eff: | |
| new_samples = [] | |
| else: | |
| remaining = [item for item in items_sorted if item not in prev_samples] | |
| new_samples = rng.sample(remaining, min(k - prev_k_eff, len(remaining))) | |
| if only_new: | |
| train_k_data.extend(new_samples) | |
| else: | |
| train_k_data.extend(prev_samples + new_samples) | |
| train_dataset = CocoCaptionDataset(train_k_data, image_dir, preprocess, n_captions) | |
| test_dataset = CocoCaptionDataset(test_data, image_dir, preprocess, n_captions) | |
| train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True, num_workers=num_workers) | |
| test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False, num_workers=num_workers) | |
| return train_loader, test_loader | |