strategies tested
This commit is contained in:
184
sets/Data.py
Normal file
184
sets/Data.py
Normal file
@@ -0,0 +1,184 @@
|
||||
from torchvision import datasets, transforms
|
||||
from torch.utils.data import Dataset, DataLoader, Subset
|
||||
import torch
|
||||
import numpy as np
|
||||
import os
|
||||
|
||||
from enum import Enum, auto
|
||||
class Set_Name(Enum):
|
||||
CELEBA = auto()
|
||||
CASIAFACES = auto()
|
||||
|
||||
# train set transform
|
||||
def train_transform(res):
|
||||
return transforms.Compose([
|
||||
# ResNet expects 224 x 224 res
|
||||
# Inception expects 299 x 299
|
||||
transforms.Resize((res, res)),
|
||||
transforms.RandomHorizontalFlip(p=0.5),
|
||||
transforms.ColorJitter(
|
||||
brightness=0.2,
|
||||
contrast=0.2,
|
||||
saturation=0.1
|
||||
),
|
||||
transforms.ToTensor(),
|
||||
# normalise to
|
||||
transforms.Normalize(
|
||||
mean=[0.485, 0.456, 0.406],
|
||||
std=[0.229, 0.224, 0.225]
|
||||
)
|
||||
])
|
||||
|
||||
# test set transform
|
||||
def test_transform(res):
|
||||
return transforms.Compose([
|
||||
transforms.Resize((res, res)),
|
||||
transforms.ToTensor(),
|
||||
transforms.Normalize(
|
||||
mean=[0.485, 0.456, 0.406],
|
||||
std=[0.229, 0.224, 0.225]
|
||||
)
|
||||
])
|
||||
|
||||
# Load data with 'identity' as target and transform it
|
||||
def get_set(set_name:Set_Name):
|
||||
return fetch_celeb_a() if set_name == Set_Name.CELEBA else fetch_casia_faces()
|
||||
|
||||
def fetch_celeb_a():
|
||||
return datasets.CelebA(
|
||||
root='./data',
|
||||
split='all',
|
||||
target_type='identity',
|
||||
download=True,
|
||||
transform=None
|
||||
)
|
||||
|
||||
def fetch_casia_faces():
|
||||
# location of the data (path relative to project root)
|
||||
final_path = os.path.abspath("./data/casia-set")
|
||||
|
||||
if not os.path.exists(final_path):
|
||||
raise FileNotFoundError(
|
||||
f"Unpacked dataset not found at {final_path}. "
|
||||
"Please run Extractor.py first!"
|
||||
)
|
||||
|
||||
print(f"Loading unpacked CASIA dataset from: {final_path}")
|
||||
|
||||
return datasets.ImageFolder(
|
||||
root=final_path,
|
||||
transform=None
|
||||
)
|
||||
|
||||
|
||||
|
||||
def get_ids_and_counts(dataset):
|
||||
|
||||
target = get_target(dataset=dataset)
|
||||
return torch.unique(
|
||||
input = target,
|
||||
return_counts = True
|
||||
)
|
||||
|
||||
|
||||
|
||||
# filter selected identities from dataset
|
||||
# How many classes, how many images per class
|
||||
def select_ids( dataset, sample_size, class_size):
|
||||
ids, counts = get_ids_and_counts(dataset = dataset)
|
||||
eligible_mask = counts >= sample_size
|
||||
eligible_ids = ids[eligible_mask].numpy()
|
||||
|
||||
if len(eligible_ids) < class_size:
|
||||
raise ValueError(
|
||||
f"Only found {len(eligible_ids)} identities with {sample_size}+ images."
|
||||
)
|
||||
|
||||
# Randomly select identities
|
||||
return np.random.choice(eligible_ids, class_size, replace=False)
|
||||
|
||||
# optional function to get max amount of samples per class
|
||||
def select_top_ids(dataset, class_size):
|
||||
ids, counts = get_ids_and_counts(dataset = dataset)
|
||||
|
||||
# sort by number of images (descending)
|
||||
sorted_indices = torch.argsort(counts, descending = True)
|
||||
|
||||
top_ids = ids[sorted_indices][:class_size].numpy()
|
||||
|
||||
return np.array(top_ids, dtype=int)
|
||||
|
||||
|
||||
def get_target(dataset):
|
||||
"""
|
||||
Unified target extractor.
|
||||
Instantly reads raw dataset arrays or safely scales down to unpack wrapped Subsets.
|
||||
"""
|
||||
if hasattr(dataset, 'identity'):
|
||||
# celebA
|
||||
targets = dataset.identity
|
||||
elif hasattr(dataset, 'targets'):
|
||||
# others
|
||||
targets = dataset.targets
|
||||
else:
|
||||
# If it's an IdentitySubset or standard Subset, extract mapped targets sequentially
|
||||
# This guarantees we get the 0 -> (n-1) remapped labels
|
||||
targets = [dataset[i][1] for i in range(len(dataset))]
|
||||
|
||||
if not isinstance(targets, torch.Tensor):
|
||||
targets = torch.tensor(targets)
|
||||
|
||||
return targets
|
||||
|
||||
|
||||
# split class images to train and test set.
|
||||
def get_indices(dataset, identities, split_at, size = 30):
|
||||
|
||||
if split_at >= size: # debug safety
|
||||
raise ValueError(f"Split point ({split_at}) must be less than total size ({size}).")
|
||||
|
||||
train_indices = []
|
||||
test_indices = []
|
||||
|
||||
target = get_target(dataset=dataset)
|
||||
|
||||
#training_sample = int(sample_size * training_ratio)
|
||||
np.random.seed(42)
|
||||
for person_id in identities:
|
||||
# Get all indices for this specific person
|
||||
indices = torch.where(target == person_id)[0].numpy()
|
||||
|
||||
# Shuffle the indices for this person
|
||||
np.random.shuffle(indices)
|
||||
|
||||
# split data to testing and training
|
||||
train_indices.extend(indices[:split_at])
|
||||
test_indices.extend(indices[split_at:size])
|
||||
|
||||
return train_indices, test_indices
|
||||
|
||||
|
||||
|
||||
def get_unlearning_loaders(dataset: Dataset, forget_class_idx: int, batch_size: int = 32) -> tuple[DataLoader, DataLoader]:
|
||||
"""
|
||||
Splits an IdentitySubset or standard Dataset into forget and retain sets
|
||||
based on a remapped target class index.
|
||||
"""
|
||||
# extract targets
|
||||
targets = get_target(dataset=dataset)
|
||||
|
||||
# mask indices local to this subset
|
||||
forget_indices = torch.where(targets == forget_class_idx)[0].tolist()
|
||||
retain_indices = torch.where(targets != forget_class_idx)[0].tolist()
|
||||
|
||||
# PyTorch Subsets
|
||||
forget_subset = Subset(dataset, forget_indices)
|
||||
retain_subset = Subset(dataset, retain_indices)
|
||||
|
||||
# DataLoaders
|
||||
forget_loader = DataLoader(forget_subset, batch_size=batch_size, shuffle=False)
|
||||
retain_loader = DataLoader(retain_subset, batch_size=batch_size, shuffle=True)
|
||||
|
||||
print(f"[Data Split] Local Class {forget_class_idx}: {len(forget_subset)} samples | Remaining Classes: {len(retain_subset)} samples.")
|
||||
|
||||
return forget_loader, retain_loader
|
||||
Reference in New Issue
Block a user