180 lines
5.0 KiB
Python
180 lines
5.0 KiB
Python
# Finetuning a selected model
|
|
# on a selected dataset
|
|
# using selected parameters
|
|
|
|
from torch.utils.data import DataLoader
|
|
from sklearn.metrics import classification_report
|
|
import SetUp
|
|
from Data import *
|
|
#from datasets.Casia import *
|
|
from IdentitySubset import IdentitySubset
|
|
#from datasets.UniversalIdentitySubset import UniversalIdentitySubset as IdentitySubset
|
|
# models
|
|
from architectures.Model import Model, Architecture
|
|
|
|
from unlearning.LinearFiltration import LinearFiltration
|
|
|
|
import Util
|
|
# WeightFiltration, CertifiedRemoval
|
|
|
|
# numbre of classes
|
|
CLASS_SIZE = 20
|
|
# batch
|
|
BATCH_SIZE = 32
|
|
|
|
# size of images per class trainset + testset
|
|
# 30 works best, more than that and we dont have enough data
|
|
SAMPLE_SIZE = 30
|
|
|
|
# this is then (full_sample - test_sample)
|
|
TRAINING_SMPLE = 27
|
|
|
|
# learning rate
|
|
LR_RATE = 0.0001
|
|
EPOCHS = 20
|
|
|
|
# depends on model architecture
|
|
# ResNet, DenseNet = 224
|
|
# Inception = 299
|
|
RESOLUTION = 224
|
|
|
|
# model architecture options are
|
|
# - RESNET18
|
|
# - RESNET50
|
|
# - DENSENET121
|
|
# - INCEPTION
|
|
# - GOOGLENET
|
|
# - EFFICIENTNET
|
|
# - SHUFFLENET
|
|
arch = Architecture.RESNET50
|
|
|
|
# DATA PREPARATION
|
|
# load data set and prepare
|
|
dataset = get_set()
|
|
# select identities for experiment
|
|
#selected_identities = select_ids(
|
|
# dataset = dataset,
|
|
# sample_size = SAMPLE_SIZE,
|
|
# class_size = CLASS_SIZE
|
|
# )
|
|
|
|
# this selects the top 50 based on sample size
|
|
# that way repeated calls return the same classes
|
|
selected_identities = select_top_ids(
|
|
dataset=dataset,
|
|
class_size= CLASS_SIZE,
|
|
)
|
|
|
|
print(f'> Selected {CLASS_SIZE} random identity classes from CelebA dataset.')
|
|
print(f'> A class has {TRAINING_SMPLE} train and {SAMPLE_SIZE-TRAINING_SMPLE} test samples')
|
|
|
|
# split class images to train/test indices
|
|
train_indices, test_indices = get_indices(
|
|
dataset = dataset,
|
|
identities = selected_identities,
|
|
split_at = TRAINING_SMPLE
|
|
)
|
|
|
|
# helps map class id to index
|
|
id_map = {old_id: new_id for new_id, old_id in enumerate(selected_identities)}
|
|
|
|
# we remap identities because crossEntropyLoss requires in indices 0 -> (n-1)
|
|
# where n = class size.
|
|
tr_transform = train_transform(res = RESOLUTION)
|
|
train_data = IdentitySubset(
|
|
dataset=dataset,
|
|
indices=train_indices,
|
|
id_mapping=id_map,
|
|
transform=tr_transform)
|
|
|
|
train_loader = DataLoader(
|
|
train_data,
|
|
batch_size = BATCH_SIZE,
|
|
shuffle = True)
|
|
|
|
print(f"> Total training images: {len(train_data)}")
|
|
|
|
print(f'> Constants : Classes = {CLASS_SIZE}, Batch = {BATCH_SIZE}, epochs = {EPOCHS}')
|
|
|
|
# MODEL PREPARATION
|
|
# cuda if exists (it does here)
|
|
device = SetUp.get_device()
|
|
|
|
for i in range(0,CLASS_SIZE):
|
|
# Create model using Factory
|
|
model = Model.create(
|
|
arch = arch,
|
|
device = device,
|
|
size = CLASS_SIZE)
|
|
|
|
# we may need to load existing model or finetune
|
|
model.train(
|
|
epochs = EPOCHS,
|
|
loader = train_loader,
|
|
rate = LR_RATE)
|
|
|
|
# save.
|
|
model.save(filename=arch.name.lower())
|
|
|
|
|
|
# done tuning
|
|
|
|
# EVALUATE
|
|
te_transform = test_transform(RESOLUTION)
|
|
# Testing
|
|
test_data = IdentitySubset(
|
|
dataset = dataset,
|
|
indices=test_indices,
|
|
id_mapping=id_map,
|
|
transform=te_transform)
|
|
|
|
test_loader = DataLoader(
|
|
test_data,
|
|
batch_size=BATCH_SIZE,
|
|
shuffle=False)
|
|
|
|
print(f"Total test images for these {CLASS_SIZE} classes: {len(test_data)}")
|
|
|
|
# Evaluate
|
|
mode, accuracy, report_dict = model.evaluate(
|
|
loader = test_loader,
|
|
mode="finetunned"
|
|
)
|
|
Util._log_to_csv(model=reloaded, mode = "finetuned", accuracy=accuracy, report_dict=report_dict, strategy="base")
|
|
|
|
# test again
|
|
reloaded = Model.create(
|
|
arch=arch,
|
|
device = device,
|
|
size = CLASS_SIZE
|
|
)
|
|
reloaded.load(arch = arch)
|
|
print("fine tunned model loaded")
|
|
# reloaded.evaluate(
|
|
# loader = test_loader
|
|
#)
|
|
|
|
# Unlearning
|
|
FORGET_CLASS_IDX = i
|
|
|
|
forget_test_loader, retain_test_loader = get_forget_retain_loaders(
|
|
dataset=test_data,
|
|
forget_class_idx=FORGET_CLASS_IDX,
|
|
batch_size=BATCH_SIZE
|
|
)
|
|
|
|
#retain_test_loader = DataLoader(retain_test_loader.dataset, batch_size=BATCH_SIZE, shuffle=False)
|
|
|
|
# 3. Instantiate and apply the Linear Filtration rule
|
|
filtration = LinearFiltration(target_class_idx=FORGET_CLASS_IDX)
|
|
filtration.apply(reloaded.model)
|
|
|
|
|
|
# 4. Final Performance Analysis
|
|
print("\n--- Performance on Retained Classes")
|
|
mode, accuracy, report_dict = reloaded.evaluate(loader=retain_test_loader, mode="retain")
|
|
Util._log_to_csv(model=reloaded, mode = "retain", accuracy=accuracy, report_dict=report_dict, strategy="linearFiltration")
|
|
|
|
print("\n--- Performance on Forgotten Class")
|
|
mode, accuracy, report_dict = reloaded.evaluate(loader=forget_test_loader,mode="forget")
|
|
Util._log_to_csv(model=reloaded, mode = "forgotten", accuracy=accuracy, report_dict=report_dict, strategy="linearFiltration") |