From 7c51adf7448d29a965bfa50e8eec0a2e96219ae1 Mon Sep 17 00:00:00 2001 From: junjie1003 Date: Mon, 25 Mar 2024 09:31:53 +0800 Subject: [PATCH] artifact submission --- .gitignore | 18 +- BM/debias/datasets/utk_face.py | 2 +- BM/train_celeba/train_celeba_adv.py | 258 ++++++------- BM/train_celeba/train_celeba_bc.py | 247 ++++++------- BM/train_celeba/train_celeba_bm.py | 334 ++++++++--------- BM/train_celeba/train_celeba_di.py | 239 ++++++------ BM/train_celeba/train_celeba_os.py | 234 ++++++------ BM/train_celeba/train_celeba_us.py | 220 +++++------ BM/train_celeba/train_celeba_uw.py | 232 ++++++------ BM/train_cifar10/train_cifar10_adv.py | 240 ++++++------ BM/train_cifar10/train_cifar10_bc.py | 231 +++++------- BM/train_cifar10/train_cifar10_bm.py | 324 ++++++++-------- BM/train_cifar10/train_cifar10_di.py | 244 +++++-------- BM/train_cifar10/train_cifar10_os.py | 214 +++++------ BM/train_cifar10/train_cifar10_us.py | 227 +++++------- BM/train_cifar10/train_cifar10_uw.py | 232 +++++------- BM/train_utk_face/train_utk_face_adv.py | 253 ++++++------- BM/train_utk_face/train_utk_face_bc.py | 255 ++++++------- BM/train_utk_face/train_utk_face_bm.py | 345 ++++++++---------- BM/train_utk_face/train_utk_face_di.py | 229 +++++------- BM/train_utk_face/train_utk_face_os.py | 231 +++++------- BM/train_utk_face/train_utk_face_us.py | 221 +++++------ BM/train_utk_face/train_utk_face_uw.py | 228 ++++++------ FAAP/arguments.py | 27 -- {datasets => FAAP/datasets}/__init__.py | 0 {datasets => FAAP/datasets}/celeba.py | 0 {datasets => FAAP/datasets}/cifar10s.py | 0 {datasets => FAAP/datasets}/utkface.py | 2 +- FAAP/faap.py | 84 +++-- FAAP/test_adversarial_examples.py | 140 +++---- FAAP/train_deployed_model.py | 45 +-- FDR/celeba.py | 125 +++---- FDR/cifar10s.py | 116 +++--- FDR/datasets/__init__.py | 0 FDR/datasets/celeba.py | 87 +++++ FDR/datasets/cifar10s.py | 142 +++++++ FDR/datasets/utkface.py | 160 ++++++++ FDR/utils.py | 21 +- FDR/utkface.py | 124 +++---- FLAC/datasets/utk_face.py | 2 +- FLAC/train_celeba.py | 226 +++++------- FLAC/train_cifar10s.py | 173 ++++----- FLAC/train_utk_face.py | 225 +++++------- FR/datasets/__init__.py | 0 FR/datasets/celeba.py | 87 +++++ FR/datasets/cifar10s.py | 142 +++++++ FR/datasets/utkface.py | 160 ++++++++ FR/program.py | 21 +- FR/test_transfer.py | 220 ----------- FR/train.py | 222 ++++------- FR/utils.py | 20 +- MFD/arguments.py | 78 ---- MFD/data_handler/dataset_factory.py | 22 +- MFD/main.py | 135 +++---- MFD/networks/model_factory.py | 11 +- MFD/trainer/kd_hinton.py | 8 +- MFD/trainer/kd_mfd.py | 79 ++-- MFD/trainer/loss_utils.py | 21 +- MFD/trainer/trainer_factory.py | 122 +++---- MFD/trainer/vanilla_train.py | 5 +- MFD/utils.py | 72 ++-- README.md | 322 +++++----------- arguments.py | 99 +++++ figures/accuracy.png | Bin 0 -> 84527 bytes figures/correlation.png | Bin 0 -> 49639 bytes figures/datasets.png | Bin 0 -> 28324 bytes figures/fairness.png | Bin 0 -> 439627 bytes figures/methods.png | Bin 0 -> 152800 bytes figures/time.png | Bin 0 -> 61424 bytes helper.py | 17 - plot/boxplot_acc_celeba.pdf | Bin 0 -> 33493 bytes plot/boxplot_acc_cifar10s.pdf | Bin 0 -> 33726 bytes plot/boxplot_acc_utkface_age.pdf | Bin 0 -> 33753 bytes plot/boxplot_acc_utkface_race.pdf | Bin 0 -> 34112 bytes plot/boxplot_accuracy.py | 288 +++++++++++++++ plot/correlation_matrix.pdf | Bin 0 -> 25403 bytes plot/pearson_correlation.py | 109 ++++++ requirements.txt | 1 + ...v_gender_blond_hair.txt => adv_celeba.txt} | 0 .../{cifar10s/adv.txt => adv_cifar10s.txt} | 0 ...adv_age_gender.txt => adv_utkface_age.txt} | 0 ...v_race_gender.txt => adv_utkface_race.txt} | 0 ...bb_gender_blond_hair.txt => bc_celeba.txt} | 0 .../{cifar10s/bc_bb.txt => bc_cifar10s.txt} | 0 ...c_bb_age_gender.txt => bc_utkface_age.txt} | 0 ...bb_race_gender.txt => bc_utkface_race.txt} | 0 ...ne_gender_blond_hair.txt => bm_celeba.txt} | 0 .../{cifar10s/bm_none.txt => bm_cifar10s.txt} | 0 ...none_age_gender.txt => bm_utkface_age.txt} | 0 ...ne_race_gender.txt => bm_utkface_race.txt} | 0 results/boxplot.sh | 9 - results/boxplot_acc.py | 128 ------- results/boxplot_acc_transpose.py | 185 ---------- results/celeba/bm_os_gender_blond_hair.txt | 7 - results/celeba/bm_us_gender_blond_hair.txt | 7 - results/celeba/bm_uw_gender_blond_hair.txt | 7 - results/celeba/fdr_ae_gender_blond_hair.txt | 8 - results/celeba/fdr_mmf_gender_blond_hair.txt | 8 - results/cifar10s/bm_os.txt | 8 - results/cifar10s/bm_us.txt | 8 - results/cifar10s/bm_uw.txt | 8 - results/cifar10s/fdr_ae.txt | 8 - results/cifar10s/fdr_mmf.txt | 7 - results/correlation_matrix.pdf | Bin 12833 -> 0 bytes ...di_gender_blond_hair.txt => di_celeba.txt} | 0 results/{cifar10s/di.txt => di_cifar10s.txt} | 0 .../di_age_gender.txt => di_utkface_age.txt} | 0 ...di_race_gender.txt => di_utkface_race.txt} | 0 ..._gender_blond_hair.txt => faap_celeba.txt} | 0 .../{cifar10s/faap.txt => faap_cifar10s.txt} | 0 ...ap_age_gender.txt => faap_utkface_age.txt} | 0 ..._race_gender.txt => faap_utkface_race.txt} | 0 ...o_gender_blond_hair.txt => fdr_celeba.txt} | 0 .../{cifar10s/fdr_eo.txt => fdr_cifar10s.txt} | 0 ..._eo_age_gender.txt => fdr_utkface_age.txt} | 0 ...o_race_gender.txt => fdr_utkface_race.txt} | 0 ..._gender_blond_hair.txt => flac_celeba.txt} | 0 .../{cifar10s/flac.txt => flac_cifar10s.txt} | 0 ...ac_age_gender.txt => flac_utkface_age.txt} | 0 ..._race_gender.txt => flac_utkface_race.txt} | 0 ...er_blond_hair.txt => fr_border_celeba.txt} | 0 .../fr_border.txt => fr_border_cifar10s.txt} | 0 ...e_gender.txt => fr_border_utkface_age.txt} | 0 ..._gender.txt => fr_border_utkface_race.txt} | 0 ...der_blond_hair.txt => fr_patch_celeba.txt} | 0 .../fr_patch.txt => fr_patch_cifar10s.txt} | 0 ...ge_gender.txt => fr_patch_utkface_age.txt} | 0 ...e_gender.txt => fr_patch_utkface_race.txt} | 0 ...d_gender_blond_hair.txt => mfd_celeba.txt} | 0 .../{cifar10s/mfd.txt => mfd_cifar10s.txt} | 0 ...mfd_age_gender.txt => mfd_utkface_age.txt} | 0 ...d_race_gender.txt => mfd_utkface_race.txt} | 0 ...os_gender_blond_hair.txt => os_celeba.txt} | 0 results/{cifar10s/os.txt => os_cifar10s.txt} | 0 .../os_age_gender.txt => os_utkface_age.txt} | 0 ...os_race_gender.txt => os_utkface_race.txt} | 0 ...us_gender_blond_hair.txt => us_celeba.txt} | 0 results/{cifar10s/us.txt => us_cifar10s.txt} | 0 .../us_age_gender.txt => us_utkface_age.txt} | 0 ...us_race_gender.txt => us_utkface_race.txt} | 0 results/utkface/bm_os_age_gender.txt | 7 - results/utkface/bm_os_race_gender.txt | 7 - results/utkface/bm_us_age_gender.txt | 7 - results/utkface/bm_us_race_gender.txt | 7 - results/utkface/bm_uw_age_gender.txt | 7 - results/utkface/bm_uw_race_gender.txt | 7 - results/utkface/fdr_ae_age_gender.txt | 8 - results/utkface/fdr_ae_race_gender.txt | 8 - results/utkface/fdr_mmf_age_gender.txt | 8 - results/utkface/fdr_mmf_race_gender.txt | 8 - ...uw_gender_blond_hair.txt => uw_celeba.txt} | 0 results/{cifar10s/uw.txt => uw_cifar10s.txt} | 0 .../uw_age_gender.txt => uw_utkface_age.txt} | 0 ...uw_race_gender.txt => uw_utkface_race.txt} | 0 scripts/celeba.sh | 44 +++ scripts/cifar10s.sh | 44 +++ scripts/clear_cache.sh | 7 + scripts/demo.sh | 16 + scripts/test_celeba.sh | 44 +++ scripts/test_cifar10s.sh | 44 +++ scripts/test_utkface.sh | 58 +++ scripts/utkface.sh | 58 +++ 162 files changed, 4857 insertions(+), 5148 deletions(-) delete mode 100644 FAAP/arguments.py rename {datasets => FAAP/datasets}/__init__.py (100%) rename {datasets => FAAP/datasets}/celeba.py (100%) rename {datasets => FAAP/datasets}/cifar10s.py (100%) rename {datasets => FAAP/datasets}/utkface.py (98%) create mode 100644 FDR/datasets/__init__.py create mode 100644 FDR/datasets/celeba.py create mode 100644 FDR/datasets/cifar10s.py create mode 100644 FDR/datasets/utkface.py create mode 100644 FR/datasets/__init__.py create mode 100644 FR/datasets/celeba.py create mode 100644 FR/datasets/cifar10s.py create mode 100644 FR/datasets/utkface.py delete mode 100644 FR/test_transfer.py delete mode 100644 MFD/arguments.py create mode 100644 arguments.py create mode 100644 figures/accuracy.png create mode 100644 figures/correlation.png create mode 100644 figures/datasets.png create mode 100644 figures/fairness.png create mode 100644 figures/methods.png create mode 100644 figures/time.png create mode 100644 plot/boxplot_acc_celeba.pdf create mode 100644 plot/boxplot_acc_cifar10s.pdf create mode 100644 plot/boxplot_acc_utkface_age.pdf create mode 100644 plot/boxplot_acc_utkface_race.pdf create mode 100644 plot/boxplot_accuracy.py create mode 100644 plot/correlation_matrix.pdf create mode 100644 plot/pearson_correlation.py rename results/{celeba/adv_gender_blond_hair.txt => adv_celeba.txt} (100%) rename results/{cifar10s/adv.txt => adv_cifar10s.txt} (100%) rename results/{utkface/adv_age_gender.txt => adv_utkface_age.txt} (100%) rename results/{utkface/adv_race_gender.txt => adv_utkface_race.txt} (100%) rename results/{celeba/bc_bb_gender_blond_hair.txt => bc_celeba.txt} (100%) rename results/{cifar10s/bc_bb.txt => bc_cifar10s.txt} (100%) rename results/{utkface/bc_bb_age_gender.txt => bc_utkface_age.txt} (100%) rename results/{utkface/bc_bb_race_gender.txt => bc_utkface_race.txt} (100%) rename results/{celeba/bm_none_gender_blond_hair.txt => bm_celeba.txt} (100%) rename results/{cifar10s/bm_none.txt => bm_cifar10s.txt} (100%) rename results/{utkface/bm_none_age_gender.txt => bm_utkface_age.txt} (100%) rename results/{utkface/bm_none_race_gender.txt => bm_utkface_race.txt} (100%) delete mode 100644 results/boxplot.sh delete mode 100644 results/boxplot_acc.py delete mode 100644 results/boxplot_acc_transpose.py delete mode 100644 results/celeba/bm_os_gender_blond_hair.txt delete mode 100644 results/celeba/bm_us_gender_blond_hair.txt delete mode 100644 results/celeba/bm_uw_gender_blond_hair.txt delete mode 100644 results/celeba/fdr_ae_gender_blond_hair.txt delete mode 100644 results/celeba/fdr_mmf_gender_blond_hair.txt delete mode 100644 results/cifar10s/bm_os.txt delete mode 100644 results/cifar10s/bm_us.txt delete mode 100644 results/cifar10s/bm_uw.txt delete mode 100644 results/cifar10s/fdr_ae.txt delete mode 100644 results/cifar10s/fdr_mmf.txt delete mode 100644 results/correlation_matrix.pdf rename results/{celeba/di_gender_blond_hair.txt => di_celeba.txt} (100%) rename results/{cifar10s/di.txt => di_cifar10s.txt} (100%) rename results/{utkface/di_age_gender.txt => di_utkface_age.txt} (100%) rename results/{utkface/di_race_gender.txt => di_utkface_race.txt} (100%) rename results/{celeba/faap_gender_blond_hair.txt => faap_celeba.txt} (100%) rename results/{cifar10s/faap.txt => faap_cifar10s.txt} (100%) rename results/{utkface/faap_age_gender.txt => faap_utkface_age.txt} (100%) rename results/{utkface/faap_race_gender.txt => faap_utkface_race.txt} (100%) rename results/{celeba/fdr_eo_gender_blond_hair.txt => fdr_celeba.txt} (100%) rename results/{cifar10s/fdr_eo.txt => fdr_cifar10s.txt} (100%) rename results/{utkface/fdr_eo_age_gender.txt => fdr_utkface_age.txt} (100%) rename results/{utkface/fdr_eo_race_gender.txt => fdr_utkface_race.txt} (100%) rename results/{celeba/flac_gender_blond_hair.txt => flac_celeba.txt} (100%) rename results/{cifar10s/flac.txt => flac_cifar10s.txt} (100%) rename results/{utkface/flac_age_gender.txt => flac_utkface_age.txt} (100%) rename results/{utkface/flac_race_gender.txt => flac_utkface_race.txt} (100%) rename results/{celeba/fr_border_gender_blond_hair.txt => fr_border_celeba.txt} (100%) rename results/{cifar10s/fr_border.txt => fr_border_cifar10s.txt} (100%) rename results/{utkface/fr_border_age_gender.txt => fr_border_utkface_age.txt} (100%) rename results/{utkface/fr_border_race_gender.txt => fr_border_utkface_race.txt} (100%) rename results/{celeba/fr_patch_gender_blond_hair.txt => fr_patch_celeba.txt} (100%) rename results/{cifar10s/fr_patch.txt => fr_patch_cifar10s.txt} (100%) rename results/{utkface/fr_patch_age_gender.txt => fr_patch_utkface_age.txt} (100%) rename results/{utkface/fr_patch_race_gender.txt => fr_patch_utkface_race.txt} (100%) rename results/{celeba/mfd_gender_blond_hair.txt => mfd_celeba.txt} (100%) rename results/{cifar10s/mfd.txt => mfd_cifar10s.txt} (100%) rename results/{utkface/mfd_age_gender.txt => mfd_utkface_age.txt} (100%) rename results/{utkface/mfd_race_gender.txt => mfd_utkface_race.txt} (100%) rename results/{celeba/os_gender_blond_hair.txt => os_celeba.txt} (100%) rename results/{cifar10s/os.txt => os_cifar10s.txt} (100%) rename results/{utkface/os_age_gender.txt => os_utkface_age.txt} (100%) rename results/{utkface/os_race_gender.txt => os_utkface_race.txt} (100%) rename results/{celeba/us_gender_blond_hair.txt => us_celeba.txt} (100%) rename results/{cifar10s/us.txt => us_cifar10s.txt} (100%) rename results/{utkface/us_age_gender.txt => us_utkface_age.txt} (100%) rename results/{utkface/us_race_gender.txt => us_utkface_race.txt} (100%) delete mode 100644 results/utkface/bm_os_age_gender.txt delete mode 100644 results/utkface/bm_os_race_gender.txt delete mode 100644 results/utkface/bm_us_age_gender.txt delete mode 100644 results/utkface/bm_us_race_gender.txt delete mode 100644 results/utkface/bm_uw_age_gender.txt delete mode 100644 results/utkface/bm_uw_race_gender.txt delete mode 100644 results/utkface/fdr_ae_age_gender.txt delete mode 100644 results/utkface/fdr_ae_race_gender.txt delete mode 100644 results/utkface/fdr_mmf_age_gender.txt delete mode 100644 results/utkface/fdr_mmf_race_gender.txt rename results/{celeba/uw_gender_blond_hair.txt => uw_celeba.txt} (100%) rename results/{cifar10s/uw.txt => uw_cifar10s.txt} (100%) rename results/{utkface/uw_age_gender.txt => uw_utkface_age.txt} (100%) rename results/{utkface/uw_race_gender.txt => uw_utkface_race.txt} (100%) create mode 100644 scripts/celeba.sh create mode 100644 scripts/cifar10s.sh create mode 100644 scripts/clear_cache.sh create mode 100644 scripts/demo.sh create mode 100644 scripts/test_celeba.sh create mode 100644 scripts/test_cifar10s.sh create mode 100644 scripts/test_utkface.sh create mode 100644 scripts/utkface.sh diff --git a/.gitignore b/.gitignore index bf25a26..d2a4a9c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,18 +1,10 @@ +checkpoints data/celeba/img_align_celeba data/celeba/img_align_celeba_png.zip data/celeba/img_align_celeba.zip -data/cifar10s/cifar-10-python.tar.gz -data/utkface/images/ +data/cifar10s +data/utkface/images data/utkface/UTKFace.tar.gz -FAAP/log -FAAP/saved_models -FDR/checkpoints -FDR/log FLAC/bias_capturing_classifiers -FR/border -FR/log -FR/patch -FR/std -MFD/log -MFD/results -MFD/trained_models +log +model_checkpoints diff --git a/BM/debias/datasets/utk_face.py b/BM/debias/datasets/utk_face.py index 4e5156b..cbe1501 100644 --- a/BM/debias/datasets/utk_face.py +++ b/BM/debias/datasets/utk_face.py @@ -58,7 +58,7 @@ def __init__(self, root, transform, split, data_split = 'train' if self.train else 'test' self.files, self.targets, self.bias_targets = pickle.load(open(save_path / f'{data_split}_dataset.pkl', 'rb')) if split in ['valid', 'test']: - save_path = Path(f'/root/study/data/clusters/utk_face_rand_indices_{bias_attr}.pkl') + save_path = Path(f'{Path(root).parent.absolute()}/clusters/utk_face_rand_indices_{bias_attr}.pkl') if not save_path.exists(): rand_indices = torch.randperm(len(self.targets)) pickle.dump(rand_indices, open(save_path, 'wb')) diff --git a/BM/train_celeba/train_celeba_adv.py b/BM/train_celeba/train_celeba_adv.py index 15c9197..049fa78 100644 --- a/BM/train_celeba/train_celeba_adv.py +++ b/BM/train_celeba/train_celeba_adv.py @@ -1,56 +1,36 @@ +import os +import sys +import time +import torch +import logging import argparse import datetime -import logging -import time -from pathlib import Path - import numpy as np -import torch from torch import nn -import torch.nn.functional as F from tqdm import tqdm +from pathlib import Path +from numpy import mean, std +import torch.nn.functional as F -import sys -sys.path.insert(1, './') +project_dir = "/root/DL-Fairness-Study" +sys.path.insert(1, os.path.join(project_dir, "BM")) +from debias.utils.logging import set_logging from debias.datasets.celeba import get_celeba from debias.networks.resnet import FCResNet18_Base -from debias.utils.logging import set_logging -from debias.utils.utils import (AverageMeter, MultiDimAverageMeter, accuracy, - pretty_dict, save_model, set_seed) +from debias.utils.utils import AverageMeter, MultiDimAverageMeter, accuracy, pretty_dict, save_model, set_seed -import os -sys.path.insert(1, '/root/study') +sys.path.insert(1, project_dir) -from numpy import mean, std +from arguments import get_args from metrics import get_metric_index, get_all_metrics, print_all_metrics -def parse_option(): - parser = argparse.ArgumentParser() - parser.add_argument('--exp_name', type=str, default='test') - parser.add_argument('--gpu', type=int, default=0) - parser.add_argument('--task', type=str, default='blonde') - - parser.add_argument('--epochs', type=int, default=20) - parser.add_argument('--seed', type=int, default=1) - - parser.add_argument('--bs', type=int, default=128, help='batch_size') - parser.add_argument('--lr', type=float, default=1e-3) - parser.add_argument('--training_ratio', type=float, default=2) - parser.add_argument('--alpha', type=float, default=1) - - opt = parser.parse_args() - os.environ['CUDA_VISIBLE_DEVICES'] = str(opt.gpu) - - return opt - - def set_model(): model = FCResNet18_Base().cuda() class_criterion = nn.CrossEntropyLoss() domain_criterion = nn.CrossEntropyLoss() - + class_network = nn.Linear(512, 2).cuda() domain_network = nn.Linear(512, 2).cuda() @@ -65,27 +45,27 @@ def train(train_loader, model, criterion, optimizer, epoch, opt): for images, labels, _, biases, _, _ in tqdm(train_iter, ascii=True): bsz = labels.shape[0] labels, biases = labels.cuda(), biases.cuda() - + optimizer[0].zero_grad() optimizer[1].zero_grad() optimizer[2].zero_grad() - + images = images.cuda() features = model[0](images) class_out = model[1](features) domain_out = model[2](features) class_loss = criterion[0](class_out, labels) - domain_loss = criterion[1](domain_out, biases) + domain_loss = criterion[1](domain_out, biases) if epoch % opt.training_ratio == 0: log_softmax = F.log_softmax(domain_out, dim=1) confusion_loss = -log_softmax.mean(dim=1).mean() - loss = class_loss + opt.alpha*confusion_loss + loss = class_loss + opt.alpha * confusion_loss loss.backward() optimizer[0].step() optimizer[1].step() - + else: # Update the domain classifier domain_loss.backward() @@ -112,74 +92,98 @@ def validate(val_loader, model): preds = output.data.max(1, keepdim=True)[1].squeeze(1) - acc1, = accuracy(output, labels, topk=(1,)) + (acc1,) = accuracy(output, labels, topk=(1,)) top1.update(acc1[0], bsz) corrects = (preds == labels).long() attrwise_acc_meter.add(corrects.cpu(), torch.stack([labels.cpu(), biases.cpu()], dim=1)) - return top1.avg, attrwise_acc_meter.get_mean(), attrwise_acc_meter.get_acc_diff() + return top1.avg, attrwise_acc_meter.get_mean(), attrwise_acc_meter.get_acc_diff() def main(): - opt = parse_option() + opt = get_args() + opt.target = "blonde" if opt.target == "Blond_Hair" else opt.target + exp_name = f"adv-celeba-lr{opt.lr}-bs{opt.batch_size}-epochs{opt.epochs}-seed{opt.seed}" - exp_name = f'adv-celeba_{opt.task}-{opt.exp_name}-lr{opt.lr}-bs{opt.bs}-seed{opt.seed}' - opt.exp_name = exp_name + # result_dir = f'../results/celeba' + # result_path = Path(result_dir) + # result_path.mkdir(parents=True, exist_ok=True) + # if opt.target == 'blonde': + # fout = open('/'.join([str(result_path), f'adv_gender_blond_hair.txt']), 'w') - result_dir = f'../results/celeba' - result_path = Path(result_dir) - result_path.mkdir(parents=True, exist_ok=True) - if opt.task == 'blonde': - fout = open('/'.join([str(result_path), f'adv_gender_blond_hair.txt']), 'w') + # results = {} + # metric_index = get_metric_index() + # for m_index in metric_index: + # results[m_index] = [] - results = {} - metric_index = get_metric_index() - for m_index in metric_index: - results[m_index] = [] + repeat_time = 1 - repeat_time = 10 - - output_dir = f'exp_results/{exp_name}' + output_dir = f"{project_dir}/checkpoints/{exp_name}" save_path = Path(output_dir) save_path.mkdir(parents=True, exist_ok=True) - set_logging(exp_name, 'INFO', str(save_path)) - logging.info(f'Set seed: {opt.seed}') + print(f"Set seed: {opt.seed}") set_seed(opt.seed) - logging.info(f'save_path: {save_path}') + print(f"save_path: {save_path}") np.set_printoptions(precision=3) torch.set_printoptions(precision=3) - root = '../data' - train_loader = get_celeba( - root, - batch_size=opt.bs, - target_attr=opt.task, - split='train', - aug=False) + root = f"{project_dir}/data" + train_loader = get_celeba(root, batch_size=opt.batch_size, target_attr=opt.target, split="train", aug=False) val_loaders = {} - val_loaders['valid'] = get_celeba( - root, - batch_size=256, - target_attr=opt.task, - split='train_valid', - aug=False) - - val_loaders['test'] = get_celeba( - root, - batch_size=256, - target_attr=opt.task, - split='valid', - aug=False) + val_loaders["valid"] = get_celeba(root, batch_size=256, target_attr=opt.target, split="train_valid", aug=False) + + val_loaders["test"] = get_celeba(root, batch_size=256, target_attr=opt.target, split="valid", aug=False) for r in range(repeat_time): - logging.info(f'Repeated experiment: {r+1}') + # print(f"Repeated experiment: {r+1}") model, criterion = set_model() + # Evaluation + if opt.checkpoint: + model[0].load_state_dict(torch.load(f"{save_path}/best_model.pt")["model"]) + model[0].eval() + model[1].load_state_dict(torch.load(f"{save_path}/best_pred.pt")["model"]) + model[1].eval() + + with torch.no_grad(): + all_labels, all_biases, all_preds = [], [], [] + for images, labels, _, biases, _, _ in val_loaders["test"]: + images = images.cuda() + + feats = model[0](images) + output = model[1](feats) + + preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() + + all_labels.append(labels) + all_biases.append(biases) + all_preds.append(preds) + + fin_labels = torch.cat(all_labels) + fin_biases = torch.cat(all_biases) + fin_preds = torch.cat(all_preds) + + ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) + print_all_metrics(ret=ret) + + sys.exit() + + # ret["time per epoch"] = total_time / opt.epochs + # for i in range(len(metric_index)): + # results[metric_index[i]].append(ret[metric_index[i]]) + + # for m_index in metric_index: + # fout.write(m_index + "\t") + # for i in range(repeat_time): + # fout.write("%f\t" % results[m_index][i]) + # fout.write("%f\t%f\n" % (mean(results[m_index]), std(results[m_index]))) + # fout.close() + decay_epochs = [opt.epochs // 3, opt.epochs * 2 // 3] optimizer_base = torch.optim.Adam(model[0].parameters(), lr=opt.lr, weight_decay=1e-4) @@ -190,20 +194,18 @@ def main(): scheduler_base = torch.optim.lr_scheduler.MultiStepLR(optimizers[0], milestones=decay_epochs, gamma=0.1) scheduler_class = torch.optim.lr_scheduler.MultiStepLR(optimizers[1], milestones=decay_epochs, gamma=0.1) scheduler_domain = torch.optim.lr_scheduler.MultiStepLR(optimizers[2], milestones=decay_epochs, gamma=0.1) - schedulers = [scheduler_base,scheduler_class, scheduler_domain] - - logging.info(f'decay_epochs: {decay_epochs}') + schedulers = [scheduler_base, scheduler_class, scheduler_domain] - # (save_path / 'checkpoints').mkdir(parents=True, exist_ok=True) + print(f"decay_epochs: {decay_epochs}") - best_accs = {'valid': 0, 'test': 0} - best_epochs = {'valid': 0, 'test': 0} + best_accs = {"valid": 0, "test": 0} + best_epochs = {"valid": 0, "test": 0} best_stats = {} start_time = time.time() for epoch in range(1, opt.epochs + 1): - logging.info(f'[{epoch} / {opt.epochs}] Learning rate: {schedulers[0].get_last_lr()[0]}') + print(f"[{epoch} / {opt.epochs}] Learning rate: {schedulers[0].get_last_lr()[0]}") loss = train(train_loader, model, criterion, optimizers, epoch, opt) - logging.info(f'[{epoch} / {opt.epochs}] Loss: {loss:.4f}') + print(f"[{epoch} / {opt.epochs}] Loss: {loss:.4f}") schedulers[0].step() schedulers[1].step() @@ -213,64 +215,40 @@ def main(): for key, val_loader in val_loaders.items(): accs, valid_attrwise_accs, diff = validate(val_loader, model) - stats[f'{key}/acc'] = accs.item() - stats[f'{key}/acc_unbiased'] = torch.mean(valid_attrwise_accs).item() * 100 - stats[f'{key}/diff'] = diff.item() * 100 - - eye_tsr = train_loader.dataset.eye_tsr - - stats[f'{key}/acc_skew'] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 - stats[f'{key}/acc_align'] = valid_attrwise_accs[eye_tsr == 0.0].mean().item() * 100 + stats[f"{key}/acc"] = accs.item() + stats[f"{key}/acc_unbiased"] = torch.mean(valid_attrwise_accs).item() * 100 + stats[f"{key}/diff"] = diff.item() * 100 - logging.info(f'[{epoch} / {opt.epochs}] {valid_attrwise_accs} {stats}') - for tag in val_loaders.keys(): - if stats[f'{tag}/acc_unbiased'] > best_accs[tag]: - best_accs[tag] = stats[f'{tag}/acc_unbiased'] - best_epochs[tag] = epoch - best_stats[tag] = pretty_dict(**{f'best_{tag}_{k}': v for k, v in stats.items()}) - - logging.info( - f'[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}') - - total_time = time.time() - start_time - total_time_str = str(datetime.timedelta(seconds=int(total_time))) - logging.info(f'Total training time: {total_time_str}') - - # Evaluation - model[0].eval() - - with torch.no_grad(): - all_labels, all_biases, all_preds = [], [], [] - for images, labels, _, biases, _, _ in val_loaders['test']: - images = images.cuda() + eye_tsr = train_loader.dataset.eye_tsr - feats = model[0](images) - output = model[1](feats) + stats[f"{key}/acc_skew"] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 + stats[f"{key}/acc_align"] = valid_attrwise_accs[eye_tsr == 0.0].mean().item() * 100 - preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() - - all_labels.append(labels) - all_biases.append(biases) - all_preds.append(preds) + print(f"[{epoch} / {opt.epochs}] {valid_attrwise_accs} {stats}") + for tag in val_loaders.keys(): + if stats[f"{tag}/acc_unbiased"] > best_accs[tag]: + best_accs[tag] = stats[f"{tag}/acc_unbiased"] + best_epochs[tag] = epoch + best_stats[tag] = pretty_dict(**{f"best_{tag}_{k}": v for k, v in stats.items()}) - fin_labels = torch.cat(all_labels) - fin_biases = torch.cat(all_biases) - fin_preds = torch.cat(all_preds) + # if tag == "valid": + # save_file = save_path / "best_model.pt" + # save_model(model[0], optimizer_base, opt, epoch, save_file) - ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) - print_all_metrics(ret=ret) + print( + f"[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}" + ) - ret['time per epoch'] = total_time / opt.epochs - for i in range(len(metric_index)): - results[metric_index[i]].append(ret[metric_index[i]]) + save_file_base = save_path / "best_model.pt" + save_model(model[0], optimizer_base, opt, epoch, save_file_base) + save_file_class = save_path / "best_pred.pt" + save_model(model[1], optimizer_class, opt, epoch, save_file_class) - for m_index in metric_index: - fout.write(m_index + '\t') - for i in range(repeat_time): - fout.write('%f\t' % results[m_index][i]) - fout.write('%f\t%f\n' % (mean(results[m_index]), std(results[m_index]))) - fout.close() + total_time = time.time() - start_time + total_time_str = str(datetime.timedelta(seconds=int(total_time))) + print(f"Total training time: {total_time_str}") + print(f"Time per epoch: {total_time / opt.epochs:.6f}") -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/BM/train_celeba/train_celeba_bc.py b/BM/train_celeba/train_celeba_bc.py index 86f50bc..f3e3a64 100644 --- a/BM/train_celeba/train_celeba_bc.py +++ b/BM/train_celeba/train_celeba_bc.py @@ -1,61 +1,34 @@ -import argparse -import datetime -import logging import os +import sys import time -from pathlib import Path - -import numpy as np import torch +import logging +import argparse +import datetime +import numpy as np from torch import nn from tqdm import tqdm +from pathlib import Path +from numpy import mean, std -import sys -sys.path.insert(1, './') +project_dir = "/root/DL-Fairness-Study" +sys.path.insert(1, os.path.join(project_dir, "BM")) +from debias.utils.logging import set_logging +from debias.networks.resnet import FCResNet18 from debias.datasets.celeba import get_celeba from debias.losses.bias_contrastive import BiasContrastiveLoss -from debias.networks.resnet import FCResNet18 -from debias.utils.logging import set_logging -from debias.utils.utils import (AverageMeter, MultiDimAverageMeter, accuracy, - save_model, set_seed, pretty_dict) +from debias.utils.utils import AverageMeter, MultiDimAverageMeter, accuracy, save_model, set_seed, pretty_dict -sys.path.insert(1, '/root/study') +sys.path.insert(1, project_dir) -from numpy import mean, std +from arguments import get_args from metrics import get_metric_index, get_all_metrics, print_all_metrics -def parse_option(): - parser = argparse.ArgumentParser() - parser.add_argument('--exp_name', type=str, default='test') - parser.add_argument('--gpu', type=int, default=0) - parser.add_argument('--task', type=str, default='makeup') - - parser.add_argument('--epochs', type=int, default=40) - parser.add_argument('--seed', type=int, default=1) - - parser.add_argument('--bs', type=int, default=128, help='batch_size') - parser.add_argument('--cbs', type=int, default=64, help='batch_size of dataloader for contrastive loss') - parser.add_argument('--lr', type=float, default=1e-3) - - # hyperparameters - parser.add_argument('--weight', type=float, default=0.01) - parser.add_argument('--ratio', type=int, default=10) - parser.add_argument('--aug', type=int, default=1) - parser.add_argument('--bb', type=int, default=0) - - opt = parser.parse_args() - os.environ['CUDA_VISIBLE_DEVICES'] = str(opt.gpu) - - return opt - - def set_model(train_loader, opt): model = FCResNet18().cuda() - criterion = BiasContrastiveLoss( - confusion_matrix=train_loader.dataset.confusion_matrix, - bb=opt.bb) + criterion = BiasContrastiveLoss(confusion_matrix=train_loader.dataset.confusion_matrix, bb=opt.bb) return model, criterion @@ -69,7 +42,7 @@ def train(train_loader, cont_train_loader, model, criterion, optimizer, epoch, o train_iter = iter(train_loader) cont_train_iter = iter(cont_train_loader) for images, labels, _, biases, _, _ in tqdm(train_iter, ascii=True): - + try: cont_images, cont_labels, _, cont_biases, _, _ = next(cont_train_iter) except: @@ -120,7 +93,7 @@ def validate(val_loader, model): output, _ = model(images) preds = output.data.max(1, keepdim=True)[1].squeeze(1) - acc1, = accuracy(output, labels, topk=(1,)) + (acc1,) = accuracy(output, labels, topk=(1,)) top1.update(acc1[0], bsz) corrects = (preds == labels).long() @@ -130,91 +103,102 @@ def validate(val_loader, model): def main(): - opt = parse_option() - - exp_name = f'bc-bb{opt.bb}-celeba_{opt.task}-{opt.exp_name}-lr{opt.lr}-bs{opt.bs}-cbs{opt.cbs}-w{opt.weight}-ratio{opt.ratio}-aug{opt.aug}-seed{opt.seed}' - opt.exp_name = exp_name + opt = get_args() + opt.target = "blonde" if opt.target == "Blond_Hair" else opt.target + exp_name = f"bc-bb{opt.bb}-celeba-lr{opt.lr}-bs{opt.batch_size}-cbs{opt.cbs}-epochs{opt.epochs}-w{opt.weight}-ratio{opt.ratio}-aug{opt.aug}-seed{opt.seed}" - result_dir = f'../results/celeba' - result_path = Path(result_dir) - result_path.mkdir(parents=True, exist_ok=True) - if opt.task == 'blonde': - fout = open('/'.join([str(result_path), 'bc_bb_gender_blond_hair.txt']), 'w') + # result_dir = f"../results/celeba" + # result_path = Path(result_dir) + # result_path.mkdir(parents=True, exist_ok=True) + # if opt.target == "blonde": + # fout = open("/".join([str(result_path), "bc_bb_gender_blond_hair.txt"]), "w") - results = {} - metric_index = get_metric_index() - for m_index in metric_index: - results[m_index] = [] + # results = {} + # metric_index = get_metric_index() + # for m_index in metric_index: + # results[m_index] = [] - repeat_time = 10 + repeat_time = 1 - output_dir = f'exp_results/{exp_name}' + output_dir = f"{project_dir}/checkpoints/{exp_name}" save_path = Path(output_dir) save_path.mkdir(parents=True, exist_ok=True) - set_logging(exp_name, 'INFO', str(save_path)) - logging.info(f'Set seed: {opt.seed}') + print(f"Set seed: {opt.seed}") set_seed(opt.seed) - logging.info(f'save_path: {save_path}') + print(f"save_path: {save_path}") np.set_printoptions(precision=3) torch.set_printoptions(precision=3) - root = '../data' + root = f"{project_dir}/data" - train_loader = get_celeba( - root, - batch_size=opt.bs, - target_attr=opt.task, - split='train', - aug=False) + train_loader = get_celeba(root, batch_size=opt.batch_size, target_attr=opt.target, split="train", aug=False) cont_train_loader = get_celeba( - root, - batch_size=opt.cbs, - target_attr=opt.task, - split='train', - aug=opt.aug, - two_crop=True, - ratio=opt.ratio, - given_y=True) + root, batch_size=opt.cbs, target_attr=opt.target, split="train", aug=opt.aug, two_crop=True, ratio=opt.ratio, given_y=True + ) val_loaders = {} - val_loaders['valid'] = get_celeba( - root, - batch_size=256, - target_attr=opt.task, - split='train_valid', - aug=False) - - val_loaders['test'] = get_celeba( - root, - batch_size=256, - target_attr=opt.task, - split='valid', - aug=False) + val_loaders["valid"] = get_celeba(root, batch_size=256, target_attr=opt.target, split="train_valid", aug=False) + + val_loaders["test"] = get_celeba(root, batch_size=256, target_attr=opt.target, split="valid", aug=False) for r in range(repeat_time): - logging.info(f'Repeated experiment: {r+1}') + # print(f"Repeated experiment: {r+1}") model, criterion = set_model(train_loader, opt) + # Evaluation + if opt.checkpoint: + model.load_state_dict(torch.load(f"{save_path}/best_model.pt")["model"]) + model.eval() + + with torch.no_grad(): + all_labels, all_biases, all_preds = [], [], [] + for _, (images, labels, _, biases, _, _) in enumerate(val_loaders["test"]): + images = images.cuda() + output, _ = model(images) + preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() + + all_labels.append(labels) + all_biases.append(biases) + all_preds.append(preds) + + fin_labels = torch.cat(all_labels) + fin_biases = torch.cat(all_biases) + fin_preds = torch.cat(all_preds) + + ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) + print_all_metrics(ret=ret) + + sys.exit() + + # ret["time per epoch"] = total_time / opt.epochs + # for i in range(len(metric_index)): + # results[metric_index[i]].append(ret[metric_index[i]]) + + # for m_index in metric_index: + # fout.write(m_index + "\t") + # for i in range(repeat_time): + # fout.write("%f\t" % results[m_index][i]) + # fout.write("%f\t%f\n" % (mean(results[m_index]), std(results[m_index]))) + # fout.close() + decay_epochs = [opt.epochs // 3, opt.epochs * 2 // 3] optimizer = torch.optim.Adam(model.parameters(), lr=opt.lr, weight_decay=1e-4) scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=decay_epochs, gamma=0.1) - logging.info(f'decay_epochs: {decay_epochs}') + print(f"decay_epochs: {decay_epochs}") - # (save_path / 'checkpoints').mkdir(parents=True, exist_ok=True) - - best_accs = {'valid': 0, 'test': 0} - best_epochs = {'valid': 0, 'test': 0} + best_accs = {"valid": 0, "test": 0} + best_epochs = {"valid": 0, "test": 0} best_stats = {} start_time = time.time() for epoch in range(1, opt.epochs + 1): - logging.info(f'[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]} weight: {opt.weight}') + print(f"[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]} weight: {opt.weight}") ce_loss, con_loss, loss = train(train_loader, cont_train_loader, model, criterion, optimizer, epoch, opt) - logging.info(f'[{epoch} / {opt.epochs}] Loss: {loss} CE Loss: {ce_loss} Con Loss: {con_loss}') + print(f"[{epoch} / {opt.epochs}] Loss: {loss} CE Loss: {ce_loss} Con Loss: {con_loss}") scheduler.step() @@ -222,61 +206,34 @@ def main(): for key, val_loader in val_loaders.items(): accs, valid_attrwise_accs, diff = validate(val_loader, model) - stats[f'{key}/acc'] = accs.item() - stats[f'{key}/acc_unbiased'] = torch.mean(valid_attrwise_accs).item() * 100 - stats[f'{key}/diff'] = diff.item() * 100 - + stats[f"{key}/acc"] = accs.item() + stats[f"{key}/acc_unbiased"] = torch.mean(valid_attrwise_accs).item() * 100 + stats[f"{key}/diff"] = diff.item() * 100 + eye_tsr = train_loader.dataset.eye_tsr - - stats[f'{key}/acc_skew'] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 - stats[f'{key}/acc_align'] = valid_attrwise_accs[eye_tsr == 0.0].mean().item() * 100 - logging.info(f'[{epoch} / {opt.epochs}] {valid_attrwise_accs} {stats}') + stats[f"{key}/acc_skew"] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 + stats[f"{key}/acc_align"] = valid_attrwise_accs[eye_tsr == 0.0].mean().item() * 100 + + print(f"[{epoch} / {opt.epochs}] {valid_attrwise_accs} {stats}") for tag in val_loaders.keys(): - if stats[f'{tag}/acc_unbiased'] > best_accs[tag]: - best_accs[tag] = stats[f'{tag}/acc_unbiased'] + if stats[f"{tag}/acc_unbiased"] > best_accs[tag]: + best_accs[tag] = stats[f"{tag}/acc_unbiased"] best_epochs[tag] = epoch - best_stats[tag] = pretty_dict(**{f'best_{tag}_{k}': v for k, v in stats.items()}) + best_stats[tag] = pretty_dict(**{f"best_{tag}_{k}": v for k, v in stats.items()}) - logging.info( - f'[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}') + print( + f"[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}" + ) + + save_file = save_path / "best_model.pt" + save_model(model, optimizer, opt, epoch, save_file) total_time = time.time() - start_time total_time_str = str(datetime.timedelta(seconds=int(total_time))) - logging.info(f'Total training time: {total_time_str}') - - # Evaluation - model.eval() - - with torch.no_grad(): - all_labels, all_biases, all_preds = [], [], [] - for _, (images, labels, _, biases, _, _) in enumerate(val_loaders['test']): - images = images.cuda() - output, _ = model(images) - preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() - - all_labels.append(labels) - all_biases.append(biases) - all_preds.append(preds) - - fin_labels = torch.cat(all_labels) - fin_biases = torch.cat(all_biases) - fin_preds = torch.cat(all_preds) - - ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) - print_all_metrics(ret=ret) - - ret['time per epoch'] = total_time / opt.epochs - for i in range(len(metric_index)): - results[metric_index[i]].append(ret[metric_index[i]]) - - for m_index in metric_index: - fout.write(m_index + '\t') - for i in range(repeat_time): - fout.write('%f\t' % results[m_index][i]) - fout.write('%f\t%f\n' % (mean(results[m_index]), std(results[m_index]))) - fout.close() + print(f"Total training time: {total_time_str}") + print(f"Time per epoch: {total_time / opt.epochs:.6f}") -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/BM/train_celeba/train_celeba_bm.py b/BM/train_celeba/train_celeba_bm.py index 354a32f..d6677b2 100644 --- a/BM/train_celeba/train_celeba_bm.py +++ b/BM/train_celeba/train_celeba_bm.py @@ -1,102 +1,73 @@ -import argparse -import datetime -import logging import os +import sys import time -from pathlib import Path - -import numpy as np import torch - +import datetime +import numpy as np from torch import nn from tqdm import tqdm +from pathlib import Path +from numpy import mean, std -import sys -sys.path.insert(1, './') +project_dir = "/root/DL-Fairness-Study" +sys.path.insert(1, os.path.join(project_dir, "BM")) +from debias.utils.logging import set_logging from debias.datasets.celeba import get_celeba -from debias.datasets.utils import over_sample_features, under_sample_features from debias.networks.resnet import FCResNet18 -from debias.utils.logging import set_logging -from debias.utils.utils import (AverageMeter, MultiDimAverageMeter, accuracy, - pretty_dict, save_model, set_seed) from sklearn.linear_model import LogisticRegression +from debias.datasets.utils import over_sample_features, under_sample_features +from debias.utils.utils import AverageMeter, MultiDimAverageMeter, accuracy, pretty_dict, save_model, set_seed -sys.path.insert(1, '/root/study') +sys.path.insert(1, project_dir) -from numpy import mean, std +from arguments import get_args from metrics import get_metric_index, get_all_metrics, print_all_metrics -def parse_option(): - parser = argparse.ArgumentParser() - parser.add_argument('--exp_name', type=str, default='test') - parser.add_argument('--gpu', type=int, default=0) - parser.add_argument('--task', type=str, default='blonde') - - parser.add_argument('--epochs', type=int, default=10) - parser.add_argument('--seed', type=int, default=1) - - parser.add_argument('--bs', type=int, default=128, help='batch_size') - parser.add_argument('--lr', type=float, default=1e-3) - parser.add_argument('--lr_layer', type=float, default=1e-3) - - parser.add_argument('--mode', type=str, default='none') - - opt = parser.parse_args() - os.environ['CUDA_VISIBLE_DEVICES'] = str(opt.gpu) - - return opt - def set_model(): model = FCResNet18(num_classes=2).cuda() pred = nn.Linear(512, 2).cuda() - models = { - 'model': model, - 'pred': pred - } + models = {"model": model, "pred": pred} - criterion = { - 'bin': nn.BCEWithLogitsLoss(reduction='none'), - 'multi': nn.CrossEntropyLoss(reduction='none') - } + criterion = {"bin": nn.BCEWithLogitsLoss(reduction="none"), "multi": nn.CrossEntropyLoss(reduction="none")} return models, criterion def train(train_loader, model, criterion, optimizer_model, opt, optimizer_layer): - model['model'].train() + model["model"].train() avg_loss = AverageMeter() train_iter = iter(train_loader) - - all_outputs = [] - all_labels_nb = [] - all_gc = [] - all_feats = [] - all_bias = [] + + all_outputs = [] + all_labels_nb = [] + all_gc = [] + all_feats = [] + all_bias = [] sig = nn.Sigmoid() - for images, labels, labels_bin, biases, gc, _ in tqdm(train_iter, ascii=True): - + for images, labels, labels_bin, biases, gc, _ in tqdm(train_iter, ascii=True): + bsz = labels.shape[0] labels, biases, labels_bin = labels.cuda(), biases.cuda(), labels_bin.cuda() - + images = images.cuda() - logits, feat = model['model'](images) + logits, feat = model["model"](images) - multi = torch.ones_like(labels_bin) + multi = torch.ones_like(labels_bin) - multi[labels_bin == -1] = 0 - labels_bin[labels_bin == -1] = 0 + multi[labels_bin == -1] = 0 + labels_bin[labels_bin == -1] = 0 - loss = criterion['bin'](logits, labels_bin) - loss = loss*multi + loss = criterion["bin"](logits, labels_bin) + loss = loss * multi - div = torch.sum(multi) - loss = torch.sum(loss/div) + div = torch.sum(multi) + loss = torch.sum(loss / div) avg_loss.update(loss.item(), bsz) @@ -104,94 +75,92 @@ def train(train_loader, model, criterion, optimizer_model, opt, optimizer_layer) loss.backward() optimizer_model.step() - all_outputs.append(sig(logits).cpu().detach().numpy()) + all_outputs.append(sig(logits).cpu().detach().numpy()) all_labels_nb.append(labels.cpu().detach().numpy()) all_gc.append(gc.numpy()) all_bias.append(biases.cpu().detach().numpy()) all_feats.append(feat.cpu().detach().numpy()) - - all_labels_nb = np.concatenate(all_labels_nb, axis=0) - all_gc = np.concatenate(all_gc, axis=0) - all_bias = np.concatenate(all_bias, axis=0) - all_feats = np.concatenate(all_feats, axis=0) - if opt.mode == 'os': + all_labels_nb = np.concatenate(all_labels_nb, axis=0) + all_gc = np.concatenate(all_gc, axis=0) + all_bias = np.concatenate(all_bias, axis=0) + all_feats = np.concatenate(all_feats, axis=0) + + if opt.mode == "os": all_feats, all_labels_nb = over_sample_features(all_bias, all_feats, all_labels_nb) - elif opt.mode == 'us': + elif opt.mode == "us": all_feats, all_labels_nb = under_sample_features(all_bias, all_feats, all_labels_nb) - batch_size = opt.bs + batch_size = opt.batch_size total_samples = len(all_labels_nb) - num_batches = total_samples//batch_size + num_batches = total_samples // batch_size all_idx = np.arange(total_samples) np.random.shuffle(all_idx) - all_feats[all_idx] = all_feats + all_feats[all_idx] = all_feats all_labels_nb[all_idx] = all_labels_nb - if opt.mode == 'uw': + if opt.mode == "uw": all_gc[all_idx] = all_gc - for batch_idx in range(num_batches): - start = batch_idx * batch_size + for batch_idx in range(num_batches): + start = batch_idx * batch_size end = min(total_samples, start + batch_size) feats = torch.from_numpy(all_feats[start:end]).cuda() labels = torch.from_numpy(all_labels_nb[start:end]).cuda() gc = torch.from_numpy(all_gc[start:end]).cuda() - optimizer_layer.zero_grad() - out_lr = model['pred'](feats) + optimizer_layer.zero_grad() + out_lr = model["pred"](feats) - if opt.mode == 'uw': - loss = criterion['multi'](out_lr, labels)*gc + if opt.mode == "uw": + loss = criterion["multi"](out_lr, labels) * gc loss = torch.mean(loss) - else: - loss = criterion['multi'](out_lr, labels) + else: + loss = criterion["multi"](out_lr, labels) loss = torch.mean(loss) - - loss.backward() + + loss.backward() optimizer_layer.step() - + return avg_loss.avg def validate(val_loader, model): - model['model'].eval() - + model["model"].eval() + top1 = AverageMeter() attrwise_acc_meter = MultiDimAverageMeter(dims=(2, 2)) - + with torch.no_grad(): for idx, (images, labels, _, biases, _, _) in enumerate(tqdm(val_loader, ascii=True)): images = images.cuda() bsz = labels.shape[0] - - output, feats = model['model'](images) - output = model['pred'](feats).detach().cpu() + + output, feats = model["model"](images) + output = model["pred"](feats).detach().cpu() preds = output.data.max(1, keepdim=True)[1].squeeze(1) - - acc1, = accuracy(output, labels.cpu(), topk=(1,)) + + (acc1,) = accuracy(output, labels.cpu(), topk=(1,)) top1.update(acc1[0], bsz) corrects = (preds == labels).long() - attrwise_acc_meter.add(corrects.cpu(), - torch.stack([labels.cpu(), biases.cpu()], dim=1)) + attrwise_acc_meter.add(corrects.cpu(), torch.stack([labels.cpu(), biases.cpu()], dim=1)) - return top1.avg, attrwise_acc_meter.get_mean(), attrwise_acc_meter.get_acc_diff() + return top1.avg, attrwise_acc_meter.get_mean(), attrwise_acc_meter.get_acc_diff() def main(): - opt = parse_option() - - exp_name = f'bm-celeba_{opt.task}-{opt.exp_name}-lr{opt.lr}-bs{opt.bs}-seed{opt.seed}-mode_{opt.mode}' - opt.exp_name = exp_name + opt = get_args() + opt.target = "blonde" if opt.target == "Blond_Hair" else opt.target + exp_name = f"bm_{opt.mode}-celeba-lr{opt.lr}-bs{opt.batch_size}-epochs{opt.epochs}-seed{opt.seed}" # result_dir = f'../results/celeba' # result_path = Path(result_dir) # result_path.mkdir(parents=True, exist_ok=True) - # if opt.task == 'blonde': + # if opt.target == 'blonde': # fout = open('/'.join([str(result_path), f'bm_{opt.mode}_gender_blond_hair.txt']), 'w') # results = {} @@ -201,66 +170,86 @@ def main(): repeat_time = 1 - output_dir = f'exp_results/{exp_name}' + output_dir = f"{project_dir}/checkpoints/{exp_name}" save_path = Path(output_dir) save_path.mkdir(parents=True, exist_ok=True) - set_logging(exp_name, 'INFO', str(save_path)) - logging.info(f'Set seed: {opt.seed}') set_seed(opt.seed) - logging.info(f'save_path: {save_path}') + print(f"save_path: {save_path}") np.set_printoptions(precision=3) torch.set_printoptions(precision=3) - - root = '../data' - train_loader = get_celeba( - root, - batch_size=opt.bs, - target_attr=opt.task, - split='train', - aug=False, - under_sample = 'bin') + + root = f"{project_dir}/data" + train_loader = get_celeba(root, batch_size=opt.batch_size, target_attr=opt.target, split="train", aug=False, under_sample="bin") val_loaders = {} - val_loaders['valid'] = get_celeba( - root, - batch_size=256, - target_attr=opt.task, - split='train_valid', - aug=False) - - val_loaders['test'] = get_celeba( - root, - batch_size=256, - target_attr=opt.task, - split='valid', - aug=False) + val_loaders["valid"] = get_celeba(root, batch_size=256, target_attr=opt.target, split="train_valid", aug=False) + + val_loaders["test"] = get_celeba(root, batch_size=256, target_attr=opt.target, split="valid", aug=False) for r in range(repeat_time): - logging.info(f'Repeated experiment: {r+1}') + # print(f"Repeated experiment: {r+1}") model, criterion = set_model() - decay_epochs = [opt.epochs // 3, opt.epochs * 2 // 3] - optimizer = torch.optim.Adam(model['model'].parameters(), lr=opt.lr, weight_decay=1e-4) + # Evaluation + if opt.checkpoint: + model["model"].load_state_dict(torch.load(f"{save_path}/best_model.pt")["model"]) + model["model"].eval() + model["pred"].load_state_dict(torch.load(f"{save_path}/best_pred.pt")["model"]) + model["pred"].eval() + + with torch.no_grad(): + all_labels, all_biases, all_preds = [], [], [] + for idx, (images, labels, _, biases, _, _) in enumerate(tqdm(val_loaders["test"], ascii=True)): + images = images.cuda() + output, feats = model["model"](images) + output = model["pred"](feats).detach().cpu() + preds = output.data.max(1, keepdim=True)[1].squeeze(1) + + all_labels.append(labels) + all_biases.append(biases) + all_preds.append(preds) + + fin_labels = torch.cat(all_labels) + fin_biases = torch.cat(all_biases) + fin_preds = torch.cat(all_preds) + + ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) + print_all_metrics(ret=ret) + + sys.exit() + + # ret["time per epoch"] = total_time / opt.epochs + # print(ret["time per epoch"]) + # for i in range(len(metric_index)): + # results[metric_index[i]].append(ret[metric_index[i]]) + + # for m_index in metric_index: + # fout.write(m_index + '\t') + # for i in range(repeat_time): + # fout.write('%f\t' % results[m_index][i]) + # fout.write('%f\t%f\n' % (mean(results[m_index]), std(results[m_index]))) + # fout.close() + + decay_epochs = [opt.epochs // 3, opt.epochs * 2 // 3] + optimizer = torch.optim.Adam(model["model"].parameters(), lr=opt.lr, weight_decay=1e-4) scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=decay_epochs, gamma=0.1) - optimizer_layer = torch.optim.Adam(model['pred'].parameters(), lr=opt.lr_layer, weight_decay=1e-4) + optimizer_layer = torch.optim.Adam(model["pred"].parameters(), lr=opt.lr_layer, weight_decay=1e-4) scheduler_layer = torch.optim.lr_scheduler.MultiStepLR(optimizer_layer, milestones=decay_epochs, gamma=0.1) + print(f"decay_epochs: {decay_epochs}") - logging.info(f'decay_epochs: {decay_epochs}') - # (save_path / 'checkpoints').mkdir(parents=True, exist_ok=True) - - best_accs = {'valid': 0, 'test': 0} - best_epochs = {'valid': 0, 'test': 0} + best_accs = {"valid": 0, "test": 0} + best_epochs = {"valid": 0, "test": 0} best_stats = {} start_time = time.time() for epoch in range(1, opt.epochs + 1): - logging.info(f'[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}') + print(f"[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}") loss = train(train_loader, model, criterion, optimizer, opt, optimizer_layer) - logging.info(f'[{epoch} / {opt.epochs}] Loss: {loss:.4f}') + print(f"[{epoch} / {opt.epochs}] Loss: {loss:.4f}") scheduler.step() scheduler_layer.step() @@ -269,63 +258,36 @@ def main(): for key, val_loader in val_loaders.items(): accs, valid_attrwise_accs, diff = validate(val_loader, model) - stats[f'{key}/acc'] = accs.item() - stats[f'{key}/acc_unbiased'] = torch.mean(valid_attrwise_accs).item() * 100 - stats[f'{key}/diff'] = diff.item() * 100 - + stats[f"{key}/acc"] = accs.item() + stats[f"{key}/acc_unbiased"] = torch.mean(valid_attrwise_accs).item() * 100 + stats[f"{key}/diff"] = diff.item() * 100 + eye_tsr = train_loader.dataset.eye_tsr - - stats[f'{key}/acc_skew'] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 - stats[f'{key}/acc_align'] = valid_attrwise_accs[eye_tsr == 0.0].mean().item() * 100 - logging.info(f'[{epoch} / {opt.epochs}] {valid_attrwise_accs} {stats}') + stats[f"{key}/acc_skew"] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 + stats[f"{key}/acc_align"] = valid_attrwise_accs[eye_tsr == 0.0].mean().item() * 100 + + print(f"[{epoch} / {opt.epochs}] {valid_attrwise_accs} {stats}") for tag in val_loaders.keys(): - if stats[f'{tag}/acc_unbiased'] > best_accs[tag]: - best_accs[tag] = stats[f'{tag}/acc_unbiased'] + if stats[f"{tag}/acc_unbiased"] > best_accs[tag]: + best_accs[tag] = stats[f"{tag}/acc_unbiased"] best_epochs[tag] = epoch - best_stats[tag] = pretty_dict(**{f'best_{tag}_{k}': v for k, v in stats.items()}) + best_stats[tag] = pretty_dict(**{f"best_{tag}_{k}": v for k, v in stats.items()}) - logging.info( - f'[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}') + print( + f"[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}" + ) + + save_file_model = save_path / "best_model.pt" + save_file_pred = save_path / "best_pred.pt" + save_model(model["model"], optimizer, opt, epoch, save_file_model) + save_model(model["pred"], optimizer_layer, opt, epoch, save_file_pred) total_time = time.time() - start_time total_time_str = str(datetime.timedelta(seconds=int(total_time))) - logging.info(f'Total training time: {total_time_str}') - - # Evaluation - model['model'].eval() - - with torch.no_grad(): - all_labels, all_biases, all_preds = [], [], [] - for idx, (images, labels, _, biases, _, _) in enumerate(tqdm(val_loaders['test'], ascii=True)): - images = images.cuda() - output, feats = model['model'](images) - output = model['pred'](feats).detach().cpu() - preds = output.data.max(1, keepdim=True)[1].squeeze(1) - - all_labels.append(labels) - all_biases.append(biases) - all_preds.append(preds) - - fin_labels = torch.cat(all_labels) - fin_biases = torch.cat(all_biases) - fin_preds = torch.cat(all_preds) - - ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) - print_all_metrics(ret=ret) - - ret['time per epoch'] = total_time / opt.epochs - print(ret['time per epoch']) - # for i in range(len(metric_index)): - # results[metric_index[i]].append(ret[metric_index[i]]) - - # for m_index in metric_index: - # fout.write(m_index + '\t') - # for i in range(repeat_time): - # fout.write('%f\t' % results[m_index][i]) - # fout.write('%f\t%f\n' % (mean(results[m_index]), std(results[m_index]))) - # fout.close() + print(f"Total training time: {total_time_str}") + print(f"Time per epoch: {total_time / opt.epochs:.6f}") -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/BM/train_celeba/train_celeba_di.py b/BM/train_celeba/train_celeba_di.py index 43b2470..96446fc 100644 --- a/BM/train_celeba/train_celeba_di.py +++ b/BM/train_celeba/train_celeba_di.py @@ -1,62 +1,44 @@ +import os +import sys +import time +import torch +import logging import argparse import datetime -import logging -import time -from pathlib import Path - import numpy as np -import torch - -import sys -sys.path.insert(1, './') +from tqdm import tqdm +from pathlib import Path +from numpy import mean, std +project_dir = "/root/DL-Fairness-Study" +sys.path.insert(1, os.path.join(project_dir, "BM")) -from debias.datasets.celeba import get_celeba from debias.losses.diloss import DILoss -from debias.networks.resnet_di import DIResNet18 from debias.utils.logging import set_logging -from debias.utils.utils import (AverageMeter, MultiDimAverageMeter, accuracy, - pretty_dict, save_model, set_seed) - -from tqdm import tqdm +from debias.datasets.celeba import get_celeba +from debias.networks.resnet_di import DIResNet18 +from debias.utils.utils import AverageMeter, MultiDimAverageMeter, accuracy, pretty_dict, save_model, set_seed -import os -sys.path.insert(1, '/root/study') +sys.path.insert(1, project_dir) -from numpy import mean, std +from arguments import get_args from metrics import get_metric_index, get_all_metrics, print_all_metrics -def parse_option(): - parser = argparse.ArgumentParser() - parser.add_argument('--exp_name', type=str, default='test') - parser.add_argument('--gpu', type=int, default=0) - parser.add_argument('--task', type=str, default='makeup') - - parser.add_argument('--epochs', type=int, default=40) - parser.add_argument('--seed', type=int, default=1) - - parser.add_argument('--bs', type=int, default=128, help='batch_size') - parser.add_argument('--lr', type=float, default=1e-3) - - opt = parser.parse_args() - os.environ['CUDA_VISIBLE_DEVICES'] = str(opt.gpu) - - return opt - def set_model(): model = DIResNet18().cuda() criterion = DILoss() return model, criterion + def train(train_loader, model, criterion, optimizer): model.train() avg_loss = AverageMeter() train_iter = iter(train_loader) for images, labels, _, biases, _, _ in tqdm(train_iter, ascii=True): - + bsz = labels.shape[0] labels, biases = labels.cuda(), biases.cuda() @@ -90,7 +72,7 @@ def validate(val_loader, model): output_sum = output[:, :2] + output[:, 2:] preds = torch.argmax(output_sum, axis=1) - acc1, = accuracy(output_sum, labels, topk=(1,)) + (acc1,) = accuracy(output_sum, labels, topk=(1,)) top1.update(acc1[0], bsz) corrects = (preds == labels).long() @@ -100,80 +82,98 @@ def validate(val_loader, model): def main(): - opt = parse_option() - - exp_name = f'di-celeba_{opt.task}-{opt.exp_name}-lr{opt.lr}-bs{opt.bs}-seed{opt.seed}' - opt.exp_name = exp_name + opt = get_args() + opt.target = "blonde" if opt.target == "Blond_Hair" else opt.target + exp_name = f"di-celeba-lr{opt.lr}-bs{opt.batch_size}-epochs{opt.epochs}-seed{opt.seed}" - result_dir = f'../results/celeba' - result_path = Path(result_dir) - result_path.mkdir(parents=True, exist_ok=True) - if opt.task == 'blonde': - fout = open('/'.join([str(result_path), 'di_gender_blond_hair.txt']), 'w') + # result_dir = f"../results/celeba" + # result_path = Path(result_dir) + # result_path.mkdir(parents=True, exist_ok=True) + # if opt.target == "blonde": + # fout = open("/".join([str(result_path), "di_gender_blond_hair.txt"]), "w") - results = {} - metric_index = get_metric_index() - for m_index in metric_index: - results[m_index] = [] + # results = {} + # metric_index = get_metric_index() + # for m_index in metric_index: + # results[m_index] = [] - repeat_time = 10 + repeat_time = 1 - output_dir = f'exp_results/{exp_name}' + output_dir = f"{project_dir}/checkpoints/{exp_name}" save_path = Path(output_dir) save_path.mkdir(parents=True, exist_ok=True) - set_logging(exp_name, 'INFO', str(save_path)) - logging.info(f'Set seed: {opt.seed}') + print(f"Set seed: {opt.seed}") set_seed(opt.seed) - logging.info(f'save_path: {save_path}') + print(f"save_path: {save_path}") np.set_printoptions(precision=3) torch.set_printoptions(precision=3) - root = '../data' - train_loader = get_celeba( - root, - batch_size=opt.bs, - target_attr=opt.task, - split='train', - aug=False) + root = f"{project_dir}/data" + train_loader = get_celeba(root, batch_size=opt.batch_size, target_attr=opt.target, split="train", aug=False) val_loaders = {} - val_loaders['valid'] = get_celeba( - root, - batch_size=256, - target_attr=opt.task, - split='train_valid', - aug=False) - - val_loaders['test'] = get_celeba( - root, - batch_size=256, - target_attr=opt.task, - split='valid', - aug=False) + val_loaders["valid"] = get_celeba(root, batch_size=256, target_attr=opt.target, split="train_valid", aug=False) + + val_loaders["test"] = get_celeba(root, batch_size=256, target_attr=opt.target, split="valid", aug=False) for r in range(repeat_time): - logging.info(f'Repeated experiment: {r+1}') + # print(f"Repeated experiment: {r+1}") model, criterion = set_model() - decay_epochs = [opt.epochs // 3, opt.epochs * 2 // 3] + # Evaluation + if opt.checkpoint: + model.load_state_dict(torch.load(f"{save_path}/best_model.pt")["model"]) + model.eval() + + with torch.no_grad(): + all_labels, all_biases, all_preds = [], [], [] + for images, labels, _, biases, _, _ in val_loaders["test"]: + images = images.cuda() + + output = model(images) + output_sum = output[:, :2] + output[:, 2:] + preds = torch.argmax(output_sum, axis=1).cpu() + all_labels.append(labels) + all_biases.append(biases) + all_preds.append(preds) + + fin_labels = torch.cat(all_labels) + fin_biases = torch.cat(all_biases) + fin_preds = torch.cat(all_preds) + + ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) + print_all_metrics(ret=ret) + + sys.exit() + + # ret["time per epoch"] = total_time / opt.epochs + # for i in range(len(metric_index)): + # results[metric_index[i]].append(ret[metric_index[i]]) + + # for m_index in metric_index: + # fout.write(m_index + "\t") + # for i in range(repeat_time): + # fout.write("%f\t" % results[m_index][i]) + # fout.write("%f\t%f\n" % (mean(results[m_index]), std(results[m_index]))) + # fout.close() + + decay_epochs = [opt.epochs // 3, opt.epochs * 2 // 3] optimizer = torch.optim.Adam(model.parameters(), lr=opt.lr, weight_decay=1e-4) scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=decay_epochs, gamma=0.1) - logging.info(f'decay_epochs: {decay_epochs}') + print(f"decay_epochs: {decay_epochs}") - # (save_path / 'checkpoints').mkdir(parents=True, exist_ok=True) - - best_accs = {'valid': 0, 'test': 0} - best_epochs = {'valid': 0, 'test': 0} + best_accs = {"valid": 0, "test": 0} + best_epochs = {"valid": 0, "test": 0} best_stats = {} start_time = time.time() for epoch in range(1, opt.epochs + 1): - logging.info(f'[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}') + print(f"[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}") loss = train(train_loader, model, criterion, optimizer) - logging.info(f'[{epoch} / {opt.epochs}] Loss: {loss:.4f}') + print(f"[{epoch} / {opt.epochs}] Loss: {loss:.4f}") scheduler.step() @@ -181,63 +181,38 @@ def main(): for key, val_loader in val_loaders.items(): accs, valid_attrwise_accs, diff = validate(val_loader, model) - stats[f'{key}/acc'] = accs.item() - stats[f'{key}/acc_unbiased'] = torch.mean(valid_attrwise_accs).item() * 100 - stats[f'{key}/diff'] = diff.item() * 100 - + stats[f"{key}/acc"] = accs.item() + stats[f"{key}/acc_unbiased"] = torch.mean(valid_attrwise_accs).item() * 100 + stats[f"{key}/diff"] = diff.item() * 100 + eye_tsr = train_loader.dataset.eye_tsr - - stats[f'{key}/acc_skew'] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 - stats[f'{key}/acc_align'] = valid_attrwise_accs[eye_tsr == 0.0].mean().item() * 100 - logging.info(f'[{epoch} / {opt.epochs}] {valid_attrwise_accs} {stats}') + stats[f"{key}/acc_skew"] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 + stats[f"{key}/acc_align"] = valid_attrwise_accs[eye_tsr == 0.0].mean().item() * 100 + + print(f"[{epoch} / {opt.epochs}] {valid_attrwise_accs} {stats}") for tag in val_loaders.keys(): - if stats[f'{tag}/acc_unbiased'] > best_accs[tag]: - best_accs[tag] = stats[f'{tag}/acc_unbiased'] + if stats[f"{tag}/acc_unbiased"] > best_accs[tag]: + best_accs[tag] = stats[f"{tag}/acc_unbiased"] best_epochs[tag] = epoch - best_stats[tag] = pretty_dict(**{f'best_{tag}_{k}': v for k, v in stats.items()}) - - logging.info( - f'[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}') - - total_time = time.time() - start_time - total_time_str = str(datetime.timedelta(seconds=int(total_time))) - logging.info(f'Total training time: {total_time_str}') + best_stats[tag] = pretty_dict(**{f"best_{tag}_{k}": v for k, v in stats.items()}) - # Evaluation - model.eval() - - with torch.no_grad(): - all_labels, all_biases, all_preds = [], [], [] - for images, labels, _, biases, _, _ in val_loaders['test']: - images = images.cuda() - - output = model(images) - output_sum = output[:, :2] + output[:, 2:] - preds = torch.argmax(output_sum, axis=1).cpu() - - all_labels.append(labels) - all_biases.append(biases) - all_preds.append(preds) + # if tag == "valid": + # save_file = save_path / "best_model.pt" + # save_model(model, optimizer, opt, epoch, save_file) - fin_labels = torch.cat(all_labels) - fin_biases = torch.cat(all_biases) - fin_preds = torch.cat(all_preds) + print( + f"[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}" + ) - ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) - print_all_metrics(ret=ret) + save_file = save_path / "best_model.pt" + save_model(model, optimizer, opt, epoch, save_file) - ret['time per epoch'] = total_time / opt.epochs - for i in range(len(metric_index)): - results[metric_index[i]].append(ret[metric_index[i]]) - - for m_index in metric_index: - fout.write(m_index + '\t') - for i in range(repeat_time): - fout.write('%f\t' % results[m_index][i]) - fout.write('%f\t%f\n' % (mean(results[m_index]), std(results[m_index]))) - fout.close() + total_time = time.time() - start_time + total_time_str = str(datetime.timedelta(seconds=int(total_time))) + print(f"Total training time: {total_time_str}") + print(f"Time per epoch: {total_time / opt.epochs:.6f}") -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/BM/train_celeba/train_celeba_os.py b/BM/train_celeba/train_celeba_os.py index a709b28..825518f 100644 --- a/BM/train_celeba/train_celeba_os.py +++ b/BM/train_celeba/train_celeba_os.py @@ -1,50 +1,30 @@ -import argparse -import datetime -import logging import os +import sys import time -from pathlib import Path - -import numpy as np import torch +import logging +import argparse +import datetime +import numpy as np from torch import nn +from tqdm import tqdm +from pathlib import Path +from numpy import mean, std -import sys -sys.path.insert(1, './') - +project_dir = "/root/DL-Fairness-Study" +sys.path.insert(1, os.path.join(project_dir, "BM")) +from debias.utils.logging import set_logging from debias.datasets.celeba import get_celeba from debias.networks.resnet import FCResNet18 -from debias.utils.logging import set_logging -from debias.utils.utils import (AverageMeter, MultiDimAverageMeter, accuracy, - pretty_dict, save_model, set_seed) - -from tqdm import tqdm +from debias.utils.utils import AverageMeter, MultiDimAverageMeter, accuracy, pretty_dict, save_model, set_seed -sys.path.insert(1, '/root/study') +sys.path.insert(1, project_dir) -from numpy import mean, std +from arguments import get_args from metrics import get_metric_index, get_all_metrics, print_all_metrics -def parse_option(): - parser = argparse.ArgumentParser() - parser.add_argument('--exp_name', type=str, default='test') - parser.add_argument('--gpu', type=int, default=0) - parser.add_argument('--task', type=str, default='makeup') - - parser.add_argument('--epochs', type=int, default=10) - parser.add_argument('--seed', type=int, default=1) - - parser.add_argument('--bs', type=int, default=128, help='batch_size') - parser.add_argument('--lr', type=float, default=1e-3) - - opt = parser.parse_args() - os.environ['CUDA_VISIBLE_DEVICES'] = str(opt.gpu) - - return opt - - def set_model(): model = FCResNet18().cuda() criterion = nn.CrossEntropyLoss() @@ -58,7 +38,7 @@ def train(train_loader, model, criterion, optimizer): train_iter = iter(train_loader) for images, labels, _, biases, _, _ in tqdm(train_iter, ascii=True): - + bsz = labels.shape[0] labels, biases = labels.cuda(), biases.cuda() @@ -90,91 +70,106 @@ def validate(val_loader, model): output, _ = model(images) preds = output.data.max(1, keepdim=True)[1].squeeze(1) - acc1, = accuracy(output, labels, topk=(1,)) + (acc1,) = accuracy(output, labels, topk=(1,)) top1.update(acc1[0], bsz) corrects = (preds == labels).long() attrwise_acc_meter.add(corrects.cpu(), torch.stack([labels.cpu(), biases.cpu()], dim=1)) - return top1.avg, attrwise_acc_meter.get_mean(), attrwise_acc_meter.get_acc_diff() + return top1.avg, attrwise_acc_meter.get_mean(), attrwise_acc_meter.get_acc_diff() def main(): - opt = parse_option() + opt = get_args() + opt.target = "blonde" if opt.target == "Blond_Hair" else opt.target + exp_name = f"os-celeba-lr{opt.lr}-bs{opt.batch_size}-epochs{opt.epochs}-seed{opt.seed}" - exp_name = f'os-celeba_{opt.task}-{opt.exp_name}-lr{opt.lr}-bs{opt.bs}-seed{opt.seed}' - opt.exp_name = exp_name + # result_dir = f"../results/celeba" + # result_path = Path(result_dir) + # result_path.mkdir(parents=True, exist_ok=True) + # if opt.target == "blonde": + # fout = open("/".join([str(result_path), "os_gender_blond_hair.txt"]), "w") - result_dir = f'../results/celeba' - result_path = Path(result_dir) - result_path.mkdir(parents=True, exist_ok=True) - if opt.task == 'blonde': - fout = open('/'.join([str(result_path), 'os_gender_blond_hair.txt']), 'w') + # results = {} + # metric_index = get_metric_index() + # for m_index in metric_index: + # results[m_index] = [] - results = {} - metric_index = get_metric_index() - for m_index in metric_index: - results[m_index] = [] + repeat_time = 1 - repeat_time = 10 - - output_dir = f'exp_results/{exp_name}' + output_dir = f"{project_dir}/checkpoints/{exp_name}" save_path = Path(output_dir) save_path.mkdir(parents=True, exist_ok=True) - set_logging(exp_name, 'INFO', str(save_path)) - logging.info(f'Set seed: {opt.seed}') + print(f"Set seed: {opt.seed}") set_seed(opt.seed) - logging.info(f'save_path: {save_path}') + print(f"save_path: {save_path}") np.set_printoptions(precision=3) torch.set_printoptions(precision=3) - root = '../data' - train_loader = get_celeba( - root, - batch_size=opt.bs, - target_attr=opt.task, - split='train', - aug=False, - under_sample='os') + root = f"{project_dir}/data" + train_loader = get_celeba(root, batch_size=opt.batch_size, target_attr=opt.target, split="train", aug=False, under_sample="os") val_loaders = {} - val_loaders['valid'] = get_celeba( - root, - batch_size=256, - target_attr=opt.task, - split='train_valid', - aug=False) - - val_loaders['test'] = get_celeba( - root, - batch_size=256, - target_attr=opt.task, - split='valid', - aug=False) + val_loaders["valid"] = get_celeba(root, batch_size=256, target_attr=opt.target, split="train_valid", aug=False) + + val_loaders["test"] = get_celeba(root, batch_size=256, target_attr=opt.target, split="valid", aug=False) for r in range(repeat_time): - logging.info(f'Repeated experiment: {r+1}') + # print(f"Repeated experiment: {r+1}") model, criterion = set_model() - decay_epochs = [opt.epochs // 3, opt.epochs * 2 // 3] + # Evaluation + if opt.checkpoint: + model.load_state_dict(torch.load(f"{save_path}/best_model.pt")["model"]) + model.eval() + + with torch.no_grad(): + all_labels, all_biases, all_preds = [], [], [] + for idx, (images, labels, _, biases, _, _) in enumerate(val_loaders["test"]): + images = images.cuda() + output, _ = model(images) + preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() + + all_labels.append(labels) + all_biases.append(biases) + all_preds.append(preds) + + fin_labels = torch.cat(all_labels) + fin_biases = torch.cat(all_biases) + fin_preds = torch.cat(all_preds) + + ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) + print_all_metrics(ret=ret) + + sys.exit() + + # ret["time per epoch"] = total_time / opt.epochs + # for i in range(len(metric_index)): + # results[metric_index[i]].append(ret[metric_index[i]]) + + # for m_index in metric_index: + # fout.write(m_index + "\t") + # for i in range(repeat_time): + # fout.write("%f\t" % results[m_index][i]) + # fout.write("%f\t%f\n" % (mean(results[m_index]), std(results[m_index]))) + # fout.close() + decay_epochs = [opt.epochs // 3, opt.epochs * 2 // 3] optimizer = torch.optim.Adam(model.parameters(), lr=opt.lr, weight_decay=1e-4) scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=decay_epochs, gamma=0.1) - logging.info(f'decay_epochs: {decay_epochs}') - - # (save_path / 'checkpoints').mkdir(parents=True, exist_ok=True) + print(f"decay_epochs: {decay_epochs}") - best_accs = {'valid': 0, 'test': 0} - best_epochs = {'valid': 0, 'test': 0} + best_accs = {"valid": 0, "test": 0} + best_epochs = {"valid": 0, "test": 0} best_stats = {} start_time = time.time() for epoch in range(1, opt.epochs + 1): - logging.info(f'[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}') + print(f"[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}") loss = train(train_loader, model, criterion, optimizer) - logging.info(f'[{epoch} / {opt.epochs}] Loss: {loss:.4f}') + print(f"[{epoch} / {opt.epochs}] Loss: {loss:.4f}") scheduler.step() @@ -182,61 +177,38 @@ def main(): for key, val_loader in val_loaders.items(): accs, valid_attrwise_accs, diff = validate(val_loader, model) - stats[f'{key}/acc'] = accs.item() - stats[f'{key}/acc_unbiased'] = torch.mean(valid_attrwise_accs).item() * 100 - stats[f'{key}/diff'] = diff.item() * 100 + stats[f"{key}/acc"] = accs.item() + stats[f"{key}/acc_unbiased"] = torch.mean(valid_attrwise_accs).item() * 100 + stats[f"{key}/diff"] = diff.item() * 100 eye_tsr = train_loader.dataset.eye_tsr - - stats[f'{key}/acc_skew'] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 - stats[f'{key}/acc_align'] = valid_attrwise_accs[eye_tsr == 0.0].mean().item() * 100 - logging.info(f'[{epoch} / {opt.epochs}] {valid_attrwise_accs} {stats}') + stats[f"{key}/acc_skew"] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 + stats[f"{key}/acc_align"] = valid_attrwise_accs[eye_tsr == 0.0].mean().item() * 100 + + print(f"[{epoch} / {opt.epochs}] {valid_attrwise_accs} {stats}") for tag in val_loaders.keys(): - if stats[f'{tag}/acc_unbiased'] > best_accs[tag]: - best_accs[tag] = stats[f'{tag}/acc_unbiased'] + if stats[f"{tag}/acc_unbiased"] > best_accs[tag]: + best_accs[tag] = stats[f"{tag}/acc_unbiased"] best_epochs[tag] = epoch - best_stats[tag] = pretty_dict(**{f'best_{tag}_{k}': v for k, v in stats.items()}) + best_stats[tag] = pretty_dict(**{f"best_{tag}_{k}": v for k, v in stats.items()}) - logging.info( - f'[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}') + # if tag == "valid": + # save_file = save_path / "best_model.pt" + # save_model(model, optimizer, opt, epoch, save_file) - total_time = time.time() - start_time - total_time_str = str(datetime.timedelta(seconds=int(total_time))) - logging.info(f'Total training time: {total_time_str}') - - # Evaluation - model.eval() + print( + f"[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}" + ) - with torch.no_grad(): - all_labels, all_biases, all_preds = [], [], [] - for idx, (images, labels, _, biases, _, _) in enumerate(val_loaders['test']): - images = images.cuda() - output, _ = model(images) - preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() + save_file = save_path / "best_model.pt" + save_model(model, optimizer, opt, epoch, save_file) - all_labels.append(labels) - all_biases.append(biases) - all_preds.append(preds) - - fin_labels = torch.cat(all_labels) - fin_biases = torch.cat(all_biases) - fin_preds = torch.cat(all_preds) - - ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) - print_all_metrics(ret=ret) - - ret['time per epoch'] = total_time / opt.epochs - for i in range(len(metric_index)): - results[metric_index[i]].append(ret[metric_index[i]]) - - for m_index in metric_index: - fout.write(m_index + '\t') - for i in range(repeat_time): - fout.write('%f\t' % results[m_index][i]) - fout.write('%f\t%f\n' % (mean(results[m_index]), std(results[m_index]))) - fout.close() + total_time = time.time() - start_time + total_time_str = str(datetime.timedelta(seconds=int(total_time))) + print(f"Total training time: {total_time_str}") + print(f"Time per epoch: {total_time / opt.epochs:.6f}") -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/BM/train_celeba/train_celeba_us.py b/BM/train_celeba/train_celeba_us.py index d39e5bb..c60a05d 100644 --- a/BM/train_celeba/train_celeba_us.py +++ b/BM/train_celeba/train_celeba_us.py @@ -1,49 +1,28 @@ -import argparse -import datetime -import logging +import os +import sys import time -from pathlib import Path - -import numpy as np import torch +import logging +import datetime +import numpy as np from torch import nn +from tqdm import tqdm +from pathlib import Path +from numpy import mean, std -import sys -sys.path.insert(1, './') +project_dir = "/root/DL-Fairness-Study" +sys.path.insert(1, os.path.join(project_dir, "BM")) +from debias.utils.logging import set_logging from debias.datasets.celeba import get_celeba from debias.networks.resnet import FCResNet18 -from debias.utils.logging import set_logging -from debias.utils.utils import (AverageMeter, MultiDimAverageMeter, accuracy, - pretty_dict, save_model, set_seed) +from debias.utils.utils import AverageMeter, MultiDimAverageMeter, accuracy, pretty_dict, save_model, set_seed -from tqdm import tqdm +sys.path.insert(1, project_dir) -import os -sys.path.insert(1, '/root/study') - -from numpy import mean, std +from arguments import get_args from metrics import get_metric_index, get_all_metrics, print_all_metrics -def parse_option(): - parser = argparse.ArgumentParser() - parser.add_argument('--exp_name', type=str, default='test') - parser.add_argument('--gpu', type=int, default=0) - parser.add_argument('--task', type=str, default='makeup') - - parser.add_argument('--epochs', type=int, default=40) - parser.add_argument('--seed', type=int, default=1) - - parser.add_argument('--bs', type=int, default=128, help='batch_size') - parser.add_argument('--lr', type=float, default=1e-3) - parser.add_argument('--rs', action="store_true") - - - opt = parser.parse_args() - os.environ["CUDA_VISIBLE_DEVICES"] = str(opt.gpu) - - return opt - def set_model(): model = FCResNet18().cuda() @@ -58,7 +37,7 @@ def train(train_loader, model, criterion, optimizer): train_iter = iter(train_loader) for images, labels, _, biases, _, _ in tqdm(train_iter, ascii=True): - + bsz = labels.shape[0] labels, biases = labels.cuda(), biases.cuda() @@ -90,25 +69,24 @@ def validate(val_loader, model): output, _ = model(images) preds = output.data.max(1, keepdim=True)[1].squeeze(1) - acc1, = accuracy(output, labels, topk=(1,)) + (acc1,) = accuracy(output, labels, topk=(1,)) top1.update(acc1[0], bsz) corrects = (preds == labels).long() attrwise_acc_meter.add(corrects.cpu(), torch.stack([labels.cpu(), biases.cpu()], dim=1)) - return top1.avg, attrwise_acc_meter.get_mean(), attrwise_acc_meter.get_acc_diff() + return top1.avg, attrwise_acc_meter.get_mean(), attrwise_acc_meter.get_acc_diff() def main(): - opt = parse_option() - - exp_name = f'us-celeba_{opt.task}-{opt.exp_name}-lr{opt.lr}-bs{opt.bs}-seed{opt.seed}' - opt.exp_name = exp_name + opt = get_args() + opt.target = "blonde" if opt.target == "Blond_Hair" else opt.target + exp_name = f"us-celeba-lr{opt.lr}-bs{opt.batch_size}-epochs{opt.epochs}-seed{opt.seed}" # result_dir = f'../results/celeba' # result_path = Path(result_dir) # result_path.mkdir(parents=True, exist_ok=True) - # if opt.task == 'blonde': + # if opt.target == 'blonde': # fout = open('/'.join([str(result_path), 'us_gender_blond_hair.txt']), 'w') # results = {} @@ -118,63 +96,79 @@ def main(): repeat_time = 1 - output_dir = f'exp_results/{exp_name}' + output_dir = f"{project_dir}/checkpoints/{exp_name}" save_path = Path(output_dir) save_path.mkdir(parents=True, exist_ok=True) - set_logging(exp_name, 'INFO', str(save_path)) - logging.info(f'Set seed: {opt.seed}') + print(f"Set seed: {opt.seed}") set_seed(opt.seed) - logging.info(f'save_path: {save_path}') + print(f"save_path: {save_path}") np.set_printoptions(precision=3) torch.set_printoptions(precision=3) - root = '../data' - train_loader = get_celeba( - root, - batch_size=opt.bs, - target_attr=opt.task, - split='train', - aug=False, - under_sample='ce') + root = f"{project_dir}/data" + train_loader = get_celeba(root, batch_size=opt.batch_size, target_attr=opt.target, split="train", aug=False, under_sample="ce") val_loaders = {} - val_loaders['valid'] = get_celeba( - root, - batch_size=256, - target_attr=opt.task, - split='train_valid', - aug=False) - - val_loaders['test'] = get_celeba( - root, - batch_size=256, - target_attr=opt.task, - split='valid', - aug=False) + val_loaders["valid"] = get_celeba(root, batch_size=256, target_attr=opt.target, split="train_valid", aug=False) + + val_loaders["test"] = get_celeba(root, batch_size=256, target_attr=opt.target, split="valid", aug=False) for r in range(repeat_time): - logging.info(f'Repeated experiment: {r+1}') + # print(f'Repeated experiment: {r+1}') model, criterion = set_model() - decay_epochs = [opt.epochs // 3, opt.epochs * 2 // 3] + # Evaluation + if opt.checkpoint: + model.load_state_dict(torch.load(f"{save_path}/best_model.pt")["model"]) + model.eval() + + with torch.no_grad(): + all_labels, all_biases, all_preds = [], [], [] + for _, (images, labels, _, biases, _, _) in enumerate(val_loaders["test"]): + images = images.cuda() + output, _ = model(images) + preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() + + all_labels.append(labels) + all_biases.append(biases) + all_preds.append(preds) + fin_labels = torch.cat(all_labels) + fin_biases = torch.cat(all_biases) + fin_preds = torch.cat(all_preds) + + ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) + print_all_metrics(ret=ret) + + sys.exit() + + # ret['time per epoch'] = total_time / opt.epochs + # for i in range(len(metric_index)): + # results[metric_index[i]].append(ret[metric_index[i]]) + + # for m_index in metric_index: + # fout.write(m_index + '\t') + # for i in range(repeat_time): + # fout.write('%f\t' % results[m_index][i]) + # fout.write('%f\t%f\n' % (mean(results[m_index]), std(results[m_index]))) + # fout.close() + + decay_epochs = [opt.epochs // 3, opt.epochs * 2 // 3] optimizer = torch.optim.Adam(model.parameters(), lr=opt.lr, weight_decay=1e-4) scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=decay_epochs, gamma=0.1) - logging.info(f'decay_epochs: {decay_epochs}') + print(f"decay_epochs: {decay_epochs}") - # (save_path / 'checkpoints').mkdir(parents=True, exist_ok=True) - - best_accs = {'valid': 0, 'test': 0} - best_epochs = {'valid': 0, 'test': 0} + best_accs = {"valid": 0, "test": 0} + best_epochs = {"valid": 0, "test": 0} best_stats = {} start_time = time.time() for epoch in range(1, opt.epochs + 1): - logging.info(f'[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}') + print(f"[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}") loss = train(train_loader, model, criterion, optimizer) - logging.info(f'[{epoch} / {opt.epochs}] Loss: {loss:.4f}') + print(f"[{epoch} / {opt.epochs}] Loss: {loss:.4f}") scheduler.step() @@ -182,66 +176,38 @@ def main(): for key, val_loader in val_loaders.items(): accs, valid_attrwise_accs, diff = validate(val_loader, model) - stats[f'{key}/acc'] = accs.item() - stats[f'{key}/acc_unbiased'] = torch.mean(valid_attrwise_accs).item() * 100 - stats[f'{key}/diff'] = diff.item() * 100 - + stats[f"{key}/acc"] = accs.item() + stats[f"{key}/acc_unbiased"] = torch.mean(valid_attrwise_accs).item() * 100 + stats[f"{key}/diff"] = diff.item() * 100 + eye_tsr = train_loader.dataset.eye_tsr - - stats[f'{key}/acc_skew'] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 - stats[f'{key}/acc_align'] = valid_attrwise_accs[eye_tsr == 0.0].mean().item() * 100 - logging.info(f'[{epoch} / {opt.epochs}] {valid_attrwise_accs} {stats}') + stats[f"{key}/acc_skew"] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 + stats[f"{key}/acc_align"] = valid_attrwise_accs[eye_tsr == 0.0].mean().item() * 100 + + print(f"[{epoch} / {opt.epochs}] {valid_attrwise_accs} {stats}") for tag in val_loaders.keys(): - if stats[f'{tag}/acc_unbiased'] > best_accs[tag]: - best_accs[tag] = stats[f'{tag}/acc_unbiased'] + if stats[f"{tag}/acc_unbiased"] > best_accs[tag]: + best_accs[tag] = stats[f"{tag}/acc_unbiased"] best_epochs[tag] = epoch - best_stats[tag] = pretty_dict(**{f'best_{tag}_{k}': v for k, v in stats.items()}) + best_stats[tag] = pretty_dict(**{f"best_{tag}_{k}": v for k, v in stats.items()}) - logging.info( - f'[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}') + print( + f"[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}" + ) - if opt.rs: + if opt.rs: train_loader.dataset.reset_data() - train_loader.dataset.under_sample_ce() + train_loader.dataset.under_sample_ce() + + save_file = save_path / "best_model.pt" + save_model(model, optimizer, opt, epoch, save_file) total_time = time.time() - start_time total_time_str = str(datetime.timedelta(seconds=int(total_time))) - logging.info(f'Total training time: {total_time_str}') - - # Evaluation - model.eval() - - with torch.no_grad(): - all_labels, all_biases, all_preds = [], [], [] - for _, (images, labels, _, biases, _, _) in enumerate(val_loaders['test']): - images = images.cuda() - output, _ = model(images) - preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() - - all_labels.append(labels) - all_biases.append(biases) - all_preds.append(preds) - - fin_labels = torch.cat(all_labels) - fin_biases = torch.cat(all_biases) - fin_preds = torch.cat(all_preds) - - ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) - print_all_metrics(ret=ret) - - ret['time per epoch'] = total_time / opt.epochs - print(ret['time per epoch']) - # for i in range(len(metric_index)): - # results[metric_index[i]].append(ret[metric_index[i]]) - - # for m_index in metric_index: - # fout.write(m_index + '\t') - # for i in range(repeat_time): - # fout.write('%f\t' % results[m_index][i]) - # fout.write('%f\t%f\n' % (mean(results[m_index]), std(results[m_index]))) - # fout.close() + print(f"Total training time: {total_time_str}") + print(f"Time per epoch: {total_time / opt.epochs:.6f}") -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/BM/train_celeba/train_celeba_uw.py b/BM/train_celeba/train_celeba_uw.py index a3748d3..f47fad9 100644 --- a/BM/train_celeba/train_celeba_uw.py +++ b/BM/train_celeba/train_celeba_uw.py @@ -1,55 +1,37 @@ -import argparse -import datetime -import logging import os +import sys import time -from pathlib import Path - -import numpy as np import torch +import logging +import argparse +import datetime +import numpy as np from torch import nn - -import sys -sys.path.insert(1, './') - from tqdm import tqdm +from pathlib import Path +from numpy import mean, std + +project_dir = "/root/DL-Fairness-Study" +sys.path.insert(1, os.path.join(project_dir, "BM")) from debias.datasets.celeba import get_celeba from debias.networks.resnet import FCResNet18 from debias.utils.logging import set_logging -from debias.utils.utils import (AverageMeter, MultiDimAverageMeter, accuracy, - pretty_dict, save_model, set_seed) +from debias.utils.utils import AverageMeter, MultiDimAverageMeter, accuracy, pretty_dict, save_model, set_seed -sys.path.insert(1, '/root/study') +sys.path.insert(1, project_dir) -from numpy import mean, std +from arguments import get_args from metrics import get_metric_index, get_all_metrics, print_all_metrics -def parse_option(): - parser = argparse.ArgumentParser() - parser.add_argument('--exp_name', type=str, default='test') - parser.add_argument('--gpu', type=int, default=0) - parser.add_argument('--task', type=str, default='makeup') - - parser.add_argument('--epochs', type=int, default=20) - parser.add_argument('--seed', type=int, default=1) - - parser.add_argument('--bs', type=int, default=128, help='batch_size') - parser.add_argument('--lr', type=float, default=1e-3) - - opt = parser.parse_args() - os.environ['CUDA_VISIBLE_DEVICES'] = str(opt.gpu) - - return opt - - def set_model(): model = FCResNet18().cuda() - criterion = nn.CrossEntropyLoss(reduction='none') + criterion = nn.CrossEntropyLoss(reduction="none") return model, criterion + def train(train_loader, model, criterion, optimizer): model.train() avg_loss = AverageMeter() @@ -72,7 +54,7 @@ def train(train_loader, model, criterion, optimizer): optimizer.zero_grad() loss.backward() optimizer.step() - + return avg_loss.avg @@ -90,91 +72,106 @@ def validate(val_loader, model): output, _ = model(images) preds = output.data.max(1, keepdim=True)[1].squeeze(1) - acc1, = accuracy(output, labels, topk=(1,)) + (acc1,) = accuracy(output, labels, topk=(1,)) top1.update(acc1[0], bsz) corrects = (preds == labels).long() attrwise_acc_meter.add(corrects.cpu(), torch.stack([labels.cpu(), biases.cpu()], dim=1)) - return top1.avg, attrwise_acc_meter.get_mean(), attrwise_acc_meter.get_acc_diff() + return top1.avg, attrwise_acc_meter.get_mean(), attrwise_acc_meter.get_acc_diff() def main(): - opt = parse_option() - - exp_name = f'uw-celeba_{opt.task}-{opt.exp_name}-lr{opt.lr}-bs{opt.bs}-seed{opt.seed}' - opt.exp_name = exp_name + opt = get_args() + opt.target = "blonde" if opt.target == "Blond_Hair" else opt.target + exp_name = f"uw-celeba-lr{opt.lr}-bs{opt.batch_size}-epochs{opt.epochs}-seed{opt.seed}" - result_dir = f'../results/celeba' - result_path = Path(result_dir) - result_path.mkdir(parents=True, exist_ok=True) - if opt.task == 'blonde': - fout = open('/'.join([str(result_path), 'uw_gender_blond_hair.txt']), 'w') + # result_dir = f"../results/celeba" + # result_path = Path(result_dir) + # result_path.mkdir(parents=True, exist_ok=True) + # if opt.target == "blonde": + # fout = open("/".join([str(result_path), "uw_gender_blond_hair.txt"]), "w") - results = {} - metric_index = get_metric_index() - for m_index in metric_index: - results[m_index] = [] + # results = {} + # metric_index = get_metric_index() + # for m_index in metric_index: + # results[m_index] = [] - repeat_time = 10 + repeat_time = 1 - output_dir = f'exp_results/{exp_name}' + output_dir = f"{project_dir}/checkpoints/{exp_name}" save_path = Path(output_dir) save_path.mkdir(parents=True, exist_ok=True) - set_logging(exp_name, 'INFO', str(save_path)) - logging.info(f'Set seed: {opt.seed}') + print(f"Set seed: {opt.seed}") set_seed(opt.seed) - logging.info(f'save_path: {save_path}') + print(f"save_path: {save_path}") np.set_printoptions(precision=3) torch.set_printoptions(precision=3) - root = '../data' - train_loader = get_celeba( - root, - batch_size=opt.bs, - target_attr=opt.task, - split='train', - aug=False) - + root = f"{project_dir}/data" + train_loader = get_celeba(root, batch_size=opt.batch_size, target_attr=opt.target, split="train", aug=False) val_loaders = {} - val_loaders['valid'] = get_celeba( - root, - batch_size=256, - target_attr=opt.task, - split='train_valid', - aug=False) - - val_loaders['test'] = get_celeba( - root, - batch_size=256, - target_attr=opt.task, - split='valid', - aug=False) + val_loaders["valid"] = get_celeba(root, batch_size=256, target_attr=opt.target, split="train_valid", aug=False) + + val_loaders["test"] = get_celeba(root, batch_size=256, target_attr=opt.target, split="valid", aug=False) for r in range(repeat_time): - logging.info(f'Repeated experiment: {r+1}') + # print(f"Repeated experiment: {r+1}") model, criterion = set_model() - decay_epochs = [opt.epochs // 3, opt.epochs * 2 // 3] + # Evaluation + if opt.checkpoint: + model.load_state_dict(torch.load(f"{save_path}/best_model.pt")["model"]) + model.eval() + + with torch.no_grad(): + all_labels, all_biases, all_preds = [], [], [] + for _, (images, labels, _, biases, _, _) in enumerate(val_loaders["test"]): + images = images.cuda() + output, _ = model(images) + preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() + + all_labels.append(labels) + all_biases.append(biases) + all_preds.append(preds) + + fin_labels = torch.cat(all_labels) + fin_biases = torch.cat(all_biases) + fin_preds = torch.cat(all_preds) + + ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) + print_all_metrics(ret=ret) + + sys.exit() + + # ret["time per epoch"] = total_time / opt.epochs + # for i in range(len(metric_index)): + # results[metric_index[i]].append(ret[metric_index[i]]) + + # for m_index in metric_index: + # fout.write(m_index + "\t") + # for i in range(repeat_time): + # fout.write("%f\t" % results[m_index][i]) + # fout.write("%f\t%f\n" % (mean(results[m_index]), std(results[m_index]))) + # fout.close() + decay_epochs = [opt.epochs // 3, opt.epochs * 2 // 3] optimizer = torch.optim.Adam(model.parameters(), lr=opt.lr, weight_decay=1e-4) scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=decay_epochs, gamma=0.1) - logging.info(f'decay_epochs: {decay_epochs}') - - # (save_path / 'checkpoints').mkdir(parents=True, exist_ok=True) + print(f"decay_epochs: {decay_epochs}") - best_accs = {'valid': 0, 'test': 0} - best_epochs = {'valid': 0, 'test': 0} + best_accs = {"valid": 0, "test": 0} + best_epochs = {"valid": 0, "test": 0} best_stats = {} start_time = time.time() for epoch in range(1, opt.epochs + 1): - logging.info(f'[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}') + print(f"[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}") loss = train(train_loader, model, criterion, optimizer) - logging.info(f'[{epoch} / {opt.epochs}] Loss: {loss:.4f}') + print(f"[{epoch} / {opt.epochs}] Loss: {loss:.4f}") scheduler.step() @@ -182,61 +179,38 @@ def main(): for key, val_loader in val_loaders.items(): accs, valid_attrwise_accs, diff = validate(val_loader, model) - stats[f'{key}/acc'] = accs.item() - stats[f'{key}/acc_unbiased'] = torch.mean(valid_attrwise_accs).item() * 100 - stats[f'{key}/diff'] = diff.item() * 100 + stats[f"{key}/acc"] = accs.item() + stats[f"{key}/acc_unbiased"] = torch.mean(valid_attrwise_accs).item() * 100 + stats[f"{key}/diff"] = diff.item() * 100 eye_tsr = train_loader.dataset.eye_tsr - stats[f'{key}/acc_skew'] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 - stats[f'{key}/acc_align'] = valid_attrwise_accs[eye_tsr == 0.0].mean().item() * 100 + stats[f"{key}/acc_skew"] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 + stats[f"{key}/acc_align"] = valid_attrwise_accs[eye_tsr == 0.0].mean().item() * 100 - logging.info(f'[{epoch} / {opt.epochs}] {valid_attrwise_accs} {stats}') + print(f"[{epoch} / {opt.epochs}] {valid_attrwise_accs} {stats}") for tag in val_loaders.keys(): - if stats[f'{tag}/acc_unbiased'] > best_accs[tag]: - best_accs[tag] = stats[f'{tag}/acc_unbiased'] + if stats[f"{tag}/acc_unbiased"] > best_accs[tag]: + best_accs[tag] = stats[f"{tag}/acc_unbiased"] best_epochs[tag] = epoch - best_stats[tag] = pretty_dict(**{f'best_{tag}_{k}': v for k, v in stats.items()}) - - logging.info( - f'[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}') - - total_time = time.time() - start_time - total_time_str = str(datetime.timedelta(seconds=int(total_time))) - logging.info(f'Total training time: {total_time_str}') + best_stats[tag] = pretty_dict(**{f"best_{tag}_{k}": v for k, v in stats.items()}) - # Evaluation - model.eval() - - with torch.no_grad(): - all_labels, all_biases, all_preds = [], [], [] - for _, (images, labels, _, biases, _, _) in enumerate(val_loaders['test']): - images = images.cuda() - output, _ = model(images) - preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() - - all_labels.append(labels) - all_biases.append(biases) - all_preds.append(preds) + # if tag == "valid": + # save_file = save_path / "best_model.pt" + # save_model(model, optimizer, opt, epoch, save_file) - fin_labels = torch.cat(all_labels) - fin_biases = torch.cat(all_biases) - fin_preds = torch.cat(all_preds) + print( + f"[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}" + ) - ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) - print_all_metrics(ret=ret) + save_file = save_path / "best_model.pt" + save_model(model, optimizer, opt, epoch, save_file) - ret['time per epoch'] = total_time / opt.epochs - for i in range(len(metric_index)): - results[metric_index[i]].append(ret[metric_index[i]]) - - for m_index in metric_index: - fout.write(m_index + '\t') - for i in range(repeat_time): - fout.write('%f\t' % results[m_index][i]) - fout.write('%f\t%f\n' % (mean(results[m_index]), std(results[m_index]))) - fout.close() + total_time = time.time() - start_time + total_time_str = str(datetime.timedelta(seconds=int(total_time))) + print(f"Total training time: {total_time_str}") + print(f"Time per epoch: {total_time / opt.epochs:.6f}") -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/BM/train_cifar10/train_cifar10_adv.py b/BM/train_cifar10/train_cifar10_adv.py index 987044c..ecc10e7 100644 --- a/BM/train_cifar10/train_cifar10_adv.py +++ b/BM/train_cifar10/train_cifar10_adv.py @@ -1,63 +1,36 @@ +import os +import sys +import time +import torch +import logging import argparse import datetime -import logging -import time -from pathlib import Path - import numpy as np -import torch from torch import nn -import torch.nn.functional as F from tqdm import tqdm +from pathlib import Path +from numpy import mean, std +import torch.nn.functional as F -import sys -sys.path.insert(1, './') +project_dir = "/root/DL-Fairness-Study" +sys.path.insert(1, os.path.join(project_dir, "BM")) +from debias.utils.logging import set_logging from debias.datasets.cifar10 import get_cifar10 from debias.networks.resnet_cifar import ResNet18_base -from debias.utils.logging import set_logging -from debias.utils.utils import (AverageMeter, MultiDimAverageMeter, accuracy, - pretty_dict, save_model, set_seed) +from debias.utils.utils import AverageMeter, MultiDimAverageMeter, accuracy, pretty_dict, save_model, set_seed -import os -sys.path.insert(1, '/root/study') +sys.path.insert(1, project_dir) -from numpy import mean, std +from arguments import get_args from metrics import get_metric_index, get_all_metrics, print_all_metrics -def parse_option(): - parser = argparse.ArgumentParser() - - parser.add_argument('--alpha', type=float, default=1) - - parser.add_argument('--exp_name', type=str, default='test', ) - parser.add_argument('--gpu', type=int, default=0) - - parser.add_argument('--print_freq', type=int, default=300, - help='print frequency') - parser.add_argument('--save_freq', type=int, default=200, - help='save frequency') - parser.add_argument('--epochs', type=int, default=500, - help='number of training epochs') - parser.add_argument('--seed', type=int, default=1) - - parser.add_argument('--bs', type=int, default=128, help='batch_size') - parser.add_argument('--lr', type=float, default=1e-4) - parser.add_argument('--corr', type=float, default=0.95) - parser.add_argument('--training_ratio', type=float, default=3) - - opt = parser.parse_args() - os.environ["CUDA_VISIBLE_DEVICES"] = str(opt.gpu) - - return opt - - def set_model(): model = ResNet18_base().cuda() class_criterion = nn.CrossEntropyLoss() domain_criterion = nn.CrossEntropyLoss() - + class_network = nn.Linear(512, 10).cuda() domain_network = nn.Linear(512, 2).cuda() @@ -73,27 +46,27 @@ def train(train_loader, model, criterion, optimizer, epoch, opt): for images, labels, _, biases, _, _ in tqdm(train_iter, ascii=True): bsz = labels.shape[0] labels, biases = labels.cuda(), biases.cuda() - + optimizer[0].zero_grad() optimizer[1].zero_grad() optimizer[2].zero_grad() - + images = images.cuda() features = model[0](images) class_out = model[1](features) domain_out = model[2](features) class_loss = criterion[0](class_out, labels) - domain_loss = criterion[1](domain_out, biases) + domain_loss = criterion[1](domain_out, biases) if epoch % opt.training_ratio == 0: log_softmax = F.log_softmax(domain_out, dim=1) confusion_loss = -log_softmax.mean(dim=1).mean() - loss = class_loss + opt.alpha*confusion_loss + loss = class_loss + opt.alpha * confusion_loss loss.backward() optimizer[0].step() optimizer[1].step() - + else: # Update the domain classifier domain_loss.backward() @@ -120,7 +93,7 @@ def validate(val_loader, model): preds = output.data.max(1, keepdim=True)[1].squeeze(1) - acc1, = accuracy(output, labels, topk=(1,)) + (acc1,) = accuracy(output, labels, topk=(1,)) top1.update(acc1[0], bsz) corrects = (preds == labels).long() @@ -130,59 +103,85 @@ def validate(val_loader, model): def main(): - opt = parse_option() + opt = get_args() + exp_name = f"adv-cifar10s-lr{opt.lr}-bs{opt.batch_size}-epochs{opt.epochs}-seed{opt.seed}" - exp_name = f'adv-cifar10-{opt.exp_name}-lr{opt.lr}-bs{opt.bs}-seed{opt.seed}' - opt.exp_name = exp_name + # result_dir = f"../results/cifar10s" + # result_path = Path(result_dir) + # result_path.mkdir(parents=True, exist_ok=True) + # fout = open("/".join([str(result_path), "adv.txt"]), "w") - result_dir = f'../results/cifar10s' - result_path = Path(result_dir) - result_path.mkdir(parents=True, exist_ok=True) - fout = open('/'.join([str(result_path), 'adv.txt']), 'w') + # results = {} + # metric_index = get_metric_index() + # for m_index in metric_index: + # results[m_index] = [] - results = {} - metric_index = get_metric_index() - for m_index in metric_index: - results[m_index] = [] + repeat_time = 1 - repeat_time = 10 - - output_dir = f'exp_results/{exp_name}' + output_dir = f"{project_dir}/checkpoints/{exp_name}" save_path = Path(output_dir) save_path.mkdir(parents=True, exist_ok=True) - set_logging(exp_name, 'INFO', str(save_path)) + print(f"Set seed: {opt.seed}") set_seed(opt.seed) - logging.info(f'save_path: {save_path}') + print(f"save_path: {save_path}") np.set_printoptions(precision=3) torch.set_printoptions(precision=3) - root = '../data/cifar10s' - train_loader = get_cifar10( - root, - split='train', - aug=False, - corr=opt.corr) + root = f"{project_dir}/data/cifar10s" + train_loader = get_cifar10(root, split="train", aug=False, corr=opt.skew_ratio) val_loaders = {} - val_loaders['valid'] = get_cifar10( - root, - split='valid', - aug=False, - corr=opt.corr - ) - val_loaders['test'] = get_cifar10( - root, - split='test', - aug=False) + val_loaders["valid"] = get_cifar10(root, split="valid", aug=False, corr=opt.skew_ratio) + val_loaders["test"] = get_cifar10(root, split="test", aug=False) for r in range(repeat_time): - logging.info(f'Repeated experiment: {r+1}') + # print(f"Repeated experiment: {r+1}") model, criterion = set_model() - decay_epochs = [opt.epochs//4, opt.epochs//2, opt.epochs//1.333] + # Evaluation + if opt.checkpoint: + model[0].load_state_dict(torch.load(f"{save_path}/best_model.pt")["model"]) + model[0].eval() + model[1].load_state_dict(torch.load(f"{save_path}/best_pred.pt")["model"]) + model[1].eval() + + with torch.no_grad(): + all_labels, all_biases, all_preds = [], [], [] + for images, labels, _, biases, _, _ in val_loaders["test"]: + images = images.cuda() + + feats = model[0](images) + output = model[1](feats) + preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() + + all_labels.append(labels) + all_biases.append(biases) + all_preds.append(preds) + + fin_labels = torch.cat(all_labels) + fin_biases = torch.cat(all_biases) + fin_preds = torch.cat(all_preds) + + ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) + print_all_metrics(ret=ret) + + sys.exit() + + # ret["time per epoch"] = total_time / opt.epochs + # for i in range(len(metric_index)): + # results[metric_index[i]].append(ret[metric_index[i]]) + + # for m_index in metric_index: + # fout.write(m_index + "\t") + # for i in range(repeat_time): + # fout.write("%f\t" % results[m_index][i]) + # fout.write("%f\t%f\n" % (mean(results[m_index]), std(results[m_index]))) + # fout.close() + + decay_epochs = [opt.epochs // 4, opt.epochs // 2, opt.epochs // 1.333] optimizer_base = torch.optim.Adam(model[0].parameters(), lr=opt.lr, weight_decay=1e-4) optimizer_class = torch.optim.Adam(model[1].parameters(), lr=opt.lr, weight_decay=1e-4) @@ -192,20 +191,18 @@ def main(): scheduler_base = torch.optim.lr_scheduler.MultiStepLR(optimizers[0], milestones=decay_epochs, gamma=0.1) scheduler_class = torch.optim.lr_scheduler.MultiStepLR(optimizers[1], milestones=decay_epochs, gamma=0.1) scheduler_domain = torch.optim.lr_scheduler.MultiStepLR(optimizers[2], milestones=decay_epochs, gamma=0.1) - schedulers = [scheduler_base,scheduler_class, scheduler_domain] + schedulers = [scheduler_base, scheduler_class, scheduler_domain] - logging.info(f"decay_epochs: {decay_epochs}") + print(f"decay_epochs: {decay_epochs}") - # (save_path / 'checkpoints').mkdir(parents=True, exist_ok=True) - - best_accs = {'valid': 0, 'test': 0} - best_epochs = {'valid': 0, 'test': 0} + best_accs = {"valid": 0, "test": 0} + best_epochs = {"valid": 0, "test": 0} best_stats = {} start_time = time.time() for epoch in range(1, opt.epochs + 1): - logging.info(f'[{epoch} / {opt.epochs}] Learning rate: {schedulers[0].get_last_lr()[0]}') + print(f"[{epoch} / {opt.epochs}] Learning rate: {schedulers[0].get_last_lr()[0]}") loss = train(train_loader, model, criterion, optimizers, epoch, opt) - logging.info(f'[{epoch} / {opt.epochs}] Loss: {loss:.4f}') + print(f"[{epoch} / {opt.epochs}] Loss: {loss:.4f}") schedulers[0].step() schedulers[1].step() @@ -215,58 +212,31 @@ def main(): for key, val_loader in val_loaders.items(): _, valid_attrwise_accs, diff = validate(val_loader, model) eye_tsr = train_loader.dataset.eye_tsr - stats[f'{key}/acc_unbiased'] = torch.mean(valid_attrwise_accs).item() * 100 - stats[f'{key}/diff'] = diff.item() * 100 - stats[f'{key}/bias_conflict'] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 + stats[f"{key}/acc_unbiased"] = torch.mean(valid_attrwise_accs).item() * 100 + stats[f"{key}/diff"] = diff.item() * 100 + stats[f"{key}/bias_conflict"] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 - logging.info(f'[{epoch} / {opt.epochs}] {stats}') + print(f"[{epoch} / {opt.epochs}] {stats}") for tag in best_accs.keys(): - if stats[f'{tag}/acc_unbiased'] > best_accs[tag]: - best_accs[tag] = stats[f'{tag}/acc_unbiased'] + if stats[f"{tag}/acc_unbiased"] > best_accs[tag]: + best_accs[tag] = stats[f"{tag}/acc_unbiased"] best_epochs[tag] = epoch - best_stats[tag] = pretty_dict(**{f'best_{tag}_{k}': v for k, v in stats.items()}) + best_stats[tag] = pretty_dict(**{f"best_{tag}_{k}": v for k, v in stats.items()}) + + print( + f"[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}" + ) - logging.info( - f'[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}') + save_file_base = save_path / "best_model.pt" + save_model(model[0], optimizer_base, opt, epoch, save_file_base) + save_file_class = save_path / "best_pred.pt" + save_model(model[1], optimizer_class, opt, epoch, save_file_class) total_time = time.time() - start_time total_time_str = str(datetime.timedelta(seconds=int(total_time))) - logging.info(f'Total training time: {total_time_str}') - - # Evaluation - model[0].eval() - - with torch.no_grad(): - all_labels, all_biases, all_preds = [], [], [] - for images, labels, _, biases, _, _ in val_loaders['test']: - images = images.cuda() - - feats = model[0](images) - output = model[1](feats) - preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() - - all_labels.append(labels) - all_biases.append(biases) - all_preds.append(preds) - - fin_labels = torch.cat(all_labels) - fin_biases = torch.cat(all_biases) - fin_preds = torch.cat(all_preds) - - ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) - print_all_metrics(ret=ret) - - ret['time per epoch'] = total_time / opt.epochs - for i in range(len(metric_index)): - results[metric_index[i]].append(ret[metric_index[i]]) - - for m_index in metric_index: - fout.write(m_index + '\t') - for i in range(repeat_time): - fout.write('%f\t' % results[m_index][i]) - fout.write('%f\t%f\n' % (mean(results[m_index]), std(results[m_index]))) - fout.close() + print(f"Total training time: {total_time_str}") + print(f"Time per epoch: {total_time / opt.epochs:.6f}") -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/BM/train_cifar10/train_cifar10_bc.py b/BM/train_cifar10/train_cifar10_bc.py index 1c6b345..857b9ef 100644 --- a/BM/train_cifar10/train_cifar10_bc.py +++ b/BM/train_cifar10/train_cifar10_bc.py @@ -1,65 +1,34 @@ -import argparse -import datetime -import logging import os +import sys import time -from pathlib import Path - -import numpy as np import torch -from torch import nn, optim +import logging +import argparse +import datetime +import numpy as np +from torch import nn +from tqdm import tqdm +from pathlib import Path +from numpy import mean, std -import sys -sys.path.insert(1, './') +project_dir = "/root/DL-Fairness-Study" +sys.path.insert(1, os.path.join(project_dir, "BM")) +from debias.utils.logging import set_logging from debias.datasets.cifar10 import get_cifar10 from debias.networks.resnet_cifar import ResNet18 from debias.losses.bias_contrastive import BiasContrastiveLoss -from debias.utils.logging import set_logging -from debias.utils.utils import (AverageMeter, MultiDimAverageMeter, accuracy, - save_model, set_seed, pretty_dict) +from debias.utils.utils import AverageMeter, MultiDimAverageMeter, accuracy, save_model, set_seed, pretty_dict -sys.path.insert(1, '/root/study') +sys.path.insert(1, project_dir) -from numpy import mean, std +from arguments import get_args from metrics import get_metric_index, get_all_metrics, print_all_metrics -def parse_option(): - parser = argparse.ArgumentParser() - parser.add_argument('--exp_name', type=str, default='test', ) - parser.add_argument('--gpu', type=int, default=0) - - parser.add_argument('--print_freq', type=int, default=300, - help='print frequency') - parser.add_argument('--save_freq', type=int, default=200, - help='save frequency') - parser.add_argument('--epochs', type=int, default=200, - help='number of training epochs') - parser.add_argument('--seed', type=int, default=1) - parser.add_argument('--corr', type=float, default=0.95) - - parser.add_argument('--bs', type=int, default=128, help='batch_size') - parser.add_argument('--cbs', type=int, default=64, help='batch_size of dataloader for contrastive loss') - parser.add_argument('--lr', type=float, default=0.1) - - # hyperparameters - parser.add_argument('--weight', type=float, default=0.01) - parser.add_argument('--ratio', type=int, default=10) - parser.add_argument('--aug', type=int, default=1) - parser.add_argument('--bb', type=int, default=0) - - opt = parser.parse_args() - os.environ["CUDA_VISIBLE_DEVICES"] = str(opt.gpu) - - return opt - - def set_model(train_loader, opt): model = ResNet18(num_classes=10).cuda() - criterion = BiasContrastiveLoss( - confusion_matrix=train_loader.dataset.confusion_matrix, - bb=opt.bb) + criterion = BiasContrastiveLoss(confusion_matrix=train_loader.dataset.confusion_matrix, bb=opt.bb) return model, criterion @@ -123,7 +92,7 @@ def validate(val_loader, model): output, _ = model(images) preds = output.data.max(1, keepdim=True)[1].squeeze(1) - acc1, = accuracy(output, labels, topk=(1,)) + (acc1,) = accuracy(output, labels, topk=(1,)) top1.update(acc1[0], bsz) corrects = (preds == labels).long() @@ -133,10 +102,8 @@ def validate(val_loader, model): def main(): - opt = parse_option() - - exp_name = f'bc-bb{opt.bb}-cifar10_corr{opt.corr}-{opt.exp_name}-lr{opt.lr}-bs{opt.bs}-cbs{opt.cbs}-w{opt.weight}-ratio{opt.ratio}-aug{opt.aug}-seed{opt.seed}' - opt.exp_name = exp_name + opt = get_args() + exp_name = f"bc-bb{opt.bb}-cifar10s-lr{opt.lr}-bs{opt.batch_size}-cbs{opt.cbs}-epochs{opt.epochs}-w{opt.weight}-ratio{opt.ratio}-aug{opt.aug}-seed{opt.seed}" # result_dir = f'../results/cifar10s' # result_path = Path(result_dir) @@ -150,72 +117,91 @@ def main(): repeat_time = 1 - output_dir = f'exp_results/{exp_name}' + output_dir = f"{project_dir}/checkpoints/{exp_name}" save_path = Path(output_dir) save_path.mkdir(parents=True, exist_ok=True) - set_logging(exp_name, 'INFO', str(save_path)) + print(f"Set seed: {opt.seed}") set_seed(opt.seed) - logging.info(f'save_path: {save_path}') + print(f"save_path: {save_path}") np.set_printoptions(precision=3) torch.set_printoptions(precision=3) - root = '../data/cifar10s' - train_loader = get_cifar10( - root, - batch_size=opt.bs, - split='train', - aug=False, - corr=opt.corr) + root = f"{project_dir}/data/cifar10s" + train_loader = get_cifar10(root, batch_size=opt.batch_size, split="train", aug=False, corr=opt.skew_ratio) - logging.info( - f'confusion_matrix - \n original: {train_loader.dataset.confusion_matrix_org}, \n normalized: {train_loader.dataset.confusion_matrix}') + print(f"confusion_matrix - \n original: {train_loader.dataset.confusion_matrix_org}, \n normalized: {train_loader.dataset.confusion_matrix}") - cont_train_loader = get_cifar10( - root, - batch_size=opt.cbs, - split='train', - aug=opt.aug, - two_crop=True, - ratio=opt.ratio, - corr=opt.corr) + cont_train_loader = get_cifar10(root, batch_size=opt.cbs, split="train", aug=opt.aug, two_crop=True, ratio=opt.ratio, corr=opt.skew_ratio) val_loaders = {} - val_loaders['valid'] = get_cifar10( + val_loaders["valid"] = get_cifar10( root, batch_size=256, - split='valid', + split="valid", aug=False, - corr=opt.corr, + corr=opt.skew_ratio, ) - val_loaders['test'] = get_cifar10( - root, - batch_size=256, - split='test', - aug=False) + val_loaders["test"] = get_cifar10(root, batch_size=256, split="test", aug=False) for r in range(repeat_time): - logging.info(f'Repeated experiment: {r+1}') + # print(f"Repeated experiment: {r+1}") model, criterion = set_model(train_loader, opt) - decay_epochs = [opt.epochs//4, opt.epochs//2, opt.epochs//1.333] + # Evaluation + if opt.checkpoint: + model.load_state_dict(torch.load(f"{save_path}/best_model.pt")["model"]) + model.eval() - optimizer = torch.optim.SGD(model.parameters(), lr=opt.lr, momentum = 0.9, weight_decay=5e-4) - scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=decay_epochs, gamma=0.1) - logging.info(f"decay_epochs: {decay_epochs}") + with torch.no_grad(): + all_labels, all_biases, all_preds = [], [], [] + for images, labels, _, biases, _, _ in val_loaders["test"]: + images = images.cuda() + + output, _ = model(images) + preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() + + all_labels.append(labels) + all_biases.append(biases) + all_preds.append(preds) + + fin_labels = torch.cat(all_labels) + fin_biases = torch.cat(all_biases) + fin_preds = torch.cat(all_preds) + + ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) + print_all_metrics(ret=ret) + + sys.exit() + + # ret["time per epoch"] = total_time / opt.epochs + # print(ret["time per epoch"]) + # for i in range(len(metric_index)): + # results[metric_index[i]].append(ret[metric_index[i]]) + + # for m_index in metric_index: + # fout.write(m_index + '\t') + # for i in range(repeat_time): + # fout.write('%f\t' % results[m_index][i]) + # fout.write('%f\t%f\n' % (mean(results[m_index]), std(results[m_index]))) + # fout.close() - (save_path / 'checkpoints').mkdir(parents=True, exist_ok=True) + decay_epochs = [opt.epochs // 4, opt.epochs // 2, opt.epochs // 1.333] - best_accs = {'valid': 0, 'test': 0} - best_epochs = {'valid': 0, 'test': 0} + optimizer = torch.optim.SGD(model.parameters(), lr=opt.lr, momentum=0.9, weight_decay=5e-4) + scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=decay_epochs, gamma=0.1) + print(f"decay_epochs: {decay_epochs}") + + best_accs = {"valid": 0, "test": 0} + best_epochs = {"valid": 0, "test": 0} best_stats = {} start_time = time.time() for epoch in range(1, opt.epochs + 1): - logging.info(f'[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]} weight: {opt.weight}') + print(f"[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]} weight: {opt.weight}") ce_loss, con_loss, loss = train(train_loader, cont_train_loader, model, criterion, optimizer, epoch, opt) - logging.info(f'[{epoch} / {opt.epochs}] Loss: {loss} CE Loss: {ce_loss} Con Loss: {con_loss}') + print(f"[{epoch} / {opt.epochs}] Loss: {loss} CE Loss: {ce_loss} Con Loss: {con_loss}") scheduler.step() @@ -225,64 +211,29 @@ def main(): eye_tsr = train_loader.dataset.eye_tsr - stats[f'{key}/acc_unbiased'] = torch.mean(valid_attrwise_accs).item() * 100 - stats[f'{key}/diff'] = diff.item() * 100 - stats[f'{key}/bias_conflict'] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 + stats[f"{key}/acc_unbiased"] = torch.mean(valid_attrwise_accs).item() * 100 + stats[f"{key}/diff"] = diff.item() * 100 + stats[f"{key}/bias_conflict"] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 - logging.info(f'[{epoch} / {opt.epochs}] {stats}') + print(f"[{epoch} / {opt.epochs}] {stats}") for tag in best_accs.keys(): - if stats[f'{tag}/acc_unbiased'] > best_accs[tag]: - best_accs[tag] = stats[f'{tag}/acc_unbiased'] + if stats[f"{tag}/acc_unbiased"] > best_accs[tag]: + best_accs[tag] = stats[f"{tag}/acc_unbiased"] best_epochs[tag] = epoch - best_stats[tag] = pretty_dict(**{f'best_{tag}_{k}': v for k, v in stats.items()}) + best_stats[tag] = pretty_dict(**{f"best_{tag}_{k}": v for k, v in stats.items()}) - save_file = save_path / "checkpoints" / f"best_{tag}_repeat{r+1}.pth" - save_model(model, optimizer, opt, epoch, save_file) + print( + f"[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}" + ) - logging.info( - f'[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}') + save_file = save_path / "best_model.pt" + save_model(model, optimizer, opt, epoch, save_file) total_time = time.time() - start_time total_time_str = str(datetime.timedelta(seconds=int(total_time))) - logging.info(f'Total training time: {total_time_str}') - - save_file = save_path / "checkpoints" / f"last_repeat{r+1}.pth" - save_model(model, optimizer, opt, opt.epochs, save_file) - - # Evaluation - model.eval() - - with torch.no_grad(): - all_labels, all_biases, all_preds = [], [], [] - for images, labels, _, biases, _, _ in val_loaders['test']: - images = images.cuda() - - output, _ = model(images) - preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() - - all_labels.append(labels) - all_biases.append(biases) - all_preds.append(preds) - - fin_labels = torch.cat(all_labels) - fin_biases = torch.cat(all_biases) - fin_preds = torch.cat(all_preds) - - ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) - print_all_metrics(ret=ret) - - ret['time per epoch'] = total_time / opt.epochs - print(ret['time per epoch']) - # for i in range(len(metric_index)): - # results[metric_index[i]].append(ret[metric_index[i]]) - - # for m_index in metric_index: - # fout.write(m_index + '\t') - # for i in range(repeat_time): - # fout.write('%f\t' % results[m_index][i]) - # fout.write('%f\t%f\n' % (mean(results[m_index]), std(results[m_index]))) - # fout.close() + print(f"Total training time: {total_time_str}") + print(f"Time per epoch: {total_time / opt.epochs:.6f}") -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/BM/train_cifar10/train_cifar10_bm.py b/BM/train_cifar10/train_cifar10_bm.py index 57ea455..753dcea 100644 --- a/BM/train_cifar10/train_cifar10_bm.py +++ b/BM/train_cifar10/train_cifar10_bm.py @@ -1,98 +1,72 @@ +import os +import sys +import time +import torch +import logging import argparse import datetime -import logging -import time -from pathlib import Path - import numpy as np -import torch from torch import nn +from tqdm import tqdm +from pathlib import Path +from numpy import mean, std -import sys -sys.path.insert(1, './') +project_dir = "/root/DL-Fairness-Study" +sys.path.insert(1, os.path.join(project_dir, "BM")) +from debias.utils.logging import set_logging from debias.datasets.cifar10 import get_cifar10 from debias.networks.resnet_cifar import ResNet18 -from debias.utils.logging import set_logging -from debias.utils.utils import (AverageMeter, MultiDimAverageMeter, accuracy, - pretty_dict, save_model, set_seed) +from debias.utils.utils import AverageMeter, MultiDimAverageMeter, accuracy, pretty_dict, save_model, set_seed from debias.datasets.utils import over_sample_features, under_sample_features -from tqdm import tqdm +sys.path.insert(1, project_dir) -import os -sys.path.insert(1, '/root/study') - -from numpy import mean, std +from arguments import get_args from metrics import get_metric_index, get_all_metrics, print_all_metrics -def parse_option(): - parser = argparse.ArgumentParser() - parser.add_argument('--exp_name', type=str, default='test') - parser.add_argument('--gpu', type=int, default=0) - - parser.add_argument('--epochs', type=int, default=200) - parser.add_argument('--seed', type=int, default=1) - - parser.add_argument('--bs', type=int, default=128, help='batch_size') - parser.add_argument('--lr', type=float, default=0.1) - parser.add_argument('--corr', type=float, default=0.95) - parser.add_argument('--ecu', type=int, default=0) - parser.add_argument('--uw', type=int, default=1) - parser.add_argument('--mode', type=str, default='none') - - opt = parser.parse_args() - os.environ["CUDA_VISIBLE_DEVICES"] = str(opt.gpu) - - return opt - - def set_model(): model = ResNet18(num_classes=10).cuda() pred = nn.Linear(512, 10).cuda() - models = { - 'model': model, - 'pred': pred - } + models = {"model": model, "pred": pred} - criterion = { - 'bin': nn.BCEWithLogitsLoss(reduction='none'), - 'multi': nn.CrossEntropyLoss(reduction='none') - } + criterion = {"bin": nn.BCEWithLogitsLoss(reduction="none"), "multi": nn.CrossEntropyLoss(reduction="none")} return models, criterion + + def train(train_loader, model, criterion, optimizer_model, opt, optimizer_layer): - model['model'].train() + model["model"].train() avg_loss = AverageMeter() train_iter = iter(train_loader) - - all_labels_nb = [] - all_gc = [] - all_feats = [] - all_bias = [] + + all_labels_nb = [] + all_gc = [] + all_feats = [] + all_bias = [] for images, labels, labels_bin, biases, gc, _ in tqdm(train_iter, ascii=True): - + bsz = labels.shape[0] labels_bin, biases = labels_bin.cuda(), biases.cuda() - + images = images.cuda() - logits, feat = model['model'](images) + logits, feat = model["model"](images) - multi = torch.ones_like(labels_bin) + multi = torch.ones_like(labels_bin) - multi[labels_bin == -1] = 0 - labels_bin[labels_bin == -1] = 0 + multi[labels_bin == -1] = 0 + labels_bin[labels_bin == -1] = 0 - loss = criterion['bin'](logits, labels_bin) - loss = loss*multi + loss = criterion["bin"](logits, labels_bin) + loss = loss * multi - div = torch.sum(multi) - loss = torch.sum(loss/div) + div = torch.sum(multi) + loss = torch.sum(loss / div) avg_loss.update(loss.item(), bsz) @@ -105,84 +79,80 @@ def train(train_loader, model, criterion, optimizer_model, opt, optimizer_layer) all_bias.append(biases.cpu().detach().numpy()) all_feats.append(feat.cpu().detach().numpy()) - all_labels_nb = np.concatenate(all_labels_nb, axis=0) - all_gc = np.concatenate(all_gc, axis=0) - all_bias = np.concatenate(all_bias, axis=0) - all_feats = np.concatenate(all_feats, axis=0) + all_labels_nb = np.concatenate(all_labels_nb, axis=0) + all_gc = np.concatenate(all_gc, axis=0) + all_bias = np.concatenate(all_bias, axis=0) + all_feats = np.concatenate(all_feats, axis=0) - if opt.mode == 'os': + if opt.mode == "os": all_feats, all_labels_nb = over_sample_features(all_bias, all_feats, all_labels_nb) - elif opt.mode == 'us': + elif opt.mode == "us": all_feats, all_labels_nb = under_sample_features(all_bias, all_feats, all_labels_nb) - batch_size = opt.bs + batch_size = opt.batch_size total_samples = len(all_labels_nb) - num_batches = total_samples//batch_size + num_batches = total_samples // batch_size for _ in tqdm(range(1), ascii=True): all_idx = np.arange(total_samples) np.random.shuffle(all_idx) - all_feats[all_idx] = all_feats + all_feats[all_idx] = all_feats all_labels_nb[all_idx] = all_labels_nb - if opt.mode == 'uw': + if opt.mode == "uw": all_gc[all_idx] = all_gc - for batch_idx in range(num_batches): - start = batch_idx * batch_size + for batch_idx in range(num_batches): + start = batch_idx * batch_size end = min(total_samples, start + batch_size) feats = torch.from_numpy(all_feats[start:end]).cuda() labels = torch.from_numpy(all_labels_nb[start:end]).cuda() gc = torch.from_numpy(all_gc[start:end]).cuda() - optimizer_layer.zero_grad() - out_lr = model['pred'](feats) + optimizer_layer.zero_grad() + out_lr = model["pred"](feats) - loss = criterion['multi'](out_lr, labels) + loss = criterion["multi"](out_lr, labels) - if opt.mode == 'uw': + if opt.mode == "uw": loss *= gc - - loss = torch.mean(loss) - loss.backward() + + loss = torch.mean(loss) + loss.backward() optimizer_layer.step() - - return avg_loss.avg + return avg_loss.avg def validate(val_loader, model): - model['model'].eval() - + model["model"].eval() + top1 = AverageMeter() attrwise_acc_meter = MultiDimAverageMeter(dims=(10, 2)) - + with torch.no_grad(): for images, labels, _, biases, _, _ in val_loader: images = images.cuda() bsz = labels.shape[0] - - output,feats = model['model'](images) - output = model['pred'](feats).detach().cpu() + + output, feats = model["model"](images) + output = model["pred"](feats).detach().cpu() preds = output.data.max(1, keepdim=True)[1].squeeze(1) - - acc1, = accuracy(output, labels, topk=(1,)) + + (acc1,) = accuracy(output, labels, topk=(1,)) top1.update(acc1[0], bsz) corrects = (preds == labels).long() - attrwise_acc_meter.add(corrects.cpu(), - torch.stack([labels.cpu(), biases.cpu()], dim=1)) + attrwise_acc_meter.add(corrects.cpu(), torch.stack([labels.cpu(), biases.cpu()], dim=1)) return top1.avg, attrwise_acc_meter.get_mean(), attrwise_acc_meter.get_acc_diff() def main(): - opt = parse_option() - - exp_name = f'bm-cifar10-{opt.exp_name}-lr{opt.lr}-bs{opt.bs}-seed{opt.seed}-mode_{opt.mode}' - opt.exp_name = exp_name + opt = get_args() + exp_name = f"bm_{opt.mode}-cifar10s-lr{opt.lr}-bs{opt.batch_size}-epochs{opt.epochs}-seed{opt.seed}" # result_dir = f'../results/cifar10s' # result_path = Path(result_dir) @@ -196,63 +166,89 @@ def main(): repeat_time = 1 - output_dir = f'exp_results/{exp_name}' + output_dir = f"{project_dir}/checkpoints/{exp_name}" save_path = Path(output_dir) save_path.mkdir(parents=True, exist_ok=True) - set_logging(exp_name, 'INFO', str(save_path)) - logging.info(f'Set seed: {opt.seed}') + print(f"Set seed: {opt.seed}") set_seed(opt.seed) - logging.info(f'save_path: {save_path}') + print(f"save_path: {save_path}") np.set_printoptions(precision=3) torch.set_printoptions(precision=3) - root = '../data/cifar10s' - train_loader = get_cifar10(root, - split='train', - aug=False, - under_sample='bin', - corr=opt.corr) + root = f"{project_dir}/data/cifar10s" + train_loader = get_cifar10(root, split="train", aug=False, under_sample="bin", corr=opt.skew_ratio) val_loaders = {} - val_loaders['valid'] = get_cifar10( - root, - split='valid', - aug=False, - corr=opt.corr) - - val_loaders['test'] = get_cifar10( - root, - split='test', - aug=False) - + val_loaders["valid"] = get_cifar10(root, split="valid", aug=False, corr=opt.skew_ratio) + + val_loaders["test"] = get_cifar10(root, split="test", aug=False) + for r in range(repeat_time): - logging.info(f'Repeated experiment: {r+1}') + # print(f"Repeated experiment: {r+1}") model, criterion = set_model() - - decay_epochs = [opt.epochs//4, opt.epochs//2, opt.epochs//1.333] - optimizer = torch.optim.SGD(model['model'].parameters(), lr=opt.lr, momentum = 0.9, weight_decay=5e-4) + # Evaluation + if opt.checkpoint: + model["model"].load_state_dict(torch.load(f"{save_path}/best_model.pt")["model"]) + model["model"].eval() + model["pred"].load_state_dict(torch.load(f"{save_path}/best_pred.pt")["model"]) + model["pred"].eval() + + with torch.no_grad(): + all_labels, all_biases, all_preds = [], [], [] + for images, labels, _, biases, _, _ in val_loaders["test"]: + images = images.cuda() + output, feats = model["model"](images) + output = model["pred"](feats).detach().cpu() + preds = output.data.max(1, keepdim=True)[1].squeeze(1) + + all_labels.append(labels) + all_biases.append(biases) + all_preds.append(preds) + + fin_labels = torch.cat(all_labels) + fin_biases = torch.cat(all_biases) + fin_preds = torch.cat(all_preds) + + ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) + print_all_metrics(ret=ret) + + sys.exit() + + # ret["time per epoch"] = total_time / opt.epochs + # print(ret["time per epoch"]) + # for i in range(len(metric_index)): + # results[metric_index[i]].append(ret[metric_index[i]]) + + # for m_index in metric_index: + # fout.write(m_index + '\t') + # for i in range(repeat_time): + # fout.write('%f\t' % results[m_index][i]) + # fout.write('%f\t%f\n' % (mean(results[m_index]), std(results[m_index]))) + # fout.close() + + decay_epochs = [opt.epochs // 4, opt.epochs // 2, opt.epochs // 1.333] + + optimizer = torch.optim.SGD(model["model"].parameters(), lr=opt.lr, momentum=0.9, weight_decay=5e-4) scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=decay_epochs, gamma=0.1) - optimizer_layer = torch.optim.SGD(model['pred'].parameters(), lr=opt.lr, momentum = 0.9, weight_decay=5e-4) + optimizer_layer = torch.optim.SGD(model["pred"].parameters(), lr=opt.lr, momentum=0.9, weight_decay=5e-4) scheduler_layer = torch.optim.lr_scheduler.MultiStepLR(optimizer_layer, milestones=decay_epochs, gamma=0.1) - logging.info(f"decay_epochs: {decay_epochs}") - - # (save_path / 'checkpoints').mkdir(parents=True, exist_ok=True) + print(f"decay_epochs: {decay_epochs}") - best_accs = {'valid': 0, 'test': 0} - best_diff = {'valid':0, 'test':0} - best_epochs = {'valid': 0, 'test': 0} - best_stats = {'valid': 0, 'test': 0} + best_accs = {"valid": 0, "test": 0} + best_diff = {"valid": 0, "test": 0} + best_epochs = {"valid": 0, "test": 0} + best_stats = {"valid": 0, "test": 0} start_time = time.time() for epoch in range(1, opt.epochs + 1): - logging.info(f'[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}') + print(f"[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}") loss = train(train_loader, model, criterion, optimizer, opt, optimizer_layer) - logging.info(f'[{epoch} / {opt.epochs}] Loss: {loss}') + print(f"[{epoch} / {opt.epochs}] Loss: {loss}") scheduler.step() scheduler_layer.step() @@ -263,62 +259,34 @@ def main(): eye_tsr = train_loader.dataset.eye_tsr - stats[f'{key}/acc_unbiased'] = torch.mean(valid_attrwise_accs).item() * 100 - stats[f'{key}/diff'] = diff.item() * 100 - stats[f'{key}/bias_conflict'] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 - + stats[f"{key}/acc_unbiased"] = torch.mean(valid_attrwise_accs).item() * 100 + stats[f"{key}/diff"] = diff.item() * 100 + stats[f"{key}/bias_conflict"] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 - logging.info(f'[{epoch} / {opt.epochs}] {stats}') + print(f"[{epoch} / {opt.epochs}] {stats}") for tag in best_accs.keys(): - if stats[f'{tag}/acc_unbiased'] > best_accs[tag]: - best_accs[tag] = stats[f'{tag}/acc_unbiased'] + if stats[f"{tag}/acc_unbiased"] > best_accs[tag]: + best_accs[tag] = stats[f"{tag}/acc_unbiased"] best_epochs[tag] = epoch - best_stats[tag] = pretty_dict(**{f'best_{tag}_{k}': v for k, v in stats.items()}) + best_stats[tag] = pretty_dict(**{f"best_{tag}_{k}": v for k, v in stats.items()}) - logging.info( - f'[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}') + print( + f"[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}" + ) - if opt.ecu: + if opt.ecu: train_loader.dataset.under_sample_ce(verbose=False) - - total_time = time.time() - start_time - total_time_str = str(datetime.timedelta(seconds=int(total_time))) - logging.info(f'Total training time: {total_time_str}') - - # Evaluation - model['model'].eval() - - with torch.no_grad(): - all_labels, all_biases, all_preds = [], [], [] - for images, labels, _, biases, _, _ in val_loaders['test']: - images = images.cuda() - output,feats = model['model'](images) - output = model['pred'](feats).detach().cpu() - preds = output.data.max(1, keepdim=True)[1].squeeze(1) - all_labels.append(labels) - all_biases.append(biases) - all_preds.append(preds) + save_file_model = save_path / "best_model.pt" + save_file_pred = save_path / "best_pred.pt" + save_model(model["model"], optimizer, opt, epoch, save_file_model) + save_model(model["pred"], optimizer_layer, opt, epoch, save_file_pred) - fin_labels = torch.cat(all_labels) - fin_biases = torch.cat(all_biases) - fin_preds = torch.cat(all_preds) - - ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) - print_all_metrics(ret=ret) - - ret['time per epoch'] = total_time / opt.epochs - print(ret['time per epoch']) - # for i in range(len(metric_index)): - # results[metric_index[i]].append(ret[metric_index[i]]) - - # for m_index in metric_index: - # fout.write(m_index + '\t') - # for i in range(repeat_time): - # fout.write('%f\t' % results[m_index][i]) - # fout.write('%f\t%f\n' % (mean(results[m_index]), std(results[m_index]))) - # fout.close() + total_time = time.time() - start_time + total_time_str = str(datetime.timedelta(seconds=int(total_time))) + print(f"Total training time: {total_time_str}") + print(f"Time per epoch: {total_time / opt.epochs:.6f}") -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/BM/train_cifar10/train_cifar10_di.py b/BM/train_cifar10/train_cifar10_di.py index cdaf7a1..0214667 100644 --- a/BM/train_cifar10/train_cifar10_di.py +++ b/BM/train_cifar10/train_cifar10_di.py @@ -1,59 +1,32 @@ -import argparse -import datetime -import logging import os +import sys import time -from pathlib import Path - -import numpy as np import torch -import torch.nn.functional as F -from torch import nn, optim +import logging +import argparse +import datetime +import numpy as np from tqdm import tqdm +from pathlib import Path +import torch.nn.functional as F -import sys -sys.path.insert(1, './') - -from tqdm import tqdm +project_dir = "/root/DL-Fairness-Study" +sys.path.insert(1, os.path.join(project_dir, "BM")) -from debias.datasets.cifar10 import get_cifar10 from debias.losses.diloss import DILoss -from debias.networks.resnet_cifar import ResNet18 from debias.utils.logging import set_logging -from debias.utils.utils import (AverageMeter, MultiDimAverageMeter, accuracy, - save_model, set_seed, pretty_dict) +from debias.datasets.cifar10 import get_cifar10 +from debias.networks.resnet_cifar import ResNet18 +from debias.utils.utils import AverageMeter, MultiDimAverageMeter, accuracy, save_model, set_seed, pretty_dict -sys.path.insert(1, '/root/study') +sys.path.insert(1, project_dir) -from numpy import mean, std +from arguments import get_args from metrics import get_metric_index, get_all_metrics, print_all_metrics -def parse_option(): - parser = argparse.ArgumentParser() - parser.add_argument('--exp_name', type=str, default='test', ) - parser.add_argument('--gpu', type=int, default=0) - - parser.add_argument('--print_freq', type=int, default=300, - help='print frequency') - parser.add_argument('--save_freq', type=int, default=200, - help='save frequency') - parser.add_argument('--epochs', type=int, default=200, - help='number of training epochs') - parser.add_argument('--seed', type=int, default=1) - - parser.add_argument('--bs', type=int, default=128, help='batch_size') - parser.add_argument('--lr', type=float, default=0.1) - parser.add_argument('--corr', type=float, default=0.95) - - opt = parser.parse_args() - os.environ["CUDA_VISIBLE_DEVICES"] = str(opt.gpu) - - return opt - - def set_model(): - model = ResNet18(num_classes=10*2).cuda() + model = ResNet18(num_classes=10 * 2).cuda() criterion = DILoss(num_classes=10, num_biases=2) return model, criterion @@ -96,89 +69,112 @@ def validate(val_loader, model): bsz = labels.shape[0] logits, _ = model(images) - logits = sum([F.log_softmax(logits[:, i * num_classes: (i + 1) * num_classes], dim=1) for i in - range(num_biases)]) + logits = sum([F.log_softmax(logits[:, i * num_classes : (i + 1) * num_classes], dim=1) for i in range(num_biases)]) preds = logits.data.max(1, keepdim=True)[1].squeeze(1) - acc1, = accuracy(logits, labels, topk=(1,)) + (acc1,) = accuracy(logits, labels, topk=(1,)) top1.update(acc1[0], bsz) corrects = (preds == labels).long() attrwise_acc_meter.add(corrects.cpu(), torch.stack([labels.cpu(), biases.cpu()], dim=1)) - + return top1.avg, attrwise_acc_meter.get_mean(), attrwise_acc_meter.get_acc_diff() def main(): - opt = parse_option() + opt = get_args() + exp_name = f"di-cifar10s-lr{opt.lr}-bs{opt.batch_size}-epochs{opt.epochs}-seed{opt.seed}" - exp_name = f'di-cifar10-{opt.exp_name}-lr{opt.lr}-bs{opt.bs}-seed{opt.seed}' - opt.exp_name = exp_name + # result_dir = f"../results/cifar10s" + # result_path = Path(result_dir) + # result_path.mkdir(parents=True, exist_ok=True) + # fout = open("/".join([str(result_path), "di.txt"]), "w") - result_dir = f'../results/cifar10s' - result_path = Path(result_dir) - result_path.mkdir(parents=True, exist_ok=True) - fout = open('/'.join([str(result_path), 'di.txt']), 'w') + # results = {} + # metric_index = get_metric_index() + # for m_index in metric_index: + # results[m_index] = [] - results = {} - metric_index = get_metric_index() - for m_index in metric_index: - results[m_index] = [] + repeat_time = 1 - repeat_time = 10 - - output_dir = f'exp_results/{exp_name}' + output_dir = f"{project_dir}/checkpoints/{exp_name}" save_path = Path(output_dir) save_path.mkdir(parents=True, exist_ok=True) - set_logging(exp_name, 'INFO', str(save_path)) - logging.info(f'Set seed: {opt.seed}') + print(f"Set seed: {opt.seed}") set_seed(opt.seed) - logging.info(f'save_path: {save_path}') + print(f"save_path: {save_path}") np.set_printoptions(precision=3) torch.set_printoptions(precision=3) - - root = '../data/cifar10s' - train_loader = get_cifar10( - root, - split='train', - aug=False, - corr=opt.corr) + + root = f"{project_dir}/data/cifar10s" + train_loader = get_cifar10(root, split="train", aug=False, corr=opt.skew_ratio) val_loaders = {} - val_loaders['valid'] = get_cifar10( - root, - split='valid', - aug=False, - corr=opt.corr - ) - val_loaders['test'] = get_cifar10( - root, - split='test', - aug=False) + val_loaders["valid"] = get_cifar10(root, split="valid", aug=False, corr=opt.skew_ratio) + val_loaders["test"] = get_cifar10(root, split="test", aug=False) for r in range(repeat_time): - logging.info(f'Repeated experiment: {r+1}') + # print(f"Repeated experiment: {r+1}") model, criterion = set_model() - decay_epochs = [opt.epochs//4, opt.epochs//2, opt.epochs//1.333] + # Evaluation + if opt.checkpoint: + model.load_state_dict(torch.load(f"{save_path}/best_model.pt")["model"]) + model.eval() + + num_biases = 2 + num_classes = 10 + + with torch.no_grad(): + all_labels, all_biases, all_preds = [], [], [] + for images, labels, _, biases, _, _ in val_loaders["test"]: + images = images.cuda() + + logits, _ = model(images) + logits = sum([F.log_softmax(logits[:, i * num_classes : (i + 1) * num_classes], dim=1) for i in range(num_biases)]) + preds = logits.data.max(1, keepdim=True)[1].squeeze(1).cpu() + + all_labels.append(labels) + all_biases.append(biases) + all_preds.append(preds) + + fin_labels = torch.cat(all_labels) + fin_biases = torch.cat(all_biases) + fin_preds = torch.cat(all_preds) + + ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) + print_all_metrics(ret=ret) + + sys.exit() + + # ret["time per epoch"] = total_time / opt.epochs + # for i in range(len(metric_index)): + # results[metric_index[i]].append(ret[metric_index[i]]) - optimizer = optim.SGD(model.parameters(), lr=opt.lr, momentum=0.9, weight_decay=5e-4) - scheduler = optim.lr_scheduler.MultiStepLR(optimizer, milestones=decay_epochs, gamma=0.1) - logging.info(f"decay_epochs: {decay_epochs}") + # for m_index in metric_index: + # fout.write(m_index + "\t") + # for i in range(repeat_time): + # fout.write("%f\t" % results[m_index][i]) + # fout.write("%f\t%f\n" % (mean(results[m_index]), std(results[m_index]))) + # fout.close() - (save_path / 'checkpoints').mkdir(parents=True, exist_ok=True) + decay_epochs = [opt.epochs // 4, opt.epochs // 2, opt.epochs // 1.333] - best_accs = {'valid': 0, 'test': 0} - best_epochs = {'valid': 0, 'test': 0} + optimizer = torch.optim.SGD(model.parameters(), lr=opt.lr, momentum=0.9, weight_decay=5e-4) + scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=decay_epochs, gamma=0.1) + print(f"decay_epochs: {decay_epochs}") + + best_accs = {"valid": 0, "test": 0} + best_epochs = {"valid": 0, "test": 0} best_stats = {} start_time = time.time() for epoch in range(1, opt.epochs + 1): - logging.info(f'[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}') + print(f"[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}") loss = train(train_loader, model, criterion, optimizer) - logging.info(f'[{epoch} / {opt.epochs}] Loss: {loss}') + print(f"[{epoch} / {opt.epochs}] Loss: {loss}") scheduler.step() @@ -188,67 +184,29 @@ def main(): eye_tsr = train_loader.dataset.eye_tsr - stats[f'{key}/acc_unbiased'] = torch.mean(valid_attrwise_accs).item() * 100 - stats[f'{key}/diff'] = diff.item() * 100 - stats[f'{key}/bias_conflict'] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 + stats[f"{key}/acc_unbiased"] = torch.mean(valid_attrwise_accs).item() * 100 + stats[f"{key}/diff"] = diff.item() * 100 + stats[f"{key}/bias_conflict"] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 - logging.info(f'[{epoch} / {opt.epochs}] {stats}') + print(f"[{epoch} / {opt.epochs}] {stats}") for tag in best_accs.keys(): - if stats[f'{tag}/acc_unbiased'] > best_accs[tag]: - best_accs[tag] = stats[f'{tag}/acc_unbiased'] + if stats[f"{tag}/acc_unbiased"] > best_accs[tag]: + best_accs[tag] = stats[f"{tag}/acc_unbiased"] best_epochs[tag] = epoch - best_stats[tag] = pretty_dict(**{f'best_{tag}_{k}': v for k, v in stats.items()}) + best_stats[tag] = pretty_dict(**{f"best_{tag}_{k}": v for k, v in stats.items()}) - save_file = save_path / "checkpoints" / f"best_{tag}_repeat{r+1}.pth" - save_model(model, optimizer, opt, epoch, save_file) + print( + f"[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}" + ) - logging.info( - f'[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}') + save_file = save_path / "best_model.pt" + save_model(model, optimizer, opt, epoch, save_file) total_time = time.time() - start_time total_time_str = str(datetime.timedelta(seconds=int(total_time))) - logging.info(f'Total training time: {total_time_str}') - - save_file = save_path / "checkpoints" / f"last_repeat{r+1}.pth" - save_model(model, optimizer, opt, opt.epochs, save_file) - - # Evaluation - model.eval() - - num_biases = 2 - num_classes = 10 - - with torch.no_grad(): - all_labels, all_biases, all_preds = [], [], [] - for images, labels, _, biases, _, _ in val_loaders['test']: - images = images.cuda() - - logits, _ = model(images) - logits = sum([F.log_softmax(logits[:, i * num_classes: (i + 1) * num_classes], dim=1) for i in range(num_biases)]) - preds = logits.data.max(1, keepdim=True)[1].squeeze(1).cpu() - - all_labels.append(labels) - all_biases.append(biases) - all_preds.append(preds) - - fin_labels = torch.cat(all_labels) - fin_biases = torch.cat(all_biases) - fin_preds = torch.cat(all_preds) - - ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) - print_all_metrics(ret=ret) - - ret['time per epoch'] = total_time / opt.epochs - for i in range(len(metric_index)): - results[metric_index[i]].append(ret[metric_index[i]]) - - for m_index in metric_index: - fout.write(m_index + '\t') - for i in range(repeat_time): - fout.write('%f\t' % results[m_index][i]) - fout.write('%f\t%f\n' % (mean(results[m_index]), std(results[m_index]))) - fout.close() + print(f"Total training time: {total_time_str}") + print(f"Time per epoch: {total_time / opt.epochs:.6f}") -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/BM/train_cifar10/train_cifar10_os.py b/BM/train_cifar10/train_cifar10_os.py index 12797c9..a815f82 100644 --- a/BM/train_cifar10/train_cifar10_os.py +++ b/BM/train_cifar10/train_cifar10_os.py @@ -1,52 +1,30 @@ -import argparse -import datetime -import logging import os +import sys import time -from pathlib import Path - -import numpy as np import torch -from torch import nn, optim +import logging +import argparse +import datetime +import numpy as np +from torch import nn +from tqdm import tqdm +from pathlib import Path +from numpy import mean, std -import sys -sys.path.insert(1, './') +project_dir = "/root/DL-Fairness-Study" +sys.path.insert(1, os.path.join(project_dir, "BM")) +from debias.utils.logging import set_logging from debias.datasets.cifar10 import get_cifar10 from debias.networks.resnet_cifar import ResNet18 -from debias.utils.logging import set_logging -from debias.utils.utils import (AverageMeter, MultiDimAverageMeter, accuracy, - save_model, set_seed, pretty_dict) +from debias.utils.utils import AverageMeter, MultiDimAverageMeter, accuracy, save_model, set_seed, pretty_dict -sys.path.insert(1, '/root/study') +sys.path.insert(1, project_dir) -from numpy import mean, std +from arguments import get_args from metrics import get_metric_index, get_all_metrics, print_all_metrics -def parse_option(): - parser = argparse.ArgumentParser() - parser.add_argument('--exp_name', type=str, default='test', ) - parser.add_argument('--gpu', type=int, default=0) - - parser.add_argument('--print_freq', type=int, default=300, - help='print frequency') - parser.add_argument('--save_freq', type=int, default=200, - help='save frequency') - parser.add_argument('--epochs', type=int, default=200, - help='number of training epochs') - parser.add_argument('--seed', type=int, default=1) - - parser.add_argument('--bs', type=int, default=128, help='batch_size') - parser.add_argument('--lr', type=float, default=0.1) - parser.add_argument('--corr', type=float, default=0.95) - - opt = parser.parse_args() - os.environ["CUDA_VISIBLE_DEVICES"] = str(opt.gpu) - - return opt - - def set_model(): model = ResNet18(num_classes=10).cuda() criterion = nn.CrossEntropyLoss() @@ -91,20 +69,18 @@ def validate(val_loader, model): output, _ = model(images) preds = output.data.max(1, keepdim=True)[1].squeeze(1) - acc1, = accuracy(output, labels, topk=(1,)) + (acc1,) = accuracy(output, labels, topk=(1,)) top1.update(acc1[0], bsz) corrects = (preds == labels).long() attrwise_acc_meter.add(corrects.cpu(), torch.stack([labels.cpu(), biases.cpu()], dim=1)) - + return top1.avg, attrwise_acc_meter.get_mean(), attrwise_acc_meter.get_acc_diff() def main(): - opt = parse_option() - - exp_name = f'os-cifar10-{opt.exp_name}-lr{opt.lr}-bs{opt.bs}-seed{opt.seed}' - opt.exp_name = exp_name + opt = get_args() + exp_name = f"os-cifar10s-lr{opt.lr}-bs{opt.batch_size}-epochs{opt.epochs}-seed{opt.seed}" # result_dir = f'../results/cifar10s' # result_path = Path(result_dir) @@ -118,57 +94,84 @@ def main(): repeat_time = 1 - output_dir = f'exp_results/{exp_name}' + output_dir = f"{project_dir}/checkpoints/{exp_name}" save_path = Path(output_dir) save_path.mkdir(parents=True, exist_ok=True) - set_logging(exp_name, 'INFO', str(save_path)) + print(f"Set seed: {opt.seed}") set_seed(opt.seed) - logging.info(f'save_path: {save_path}') + print(f"save_path: {save_path}") np.set_printoptions(precision=3) torch.set_printoptions(precision=3) - root = '../data/cifar10s' - train_loader = get_cifar10( - root, - split='train', - aug=False, - under_sample ='os', - corr=opt.corr) + root = f"{project_dir}/data/cifar10s" + train_loader = get_cifar10(root, split="train", aug=False, under_sample="os", corr=opt.skew_ratio) val_loaders = {} - val_loaders['valid'] = get_cifar10( + val_loaders["valid"] = get_cifar10( root, - split='valid', + split="valid", aug=False, ) - val_loaders['test'] = get_cifar10( - root, - split='test', - aug=False) + val_loaders["test"] = get_cifar10(root, split="test", aug=False) for r in range(repeat_time): - logging.info(f'Repeated experiment: {r+1}') + # print(f"Repeated experiment: {r+1}") model, criterion = set_model() - decay_epochs = [opt.epochs//4, opt.epochs//2, opt.epochs//1.333] - - optimizer = optim.SGD(model.parameters(), lr=opt.lr, momentum =0.9, weight_decay=5e-4) - scheduler = optim.lr_scheduler.MultiStepLR(optimizer, milestones=decay_epochs, gamma=0.1) - logging.info(f"decay_epochs: {decay_epochs}") - - (save_path / 'checkpoints').mkdir(parents=True, exist_ok=True) - - best_accs = {'valid': 0, 'test': 0} - best_epochs = {'valid': 0, 'test': 0} + # Evaluation + if opt.checkpoint: + model.load_state_dict(torch.load(f"{save_path}/best_model.pt")["model"]) + model.eval() + + with torch.no_grad(): + all_labels, all_biases, all_preds = [], [], [] + for images, labels, _, biases, _, _ in val_loaders["test"]: + images = images.cuda() + output, _ = model(images) + preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() + + all_labels.append(labels) + all_biases.append(biases) + all_preds.append(preds) + + fin_labels = torch.cat(all_labels) + fin_biases = torch.cat(all_biases) + fin_preds = torch.cat(all_preds) + + ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) + print_all_metrics(ret=ret) + + sys.exit() + + # ret["time per epoch"] = total_time / opt.epochs + # print(ret["time per epoch"]) + # for i in range(len(metric_index)): + # results[metric_index[i]].append(ret[metric_index[i]]) + + # for m_index in metric_index: + # fout.write(m_index + '\t') + # for i in range(repeat_time): + # fout.write('%f\t' % results[m_index][i]) + # fout.write('%f\t%f\n' % (mean(results[m_index]), std(results[m_index]))) + # fout.close() + + decay_epochs = [opt.epochs // 4, opt.epochs // 2, opt.epochs // 1.333] + + optimizer = torch.optim.SGD(model.parameters(), lr=opt.lr, momentum=0.9, weight_decay=5e-4) + scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=decay_epochs, gamma=0.1) + print(f"decay_epochs: {decay_epochs}") + + best_accs = {"valid": 0, "test": 0} + best_epochs = {"valid": 0, "test": 0} best_stats = {} start_time = time.time() for epoch in range(1, opt.epochs + 1): - logging.info(f'[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}') + print(f"[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}") loss = train(train_loader, model, criterion, optimizer) - logging.info(f'[{epoch} / {opt.epochs}] Loss: {loss}') + print(f"[{epoch} / {opt.epochs}] Loss: {loss}") scheduler.step() @@ -178,64 +181,29 @@ def main(): eye_tsr = train_loader.dataset.eye_tsr - stats[f'{key}/acc_unbiased'] = torch.mean(valid_attrwise_accs).item() * 100 - stats[f'{key}/diff'] = diff.item() * 100 - stats[f'{key}/bias_conflict'] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 - + stats[f"{key}/acc_unbiased"] = torch.mean(valid_attrwise_accs).item() * 100 + stats[f"{key}/diff"] = diff.item() * 100 + stats[f"{key}/bias_conflict"] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 - logging.info(f'[{epoch} / {opt.epochs}] {stats}') + print(f"[{epoch} / {opt.epochs}] {stats}") for tag in best_accs.keys(): - if stats[f'{tag}/acc_unbiased'] > best_accs[tag]: - best_accs[tag] = stats[f'{tag}/acc_unbiased'] + if stats[f"{tag}/acc_unbiased"] > best_accs[tag]: + best_accs[tag] = stats[f"{tag}/acc_unbiased"] best_epochs[tag] = epoch - best_stats[tag] = pretty_dict(**{f'best_{tag}_{k}': v for k, v in stats.items()}) + best_stats[tag] = pretty_dict(**{f"best_{tag}_{k}": v for k, v in stats.items()}) + + print( + f"[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}" + ) - save_file = save_path / "checkpoints" / f"best_{tag}_repeat{r+1}.pth" - save_model(model, optimizer, opt, epoch, save_file) + save_file = save_path / f"best_model.pt" + save_model(model, optimizer, opt, epoch, save_file) - logging.info( - f'[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}') - total_time = time.time() - start_time total_time_str = str(datetime.timedelta(seconds=int(total_time))) - logging.info(f'Total training time: {total_time_str}') - - save_file = save_path / "checkpoints" / f"last_repeat{r+1}.pth" - save_model(model, optimizer, opt, opt.epochs, save_file) - - # Evaluation - model.eval() - - with torch.no_grad(): - all_labels, all_biases, all_preds = [], [], [] - for images, labels, _, biases, _, _ in val_loaders['test']: - images = images.cuda() - output, _ = model(images) - preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() - - all_labels.append(labels) - all_biases.append(biases) - all_preds.append(preds) - - fin_labels = torch.cat(all_labels) - fin_biases = torch.cat(all_biases) - fin_preds = torch.cat(all_preds) - - ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) - print_all_metrics(ret=ret) - - ret['time per epoch'] = total_time / opt.epochs - print(ret['time per epoch']) - # for i in range(len(metric_index)): - # results[metric_index[i]].append(ret[metric_index[i]]) - - # for m_index in metric_index: - # fout.write(m_index + '\t') - # for i in range(repeat_time): - # fout.write('%f\t' % results[m_index][i]) - # fout.write('%f\t%f\n' % (mean(results[m_index]), std(results[m_index]))) - # fout.close() + print(f"Total training time: {total_time_str}") + print(f"Time per epoch: {total_time / opt.epochs:.6f}") -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/BM/train_cifar10/train_cifar10_us.py b/BM/train_cifar10/train_cifar10_us.py index b7932c1..ff7a7b0 100644 --- a/BM/train_cifar10/train_cifar10_us.py +++ b/BM/train_cifar10/train_cifar10_us.py @@ -1,56 +1,29 @@ -import argparse -import datetime -import logging import os +import sys import time -from pathlib import Path - -import numpy as np import torch -from torch import nn, optim +import logging +import datetime +import numpy as np +from torch import nn +from tqdm import tqdm +from pathlib import Path +from numpy import mean, std -import sys -sys.path.insert(1, './') +project_dir = "/root/DL-Fairness-Study" +sys.path.insert(1, os.path.join(project_dir, "BM")) +from debias.utils.logging import set_logging from debias.datasets.cifar10 import get_cifar10 from debias.networks.resnet_cifar import ResNet18 -from debias.utils.logging import set_logging -from debias.utils.utils import (AverageMeter, MultiDimAverageMeter, accuracy, - save_model, set_seed, pretty_dict) +from debias.utils.utils import AverageMeter, MultiDimAverageMeter, accuracy, save_model, set_seed, pretty_dict -from tqdm import tqdm - -sys.path.insert(1, '/root/study') +sys.path.insert(1, project_dir) -from numpy import mean, std +from arguments import get_args from metrics import get_metric_index, get_all_metrics, print_all_metrics -def parse_option(): - parser = argparse.ArgumentParser() - parser.add_argument('--exp_name', type=str, default='test', ) - parser.add_argument('--gpu', type=int, default=0) - - parser.add_argument('--print_freq', type=int, default=300, - help='print frequency') - parser.add_argument('--save_freq', type=int, default=200, - help='save frequency') - parser.add_argument('--epochs', type=int, default=200, - help='number of training epochs') - parser.add_argument('--seed', type=int, default=1) - - parser.add_argument('--bs', type=int, default=128, help='batch_size') - parser.add_argument('--lr', type=float, default=0.1) - parser.add_argument('--corr', type=float, default=0.95) - parser.add_argument('--rs', action="store_true") - - - opt = parser.parse_args() - os.environ["CUDA_VISIBLE_DEVICES"] = str(opt.gpu) - - return opt - - def set_model(): model = ResNet18(num_classes=10).cuda() criterion = nn.CrossEntropyLoss() @@ -95,82 +68,106 @@ def validate(val_loader, model): output, _ = model(images) preds = output.data.max(1, keepdim=True)[1].squeeze(1) - acc1, = accuracy(output, labels, topk=(1,)) + (acc1,) = accuracy(output, labels, topk=(1,)) top1.update(acc1[0], bsz) corrects = (preds == labels).long() attrwise_acc_meter.add(corrects.cpu(), torch.stack([labels.cpu(), biases.cpu()], dim=1)) - + return top1.avg, attrwise_acc_meter.get_mean(), attrwise_acc_meter.get_acc_diff() def main(): - opt = parse_option() - - exp_name = f'us-cifar10-{opt.exp_name}-lr{opt.lr}-bs{opt.bs}-seed{opt.seed}' - opt.exp_name = exp_name + opt = get_args() + exp_name = f"us-cifar10s-lr{opt.lr}-bs{opt.batch_size}-epochs{opt.epochs}-seed{opt.seed}" - result_dir = f'../results/cifar10s' - result_path = Path(result_dir) - result_path.mkdir(parents=True, exist_ok=True) - fout = open('/'.join([str(result_path), 'us.txt']), 'w') + # result_dir = f"../results/cifar10s" + # result_path = Path(result_dir) + # result_path.mkdir(parents=True, exist_ok=True) + # fout = open("/".join([str(result_path), "us.txt"]), "w") - results = {} - metric_index = get_metric_index() - for m_index in metric_index: - results[m_index] = [] + # results = {} + # metric_index = get_metric_index() + # for m_index in metric_index: + # results[m_index] = [] - repeat_time = 10 + repeat_time = 1 - output_dir = f'exp_results/{exp_name}' + output_dir = f"{project_dir}/checkpoints/{exp_name}" save_path = Path(output_dir) save_path.mkdir(parents=True, exist_ok=True) - set_logging(exp_name, 'INFO', str(save_path)) + print(f"Set seed: {opt.seed}") set_seed(opt.seed) - logging.info(f'save_path: {save_path}') + print(f"save_path: {save_path}") np.set_printoptions(precision=3) torch.set_printoptions(precision=3) - root = '../data/cifar10s' - train_loader = get_cifar10( - root, - split='train', - aug=False, - under_sample ='ce', - corr=opt.corr) + root = f"{project_dir}/data/cifar10s" + train_loader = get_cifar10(root, split="train", aug=False, under_sample="ce", corr=opt.skew_ratio) val_loaders = {} - val_loaders['valid'] = get_cifar10( + val_loaders["valid"] = get_cifar10( root, - split='valid', + split="valid", aug=False, ) - val_loaders['test'] = get_cifar10( - root, - split='test', - aug=False) + val_loaders["test"] = get_cifar10(root, split="test", aug=False) for r in range(repeat_time): - logging.info(f'Repeated experiment: {r+1}') + # print(f"Repeated experiment: {r+1}") model, criterion = set_model() - decay_epochs = [opt.epochs//4, opt.epochs//2, opt.epochs//1.333] + # Evaluation + if opt.checkpoint: + model.load_state_dict(torch.load(f"{save_path}/best_model.pt")["model"]) + model.eval() + + with torch.no_grad(): + all_labels, all_biases, all_preds = [], [], [] + for images, labels, _, biases, _, _ in val_loaders["test"]: + images = images.cuda() + output, _ = model(images) + preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() + + all_labels.append(labels) + all_biases.append(biases) + all_preds.append(preds) + + fin_labels = torch.cat(all_labels) + fin_biases = torch.cat(all_biases) + fin_preds = torch.cat(all_preds) + + ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) + print_all_metrics(ret=ret) + + sys.exit() - optimizer = optim.SGD(model.parameters(), lr=opt.lr, momentum =0.9, weight_decay=5e-4) - scheduler = optim.lr_scheduler.MultiStepLR(optimizer, milestones=decay_epochs, gamma=0.1) - logging.info(f"decay_epochs: {decay_epochs}") + # ret["time per epoch"] = total_time / opt.epochs + # for i in range(len(metric_index)): + # results[metric_index[i]].append(ret[metric_index[i]]) - (save_path / 'checkpoints').mkdir(parents=True, exist_ok=True) + # for m_index in metric_index: + # fout.write(m_index + "\t") + # for i in range(repeat_time): + # fout.write("%f\t" % results[m_index][i]) + # fout.write("%f\t%f\n" % (mean(results[m_index]), std(results[m_index]))) + # fout.close() - best_accs = {'valid': 0, 'test': 0} - best_epochs = {'valid': 0, 'test': 0} + decay_epochs = [opt.epochs // 4, opt.epochs // 2, opt.epochs // 1.333] + + optimizer = torch.optim.SGD(model.parameters(), lr=opt.lr, momentum=0.9, weight_decay=5e-4) + scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=decay_epochs, gamma=0.1) + print(f"decay_epochs: {decay_epochs}") + + best_accs = {"valid": 0, "test": 0} + best_epochs = {"valid": 0, "test": 0} best_stats = {} start_time = time.time() for epoch in range(1, opt.epochs + 1): - logging.info(f'[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}') + print(f"[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}") loss = train(train_loader, model, criterion, optimizer) scheduler.step() @@ -181,67 +178,33 @@ def main(): eye_tsr = train_loader.dataset.eye_tsr - stats[f'{key}/acc_unbiased'] = torch.mean(valid_attrwise_accs).item() * 100 - stats[f'{key}/diff'] = diff.item() * 100 - stats[f'{key}/bias_conflict'] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 - + stats[f"{key}/acc_unbiased"] = torch.mean(valid_attrwise_accs).item() * 100 + stats[f"{key}/diff"] = diff.item() * 100 + stats[f"{key}/bias_conflict"] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 - logging.info(f'[{epoch} / {opt.epochs}] {stats}') + print(f"[{epoch} / {opt.epochs}] {stats}") for tag in best_accs.keys(): - if stats[f'{tag}/acc_unbiased'] > best_accs[tag]: - best_accs[tag] = stats[f'{tag}/acc_unbiased'] + if stats[f"{tag}/acc_unbiased"] > best_accs[tag]: + best_accs[tag] = stats[f"{tag}/acc_unbiased"] best_epochs[tag] = epoch - best_stats[tag] = pretty_dict(**{f'best_{tag}_{k}': v for k, v in stats.items()}) + best_stats[tag] = pretty_dict(**{f"best_{tag}_{k}": v for k, v in stats.items()}) - save_file = save_path / "checkpoints" / f"best_{tag}_repeat{r+1}.pth" - save_model(model, optimizer, opt, epoch, save_file) + print( + f"[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}" + ) - logging.info( - f'[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}') - if opt.rs: train_loader.dataset.reset_data() - train_loader.dataset.under_sample_ce() + train_loader.dataset.under_sample_ce() + + save_file = save_path / "best_model.pt" + save_model(model, optimizer, opt, epoch, save_file) total_time = time.time() - start_time total_time_str = str(datetime.timedelta(seconds=int(total_time))) - logging.info(f'Total training time: {total_time_str}') - - save_file = save_path / "checkpoints" / f"last_repeat{r+1}.pth" - save_model(model, optimizer, opt, opt.epochs, save_file) - - # Evaluation - model.eval() - - with torch.no_grad(): - all_labels, all_biases, all_preds = [], [], [] - for images, labels, _, biases, _, _ in val_loaders['test']: - images = images.cuda() - output, _ = model(images) - preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() - - all_labels.append(labels) - all_biases.append(biases) - all_preds.append(preds) - - fin_labels = torch.cat(all_labels) - fin_biases = torch.cat(all_biases) - fin_preds = torch.cat(all_preds) - - ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) - print_all_metrics(ret=ret) - - ret['time per epoch'] = total_time / opt.epochs - for i in range(len(metric_index)): - results[metric_index[i]].append(ret[metric_index[i]]) - - for m_index in metric_index: - fout.write(m_index + '\t') - for i in range(repeat_time): - fout.write('%f\t' % results[m_index][i]) - fout.write('%f\t%f\n' % (mean(results[m_index]), std(results[m_index]))) - fout.close() + print(f"Total training time: {total_time_str}") + print(f"Time per epoch: {total_time / opt.epochs:.6f}") -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/BM/train_cifar10/train_cifar10_uw.py b/BM/train_cifar10/train_cifar10_uw.py index 567051a..2e4b916 100644 --- a/BM/train_cifar10/train_cifar10_uw.py +++ b/BM/train_cifar10/train_cifar10_uw.py @@ -1,57 +1,33 @@ -import argparse -import datetime -import logging import os +import sys import time -from pathlib import Path - -import numpy as np import torch -from torch import nn, optim +import logging +import argparse +import datetime +import numpy as np +from torch import nn +from tqdm import tqdm +from pathlib import Path +from numpy import mean, std -import sys -sys.path.insert(1, './') +project_dir = "/root/DL-Fairness-Study" +sys.path.insert(1, os.path.join(project_dir, "BM")) +from debias.utils.logging import set_logging from debias.datasets.cifar10 import get_cifar10 from debias.networks.resnet_cifar import ResNet18 -from debias.utils.logging import set_logging -from debias.utils.utils import (AverageMeter, MultiDimAverageMeter, accuracy, - save_model, set_seed, pretty_dict) +from debias.utils.utils import AverageMeter, MultiDimAverageMeter, accuracy, save_model, set_seed, pretty_dict -from tqdm import tqdm +sys.path.insert(1, project_dir) -sys.path.insert(1, '/root/study') - -from numpy import mean, std +from arguments import get_args from metrics import get_metric_index, get_all_metrics, print_all_metrics -def parse_option(): - parser = argparse.ArgumentParser() - parser.add_argument('--exp_name', type=str, default='test', ) - parser.add_argument('--gpu', type=int, default=0) - - parser.add_argument('--print_freq', type=int, default=300, - help='print frequency') - parser.add_argument('--save_freq', type=int, default=200, - help='save frequency') - parser.add_argument('--epochs', type=int, default=200, - help='number of training epochs') - parser.add_argument('--seed', type=int, default=1) - - parser.add_argument('--bs', type=int, default=128, help='batch_size') - parser.add_argument('--lr', type=float, default=0.1) - parser.add_argument('--corr', type=float, default=0.95) - - opt = parser.parse_args() - os.environ["CUDA_VISIBLE_DEVICES"] = str(opt.gpu) - - return opt - - def set_model(): model = ResNet18(num_classes=10).cuda() - criterion = nn.CrossEntropyLoss(reduction = 'none') + criterion = nn.CrossEntropyLoss(reduction="none") return model, criterion @@ -70,8 +46,8 @@ def train(train_loader, model, criterion, optimizer): logits, _ = model(images) loss = criterion(logits, labels) - loss *= gc - loss = torch.mean(loss) + loss *= gc + loss = torch.mean(loss) avg_loss.update(loss.item(), bsz) @@ -96,84 +72,104 @@ def validate(val_loader, model): output, _ = model(images) preds = output.data.max(1, keepdim=True)[1].squeeze(1) - acc1, = accuracy(output, labels, topk=(1,)) + (acc1,) = accuracy(output, labels, topk=(1,)) top1.update(acc1[0], bsz) corrects = (preds == labels).long() attrwise_acc_meter.add(corrects.cpu(), torch.stack([labels.cpu(), biases.cpu()], dim=1)) - + return top1.avg, attrwise_acc_meter.get_mean(), attrwise_acc_meter.get_acc_diff() def main(): - opt = parse_option() - - exp_name = f'uw-cifar10-{opt.exp_name}-lr{opt.lr}-bs{opt.bs}-seed{opt.seed}' - opt.exp_name = exp_name + opt = get_args() + exp_name = f"uw-cifar10s-lr{opt.lr}-bs{opt.batch_size}-epochs{opt.epochs}-seed{opt.seed}" - result_dir = f'../results/cifar10s' - result_path = Path(result_dir) - result_path.mkdir(parents=True, exist_ok=True) - fout = open('/'.join([str(result_path), 'uw.txt']), 'w') + # result_dir = f"../results/cifar10s" + # result_path = Path(result_dir) + # result_path.mkdir(parents=True, exist_ok=True) + # fout = open("/".join([str(result_path), "uw.txt"]), "w") - results = {} - metric_index = get_metric_index() - for m_index in metric_index: - results[m_index] = [] + # results = {} + # metric_index = get_metric_index() + # for m_index in metric_index: + # results[m_index] = [] - repeat_time = 10 + repeat_time = 1 - output_dir = f'exp_results/{exp_name}' + output_dir = f"{project_dir}/checkpoints/{exp_name}" save_path = Path(output_dir) save_path.mkdir(parents=True, exist_ok=True) - set_logging(exp_name, 'INFO', str(save_path)) + print(f"Set seed: {opt.seed}") set_seed(opt.seed) - logging.info(f'save_path: {save_path}') + print(f"save_path: {save_path}") np.set_printoptions(precision=3) torch.set_printoptions(precision=3) - root = '../data/cifar10s' - train_loader = get_cifar10( - root, - split='train', - aug=False, - corr=opt.corr) + root = f"{project_dir}/data/cifar10s" + train_loader = get_cifar10(root, split="train", aug=False, corr=opt.skew_ratio) val_loaders = {} - val_loaders['valid'] = get_cifar10( - root, - split='valid', - aug=False, - corr=opt.corr - ) - val_loaders['test'] = get_cifar10( - root, - split='test', - aug=False) + val_loaders["valid"] = get_cifar10(root, split="valid", aug=False, corr=opt.skew_ratio) + val_loaders["test"] = get_cifar10(root, split="test", aug=False) for r in range(repeat_time): - logging.info(f'Repeated experiment: {r+1}') + # print(f"Repeated experiment: {r+1}") model, criterion = set_model() - decay_epochs = [opt.epochs//4, opt.epochs//2, opt.epochs//1.333] + # Evaluation + if opt.checkpoint: + model.load_state_dict(torch.load(f"{save_path}/best_model.pt")["model"]) + model.eval() + + with torch.no_grad(): + all_labels, all_biases, all_preds = [], [], [] + for images, labels, _, biases, _, _ in val_loaders["test"]: + images = images.cuda() + output, _ = model(images) + preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() + + all_labels.append(labels) + all_biases.append(biases) + all_preds.append(preds) + + fin_labels = torch.cat(all_labels) + fin_biases = torch.cat(all_biases) + fin_preds = torch.cat(all_preds) + + ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) + print_all_metrics(ret=ret) + + sys.exit() - optimizer = optim.SGD(model.parameters(), lr=opt.lr, momentum = 0.9, weight_decay=5e-4) - scheduler = optim.lr_scheduler.MultiStepLR(optimizer, milestones=decay_epochs, gamma=0.1) - logging.info(f"decay_epochs: {decay_epochs}") + # ret["time per epoch"] = total_time / opt.epochs + # for i in range(len(metric_index)): + # results[metric_index[i]].append(ret[metric_index[i]]) - (save_path / 'checkpoints').mkdir(parents=True, exist_ok=True) + # for m_index in metric_index: + # fout.write(m_index + "\t") + # for i in range(repeat_time): + # fout.write("%f\t" % results[m_index][i]) + # fout.write("%f\t%f\n" % (mean(results[m_index]), std(results[m_index]))) + # fout.close() - best_accs = {'valid': 0, 'test': 0} - best_epochs = {'valid': 0, 'test': 0} + decay_epochs = [opt.epochs // 4, opt.epochs // 2, opt.epochs // 1.333] + + optimizer = torch.optim.SGD(model.parameters(), lr=opt.lr, momentum=0.9, weight_decay=5e-4) + scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=decay_epochs, gamma=0.1) + print(f"decay_epochs: {decay_epochs}") + + best_accs = {"valid": 0, "test": 0} + best_epochs = {"valid": 0, "test": 0} best_stats = {} start_time = time.time() for epoch in range(1, opt.epochs + 1): - logging.info(f'[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}') + print(f"[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}") loss = train(train_loader, model, criterion, optimizer) - logging.info(f'[{epoch} / {opt.epochs}] Loss: {loss}') + print(f"[{epoch} / {opt.epochs}] Loss: {loss}") scheduler.step() @@ -183,63 +179,29 @@ def main(): eye_tsr = train_loader.dataset.eye_tsr - stats[f'{key}/acc_unbiased'] = torch.mean(valid_attrwise_accs).item() * 100 - stats[f'{key}/diff'] = diff.item() * 100 - stats[f'{key}/bias_conflict'] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 - + stats[f"{key}/acc_unbiased"] = torch.mean(valid_attrwise_accs).item() * 100 + stats[f"{key}/diff"] = diff.item() * 100 + stats[f"{key}/bias_conflict"] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 - logging.info(f'[{epoch} / {opt.epochs}] {stats}') + print(f"[{epoch} / {opt.epochs}] {stats}") for tag in best_accs.keys(): - if stats[f'{tag}/acc_unbiased'] > best_accs[tag]: - best_accs[tag] = stats[f'{tag}/acc_unbiased'] + if stats[f"{tag}/acc_unbiased"] > best_accs[tag]: + best_accs[tag] = stats[f"{tag}/acc_unbiased"] best_epochs[tag] = epoch - best_stats[tag] = pretty_dict(**{f'best_{tag}_{k}': v for k, v in stats.items()}) + best_stats[tag] = pretty_dict(**{f"best_{tag}_{k}": v for k, v in stats.items()}) - save_file = save_path / "checkpoints" / f"best_{tag}_repeat{r+1}.pth" - save_model(model, optimizer, opt, epoch, save_file) + print( + f"[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}" + ) - logging.info( - f'[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}') + save_file = save_path / "best_model.pt" + save_model(model, optimizer, opt, epoch, save_file) total_time = time.time() - start_time total_time_str = str(datetime.timedelta(seconds=int(total_time))) - logging.info(f'Total training time: {total_time_str}') - - save_file = save_path / "checkpoints" / f"last_repeat{r+1}.pth" - save_model(model, optimizer, opt, opt.epochs, save_file) - - # Evaluation - model.eval() - - with torch.no_grad(): - all_labels, all_biases, all_preds = [], [], [] - for images, labels, _, biases, _, _ in val_loaders['test']: - images = images.cuda() - output, _ = model(images) - preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() - - all_labels.append(labels) - all_biases.append(biases) - all_preds.append(preds) - - fin_labels = torch.cat(all_labels) - fin_biases = torch.cat(all_biases) - fin_preds = torch.cat(all_preds) - - ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) - print_all_metrics(ret=ret) - - ret['time per epoch'] = total_time / opt.epochs - for i in range(len(metric_index)): - results[metric_index[i]].append(ret[metric_index[i]]) - - for m_index in metric_index: - fout.write(m_index + '\t') - for i in range(repeat_time): - fout.write('%f\t' % results[m_index][i]) - fout.write('%f\t%f\n' % (mean(results[m_index]), std(results[m_index]))) - fout.close() + print(f"Total training time: {total_time_str}") + print(f"Time per epoch: {total_time / opt.epochs:.6f}") -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/BM/train_utk_face/train_utk_face_adv.py b/BM/train_utk_face/train_utk_face_adv.py index af29ea9..f51ab57 100644 --- a/BM/train_utk_face/train_utk_face_adv.py +++ b/BM/train_utk_face/train_utk_face_adv.py @@ -1,56 +1,36 @@ -import argparse -import datetime -import logging +import os +import sys import time -from pathlib import Path - -import numpy as np import torch -from torch import nn +import logging +import datetime +import numpy as np import torch.nn.functional as F + +from torch import nn from tqdm import tqdm +from pathlib import Path +from numpy import mean, std -import sys -sys.path.insert(1, './') +project_dir = "/root/DL-Fairness-Study" +sys.path.insert(1, os.path.join(project_dir, "BM")) +from debias.utils.logging import set_logging from debias.datasets.utk_face import get_utk_face from debias.networks.resnet import FCResNet18_Base -from debias.utils.logging import set_logging -from debias.utils.utils import (AverageMeter, MultiDimAverageMeter, accuracy, - pretty_dict, save_model, set_seed) +from debias.utils.utils import AverageMeter, MultiDimAverageMeter, accuracy, pretty_dict, save_model, set_seed -import os -sys.path.insert(1, '/root/study') +sys.path.insert(1, project_dir) -from numpy import mean, std +from arguments import get_args from metrics import get_metric_index, get_all_metrics, print_all_metrics -def parse_option(): - parser = argparse.ArgumentParser() - parser.add_argument('--exp_name', type=str, default='test') - parser.add_argument('--gpu', type=int, default=0) - parser.add_argument('--task', type=str, default='race') - - parser.add_argument('--epochs', type=int, default=40) - parser.add_argument('--seed', type=int, default=1) - - parser.add_argument('--bs', type=int, default=128, help='batch_size') - parser.add_argument('--lr', type=float, default=1e-3) - parser.add_argument('--training_ratio', type=float, default=3) - parser.add_argument('--alpha', type=float, default=1) - - opt = parser.parse_args() - os.environ['CUDA_VISIBLE_DEVICES'] = str(opt.gpu) - - return opt - - def set_model(): model = FCResNet18_Base().cuda() class_criterion = nn.CrossEntropyLoss() domain_criterion = nn.CrossEntropyLoss() - + class_network = nn.Linear(512, 2).cuda() domain_network = nn.Linear(512, 2).cuda() @@ -66,27 +46,27 @@ def train(train_loader, model, criterion, optimizer, epoch, opt): for images, labels, _, biases, _, _ in tqdm(train_iter, ascii=True): bsz = labels.shape[0] labels, biases = labels.cuda(), biases.cuda() - + optimizer[0].zero_grad() optimizer[1].zero_grad() optimizer[2].zero_grad() - + images = images.cuda() features = model[0](images) class_out = model[1](features) domain_out = model[2](features) class_loss = criterion[0](class_out, labels) - domain_loss = criterion[1](domain_out, biases) + domain_loss = criterion[1](domain_out, biases) if epoch % opt.training_ratio == 0: log_softmax = F.log_softmax(domain_out, dim=1) confusion_loss = -log_softmax.mean(dim=1).mean() - loss = class_loss + opt.alpha*confusion_loss + loss = class_loss + opt.alpha * confusion_loss loss.backward() optimizer[0].step() optimizer[1].step() - + else: # Update the domain classifier domain_loss.backward() @@ -113,76 +93,105 @@ def validate(val_loader, model): preds = output.data.max(1, keepdim=True)[1].squeeze(1) - acc1, = accuracy(output, labels, topk=(1,)) + (acc1,) = accuracy(output, labels, topk=(1,)) top1.update(acc1[0], bsz) corrects = (preds == labels).long() attrwise_acc_meter.add(corrects.cpu(), torch.stack([labels.cpu(), biases.cpu()], dim=1)) - return top1.avg, attrwise_acc_meter.get_mean(), attrwise_acc_meter.get_acc_diff() + return top1.avg, attrwise_acc_meter.get_mean(), attrwise_acc_meter.get_acc_diff() def main(): - opt = parse_option() + opt = get_args() + exp_name = f"adv-utkface_{opt.sensitive}-lr{opt.lr}-bs{opt.batch_size}-epochs{opt.epochs}-seed{opt.seed}" - exp_name = f'adv-utk_face_{opt.task}-{opt.exp_name}-lr{opt.lr}-bs{opt.bs}-seed{opt.seed}' - opt.exp_name = exp_name + # result_dir = f"../results/utkface" + # result_path = Path(result_dir) + # result_path.mkdir(parents=True, exist_ok=True) + # if opt.sensitive == "age": + # fout = open("/".join([str(result_path), f"adv_age_gender.txt"]), "w") + # elif opt.sensitive == "race": + # fout = open("/".join([str(result_path), f"adv_race_gender.txt"]), "w") - result_dir = f'../results/utkface' - result_path = Path(result_dir) - result_path.mkdir(parents=True, exist_ok=True) - if opt.task == 'age': - fout = open('/'.join([str(result_path), f'adv_age_gender.txt']), 'w') - elif opt.task == 'race': - fout = open('/'.join([str(result_path), f'adv_race_gender.txt']), 'w') + # results = {} + # metric_index = get_metric_index() + # for m_index in metric_index: + # results[m_index] = [] - results = {} - metric_index = get_metric_index() - for m_index in metric_index: - results[m_index] = [] + repeat_time = 1 - repeat_time = 10 - - output_dir = f'exp_results/{exp_name}' + output_dir = f"{project_dir}/checkpoints/{exp_name}" save_path = Path(output_dir) save_path.mkdir(parents=True, exist_ok=True) - set_logging(exp_name, 'INFO', str(save_path)) - logging.info(f'Set seed: {opt.seed}') + print(f"Set seed: {opt.seed}") set_seed(opt.seed) - logging.info(f'save_path: {save_path}') + print(f"save_path: {save_path}") np.set_printoptions(precision=3) torch.set_printoptions(precision=3) - root = '../data/utkface' + root = f"{project_dir}/data/utkface" train_loader = get_utk_face( root, - batch_size=opt.bs, - bias_attr=opt.task, - split='train', - aug=False, ) + batch_size=opt.batch_size, + bias_attr=opt.sensitive, + split="train", + aug=False, + ) val_loaders = {} - val_loaders['valid'] = get_utk_face( - root, - batch_size=256, - bias_attr=opt.task, - split='valid', - aug=False) + val_loaders["valid"] = get_utk_face(root, batch_size=256, bias_attr=opt.sensitive, split="valid", aug=False) - val_loaders['test'] = get_utk_face( - root, - batch_size=256, - bias_attr=opt.task, - split='test', - aug=False) + val_loaders["test"] = get_utk_face(root, batch_size=256, bias_attr=opt.sensitive, split="test", aug=False) for r in range(repeat_time): - logging.info(f'Repeated experiment: {r+1}') + # print(f"Repeated experiment: {r+1}") model, criterion = set_model() + # Evaluation + if opt.checkpoint: + model[0].load_state_dict(torch.load(f"{save_path}/best_model.pt")["model"]) + model[0].eval() + model[1].load_state_dict(torch.load(f"{save_path}/best_pred.pt")["model"]) + model[1].eval() + + with torch.no_grad(): + all_labels, all_biases, all_preds = [], [], [] + for images, labels, _, biases, _, _ in val_loaders["test"]: + images = images.cuda() + + feats = model[0](images) + output = model[1](feats) + + preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() + + all_labels.append(labels) + all_biases.append(biases) + all_preds.append(preds) + + fin_labels = torch.cat(all_labels) + fin_biases = torch.cat(all_biases) + fin_preds = torch.cat(all_preds) + + ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) + print_all_metrics(ret=ret) + + sys.exit() + + # ret["time per epoch"] = total_time / opt.epochs + # for i in range(len(metric_index)): + # results[metric_index[i]].append(ret[metric_index[i]]) + + # for m_index in metric_index: + # fout.write(m_index + "\t") + # for i in range(repeat_time): + # fout.write("%f\t" % results[m_index][i]) + # fout.write("%f\t%f\n" % (mean(results[m_index]), std(results[m_index]))) + # fout.close() + decay_epochs = [opt.epochs // 3, opt.epochs * 2 // 3] optimizer_base = torch.optim.Adam(model[0].parameters(), lr=opt.lr, weight_decay=1e-4) @@ -193,20 +202,18 @@ def main(): scheduler_base = torch.optim.lr_scheduler.MultiStepLR(optimizers[0], milestones=decay_epochs, gamma=0.1) scheduler_class = torch.optim.lr_scheduler.MultiStepLR(optimizers[1], milestones=decay_epochs, gamma=0.1) scheduler_domain = torch.optim.lr_scheduler.MultiStepLR(optimizers[2], milestones=decay_epochs, gamma=0.1) - schedulers = [scheduler_base,scheduler_class, scheduler_domain] + schedulers = [scheduler_base, scheduler_class, scheduler_domain] - logging.info(f'decay_epochs: {decay_epochs}') + print(f"decay_epochs: {decay_epochs}") - # (save_path / 'checkpoints').mkdir(parents=True, exist_ok=True) - - best_accs = {'valid': 0, 'test': 0} - best_epochs = {'valid': 0, 'test': 0} + best_accs = {"valid": 0, "test": 0} + best_epochs = {"valid": 0, "test": 0} best_stats = {} start_time = time.time() for epoch in range(1, opt.epochs + 1): - logging.info(f'[{epoch} / {opt.epochs}] Learning rate: {schedulers[0].get_last_lr()[0]}') + print(f"[{epoch} / {opt.epochs}] Learning rate: {schedulers[0].get_last_lr()[0]}") loss = train(train_loader, model, criterion, optimizers, epoch, opt) - logging.info(f'[{epoch} / {opt.epochs}] Loss: {loss:.4f}') + print(f"[{epoch} / {opt.epochs}] Loss: {loss:.4f}") schedulers[0].step() schedulers[1].step() @@ -216,64 +223,36 @@ def main(): for key, val_loader in val_loaders.items(): accs, valid_attrwise_accs, diff = validate(val_loader, model) - stats[f'{key}/acc'] = accs.item() - stats[f'{key}/acc_unbiased'] = torch.mean(valid_attrwise_accs).item() * 100 - stats[f'{key}/diff'] = diff.item() * 100 + stats[f"{key}/acc"] = accs.item() + stats[f"{key}/acc_unbiased"] = torch.mean(valid_attrwise_accs).item() * 100 + stats[f"{key}/diff"] = diff.item() * 100 eye_tsr = train_loader.dataset.eye_tsr - stats[f'{key}/acc_skew'] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 - stats[f'{key}/acc_align'] = valid_attrwise_accs[eye_tsr == 0.0].mean().item() * 100 + stats[f"{key}/acc_skew"] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 + stats[f"{key}/acc_align"] = valid_attrwise_accs[eye_tsr == 0.0].mean().item() * 100 - logging.info(f'[{epoch} / {opt.epochs}] {valid_attrwise_accs} {stats}') + print(f"[{epoch} / {opt.epochs}] {valid_attrwise_accs} {stats}") for tag in val_loaders.keys(): - if stats[f'{tag}/acc_unbiased'] > best_accs[tag]: - best_accs[tag] = stats[f'{tag}/acc_unbiased'] + if stats[f"{tag}/acc_unbiased"] > best_accs[tag]: + best_accs[tag] = stats[f"{tag}/acc_unbiased"] best_epochs[tag] = epoch - best_stats[tag] = pretty_dict(**{f'best_{tag}_{k}': v for k, v in stats.items()}) + best_stats[tag] = pretty_dict(**{f"best_{tag}_{k}": v for k, v in stats.items()}) + + print( + f"[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}" + ) - logging.info( - f'[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}') + save_file_base = save_path / "best_model.pt" + save_model(model[0], optimizer_base, opt, epoch, save_file_base) + save_file_class = save_path / "best_pred.pt" + save_model(model[1], optimizer_class, opt, epoch, save_file_class) total_time = time.time() - start_time total_time_str = str(datetime.timedelta(seconds=int(total_time))) - logging.info(f'Total training time: {total_time_str}') - - # Evaluation - model[0].eval() - - with torch.no_grad(): - all_labels, all_biases, all_preds = [], [], [] - for images, labels, _, biases, _, _ in val_loaders['test']: - images = images.cuda() - - feats = model[0](images) - output = model[1](feats) - - preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() - - all_labels.append(labels) - all_biases.append(biases) - all_preds.append(preds) - - fin_labels = torch.cat(all_labels) - fin_biases = torch.cat(all_biases) - fin_preds = torch.cat(all_preds) - - ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) - print_all_metrics(ret=ret) - - ret['time per epoch'] = total_time / opt.epochs - for i in range(len(metric_index)): - results[metric_index[i]].append(ret[metric_index[i]]) - - for m_index in metric_index: - fout.write(m_index + '\t') - for i in range(repeat_time): - fout.write('%f\t' % results[m_index][i]) - fout.write('%f\t%f\n' % (mean(results[m_index]), std(results[m_index]))) - fout.close() + print(f"Total training time: {total_time_str}") + print(f"Time per epoch: {total_time / opt.epochs:.6f}") -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/BM/train_utk_face/train_utk_face_bc.py b/BM/train_utk_face/train_utk_face_bc.py index 7ad2e56..698643e 100644 --- a/BM/train_utk_face/train_utk_face_bc.py +++ b/BM/train_utk_face/train_utk_face_bc.py @@ -1,61 +1,34 @@ -import argparse -import datetime -import logging import os +import sys import time -from pathlib import Path - -import numpy as np import torch +import logging +import argparse +import datetime +import numpy as np from torch import nn from tqdm import tqdm +from pathlib import Path +from numpy import mean, std -import sys -sys.path.insert(1, './') +project_dir = "/root/DL-Fairness-Study" +sys.path.insert(1, os.path.join(project_dir, "BM")) +from debias.utils.logging import set_logging +from debias.networks.resnet import FCResNet18 from debias.datasets.utk_face import get_utk_face from debias.losses.bias_contrastive import BiasContrastiveLoss -from debias.networks.resnet import FCResNet18 -from debias.utils.logging import set_logging -from debias.utils.utils import (AverageMeter, MultiDimAverageMeter, accuracy, - pretty_dict, save_model, set_seed) +from debias.utils.utils import AverageMeter, MultiDimAverageMeter, accuracy, pretty_dict, save_model, set_seed -sys.path.insert(1, '/root/study') +sys.path.insert(1, project_dir) -from numpy import mean, std +from arguments import get_args from metrics import get_metric_index, get_all_metrics, print_all_metrics -def parse_option(): - parser = argparse.ArgumentParser() - parser.add_argument('--exp_name', type=str, default='test') - parser.add_argument('--gpu', type=int, default=0) - parser.add_argument('--task', type=str, default='race') - - parser.add_argument('--epochs', type=int, default=20) - parser.add_argument('--seed', type=int, default=1) - - parser.add_argument('--bs', type=int, default=128, help='batch_size') - parser.add_argument('--cbs', type=int, default=64, help='batch_size of dataloader for contrastive loss') - parser.add_argument('--lr', type=float, default=1e-3) - - # hyperparameters - parser.add_argument('--weight', type=float, default=0.01) - parser.add_argument('--ratio', type=int, default=10) - parser.add_argument('--aug', type=int, default=1) - parser.add_argument('--bb', type=int, default=0) - - opt = parser.parse_args() - os.environ['CUDA_VISIBLE_DEVICES'] = str(opt.gpu) - - return opt - - def set_model(train_loader, opt): model = FCResNet18().cuda() - criterion = BiasContrastiveLoss( - confusion_matrix=train_loader.dataset.confusion_matrix, - bb=opt.bb) + criterion = BiasContrastiveLoss(confusion_matrix=train_loader.dataset.confusion_matrix, bb=opt.bb) return model, criterion @@ -70,10 +43,10 @@ def train(train_loader, cont_train_loader, model, criterion, optimizer, epoch, o cont_train_iter = iter(cont_train_loader) for images, labels, _, biases, _, _ in tqdm(train_iter, ascii=True): try: - cont_images, cont_labels, _, cont_biases, _ , _ = next(cont_train_iter) + cont_images, cont_labels, _, cont_biases, _, _ = next(cont_train_iter) except: cont_train_iter = iter(cont_train_loader) - cont_images, cont_labels, _, cont_biases, _ , _ = next(cont_train_iter) + cont_images, cont_labels, _, cont_biases, _, _ = next(cont_train_iter) bsz = labels.shape[0] cont_bsz = cont_labels.shape[0] @@ -119,104 +92,121 @@ def validate(val_loader, model): output, _ = model(images) preds = output.data.max(1, keepdim=True)[1].squeeze(1) - acc1, = accuracy(output, labels, topk=(1,)) + (acc1,) = accuracy(output, labels, topk=(1,)) top1.update(acc1[0], bsz) corrects = (preds == labels).long() attrwise_acc_meter.add(corrects.cpu(), torch.stack([labels.cpu(), biases.cpu()], dim=1)) - return top1.avg, attrwise_acc_meter.get_mean(), attrwise_acc_meter.get_acc_diff() + return top1.avg, attrwise_acc_meter.get_mean(), attrwise_acc_meter.get_acc_diff() def main(): - opt = parse_option() - - exp_name = f'bc-bb{opt.bb}-utk_face_{opt.task}-{opt.exp_name}-lr{opt.lr}-bs{opt.bs}-cbs{opt.cbs}-w{opt.weight}-ratio{opt.ratio}-aug{opt.aug}-seed{opt.seed}' - opt.exp_name = exp_name + opt = get_args() + exp_name = f"bc-bb{opt.bb}-utkface_{opt.sensitive}-lr{opt.lr}-bs{opt.batch_size}-cbs{opt.cbs}-epochs{opt.epochs}-w{opt.weight}-ratio{opt.ratio}-aug{opt.aug}-seed{opt.seed}" - result_dir = f'../results/utkface' - result_path = Path(result_dir) - result_path.mkdir(parents=True, exist_ok=True) - if opt.task == 'age': - fout = open('/'.join([str(result_path), 'bc_bb_age_gender.txt']), 'w') - elif opt.task == 'race': - fout = open('/'.join([str(result_path), 'bc_bb_race_gender.txt']), 'w') + # result_dir = f"../results/utkface" + # result_path = Path(result_dir) + # result_path.mkdir(parents=True, exist_ok=True) + # if opt.sensitive == "age": + # fout = open("/".join([str(result_path), "bc_bb_age_gender.txt"]), "w") + # elif opt.sensitive == "race": + # fout = open("/".join([str(result_path), "bc_bb_race_gender.txt"]), "w") - results = {} - metric_index = get_metric_index() - for m_index in metric_index: - results[m_index] = [] + # results = {} + # metric_index = get_metric_index() + # for m_index in metric_index: + # results[m_index] = [] - repeat_time = 10 + repeat_time = 1 - output_dir = f'exp_results/{exp_name}' + output_dir = f"{project_dir}/checkpoints/{exp_name}" save_path = Path(output_dir) save_path.mkdir(parents=True, exist_ok=True) - set_logging(exp_name, 'INFO', str(save_path)) - logging.info(f'Set seed: {opt.seed}') + print(f"Set seed: {opt.seed}") set_seed(opt.seed) - logging.info(f'save_path: {save_path}') + print(f"save_path: {save_path}") np.set_printoptions(precision=3) torch.set_printoptions(precision=3) - root = '../data/utkface' + root = f"{project_dir}/data/utkface" train_loader = get_utk_face( root, - batch_size=opt.bs, - bias_attr=opt.task, - split='train', - aug=False, ) - logging.info( - f'confusion_matrix - \n original: {train_loader.dataset.confusion_matrix_org}, \n normalized: {train_loader.dataset.confusion_matrix}, \n b|y: {train_loader.dataset.confusion_matrix_by}') + batch_size=opt.batch_size, + bias_attr=opt.sensitive, + split="train", + aug=False, + ) + print( + f"confusion_matrix - \n original: {train_loader.dataset.confusion_matrix_org}, \n normalized: {train_loader.dataset.confusion_matrix}, \n b|y: {train_loader.dataset.confusion_matrix_by}" + ) cont_train_loader = get_utk_face( - root, - batch_size=opt.cbs, - bias_attr=opt.task, - split='train', - aug=opt.aug, - two_crop=True, - ratio=opt.ratio, - given_y=True) + root, batch_size=opt.cbs, bias_attr=opt.sensitive, split="train", aug=opt.aug, two_crop=True, ratio=opt.ratio, given_y=True + ) val_loaders = {} - val_loaders['valid'] = get_utk_face( - root, - batch_size=256, - bias_attr=opt.task, - split='valid', - aug=False) + val_loaders["valid"] = get_utk_face(root, batch_size=256, bias_attr=opt.sensitive, split="valid", aug=False) - val_loaders['test'] = get_utk_face( - root, - batch_size=256, - bias_attr=opt.task, - split='test', - aug=False) + val_loaders["test"] = get_utk_face(root, batch_size=256, bias_attr=opt.sensitive, split="test", aug=False) for r in range(repeat_time): - logging.info(f'Repeated experiment: {r+1}') + # print(f"Repeated experiment: {r+1}") model, criterion = set_model(train_loader, opt) + # Evaluation + if opt.checkpoint: + model.load_state_dict(torch.load(f"{save_path}/best_model.pt")["model"]) + model.eval() + + with torch.no_grad(): + all_labels, all_biases, all_preds = [], [], [] + for images, labels, _, biases, _, _ in val_loaders["test"]: + images = images.cuda() + output, _ = model(images) + preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() + + all_labels.append(labels) + all_biases.append(biases) + all_preds.append(preds) + + fin_labels = torch.cat(all_labels) + fin_biases = torch.cat(all_biases) + fin_preds = torch.cat(all_preds) + + ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) + print_all_metrics(ret=ret) + + sys.exit() + + # ret["time per epoch"] = total_time / opt.epochs + # for i in range(len(metric_index)): + # results[metric_index[i]].append(ret[metric_index[i]]) + + # for m_index in metric_index: + # fout.write(m_index + "\t") + # for i in range(repeat_time): + # fout.write("%f\t" % results[m_index][i]) + # fout.write("%f\t%f\n" % (mean(results[m_index]), std(results[m_index]))) + # fout.close() + decay_epochs = [opt.epochs // 3, opt.epochs * 2 // 3] optimizer = torch.optim.Adam(model.parameters(), lr=opt.lr, weight_decay=1e-4) scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=decay_epochs, gamma=0.1) - logging.info(f'decay_epochs: {decay_epochs}') - - # (save_path / 'checkpoints').mkdir(parents=True, exist_ok=True) + print(f"decay_epochs: {decay_epochs}") - best_accs = {'valid': 0, 'test': 0} - best_epochs = {'valid': 0, 'test': 0} + best_accs = {"valid": 0, "test": 0} + best_epochs = {"valid": 0, "test": 0} best_stats = {} start_time = time.time() for epoch in range(1, opt.epochs + 1): - logging.info(f'[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]} weight: {opt.weight}') + print(f"[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]} weight: {opt.weight}") ce_loss, con_loss, loss = train(train_loader, cont_train_loader, model, criterion, optimizer, epoch, opt) - logging.info(f'[{epoch} / {opt.epochs}] Loss: {loss} CE Loss: {ce_loss} Con Loss: {con_loss}') + print(f"[{epoch} / {opt.epochs}] Loss: {loss} CE Loss: {ce_loss} Con Loss: {con_loss}") scheduler.step() @@ -224,61 +214,34 @@ def main(): for key, val_loader in val_loaders.items(): accs, valid_attrwise_accs, diff = validate(val_loader, model) - stats[f'{key}/acc'] = accs.item() - stats[f'{key}/acc_unbiased'] = torch.mean(valid_attrwise_accs).item() * 100 - stats[f'{key}/diff'] = diff.item()*100 + stats[f"{key}/acc"] = accs.item() + stats[f"{key}/acc_unbiased"] = torch.mean(valid_attrwise_accs).item() * 100 + stats[f"{key}/diff"] = diff.item() * 100 eye_tsr = train_loader.dataset.eye_tsr - stats[f'{key}/acc_skew'] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 - stats[f'{key}/acc_align'] = valid_attrwise_accs[eye_tsr == 0.0].mean().item() * 100 + stats[f"{key}/acc_skew"] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 + stats[f"{key}/acc_align"] = valid_attrwise_accs[eye_tsr == 0.0].mean().item() * 100 - logging.info(f'[{epoch} / {opt.epochs}] {valid_attrwise_accs} {stats}') + print(f"[{epoch} / {opt.epochs}] {valid_attrwise_accs} {stats}") for tag in val_loaders.keys(): - if stats[f'{tag}/acc_unbiased'] > best_accs[tag]: - best_accs[tag] = stats[f'{tag}/acc_unbiased'] + if stats[f"{tag}/acc_unbiased"] > best_accs[tag]: + best_accs[tag] = stats[f"{tag}/acc_unbiased"] best_epochs[tag] = epoch - best_stats[tag] = pretty_dict(**{f'best_{tag}_{k}': v for k, v in stats.items()}) + best_stats[tag] = pretty_dict(**{f"best_{tag}_{k}": v for k, v in stats.items()}) - logging.info( - f'[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}') + print( + f"[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}" + ) + + save_file = save_path / f"best_model.pt" + save_model(model, optimizer, opt, epoch, save_file) total_time = time.time() - start_time total_time_str = str(datetime.timedelta(seconds=int(total_time))) - logging.info(f'Total training time: {total_time_str}') - - # Evaluation - model.eval() - - with torch.no_grad(): - all_labels, all_biases, all_preds = [], [], [] - for images, labels, _, biases, _, _ in val_loaders['test']: - images = images.cuda() - output, _ = model(images) - preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() - - all_labels.append(labels) - all_biases.append(biases) - all_preds.append(preds) - - fin_labels = torch.cat(all_labels) - fin_biases = torch.cat(all_biases) - fin_preds = torch.cat(all_preds) - - ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) - print_all_metrics(ret=ret) - - ret['time per epoch'] = total_time / opt.epochs - for i in range(len(metric_index)): - results[metric_index[i]].append(ret[metric_index[i]]) - - for m_index in metric_index: - fout.write(m_index + '\t') - for i in range(repeat_time): - fout.write('%f\t' % results[m_index][i]) - fout.write('%f\t%f\n' % (mean(results[m_index]), std(results[m_index]))) - fout.close() + print(f"Total training time: {total_time_str}") + print(f"Time per epoch: {total_time / opt.epochs:.6f}") -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/BM/train_utk_face/train_utk_face_bm.py b/BM/train_utk_face/train_utk_face_bm.py index 405c7aa..b20229c 100644 --- a/BM/train_utk_face/train_utk_face_bm.py +++ b/BM/train_utk_face/train_utk_face_bm.py @@ -1,98 +1,71 @@ -import argparse -import datetime -import logging +import os +import sys import time -from pathlib import Path - -import numpy as np import torch +import logging +import datetime +import numpy as np from torch import nn +from tqdm import tqdm +from pathlib import Path +from numpy import mean, std -import sys -sys.path.insert(1, './') +project_dir = "/root/DL-Fairness-Study" +sys.path.insert(1, os.path.join(project_dir, "BM")) -from debias.datasets.utk_face import get_utk_face -from debias.networks.resnet import FCResNet18 from debias.utils.logging import set_logging -from debias.utils.utils import (AverageMeter, MultiDimAverageMeter, accuracy, - pretty_dict, save_model, set_seed) +from debias.networks.resnet import FCResNet18 +from debias.datasets.utk_face import get_utk_face +from debias.utils.utils import AverageMeter, MultiDimAverageMeter, accuracy, pretty_dict, save_model, set_seed from debias.datasets.utils import over_sample_features, under_sample_features -from tqdm import tqdm - -import os -sys.path.insert(1, '/root/study') +sys.path.insert(1, project_dir) -from numpy import mean, std +from arguments import get_args from metrics import get_metric_index, get_all_metrics, print_all_metrics -def parse_option(): - parser = argparse.ArgumentParser() - parser.add_argument('--exp_name', type=str, default='test') - parser.add_argument('--gpu', type=int, default=0) - parser.add_argument('--task', type=str, default='race') - - parser.add_argument('--epochs', type=int, default=20) - parser.add_argument('--seed', type=int, default=2023) - - parser.add_argument('--bs', type=int, default=128, help='batch_size') - parser.add_argument('--lr', type=float, default=1e-3) - parser.add_argument('--ecu', type=int, default=0) - parser.add_argument('--uw', type=int, default=1) - parser.add_argument('--mode', type=str, default='none') - - opt = parser.parse_args() - os.environ['CUDA_VISIBLE_DEVICES'] = str(opt.gpu) - - return opt - def set_model(): model = FCResNet18(num_classes=2).cuda() pred = nn.Linear(512, 2).cuda() - models = { - 'model': model, - 'pred': pred - } + models = {"model": model, "pred": pred} - criterion = { - 'bin': nn.BCEWithLogitsLoss(reduction='none'), - 'multi': nn.CrossEntropyLoss(reduction='none') - } + criterion = {"bin": nn.BCEWithLogitsLoss(reduction="none"), "multi": nn.CrossEntropyLoss(reduction="none")} return models, criterion + def train(train_loader, model, criterion, optimizer_model, opt, optimizer_layer): - model['model'].train() + model["model"].train() avg_loss = AverageMeter() train_iter = iter(train_loader) - - all_labels_nb = [] - all_gc = [] - all_feats = [] - all_bias = [] + + all_labels_nb = [] + all_gc = [] + all_feats = [] + all_bias = [] for images, labels, labels_bin, biases, gc, _ in tqdm(train_iter, ascii=True): - + bsz = labels.shape[0] labels_bin, biases = labels_bin.cuda(), biases.cuda() - + images = images.cuda() - logits, feat = model['model'](images) + logits, feat = model["model"](images) - multi = torch.ones_like(labels_bin) + multi = torch.ones_like(labels_bin) - multi[labels_bin == -1] = 0 - labels_bin[labels_bin == -1] = 0 + multi[labels_bin == -1] = 0 + labels_bin[labels_bin == -1] = 0 - loss = criterion['bin'](logits, labels_bin) - loss = loss*multi + loss = criterion["bin"](logits, labels_bin) + loss = loss * multi - div = torch.sum(multi) - loss = torch.sum(loss/div) + div = torch.sum(multi) + loss = torch.sum(loss / div) avg_loss.update(loss.item(), bsz) @@ -105,158 +78,176 @@ def train(train_loader, model, criterion, optimizer_model, opt, optimizer_layer) all_bias.append(biases.cpu().detach().numpy()) all_feats.append(feat.cpu().detach().numpy()) - all_labels_nb = np.concatenate(all_labels_nb, axis=0) - all_gc = np.concatenate(all_gc, axis=0) - all_bias = np.concatenate(all_bias, axis=0) - all_feats = np.concatenate(all_feats, axis=0) + all_labels_nb = np.concatenate(all_labels_nb, axis=0) + all_gc = np.concatenate(all_gc, axis=0) + all_bias = np.concatenate(all_bias, axis=0) + all_feats = np.concatenate(all_feats, axis=0) - if opt.mode == 'os': + if opt.mode == "os": all_feats, all_labels_nb = over_sample_features(all_bias, all_feats, all_labels_nb) - elif opt.mode == 'us': + elif opt.mode == "us": all_feats, all_labels_nb = under_sample_features(all_bias, all_feats, all_labels_nb) - batch_size = opt.bs + batch_size = opt.batch_size total_samples = len(all_labels_nb) - num_batches = total_samples//batch_size + num_batches = total_samples // batch_size all_idx = np.arange(total_samples) np.random.shuffle(all_idx) - all_feats[all_idx] = all_feats + all_feats[all_idx] = all_feats all_labels_nb[all_idx] = all_labels_nb - if opt.mode == 'uw': + if opt.mode == "uw": all_gc[all_idx] = all_gc - for batch_idx in range(num_batches): - start = batch_idx * batch_size + for batch_idx in range(num_batches): + start = batch_idx * batch_size end = min(total_samples, start + batch_size) feats = torch.from_numpy(all_feats[start:end]).cuda() labels = torch.from_numpy(all_labels_nb[start:end]).cuda() gc = torch.from_numpy(all_gc[start:end]).cuda() - optimizer_layer.zero_grad() - out_lr = model['pred'](feats) + optimizer_layer.zero_grad() + out_lr = model["pred"](feats) - loss = criterion['multi'](out_lr, labels) + loss = criterion["multi"](out_lr, labels) - if opt.mode == 'uw': + if opt.mode == "uw": loss *= gc - - loss = torch.mean(loss) - loss.backward() + + loss = torch.mean(loss) + loss.backward() optimizer_layer.step() - + return avg_loss.avg + def validate(val_loader, model): - model['model'].eval() - + model["model"].eval() + top1 = AverageMeter() attrwise_acc_meter = MultiDimAverageMeter(dims=(2, 2)) - + with torch.no_grad(): for images, labels, _, biases, _, _ in val_loader: images = images.cuda() bsz = labels.shape[0] - - output, feats = model['model'](images) - output = model['pred'](feats).detach().cpu() + + output, feats = model["model"](images) + output = model["pred"](feats).detach().cpu() preds = output.data.max(1, keepdim=True)[1].squeeze(1) - - acc1, = accuracy(output, labels, topk=(1,)) + + (acc1,) = accuracy(output, labels, topk=(1,)) top1.update(acc1[0], bsz) corrects = (preds == labels).long() - attrwise_acc_meter.add(corrects.cpu(), - torch.stack([labels.cpu(), biases.cpu()], dim=1)) + attrwise_acc_meter.add(corrects.cpu(), torch.stack([labels.cpu(), biases.cpu()], dim=1)) - return top1.avg, attrwise_acc_meter.get_mean(), attrwise_acc_meter.get_acc_diff() + return top1.avg, attrwise_acc_meter.get_mean(), attrwise_acc_meter.get_acc_diff() def main(): - opt = parse_option() - - exp_name = f'bm-utk_face_{opt.task}-{opt.exp_name}-lr{opt.lr}-bs{opt.bs}-seed{opt.seed}-mode_{opt.mode}' - opt.exp_name = exp_name + opt = get_args() + exp_name = f"bm_{opt.mode}-utkface_{opt.sensitive}-lr{opt.lr}-bs{opt.batch_size}-epochs{opt.epochs}-seed{opt.seed}" - result_dir = f'../results/utkface' - result_path = Path(result_dir) - result_path.mkdir(parents=True, exist_ok=True) - if opt.task == 'age': - fout = open('/'.join([str(result_path), f'bm_{opt.mode}_age_gender.txt']), 'w') - elif opt.task == 'race': - fout = open('/'.join([str(result_path), f'bm_{opt.mode}_race_gender.txt']), 'w') + # result_dir = f'../results/utkface' + # result_path = Path(result_dir) + # result_path.mkdir(parents=True, exist_ok=True) + # if opt.sensitive == 'age': + # fout = open('/'.join([str(result_path), f'bm_{opt.mode}_age_gender.txt']), 'w') + # elif opt.sensitive == 'race': + # fout = open('/'.join([str(result_path), f'bm_{opt.mode}_race_gender.txt']), 'w') - results = {} - metric_index = get_metric_index() - for m_index in metric_index: - results[m_index] = [] + # results = {} + # metric_index = get_metric_index() + # for m_index in metric_index: + # results[m_index] = [] - repeat_time = 10 + repeat_time = 1 - output_dir = f'exp_results/{exp_name}' + output_dir = f"{project_dir}/checkpoints/{exp_name}" save_path = Path(output_dir) save_path.mkdir(parents=True, exist_ok=True) - set_logging(exp_name, 'INFO', str(save_path)) - logging.info(f'Set seed: {opt.seed}') + print(f"Set seed: {opt.seed}") set_seed(opt.seed) - logging.info(f'save_path: {save_path}') + print(f"save_path: {save_path}") np.set_printoptions(precision=3) torch.set_printoptions(precision=3) - root = '../data/utkface' - train_loader = get_utk_face( - root, - batch_size=opt.bs, - bias_attr=opt.task, - split='train', - aug=False, - sampling = 'bin') - + root = f"{project_dir}/data/utkface" + train_loader = get_utk_face(root, batch_size=opt.batch_size, bias_attr=opt.sensitive, split="train", aug=False, sampling="bin") + val_loaders = {} - val_loaders['valid'] = get_utk_face( - root, - batch_size=256, - bias_attr=opt.task, - split='valid', - aug=False) - - val_loaders['test'] = get_utk_face( - root, - batch_size=256, - bias_attr=opt.task, - split='test', - aug=False) + val_loaders["valid"] = get_utk_face(root, batch_size=256, bias_attr=opt.sensitive, split="valid", aug=False) + + val_loaders["test"] = get_utk_face(root, batch_size=256, bias_attr=opt.sensitive, split="test", aug=False) for r in range(repeat_time): - logging.info(f'Repeated experiment: {r+1}') + # print(f"Repeated experiment: {r+1}") model, criterion = set_model() + # Evaluation + if opt.checkpoint: + model["model"].load_state_dict(torch.load(f"{save_path}/best_model.pt")["model"]) + model["model"].eval() + model["pred"].load_state_dict(torch.load(f"{save_path}/best_pred.pt")["model"]) + model["pred"].eval() + + with torch.no_grad(): + all_labels, all_biases, all_preds = [], [], [] + for images, labels, _, biases, _, _ in val_loaders["test"]: + images = images.cuda() + output, feats = model["model"](images) + output = model["pred"](feats).detach().cpu() + preds = output.data.max(1, keepdim=True)[1].squeeze(1) + + all_labels.append(labels) + all_biases.append(biases) + all_preds.append(preds) + + fin_labels = torch.cat(all_labels) + fin_biases = torch.cat(all_biases) + fin_preds = torch.cat(all_preds) + + ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) + print_all_metrics(ret=ret) + + sys.exit() + + # ret["time per epoch"] = total_time / opt.epochs + # for i in range(len(metric_index)): + # results[metric_index[i]].append(ret[metric_index[i]]) + + # for m_index in metric_index: + # fout.write(m_index + "\t") + # for i in range(repeat_time): + # fout.write("%f\t" % results[m_index][i]) + # fout.write("%f\t%f\n" % (mean(results[m_index]), std(results[m_index]))) + # fout.close() + decay_epochs = [opt.epochs // 3, opt.epochs * 2 // 3] - optimizer = torch.optim.Adam(model['model'].parameters(), lr=opt.lr, weight_decay=1e-4) + optimizer = torch.optim.Adam(model["model"].parameters(), lr=opt.lr, weight_decay=1e-4) scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=decay_epochs, gamma=0.1) - optimizer_layer = torch.optim.Adam(model['pred'].parameters(), lr=opt.lr, weight_decay=1e-4) + optimizer_layer = torch.optim.Adam(model["pred"].parameters(), lr=opt.lr, weight_decay=1e-4) scheduler_layer = torch.optim.lr_scheduler.MultiStepLR(optimizer_layer, milestones=decay_epochs, gamma=0.1) + print(f"decay_epochs: {decay_epochs}") - logging.info(f'decay_epochs: {decay_epochs}') - # (save_path / 'checkpoints').mkdir(parents=True, exist_ok=True) - - best_accs = {'valid': 0, 'test': 0} - best_epochs = {'valid': 0, 'test': 0} + best_accs = {"valid": 0, "test": 0} + best_epochs = {"valid": 0, "test": 0} best_stats = {} start_time = time.time() for epoch in range(1, opt.epochs + 1): - logging.info(f'[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}') + print(f"[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}") loss = train(train_loader, model, criterion, optimizer, opt, optimizer_layer) - logging.info(f'[{epoch} / {opt.epochs}] Loss: {loss:.4f}') + print(f"[{epoch} / {opt.epochs}] Loss: {loss:.4f}") scheduler.step() scheduler_layer.step() @@ -265,62 +256,36 @@ def main(): for key, val_loader in val_loaders.items(): accs, valid_attrwise_accs, diff = validate(val_loader, model) - stats[f'{key}/acc'] = accs.item() - stats[f'{key}/acc_unbiased'] = torch.mean(valid_attrwise_accs).item() * 100 - stats[f'{key}/diff'] = diff.item() * 100 + stats[f"{key}/acc"] = accs.item() + stats[f"{key}/acc_unbiased"] = torch.mean(valid_attrwise_accs).item() * 100 + stats[f"{key}/diff"] = diff.item() * 100 eye_tsr = train_loader.dataset.eye_tsr - stats[f'{key}/acc_skew'] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 - stats[f'{key}/acc_align'] = valid_attrwise_accs[eye_tsr == 0.0].mean().item() * 100 + stats[f"{key}/acc_skew"] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 + stats[f"{key}/acc_align"] = valid_attrwise_accs[eye_tsr == 0.0].mean().item() * 100 - logging.info(f'[{epoch} / {opt.epochs}] {valid_attrwise_accs} {stats}') + print(f"[{epoch} / {opt.epochs}] {valid_attrwise_accs} {stats}") for tag in val_loaders.keys(): - if stats[f'{tag}/acc_unbiased'] > best_accs[tag]: - best_accs[tag] = stats[f'{tag}/acc_unbiased'] + if stats[f"{tag}/acc_unbiased"] > best_accs[tag]: + best_accs[tag] = stats[f"{tag}/acc_unbiased"] best_epochs[tag] = epoch - best_stats[tag] = pretty_dict(**{f'best_{tag}_{k}': v for k, v in stats.items()}) + best_stats[tag] = pretty_dict(**{f"best_{tag}_{k}": v for k, v in stats.items()}) - logging.info( - f'[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}') + print( + f"[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}" + ) + + save_file_model = save_path / "best_model.pt" + save_file_pred = save_path / "best_pred.pt" + save_model(model["model"], optimizer, opt, epoch, save_file_model) + save_model(model["pred"], optimizer_layer, opt, epoch, save_file_pred) total_time = time.time() - start_time total_time_str = str(datetime.timedelta(seconds=int(total_time))) - logging.info(f'Total training time: {total_time_str}') - - # Evaluation - model['model'].eval() - - with torch.no_grad(): - all_labels, all_biases, all_preds = [], [], [] - for images, labels, _, biases, _, _ in val_loaders['test']: - images = images.cuda() - output, feats = model['model'](images) - output = model['pred'](feats).detach().cpu() - preds = output.data.max(1, keepdim=True)[1].squeeze(1) - - all_labels.append(labels) - all_biases.append(biases) - all_preds.append(preds) - - fin_labels = torch.cat(all_labels) - fin_biases = torch.cat(all_biases) - fin_preds = torch.cat(all_preds) - - ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) - print_all_metrics(ret=ret) - - ret['time per epoch'] = total_time / opt.epochs - for i in range(len(metric_index)): - results[metric_index[i]].append(ret[metric_index[i]]) - - for m_index in metric_index: - fout.write(m_index + '\t') - for i in range(repeat_time): - fout.write('%f\t' % results[m_index][i]) - fout.write('%f\t%f\n' % (mean(results[m_index]), std(results[m_index]))) - fout.close() + print(f"Total training time: {total_time_str}") + print(f"Time per epoch: {total_time / opt.epochs:.6f}") -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/BM/train_utk_face/train_utk_face_di.py b/BM/train_utk_face/train_utk_face_di.py index 3853b52..d469094 100644 --- a/BM/train_utk_face/train_utk_face_di.py +++ b/BM/train_utk_face/train_utk_face_di.py @@ -1,48 +1,28 @@ -import argparse -import datetime -import logging import os +import sys import time -from pathlib import Path - -import numpy as np import torch -from torch import nn +import logging +import datetime +import numpy as np +from pathlib import Path +from numpy import mean, std -import sys -sys.path.insert(1, './') +project_dir = "/root/DL-Fairness-Study" +sys.path.insert(1, os.path.join(project_dir, "BM")) -from debias.datasets.utk_face import get_utk_face from debias.losses.diloss import DILoss -from debias.networks.resnet_di import DIResNet18 from debias.utils.logging import set_logging -from debias.utils.utils import (AverageMeter, MultiDimAverageMeter, accuracy, - pretty_dict, save_model, set_seed) +from debias.datasets.utk_face import get_utk_face +from debias.networks.resnet_di import DIResNet18 +from debias.utils.utils import AverageMeter, MultiDimAverageMeter, accuracy, pretty_dict, save_model, set_seed -sys.path.insert(1, '/root/study') +sys.path.insert(1, project_dir) -from numpy import mean, std +from arguments import get_args from metrics import get_metric_index, get_all_metrics, print_all_metrics -def parse_option(): - parser = argparse.ArgumentParser() - parser.add_argument('--exp_name', type=str, default='test') - parser.add_argument('--gpu', type=int, default=0) - parser.add_argument('--task', type=str, default='race') - - parser.add_argument('--epochs', type=int, default=20) - parser.add_argument('--seed', type=int, default=1) - - parser.add_argument('--bs', type=int, default=128, help='batch_size') - parser.add_argument('--lr', type=float, default=1e-3) - - opt = parser.parse_args() - os.environ['CUDA_VISIBLE_DEVICES'] = str(opt.gpu) - - return opt - - def set_model(): model = DIResNet18().cuda() criterion = DILoss() @@ -89,92 +69,110 @@ def validate(val_loader, model): output_sum = output[:, :2] + output[:, 2:] preds = torch.argmax(output_sum, axis=1) - acc1, = accuracy(output_sum, labels, topk=(1,)) + (acc1,) = accuracy(output_sum, labels, topk=(1,)) top1.update(acc1[0], bsz) corrects = (preds == labels).long() attrwise_acc_meter.add(corrects.cpu(), torch.stack([labels.cpu(), biases.cpu()], dim=1)) - return top1.avg, attrwise_acc_meter.get_mean(), attrwise_acc_meter.get_acc_diff() + return top1.avg, attrwise_acc_meter.get_mean(), attrwise_acc_meter.get_acc_diff() def main(): - opt = parse_option() + opt = get_args() + exp_name = f"di-utkface_{opt.sensitive}-lr{opt.lr}-bs{opt.batch_size}-epochs{opt.epochs}-seed{opt.seed}" - exp_name = f'di-utk_face_{opt.task}-{opt.exp_name}-lr{opt.lr}-bs{opt.bs}-seed{opt.seed}' - opt.exp_name = exp_name + # result_dir = f"../results/utkface" + # result_path = Path(result_dir) + # result_path.mkdir(parents=True, exist_ok=True) + # if opt.sensitive == "age": + # fout = open("/".join([str(result_path), "di_age_gender.txt"]), "w") + # elif opt.sensitive == "race": + # fout = open("/".join([str(result_path), "di_race_gender.txt"]), "w") - result_dir = f'../results/utkface' - result_path = Path(result_dir) - result_path.mkdir(parents=True, exist_ok=True) - if opt.task == 'age': - fout = open('/'.join([str(result_path), 'di_age_gender.txt']), 'w') - elif opt.task == 'race': - fout = open('/'.join([str(result_path), 'di_race_gender.txt']), 'w') + # results = {} + # metric_index = get_metric_index() + # for m_index in metric_index: + # results[m_index] = [] - results = {} - metric_index = get_metric_index() - for m_index in metric_index: - results[m_index] = [] + repeat_time = 1 - repeat_time = 10 - - output_dir = f'exp_results/{exp_name}' + output_dir = f"{project_dir}/checkpoints/{exp_name}" save_path = Path(output_dir) save_path.mkdir(parents=True, exist_ok=True) - set_logging(exp_name, 'INFO', str(save_path)) - logging.info(f'Set seed: {opt.seed}') + print(f"Set seed: {opt.seed}") set_seed(opt.seed) - logging.info(f'save_path: {save_path}') + print(f"save_path: {save_path}") np.set_printoptions(precision=3) torch.set_printoptions(precision=3) - root = '../data/utkface' - train_loader = get_utk_face( - root, - batch_size=opt.bs, - bias_attr=opt.task, - split='train', - aug=False) + root = f"{project_dir}/data/utkface" + train_loader = get_utk_face(root, batch_size=opt.batch_size, bias_attr=opt.sensitive, split="train", aug=False) val_loaders = {} - val_loaders['valid'] = get_utk_face( - root, - batch_size=256, - bias_attr=opt.task, - split='valid', - aug=False) - - val_loaders['test'] = get_utk_face( - root, - batch_size=256, - bias_attr=opt.task, - split='test', - aug=False) + val_loaders["valid"] = get_utk_face(root, batch_size=256, bias_attr=opt.sensitive, split="valid", aug=False) + + val_loaders["test"] = get_utk_face(root, batch_size=256, bias_attr=opt.sensitive, split="test", aug=False) for r in range(repeat_time): - logging.info(f'Repeated experiment: {r+1}') + # print(f"Repeated experiment: {r+1}") model, criterion = set_model() + # Evaluation + if opt.checkpoint: + model.load_state_dict(torch.load(f"{save_path}/best_model.pt")["model"]) + model.eval() + + with torch.no_grad(): + all_labels, all_biases, all_preds = [], [], [] + for images, labels, _, biases, _, _ in val_loaders["test"]: + images = images.cuda() + + output = model(images) + output_sum = output[:, :2] + output[:, 2:] + preds = torch.argmax(output_sum, axis=1).cpu() + + all_labels.append(labels) + all_biases.append(biases) + all_preds.append(preds) + + fin_labels = torch.cat(all_labels) + fin_biases = torch.cat(all_biases) + fin_preds = torch.cat(all_preds) + + ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) + print_all_metrics(ret=ret) + + sys.exit() + + # ret["time per epoch"] = total_time / opt.epochs + # for i in range(len(metric_index)): + # results[metric_index[i]].append(ret[metric_index[i]]) + + # for m_index in metric_index: + # fout.write(m_index + "\t") + # for i in range(repeat_time): + # fout.write("%f\t" % results[m_index][i]) + # fout.write("%f\t%f\n" % (mean(results[m_index]), std(results[m_index]))) + # fout.close() + decay_epochs = [opt.epochs // 3, opt.epochs * 2 // 3] optimizer = torch.optim.Adam(model.parameters(), lr=opt.lr, weight_decay=1e-4) scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=decay_epochs, gamma=0.1) - logging.info(f'decay_epochs: {decay_epochs}') + print(f"decay_epochs: {decay_epochs}") - # (save_path / 'checkpoints').mkdir(parents=True, exist_ok=True) - - best_accs = {'valid': 0, 'test': 0} - best_epochs = {'valid': 0, 'test': 0} + best_accs = {"valid": 0, "test": 0} + best_epochs = {"valid": 0, "test": 0} best_stats = {} start_time = time.time() for epoch in range(1, opt.epochs + 1): - logging.info(f'[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}') + print(f"[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}") loss = train(train_loader, model, criterion, optimizer) - logging.info(f'[{epoch} / {opt.epochs}] Loss: {loss:.4f}') + print(f"[{epoch} / {opt.epochs}] Loss: {loss:.4f}") scheduler.step() @@ -182,63 +180,34 @@ def main(): for key, val_loader in val_loaders.items(): accs, valid_attrwise_accs, diff = validate(val_loader, model) - stats[f'{key}/acc'] = accs.item() - stats[f'{key}/acc_unbiased'] = torch.mean(valid_attrwise_accs).item() * 100 - stats[f'{key}/diff'] = diff.item() * 100 + stats[f"{key}/acc"] = accs.item() + stats[f"{key}/acc_unbiased"] = torch.mean(valid_attrwise_accs).item() * 100 + stats[f"{key}/diff"] = diff.item() * 100 eye_tsr = train_loader.dataset.eye_tsr - stats[f'{key}/acc_skew'] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 - stats[f'{key}/acc_align'] = valid_attrwise_accs[eye_tsr == 0.0].mean().item() * 100 + stats[f"{key}/acc_skew"] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 + stats[f"{key}/acc_align"] = valid_attrwise_accs[eye_tsr == 0.0].mean().item() * 100 - logging.info(f'[{epoch} / {opt.epochs}] {valid_attrwise_accs} {stats}') + print(f"[{epoch} / {opt.epochs}] {valid_attrwise_accs} {stats}") for tag in val_loaders.keys(): - if stats[f'{tag}/acc_unbiased'] > best_accs[tag]: - best_accs[tag] = stats[f'{tag}/acc_unbiased'] + if stats[f"{tag}/acc_unbiased"] > best_accs[tag]: + best_accs[tag] = stats[f"{tag}/acc_unbiased"] best_epochs[tag] = epoch - best_stats[tag] = pretty_dict(**{f'best_{tag}_{k}': v for k, v in stats.items()}) + best_stats[tag] = pretty_dict(**{f"best_{tag}_{k}": v for k, v in stats.items()}) + + print( + f"[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}" + ) - logging.info( - f'[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}') + save_file = save_path / f"best_model.pt" + save_model(model, optimizer, opt, epoch, save_file) total_time = time.time() - start_time total_time_str = str(datetime.timedelta(seconds=int(total_time))) - logging.info(f'Total training time: {total_time_str}') - - # Evaluation - model.eval() - - with torch.no_grad(): - all_labels, all_biases, all_preds = [], [], [] - for images, labels, _, biases, _, _ in val_loaders['test']: - images = images.cuda() - - output = model(images) - output_sum = output[:, :2] + output[:, 2:] - preds = torch.argmax(output_sum, axis=1).cpu() - - all_labels.append(labels) - all_biases.append(biases) - all_preds.append(preds) - - fin_labels = torch.cat(all_labels) - fin_biases = torch.cat(all_biases) - fin_preds = torch.cat(all_preds) - - ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) - print_all_metrics(ret=ret) - - ret['time per epoch'] = total_time / opt.epochs - for i in range(len(metric_index)): - results[metric_index[i]].append(ret[metric_index[i]]) - - for m_index in metric_index: - fout.write(m_index + '\t') - for i in range(repeat_time): - fout.write('%f\t' % results[m_index][i]) - fout.write('%f\t%f\n' % (mean(results[m_index]), std(results[m_index]))) - fout.close() + print(f"Total training time: {total_time_str}") + print(f"Time per epoch: {total_time / opt.epochs:.6f}") -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/BM/train_utk_face/train_utk_face_os.py b/BM/train_utk_face/train_utk_face_os.py index 44a0ca5..8efdb52 100644 --- a/BM/train_utk_face/train_utk_face_os.py +++ b/BM/train_utk_face/train_utk_face_os.py @@ -1,47 +1,28 @@ -import argparse -import datetime -import logging import os +import sys import time -from pathlib import Path - -import numpy as np import torch +import logging +import datetime +import numpy as np from torch import nn +from pathlib import Path +from numpy import mean, std -import sys -sys.path.insert(1, './') +project_dir = "/root/DL-Fairness-Study" +sys.path.insert(1, os.path.join(project_dir, "BM")) -from debias.datasets.utk_face import get_utk_face -from debias.networks.resnet import FCResNet18 from debias.utils.logging import set_logging -from debias.utils.utils import (AverageMeter, MultiDimAverageMeter, accuracy, - pretty_dict, save_model, set_seed) +from debias.networks.resnet import FCResNet18 +from debias.datasets.utk_face import get_utk_face +from debias.utils.utils import AverageMeter, MultiDimAverageMeter, accuracy, pretty_dict, save_model, set_seed -sys.path.insert(1, '/root/study') +sys.path.insert(1, project_dir) -from numpy import mean, std +from arguments import get_args from metrics import get_metric_index, get_all_metrics, print_all_metrics -def parse_option(): - parser = argparse.ArgumentParser() - parser.add_argument('--exp_name', type=str, default='test') - parser.add_argument('--gpu', type=int, default=0) - parser.add_argument('--task', type=str, default='race') - - parser.add_argument('--epochs', type=int, default=20) - parser.add_argument('--seed', type=int, default=1) - - parser.add_argument('--bs', type=int, default=128, help='batch_size') - parser.add_argument('--lr', type=float, default=1e-3) - - opt = parser.parse_args() - os.environ['CUDA_VISIBLE_DEVICES'] = str(opt.gpu) - - return opt - - def set_model(): model = FCResNet18().cuda() criterion = nn.CrossEntropyLoss() @@ -68,7 +49,7 @@ def train(train_loader, model, criterion, optimizer): optimizer.zero_grad() loss.backward() optimizer.step() - + return avg_loss.avg @@ -86,7 +67,7 @@ def validate(val_loader, model): output, _ = model(images) preds = output.data.max(1, keepdim=True)[1].squeeze(1) - acc1, = accuracy(output, labels, topk=(1,)) + (acc1,) = accuracy(output, labels, topk=(1,)) top1.update(acc1[0], bsz) corrects = (preds == labels).long() @@ -96,83 +77,98 @@ def validate(val_loader, model): def main(): - opt = parse_option() + opt = get_args() + exp_name = f"os-utkface_{opt.sensitive}-lr{opt.lr}-bs{opt.batch_size}-epochs{opt.epochs}-seed{opt.seed}" - exp_name = f'os-utk_face_{opt.task}-{opt.exp_name}-lr{opt.lr}-bs{opt.bs}-seed{opt.seed}' - opt.exp_name = exp_name + # result_dir = f"../results/utkface" + # result_path = Path(result_dir) + # result_path.mkdir(parents=True, exist_ok=True) + # if opt.sensitive == "age": + # fout = open("/".join([str(result_path), "os_age_gender.txt"]), "w") + # elif opt.sensitive == "race": + # fout = open("/".join([str(result_path), "os_race_gender.txt"]), "w") - result_dir = f'../results/utkface' - result_path = Path(result_dir) - result_path.mkdir(parents=True, exist_ok=True) - if opt.task == 'age': - fout = open('/'.join([str(result_path), 'os_age_gender.txt']), 'w') - elif opt.task == 'race': - fout = open('/'.join([str(result_path), 'os_race_gender.txt']), 'w') + # results = {} + # metric_index = get_metric_index() + # for m_index in metric_index: + # results[m_index] = [] - results = {} - metric_index = get_metric_index() - for m_index in metric_index: - results[m_index] = [] + repeat_time = 1 - repeat_time = 10 - - output_dir = f'exp_results/{exp_name}' + output_dir = f"{project_dir}/checkpoints/{exp_name}" save_path = Path(output_dir) save_path.mkdir(parents=True, exist_ok=True) - set_logging(exp_name, 'INFO', str(save_path)) - logging.info(f'Set seed: {opt.seed}') + print(f"Set seed: {opt.seed}") set_seed(opt.seed) - logging.info(f'save_path: {save_path}') + print(f"save_path: {save_path}") np.set_printoptions(precision=3) torch.set_printoptions(precision=3) - - root = '../data/utkface' - train_loader = get_utk_face( - root, - batch_size=opt.bs, - bias_attr=opt.task, - split='train', - aug=False, - sampling = 'os') - + + root = f"{project_dir}/data/utkface" + train_loader = get_utk_face(root, batch_size=opt.batch_size, bias_attr=opt.sensitive, split="train", aug=False, sampling="os") + val_loaders = {} - val_loaders['valid'] = get_utk_face( - root, - batch_size=256, - bias_attr=opt.task, - split='valid', - aug=False) - - val_loaders['test'] = get_utk_face( - root, - batch_size=256, - bias_attr=opt.task, - split='test', - aug=False) + val_loaders["valid"] = get_utk_face(root, batch_size=256, bias_attr=opt.sensitive, split="valid", aug=False) + + val_loaders["test"] = get_utk_face(root, batch_size=256, bias_attr=opt.sensitive, split="test", aug=False) for r in range(repeat_time): - logging.info(f'Repeated experiment: {r+1}') + # print(f"Repeated experiment: {r+1}") model, criterion = set_model() + # Evaluation + if opt.checkpoint: + model.load_state_dict(torch.load(f"{save_path}/best_model.pt")["model"]) + model.eval() + + with torch.no_grad(): + all_labels, all_biases, all_preds = [], [], [] + for images, labels, _, biases, _, _ in val_loaders["test"]: + images = images.cuda() + output, _ = model(images) + preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() + + all_labels.append(labels) + all_biases.append(biases) + all_preds.append(preds) + + fin_labels = torch.cat(all_labels) + fin_biases = torch.cat(all_biases) + fin_preds = torch.cat(all_preds) + + ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) + print_all_metrics(ret=ret) + + sys.exit() + + # ret["time per epoch"] = total_time / opt.epochs + # for i in range(len(metric_index)): + # results[metric_index[i]].append(ret[metric_index[i]]) + + # for m_index in metric_index: + # fout.write(m_index + "\t") + # for i in range(repeat_time): + # fout.write("%f\t" % results[m_index][i]) + # fout.write("%f\t%f\n" % (mean(results[m_index]), std(results[m_index]))) + # fout.close() + decay_epochs = [opt.epochs // 3, opt.epochs * 2 // 3] optimizer = torch.optim.Adam(model.parameters(), lr=opt.lr, weight_decay=1e-4) scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=decay_epochs, gamma=0.1) - logging.info(f'decay_epochs: {decay_epochs}') - - # (save_path / 'checkpoints').mkdir(parents=True, exist_ok=True) + print(f"decay_epochs: {decay_epochs}") - best_accs = {'valid': 0, 'test': 0} - best_epochs = {'valid': 0, 'test': 0} + best_accs = {"valid": 0, "test": 0} + best_epochs = {"valid": 0, "test": 0} best_stats = {} start_time = time.time() for epoch in range(1, opt.epochs + 1): - logging.info(f'[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}') + print(f"[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}") loss = train(train_loader, model, criterion, optimizer) - logging.info(f'[{epoch} / {opt.epochs}] Loss: {loss:.4f}') + print(f"[{epoch} / {opt.epochs}] Loss: {loss:.4f}") scheduler.step() @@ -180,61 +176,34 @@ def main(): for key, val_loader in val_loaders.items(): accs, valid_attrwise_accs, acc_diff = validate(val_loader, model) - stats[f'{key}/acc'] = accs.item() - stats[f'{key}/acc_unbiased'] = torch.mean(valid_attrwise_accs).item() * 100 - stats[f'{key}/acc_diff'] = acc_diff.item() * 100 + stats[f"{key}/acc"] = accs.item() + stats[f"{key}/acc_unbiased"] = torch.mean(valid_attrwise_accs).item() * 100 + stats[f"{key}/acc_diff"] = acc_diff.item() * 100 eye_tsr = train_loader.dataset.eye_tsr - stats[f'{key}/acc_skew'] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 - stats[f'{key}/acc_align'] = valid_attrwise_accs[eye_tsr == 0.0].mean().item() * 100 + stats[f"{key}/acc_skew"] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 + stats[f"{key}/acc_align"] = valid_attrwise_accs[eye_tsr == 0.0].mean().item() * 100 - logging.info(f'[{epoch} / {opt.epochs}] {valid_attrwise_accs} {stats}') + print(f"[{epoch} / {opt.epochs}] {valid_attrwise_accs} {stats}") for tag in val_loaders.keys(): - if stats[f'{tag}/acc_unbiased'] > best_accs[tag]: - best_accs[tag] = stats[f'{tag}/acc_unbiased'] + if stats[f"{tag}/acc_unbiased"] > best_accs[tag]: + best_accs[tag] = stats[f"{tag}/acc_unbiased"] best_epochs[tag] = epoch - best_stats[tag] = pretty_dict(**{f'best_{tag}_{k}': v for k, v in stats.items()}) - - logging.info( - f'[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}') - - total_time = time.time() - start_time - total_time_str = str(datetime.timedelta(seconds=int(total_time))) - logging.info(f'Total training time: {total_time_str}') - - # Evaluation - model.eval() - - with torch.no_grad(): - all_labels, all_biases, all_preds = [], [], [] - for images, labels, _, biases, _, _ in val_loaders['test']: - images = images.cuda() - output, _ = model(images) - preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() - - all_labels.append(labels) - all_biases.append(biases) - all_preds.append(preds) + best_stats[tag] = pretty_dict(**{f"best_{tag}_{k}": v for k, v in stats.items()}) - fin_labels = torch.cat(all_labels) - fin_biases = torch.cat(all_biases) - fin_preds = torch.cat(all_preds) + print( + f"[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}" + ) - ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) - print_all_metrics(ret=ret) + save_file = save_path / "best_model.pt" + save_model(model, optimizer, opt, epoch, save_file) - ret['time per epoch'] = total_time / opt.epochs - for i in range(len(metric_index)): - results[metric_index[i]].append(ret[metric_index[i]]) - - for m_index in metric_index: - fout.write(m_index + '\t') - for i in range(repeat_time): - fout.write('%f\t' % results[m_index][i]) - fout.write('%f\t%f\n' % (mean(results[m_index]), std(results[m_index]))) - fout.close() + total_time = time.time() - start_time + total_time_str = str(datetime.timedelta(seconds=int(total_time))) + print(f"Total training time: {total_time_str}") + print(f"Time per epoch: {total_time / opt.epochs:.6f}") -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/BM/train_utk_face/train_utk_face_us.py b/BM/train_utk_face/train_utk_face_us.py index 5b10e10..c73b20a 100644 --- a/BM/train_utk_face/train_utk_face_us.py +++ b/BM/train_utk_face/train_utk_face_us.py @@ -1,49 +1,28 @@ -import argparse -import datetime -import logging import os +import sys import time -from pathlib import Path - -import numpy as np import torch +import logging +import datetime +import numpy as np from torch import nn +from pathlib import Path +from numpy import mean, std -import sys -sys.path.insert(1, './') +project_dir = "/root/DL-Fairness-Study" +sys.path.insert(1, os.path.join(project_dir, "BM")) -from debias.datasets.utk_face import get_utk_face -from debias.networks.resnet import FCResNet18 from debias.utils.logging import set_logging -from debias.utils.utils import (AverageMeter, MultiDimAverageMeter, accuracy, - pretty_dict, save_model, set_seed) +from debias.networks.resnet import FCResNet18 +from debias.datasets.utk_face import get_utk_face +from debias.utils.utils import AverageMeter, MultiDimAverageMeter, accuracy, pretty_dict, save_model, set_seed -sys.path.insert(1, '/root/study') +sys.path.insert(1, project_dir) -from numpy import mean, std +from arguments import get_args from metrics import get_metric_index, get_all_metrics, print_all_metrics -def parse_option(): - parser = argparse.ArgumentParser() - parser.add_argument('--exp_name', type=str, default='test') - parser.add_argument('--gpu', type=int, default=0) - parser.add_argument('--task', type=str, default='race') - - parser.add_argument('--epochs', type=int, default=20) - parser.add_argument('--epochs_extra', type=int, default=20) - parser.add_argument('--seed', type=int, default=1) - - parser.add_argument('--bs', type=int, default=128, help='batch_size') - parser.add_argument('--lr', type=float, default=1e-3) - parser.add_argument('--rs', action='store_true') - - opt = parser.parse_args() - os.environ['CUDA_VISIBLE_DEVICES'] = str(opt.gpu) - - return opt - - def set_model(): model = FCResNet18().cuda() criterion = nn.CrossEntropyLoss() @@ -71,7 +50,7 @@ def train(train_loader, model, criterion, optimizer): optimizer.zero_grad() loss.backward() optimizer.step() - + return avg_loss.avg @@ -89,7 +68,7 @@ def validate(val_loader, model): output, _ = model(images) preds = output.data.max(1, keepdim=True)[1].squeeze(1) - acc1, = accuracy(output, labels, topk=(1,)) + (acc1,) = accuracy(output, labels, topk=(1,)) top1.update(acc1[0], bsz) corrects = (preds == labels).long() @@ -99,17 +78,15 @@ def validate(val_loader, model): def main(): - opt = parse_option() - - exp_name = f'us-utk_face_{opt.task}-{opt.exp_name}-lr{opt.lr}-bs{opt.bs}-seed{opt.seed}' - opt.exp_name = exp_name + opt = get_args() + exp_name = f"us-utkface_{opt.sensitive}-lr{opt.lr}-bs{opt.batch_size}-epochs{opt.epochs}-seed{opt.seed}" # result_dir = f'../results/utkface' # result_path = Path(result_dir) # result_path.mkdir(parents=True, exist_ok=True) - # if opt.task == 'age': + # if opt.sensitive == 'age': # fout = open('/'.join([str(result_path), 'us_age_gender.txt']), 'w') - # elif opt.task == 'race': + # elif opt.sensitive == 'race': # fout = open('/'.join([str(result_path), 'us_race_gender.txt']), 'w') # results = {} @@ -119,64 +96,82 @@ def main(): repeat_time = 1 - output_dir = f'exp_results/{exp_name}' + output_dir = f"{project_dir}/checkpoints/{exp_name}" save_path = Path(output_dir) save_path.mkdir(parents=True, exist_ok=True) - set_logging(exp_name, 'INFO', str(save_path)) - logging.info(f'Set seed: {opt.seed}') + print(f"Set seed: {opt.seed}") set_seed(opt.seed) - logging.info(f'save_path: {save_path}') + print(f"save_path: {save_path}") np.set_printoptions(precision=3) torch.set_printoptions(precision=3) - - root = '../data/utkface' - train_loader = get_utk_face( - root, - batch_size=opt.bs, - bias_attr=opt.task, - split='train', - aug=False, - sampling = 'ce') - + + root = f"{project_dir}/data/utkface" + train_loader = get_utk_face(root, batch_size=opt.batch_size, bias_attr=opt.sensitive, split="train", aug=False, sampling="ce") + val_loaders = {} - val_loaders['valid'] = get_utk_face( - root, - batch_size=256, - bias_attr=opt.task, - split='valid', - aug=False) - - val_loaders['test'] = get_utk_face( - root, - batch_size=256, - bias_attr=opt.task, - split='test', - aug=False) + val_loaders["valid"] = get_utk_face(root, batch_size=256, bias_attr=opt.sensitive, split="valid", aug=False) + + val_loaders["test"] = get_utk_face(root, batch_size=256, bias_attr=opt.sensitive, split="test", aug=False) for r in range(repeat_time): - logging.info(f'Repeated experiment: {r+1}') + # print(f"Repeated experiment: {r+1}") model, criterion = set_model() + + # Evaluation + if opt.checkpoint: + model.load_state_dict(torch.load(f"{save_path}/best_model.pt")["model"]) + model.eval() + + with torch.no_grad(): + all_labels, all_biases, all_preds = [], [], [] + for images, labels, _, biases, _, _ in val_loaders["test"]: + images = images.cuda() + output, _ = model(images) + preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() + + all_labels.append(labels) + all_biases.append(biases) + all_preds.append(preds) + + fin_labels = torch.cat(all_labels) + fin_biases = torch.cat(all_biases) + fin_preds = torch.cat(all_preds) + + ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) + print_all_metrics(ret=ret) + + sys.exit() + + # ret["time per epoch"] = total_time / opt.epochs + # for i in range(len(metric_index)): + # results[metric_index[i]].append(ret[metric_index[i]]) + + # for m_index in metric_index: + # fout.write(m_index + '\t') + # for i in range(repeat_time): + # fout.write('%f\t' % results[m_index][i]) + # fout.write('%f\t%f\n' % (mean(results[m_index]), std(results[m_index]))) + # fout.close() + decay_epochs = [opt.epochs // 3, opt.epochs * 2 // 3] optimizer = torch.optim.Adam(model.parameters(), lr=opt.lr, weight_decay=1e-4) scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=decay_epochs, gamma=0.1) - logging.info(f'decay_epochs: {decay_epochs}') + print(f"decay_epochs: {decay_epochs}") - # (save_path / 'checkpoints').mkdir(parents=True, exist_ok=True) - - best_accs = {'valid': 0, 'test': 0} - best_epochs = {'valid': 0, 'test': 0} + best_accs = {"valid": 0, "test": 0} + best_epochs = {"valid": 0, "test": 0} best_stats = {} start_time = time.time() for epoch in range(1, opt.epochs + 1): - logging.info(f'[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}') + print(f"[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}") - for _ in range(opt.epochs_extra): + for _ in range(opt.epochs_extra): loss = train(train_loader, model, criterion, optimizer) - logging.info(f'[{epoch} / {opt.epochs}] Loss: {loss:.4f}') + print(f"[{epoch} / {opt.epochs}] Loss: {loss:.4f}") scheduler.step() @@ -184,66 +179,38 @@ def main(): for key, val_loader in val_loaders.items(): accs, valid_attrwise_accs, acc_diff = validate(val_loader, model) - stats[f'{key}/acc'] = accs.item() - stats[f'{key}/acc_unbiased'] = torch.mean(valid_attrwise_accs).item() * 100 - stats[f'{key}/acc_diff'] = acc_diff.item() * 100 + stats[f"{key}/acc"] = accs.item() + stats[f"{key}/acc_unbiased"] = torch.mean(valid_attrwise_accs).item() * 100 + stats[f"{key}/acc_diff"] = acc_diff.item() * 100 - eye_tsr = train_loader.dataset.eye_tsr + eye_tsr = train_loader.dataset.eye_tsr - stats[f'{key}/acc_skew'] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 - stats[f'{key}/acc_align'] = valid_attrwise_accs[eye_tsr == 0.0].mean().item() * 100 + stats[f"{key}/acc_skew"] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 + stats[f"{key}/acc_align"] = valid_attrwise_accs[eye_tsr == 0.0].mean().item() * 100 - logging.info(f'[{epoch} / {opt.epochs}] {valid_attrwise_accs} {stats}') + print(f"[{epoch} / {opt.epochs}] {valid_attrwise_accs} {stats}") for tag in val_loaders.keys(): - if stats[f'{tag}/acc_unbiased'] > best_accs[tag]: - best_accs[tag] = stats[f'{tag}/acc_unbiased'] + if stats[f"{tag}/acc_unbiased"] > best_accs[tag]: + best_accs[tag] = stats[f"{tag}/acc_unbiased"] best_epochs[tag] = epoch - best_stats[tag] = pretty_dict(**{f'best_{tag}_{k}': v for k, v in stats.items()}) + best_stats[tag] = pretty_dict(**{f"best_{tag}_{k}": v for k, v in stats.items()}) - logging.info( - f'[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}') + print( + f"[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}" + ) if opt.rs: train_loader.dataset.reset_data() - train_loader.dataset.under_sample_ce() - - total_time = time.time() - start_time - total_time_str = str(datetime.timedelta(seconds=int(total_time))) - logging.info(f'Total training time: {total_time_str}') - - # Evaluation - model.eval() - - with torch.no_grad(): - all_labels, all_biases, all_preds = [], [], [] - for images, labels, _, biases, _, _ in val_loaders['test']: - images = images.cuda() - output, _ = model(images) - preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() + train_loader.dataset.under_sample_ce() - all_labels.append(labels) - all_biases.append(biases) - all_preds.append(preds) + save_file = save_path / "best_model.pt" + save_model(model, optimizer, opt, epoch, save_file) - fin_labels = torch.cat(all_labels) - fin_biases = torch.cat(all_biases) - fin_preds = torch.cat(all_preds) - - ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) - print_all_metrics(ret=ret) - - ret['time per epoch'] = total_time / opt.epochs - print(ret['time per epoch']) - # for i in range(len(metric_index)): - # results[metric_index[i]].append(ret[metric_index[i]]) - - # for m_index in metric_index: - # fout.write(m_index + '\t') - # for i in range(repeat_time): - # fout.write('%f\t' % results[m_index][i]) - # fout.write('%f\t%f\n' % (mean(results[m_index]), std(results[m_index]))) - # fout.close() + total_time = time.time() - start_time + total_time_str = str(datetime.timedelta(seconds=int(total_time))) + print(f"Total training time: {total_time_str}") + print(f"Time per epoch: {total_time / opt.epochs:.6f}") -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/BM/train_utk_face/train_utk_face_uw.py b/BM/train_utk_face/train_utk_face_uw.py index eaec52c..6259f98 100644 --- a/BM/train_utk_face/train_utk_face_uw.py +++ b/BM/train_utk_face/train_utk_face_uw.py @@ -1,50 +1,31 @@ -import argparse -import datetime -import logging import os +import sys import time -from pathlib import Path - -import numpy as np import torch +import logging +import datetime +import numpy as np from torch import nn +from pathlib import Path +from numpy import mean, std -import sys -sys.path.insert(1, './') +project_dir = "/root/DL-Fairness-Study" +sys.path.insert(1, os.path.join(project_dir, "BM")) -from debias.datasets.utk_face import get_utk_face -from debias.networks.resnet import FCResNet18 from debias.utils.logging import set_logging -from debias.utils.utils import (AverageMeter, MultiDimAverageMeter, accuracy, - pretty_dict, save_model, set_seed) +from debias.networks.resnet import FCResNet18 +from debias.datasets.utk_face import get_utk_face +from debias.utils.utils import AverageMeter, MultiDimAverageMeter, accuracy, pretty_dict, save_model, set_seed -sys.path.insert(1, '/root/study') +sys.path.insert(1, project_dir) -from numpy import mean, std +from arguments import get_args from metrics import get_metric_index, get_all_metrics, print_all_metrics -def parse_option(): - parser = argparse.ArgumentParser() - parser.add_argument('--exp_name', type=str, default='test') - parser.add_argument('--gpu', type=int, default=0) - parser.add_argument('--task', type=str, default='race') - - parser.add_argument('--epochs', type=int, default=20) - parser.add_argument('--seed', type=int, default=1) - - parser.add_argument('--bs', type=int, default=128, help='batch_size') - parser.add_argument('--lr', type=float, default=1e-3) - - opt = parser.parse_args() - os.environ['CUDA_VISIBLE_DEVICES'] = str(opt.gpu) - - return opt - - def set_model(): model = FCResNet18().cuda() - criterion = nn.CrossEntropyLoss(reduction = 'none') + criterion = nn.CrossEntropyLoss(reduction="none") return model, criterion @@ -90,92 +71,114 @@ def validate(val_loader, model): output, _ = model(images) preds = output.data.max(1, keepdim=True)[1].squeeze(1) - acc1, = accuracy(output, labels, topk=(1,)) + (acc1,) = accuracy(output, labels, topk=(1,)) top1.update(acc1[0], bsz) corrects = (preds == labels).long() attrwise_acc_meter.add(corrects.cpu(), torch.stack([labels.cpu(), biases.cpu()], dim=1)) - return top1.avg, attrwise_acc_meter.get_mean(), attrwise_acc_meter.get_acc_diff() + return top1.avg, attrwise_acc_meter.get_mean(), attrwise_acc_meter.get_acc_diff() def main(): - opt = parse_option() + opt = get_args() + exp_name = f"uw-utkface_{opt.sensitive}-lr{opt.lr}-bs{opt.batch_size}-epochs{opt.epochs}-seed{opt.seed}" - exp_name = f'uw-utk_face_{opt.task}-{opt.exp_name}-lr{opt.lr}-bs{opt.bs}-seed{opt.seed}' - opt.exp_name = exp_name + # result_dir = f"../results/utkface" + # result_path = Path(result_dir) + # result_path.mkdir(parents=True, exist_ok=True) + # if opt.sensitive == "age": + # fout = open("/".join([str(result_path), "uw_age_gender.txt"]), "w") + # elif opt.sensitive == "race": + # fout = open("/".join([str(result_path), "uw_race_gender.txt"]), "w") - result_dir = f'../results/utkface' - result_path = Path(result_dir) - result_path.mkdir(parents=True, exist_ok=True) - if opt.task == 'age': - fout = open('/'.join([str(result_path), 'uw_age_gender.txt']), 'w') - elif opt.task == 'race': - fout = open('/'.join([str(result_path), 'uw_race_gender.txt']), 'w') + # results = {} + # metric_index = get_metric_index() + # for m_index in metric_index: + # results[m_index] = [] - results = {} - metric_index = get_metric_index() - for m_index in metric_index: - results[m_index] = [] + repeat_time = 1 - repeat_time = 10 - - output_dir = f'exp_results/{exp_name}' + output_dir = f"{project_dir}/checkpoints/{exp_name}" save_path = Path(output_dir) save_path.mkdir(parents=True, exist_ok=True) - set_logging(exp_name, 'INFO', str(save_path)) - logging.info(f'Set seed: {opt.seed}') + print(f"Set seed: {opt.seed}") set_seed(opt.seed) - logging.info(f'save_path: {save_path}') + print(f"save_path: {save_path}") np.set_printoptions(precision=3) torch.set_printoptions(precision=3) - root = '../data/utkface' + root = f"{project_dir}/data/utkface" train_loader = get_utk_face( root, - batch_size=opt.bs, - bias_attr=opt.task, - split='train', - aug=False, ) + batch_size=opt.batch_size, + bias_attr=opt.sensitive, + split="train", + aug=False, + ) val_loaders = {} - val_loaders['valid'] = get_utk_face( - root, - batch_size=256, - bias_attr=opt.task, - split='valid', - aug=False) + val_loaders["valid"] = get_utk_face(root, batch_size=256, bias_attr=opt.sensitive, split="valid", aug=False) - val_loaders['test'] = get_utk_face( - root, - batch_size=256, - bias_attr=opt.task, - split='test', - aug=False) + val_loaders["test"] = get_utk_face(root, batch_size=256, bias_attr=opt.sensitive, split="test", aug=False) for r in range(repeat_time): - logging.info(f'Repeated experiment: {r+1}') + # print(f"Repeated experiment: {r+1}") model, criterion = set_model() + # Evaluation + if opt.checkpoint: + model.load_state_dict(torch.load(f"{save_path}/best_model.pt")["model"]) + model.eval() + + with torch.no_grad(): + all_labels, all_biases, all_preds = [], [], [] + for images, labels, _, biases, _, _ in val_loaders["test"]: + images = images.cuda() + output, _ = model(images) + preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() + + all_labels.append(labels) + all_biases.append(biases) + all_preds.append(preds) + + fin_labels = torch.cat(all_labels) + fin_biases = torch.cat(all_biases) + fin_preds = torch.cat(all_preds) + + ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) + print_all_metrics(ret=ret) + + sys.exit() + + # ret["time per epoch"] = total_time / opt.epochs + # for i in range(len(metric_index)): + # results[metric_index[i]].append(ret[metric_index[i]]) + + # for m_index in metric_index: + # fout.write(m_index + "\t") + # for i in range(repeat_time): + # fout.write("%f\t" % results[m_index][i]) + # fout.write("%f\t%f\n" % (mean(results[m_index]), std(results[m_index]))) + # fout.close() + decay_epochs = [opt.epochs // 3, opt.epochs * 2 // 3] optimizer = torch.optim.Adam(model.parameters(), lr=opt.lr, weight_decay=1e-4) scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=decay_epochs, gamma=0.1) - logging.info(f'decay_epochs: {decay_epochs}') - - # (save_path / 'checkpoints').mkdir(parents=True, exist_ok=True) + print(f"decay_epochs: {decay_epochs}") - best_accs = {'valid': 0, 'test': 0} - best_epochs = {'valid': 0, 'test': 0} + best_accs = {"valid": 0, "test": 0} + best_epochs = {"valid": 0, "test": 0} best_stats = {} start_time = time.time() for epoch in range(1, opt.epochs + 1): - logging.info(f'[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}') + print(f"[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}") loss = train(train_loader, model, criterion, optimizer) - logging.info(f'[{epoch} / {opt.epochs}] Loss: {loss:.4f}') + print(f"[{epoch} / {opt.epochs}] Loss: {loss:.4f}") scheduler.step() @@ -183,61 +186,34 @@ def main(): for key, val_loader in val_loaders.items(): accs, valid_attrwise_accs, diff = validate(val_loader, model) - stats[f'{key}/acc'] = accs.item() - stats[f'{key}/acc_unbiased'] = torch.mean(valid_attrwise_accs).item() * 100 - stats[f'{key}/diff'] = diff.item() * 100 + stats[f"{key}/acc"] = accs.item() + stats[f"{key}/acc_unbiased"] = torch.mean(valid_attrwise_accs).item() * 100 + stats[f"{key}/diff"] = diff.item() * 100 - eye_tsr = train_loader.dataset.eye_tsr + eye_tsr = train_loader.dataset.eye_tsr - stats[f'{key}/acc_skew'] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 - stats[f'{key}/acc_align'] = valid_attrwise_accs[eye_tsr == 0.0].mean().item() * 100 + stats[f"{key}/acc_skew"] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 + stats[f"{key}/acc_align"] = valid_attrwise_accs[eye_tsr == 0.0].mean().item() * 100 - logging.info(f'[{epoch} / {opt.epochs}] {valid_attrwise_accs} {stats}') + print(f"[{epoch} / {opt.epochs}] {valid_attrwise_accs} {stats}") for tag in val_loaders.keys(): - if stats[f'{tag}/acc_unbiased'] > best_accs[tag]: - best_accs[tag] = stats[f'{tag}/acc_unbiased'] + if stats[f"{tag}/acc_unbiased"] > best_accs[tag]: + best_accs[tag] = stats[f"{tag}/acc_unbiased"] best_epochs[tag] = epoch - best_stats[tag] = pretty_dict(**{f'best_{tag}_{k}': v for k, v in stats.items()}) + best_stats[tag] = pretty_dict(**{f"best_{tag}_{k}": v for k, v in stats.items()}) + + print( + f"[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}" + ) - logging.info( - f'[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}') + save_file = save_path / "best_model.pt" + save_model(model, optimizer, opt, epoch, save_file) total_time = time.time() - start_time total_time_str = str(datetime.timedelta(seconds=int(total_time))) - logging.info(f'Total training time: {total_time_str}') - - # Evaluation - model.eval() - - with torch.no_grad(): - all_labels, all_biases, all_preds = [], [], [] - for images, labels, _, biases, _, _ in val_loaders['test']: - images = images.cuda() - output, _ = model(images) - preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() - - all_labels.append(labels) - all_biases.append(biases) - all_preds.append(preds) - - fin_labels = torch.cat(all_labels) - fin_biases = torch.cat(all_biases) - fin_preds = torch.cat(all_preds) - - ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) - print_all_metrics(ret=ret) - - ret['time per epoch'] = total_time / opt.epochs - for i in range(len(metric_index)): - results[metric_index[i]].append(ret[metric_index[i]]) - - for m_index in metric_index: - fout.write(m_index + '\t') - for i in range(repeat_time): - fout.write('%f\t' % results[m_index][i]) - fout.write('%f\t%f\n' % (mean(results[m_index]), std(results[m_index]))) - fout.close() + print(f"Total training time: {total_time_str}") + print(f"Time per epoch: {total_time / opt.epochs:.6f}") -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/FAAP/arguments.py b/FAAP/arguments.py deleted file mode 100644 index 47d8d31..0000000 --- a/FAAP/arguments.py +++ /dev/null @@ -1,27 +0,0 @@ -import os -import argparse - - -def get_args(): - parser = argparse.ArgumentParser(description="Fairness") - - parser.add_argument("--gpu", default=0, type=int, help="CUDA visible device") - parser.add_argument("--date", default="230929", type=str, help="experiment date") - parser.add_argument("--model", default="resnet18", type=str, choices=["resnet18"]) - parser.add_argument("--data-dir", default="../data", type=str, help="data directory") - parser.add_argument("--target", default="Blond_Hair", type=str, help="target attribute for celeba") - parser.add_argument("--sensitive", default="race", type=str, help="sensitive attribute for utkface") - parser.add_argument("--pretrained", default=False, action="store_true", help="load pre-trained model") - parser.add_argument("--dataset", default="celeba", type=str, choices=["celeba", "utkface", "cifar10s"]) - parser.add_argument("--save-dir", default="./saved_models", type=str, help="directory to save trained models)") - - parser.add_argument("--lr", default=1e-3, type=float, help="learning rate") - parser.add_argument("--seed", default=1, type=int, help="seed for randomness") - parser.add_argument("--batch-size", default=64, type=int, help="mini batch size") - parser.add_argument("--epochs", default=100, type=int, help="number of training epochs") - parser.add_argument("--img-size", default=224, type=int, help="image size for preprocessing") - - args = parser.parse_args() - os.environ["CUDA_VISIBLE_DEVICES"] = str(args.gpu) - - return args diff --git a/datasets/__init__.py b/FAAP/datasets/__init__.py similarity index 100% rename from datasets/__init__.py rename to FAAP/datasets/__init__.py diff --git a/datasets/celeba.py b/FAAP/datasets/celeba.py similarity index 100% rename from datasets/celeba.py rename to FAAP/datasets/celeba.py diff --git a/datasets/cifar10s.py b/FAAP/datasets/cifar10s.py similarity index 100% rename from datasets/cifar10s.py rename to FAAP/datasets/cifar10s.py diff --git a/datasets/utkface.py b/FAAP/datasets/utkface.py similarity index 98% rename from datasets/utkface.py rename to FAAP/datasets/utkface.py index cc1a467..be85c7d 100644 --- a/datasets/utkface.py +++ b/FAAP/datasets/utkface.py @@ -31,7 +31,7 @@ def __init__(self, root, split, transform, bias_attr, bias_rate=0.9): data_split = "train" if self.train else "test" self.files, self.targets, self.bias_targets = pickle.load(open(save_path / f"{data_split}_dataset.pkl", "rb")) if split in ["valid", "test"]: - save_path = Path(f"/root/study/data/clusters/utk_face_rand_indices_{bias_attr}.pkl") + save_path = Path(f"{Path(root).parent.absolute()}/clusters/utk_face_rand_indices_{bias_attr}.pkl") if not save_path.exists(): rand_indices = torch.randperm(len(self.targets)) pickle.dump(rand_indices, open(save_path, "wb")) diff --git a/FAAP/faap.py b/FAAP/faap.py index 08b1c32..3112cd3 100644 --- a/FAAP/faap.py +++ b/FAAP/faap.py @@ -1,22 +1,24 @@ import os import sys import time -import numpy as np -from pathlib import Path - import torch +import numpy as np import torch.nn as nn import torch.nn.functional as F -from torch.distributions import Categorical -from arguments import get_args -from models import Discriminator, Generator, ResNet18 +from pathlib import Path +from torch.distributions import Categorical -sys.path.insert(1, "/root/study") +project_dir = "/root/DL-Fairness-Study" +sys.path.insert(1, os.path.join(project_dir, "FAAP")) from datasets.celeba import get_celeba from datasets.utkface import get_utkface from datasets.cifar10s import get_cifar10s -from helper import set_seed, make_log_name +from models import Discriminator, Generator, ResNet18 + +sys.path.insert(1, project_dir) +from helper import set_seed +from arguments import get_args args = get_args() @@ -32,17 +34,16 @@ def init_weights(m): class FAAP: - def __init__(self, model, device, save_dir, log_name, epochs, channels=3, box_min=-1, box_max=1): + def __init__(self, model, save_dir, log_name, epochs, channels=3, box_min=-1, box_max=1): self.model = model - self.device = device self.save_dir = save_dir self.log_name = log_name self.epochs = epochs self.box_min = box_min self.box_max = box_max - self.netG = Generator(channels).to(device) - self.netD = Discriminator().to(device) + self.netG = Generator(channels).cuda() + self.netD = Discriminator().cuda() # Initialize all weights self.netG.apply(init_weights) @@ -108,7 +109,7 @@ def train(self, train_dataloader): for images, labels, biases in train_dataloader: # if epoch == 1: # print(images, images.shape) - images, labels, biases = images.to(self.device), labels.to(self.device), biases.to(self.device) + images, labels, biases = images.cuda(), labels.cuda(), biases.cuda() loss_D_batch, loss_G_batch = self.train_batch(images, labels, biases) @@ -119,8 +120,8 @@ def train(self, train_dataloader): print("Epoch %d:\nloss_D: %.3f, loss_G: %.3f\n" % (epoch, loss_D_sum / num_batch, loss_G_sum / num_batch)) # Save generators - if epoch > self.epochs - 10: - netG_filename = os.path.join(self.save_dir, f"{self.log_name}_epoch{str(epoch)}.pt") + if epoch == self.epochs: + netG_filename = Path(f"{self.log_name}/best_model.pt") torch.save(self.netG.state_dict(), netG_filename) @@ -131,58 +132,61 @@ def train(self, train_dataloader): np.set_printoptions(precision=3) torch.set_printoptions(precision=3, sci_mode=False) - save_dir = Path(f"{args.save_dir}/{args.date}") + if args.dataset in ["celeba", "cifar10s"]: + exp_name = f"faap-{args.dataset}-lr{args.lr}-bs{args.batch_size}-epochs{args.epochs}-seed{args.seed}" + elif args.dataset == "utkface": + exp_name = f"faap-utkface_{args.sensitive}-lr{args.lr}-bs{args.batch_size}-epochs{args.epochs}-seed{args.seed}" + save_dir = Path(f"{project_dir}/checkpoints/{exp_name}") save_dir.mkdir(parents=True, exist_ok=True) - log_name_d = make_log_name(args, model_name="deployed_model") - log_name_g = make_log_name(args, model_name="generator") + data_dir = f"{project_dir}/data" + log_name_g = f"{project_dir}/checkpoints/{exp_name}" + print(f"log name of generator: {log_name_g}") + log_name_d = f"{project_dir}/checkpoints/{args.model_path}" + print(f"log name of deployed model: {log_name_d}") num_classes = 10 if args.dataset == "cifar10s" else 2 - # Define what device we are using - print("CUDA Available: ", torch.cuda.is_available()) - device = torch.device("cuda" if torch.cuda.is_available() else "cpu") - # Load datasets - data_dir = f"{args.data_dir}/{args.dataset}" + dataset_dir = f"{data_dir}/{args.dataset}" if args.dataset == "celeba": train_dataset, train_loader = get_celeba( - root=args.data_dir, split="train", target_attr=args.target, img_size=args.img_size, batch_size=args.batch_size + root=data_dir, split="train", target_attr=args.target, img_size=args.img_size, batch_size=args.batch_size ) valid_dataset, valid_loader = get_celeba( - root=args.data_dir, split="valid", target_attr=args.target, img_size=args.img_size, batch_size=args.batch_size + root=data_dir, split="valid", target_attr=args.target, img_size=args.img_size, batch_size=args.batch_size ) test_dataset, test_loader = get_celeba( - root=args.data_dir, split="test", target_attr=args.target, img_size=args.img_size, batch_size=args.batch_size + root=data_dir, split="test", target_attr=args.target, img_size=args.img_size, batch_size=args.batch_size ) elif args.dataset == "utkface": train_dataset, train_loader = get_utkface( - root=data_dir, split="train", bias_attr=args.sensitive, img_size=args.img_size, batch_size=args.batch_size + root=dataset_dir, split="train", bias_attr=args.sensitive, img_size=args.img_size, batch_size=args.batch_size ) valid_dataset, valid_loader = get_utkface( - root=data_dir, split="valid", bias_attr=args.sensitive, img_size=args.img_size, batch_size=args.batch_size + root=dataset_dir, split="valid", bias_attr=args.sensitive, img_size=args.img_size, batch_size=args.batch_size ) test_dataset, test_loader = get_utkface( - root=data_dir, split="test", bias_attr=args.sensitive, img_size=args.img_size, batch_size=args.batch_size + root=dataset_dir, split="test", bias_attr=args.sensitive, img_size=args.img_size, batch_size=args.batch_size ) elif args.dataset == "cifar10s": - train_dataset, train_loader = get_cifar10s(root=data_dir, split="train", img_size=args.img_size, batch_size=args.batch_size) - valid_dataset, valid_loader = get_cifar10s(root=data_dir, split="valid", img_size=args.img_size, batch_size=args.batch_size) - test_dataset, test_loader = get_cifar10s(root=data_dir, split="test", img_size=args.img_size, batch_size=args.batch_size) - - ckpt_path = os.path.join(save_dir, log_name_d + ".pt") - - deployed_model = ResNet18(num_classes=num_classes, pretrained=False).to(device) - deployed_model.load_state_dict(torch.load(ckpt_path, map_location=device)) + train_dataset, train_loader = get_cifar10s(root=dataset_dir, split="train", img_size=args.img_size, batch_size=args.batch_size) + valid_dataset, valid_loader = get_cifar10s(root=dataset_dir, split="valid", img_size=args.img_size, batch_size=args.batch_size) + test_dataset, test_loader = get_cifar10s(root=dataset_dir, split="test", img_size=args.img_size, batch_size=args.batch_size) + + ckpt_path = f"{log_name_d}/best_model.pt" + print(ckpt_path) + deployed_model = ResNet18(num_classes=num_classes, pretrained=False).cuda() + deployed_model.load_state_dict(torch.load(ckpt_path)) deployed_model.eval() start_time = time.time() if args.dataset == "celeba": - faap = FAAP(deployed_model, device, save_dir, log_name_g, args.epochs, channels=3, box_min=0, box_max=1) + faap = FAAP(deployed_model, save_dir, log_name_g, args.epochs, channels=3, box_min=0, box_max=1) elif args.dataset == "utkface": - faap = FAAP(deployed_model, device, save_dir, log_name_g, args.epochs, channels=3, box_min=0, box_max=1) + faap = FAAP(deployed_model, save_dir, log_name_g, args.epochs, channels=3, box_min=0, box_max=1) elif args.dataset == "cifar10s": - faap = FAAP(deployed_model, device, save_dir, log_name_g, args.epochs, channels=3, box_min=-1, box_max=1) + faap = FAAP(deployed_model, save_dir, log_name_g, args.epochs, channels=3, box_min=-1, box_max=1) faap.train(train_loader) diff --git a/FAAP/test_adversarial_examples.py b/FAAP/test_adversarial_examples.py index 2df4eae..f49d536 100644 --- a/FAAP/test_adversarial_examples.py +++ b/FAAP/test_adversarial_examples.py @@ -4,14 +4,17 @@ from pathlib import Path from numpy import mean, std -from arguments import get_args -from models import Generator, ResNet18 +project_dir = "/root/DL-Fairness-Study" +sys.path.insert(1, os.path.join(project_dir, "FAAP")) -sys.path.insert(1, "/root/study") +from models import Generator, ResNet18 from datasets.celeba import get_celeba from datasets.utkface import get_utkface from datasets.cifar10s import get_cifar10s -from helper import set_seed, make_log_name + +sys.path.insert(1, project_dir) +from helper import set_seed +from arguments import get_args from metrics import get_metric_index, get_all_metrics, print_all_metrics args = get_args() @@ -21,13 +24,13 @@ def test_adv(args): print(args) set_seed(args.seed) - save_dir = Path(f"{args.save_dir}/{args.date}") + if args.dataset in ["celeba", "cifar10s"]: + exp_name = f"faap-{args.dataset}-lr{args.lr}-bs{args.batch_size}-epochs{args.epochs}-seed{args.seed}" + elif args.dataset == "utkface": + exp_name = f"faap-utkface_{args.sensitive}-lr{args.lr}-bs{args.batch_size}-epochs{args.epochs}-seed{args.seed}" + save_dir = Path(f"{project_dir}/checkpoints/{exp_name}") save_dir.mkdir(parents=True, exist_ok=True) - # Define what device we are using - print("CUDA Available: ", torch.cuda.is_available()) - device = torch.device("cuda" if torch.cuda.is_available() else "cpu") - # result_dir = f"../results/{args.dataset}" # result_path = Path(result_dir) # result_path.mkdir(parents=True, exist_ok=True) @@ -47,43 +50,45 @@ def test_adv(args): # for m_index in metric_index: # results[m_index] = [] - start_epoch = args.epochs - 9 - - log_name_d = make_log_name(args, model_name="deployed_model") - log_name_g = make_log_name(args, model_name="generator") + data_dir = f"{project_dir}/data" + log_name_g = f"{project_dir}/checkpoints/{exp_name}" + print(f"log name of generator: {log_name_g}") + log_name_d = f"{project_dir}/checkpoints/{args.model_path}" + print(f"log name of deployed model: {log_name_d}") num_classes = 10 if args.dataset == "cifar10s" else 2 # Load datasets - data_dir = f"{args.data_dir}/{args.dataset}" + dataset_dir = f"{data_dir}/{args.dataset}" if args.dataset == "celeba": train_dataset, train_loader = get_celeba( - root=args.data_dir, split="train", target_attr=args.target, img_size=args.img_size, batch_size=args.batch_size + root=data_dir, split="train", target_attr=args.target, img_size=args.img_size, batch_size=args.batch_size ) valid_dataset, valid_loader = get_celeba( - root=args.data_dir, split="valid", target_attr=args.target, img_size=args.img_size, batch_size=args.batch_size + root=data_dir, split="valid", target_attr=args.target, img_size=args.img_size, batch_size=args.batch_size ) test_dataset, test_loader = get_celeba( - root=args.data_dir, split="test", target_attr=args.target, img_size=args.img_size, batch_size=args.batch_size + root=data_dir, split="test", target_attr=args.target, img_size=args.img_size, batch_size=args.batch_size ) elif args.dataset == "utkface": train_dataset, train_loader = get_utkface( - root=data_dir, split="train", bias_attr=args.sensitive, img_size=args.img_size, batch_size=args.batch_size + root=dataset_dir, split="train", bias_attr=args.sensitive, img_size=args.img_size, batch_size=args.batch_size ) valid_dataset, valid_loader = get_utkface( - root=data_dir, split="valid", bias_attr=args.sensitive, img_size=args.img_size, batch_size=args.batch_size + root=dataset_dir, split="valid", bias_attr=args.sensitive, img_size=args.img_size, batch_size=args.batch_size ) test_dataset, test_loader = get_utkface( - root=data_dir, split="test", bias_attr=args.sensitive, img_size=args.img_size, batch_size=args.batch_size + root=dataset_dir, split="test", bias_attr=args.sensitive, img_size=args.img_size, batch_size=args.batch_size ) elif args.dataset == "cifar10s": - train_dataset, train_loader = get_cifar10s(root=data_dir, split="train", img_size=args.img_size, batch_size=args.batch_size) - valid_dataset, valid_loader = get_cifar10s(root=data_dir, split="valid", img_size=args.img_size, batch_size=args.batch_size) - test_dataset, test_loader = get_cifar10s(root=data_dir, split="test", img_size=args.img_size, batch_size=args.batch_size) + train_dataset, train_loader = get_cifar10s(root=dataset_dir, split="train", img_size=args.img_size, batch_size=args.batch_size) + valid_dataset, valid_loader = get_cifar10s(root=dataset_dir, split="valid", img_size=args.img_size, batch_size=args.batch_size) + test_dataset, test_loader = get_cifar10s(root=dataset_dir, split="test", img_size=args.img_size, batch_size=args.batch_size) # Load the pretrained models - ckpt_path = os.path.join(save_dir, log_name_d + ".pt") - deployed_model = ResNet18(num_classes=num_classes, pretrained=False).to(device) - deployed_model.load_state_dict(torch.load(ckpt_path, map_location=device)) + ckpt_path = f"{log_name_d}/best_model.pt" + print(ckpt_path) + deployed_model = ResNet18(num_classes=num_classes, pretrained=False).cuda() + deployed_model.load_state_dict(torch.load(ckpt_path)) deployed_model.eval() # Test original test dataset @@ -91,7 +96,7 @@ def test_adv(args): with torch.no_grad(): all_labels, all_biases, all_preds = [], [], [] for images, labels, biases in test_loader: - images = images.to(device) + images = images.cuda() logits, _ = deployed_model(images) preds = torch.argmax(logits.data, 1).cpu() @@ -110,48 +115,45 @@ def test_adv(args): ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) print_all_metrics(ret=ret) - for epoch in range(start_epoch, args.epochs + 1): - print(f"Epoch: {epoch}") - - # Load the generators - ckpt_path_G = os.path.join(save_dir, log_name_g + f"_epoch{epoch}.pt") - print(f"Load checkpoint: {ckpt_path_G}") - netG = Generator().to(device) - netG.load_state_dict(torch.load(ckpt_path_G)) - netG.eval() - - # Test adversarial examples in test dataset - num_correct = 0 - with torch.no_grad(): - all_labels, all_biases, all_preds = [], [], [] - for images, labels, biases in test_loader: - images = images.to(device) - perturbation = netG(images) - perturbation = torch.clamp(perturbation, -0.05, 0.05) - adv_img = perturbation + images - if args.dataset == "celeba": - adv_img = torch.clamp(adv_img, 0, 1) - elif args.dataset == "utkface": - adv_img = torch.clamp(adv_img, 0, 1) - elif args.dataset == "cifar10s": - adv_img = torch.clamp(adv_img, -1, 1) - - logits, _ = deployed_model(adv_img) - preds = torch.argmax(logits.data, 1).cpu() - num_correct += torch.sum(preds == labels) - - all_labels.append(labels) - all_biases.append(biases) - all_preds.append(preds) - - print("accuracy of adversarial images in test dataset: %.3f\n" % (num_correct.item() / len(test_dataset))) - - fin_labels = torch.cat(all_labels) - fin_biases = torch.cat(all_biases) - fin_preds = torch.cat(all_preds) - - ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) - print_all_metrics(ret=ret) + # Load the generators + ckpt_path_G = f"{log_name_g}/best_model.pt" + print(f"Load checkpoint: {ckpt_path_G}") + netG = Generator().cuda() + netG.load_state_dict(torch.load(ckpt_path_G)) + netG.eval() + + # Test adversarial examples in test dataset + num_correct = 0 + with torch.no_grad(): + all_labels, all_biases, all_preds = [], [], [] + for images, labels, biases in test_loader: + images = images.cuda() + perturbation = netG(images) + perturbation = torch.clamp(perturbation, -0.05, 0.05) + adv_img = perturbation + images + if args.dataset == "celeba": + adv_img = torch.clamp(adv_img, 0, 1) + elif args.dataset == "utkface": + adv_img = torch.clamp(adv_img, 0, 1) + elif args.dataset == "cifar10s": + adv_img = torch.clamp(adv_img, -1, 1) + + logits, _ = deployed_model(adv_img) + preds = torch.argmax(logits.data, 1).cpu() + num_correct += torch.sum(preds == labels) + + all_labels.append(labels) + all_biases.append(biases) + all_preds.append(preds) + + print("accuracy of adversarial images in test dataset: %.3f\n" % (num_correct.item() / len(test_dataset))) + + fin_labels = torch.cat(all_labels) + fin_biases = torch.cat(all_biases) + fin_preds = torch.cat(all_preds) + + ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) + print_all_metrics(ret=ret) if __name__ == "__main__": diff --git a/FAAP/train_deployed_model.py b/FAAP/train_deployed_model.py index 27f55f0..794db02 100644 --- a/FAAP/train_deployed_model.py +++ b/FAAP/train_deployed_model.py @@ -5,14 +5,17 @@ from pathlib import Path from copy import deepcopy -from models import ResNet18 -from arguments import get_args +project_dir = "/root/DL-Fairness-Study" +sys.path.insert(1, os.path.join(project_dir, "FAAP")) -sys.path.insert(1, "/root/study") +from models import ResNet18 from datasets.celeba import get_celeba from datasets.utkface import get_utkface from datasets.cifar10s import get_cifar10s -from helper import set_seed, make_log_name + +sys.path.insert(1, project_dir) +from helper import set_seed +from arguments import get_args args = get_args() @@ -75,42 +78,42 @@ def main(): print(args) set_seed(args.seed) - save_dir = Path(f"{args.save_dir}/{args.date}") + if args.dataset in ["celeba", "cifar10s"]: + exp_name = f"deployed-{args.dataset}-lr{args.lr}-bs{args.batch_size}-epochs{args.epochs}-seed{args.seed}" + elif args.dataset == "utkface": + exp_name = f"deployed-utkface_{args.sensitive}-lr{args.lr}-bs{args.batch_size}-epochs{args.epochs}-seed{args.seed}" + save_dir = Path(f"{project_dir}/checkpoints/{exp_name}") save_dir.mkdir(parents=True, exist_ok=True) - log_name = make_log_name(args, model_name="deployed_model") + data_dir = f"{project_dir}/data" num_classes = 10 if args.dataset == "cifar10s" else 2 - # Define what device we are using - print("CUDA Available: ", torch.cuda.is_available()) - device = torch.device("cuda" if torch.cuda.is_available() else "cpu") - # Load datasets - data_dir = f"{args.data_dir}/{args.dataset}" + dataset_dir = f"{data_dir}/{args.dataset}" if args.dataset == "celeba": train_dataset, train_loader = get_celeba( - root=args.data_dir, split="train", target_attr=args.target, img_size=args.img_size, batch_size=args.batch_size + root=data_dir, split="train", target_attr=args.target, img_size=args.img_size, batch_size=args.batch_size ) valid_dataset, valid_loader = get_celeba( - root=args.data_dir, split="valid", target_attr=args.target, img_size=args.img_size, batch_size=args.batch_size + root=data_dir, split="valid", target_attr=args.target, img_size=args.img_size, batch_size=args.batch_size ) test_dataset, test_loader = get_celeba( - root=args.data_dir, split="test", target_attr=args.target, img_size=args.img_size, batch_size=args.batch_size + root=data_dir, split="test", target_attr=args.target, img_size=args.img_size, batch_size=args.batch_size ) elif args.dataset == "utkface": train_dataset, train_loader = get_utkface( - root=data_dir, split="train", bias_attr=args.sensitive, img_size=args.img_size, batch_size=args.batch_size + root=dataset_dir, split="train", bias_attr=args.sensitive, img_size=args.img_size, batch_size=args.batch_size ) valid_dataset, valid_loader = get_utkface( - root=data_dir, split="valid", bias_attr=args.sensitive, img_size=args.img_size, batch_size=args.batch_size + root=dataset_dir, split="valid", bias_attr=args.sensitive, img_size=args.img_size, batch_size=args.batch_size ) test_dataset, test_loader = get_utkface( - root=data_dir, split="test", bias_attr=args.sensitive, img_size=args.img_size, batch_size=args.batch_size + root=dataset_dir, split="test", bias_attr=args.sensitive, img_size=args.img_size, batch_size=args.batch_size ) elif args.dataset == "cifar10s": - train_dataset, train_loader = get_cifar10s(root=data_dir, split="train", img_size=args.img_size, batch_size=args.batch_size) - valid_dataset, valid_loader = get_cifar10s(root=data_dir, split="valid", img_size=args.img_size, batch_size=args.batch_size) - test_dataset, test_loader = get_cifar10s(root=data_dir, split="test", img_size=args.img_size, batch_size=args.batch_size) + train_dataset, train_loader = get_cifar10s(root=dataset_dir, split="train", img_size=args.img_size, batch_size=args.batch_size) + valid_dataset, valid_loader = get_cifar10s(root=dataset_dir, split="valid", img_size=args.img_size, batch_size=args.batch_size) + test_dataset, test_loader = get_cifar10s(root=dataset_dir, split="test", img_size=args.img_size, batch_size=args.batch_size) # Train the deployed model deployed_model = ResNet18(num_classes=num_classes, pretrained=args.pretrained).cuda() @@ -156,7 +159,7 @@ def main(): print("Test Accuracy: %.3f" % (test_acc)) # Save the best model - save_file = os.path.join(save_dir, log_name + ".pt") + save_file = os.path.join(f"{save_dir}/best_model.pt") torch.save(best_deployed_model.state_dict(), save_file) diff --git a/FDR/celeba.py b/FDR/celeba.py index 53faac1..2b76da7 100644 --- a/FDR/celeba.py +++ b/FDR/celeba.py @@ -1,63 +1,48 @@ +import os import sys import time +import torch import argparse import datetime import numpy as np +import torch.nn as nn from pathlib import Path from copy import deepcopy from numpy import mean, std - -import torch -import torch.nn as nn -import torch.optim as optim import torch.nn.functional as F from torchvision import datasets from torchvision import transforms from torch.utils.data import TensorDataset - -from fairlearn.metrics import ( - equalized_odds_difference, - equalized_odds_ratio, - equalized_odds_difference, -) from sklearn.metrics import balanced_accuracy_score +from fairlearn.metrics import equalized_odds_difference, equalized_odds_ratio, equalized_odds_difference + +project_dir = "/root/DL-Fairness-Study" +sys.path.insert(1, os.path.join(project_dir, "FDR")) from utils import * from models import MyResNet -sys.path.insert(1, "/root/study") +sys.path.insert(1, project_dir) from helper import set_seed +from arguments import get_args from metrics import get_metric_index, get_all_metrics, print_all_metrics -parser = argparse.ArgumentParser(description="fairness") -parser.add_argument("--method", type=str, default="M2") -parser.add_argument("--ft_epoch", type=int, default=1000) -parser.add_argument("--ft_lr", type=float, default=1e-3) -parser.add_argument("--alpha", type=float, default=2.0) -parser.add_argument("--constraint", type=str, default="EO") -parser.add_argument("--seed", type=int, default=1) -parser.add_argument("--data_path", type=str, default="../data") -parser.add_argument("--batch_size", type=int, default=-1) -parser.add_argument("--checkpoint", type=str, default=None) -args = parser.parse_args() +args = get_args() set_seed(args.seed) print(args) -device = torch.device("cuda" if torch.cuda.is_available() else "cpu") -print(device) - -result_dir = f"../results/celeba" -result_path = Path(result_dir) -result_path.mkdir(parents=True, exist_ok=True) -fout = open("/".join([str(result_path), f"fdr_{args.constraint.lower()}_gender_blond_hair.txt"]), "w") +# result_dir = f"../results/celeba" +# result_path = Path(result_dir) +# result_path.mkdir(parents=True, exist_ok=True) +# fout = open("/".join([str(result_path), f"fdr_{args.constraint.lower()}_gender_blond_hair.txt"]), "w") -results = {} -metric_index = get_metric_index() -for m_index in metric_index: - results[m_index] = [] +# results = {} +# metric_index = get_metric_index() +# for m_index in metric_index: +# results[m_index] = [] -repeat_time = 10 +repeat_time = 1 ###################### # Data Preprocessing # @@ -75,7 +60,7 @@ ######################### # CelebA dataset (could be slow!) -data_root = args.data_path +data_root = Path(f"{project_dir}/data") train_dataset = datasets.CelebA(data_root, split="train", target_type=["attr"], transform=transform) valid_dataset = datasets.CelebA(data_root, split="valid", target_type=["attr"], transform=transform) test_dataset = datasets.CelebA(data_root, split="test", target_type=["attr"], transform=transform) @@ -100,7 +85,7 @@ def train_per_epoch(model, optimizer, criterion, epoch, num_epochs): optimizer.zero_grad() # move to GPU - images, labels = images.to(device), labels[:, 9].to(device) + images, labels = images.cuda(), labels[:, 9].cuda() # if batch_idx == 0: # print(images.shape, labels.shape) @@ -130,7 +115,7 @@ def valid_per_epoch(model, epoch, num_epochs, criterion): for batch_idx, (images, labels) in enumerate(valloader): # move to GPU - images, labels = images.to(device), labels[:, 9].to(device) + images, labels = images.cuda(), labels[:, 9].cuda() # forward outputs = model.forward(images) @@ -154,7 +139,8 @@ def Finetune(model, criterion, trainloader, valloader, testloader): model.eval() best_clf = None - method = args.method + method = args.finetune_method + print(f"Finetune method: {method}") ################################################### # Option 1 (B1): Directly test @@ -167,13 +153,13 @@ def Finetune(model, criterion, trainloader, valloader, testloader): ################ # Prepare the dataset ################ - x_train, y_train, a_train = prepare_data(trainloader, model, device) + x_train, y_train, a_train = prepare_data(trainloader, model) print(x_train.shape, y_train.shape, a_train.shape) - x_test, y_test, a_test = prepare_data(testloader, model, device) + x_test, y_test, a_test = prepare_data(testloader, model) print(x_test.shape, y_test.shape, a_test.shape) - x_finetune, y_finetune, a_finetune = prepare_data(valloader, model, device) + x_finetune, y_finetune, a_finetune = prepare_data(valloader, model) print(x_finetune.shape, y_finetune.shape, a_finetune.shape) if method == "B1": @@ -209,10 +195,10 @@ def Finetune(model, criterion, trainloader, valloader, testloader): model.train() model.set_grad(False) model.append_last_layer() - model = model.to(device) - optimizer = optim.SGD(model.out_fc.parameters(), lr=args.ft_lr, momentum=0.9, weight_decay=5e-4) + model = model.cuda() + optimizer = torch.optim.SGD(model.out_fc.parameters(), lr=args.lr, momentum=0.9, weight_decay=5e-4) # scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=2000, gamma=0.1, last_epoch=-1) - # scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=args.ft_epoch) + # scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=args.epochs) finetune_dataset = TensorDataset(x_finetune, y_finetune, a_finetune) # For B3 and M2, considering balance, only tried full batch if args.batch_size < 0: @@ -224,19 +210,19 @@ def Finetune(model, criterion, trainloader, valloader, testloader): print(len(finetune_dataset)) weights = max(torch.bincount(y_finetune)) / torch.bincount(y_finetune) - class_weights = torch.FloatTensor(weights).to(device) + class_weights = torch.FloatTensor(weights).cuda() print(torch.bincount(y_finetune)) print(class_weights) losses = [] trigger_times = 0 best_loss = 1e9 - for epoch in range(1, args.ft_epoch + 1): + for epoch in range(1, args.epochs + 1): epoch_loss = 0.0 epoch_loss_fairness = 0.0 epoch_acc = 0.0 for batch_idx, (x, y, a) in enumerate(finetuneloader): - x, y, a = x.to(device), y.to(device), a.to(device) + x, y, a = x.cuda(), y.cuda(), a.cuda() optimizer.zero_grad() outputs = model.out_fc(x) log_softmax, softmax = F.log_softmax(outputs, dim=1), F.softmax(outputs, dim=1) @@ -274,8 +260,7 @@ def Finetune(model, criterion, trainloader, valloader, testloader): epoch_acc /= len(finetune_dataset) losses.append(epoch_loss) print( - "FINETUNE Epoch %d/%d Loss_1: %.4f Loss_2: %.4f Accuracy: %.4f" - % (epoch, args.ft_epoch, epoch_loss, epoch_loss_fairness, epoch_acc) + "FINETUNE Epoch %d/%d Loss_1: %.4f Loss_2: %.4f Accuracy: %.4f" % (epoch, args.epochs, epoch_loss, epoch_loss_fairness, epoch_acc) ) # Early Stop @@ -302,7 +287,7 @@ def get_pred(x): # Avoid exceeding the memory limit loader = torch.utils.data.DataLoader(dataset, batch_size=TEST_BS, shuffle=False) outs = [] for x in loader: - out = F.softmax(model.out_fc(x[0].to(device)), dim=1).cpu().detach().numpy() + out = F.softmax(model.out_fc(x[0].cuda()), dim=1).cpu().detach().numpy() outs.append(out) outs = np.concatenate(outs) pred = np.argmax(outs, 1) @@ -399,7 +384,10 @@ def train_test_classifier(): def main(): for r in range(repeat_time): - print(f"Repeated experiment: {r+1}") + # print(f"Repeated experiment: {r+1}") + + ckpt_path = Path(f"{project_dir}/checkpoints/fdr_{args.constraint.lower()}-celeba-lr{args.lr}-bs{args.batch_size}-epochs{args.epochs}-seed{args.seed}") + ckpt_path.mkdir(parents=True, exist_ok=True) model = MyResNet(num_classes=2, pretrain=False) model = model.cuda() @@ -407,9 +395,9 @@ def main(): start_time = time.time() - if args.checkpoint is not None: - print("Recovering from %s ..." % (args.checkpoint)) - checkpoint = torch.load(args.checkpoint) + if args.checkpoint: + print("Recovering from %s ..." % (f"{ckpt_path}/best_model.pt")) + checkpoint = torch.load(f"{ckpt_path}/best_model.pt") model.load_state_dict(checkpoint["model_state_dict"]) else: ######### @@ -420,7 +408,7 @@ def main(): trigger_times = 0 best_loss = 1e9 best_model = None - optimizer = optim.SGD(model.parameters(), lr=1e-3, momentum=0.9, weight_decay=5e-4) + optimizer = torch.optim.SGD(model.parameters(), lr=1e-3, momentum=0.9, weight_decay=5e-4) scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=20, gamma=0.5, last_epoch=-1) for epoch in range(NUM_EPOCHS): train_per_epoch(model, optimizer, criterion, epoch + 1, NUM_EPOCHS) @@ -440,9 +428,7 @@ def main(): scheduler.step() checkpoint = {"model_state_dict": best_model.state_dict()} - ckpt_path = Path("./checkpoints/celeba") - ckpt_path.mkdir(parents=True, exist_ok=True) - torch.save(checkpoint, f"{str(ckpt_path)}/ckpt_celeba_{args.constraint.lower()}_seed{str(args.seed)}_repeat{str(r+1)}.pkl") + torch.save(checkpoint, f"{ckpt_path}/best_model.pt") model = best_model ################ @@ -453,17 +439,18 @@ def main(): total_time = time.time() - start_time total_time_str = str(datetime.timedelta(seconds=int(total_time))) print(f"Total training time: {total_time_str}") - - ret["time per epoch"] = total_time / args.ft_epoch - for i in range(len(metric_index)): - results[metric_index[i]].append(ret[metric_index[i]]) - - for m_index in metric_index: - fout.write(m_index + "\t") - for i in range(repeat_time): - fout.write("%f\t" % results[m_index][i]) - fout.write("%f\t%f\n" % (mean(results[m_index]), std(results[m_index]))) - fout.close() + print(f"Time per epoch: {total_time / args.epochs:.6f}") + + # ret["time per epoch"] = total_time / args.epochs + # for i in range(len(metric_index)): + # results[metric_index[i]].append(ret[metric_index[i]]) + + # for m_index in metric_index: + # fout.write(m_index + "\t") + # for i in range(repeat_time): + # fout.write("%f\t" % results[m_index][i]) + # fout.write("%f\t%f\n" % (mean(results[m_index]), std(results[m_index]))) + # fout.close() if __name__ == "__main__": diff --git a/FDR/cifar10s.py b/FDR/cifar10s.py index bf21bd8..27612ae 100644 --- a/FDR/cifar10s.py +++ b/FDR/cifar10s.py @@ -1,7 +1,7 @@ +import os import sys import time import random -import argparse import datetime import numpy as np from PIL import Image @@ -19,42 +19,33 @@ from torch.utils.data import TensorDataset from torchvision.datasets.vision import VisionDataset +project_dir = "/root/DL-Fairness-Study" +sys.path.insert(1, os.path.join(project_dir, "FDR")) + from utils import * from models import MyResNet -sys.path.insert(1, "/root/study") +sys.path.insert(1, project_dir) from helper import set_seed +from arguments import get_args from metrics import get_metric_index, get_all_metrics, print_all_metrics -parser = argparse.ArgumentParser(description="fairness") -parser.add_argument("--method", type=str, default="M2") -parser.add_argument("--ft_epoch", type=int, default=1000) -parser.add_argument("--ft_lr", type=float, default=1e-3) -parser.add_argument("--alpha", type=float, default=2.0) -parser.add_argument("--constraint", type=str, default="EO") -parser.add_argument("--seed", type=int, default=1) -parser.add_argument("--data_path", type=str, default="../data/cifar10s") -parser.add_argument("--batch_size", type=int, default=-1) -parser.add_argument("--checkpoint", type=str, default=None) -args = parser.parse_args() +args = get_args() set_seed(args.seed) print(args) -device = torch.device("cuda" if torch.cuda.is_available() else "cpu") -print(device) - -result_dir = "../results/cifar10s" -result_path = Path(result_dir) -result_path.mkdir(parents=True, exist_ok=True) -fout = open("/".join([str(result_path), f"fdr_{args.constraint.lower()}.txt"]), "w") +# result_dir = "../results/cifar10s" +# result_path = Path(result_dir) +# result_path.mkdir(parents=True, exist_ok=True) +# fout = open("/".join([str(result_path), f"fdr_{args.constraint.lower()}.txt"]), "w") -results = {} -metric_index = get_metric_index() -for m_index in metric_index: - results[m_index] = [] +# results = {} +# metric_index = get_metric_index() +# for m_index in metric_index: +# results[m_index] = [] -repeat_time = 10 +repeat_time = 1 ###################### # Data Preprocessing # @@ -205,7 +196,7 @@ def get_cifar10s(root, split, skewed_ratio=0.95, batch_size=128, num_workers=4): ######################### # CIFAR-10S dataset skewed_ratio = 0.95 -root = args.data_path +root = Path(f"{project_dir}/data/cifar10s") train_loader, train_size = get_cifar10s(root, split="train") @@ -224,7 +215,7 @@ def train_per_epoch(model, optimizer, criterion, epoch, num_epochs): optimizer.zero_grad() # move to GPU - images, labels = images.to(device), labels.to(device) + images, labels = images.cuda(), labels.cuda() # if batch_idx == 0: # print(images.shape, labels.shape) @@ -254,7 +245,7 @@ def valid_per_epoch(model, epoch, num_epochs, criterion): for batch_idx, (images, labels, biases) in enumerate(val_loader): # move to GPU - images, labels = images.to(device), labels.to(device) + images, labels = images.cuda(), labels.cuda() # forward outputs = model.forward(images) @@ -278,7 +269,7 @@ def Finetune(model, criterion, train_loader, val_loader, test_loader): model.eval() best_clf = None - method = args.method + method = args.finetune_method ################################################### # Option 1 (B1): Directly test @@ -291,13 +282,13 @@ def Finetune(model, criterion, train_loader, val_loader, test_loader): ################ # Prepare the dataset ################ - x_train, y_train, a_train = prepare_cifar10s_data(train_loader, model, device) + x_train, y_train, a_train = prepare_cifar10s_data(train_loader, model) print(x_train.shape, y_train.shape, a_train.shape) - x_test, y_test, a_test = prepare_cifar10s_data(test_loader, model, device) + x_test, y_test, a_test = prepare_cifar10s_data(test_loader, model) print(x_test.shape, y_test.shape, a_test.shape) - x_finetune, y_finetune, a_finetune = prepare_cifar10s_data(val_loader, model, device) + x_finetune, y_finetune, a_finetune = prepare_cifar10s_data(val_loader, model) print(x_finetune.shape, y_finetune.shape, a_finetune.shape) if method == "B1": @@ -341,11 +332,11 @@ def Finetune(model, criterion, train_loader, val_loader, test_loader): model.train() model.set_grad(False) model.append_last_layer(num_classes=10) - model = model.to(device) - # optimizer = optim.SGD(model.out_fc.parameters(), lr=args.ft_lr, momentum=0.9, weight_decay=5e-4) - optimizer = optim.NAdam(model.out_fc.parameters(), lr=args.ft_lr, weight_decay=5e-4) + model = model.cuda() + # optimizer = optim.SGD(model.out_fc.parameters(), lr=args.lr, momentum=0.9, weight_decay=5e-4) + optimizer = optim.NAdam(model.out_fc.parameters(), lr=args.lr, weight_decay=5e-4) # scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=2000, gamma=0.1, last_epoch=-1) - # scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=args.ft_epoch) + # scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=args.epochs) finetune_dataset = TensorDataset(x_finetune, y_finetune, a_finetune) # For B3 and M2, considering balance, only tried full batch if args.batch_size < 0: @@ -357,19 +348,19 @@ def Finetune(model, criterion, train_loader, val_loader, test_loader): print(len(finetune_dataset)) weights = max(torch.bincount(y_finetune)) / torch.bincount(y_finetune) - class_weights = torch.FloatTensor(weights).to(device) + class_weights = torch.FloatTensor(weights).cuda() print(torch.bincount(y_finetune)) print(class_weights) losses = [] trigger_times = 0 best_loss = 1e9 - for epoch in range(1, args.ft_epoch + 1): + for epoch in range(1, args.epochs + 1): epoch_loss = 0.0 epoch_loss_fairness = 0.0 epoch_acc = 0.0 for batch_idx, (x, y, a) in enumerate(finetuneloader): - x, y, a = x.to(device), y.to(device), a.to(device) + x, y, a = x.cuda(), y.cuda(), a.cuda() optimizer.zero_grad() outputs = model.out_fc(x) log_softmax, softmax = F.log_softmax(outputs, dim=1), F.softmax(outputs, dim=1) @@ -407,8 +398,7 @@ def Finetune(model, criterion, train_loader, val_loader, test_loader): epoch_acc /= len(finetune_dataset) losses.append(epoch_loss) print( - "FINETUNE Epoch %d/%d Loss_1: %.4f Loss_2: %.4f Accuracy: %.4f" - % (epoch, args.ft_epoch, epoch_loss, epoch_loss_fairness, epoch_acc) + "FINETUNE Epoch %d/%d Loss_1: %.4f Loss_2: %.4f Accuracy: %.4f" % (epoch, args.epochs, epoch_loss, epoch_loss_fairness, epoch_acc) ) # Early Stop @@ -435,7 +425,7 @@ def get_pred(x): # Avoid exceeding the memory limit loader = torch.utils.data.DataLoader(dataset, batch_size=128, shuffle=False) outs = [] for x in loader: - out = F.softmax(model.out_fc(x[0].to(device)), dim=1).cpu().detach().numpy() + out = F.softmax(model.out_fc(x[0].cuda()), dim=1).cpu().detach().numpy() outs.append(out) outs = np.concatenate(outs) pred = np.argmax(outs, 1) @@ -470,7 +460,10 @@ def get_pred(x): # Avoid exceeding the memory limit def main(): for r in range(repeat_time): - print(f"Repeated experiment: {r+1}") + # print(f"Repeated experiment: {r+1}") + + ckpt_path = Path(f"{project_dir}/checkpoints/fdr_{args.constraint.lower()}-cifar10s-lr{args.lr}-bs{args.batch_size}-epochs{args.epochs}-seed{args.seed}") + ckpt_path.mkdir(parents=True, exist_ok=True) model = MyResNet(num_classes=10, pretrain=False) model = model.cuda() @@ -478,10 +471,9 @@ def main(): start_time = time.time() - if args.checkpoint is not None: - ckpt_path = args.checkpoint.replace(".pkl", f"_repeat{r+1}.pkl") - print("Recovering from %s ..." % (ckpt_path)) - checkpoint = torch.load(ckpt_path) + if args.checkpoint: + print("Recovering from %s ..." % (f"{ckpt_path}/best_model.pt")) + checkpoint = torch.load(f"{ckpt_path}/best_model.pt") model.load_state_dict(checkpoint["model_state_dict"]) else: ######### @@ -513,12 +505,7 @@ def main(): scheduler.step() checkpoint = {"model_state_dict": best_model.state_dict()} - ckpt_path = Path("./checkpoints/cifar10s") - ckpt_path.mkdir(parents=True, exist_ok=True) - torch.save( - checkpoint, - f"{str(ckpt_path)}/ckpt_cifar10s_{args.constraint.lower()}_seed{str(args.seed)}_repeat{str(r+1)}.pkl", - ) + torch.save(checkpoint, f"{ckpt_path}/best_model.pt") model = best_model ################ @@ -529,17 +516,18 @@ def main(): total_time = time.time() - start_time total_time_str = str(datetime.timedelta(seconds=int(total_time))) print(f"Total training time: {total_time_str}") - - ret["time per epoch"] = total_time / args.ft_epoch - for i in range(len(metric_index)): - results[metric_index[i]].append(ret[metric_index[i]]) - - for m_index in metric_index: - fout.write(m_index + "\t") - for i in range(repeat_time): - fout.write("%f\t" % results[m_index][i]) - fout.write("%f\t%f\n" % (mean(results[m_index]), std(results[m_index]))) - fout.close() + print(f"Time per epoch: {total_time / args.epochs:.6f}") + + # ret["time per epoch"] = total_time / args.epochs + # for i in range(len(metric_index)): + # results[metric_index[i]].append(ret[metric_index[i]]) + + # for m_index in metric_index: + # fout.write(m_index + "\t") + # for i in range(repeat_time): + # fout.write("%f\t" % results[m_index][i]) + # fout.write("%f\t%f\n" % (mean(results[m_index]), std(results[m_index]))) + # fout.close() if __name__ == "__main__": diff --git a/FDR/datasets/__init__.py b/FDR/datasets/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/FDR/datasets/celeba.py b/FDR/datasets/celeba.py new file mode 100644 index 0000000..d3825dc --- /dev/null +++ b/FDR/datasets/celeba.py @@ -0,0 +1,87 @@ +import torch +import pickle +import numpy as np +from pathlib import Path +from torchvision import transforms +from torchvision.datasets.celeba import CelebA +from torch.utils.data.dataloader import DataLoader + + +class MyCelebA: + def __init__(self, root, split, transform, target_attr): + self.transform = transform + self.target_attr = target_attr + + self.celeba = CelebA(root=root, split=split, target_type="attr", transform=transform) + + self.bias_idx = 20 # Gender Attribute. + + if target_attr == "Blond_Hair": + self.target_idx = 9 + if split in ["train"]: + save_path = Path(root) / "celeba" / "pickles" / "blonde" + if save_path.is_dir(): + print(f"use existing blonde indices from {save_path}") + self.indices = pickle.load(open(save_path / "indices.pkl", "rb")) + else: + self.indices = self.build_blonde() + print(f"save blonde indices to {save_path}") + save_path.mkdir(parents=True, exist_ok=True) + pickle.dump(self.indices, open(save_path / f"indices.pkl", "wb")) + self.attr = self.celeba.attr[self.indices] + else: + self.attr = self.celeba.attr + self.indices = torch.arange(len(self.celeba)) + + else: + raise AttributeError + + self.targets = self.attr[:, self.target_idx] + self.bias_targets = self.attr[:, self.bias_idx] + + def build_blonde(self): + bias_targets = self.celeba.attr[:, self.bias_idx] + targets = self.celeba.attr[:, self.target_idx] + selects = torch.arange(len(self.celeba))[(bias_targets == 0) & (targets == 0)] + non_selects = torch.arange(len(self.celeba))[~((bias_targets == 0) & (targets == 0))] + np.random.seed(1) + np.random.shuffle(selects) + indices = torch.cat([selects[:2000], non_selects]) + return indices + + def __getitem__(self, index): + img, _ = self.celeba.__getitem__(self.indices[index]) + target, bias = self.targets[index], self.bias_targets[index] + + return img, target, bias + + def __len__(self): + return len(self.targets) + + +def get_celeba(root, split, target_attr, img_size, batch_size, num_workers=4): + if split == "train": + transform = transforms.Compose( + [ + transforms.Resize((img_size, img_size)), + transforms.RandomHorizontalFlip(), + transforms.ToTensor(), + transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), + ] + ) + else: + transform = transforms.Compose( + [ + transforms.Resize((img_size, img_size)), + transforms.ToTensor(), + transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), + ] + ) + + dataset = MyCelebA(root=root, split=split, transform=transform, target_attr=target_attr) + + print(f"\nget_celeba - split: {split} size: {len(dataset)}") + + dataloader = DataLoader(dataset=dataset, batch_size=batch_size, shuffle=True if split == "train" else False, num_workers=num_workers) + + return dataset, dataloader diff --git a/FDR/datasets/cifar10s.py b/FDR/datasets/cifar10s.py new file mode 100644 index 0000000..771b077 --- /dev/null +++ b/FDR/datasets/cifar10s.py @@ -0,0 +1,142 @@ +import torch +import random +import numpy as np +import torchvision.transforms as transforms + +from PIL import Image +from tqdm import tqdm +from torch.utils.data import DataLoader +from torchvision.datasets import CIFAR10 + + +class CIFAR_10S: + def __init__(self, root, split, transform, skew_ratio): + self.transform = transform + train_valid = split == "train" + self.cifar10 = CIFAR10(root, train=train_valid, download=True) + self.images = self.cifar10.data + self.targets = np.array(self.cifar10.targets) + self.bias_targets = np.zeros_like(self.targets) + self.split = split + + if not train_valid: + self.build_split() + + if split == "train": + print("********") + print("Skew ratio used %.2f" % skew_ratio) + print("********") + + self.corrupt_dataset(skew_ratio) + + else: + self.corrupt_test_dataset() + + self.targets, self.bias_targets = torch.from_numpy(self.targets).long(), torch.from_numpy(self.bias_targets).long() + + def build_split(self): + indices = {i: [] for i in range(10)} + size_per_class = 1000 + for idx, tar in enumerate(self.targets): + indices[tar].append(idx) + + if self.split == "test": + start = 0 + end = int(size_per_class * 0.9) + + if self.split == "valid": + start = int(size_per_class * 0.9) + end = size_per_class + + final_indices = [] + for ind_group in indices.values(): + final_indices.extend(ind_group[start:end]) + + np.random.seed(1) + np.random.shuffle(final_indices) + + self.images = self.images[final_indices] + self.bias_targets = self.bias_targets[final_indices] + self.targets = self.targets[final_indices] + + def rgb_to_grayscale(self, img): + """Convert image to gray scale""" + + pil_img = Image.fromarray(img) + pil_gray_img = pil_img.convert("L") + np_gray_img = np.array(pil_gray_img, dtype=np.uint8) + np_gray_img = np.dstack([np_gray_img, np_gray_img, np_gray_img]) + + return np_gray_img + + def corrupt_test_dataset(self): + self.images_gray = np.copy(self.images) + self.bias_targets_gray = np.copy(self.bias_targets) + self.targets_gray = np.copy(self.targets) + + for idx, img in enumerate(self.images_gray): + self.images_gray[idx] = self.rgb_to_grayscale(img) + self.bias_targets_gray[idx] = 1 + + self.images = np.concatenate((self.images, self.images_gray), axis=0) + self.bias_targets = np.concatenate((self.bias_targets, self.bias_targets_gray), axis=0) + self.targets = np.concatenate((self.targets, self.targets_gray), axis=0) + + def corrupt_dataset(self, skew_level): + gray_classes = [0, 2, 4, 6, 8] + + samples_by_class = {i: [] for i in range(10)} + for idx, target in enumerate(self.targets): + samples_by_class[target].append(idx) + + for class_idx in tqdm(range(10), ascii=True): + class_samples = samples_by_class[class_idx] + if class_idx in gray_classes: + samples_skew_num = int(len(class_samples) * skew_level) + else: + samples_skew_num = int(len(class_samples) * (1 - skew_level)) + + random.seed(1) + samples_skew = random.sample(class_samples, samples_skew_num) + for sample_idx in samples_skew: + self.images[sample_idx] = self.rgb_to_grayscale(self.images[sample_idx]) + self.bias_targets[sample_idx] = 1 + + def __len__(self): + return len(self.images) + + def __getitem__(self, index): + img = self.images[index] + target = self.targets[index] + bias = self.bias_targets[index] + + if self.transform: + img = self.transform(img) + + return img, target, bias + + +def get_cifar10s(root, split, img_size, batch_size, skew_ratio=0.95, num_workers=4): + mean = [0.4914, 0.4822, 0.4465] + std = [0.2470, 0.2435, 0.2616] + + if split == "test" or split == "valid": + transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize(mean, std)]) + else: + transform = transforms.Compose( + [ + transforms.ToPILImage(), + transforms.RandomCrop(img_size, padding=4), + transforms.RandomHorizontalFlip(), + transforms.ToTensor(), + transforms.Normalize(mean, std), + ] + ) + + dataset = CIFAR_10S(root=root, split=split, transform=transform, skew_ratio=skew_ratio) + + print(f"\nget_cifar10s - split: {split} size: {len(dataset)}") + + dataloader = DataLoader(dataset=dataset, batch_size=batch_size, shuffle=True if split == "train" else False, num_workers=num_workers) + + return dataset, dataloader diff --git a/FDR/datasets/utkface.py b/FDR/datasets/utkface.py new file mode 100644 index 0000000..be85c7d --- /dev/null +++ b/FDR/datasets/utkface.py @@ -0,0 +1,160 @@ +import os +import PIL +import torch +import pickle +import numpy as np + +from pathlib import Path +from torchvision import transforms +from torch.utils.data import DataLoader + + +class UTKFace: + def __init__(self, root, split, transform, bias_attr, bias_rate=0.9): + self.root = Path(root) / "images" + filenames = np.array(os.listdir(self.root)) + np.random.seed(1) + np.random.shuffle(filenames) + num_files = len(filenames) + num_train = int(num_files * 0.8) + target_attr = "gender" + + self.transform = transform + self.target_attr = target_attr + self.bias_rate = bias_rate + self.bias_attr = bias_attr + self.train = split == "train" + + save_path = Path(root) / "pickles" / f"biased_utk_face-target_{target_attr}-bias_{bias_attr}-{bias_rate}" + if save_path.is_dir(): + print(f"use existing biased_utk_face from {save_path}") + data_split = "train" if self.train else "test" + self.files, self.targets, self.bias_targets = pickle.load(open(save_path / f"{data_split}_dataset.pkl", "rb")) + if split in ["valid", "test"]: + save_path = Path(f"{Path(root).parent.absolute()}/clusters/utk_face_rand_indices_{bias_attr}.pkl") + if not save_path.exists(): + rand_indices = torch.randperm(len(self.targets)) + pickle.dump(rand_indices, open(save_path, "wb")) + else: + rand_indices = pickle.load(open(save_path, "rb")) + num_total = len(rand_indices) + num_valid = int(0.5 * num_total) + + if split == "valid": + indices = rand_indices[:num_valid] + elif split == "test": + indices = rand_indices[num_valid:] + + indices = indices.numpy() + + self.files = self.files[indices] + self.targets = self.targets[indices] + self.bias_targets = self.bias_targets[indices] + else: + train_dataset = self.build(filenames[:num_train], train=True) + test_dataset = self.build(filenames[num_train:], train=False) + + print(f"save biased_utk_face to {save_path}") + save_path.mkdir(parents=True, exist_ok=True) + pickle.dump(train_dataset, open(save_path / f"train_dataset.pkl", "wb")) + pickle.dump(test_dataset, open(save_path / f"test_dataset.pkl", "wb")) + + self.files, self.targets, self.bias_targets = train_dataset if self.train else test_dataset + + self.targets, self.bias_targets = torch.from_numpy(self.targets).long(), torch.from_numpy(self.bias_targets).long() + + def build(self, filenames, train=False): + attr_dict = { + "age": ( + 0, + lambda x: x >= 20, + lambda x: x <= 10, + ), + "gender": (1, lambda x: x == 0, lambda x: x == 1), + "race": (2, lambda x: x == 0, lambda x: x != 0), + } + assert self.target_attr in attr_dict.keys() + target_cls_idx, *target_filters = attr_dict[self.target_attr] + bias_cls_idx, *bias_filters = attr_dict[self.bias_attr] + + target_classes = self.get_class_from_filename(filenames, target_cls_idx) + bias_classes = self.get_class_from_filename(filenames, bias_cls_idx) + + total_files = [] + total_targets = [] + total_bias_targets = [] + + for i in (0, 1): + major_idx = np.where(target_filters[i](target_classes) & bias_filters[i](bias_classes))[0] + minor_idx = np.where(target_filters[1 - i](target_classes) & bias_filters[i](bias_classes))[0] + np.random.seed(1) + np.random.shuffle(minor_idx) + + num_major = major_idx.shape[0] + num_minor_org = minor_idx.shape[0] + if train: + num_minor = int(num_major * (1 - self.bias_rate)) + else: + num_minor = minor_idx.shape[0] + num_minor = min(num_minor, num_minor_org) + num_total = num_major + num_minor + + majors = filenames[major_idx] + minors = filenames[minor_idx][:num_minor] + + total_files.append(np.concatenate((majors, minors))) + total_bias_targets.append(np.ones(num_total) * i) + total_targets.append(np.concatenate((np.ones(num_major) * i, np.ones(num_minor) * (1 - i)))) + + files = np.concatenate(total_files) + targets = np.concatenate(total_targets) + bias_targets = np.concatenate(total_bias_targets) + return files, targets, bias_targets + + def get_class_from_filename(self, filenames, cls_idx): + return np.array([int(fname.split("_")[cls_idx]) if len(fname.split("_")) == 4 else 10 for fname in filenames]) + + def __getitem__(self, index): + filename, target, bias = (self.files[index], int(self.targets[index]), int(self.bias_targets[index])) + X = PIL.Image.open(os.path.join(self.root, filename)) + + if self.transform is not None: + X = self.transform(X) + + return X, target, bias + + def __len__(self): + return len(self.files) + + +def get_utkface(root, split, bias_attr, img_size, batch_size, bias_rate=0.9, num_workers=4): + size_dict = {64: 72, 128: 144, 224: 256} + load_size = size_dict[img_size] + + if split == "train": + transform = transforms.Compose( + [ + transforms.RandomResizedCrop(img_size), + transforms.RandomHorizontalFlip(), + transforms.ToTensor(), + transforms.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)), + ] + ) + + else: + transform = transforms.Compose( + [ + transforms.Resize(load_size), + transforms.CenterCrop(img_size), + transforms.ToTensor(), + transforms.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)), + ] + ) + + dataset = UTKFace(root=root, split=split, transform=transform, bias_attr=bias_attr, bias_rate=bias_rate) + + print(f"\nget_utkface - split: {split} size: {len(dataset)}") + + dataloader = DataLoader(dataset=dataset, batch_size=batch_size, shuffle=True if split == "train" else False, num_workers=num_workers) + + return dataset, dataloader diff --git a/FDR/utils.py b/FDR/utils.py index dc7320a..19b00f9 100644 --- a/FDR/utils.py +++ b/FDR/utils.py @@ -1,16 +1,9 @@ import torch -import numpy as np -from copy import deepcopy from sklearn.metrics import accuracy_score, roc_auc_score -from fairlearn.metrics import ( - demographic_parity_difference, - demographic_parity_ratio, - false_positive_rate, - false_negative_rate, -) +from fairlearn.metrics import demographic_parity_difference, demographic_parity_ratio, false_positive_rate, false_negative_rate -def prepare_data(dataloader, model, device): +def prepare_data(dataloader, model): x_, y_, a_ = [], [], [] for batch_idx, (images, labels) in enumerate(dataloader): gender = labels[:, 20] @@ -21,7 +14,7 @@ def prepare_data(dataloader, model, device): if batch_idx == 0: print(images.shape) - X = model.get_features(images.to(device)).detach().cpu() + X = model.get_features(images.cuda()).detach().cpu() if batch_idx == 0: print(X.shape) @@ -31,14 +24,14 @@ def prepare_data(dataloader, model, device): return torch.cat(x_), torch.cat(y_), torch.cat(a_) -def prepare_cifar10s_data(dataloader, model, device): +def prepare_cifar10s_data(dataloader, model): x_, y_, a_ = [], [], [] for batch_idx, (images, labels, biases) in enumerate(dataloader): a_.append(biases) y_.append(labels) if batch_idx == 0: print(images.shape) - X = model.get_features(images.to(device)).detach().cpu() + X = model.get_features(images.cuda()).detach().cpu() if batch_idx == 0: print(X.shape) x_.append(X) @@ -46,14 +39,14 @@ def prepare_cifar10s_data(dataloader, model, device): return torch.cat(x_), torch.cat(y_), torch.cat(a_) -def prepare_utkface_data(dataloader, model, device): +def prepare_utkface_data(dataloader, model): x_, y_, a_ = [], [], [] for batch_idx, (images, labels, biases) in enumerate(dataloader): a_.append(biases) y_.append(labels) if batch_idx == 0: print(images.shape) - X = model.get_features(images.to(device)).detach().cpu() + X = model.get_features(images.cuda()).detach().cpu() if batch_idx == 0: print(X.shape) x_.append(X) diff --git a/FDR/utkface.py b/FDR/utkface.py index cb05fb1..9a6e3e8 100644 --- a/FDR/utkface.py +++ b/FDR/utkface.py @@ -1,61 +1,51 @@ +import os import sys import time -import argparse +import torch import datetime import numpy as np +import torch.nn as nn +import torch.optim as optim +import torch.nn.functional as F from pathlib import Path from copy import deepcopy from numpy import mean, std - -import torch -import torch.nn as nn -import torch.optim as optim -import torch.nn.functional as F from torch.utils.data import TensorDataset +project_dir = "/root/DL-Fairness-Study" +sys.path.insert(1, os.path.join(project_dir, "FDR")) + from utils import * from models import MyResNet +from datasets.utkface import get_utkface -sys.path.insert(1, "/root/study") +sys.path.insert(1, project_dir) from helper import set_seed -from datasets.utkface import get_utkface +from arguments import get_args from metrics import get_metric_index, get_all_metrics, print_all_metrics -parser = argparse.ArgumentParser(description="fairness") -parser.add_argument("--method", type=str, default="M2") -parser.add_argument("--ft_epoch", type=int, default=1000) -parser.add_argument("--ft_lr", type=float, default=1e-3) -parser.add_argument("--alpha", type=float, default=2.0) -parser.add_argument("--constraint", type=str, default="EO") -parser.add_argument("--sensitive", type=str, default="race") -parser.add_argument("--seed", type=int, default=1) -parser.add_argument("--data_path", type=str, default="../data/utkface") -parser.add_argument("--batch_size", type=int, default=-1) -parser.add_argument("--checkpoint", type=str, default=None) -args = parser.parse_args() + +args = get_args() set_seed(args.seed) print(args) -device = torch.device("cuda" if torch.cuda.is_available() else "cpu") -print(device) +# result_dir = "../results/utkface" +# result_path = Path(result_dir) +# result_path.mkdir(parents=True, exist_ok=True) +# fout = open("/".join([str(result_path), f"fdr_{args.constraint.lower()}_{args.sensitive.lower()}_gender.txt"]), "w") -result_dir = "../results/utkface" -result_path = Path(result_dir) -result_path.mkdir(parents=True, exist_ok=True) -fout = open("/".join([str(result_path), f"fdr_{args.constraint.lower()}_{args.sensitive.lower()}_gender.txt"]), "w") +# results = {} +# metric_index = get_metric_index() +# for m_index in metric_index: +# results[m_index] = [] -results = {} -metric_index = get_metric_index() -for m_index in metric_index: - results[m_index] = [] +TRAIN_BS = 256 +TEST_BS = 512 -TRAIN_BS = 1024 -TEST_BS = 2048 - -repeat_time = 10 -root = args.data_path +repeat_time = 1 +root = Path(f"{project_dir}/data/utkface") train_dataset, train_loader = get_utkface(root, split="train", batch_size=TRAIN_BS, bias_attr=args.sensitive, img_size=224) @@ -74,7 +64,7 @@ def train_per_epoch(model, optimizer, criterion, epoch, num_epochs): optimizer.zero_grad() # move to GPU - images, labels = images.to(device), labels.to(device) + images, labels = images.cuda(), labels.cuda() # if batch_idx == 0: # print(images.shape, labels.shape) @@ -104,7 +94,7 @@ def valid_per_epoch(model, epoch, num_epochs, criterion): for batch_idx, (images, labels, biases) in enumerate(val_loader): # move to GPU - images, labels = images.to(device), labels.to(device) + images, labels = images.cuda(), labels.cuda() # forward outputs = model.forward(images) @@ -128,7 +118,7 @@ def Finetune(model, criterion, train_loader, val_loader, test_loader): model.eval() best_clf = None - method = args.method + method = args.finetune_method ################################################### # Option 1 (B1): Directly test @@ -141,13 +131,13 @@ def Finetune(model, criterion, train_loader, val_loader, test_loader): ################ # Prepare the dataset ################ - x_train, y_train, a_train = prepare_utkface_data(train_loader, model, device) + x_train, y_train, a_train = prepare_utkface_data(train_loader, model) print(x_train.shape, y_train.shape, a_train.shape) - x_test, y_test, a_test = prepare_utkface_data(test_loader, model, device) + x_test, y_test, a_test = prepare_utkface_data(test_loader, model) print(x_test.shape, y_test.shape, a_test.shape) - x_finetune, y_finetune, a_finetune = prepare_utkface_data(val_loader, model, device) + x_finetune, y_finetune, a_finetune = prepare_utkface_data(val_loader, model) print(x_finetune.shape, y_finetune.shape, a_finetune.shape) if method == "B1": @@ -183,8 +173,8 @@ def Finetune(model, criterion, train_loader, val_loader, test_loader): model.train() model.set_grad(False) model.append_last_layer() - model = model.to(device) - optimizer = optim.SGD(model.out_fc.parameters(), lr=args.ft_lr, momentum=0.9, weight_decay=5e-4) + model = model.cuda() + optimizer = optim.SGD(model.out_fc.parameters(), lr=args.lr, momentum=0.9, weight_decay=5e-4) finetune_dataset = TensorDataset(x_finetune, y_finetune, a_finetune) # For B3 and M2, considering balance, only tried full batch if args.batch_size < 0: @@ -196,19 +186,19 @@ def Finetune(model, criterion, train_loader, val_loader, test_loader): print(len(finetune_dataset)) weights = max(torch.bincount(y_finetune)) / torch.bincount(y_finetune) - class_weights = torch.FloatTensor(weights).to(device) + class_weights = torch.FloatTensor(weights).cuda() print(torch.bincount(y_finetune)) print(class_weights) losses = [] trigger_times = 0 best_loss = 1e9 - for epoch in range(1, args.ft_epoch + 1): + for epoch in range(1, args.epochs + 1): epoch_loss = 0.0 epoch_loss_fairness = 0.0 epoch_acc = 0.0 for batch_idx, (x, y, a) in enumerate(finetuneloader): - x, y, a = x.to(device), y.to(device), a.to(device) + x, y, a = x.cuda(), y.cuda(), a.cuda() optimizer.zero_grad() outputs = model.out_fc(x) log_softmax, softmax = F.log_softmax(outputs, dim=1), F.softmax(outputs, dim=1) @@ -244,8 +234,7 @@ def Finetune(model, criterion, train_loader, val_loader, test_loader): epoch_acc /= len(finetune_dataset) losses.append(epoch_loss) print( - "FINETUNE Epoch %d/%d Loss_1: %.4f Loss_2: %.4f Accuracy: %.4f" - % (epoch, args.ft_epoch, epoch_loss, epoch_loss_fairness, epoch_acc) + "FINETUNE Epoch %d/%d Loss_1: %.4f Loss_2: %.4f Accuracy: %.4f" % (epoch, args.epochs, epoch_loss, epoch_loss_fairness, epoch_acc) ) model.eval() @@ -258,7 +247,7 @@ def get_pred(x): # Avoid exceeding the memory limit loader = torch.utils.data.DataLoader(dataset, batch_size=TEST_BS, shuffle=False) outs = [] for x in loader: - out = F.softmax(model.out_fc(x[0].to(device)), dim=1).cpu().detach().numpy() + out = F.softmax(model.out_fc(x[0].cuda()), dim=1).cpu().detach().numpy() outs.append(out) outs = np.concatenate(outs) pred = np.argmax(outs, 1) @@ -300,12 +289,13 @@ def set_model(num_classes, pretrain): def main(): model, criterion = set_model(num_classes=2, pretrain=True) - + ckpt_path = Path(f"{project_dir}/checkpoints/fdr_{args.constraint.lower()}-utkface_{args.sensitive}-lr{args.lr}-bs{args.batch_size}-epochs{args.epochs}-seed{args.seed}") + ckpt_path.mkdir(parents=True, exist_ok=True) best_model = None start_time = time.time() - if args.checkpoint is not None: - print("Recovering from %s ..." % (args.checkpoint)) - checkpoint = torch.load(args.checkpoint) + if args.checkpoint: + print("Recovering from %s ..." % (f"{ckpt_path}/best_model.pt")) + checkpoint = torch.load(f"{ckpt_path}/best_model.pt") model.load_state_dict(checkpoint["model_state_dict"]) best_model = deepcopy(model) else: @@ -340,19 +330,15 @@ def main(): scheduler.step() checkpoint = {"model_state_dict": best_model.state_dict()} - ckpt_path = Path("./checkpoints") - ckpt_path.mkdir(parents=True, exist_ok=True) - torch.save( - checkpoint, - f"{str(ckpt_path)}/ckpt_utkface_{args.constraint.lower()}_{args.sensitive}_seed{str(args.seed)}.pkl", - ) + torch.save(checkpoint, f"{ckpt_path}/best_model.pt") + training_time = time.time() - start_time ################ # Finetune and test # ################ for r in range(repeat_time): - print(f"Repeated experiment: {r+1}") + # print(f"Repeated experiment: {r+1}") model = deepcopy(best_model) @@ -362,17 +348,17 @@ def main(): total_time_str = str(datetime.timedelta(seconds=int(total_time))) print(f"Total training time: {total_time_str}") - ret["time per epoch"] = total_time / args.ft_epoch + print(f"Time per epoch: {total_time / args.epochs:.6f}") - for i in range(len(metric_index)): - results[metric_index[i]].append(ret[metric_index[i]]) + # for i in range(len(metric_index)): + # results[metric_index[i]].append(ret[metric_index[i]]) - for m_index in metric_index: - fout.write(m_index + "\t") - for i in range(repeat_time): - fout.write("%f\t" % results[m_index][i]) - fout.write("%f\t%f\n" % (mean(results[m_index]), std(results[m_index]))) - fout.close() + # for m_index in metric_index: + # fout.write(m_index + "\t") + # for i in range(repeat_time): + # fout.write("%f\t" % results[m_index][i]) + # fout.write("%f\t%f\n" % (mean(results[m_index]), std(results[m_index]))) + # fout.close() if __name__ == "__main__": diff --git a/FLAC/datasets/utk_face.py b/FLAC/datasets/utk_face.py index 194bb11..d46e340 100644 --- a/FLAC/datasets/utk_face.py +++ b/FLAC/datasets/utk_face.py @@ -75,7 +75,7 @@ def __init__( open(save_path / f"{data_split}_dataset.pkl", "rb") ) if split in ["valid", "test"]: - save_path = Path(f"/root/study/data/clusters/utk_face_rand_indices_{bias_attr}.pkl") + save_path = Path(f'{Path(root).parent.absolute()}/clusters/utk_face_rand_indices_{bias_attr}.pkl') if not save_path.exists(): rand_indices = torch.randperm(len(self.targets)) pickle.dump(rand_indices, open(save_path, "wb")) diff --git a/FLAC/train_celeba.py b/FLAC/train_celeba.py index 8911b9e..d349db4 100644 --- a/FLAC/train_celeba.py +++ b/FLAC/train_celeba.py @@ -1,17 +1,23 @@ -import argparse -import datetime -import logging import os +import sys import time -from pathlib import Path - -import numpy as np import torch +import logging +import argparse +import datetime +import numpy as np from torch import nn +from tqdm import tqdm +from pathlib import Path +from numpy import mean, std + +project_dir = "/root/DL-Fairness-Study" +sys.path.insert(1, os.path.join(project_dir, "FLAC")) + from flac import flac_loss -from datasets.celeba import get_celeba from models.resnet import ResNet18 from utils.logging import set_logging +from datasets.celeba import get_celeba from utils.utils import ( AverageMeter, MultiDimAverageMeter, @@ -22,38 +28,12 @@ set_seed, ) -from tqdm import tqdm - -import sys -sys.path.insert(1, "/root/study") +sys.path.insert(1, project_dir) -from numpy import mean, std +from arguments import get_args from metrics import get_metric_index, get_all_metrics, print_all_metrics -def parse_option(): - parser = argparse.ArgumentParser() - parser.add_argument("--exp_name", type=str, default="test") - parser.add_argument("--gpu", type=int, default=0) - parser.add_argument("--task", type=str, default="blonde") - parser.add_argument( - "--gender_classifier", - type=str, - default="./bias_capturing_classifiers/bcc_gender.pth", - ) - - parser.add_argument("--epochs", type=int, default=40) - parser.add_argument("--seed", type=int, default=1) - - parser.add_argument("--bs", type=int, default=128, help="batch_size") - parser.add_argument("--lr", type=float, default=1e-3) - parser.add_argument("--alpha", type=float, default=20000) - opt = parser.parse_args() - os.environ["CUDA_VISIBLE_DEVICES"] = str(opt.gpu) - - return opt - - def set_model(opt): model = ResNet18(pretrained=True).cuda() criterion1 = nn.CrossEntropyLoss() @@ -120,99 +100,118 @@ def validate(val_loader, model): top1.update(acc1[0], bsz) corrects = (preds == labels).long() - attrwise_acc_meter.add( - corrects.cpu(), torch.stack([labels.cpu(), biases.cpu()], dim=1) - ) + attrwise_acc_meter.add(corrects.cpu(), torch.stack([labels.cpu(), biases.cpu()], dim=1)) return top1.avg, attrwise_acc_meter.get_mean() def main(): - opt = parse_option() + opt = get_args() + opt.target = "blonde" if opt.target == "Blond_Hair" else opt.target + opt.gender_classifier = f"{project_dir}/FLAC/bias_capturing_classifiers/bcc_gender.pth" + exp_name = f"flac-celeba-lr{opt.lr}-bs{opt.batch_size}-epochs{opt.epochs}-alpha{opt.alpha}-seed{opt.seed}" - exp_name = f"flac-celeba_{opt.task}-{opt.exp_name}-lr{opt.lr}-alpha{opt.alpha}-bs{opt.bs}-seed{opt.seed}" - opt.exp_name = exp_name - - if opt.task == "makeup": + if opt.target == "makeup": opt.epochs = 40 - elif opt.task == "blonde": + elif opt.target == "blonde": opt.epochs = 10 else: raise AttributeError() - result_dir = f"../results/celeba" - result_path = Path(result_dir) - result_path.mkdir(parents=True, exist_ok=True) - if opt.task == "blonde": - fout = open("/".join([str(result_path), "flac_gender_blond_hair.txt"]), "w") + # result_dir = f"../results/celeba" + # result_path = Path(result_dir) + # result_path.mkdir(parents=True, exist_ok=True) + # if opt.target == "blonde": + # fout = open("/".join([str(result_path), "flac_gender_blond_hair.txt"]), "w") - results = {} - metric_index = get_metric_index() - for m_index in metric_index: - results[m_index] = [] + # results = {} + # metric_index = get_metric_index() + # for m_index in metric_index: + # results[m_index] = [] - repeat_time = 10 + repeat_time = 1 - output_dir = f"results/{exp_name}" + output_dir = f"{project_dir}/checkpoints/{exp_name}" save_path = Path(output_dir) save_path.mkdir(parents=True, exist_ok=True) - set_logging(exp_name, "INFO", str(save_path)) - logging.info(f"Set seed: {opt.seed}") + print(f"Set seed: {opt.seed}") set_seed(opt.seed) - logging.info(f"save_path: {save_path}") + print(f"save_path: {save_path}") np.set_printoptions(precision=3) torch.set_printoptions(precision=3) - root = "../data/" + root = f"{project_dir}/data" train_loader = get_celeba( root, - batch_size=opt.bs, - target_attr=opt.task, + batch_size=opt.batch_size, + target_attr=opt.target, split="train", aug=False, ) val_loaders = {} - val_loaders["valid"] = get_celeba( - root, batch_size=256, target_attr=opt.task, split="train_valid", aug=False - ) + val_loaders["valid"] = get_celeba(root, batch_size=256, target_attr=opt.target, split="train_valid", aug=False) - val_loaders["test"] = get_celeba( - root, batch_size=256, target_attr=opt.task, split="valid", aug=False - ) + val_loaders["test"] = get_celeba(root, batch_size=256, target_attr=opt.target, split="valid", aug=False) for r in range(repeat_time): - logging.info(f"Repeated experiment: {r+1}") + # print(f"Repeated experiment: {r+1}") model, criterion, protected_net = set_model(opt) + # Evaluation + if opt.checkpoint: + model.load_state_dict(torch.load(f"{save_path}/best_model.pt")["model"]) + model.eval() + + with torch.no_grad(): + all_labels, all_biases, all_preds = [], [], [] + for idx, (images, labels, biases, _) in enumerate(val_loaders["test"]): + images = images.cuda() + output, _ = model(images) + preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() + + all_labels.append(labels) + all_biases.append(biases) + all_preds.append(preds) + + fin_labels = torch.cat(all_labels) + fin_biases = torch.cat(all_biases) + fin_preds = torch.cat(all_preds) + + ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) + print_all_metrics(ret=ret) + + sys.exit() + + # ret["time per epoch"] = total_time / opt.epochs + # for i in range(len(metric_index)): + # results[metric_index[i]].append(ret[metric_index[i]]) + + # for m_index in metric_index: + # fout.write(m_index + "\t") + # for i in range(repeat_time): + # fout.write("%f\t" % results[m_index][i]) + # fout.write("%f\t%f\n" % (mean(results[m_index]), std(results[m_index]))) + # fout.close() + decay_epochs = [opt.epochs // 3, opt.epochs * 2 // 3] optimizer = torch.optim.Adam(model.parameters(), lr=opt.lr, weight_decay=1e-4) - scheduler = torch.optim.lr_scheduler.MultiStepLR( - optimizer, milestones=decay_epochs, gamma=0.1 - ) - logging.info(f"decay_epochs: {decay_epochs}") - - (save_path / "checkpoints").mkdir(parents=True, exist_ok=True) + scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=decay_epochs, gamma=0.1) + print(f"decay_epochs: {decay_epochs}") best_accs = {"valid": 0, "test": 0} best_epochs = {"valid": 0, "test": 0} best_stats = {} start_time = time.time() for epoch in range(1, opt.epochs + 1): - logging.info( - f"[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}" - ) + print(f"[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}") # loss = train(train_loader, model, criterion, optimizer) - # logging.info(f"[{epoch} / {opt.epochs}] Loss: {loss:.4f}") - loss, cllossp, milossp = train( - train_loader, model, criterion, optimizer, protected_net, opt - ) - logging.info( - f"[{epoch} / {opt.epochs}] Loss: {loss} Loss CE: {cllossp} Loss MI: {milossp}" - ) + # print(f"[{epoch} / {opt.epochs}] Loss: {loss:.4f}") + loss, cllossp, milossp = train(train_loader, model, criterion, optimizer, protected_net, opt) + print(f"[{epoch} / {opt.epochs}] Loss: {loss} Loss CE: {cllossp} Loss MI: {milossp}") scheduler.step() stats = pretty_dict(epoch=epoch) @@ -222,66 +221,27 @@ def main(): stats[f"{key}/acc"] = accs.item() stats[f"{key}/acc_unbiased"] = torch.mean(valid_attrwise_accs).item() * 100 eye_tsr = torch.eye(2) - stats[f"{key}/acc_skew"] = ( - valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 - ) - stats[f"{key}/acc_align"] = ( - valid_attrwise_accs[eye_tsr == 0.0].mean().item() * 100 - ) + stats[f"{key}/acc_skew"] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 + stats[f"{key}/acc_align"] = valid_attrwise_accs[eye_tsr == 0.0].mean().item() * 100 - logging.info(f"[{epoch} / {opt.epochs}] {valid_attrwise_accs} {stats}") + print(f"[{epoch} / {opt.epochs}] {valid_attrwise_accs} {stats}") for tag in val_loaders.keys(): if stats[f"{tag}/acc_unbiased"] > best_accs[tag]: best_accs[tag] = stats[f"{tag}/acc_unbiased"] best_epochs[tag] = epoch - best_stats[tag] = pretty_dict( - **{f"best_{tag}_{k}": v for k, v in stats.items()} - ) + best_stats[tag] = pretty_dict(**{f"best_{tag}_{k}": v for k, v in stats.items()}) - save_file = save_path / "checkpoints" / f"best_{tag}_repeat{r+1}.pth" - save_model(model, optimizer, opt, epoch, save_file) - logging.info( + print( f"[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}" ) + save_file = save_path / "best_model.pt" + save_model(model, optimizer, opt, epoch, save_file) + total_time = time.time() - start_time total_time_str = str(datetime.timedelta(seconds=int(total_time))) - logging.info(f"Total training time: {total_time_str}") - - save_file = save_path / "checkpoints" / f"last_repeat{r+1}.pth" - save_model(model, optimizer, opt, opt.epochs, save_file) - - # Evaluation - model.eval() - - with torch.no_grad(): - all_labels, all_biases, all_preds = [], [], [] - for idx, (images, labels, biases, _) in enumerate(val_loaders["test"]): - images = images.cuda() - output, _ = model(images) - preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() - - all_labels.append(labels) - all_biases.append(biases) - all_preds.append(preds) - - fin_labels = torch.cat(all_labels) - fin_biases = torch.cat(all_biases) - fin_preds = torch.cat(all_preds) - - ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) - print_all_metrics(ret=ret) - - ret['time per epoch'] = total_time / opt.epochs - for i in range(len(metric_index)): - results[metric_index[i]].append(ret[metric_index[i]]) - - for m_index in metric_index: - fout.write(m_index + "\t") - for i in range(repeat_time): - fout.write("%f\t" % results[m_index][i]) - fout.write("%f\t%f\n" % (mean(results[m_index]), std(results[m_index]))) - fout.close() + print(f"Total training time: {total_time_str}") + print(f"Time per epoch: {total_time / opt.epochs:.6f}") if __name__ == "__main__": diff --git a/FLAC/train_cifar10s.py b/FLAC/train_cifar10s.py index 1644cbb..6461d46 100644 --- a/FLAC/train_cifar10s.py +++ b/FLAC/train_cifar10s.py @@ -1,19 +1,18 @@ import os +import sys import time +import torch import logging import argparse import datetime import numpy as np +from torch import nn from tqdm import tqdm from pathlib import Path from numpy import mean, std -import torch -from torch import nn, optim - -import sys - -sys.path.insert(1, "./") +project_dir = "/root/DL-Fairness-Study" +sys.path.insert(1, os.path.join(project_dir, "FLAC")) from flac import flac_loss from models.resnet import ResNet18 @@ -21,30 +20,10 @@ from datasets.cifar10s import get_cifar10s from utils.utils import AverageMeter, MultiDimAverageMeter, accuracy, load_model, save_model, set_seed, pretty_dict -sys.path.insert(1, "/root/study") -from metrics import get_metric_index, get_all_metrics, print_all_metrics - - -def parse_option(): - parser = argparse.ArgumentParser() - parser.add_argument("--exp_name", type=str, default="test") - parser.add_argument("--gpu", type=int, default=0) - parser.add_argument( - "--color_classifier", - type=str, - default="./bias_capturing_classifiers/bcc_cifar10s.pth", - ) - parser.add_argument("--epochs", type=int, default=200, help="number of training epochs") - parser.add_argument("--seed", type=int, default=1) - parser.add_argument("--bs", type=int, default=128, help="batch_size") - parser.add_argument("--lr", type=float, default=1e-3) - parser.add_argument("--alpha", type=float, default=1000) - parser.add_argument("--skewed_ratio", type=float, default=0.95) +sys.path.insert(1, project_dir) - opt = parser.parse_args() - os.environ["CUDA_VISIBLE_DEVICES"] = str(opt.gpu) - - return opt +from arguments import get_args +from metrics import get_metric_index, get_all_metrics, print_all_metrics def train_per_epoch(model, train_loader, criterion, optimizer): @@ -192,67 +171,100 @@ def train(opt, model, protected_net, train_loader, criterion, optimizer): def main(): - opt = parse_option() + opt = get_args() + exp_name = f"flac-cifar10s-lr{opt.lr}-bs{opt.batch_size}-epochs{opt.epochs}-alpha{opt.alpha}-seed{opt.seed}" - exp_name = f"flac-cifar10s-{opt.exp_name}-lr{opt.lr}-alpha{opt.alpha}-bs{opt.bs}-seed{opt.seed}" - opt.exp_name = exp_name + # result_dir = "../results/cifar10s" + # result_path = Path(result_dir) + # result_path.mkdir(parents=True, exist_ok=True) + # fout = open("/".join([str(result_path), "flac.txt"]), "w") - result_dir = "../results/cifar10s" - result_path = Path(result_dir) - result_path.mkdir(parents=True, exist_ok=True) - fout = open("/".join([str(result_path), "flac.txt"]), "w") + # results = {} + # metric_index = get_metric_index() + # for m_index in metric_index: + # results[m_index] = [] - results = {} - metric_index = get_metric_index() - for m_index in metric_index: - results[m_index] = [] + repeat_time = 1 - repeat_time = 10 - - output_dir = f"results/{exp_name}" + output_dir = f"{project_dir}/checkpoints/{exp_name}" save_path = Path(output_dir) save_path.mkdir(parents=True, exist_ok=True) - set_logging(exp_name, "INFO", str(save_path)) - logging.info(f"Set seed: {opt.seed}") + print(f"Set seed: {opt.seed}") set_seed(opt.seed) - logging.info(f"save_path: {save_path}") + print(f"save_path: {save_path}") np.set_printoptions(precision=3) torch.set_printoptions(precision=3) - root = "../data/cifar10s" - train_loader = get_cifar10s(root, split="train", batch_size=opt.bs, aug=False, skewed_ratio=opt.skewed_ratio) - val_loader = get_cifar10s(root, split="valid", batch_size=opt.bs, aug=False, skewed_ratio=opt.skewed_ratio) - test_loader = get_cifar10s(root, split="test", batch_size=opt.bs, aug=False, skewed_ratio=opt.skewed_ratio) + root = f"{project_dir}/data/cifar10s" + train_loader = get_cifar10s(root, split="train", batch_size=opt.batch_size, aug=False, skewed_ratio=opt.skew_ratio) + val_loader = get_cifar10s(root, split="valid", batch_size=opt.batch_size, aug=False, skewed_ratio=opt.skew_ratio) + test_loader = get_cifar10s(root, split="test", batch_size=opt.batch_size, aug=False, skewed_ratio=opt.skew_ratio) + opt.color_classifier = f"{project_dir}/FLAC/bias_capturing_classifiers/bcc_cifar10s.pth" bcc_path = Path(opt.color_classifier) if not bcc_path.exists(): # Train a vanilla bias-capturing classifier on CIFAR-10S dataset with a standard cross entropy loss train_vanilla(opt, train_loader, val_loader, test_loader) for r in range(repeat_time): - logging.info(f"Repeated experiment: {r+1}") + # print(f"Repeated experiment: {r+1}") model, criterion, protected_net = set_model(opt) + # Evaluation + if opt.checkpoint: + model.load_state_dict(torch.load(f"{save_path}/best_model.pt")["model"]) + model.eval() + + with torch.no_grad(): + all_labels, all_biases, all_preds = [], [], [] + for images, labels, biases, _ in test_loader: + images = images.cuda() + + output, _ = model(images) + preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() + + all_labels.append(labels) + all_biases.append(biases) + all_preds.append(preds) + + fin_labels = torch.cat(all_labels) + fin_biases = torch.cat(all_biases) + fin_preds = torch.cat(all_preds) + + ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) + print_all_metrics(ret=ret) + + sys.exit() + + # ret["time per epoch"] = total_time / opt.epochs + # for i in range(len(metric_index)): + # results[metric_index[i]].append(ret[metric_index[i]]) + + # for m_index in metric_index: + # fout.write(m_index + "\t") + # for i in range(repeat_time): + # fout.write("%f\t" % results[m_index][i]) + # fout.write("%f\t%f\n" % (mean(results[m_index]), std(results[m_index]))) + # fout.close() + decay_epochs = [opt.epochs // 3, opt.epochs * 2 // 3] - logging.info(f"decay_epochs: {decay_epochs}") + print(f"decay_epochs: {decay_epochs}") optimizer = torch.optim.Adam(model.parameters(), lr=opt.lr, weight_decay=1e-4) scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=decay_epochs, gamma=0.1) - (save_path / "checkpoints").mkdir(parents=True, exist_ok=True) - best_accs = 0 best_epochs = 0 best_stats = {} start_time = time.time() for epoch in range(1, opt.epochs + 1): - logging.info(f"Epoch {epoch}") - logging.info(f"[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}") + print(f"Epoch {epoch}") + print(f"[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}") loss, cllossp, milossp = train(opt, model, protected_net, train_loader, criterion, optimizer) - logging.info(f"[{epoch} / {opt.epochs}] Loss: {loss} Loss CE: {cllossp} Loss MI: {milossp}") + print(f"[{epoch} / {opt.epochs}] Loss: {loss} Loss CE: {cllossp} Loss MI: {milossp}") scheduler.step() stats = pretty_dict(epoch=epoch) @@ -265,57 +277,22 @@ def main(): stats["test/acc"] = test_accs.item() stats["test/acc_unbiased"] = torch.mean(test_attrwise_accs).item() * 100 - logging.info(f"[{epoch} / {opt.epochs}] {stats}") + print(f"[{epoch} / {opt.epochs}] {stats}") if stats["test/acc_unbiased"] > best_accs: best_accs = stats["test/acc_unbiased"] best_epochs = epoch best_stats = pretty_dict(**{f"best_{k}": v for k, v in stats.items()}) - save_file = save_path / "checkpoints" / f"best_test_repeat{r+1}.pth" - save_model(model, optimizer, opt, epoch, save_file) + print(f"[{epoch} / {opt.epochs}] best test accuracy: {best_accs:.6f} at epoch {best_epochs} \n best_stats: {best_stats}") - logging.info(f"[{epoch} / {opt.epochs}] best test accuracy: {best_accs:.6f} at epoch {best_epochs} \n best_stats: {best_stats}") + save_file = save_path / "best_model.pt" + save_model(model, optimizer, opt, epoch, save_file) total_time = time.time() - start_time total_time_str = str(datetime.timedelta(seconds=int(total_time))) - logging.info(f"Total training time: {total_time_str}") - - save_file = save_path / "checkpoints" / f"last_repeat{r+1}.pth" - save_model(model, optimizer, opt, opt.epochs, save_file) - - # Evaluation - model.eval() - - with torch.no_grad(): - all_labels, all_biases, all_preds = [], [], [] - for images, labels, biases, _ in test_loader: - images = images.cuda() - - output, _ = model(images) - preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() - - all_labels.append(labels) - all_biases.append(biases) - all_preds.append(preds) - - fin_labels = torch.cat(all_labels) - fin_biases = torch.cat(all_biases) - fin_preds = torch.cat(all_preds) - - ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) - print_all_metrics(ret=ret) - - ret["time per epoch"] = total_time / opt.epochs - for i in range(len(metric_index)): - results[metric_index[i]].append(ret[metric_index[i]]) - - for m_index in metric_index: - fout.write(m_index + "\t") - for i in range(repeat_time): - fout.write("%f\t" % results[m_index][i]) - fout.write("%f\t%f\n" % (mean(results[m_index]), std(results[m_index]))) - fout.close() + print(f"Total training time: {total_time_str}") + print(f"Time per epoch: {total_time / opt.epochs:.6f}") if __name__ == "__main__": diff --git a/FLAC/train_utk_face.py b/FLAC/train_utk_face.py index 633fcbd..958e23a 100644 --- a/FLAC/train_utk_face.py +++ b/FLAC/train_utk_face.py @@ -1,17 +1,23 @@ -import argparse -import datetime -import logging import os +import sys import time -from pathlib import Path - -import numpy as np import torch +import logging +import argparse +import datetime +import numpy as np from torch import nn +from tqdm import tqdm +from pathlib import Path +from numpy import mean, std + +project_dir = "/root/DL-Fairness-Study" +sys.path.insert(1, os.path.join(project_dir, "FLAC")) + from flac import flac_loss -from datasets.utk_face import get_utk_face from models.resnet import ResNet18 from utils.logging import set_logging +from datasets.utk_face import get_utk_face from utils.utils import ( AverageMeter, MultiDimAverageMeter, @@ -22,38 +28,21 @@ set_seed, ) -import sys -sys.path.insert(1, "/root/study") - -from numpy import mean, std -from metrics import get_metric_index, get_all_metrics, print_all_metrics - - -def parse_option(): - parser = argparse.ArgumentParser() - parser.add_argument("--exp_name", type=str, default="test") - parser.add_argument("--gpu", type=int, default=0) - parser.add_argument("--task", type=str, default="race") - parser.add_argument("--epochs", type=int, default=20) - parser.add_argument("--seed", type=int, default=1) - parser.add_argument("--bs", type=int, default=128, help="batch_size") - parser.add_argument("--lr", type=float, default=1e-3) - parser.add_argument("--alpha", type=float, default=1000) - opt = parser.parse_args() - os.environ["CUDA_VISIBLE_DEVICES"] = str(opt.gpu) +sys.path.insert(1, project_dir) - return opt +from arguments import get_args +from metrics import get_metric_index, get_all_metrics, print_all_metrics def set_model(opt): model = ResNet18().cuda() criterion1 = nn.CrossEntropyLoss() protected_net = ResNet18() - if opt.task == "race": - protected_attr_model = "./bias_capturing_classifiers/bcc_race.pth" - elif opt.task == "age": - protected_attr_model = "./bias_capturing_classifiers/bcc_age.pth" + if opt.sensitive == "race": + protected_attr_model = f"{project_dir}/FLAC/bias_capturing_classifiers/bcc_race.pth" + elif opt.sensitive == "age": + protected_attr_model = f"{project_dir}/FLAC/bias_capturing_classifiers/bcc_age.pth" dd = load_model(protected_attr_model) protected_net.load_state_dict(dd) protected_net.cuda() @@ -115,94 +104,112 @@ def validate(val_loader, model): top1.update(acc1[0], bsz) corrects = (preds == labels).long() - attrwise_acc_meter.add( - corrects.cpu(), torch.stack([labels.cpu(), biases.cpu()], dim=1) - ) + attrwise_acc_meter.add(corrects.cpu(), torch.stack([labels.cpu(), biases.cpu()], dim=1)) return top1.avg, attrwise_acc_meter.get_mean() def main(): - opt = parse_option() - - exp_name = f"flac-utk_face_{opt.task}-{opt.exp_name}-lr{opt.lr}-alpha{opt.alpha}-bs{opt.bs}-seed{opt.seed}" - opt.exp_name = exp_name + opt = get_args() + exp_name = f"flac-utkface_{opt.sensitive}-lr{opt.lr}-bs{opt.batch_size}-epochs{opt.epochs}-alpha{opt.alpha}-seed{opt.seed}" - result_dir = f"../results/utkface" - result_path = Path(result_dir) - result_path.mkdir(parents=True, exist_ok=True) - if opt.task == "age": - fout = open("/".join([str(result_path), f"flac_age_gender.txt"]), "w") - elif opt.task == "race": - fout = open("/".join([str(result_path), f"flac_race_gender.txt"]), "w") + # result_dir = f"../results/utkface" + # result_path = Path(result_dir) + # result_path.mkdir(parents=True, exist_ok=True) + # if opt.sensitive == "age": + # fout = open("/".join([str(result_path), f"flac_age_gender.txt"]), "w") + # elif opt.sensitive == "race": + # fout = open("/".join([str(result_path), f"flac_race_gender.txt"]), "w") - results = {} - metric_index = get_metric_index() - for m_index in metric_index: - results[m_index] = [] + # results = {} + # metric_index = get_metric_index() + # for m_index in metric_index: + # results[m_index] = [] - repeat_time = 10 + repeat_time = 1 - output_dir = f"results/{exp_name}" + output_dir = f"{project_dir}/checkpoints/{exp_name}" save_path = Path(output_dir) save_path.mkdir(parents=True, exist_ok=True) - set_logging(exp_name, "INFO", str(save_path)) - logging.info(f"Set seed: {opt.seed}") + print(f"Set seed: {opt.seed}") set_seed(opt.seed) - logging.info(f"save_path: {save_path}") + print(f"save_path: {save_path}") np.set_printoptions(precision=3) torch.set_printoptions(precision=3) - root = "../data/utkface" + root = f"{project_dir}/data/utkface" train_loader = get_utk_face( root, - batch_size=opt.bs, - bias_attr=opt.task, + batch_size=opt.batch_size, + bias_attr=opt.sensitive, split="train", aug=False, ) val_loaders = {} - val_loaders["valid"] = get_utk_face( - root, batch_size=256, bias_attr=opt.task, split="valid", aug=False - ) + val_loaders["valid"] = get_utk_face(root, batch_size=256, bias_attr=opt.sensitive, split="valid", aug=False) - val_loaders["test"] = get_utk_face( - root, batch_size=256, bias_attr=opt.task, split="test", aug=False - ) + val_loaders["test"] = get_utk_face(root, batch_size=256, bias_attr=opt.sensitive, split="test", aug=False) for r in range(repeat_time): - logging.info(f"Repeated experiment: {r+1}") + # print(f"Repeated experiment: {r+1}") model, criterion, protected_net = set_model(opt) + # Evaluation + if opt.checkpoint: + model.load_state_dict(torch.load(f"{save_path}/best_model.pt")["model"]) + model.eval() + + with torch.no_grad(): + all_labels, all_biases, all_preds = [], [], [] + for idx, (images, labels, biases, _) in enumerate(val_loaders["test"]): + images = images.cuda() + + output, _ = model(images) + preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() + + all_labels.append(labels) + all_biases.append(biases) + all_preds.append(preds) + + fin_labels = torch.cat(all_labels) + fin_biases = torch.cat(all_biases) + fin_preds = torch.cat(all_preds) + + ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) + print_all_metrics(ret=ret) + + sys.exit() + + # ret["time per epoch"] = total_time / opt.epochs + # for i in range(len(metric_index)): + # results[metric_index[i]].append(ret[metric_index[i]]) + + # for m_index in metric_index: + # fout.write(m_index + "\t") + # for i in range(repeat_time): + # fout.write("%f\t" % results[m_index][i]) + # fout.write("%f\t%f\n" % (mean(results[m_index]), std(results[m_index]))) + # fout.close() + decay_epochs = [opt.epochs // 3, opt.epochs * 2 // 3] optimizer = torch.optim.Adam(model.parameters(), lr=opt.lr) - scheduler = torch.optim.lr_scheduler.MultiStepLR( - optimizer, milestones=decay_epochs, gamma=0.1 - ) - - logging.info(f"decay_epochs: {decay_epochs}") + scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=decay_epochs, gamma=0.1) - (save_path / "checkpoints").mkdir(parents=True, exist_ok=True) + print(f"decay_epochs: {decay_epochs}") best_accs = {"valid": 0, "test": 0} best_epochs = {"valid": 0, "test": 0} best_stats = {} start_time = time.time() for epoch in range(1, opt.epochs + 1): - logging.info( - f"[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}" - ) - loss, cllossp, milossp = train( - train_loader, model, criterion, optimizer, protected_net, opt - ) - logging.info( - f"[{epoch} / {opt.epochs}] Loss: {loss} Loss CE: {cllossp} Loss MI: {milossp}" - ) + print(f"[{epoch} / {opt.epochs}] Learning rate: {scheduler.get_last_lr()[0]}") + loss, cllossp, milossp = train(train_loader, model, criterion, optimizer, protected_net, opt) + print(f"[{epoch} / {opt.epochs}] Loss: {loss} Loss CE: {cllossp} Loss MI: {milossp}") scheduler.step() @@ -213,67 +220,27 @@ def main(): stats[f"{key}/acc"] = accs.item() stats[f"{key}/acc_unbiased"] = torch.mean(valid_attrwise_accs).item() * 100 eye_tsr = torch.eye(2) - stats[f"{key}/acc_skew"] = ( - valid_attrwise_accs[eye_tsr == 0.0].mean().item() * 100 - ) - stats[f"{key}/acc_align"] = ( - valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 - ) + stats[f"{key}/acc_skew"] = valid_attrwise_accs[eye_tsr == 0.0].mean().item() * 100 + stats[f"{key}/acc_align"] = valid_attrwise_accs[eye_tsr > 0.0].mean().item() * 100 - logging.info(f"[{epoch} / {opt.epochs}] {valid_attrwise_accs} {stats}") + print(f"[{epoch} / {opt.epochs}] {valid_attrwise_accs} {stats}") for tag in val_loaders.keys(): if stats[f"{tag}/acc_unbiased"] > best_accs[tag]: best_accs[tag] = stats[f"{tag}/acc_unbiased"] best_epochs[tag] = epoch - best_stats[tag] = pretty_dict( - **{f"best_{tag}_{k}": v for k, v in stats.items()} - ) + best_stats[tag] = pretty_dict(**{f"best_{tag}_{k}": v for k, v in stats.items()}) - save_file = save_path / "checkpoints" / f"best_{tag}_{r+1}.pth" - save_model(model, optimizer, opt, epoch, save_file) - logging.info( + print( f"[{epoch} / {opt.epochs}] best {tag} accuracy: {best_accs[tag]:.3f} at epoch {best_epochs[tag]} \n best_stats: {best_stats[tag]}" ) + save_file = save_path / "best_model.pt" + save_model(model, optimizer, opt, epoch, save_file) + total_time = time.time() - start_time total_time_str = str(datetime.timedelta(seconds=int(total_time))) - logging.info(f"Total training time: {total_time_str}") - - save_file = save_path / "checkpoints" / f"last_{r+1}.pth" - save_model(model, optimizer, opt, opt.epochs, save_file) - - # Evaluation - model.eval() - - with torch.no_grad(): - all_labels, all_biases, all_preds = [], [], [] - for idx, (images, labels, biases, _) in enumerate(val_loaders["test"]): - images = images.cuda() - - output, _ = model(images) - preds = output.data.max(1, keepdim=True)[1].squeeze(1).cpu() - - all_labels.append(labels) - all_biases.append(biases) - all_preds.append(preds) - - fin_labels = torch.cat(all_labels) - fin_biases = torch.cat(all_biases) - fin_preds = torch.cat(all_preds) - - ret = get_all_metrics(y_true=fin_labels, y_pred=fin_preds, sensitive_features=fin_biases) - print_all_metrics(ret=ret) - - ret['time per epoch'] = total_time / opt.epochs - for i in range(len(metric_index)): - results[metric_index[i]].append(ret[metric_index[i]]) - - for m_index in metric_index: - fout.write(m_index + "\t") - for i in range(repeat_time): - fout.write("%f\t" % results[m_index][i]) - fout.write("%f\t%f\n" % (mean(results[m_index]), std(results[m_index]))) - fout.close() + print(f"Total training time: {total_time_str}") + print(f"Time per epoch: {total_time / opt.epochs:.6f}") if __name__ == "__main__": diff --git a/FR/datasets/__init__.py b/FR/datasets/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/FR/datasets/celeba.py b/FR/datasets/celeba.py new file mode 100644 index 0000000..d3825dc --- /dev/null +++ b/FR/datasets/celeba.py @@ -0,0 +1,87 @@ +import torch +import pickle +import numpy as np +from pathlib import Path +from torchvision import transforms +from torchvision.datasets.celeba import CelebA +from torch.utils.data.dataloader import DataLoader + + +class MyCelebA: + def __init__(self, root, split, transform, target_attr): + self.transform = transform + self.target_attr = target_attr + + self.celeba = CelebA(root=root, split=split, target_type="attr", transform=transform) + + self.bias_idx = 20 # Gender Attribute. + + if target_attr == "Blond_Hair": + self.target_idx = 9 + if split in ["train"]: + save_path = Path(root) / "celeba" / "pickles" / "blonde" + if save_path.is_dir(): + print(f"use existing blonde indices from {save_path}") + self.indices = pickle.load(open(save_path / "indices.pkl", "rb")) + else: + self.indices = self.build_blonde() + print(f"save blonde indices to {save_path}") + save_path.mkdir(parents=True, exist_ok=True) + pickle.dump(self.indices, open(save_path / f"indices.pkl", "wb")) + self.attr = self.celeba.attr[self.indices] + else: + self.attr = self.celeba.attr + self.indices = torch.arange(len(self.celeba)) + + else: + raise AttributeError + + self.targets = self.attr[:, self.target_idx] + self.bias_targets = self.attr[:, self.bias_idx] + + def build_blonde(self): + bias_targets = self.celeba.attr[:, self.bias_idx] + targets = self.celeba.attr[:, self.target_idx] + selects = torch.arange(len(self.celeba))[(bias_targets == 0) & (targets == 0)] + non_selects = torch.arange(len(self.celeba))[~((bias_targets == 0) & (targets == 0))] + np.random.seed(1) + np.random.shuffle(selects) + indices = torch.cat([selects[:2000], non_selects]) + return indices + + def __getitem__(self, index): + img, _ = self.celeba.__getitem__(self.indices[index]) + target, bias = self.targets[index], self.bias_targets[index] + + return img, target, bias + + def __len__(self): + return len(self.targets) + + +def get_celeba(root, split, target_attr, img_size, batch_size, num_workers=4): + if split == "train": + transform = transforms.Compose( + [ + transforms.Resize((img_size, img_size)), + transforms.RandomHorizontalFlip(), + transforms.ToTensor(), + transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), + ] + ) + else: + transform = transforms.Compose( + [ + transforms.Resize((img_size, img_size)), + transforms.ToTensor(), + transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), + ] + ) + + dataset = MyCelebA(root=root, split=split, transform=transform, target_attr=target_attr) + + print(f"\nget_celeba - split: {split} size: {len(dataset)}") + + dataloader = DataLoader(dataset=dataset, batch_size=batch_size, shuffle=True if split == "train" else False, num_workers=num_workers) + + return dataset, dataloader diff --git a/FR/datasets/cifar10s.py b/FR/datasets/cifar10s.py new file mode 100644 index 0000000..771b077 --- /dev/null +++ b/FR/datasets/cifar10s.py @@ -0,0 +1,142 @@ +import torch +import random +import numpy as np +import torchvision.transforms as transforms + +from PIL import Image +from tqdm import tqdm +from torch.utils.data import DataLoader +from torchvision.datasets import CIFAR10 + + +class CIFAR_10S: + def __init__(self, root, split, transform, skew_ratio): + self.transform = transform + train_valid = split == "train" + self.cifar10 = CIFAR10(root, train=train_valid, download=True) + self.images = self.cifar10.data + self.targets = np.array(self.cifar10.targets) + self.bias_targets = np.zeros_like(self.targets) + self.split = split + + if not train_valid: + self.build_split() + + if split == "train": + print("********") + print("Skew ratio used %.2f" % skew_ratio) + print("********") + + self.corrupt_dataset(skew_ratio) + + else: + self.corrupt_test_dataset() + + self.targets, self.bias_targets = torch.from_numpy(self.targets).long(), torch.from_numpy(self.bias_targets).long() + + def build_split(self): + indices = {i: [] for i in range(10)} + size_per_class = 1000 + for idx, tar in enumerate(self.targets): + indices[tar].append(idx) + + if self.split == "test": + start = 0 + end = int(size_per_class * 0.9) + + if self.split == "valid": + start = int(size_per_class * 0.9) + end = size_per_class + + final_indices = [] + for ind_group in indices.values(): + final_indices.extend(ind_group[start:end]) + + np.random.seed(1) + np.random.shuffle(final_indices) + + self.images = self.images[final_indices] + self.bias_targets = self.bias_targets[final_indices] + self.targets = self.targets[final_indices] + + def rgb_to_grayscale(self, img): + """Convert image to gray scale""" + + pil_img = Image.fromarray(img) + pil_gray_img = pil_img.convert("L") + np_gray_img = np.array(pil_gray_img, dtype=np.uint8) + np_gray_img = np.dstack([np_gray_img, np_gray_img, np_gray_img]) + + return np_gray_img + + def corrupt_test_dataset(self): + self.images_gray = np.copy(self.images) + self.bias_targets_gray = np.copy(self.bias_targets) + self.targets_gray = np.copy(self.targets) + + for idx, img in enumerate(self.images_gray): + self.images_gray[idx] = self.rgb_to_grayscale(img) + self.bias_targets_gray[idx] = 1 + + self.images = np.concatenate((self.images, self.images_gray), axis=0) + self.bias_targets = np.concatenate((self.bias_targets, self.bias_targets_gray), axis=0) + self.targets = np.concatenate((self.targets, self.targets_gray), axis=0) + + def corrupt_dataset(self, skew_level): + gray_classes = [0, 2, 4, 6, 8] + + samples_by_class = {i: [] for i in range(10)} + for idx, target in enumerate(self.targets): + samples_by_class[target].append(idx) + + for class_idx in tqdm(range(10), ascii=True): + class_samples = samples_by_class[class_idx] + if class_idx in gray_classes: + samples_skew_num = int(len(class_samples) * skew_level) + else: + samples_skew_num = int(len(class_samples) * (1 - skew_level)) + + random.seed(1) + samples_skew = random.sample(class_samples, samples_skew_num) + for sample_idx in samples_skew: + self.images[sample_idx] = self.rgb_to_grayscale(self.images[sample_idx]) + self.bias_targets[sample_idx] = 1 + + def __len__(self): + return len(self.images) + + def __getitem__(self, index): + img = self.images[index] + target = self.targets[index] + bias = self.bias_targets[index] + + if self.transform: + img = self.transform(img) + + return img, target, bias + + +def get_cifar10s(root, split, img_size, batch_size, skew_ratio=0.95, num_workers=4): + mean = [0.4914, 0.4822, 0.4465] + std = [0.2470, 0.2435, 0.2616] + + if split == "test" or split == "valid": + transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize(mean, std)]) + else: + transform = transforms.Compose( + [ + transforms.ToPILImage(), + transforms.RandomCrop(img_size, padding=4), + transforms.RandomHorizontalFlip(), + transforms.ToTensor(), + transforms.Normalize(mean, std), + ] + ) + + dataset = CIFAR_10S(root=root, split=split, transform=transform, skew_ratio=skew_ratio) + + print(f"\nget_cifar10s - split: {split} size: {len(dataset)}") + + dataloader = DataLoader(dataset=dataset, batch_size=batch_size, shuffle=True if split == "train" else False, num_workers=num_workers) + + return dataset, dataloader diff --git a/FR/datasets/utkface.py b/FR/datasets/utkface.py new file mode 100644 index 0000000..be85c7d --- /dev/null +++ b/FR/datasets/utkface.py @@ -0,0 +1,160 @@ +import os +import PIL +import torch +import pickle +import numpy as np + +from pathlib import Path +from torchvision import transforms +from torch.utils.data import DataLoader + + +class UTKFace: + def __init__(self, root, split, transform, bias_attr, bias_rate=0.9): + self.root = Path(root) / "images" + filenames = np.array(os.listdir(self.root)) + np.random.seed(1) + np.random.shuffle(filenames) + num_files = len(filenames) + num_train = int(num_files * 0.8) + target_attr = "gender" + + self.transform = transform + self.target_attr = target_attr + self.bias_rate = bias_rate + self.bias_attr = bias_attr + self.train = split == "train" + + save_path = Path(root) / "pickles" / f"biased_utk_face-target_{target_attr}-bias_{bias_attr}-{bias_rate}" + if save_path.is_dir(): + print(f"use existing biased_utk_face from {save_path}") + data_split = "train" if self.train else "test" + self.files, self.targets, self.bias_targets = pickle.load(open(save_path / f"{data_split}_dataset.pkl", "rb")) + if split in ["valid", "test"]: + save_path = Path(f"{Path(root).parent.absolute()}/clusters/utk_face_rand_indices_{bias_attr}.pkl") + if not save_path.exists(): + rand_indices = torch.randperm(len(self.targets)) + pickle.dump(rand_indices, open(save_path, "wb")) + else: + rand_indices = pickle.load(open(save_path, "rb")) + num_total = len(rand_indices) + num_valid = int(0.5 * num_total) + + if split == "valid": + indices = rand_indices[:num_valid] + elif split == "test": + indices = rand_indices[num_valid:] + + indices = indices.numpy() + + self.files = self.files[indices] + self.targets = self.targets[indices] + self.bias_targets = self.bias_targets[indices] + else: + train_dataset = self.build(filenames[:num_train], train=True) + test_dataset = self.build(filenames[num_train:], train=False) + + print(f"save biased_utk_face to {save_path}") + save_path.mkdir(parents=True, exist_ok=True) + pickle.dump(train_dataset, open(save_path / f"train_dataset.pkl", "wb")) + pickle.dump(test_dataset, open(save_path / f"test_dataset.pkl", "wb")) + + self.files, self.targets, self.bias_targets = train_dataset if self.train else test_dataset + + self.targets, self.bias_targets = torch.from_numpy(self.targets).long(), torch.from_numpy(self.bias_targets).long() + + def build(self, filenames, train=False): + attr_dict = { + "age": ( + 0, + lambda x: x >= 20, + lambda x: x <= 10, + ), + "gender": (1, lambda x: x == 0, lambda x: x == 1), + "race": (2, lambda x: x == 0, lambda x: x != 0), + } + assert self.target_attr in attr_dict.keys() + target_cls_idx, *target_filters = attr_dict[self.target_attr] + bias_cls_idx, *bias_filters = attr_dict[self.bias_attr] + + target_classes = self.get_class_from_filename(filenames, target_cls_idx) + bias_classes = self.get_class_from_filename(filenames, bias_cls_idx) + + total_files = [] + total_targets = [] + total_bias_targets = [] + + for i in (0, 1): + major_idx = np.where(target_filters[i](target_classes) & bias_filters[i](bias_classes))[0] + minor_idx = np.where(target_filters[1 - i](target_classes) & bias_filters[i](bias_classes))[0] + np.random.seed(1) + np.random.shuffle(minor_idx) + + num_major = major_idx.shape[0] + num_minor_org = minor_idx.shape[0] + if train: + num_minor = int(num_major * (1 - self.bias_rate)) + else: + num_minor = minor_idx.shape[0] + num_minor = min(num_minor, num_minor_org) + num_total = num_major + num_minor + + majors = filenames[major_idx] + minors = filenames[minor_idx][:num_minor] + + total_files.append(np.concatenate((majors, minors))) + total_bias_targets.append(np.ones(num_total) * i) + total_targets.append(np.concatenate((np.ones(num_major) * i, np.ones(num_minor) * (1 - i)))) + + files = np.concatenate(total_files) + targets = np.concatenate(total_targets) + bias_targets = np.concatenate(total_bias_targets) + return files, targets, bias_targets + + def get_class_from_filename(self, filenames, cls_idx): + return np.array([int(fname.split("_")[cls_idx]) if len(fname.split("_")) == 4 else 10 for fname in filenames]) + + def __getitem__(self, index): + filename, target, bias = (self.files[index], int(self.targets[index]), int(self.bias_targets[index])) + X = PIL.Image.open(os.path.join(self.root, filename)) + + if self.transform is not None: + X = self.transform(X) + + return X, target, bias + + def __len__(self): + return len(self.files) + + +def get_utkface(root, split, bias_attr, img_size, batch_size, bias_rate=0.9, num_workers=4): + size_dict = {64: 72, 128: 144, 224: 256} + load_size = size_dict[img_size] + + if split == "train": + transform = transforms.Compose( + [ + transforms.RandomResizedCrop(img_size), + transforms.RandomHorizontalFlip(), + transforms.ToTensor(), + transforms.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)), + ] + ) + + else: + transform = transforms.Compose( + [ + transforms.Resize(load_size), + transforms.CenterCrop(img_size), + transforms.ToTensor(), + transforms.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)), + ] + ) + + dataset = UTKFace(root=root, split=split, transform=transform, bias_attr=bias_attr, bias_rate=bias_rate) + + print(f"\nget_utkface - split: {split} size: {len(dataset)}") + + dataloader = DataLoader(dataset=dataset, batch_size=batch_size, shuffle=True if split == "train" else False, num_workers=num_workers) + + return dataset, dataloader diff --git a/FR/program.py b/FR/program.py index 930b92b..8c3d53a 100644 --- a/FR/program.py +++ b/FR/program.py @@ -16,17 +16,17 @@ def forward(self, mask): class AdvProgram(nn.Module): - def __init__(self, in_size, out_size, mask_size, device=torch.device('cuda')): + def __init__(self, in_size, out_size, mask_size): super(AdvProgram, self).__init__() self.in_size = in_size self.out_size = out_size - self.program = Program(out_size).to(device) + self.program = Program(out_size).cuda() l_pad = int((mask_size[0] - in_size[0] + 1) / 2) r_pad = int((mask_size[0] - in_size[0]) / 2) - mask = torch.zeros(3, *in_size, device=device) + mask = torch.zeros(3, *in_size).cuda() self.mask = F.pad(mask, (l_pad, r_pad, l_pad, r_pad), value=1) def forward(self, x): @@ -35,18 +35,18 @@ def forward(self, x): class PatchProgram(nn.Module): - def __init__(self, patch_size, out_size, loc=0, device=torch.device('cuda')): + def __init__(self, patch_size, out_size, loc=0): super(PatchProgram, self).__init__() assert len(patch_size) == 2 and len(out_size) == 2 and patch_size[0] * 2 < out_size[0] self.trigger_size = patch_size self.out_size = out_size - self.program = Program(out_size).to(device) + self.program = Program(out_size).cuda() - mask = torch.ones(3, *patch_size, device=device) + mask = torch.ones(3, *patch_size).cuda() # background - bg = torch.zeros(3, *out_size, device=device) + bg = torch.zeros(3, *out_size).cuda() # loc represents different corners: # 01 @@ -70,14 +70,13 @@ def forward(self, x): class OptimProgram(nn.Module): - def __init__(self, size, k, device=torch.device('cuda')): + def __init__(self, size, k): super(OptimProgram, self).__init__() self.size = size self.k = k - self.device = device - self.program = Program(size).to(device) + self.program = Program(size).cuda() - self.scores = torch.nn.Parameter(data=torch.Tensor(3, *size)).to(device) + self.scores = torch.nn.Parameter(data=torch.Tensor(3, *size)).cuda() self.scores.data.uniform_(-1, 1) def forward(self, x): diff --git a/FR/test_transfer.py b/FR/test_transfer.py deleted file mode 100644 index 370fea0..0000000 --- a/FR/test_transfer.py +++ /dev/null @@ -1,220 +0,0 @@ -import argparse -from torch.cuda.amp import autocast -from torch import nn -from torch.utils.data import DataLoader -from torchvision.models.resnet import resnet18 - -from dataset import CelebA -from metric import * -from utils import * -from models.model_zoo import * -from program import AdvProgram, PatchProgram - -attr_list = ('5_o_Clock_Shadow,Arched_Eyebrows,Attractive,Bags_Under_Eyes,Bald,Bangs,Big_Lips,Big_Nose,' - 'Black_Hair,Blond_Hair,Blurry,Brown_Hair,Bushy_Eyebrows,Chubby,Double_Chin,Eyeglasses,Goatee,Gray_Hair,' - 'Heavy_Makeup,High_Cheekbones,Male,Mouth_Slightly_Open,Mustache,Narrow_Eyes,No_Beard,Oval_Face,Pale_Skin,' - 'Pointy_Nose,Receding_Hairline,Rosy_Cheeks,Sideburns,Smiling,Straight_Hair,Wavy_Hair,Wearing_Earrings,' - 'Wearing_Hat,Wearing_Lipstick,Wearing_Necklace,Wearing_Necktie,Young' - ).split(',') - -attr_dict = {} -for i, attr in enumerate(attr_list): - attr_dict[attr] = i - -insufficient_attr_list = '5_o_Clock_Shadow,Goatee,Mustache,Sideburns,Wearing_Necktie'.split(',') - - -def get_args(): - parser = argparse.ArgumentParser() - parser.add_argument('--arch', type=str, default="resnet18", choices=["resnet18"]) - parser.add_argument('--data-path', type=str, default=None, required=True) - parser.add_argument('--save-path', type=str, default='results') - parser.add_argument('--load-path', type=str, default=None, required=True) - parser.add_argument('--load-trigger', type=str, default=None) - parser.add_argument('--in-size', type=int, default=170) - parser.add_argument('--trigger-type', type=str, default="normal", choices=["normal", "patch"]) - parser.add_argument('--patch-size', type=int, default=40) - parser.add_argument('--patch-loc', type=int, default=0, choices=[0, 1, 2, 3], - help="left upper corner, right upper corner, left bottom corner, right bottom corner") - parser.add_argument('--exp-name', type=str, default=None) - parser.add_argument('--domain-attrs', type=str, default='Male') - parser.add_argument('--target-attrs', type=str, default='Blond_Hair') - parser.add_argument('--batch-size', type=int, default=512) - parser.add_argument('--seed', type=int, default=42) - parser.add_argument('--num-workers', type=int, default=4) - parser.add_argument('--display', action="store_true", default=False) - - args = parser.parse_args() - - args.domain_attrs = args.domain_attrs.split(',') - assert args.target_attrs in attr_list - args.target_attrs = [args.target_attrs] - - return args - - -def main(args): - device = "cuda:0" if torch.cuda.is_available() else "cpu" - - num_class = 2 - - # init model - if args.arch == "resnet18": - predictor = resnet18(pretrained=False) - predictor.fc = nn.Linear(512, num_class) - else: - predictor = resnet20s(num_class) - predictor = predictor.to(device) - predictor.load_state_dict(torch.load(args.load_path, map_location=device)) - - print("===============================Start Evaluate Standard Model ==================================") - transform_test = transforms.Compose([ - transforms.Resize(256), - transforms.CenterCrop(224), - transforms.ToTensor(), - ]) - test_set = CelebA(args.data_path, args.target_attrs, args.domain_attrs, - img_transform=transform_test, type="test") - test_loader = DataLoader(test_set, batch_size=args.batch_size, num_workers=args.num_workers, pin_memory=True) - - # evaluating - predictor.eval() - pbar = tqdm(test_loader, total=len(test_loader), ncols=120, desc="Testing") - fxs = [] - fxs_prob = [] - ys = [] - ds = [] - test_total_num = 0 - test_true_num = 0 - for x, y, d in pbar: - ys.append(y) - ds.append(d) - x = x.to(device) - y = y.to(device) - with torch.no_grad(), autocast(): - lgt = predictor(x) - fxs_prob.append(lgt) - test_total_num += y.shape[0] - pred = lgt.argmax(1) # [bs] - fxs.append(pred) - test_true_num += (pred == y.view(-1)).type(torch.float).sum().detach().cpu().item() - acc = test_true_num * 1.0 / test_total_num - pbar.set_description(f"Test Acc {100 * acc:.2f}%") - pbar.set_description(f"Test Acc {100 * test_true_num / test_total_num:.2f}%") - - ys, ds = torch.cat(ys).view(-1).cpu().numpy(), torch.cat(ds).view(-1).cpu().numpy() - ds_dict = {"Male": ds, "Female": 1 - ds} - fxs = torch.cat(fxs).view(-1).detach().cpu().numpy() - fxs_prob = torch.cat(fxs_prob, dim=0).detach().cpu().numpy() - - # So that there will not be nan to the get_all_metrics function - fxs_prob = np.clip(fxs_prob, a_min=-100000.0, a_max=100000.0) - - ret_no_class_balance = get_all_metrics(y_true=ys, y_pred=fxs, y_prob=fxs_prob, z=ds_dict, - use_class_balance=False) - accuracy = test_true_num / test_total_num - - print(f"test acc: {accuracy:.4f}") - print(f"Min_ACC_AcrossZY: {ret_no_class_balance['Min_ACC_AcrossZY']: .4f}") - print(f"ED_FPR_AcrossZ: {ret_no_class_balance['ED_FPR_AcrossZ']: .4f}") - print(f"ED_FNR_AcrossZ: {ret_no_class_balance['ED_FNR_AcrossZ']: .4f}") - print( - f"ED_FR_AcrossZ: {(ret_no_class_balance['ED_FPR_AcrossZ'] + ret_no_class_balance['ED_FNR_AcrossZ']): .4f}") - print(f"ED_PO1_AcrossZ: {ret_no_class_balance['ED_PO1_AcrossZ']: .4f}") - - print("===============================Start Evaluating Reprogramming ==================================") - # Reprogram configuration - if args.trigger_type == "normal": - - in_size = (args.in_size, args.in_size) - out_size = (224, 224) - mask_size = out_size - - l_pad = int((out_size[0] - in_size[0] + 1) / 2) - r_pad = int((out_size[0] - in_size[0]) / 2) - - transform_test = transforms.Compose([ - transforms.Resize(256), - transforms.CenterCrop(224), - transforms.Resize(in_size[0]), - transforms.Pad(padding=(l_pad, l_pad, r_pad, r_pad)), - transforms.ToTensor(), - ]) - - # init reprogramme - adv_program = AdvProgram(in_size, out_size, mask_size, device=device) - - else: - out_size = (224, 224) - patch_size = (args.patch_size, args.patch_size) - - transform_test = transforms.Compose([ - transforms.Resize(256), - transforms.CenterCrop(224), - transforms.ToTensor(), - ]) - # init reprogramme - adv_program = PatchProgram(patch_size=patch_size, out_size=out_size, loc=args.patch_loc, device=device) - - if args.load_trigger is not None: - adv_program.load_state_dict(torch.load(args.load_trigger, map_location=device)) - - test_set = CelebA(args.data_path, args.target_attrs, args.domain_attrs, - img_transform=transform_test, type="test") - test_loader = DataLoader(test_set, batch_size=args.batch_size, num_workers=args.num_workers, pin_memory=True) - - # evaluating - adv_program.eval() - pbar = tqdm(test_loader, total=len(test_loader), ncols=120, desc="Testing") - fxs = [] - fxs_prob = [] - y_all = [] - d_all = [] - test_total_num = 0 - test_true_num = 0 - for x, y, d in pbar: - y_all.append(y) - d_all.append(d) - x = x.to(device) - y = y.to(device) - with torch.no_grad(): - x = adv_program(x) - - if args.display: - plt.imshow(x[0].permute(1, 2, 0)) - plt.title(f"{args.trigger_type} Trigger, Size {args.patch_size}") - plt.show() - return - - lgt = predictor(x) - fxs_prob.append(lgt) - test_total_num += y.shape[0] - pred = lgt.argmax(1) # [bs] - fxs.append(pred) - test_true_num += (pred == y.view(-1)).type(torch.float).sum().detach().cpu().item() - acc = test_true_num * 1.0 / test_total_num - pbar.set_description(f"Test Acc {100 * acc:.2f}%") - pbar.set_description(f"Test Acc {100 * test_true_num / test_total_num:.2f}%") - - y_all, d_all = torch.cat(y_all).view(-1).cpu().numpy(), torch.cat(d_all).view(-1).cpu().numpy() - ds_dict = {"Male": d_all, "Female": 1 - d_all} - fxs = torch.cat(fxs).view(-1).detach().cpu().numpy() - fxs_prob = torch.cat(fxs_prob, dim=0).detach().cpu().numpy() - - ret_no_class_balance = get_all_metrics(y_true=y_all, y_pred=fxs, y_prob=fxs_prob, z=ds_dict, - use_class_balance=False) - - accuracy = test_true_num / test_total_num - print(f"test acc: {accuracy:.4f}") - print(f"Min_ACC_AcrossZY: {ret_no_class_balance['Min_ACC_AcrossZY']: .4f}") - print(f"ED_FPR_AcrossZ: {ret_no_class_balance['ED_FPR_AcrossZ']: .4f}") - print(f"ED_FNR_AcrossZ: {ret_no_class_balance['ED_FNR_AcrossZ']: .4f}") - print( - f"ED_FR_AcrossZ: {(ret_no_class_balance['ED_FPR_AcrossZ'] + ret_no_class_balance['ED_FNR_AcrossZ']): .4f}") - print(f"ED_PO1_AcrossZ: {ret_no_class_balance['ED_PO1_AcrossZ']: .4f}") - - -if __name__ == '__main__': - args = get_args() - print(args) - main(args) diff --git a/FR/train.py b/FR/train.py index a75329d..262d7da 100644 --- a/FR/train.py +++ b/FR/train.py @@ -1,96 +1,34 @@ import os import sys import time -import argparse +import torch import warnings from pathlib import Path -import torch from torch import nn +from numpy import mean, std from torch.utils.data import DataLoader from torchvision.models.resnet import resnet18 from torch.cuda.amp import autocast, GradScaler +project_dir = "/root/DL-Fairness-Study" warnings.filterwarnings("ignore") +sys.path.insert(1, os.path.join(project_dir, "FR")) + from utils import * from models.model_zoo import * from models.resnet9 import resnet9 - -sys.path.insert(1, "/root/study") -from numpy import mean, std from datasets.celeba import MyCelebA from datasets.utkface import UTKFace from datasets.cifar10s import CIFAR_10S -from metrics import get_metric_index, get_all_metrics, print_all_metrics +sys.path.insert(1, project_dir) -def get_args(): - parser = argparse.ArgumentParser() - parser.add_argument("--evaluate", action="store_true") - parser.add_argument("--exp-name", type=str, default=None) - parser.add_argument("--checkpoint", type=str, default=None) - parser.add_argument("--domain-attrs", type=str, default="Male") - parser.add_argument("--result-dir", type=str, default="results") - parser.add_argument("--resume", action="store_true", default=False) - parser.add_argument("--target-attrs", type=str, default="Blond_Hair") - parser.add_argument("--data-dir", type=str, default="/root/study/data") - parser.add_argument("--gpu", default=0, type=int, help="CUDA visible device") - parser.add_argument("--dataset", default="celeba", type=str, choices=["celeba", "utkface", "cifar10s"]) - parser.add_argument("--arch", type=str, default="resnet18", choices=["resnet18", "resnet20s", "resnet9"]) - - parser.add_argument("--seed", type=int, default=1) - parser.add_argument("--lr", type=float, default=1e-4) - parser.add_argument("--wd", type=float, default=2e-5) - parser.add_argument("--epochs", type=int, default=50) - parser.add_argument("--num-workers", type=int, default=8) - parser.add_argument("--batch-size", type=int, default=512) - - parser.add_argument( - "--method", - "--m", - type=str, - default="std", - choices=["std", "adv", "repro", "rpatch", "roptim"], - help="Method: standard training, adv training, reprogram (vanilla, patch, optimization-based)", - ) - - # ================================ Adv Training ================================ # - parser.add_argument( - "--adversary-with-y", - action="store_true", - default=False, - help="True for Equalized Odds, target on [ED_PO1_AcrossZ], " "False for Demographic Parity, target on [ED_FR_AcrossZ].", - ) - parser.add_argument("--adversary-with-logits", action="store_true", default=False) - parser.add_argument("--adversary-lr", type=float, default=1e-3) - parser.add_argument("--lmbda", type=float, default=0.5, help="The coefficient of the adversarial loss applied to CE loss") - - # ================================ Reprogramming ================================ # - parser.add_argument( - "--reprogram-size", - type=int, - default=200, - help="This parameter has different meanings for different reprogramming methods. " - "For vanilla reprogramming method, the size of the resized image." - "For reprogram patch, the patch size." - "For optimization-based reprogram, the equivalent size of a patch for optimized pixels.", - ) - parser.add_argument( - "--trigger-data-num", - type=int, - default=0, - help="How many data do you want to use to train reprogram, default for using the whole training set!", - ) - - args = parser.parse_args() - args.domain_attrs = args.domain_attrs.split(",") - args.target_attrs = args.target_attrs.split(",") - os.environ["CUDA_VISIBLE_DEVICES"] = str(args.gpu) - - return args +from arguments import get_args +from metrics import get_metric_index, get_all_metrics, print_all_metrics -def fairness_evaluation(reprogram, test_loader, predictor, epoch, device): +def fairness_evaluation(reprogram, test_loader, predictor, epoch): if reprogram is not None: reprogram.eval() predictor.eval() @@ -103,8 +41,8 @@ def fairness_evaluation(reprogram, test_loader, predictor, epoch, device): for x, y, d in pbar: y_all.append(y) d_all.append(d) - x = x.to(device) - y = y.to(device) + x = x.cuda() + y = y.cuda() with torch.no_grad(): if reprogram is not None: x = reprogram(x) @@ -129,18 +67,16 @@ def fairness_evaluation(reprogram, test_loader, predictor, epoch, device): def main(args): - device = "cuda:0" if torch.cuda.is_available() else "cpu" setup_seed(args.seed) # Sanity Check! - assert args.data_dir is not None - assert args.method in ["std", "adv"] or args.checkpoint is not None + assert args.rmethod in ["std", "adv"] or args.model_path is not None - metric_index = get_metric_index() - metric_index.remove("time per epoch") - print(metric_index) + # metric_index = get_metric_index() + # metric_index.remove("time per epoch") + # print(metric_index) - # if args.evaluate and args.method in ["repro", "rpatch"]: + # if args.checkpoint and args.rmethod in ["repro", "rpatch"]: # result_dir = f"/root/study/results/{args.dataset}" # result_path = Path(result_dir) # result_path.mkdir(parents=True, exist_ok=True) @@ -175,53 +111,53 @@ def main(args): # results[m_index] = [] # make save path dir - os.makedirs(args.result_dir, exist_ok=True) - - model_attr_name = f"{args.method}_{args.arch}_{args.dataset}_" - if args.dataset == "utkface": - for attr in args.domain_attrs: - model_attr_name += f"{attr.lower()}_" + rmethod = {"std": "std", "repro": "border", "rpatch": "patch"} + if args.dataset in ["celeba", "cifar10s"]: + model_attr_name = f"fr_{rmethod[args.rmethod]}-{args.dataset}-lr{args.lr}-bs{args.batch_size}-epochs{args.epochs}-seed{args.seed}" + elif args.dataset == "utkface": + model_attr_name = ( + f"fr_{rmethod[args.rmethod]}-{args.dataset}_{args.sensitive}-lr{args.lr}-bs{args.batch_size}-epochs{args.epochs}-seed{args.seed}" + ) - if args.method in ["adv", "repro", "rpatch", "rpoptim"]: - model_attr_name += f"lambda{args.lmbda}_" - model_attr_name += "y_" if args.adversary_with_y else "n_" - if args.method in ["repro", "rpatch", "rpoptim"]: - model_attr_name += f"size{args.reprogram_size}_" + if args.rmethod in ["adv", "repro", "rpatch", "rpoptim"]: + model_attr_name += f"-lambda{args.lmbda}" + model_attr_name += "-eo" if args.adversary_with_y else "-dp" + if args.rmethod in ["repro", "rpatch", "rpoptim"]: + model_attr_name += f"-size{args.reprogram_size}" if args.trigger_data_num > 0: - model_attr_name += f"num{args.trigger_data_num}_" + model_attr_name += f"-num{args.trigger_data_num}" - model_attr_name += f"seed{args.seed}" - if args.exp_name is not None: - model_attr_name += f"_{args.exp_name}" + output_dir = f"{project_dir}/checkpoints/{model_attr_name}" + save_path = Path(output_dir) + save_path.mkdir(parents=True, exist_ok=True) image_size = 32 if args.dataset == "cifar10s" else 224 transform_train, transform_test = get_transform( - dataset=args.dataset, method=args.method, image_size=image_size, reprogram_size=args.reprogram_size + dataset=args.dataset, method=args.rmethod, image_size=image_size, reprogram_size=args.reprogram_size ) # We will use this a lot. - use_reprogram = args.method in ["repro", "rpatch", "roptim"] - use_adv = args.method in ["adv", "repro", "rpatch", "roptim"] + use_reprogram = args.rmethod in ["repro", "rpatch", "roptim"] + use_adv = args.rmethod in ["adv", "repro", "rpatch", "roptim"] num_class = 10 if args.dataset == "cifar10s" else 2 - attr_class = 2 ** len(args.domain_attrs) - assert attr_class == 2 + attr_class = 2 # add dropout dropout_prob = 0.5 classifier = nn.Sequential(nn.Linear(512, 256), nn.ReLU(), nn.Dropout(p=dropout_prob), nn.Linear(256, num_class)) # init model - if args.arch == "resnet18": + if args.model == "resnet18": predictor = resnet18(pretrained=False) predictor.fc = classifier # predictor.fc = nn.Linear(512, num_class) - elif args.arch == "resnet9": + elif args.model == "resnet9": predictor = resnet9(num_classes=num_class) else: predictor = resnet20s(num_class) - predictor = predictor.to(device) + predictor = predictor.cuda() fc_params = list(map(id, predictor.fc.parameters())) base_params = filter(lambda p: id(p) not in fc_params, predictor.parameters()) @@ -242,7 +178,7 @@ def main(args): with_logits=args.adversary_with_logits, use_mlp=True, ) - adversary = adversary.to(device) + adversary = adversary.cuda() a_optim = torch.optim.Adam(adversary.parameters(), lr=args.adversary_lr, weight_decay=args.wd) a_lr_scheduler = torch.optim.lr_scheduler.MultiStepLR( a_optim, gamma=0.1, milestones=[int(0.3 * args.epochs), int(0.6 * args.epochs), int(0.9 * args.epochs)] @@ -254,7 +190,7 @@ def main(args): # Initialize reprogrammers if use_reprogram: - reprogram = get_reprogram(method=args.method, image_size=image_size, reprogram_size=args.reprogram_size, device=device) + reprogram = get_reprogram(method=args.rmethod, image_size=image_size, reprogram_size=args.reprogram_size) r_optim = torch.optim.Adam(reprogram.parameters(), lr=args.lr, weight_decay=args.wd) r_lr_scheduler = torch.optim.lr_scheduler.MultiStepLR( r_optim, gamma=0.1, milestones=[int(0.3 * args.epochs), int(0.6 * args.epochs), int(0.9 * args.epochs)] @@ -268,9 +204,12 @@ def main(args): # Load checkpoints start_epoch = 0 - best_metric = 0.0 if args.method == "std" else 1.0 - if args.checkpoint is not None: - checkpoint = torch.load(args.checkpoint, map_location=device) + best_metric = 0.0 if args.rmethod == "std" else 1.0 + if args.model_path is not None: + if not args.checkpoint: + checkpoint = torch.load(f"{project_dir}/checkpoints/{args.model_path}/best_model.pth.tar") + else: + checkpoint = torch.load(f"{project_dir}/checkpoints/{args.model_path}/best_model.pt") predictor.load_state_dict(checkpoint["predictor"]) # We use the args.resume to distinguish whether the user want to resume the checkpoint # or they just want to load the pretrained models and train the reprogram from scratch. @@ -288,21 +227,22 @@ def main(args): r_optim.load_state_dict(checkpoint["r_optim"]) r_lr_scheduler.load_state_dict(checkpoint["r_lr_scheduler"]) - data_dir = os.path.join(args.data_dir, args.dataset) + data_dir = f"{project_dir}/data" + dataset_dir = f"{data_dir}/{args.dataset}" if args.dataset == "celeba": - train_set = MyCelebA(root=args.data_dir, split="train", transform=transform_train, target_attr=args.target_attrs[0]) - val_set = MyCelebA(root=args.data_dir, split="valid", transform=transform_test, target_attr=args.target_attrs[0]) - test_set = MyCelebA(root=args.data_dir, split="test", transform=transform_test, target_attr=args.target_attrs[0]) + train_set = MyCelebA(root=data_dir, split="train", transform=transform_train, target_attr=args.target) + val_set = MyCelebA(root=data_dir, split="valid", transform=transform_test, target_attr=args.target) + test_set = MyCelebA(root=data_dir, split="test", transform=transform_test, target_attr=args.target) elif args.dataset == "utkface": - bias_attr = args.domain_attrs[0].lower() + bias_attr = args.sensitive print(bias_attr) - train_set = UTKFace(root=data_dir, split="train", transform=transform_train, bias_attr=bias_attr) - val_set = UTKFace(root=data_dir, split="valid", transform=transform_test, bias_attr=bias_attr) - test_set = UTKFace(root=data_dir, split="test", transform=transform_test, bias_attr=bias_attr) + train_set = UTKFace(root=dataset_dir, split="train", transform=transform_train, bias_attr=bias_attr) + val_set = UTKFace(root=dataset_dir, split="valid", transform=transform_test, bias_attr=bias_attr) + test_set = UTKFace(root=dataset_dir, split="test", transform=transform_test, bias_attr=bias_attr) elif args.dataset == "cifar10s": - train_set = CIFAR_10S(root=data_dir, split="train", transform=transform_train, skew_ratio=0.95) - val_set = CIFAR_10S(root=data_dir, split="valid", transform=transform_test, skew_ratio=0.95) - test_set = CIFAR_10S(root=data_dir, split="test", transform=transform_test, skew_ratio=0.95) + train_set = CIFAR_10S(root=dataset_dir, split="train", transform=transform_train, skew_ratio=0.95) + val_set = CIFAR_10S(root=dataset_dir, split="valid", transform=transform_test, skew_ratio=0.95) + test_set = CIFAR_10S(root=dataset_dir, split="test", transform=transform_test, skew_ratio=0.95) else: raise ValueError @@ -310,12 +250,12 @@ def main(args): val_loader = DataLoader(dataset=val_set, batch_size=args.batch_size, shuffle=False, num_workers=args.num_workers, pin_memory=True) test_loader = DataLoader(dataset=test_set, batch_size=args.batch_size, shuffle=False, num_workers=args.num_workers, pin_memory=True) - if args.evaluate or args.checkpoint is not None: + if args.checkpoint or args.model_path is not None: print("================= Evaluating on Test Set before Training =================") - test_result, test_acc = fairness_evaluation(None, test_loader, predictor, -1, device) + test_result, test_acc = fairness_evaluation(None, test_loader, predictor, -1) print(f"Test Accuracy: {test_acc}") print(test_result) - if args.evaluate: + if args.checkpoint: sys.exit() time_per_epoch = [] @@ -323,9 +263,9 @@ def main(args): for epoch in range(start_epoch, args.epochs): # training - if args.method == "std": + if args.rmethod == "std": predictor.train() - elif args.method == "adv": + elif args.rmethod == "adv": predictor.train() adversary.train() else: @@ -341,14 +281,14 @@ def main(args): total_num = 0 true_num = 0 for x, y, d in pbar: - x, y, d = x.to(device), y.to(device), d.to(device) - y_one_hot = get_one_hot(y, num_class, device) # one-hot [bs, num_class] - d_one_hot = get_one_hot(d, attr_class, device) # one-hot [bs, attr_class] + x, y, d = x.cuda(), y.cuda(), d.cuda() + y_one_hot = get_one_hot(y, num_class) # one-hot [bs, num_class] + d_one_hot = get_one_hot(d, attr_class) # one-hot [bs, attr_class] p_optim.zero_grad() - if args.method != "std": + if args.rmethod != "std": a_optim.zero_grad() - if args.method != "adv": + if args.rmethod != "adv": r_optim.zero_grad() with autocast(): @@ -358,7 +298,7 @@ def main(args): lgt = predictor(x) # print(lgt.shape) pred_loss = nn.functional.cross_entropy(lgt, y_one_hot) - if args.method != "std": + if args.rmethod != "std": protect_pred = adversary(lgt, y=y_one_hot if args.adversary_with_y else None) adversary_loss = torch.nn.functional.cross_entropy(protect_pred, d_one_hot) @@ -398,9 +338,9 @@ def main(args): pbar.set_description(f"Training Epoch {epoch} Acc {100 * acc:.2f}%") pbar.set_description(f"Training Epoch {epoch} Acc {100 * true_num / total_num:.2f}%") - if args.method == "std": + if args.rmethod == "std": p_lr_scheduler.step() - elif args.method == "adv": + elif args.rmethod == "adv": p_lr_scheduler.step() a_lr_scheduler.step() else: @@ -409,11 +349,11 @@ def main(args): # evaluating print("================= Evaluating on Validation Set =================") - res, accuracy = fairness_evaluation(reprogram, val_loader, predictor, epoch, device) + res, accuracy = fairness_evaluation(reprogram, val_loader, predictor, epoch) print(res) print(accuracy) - if args.method == "std": + if args.rmethod == "std": metric = res["bacc"] if metric > best_metric: print("+++++++++++ Find New Best Metric +++++++++++") @@ -425,15 +365,15 @@ def main(args): "epoch": epoch, "best_metric": best_metric, } - if args.method != "std": + if args.rmethod != "std": cp["adversary"] = adversary.state_dict() cp["a_optim"] = a_optim.state_dict() cp["a_lr_scheduler"] = a_lr_scheduler.state_dict() - if args.method != "adv": + if args.rmethod != "adv": cp["reprogram"] = reprogram.state_dict() cp["r_optim"] = r_optim.state_dict() cp["r_lr_scheduler"] = r_lr_scheduler.state_dict() - torch.save(cp, os.path.join(args.result_dir, f"{model_attr_name}_best.pth.tar")) + torch.save(cp, f"{save_path}/best_model.pt") else: metric = res["aaod"] if metric < best_metric: @@ -446,17 +386,17 @@ def main(args): "epoch": epoch, "best_metric": best_metric, } - if args.method != "std": + if args.rmethod != "std": cp["adversary"] = adversary.state_dict() cp["a_optim"] = a_optim.state_dict() cp["a_lr_scheduler"] = a_lr_scheduler.state_dict() - if args.method != "adv": + if args.rmethod != "adv": cp["reprogram"] = reprogram.state_dict() cp["r_optim"] = r_optim.state_dict() cp["r_lr_scheduler"] = r_lr_scheduler.state_dict() - torch.save(cp, os.path.join(args.result_dir, f"{model_attr_name}_best.pth.tar")) + torch.save(cp, f"{save_path}/best_model.pt") print("================= Evaluating on Test Set =================") - test_result_list, accuracy = fairness_evaluation(reprogram, test_loader, predictor, epoch, device) + test_result_list, accuracy = fairness_evaluation(reprogram, test_loader, predictor, epoch) print(test_result_list) print(accuracy) diff --git a/FR/utils.py b/FR/utils.py index a5c3425..572f297 100644 --- a/FR/utils.py +++ b/FR/utils.py @@ -27,19 +27,19 @@ def write_csv_rows(file_name, column_list): writer.writerows(column_list) -def get_one_hot(y, num_class, device): +def get_one_hot(y, num_class): # Please check, y should start from 0 and be in range [0, num_class - 1] if len(y.shape) == 1: y_new = y.unsqueeze(-1) else: y_new = y - y_one_hot = torch.FloatTensor(y_new.shape[0], num_class).to(device) + y_one_hot = torch.FloatTensor(y_new.shape[0], num_class).cuda() y_one_hot.zero_() y_one_hot.scatter_(1, y_new, 1) return y_one_hot -# def evaluation(reprogram, test_loader, predictor, epoch, device): +# def evaluation(reprogram, test_loader, predictor, epoch): # if reprogram is not None: # reprogram.eval() # predictor.eval() @@ -53,8 +53,8 @@ def get_one_hot(y, num_class, device): # for x, y, d in pbar: # y_all.append(y) # d_all.append(d) -# x = x.to(device) -# y = y.to(device) +# x = x.cuda() +# y = y.cuda() # with torch.no_grad(): # if reprogram is not None: # x = reprogram(x) @@ -98,18 +98,18 @@ def display_result(accuracy, ret_no_class_balance): print(f"ED_PO1_AcrossZ: {ret_no_class_balance['ED_PO1_AcrossZ']: .4f}") -def get_reprogram(method, image_size: int = 0, reprogram_size: int = 0, device="cpu"): +def get_reprogram(method, image_size: int = 0, reprogram_size: int = 0): image_size = (image_size, image_size) reprogram_size = (reprogram_size, reprogram_size) if method in ["std", "adv"]: reprogram = None elif method == "repro": - reprogram = AdvProgram(reprogram_size, image_size, image_size, device=device) + reprogram = AdvProgram(reprogram_size, image_size, image_size) elif method == "rpatch": - reprogram = PatchProgram(patch_size=reprogram_size, out_size=image_size, device=device) + reprogram = PatchProgram(patch_size=reprogram_size, out_size=image_size) elif method == "roptim": k = float(reprogram_size[0]) / float(image_size[0]) - reprogram = OptimProgram(size=image_size, k=k, device=device) + reprogram = OptimProgram(size=image_size, k=k) else: raise ValueError return reprogram @@ -121,7 +121,7 @@ def get_transform(dataset, method, image_size, reprogram_size=None): std = [0.2470, 0.2435, 0.2616] if method in ["std", "adv", "rpatch", "roptim"]: transform_train = transforms.Compose( - [ + [ transforms.ToPILImage(), transforms.Resize(64), transforms.RandomCrop(image_size), diff --git a/MFD/arguments.py b/MFD/arguments.py deleted file mode 100644 index f36132e..0000000 --- a/MFD/arguments.py +++ /dev/null @@ -1,78 +0,0 @@ -import argparse -import torch - -def get_args(): - parser = argparse.ArgumentParser(description='Fairness') - parser.add_argument('--log-dir', default='./results/', - help='directory to save logs (default: ./results/)') - parser.add_argument('--data-dir', default='../data/', - help='data directory (default: ../data/)') - parser.add_argument('--save-dir', default='./trained_models/', - help='directory to save trained models (default: ./trained_models/)') - parser.add_argument('--no-cuda', action='store_true', default=False, - help='disables CUDA training') - parser.add_argument('--device', default=0, type=int, help='cuda device number') - parser.add_argument('--t-device', default=0, type=int, help='teacher cuda device number') - - - parser.add_argument('--mode', default='train', choices=['train', 'eval']) - parser.add_argument('--model-path', default=None) - parser.add_argument('--evalset', default='all', choices=['all', 'train', 'test']) - - parser.add_argument('--dataset', required=True, default='', choices=['utkface', 'celeba', 'cifar10s']) - parser.add_argument('--skew-ratio', default=0.95, type=float, help='skew ratio for cifar-10s') - parser.add_argument('--img-size', default=224, type=int, help='img size for preprocessing') - - parser.add_argument('--lr', default=1e-3, type=float, help='learning rate') - parser.add_argument('--epochs', default=100, type=int, help='number of training epochs') - parser.add_argument('--batch-size', default=128, type=int, help='mini batch size') - parser.add_argument('--seed', default=1, type=int, help='seed for randomness') - parser.add_argument('--date', default='230929', type=str, help='experiment date') - parser.add_argument('--method', default='scratch', type=str, required=True, - choices=['scratch', 'kd_hinton', 'kd_fitnet', 'kd_at', - 'kd_mfd', 'scratch_mmd', 'kd_nst', 'adv_debiasing']) - - parser.add_argument('--optimizer', default='Adam', type=str, required=False, - choices=['SGD', 'SGD_momentum_decay', 'Adam'], - help='(default=%(default)s)') - - parser.add_argument('--lambh', default=4, type=float, help='kd strength hyperparameter') - parser.add_argument('--lambf', default=1, type=float, help='feature distill strength hyperparameter') - parser.add_argument('--kd-temp', default=3, type=float, help='temperature for KD') - - parser.add_argument('--model', default='resnet', type=str, choices=['resnet', 'shufflenet', 'mlp', 'cifar_net']) - parser.add_argument('--parallel', default=False, action='store_true', help='data parallel') - parser.add_argument('--teacher-type', default=None, choices=['resnet', 'shufflenet', 'cifar_net']) - parser.add_argument('--teacher-path', default=None, help='teacher model path') - - parser.add_argument('--pretrained', default=False, action='store_true', help='load imagenet pretrained model') - parser.add_argument('--num-workers', default=8, type=int, help='the number of thread used in dataloader') - parser.add_argument('--term', default=20, type=int, help='the period for recording train acc') - parser.add_argument('--target', default='Blond_Hair', type=str, help='target attribute for celeba') - - parser.add_argument('--no-annealing', action='store_true', default=False, help='do not anneal lamb during training') - parser.add_argument('--fitnet-simul', default=False, action='store_true', help='no hint-training') - - parser.add_argument('--eta', default=0.0003, type=float, help='adversary training learning rate') - parser.add_argument('--adv-lambda', default=2.0, type=float, help='adversary loss strength') - - parser.add_argument('--sigma', default=1.0, type=float, help='sigma for rbf kernel') - parser.add_argument('--kernel', default='rbf', type=str, choices=['rbf', 'poly'], help='kernel for mmd') - parser.add_argument('--labelwise', default=False, action='store_true', help='labelwise loader') - parser.add_argument('--jointfeature', default=False, action='store_true', help='mmd with both joint') - parser.add_argument('--get-inter', default=False, action='store_true', - help='get penultimate features for TSNE visualization') - - parser.add_argument('--repeat-time', default=10, type=int, help='the number of experimental repeats') - parser.add_argument('--sensitive', default='race', type=str, help='sensitive attribute for utkface') - - args = parser.parse_args() - args.cuda = not args.no_cuda and torch.cuda.is_available() - if args.mode == 'train' and (args.method.startswith('kd')): - if args.teacher_path is None: - raise Exception('A teacher model path is not specified.') - - if args.mode == 'eval' and args.model_path is None: - raise Exception('Model path to load is not specified!') - - return args diff --git a/MFD/data_handler/dataset_factory.py b/MFD/data_handler/dataset_factory.py index 8ec54db..b70cc21 100644 --- a/MFD/data_handler/dataset_factory.py +++ b/MFD/data_handler/dataset_factory.py @@ -1,23 +1,29 @@ +import os + +project_dir = "/root/DL-Fairness-Study" + + class DatasetFactory: def __init__(self): pass @staticmethod - def get_dataset(name, transform=None, split='Train', sensitive='race', target='Attractive', seed=0, skew_ratio=1., labelwise=False): + def get_dataset(name, transform=None, split="Train", sensitive="race", target="Attractive", seed=0, skew_ratio=1.0, labelwise=False): if name == "utkface": from data_handler.utkface import UTKFaceDataset - root = '../data/utkface/images' - return UTKFaceDataset(root=root, split=split, transform=transform, sensitive_attr=sensitive, - labelwise=labelwise) + + root = f"{project_dir}/data/utkface/images" + return UTKFaceDataset(root=root, split=split, transform=transform, sensitive_attr=sensitive, labelwise=labelwise) elif name == "celeba": from data_handler.celeba import CelebA - root='../data' + + root = f"{project_dir}/data" return CelebA(root=root, split=split, transform=transform, target_attr=target, labelwise=labelwise) elif name == "cifar10s": from data_handler.cifar10 import CIFAR_10S - root = '../data/cifar10s' - return CIFAR_10S(root=root, split=split, transform=transform, seed=seed, skewed_ratio=skew_ratio, - labelwise=labelwise) + + root = f"{project_dir}/data/cifar10s" + return CIFAR_10S(root=root, split=split, transform=transform, seed=seed, skewed_ratio=skew_ratio, labelwise=labelwise) diff --git a/MFD/main.py b/MFD/main.py index db7713f..06e7851 100644 --- a/MFD/main.py +++ b/MFD/main.py @@ -1,29 +1,32 @@ import os import sys import time +import torch import networks import numpy as np +import torch.nn as nn from pathlib import Path +import torch.optim as optim from numpy import mean, std -import torch -import torch.nn as nn -import torch.optim as optim +project_dir = "/root/DL-Fairness-Study" +sys.path.insert(1, os.path.join(project_dir, "MFD")) import trainer import data_handler -from arguments import get_args from utils import check_log_dir, make_log_name -sys.path.insert(1, "/root/study") +sys.path.insert(1, project_dir) from helper import set_seed +from arguments import get_args from metrics import get_metric_index, get_all_metrics, print_all_metrics args = get_args() def main(): + args.gpu = int(args.gpu) torch.backends.cudnn.enabled = True seed = args.seed @@ -34,33 +37,32 @@ def main(): log_name = make_log_name(args) dataset = args.dataset - save_dir = os.path.join(args.save_dir, args.date, dataset, args.method) - log_dir = os.path.join(args.log_dir, args.date, dataset, args.method) - check_log_dir(save_dir) - check_log_dir(log_dir) - - if args.mode == "eval": - result_dir = f"../results/{args.dataset}" - result_path = Path(result_dir) - result_path.mkdir(parents=True, exist_ok=True) - - if args.dataset == "celeba" and args.target == "Blond_Hair": - fout = open("/".join([str(result_path), "mfd_gender_blond_hair.txt"]), "w") - - if args.dataset == "utkface": - if args.sensitive == "age": - fout = open("/".join([str(result_path), f"mfd_age_gender.txt"]), "w") - elif args.sensitive == "race": - fout = open("/".join([str(result_path), f"mfd_race_gender.txt"]), "w") - - if args.dataset == "cifar10s": - fout = open("/".join([str(result_path), "mfd.txt"]), "w") - - results = {} - metric_index = get_metric_index() - metric_index.remove("time per epoch") - for m_index in metric_index: - results[m_index] = [] + save_dir = os.path.join(project_dir, "checkpoints", log_name) + if not args.checkpoint: + check_log_dir(save_dir) + + # if args.checkpoint: + # result_dir = f"../results/{args.dataset}" + # result_path = Path(result_dir) + # result_path.mkdir(parents=True, exist_ok=True) + + # if args.dataset == "celeba" and args.target == "Blond_Hair": + # fout = open("/".join([str(result_path), "mfd_gender_blond_hair.txt"]), "w") + + # if args.dataset == "utkface": + # if args.sensitive == "age": + # fout = open("/".join([str(result_path), f"mfd_age_gender.txt"]), "w") + # elif args.sensitive == "race": + # fout = open("/".join([str(result_path), f"mfd_race_gender.txt"]), "w") + + # if args.dataset == "cifar10s": + # fout = open("/".join([str(result_path), "mfd.txt"]), "w") + + # results = {} + # metric_index = get_metric_index() + # metric_index.remove("time per epoch") + # for m_index in metric_index: + # results[m_index] = [] ########################## get dataloader ################################ @@ -77,9 +79,9 @@ def main(): ) num_classes, num_groups, train_loader, test_loader = tmp - time_per_epoch = [] + # time_per_epoch = [] for r in range(args.repeat_time): - print(f"Repeated experiment: {r+1}") + # print(f"Repeated experiment: {r+1}") ################################## get model ################################## @@ -88,18 +90,18 @@ def main(): if args.parallel: model = nn.DataParallel(model) - model.cuda("cuda:{}".format(args.device)) + model.cuda() # if args.model_path is not None: # model.load_state_dict(torch.load(args.model_path)) teacher = None - if (args.method.startswith("kd") or args.teacher_path is not None) and args.mode != "eval": + if (args.method.startswith("kd") or args.teacher_path is not None) and not args.checkpoint: teacher = networks.ModelFactory.get_model(args.model, train_loader.dataset.num_classes, args.img_size) if args.parallel: teacher = nn.DataParallel(teacher) - teacher.load_state_dict(torch.load(args.teacher_path)) - teacher.cuda("cuda:{}".format(args.t_device)) + teacher.load_state_dict(torch.load(f"{project_dir}/checkpoints/{args.teacher_path}")) + teacher.cuda() ################################## get trainer ################################## @@ -111,25 +113,35 @@ def main(): trainer_ = trainer.TrainerFactory.get_trainer(args.method, model=model, args=args, optimizer=optimizer, teacher=teacher) ################################## start training or evaluating ################################## - log_name_r = log_name + f"_repeat{r+1}" if args.repeat_time > 1 else log_name - if args.mode == "train": + # log_name_r = log_name + f"_repeat{r+1}" if args.repeat_time > 1 else log_name + if not args.checkpoint: start_t = time.time() trainer_.train(train_loader, test_loader, args.epochs) end_t = time.time() tpe = (end_t - start_t) / args.epochs - time_per_epoch.append(tpe) + # time_per_epoch.append(tpe) + print(f"Time per epoch: {tpe:.6f}") train_t = int((end_t - start_t) / 60) # to minutes print("Training Time : {} hours {} minutes".format(int(train_t / 60), (train_t % 60))) - trainer_.save_model(save_dir, log_name_r) + trainer_.save_model(save_dir) + + if args.evalset == "all": + trainer_.compute_confusion_matrix("train", train_loader.dataset.num_classes, train_loader, save_dir) + trainer_.compute_confusion_matrix("test", test_loader.dataset.num_classes, test_loader, save_dir) + + elif args.evalset == "train": + trainer_.compute_confusion_matrix("train", train_loader.dataset.num_classes, train_loader, save_dir) + else: + trainer_.compute_confusion_matrix("test", test_loader.dataset.num_classes, test_loader, save_dir) + + print("Done!") else: print("Evaluation ----------------") - model_to_load = args.model_path.replace(".pt", f"_repeat{r+1}.pt") - print(model_to_load) - trainer_.model.load_state_dict(torch.load(model_to_load)) + trainer_.model.load_state_dict(torch.load(os.path.join(project_dir, "checkpoints", args.model_path))) print("Trained model loaded successfully") trainer_.model.eval() @@ -156,30 +168,19 @@ def main(): print(ret) print_all_metrics(ret=ret) - for i in range(len(metric_index)): - results[metric_index[i]].append(ret[metric_index[i]]) - - if args.evalset == "all": - trainer_.compute_confusion_matix("train", train_loader.dataset.num_classes, train_loader, log_dir, log_name_r) - trainer_.compute_confusion_matix("test", test_loader.dataset.num_classes, test_loader, log_dir, log_name_r) - - elif args.evalset == "train": - trainer_.compute_confusion_matix("train", train_loader.dataset.num_classes, train_loader, log_dir, log_name_r) - else: - trainer_.compute_confusion_matix("test", test_loader.dataset.num_classes, test_loader, log_dir, log_name_r) - - print("Done!") + # for i in range(len(metric_index)): + # results[metric_index[i]].append(ret[metric_index[i]]) - if args.mode == "train": - print("Average Training Time Per Epoch: {} seconds".format(mean(time_per_epoch))) + # if args.mode == "train": + # print("Average Training Time Per Epoch: {} seconds".format(mean(time_per_epoch))) - if args.mode == "eval": - for m_index in metric_index: - fout.write(m_index + "\t") - for i in range(args.repeat_time): - fout.write("%f\t" % results[m_index][i]) - fout.write("%f\t%f\n" % (mean(results[m_index]), std(results[m_index]))) - fout.close() + # if args.mode == "eval": + # for m_index in metric_index: + # fout.write(m_index + "\t") + # for i in range(args.repeat_time): + # fout.write("%f\t" % results[m_index][i]) + # fout.write("%f\t%f\n" % (mean(results[m_index]), std(results[m_index]))) + # fout.close() if __name__ == "__main__": diff --git a/MFD/networks/model_factory.py b/MFD/networks/model_factory.py index b1fd1af..60f7425 100644 --- a/MFD/networks/model_factory.py +++ b/MFD/networks/model_factory.py @@ -6,17 +6,17 @@ from networks.mlp import MLP -class ModelFactory(): +class ModelFactory: def __init__(self): pass @staticmethod def get_model(target_model, num_classes, img_size, pretrained=False): - if target_model == 'mlp': + if target_model == "mlp": return MLP(feature_size=img_size, hidden_dim=40, num_class=num_classes) - elif target_model == 'resnet': + elif target_model == "resnet18": if pretrained: model = resnet18(pretrained=True) model.fc = nn.Linear(in_features=512, out_features=num_classes, bias=True) @@ -24,10 +24,10 @@ def get_model(target_model, num_classes, img_size, pretrained=False): model = resnet18(pretrained=False, num_classes=num_classes) return model - elif target_model == 'cifar_net': + elif target_model == "cifar_net": return Net(num_classes=num_classes) - elif target_model == 'shufflenet': + elif target_model == "shufflenet": if pretrained: model = shufflenet_v2_x1_0(pretrained=True) model.fc = nn.Linear(in_features=1024, out_features=num_classes, bias=True) @@ -37,4 +37,3 @@ def get_model(target_model, num_classes, img_size, pretrained=False): else: raise NotImplementedError - diff --git a/MFD/trainer/kd_hinton.py b/MFD/trainer/kd_hinton.py index 37d2e66..b8ed0e1 100644 --- a/MFD/trainer/kd_hinton.py +++ b/MFD/trainer/kd_hinton.py @@ -49,13 +49,13 @@ def _train_epoch(self, epoch, train_loader, model, teacher, distiller=None): labels = targets if self.cuda: - inputs = inputs.cuda(self.device) - labels = labels.cuda(self.device) - t_inputs = inputs.to(self.t_device) + inputs = inputs.cuda() + labels = labels.cuda() + t_inputs = inputs.cuda() outputs = model(inputs) t_outputs = teacher(t_inputs) - kd_loss = compute_hinton_loss(outputs, t_outputs, kd_temp=self.kd_temp, device=self.device) + kd_loss = compute_hinton_loss(outputs, t_outputs, kd_temp=self.kd_temp) loss = self.criterion(outputs, labels) + self.lambh * kd_loss diff --git a/MFD/trainer/kd_mfd.py b/MFD/trainer/kd_mfd.py index 965edd4..cf6a2bf 100644 --- a/MFD/trainer/kd_mfd.py +++ b/MFD/trainer/kd_mfd.py @@ -23,23 +23,24 @@ def train(self, train_loader, test_loader, epochs): num_classes = train_loader.dataset.num_classes num_groups = train_loader.dataset.num_groups - distiller = MMDLoss(w_m=self.lambf, sigma=self.sigma, - num_classes=num_classes, num_groups=num_groups, kernel=self.kernel) + distiller = MMDLoss(w_m=self.lambf, sigma=self.sigma, num_classes=num_classes, num_groups=num_groups, kernel=self.kernel) for epoch in range(self.epochs): self._train_epoch(epoch, train_loader, self.model, self.teacher, distiller=distiller) eval_start_time = time.time() eval_loss, eval_acc, eval_deopp = self.evaluate(self.model, test_loader, self.criterion) eval_end_time = time.time() - print('[{}/{}] Method: {} ' - 'Test Loss: {:.3f} Test Acc: {:.2f} Test DEopp {:.2f} [{:.2f} s]'.format - (epoch + 1, epochs, self.method, - eval_loss, eval_acc, eval_deopp, (eval_end_time - eval_start_time))) + print( + "[{}/{}] Method: {} " + "Test Loss: {:.3f} Test Acc: {:.2f} Test DEopp {:.2f} [{:.2f} s]".format( + epoch + 1, epochs, self.method, eval_loss, eval_acc, eval_deopp, (eval_end_time - eval_start_time) + ) + ) if self.scheduler != None: self.scheduler.step(eval_loss) - print('Training Finished!') + print("Training Finished!") def _train_epoch(self, epoch, train_loader, model, teacher, distiller=None): model.train() @@ -54,11 +55,10 @@ def _train_epoch(self, epoch, train_loader, model, teacher, distiller=None): inputs, _, groups, targets, _ = data labels = targets - if self.cuda: - inputs = inputs.cuda(self.device) - labels = labels.cuda(self.device) - groups = groups.long().cuda(self.device) - t_inputs = inputs.to(self.t_device) + inputs = inputs.cuda() + labels = labels.cuda() + groups = groups.long().cuda() + t_inputs = inputs.cuda() outputs = model(inputs, get_inter=True) stu_logits = outputs[-1] @@ -66,13 +66,11 @@ def _train_epoch(self, epoch, train_loader, model, teacher, distiller=None): t_outputs = teacher(t_inputs, get_inter=True) tea_logits = t_outputs[-1] - kd_loss = compute_hinton_loss(stu_logits, t_outputs=tea_logits, - kd_temp=self.kd_temp, device=self.device) if self.lambh != 0 else 0 + kd_loss = compute_hinton_loss(stu_logits, t_outputs=tea_logits, kd_temp=self.kd_temp) if self.lambh != 0 else 0 loss = self.criterion(stu_logits, labels) loss = loss + self.lambh * kd_loss - f_s = outputs[-2] f_t = t_outputs[-2] mmd_loss = distiller.forward(f_s, f_t, groups=groups, labels=labels, jointfeature=self.jointfeature) @@ -87,10 +85,12 @@ def _train_epoch(self, epoch, train_loader, model, teacher, distiller=None): if i % self.term == self.term - 1: # print every self.term mini-batches avg_batch_time = time.time() - batch_start_time - print('[{}/{}, {:5d}] Method: {} Train Loss: {:.3f} Train Acc: {:.2f} ' - '[{:.2f} s/batch]'.format - (epoch + 1, self.epochs, i + 1, self.method, running_loss / self.term, running_acc / self.term, - avg_batch_time / self.term)) + print( + "[{}/{}, {:5d}] Method: {} Train Loss: {:.3f} Train Acc: {:.2f} " + "[{:.2f} s/batch]".format( + epoch + 1, self.epochs, i + 1, self.method, running_loss / self.term, running_acc / self.term, avg_batch_time / self.term + ) + ) running_loss = 0.0 running_acc = 0.0 @@ -110,7 +110,7 @@ def __init__(self, w_m, sigma, num_groups, num_classes, kernel): self.kernel = kernel def forward(self, f_s, f_t, groups, labels, jointfeature=False): - if self.kernel == 'poly': + if self.kernel == "poly": student = F.normalize(f_s.view(f_s.shape[0], -1), dim=1) teacher = F.normalize(f_t.view(f_t.shape[0], -1), dim=1).detach() else: @@ -120,11 +120,9 @@ def forward(self, f_s, f_t, groups, labels, jointfeature=False): mmd_loss = 0 if jointfeature: - K_TS, sigma_avg = self.pdist(teacher, student, - sigma_base=self.sigma, kernel=self.kernel) + K_TS, sigma_avg = self.pdist(teacher, student, sigma_base=self.sigma, kernel=self.kernel) K_TT, _ = self.pdist(teacher, teacher, sigma_base=self.sigma, sigma_avg=sigma_avg, kernel=self.kernel) - K_SS, _ = self.pdist(student, student, - sigma_base=self.sigma, sigma_avg=sigma_avg, kernel=self.kernel) + K_SS, _ = self.pdist(student, student, sigma_base=self.sigma, sigma_avg=sigma_avg, kernel=self.kernel) mmd_loss += K_TT.mean() + K_SS.mean() - 2 * K_TS.mean() @@ -133,39 +131,44 @@ def forward(self, f_s, f_t, groups, labels, jointfeature=False): _, sigma_avg = self.pdist(teacher, student, sigma_base=self.sigma, kernel=self.kernel) for c in range(self.num_classes): - if len(teacher[labels==c]) == 0: + if len(teacher[labels == c]) == 0: continue for g in range(self.num_groups): - if len(student[(labels==c) * (groups == g)]) == 0: + if len(student[(labels == c) * (groups == g)]) == 0: continue - K_TS, _ = self.pdist(teacher[labels == c], student[(labels == c) * (groups == g)], - sigma_base=self.sigma, sigma_avg=sigma_avg, kernel=self.kernel) - K_SS, _ = self.pdist(student[(labels == c) * (groups == g)], student[(labels == c) * (groups == g)], - sigma_base=self.sigma, sigma_avg=sigma_avg, kernel=self.kernel) - - K_TT, _ = self.pdist(teacher[labels == c], teacher[labels == c], sigma_base=self.sigma, - sigma_avg=sigma_avg, kernel=self.kernel) + K_TS, _ = self.pdist( + teacher[labels == c], student[(labels == c) * (groups == g)], sigma_base=self.sigma, sigma_avg=sigma_avg, kernel=self.kernel + ) + K_SS, _ = self.pdist( + student[(labels == c) * (groups == g)], + student[(labels == c) * (groups == g)], + sigma_base=self.sigma, + sigma_avg=sigma_avg, + kernel=self.kernel, + ) + + K_TT, _ = self.pdist(teacher[labels == c], teacher[labels == c], sigma_base=self.sigma, sigma_avg=sigma_avg, kernel=self.kernel) mmd_loss += K_TT.mean() + K_SS.mean() - 2 * K_TS.mean() - loss = (1/2) * self.w_m * mmd_loss + loss = (1 / 2) * self.w_m * mmd_loss return loss @staticmethod - def pdist(e1, e2, eps=1e-12, kernel='rbf', sigma_base=1.0, sigma_avg=None): + def pdist(e1, e2, eps=1e-12, kernel="rbf", sigma_base=1.0, sigma_avg=None): if len(e1) == 0 or len(e2) == 0: res = torch.zeros(1) else: - if kernel == 'rbf': + if kernel == "rbf": e1_square = e1.pow(2).sum(dim=1) e2_square = e2.pow(2).sum(dim=1) prod = e1 @ e2.t() res = (e1_square.unsqueeze(1) + e2_square.unsqueeze(0) - 2 * prod).clamp(min=eps) res = res.clone() sigma_avg = res.mean().detach() if sigma_avg is None else sigma_avg - res = torch.exp(-res / (2*(sigma_base)*sigma_avg)) - elif kernel == 'poly': + res = torch.exp(-res / (2 * (sigma_base) * sigma_avg)) + elif kernel == "poly": res = torch.matmul(e1, e2.t()).pow(2) return res, sigma_avg diff --git a/MFD/trainer/loss_utils.py b/MFD/trainer/loss_utils.py index 50a235d..6a6e249 100644 --- a/MFD/trainer/loss_utils.py +++ b/MFD/trainer/loss_utils.py @@ -6,14 +6,14 @@ def mse(inputs, targets): return (inputs - targets).pow(2).mean() -def compute_feature_loss(inputs, t_inputs, student, teacher, device=0): +def compute_feature_loss(inputs, t_inputs, student, teacher): stu_outputs = student(inputs, get_inter=True) f_s = stu_outputs[-2] f_s = f_s.view(f_s.shape[0], -1) stu_logits = stu_outputs[-1] tea_outputs = teacher(t_inputs, get_inter=True) - f_t = tea_outputs[-2].to(device) + f_t = tea_outputs[-2].cuda() f_t = f_t.view(f_t.shape[0], -1).detach() tea_logits = tea_outputs[-1] @@ -23,28 +23,27 @@ def compute_feature_loss(inputs, t_inputs, student, teacher, device=0): return fitnet_loss, stu_logits, tea_logits, f_s, f_t -def compute_hinton_loss(outputs, t_outputs=None, teacher=None, t_inputs=None, kd_temp=3, device=0): +def compute_hinton_loss(outputs, t_outputs=None, teacher=None, t_inputs=None, kd_temp=3): if t_outputs is None: - if (t_inputs is not None and teacher is not None): + if t_inputs is not None and teacher is not None: t_outputs = teacher(t_inputs) else: - Exception('Nothing is given to compute hinton loss') + Exception("Nothing is given to compute hinton loss") - soft_label = F.softmax(t_outputs / kd_temp, dim=1).to(device).detach() - kd_loss = nn.KLDivLoss(reduction='batchmean')(F.log_softmax(outputs / kd_temp, dim=1), - soft_label) * (kd_temp * kd_temp) + soft_label = F.softmax(t_outputs / kd_temp, dim=1).cuda().detach() + kd_loss = nn.KLDivLoss(reduction="batchmean")(F.log_softmax(outputs / kd_temp, dim=1), soft_label) * (kd_temp * kd_temp) return kd_loss -def compute_at_loss(inputs, t_inputs, student, teacher, device=0, for_cifar=False): +def compute_at_loss(inputs, t_inputs, student, teacher, for_cifar=False): stu_outputs = student(inputs, get_inter=True) if not for_cifar else student(inputs, get_inter=True, before_fc=True) stu_logits = stu_outputs[-1] f_s = stu_outputs[-2] tea_outputs = teacher(t_inputs, get_inter=True) if not for_cifar else teacher(inputs, get_inter=True, before_fc=True) - tea_logits = tea_outputs[-1].to(device) - f_t = tea_outputs[-2].to(device) + tea_logits = tea_outputs[-1].cuda() + f_t = tea_outputs[-2].cuda() attention_loss = (1 / 2) * (at_loss(f_s, f_t)) return attention_loss, stu_logits, tea_logits, f_s, f_t diff --git a/MFD/trainer/trainer_factory.py b/MFD/trainer/trainer_factory.py index 8bee464..a8b85e4 100644 --- a/MFD/trainer/trainer_factory.py +++ b/MFD/trainer/trainer_factory.py @@ -13,37 +13,38 @@ def __init__(self): @staticmethod def get_trainer(method, **kwargs): - if method == 'scratch': + if method == "scratch": import trainer.vanilla_train as trainer - elif method == 'kd_hinton': + elif method == "kd_hinton": import trainer.kd_hinton as trainer - elif method == 'kd_fitnet': + elif method == "kd_fitnet": import trainer.kd_fitnet as trainer - elif method == 'kd_at': + elif method == "kd_at": import trainer.kd_at as trainer - elif method == 'kd_nst': + elif method == "kd_nst": import trainer.kd_nst as trainer - elif method == 'kd_mfd': + elif method == "kd_mfd": import trainer.kd_mfd as trainer - elif method == 'scratch_mmd': + elif method == "scratch_mmd": import trainer.scratch_mmd as trainer - elif method == 'adv_debiasing': + elif method == "adv_debiasing": import trainer.adv_debiasing as trainer else: - raise Exception('Not allowed method') + raise Exception("Not allowed method") return trainer.Trainer(**kwargs) class GenericTrainer: - ''' - Base class for trainer; to implement a new training routine, inherit from this. - ''' + """ + Base class for trainer; to implement a new training routine, inherit from this. + """ + def __init__(self, model, args, optimizer, teacher=None): self.get_inter = args.get_inter - - self.cuda = args.cuda - self.device = args.device - self.t_device = args.t_device + + # self.cuda = args.cuda + # self.device = args.gpu + # self.t_device = args.t_device self.term = args.term self.lr = args.lr self.parallel = args.parallel @@ -53,53 +54,53 @@ def __init__(self, model, args, optimizer, teacher=None): self.teacher = teacher self.optimizer = optimizer self.optim_type = args.optimizer - self.img_size = args.img_size if not 'cifar10s' in args.dataset else 32 - self.criterion=torch.nn.CrossEntropyLoss() + self.img_size = args.img_size if not "cifar10s" in args.dataset else 32 + self.criterion = torch.nn.CrossEntropyLoss() self.scheduler = None self.log_name = make_log_name(args) - self.log_dir = os.path.join(args.log_dir, args.date, args.dataset, args.method) - self.save_dir = os.path.join(args.save_dir, args.date, args.dataset, args.method) + project_dir = "/root/DL-Fairness-Study" + # self.log_dir = os.path.join(args.log_dir, args.date, args.dataset, args.method) + self.save_dir = os.path.join(project_dir, "checkpoints", self.log_name) decay_epochs = [args.epochs // 4, args.epochs // 2, args.epochs * 3 // 4] print(decay_epochs) - if self.optim_type == 'Adam' and self.optimizer is not None: + if self.optim_type == "Adam" and self.optimizer is not None: # self.scheduler = ReduceLROnPlateau(self.optimizer) self.scheduler = MultiStepLR(self.optimizer, milestones=decay_epochs, gamma=0.1) - else: + else: self.scheduler = MultiStepLR(self.optimizer, [30, 60, 90], gamma=0.1) - def evaluate(self, model, loader, criterion, device=None, groupwise=False): + def evaluate(self, model, loader, criterion, groupwise=False): model.eval() num_groups = loader.dataset.num_groups num_classes = loader.dataset.num_classes - device = self.device if device is None else device - - eval_acc = 0 if not groupwise else torch.zeros(num_groups, num_classes).cuda(device) - eval_loss = 0 if not groupwise else torch.zeros(num_groups, num_classes).cuda(device) - eval_eopp_list = torch.zeros(num_groups, num_classes).cuda(device) - eval_data_count = torch.zeros(num_groups, num_classes).cuda(device) - - if 'Custom' in type(loader).__name__: + # device = self.device if device is None else device + + eval_acc = 0 if not groupwise else torch.zeros(num_groups, num_classes).cuda() + eval_loss = 0 if not groupwise else torch.zeros(num_groups, num_classes).cuda() + eval_eopp_list = torch.zeros(num_groups, num_classes).cuda() + eval_data_count = torch.zeros(num_groups, num_classes).cuda() + + if "Custom" in type(loader).__name__: loader = loader.generate() with torch.no_grad(): for j, eval_data in enumerate(loader): # Get the inputs inputs, _, groups, classes, _ = eval_data # - labels = classes - if self.cuda: - inputs = inputs.cuda(device) - labels = labels.cuda(device) - groups = groups.cuda(device) + labels = classes + + inputs = inputs.cuda() + labels = labels.cuda() + groups = groups.cuda() outputs = model(inputs) if groupwise: - if self.cuda: - groups = groups.cuda(device) - loss = nn.CrossEntropyLoss(reduction='none')(outputs, labels) + groups = groups.cuda() + loss = nn.CrossEntropyLoss(reduction="none")(outputs, labels) preds = torch.argmax(outputs, 1) acc = (preds == labels).float().squeeze() for g in range(num_groups): @@ -127,28 +128,28 @@ def evaluate(self, model, loader, criterion, device=None, groupwise=False): eval_max_eopp = torch.max(eval_max_eopp).item() model.train() return eval_loss, eval_acc, eval_max_eopp - - def save_model(self, save_dir, log_name="", model=None): + + def save_model(self, save_dir, model=None): model_to_save = self.model if model is None else model - model_savepath = os.path.join(save_dir, log_name + '.pt') + model_savepath = f"{save_dir}/best_model.pt" torch.save(model_to_save.state_dict(), model_savepath) - print('Model saved to %s' % model_savepath) + print("Model saved to %s" % model_savepath) - def compute_confusion_matix(self, dataset='test', num_classes=2, - dataloader=None, log_dir="", log_name=""): + def compute_confusion_matrix(self, dataset="test", num_classes=2, dataloader=None, log_dir=""): from scipy.io import savemat from collections import defaultdict + self.model.eval() confu_mat = defaultdict(lambda: np.zeros((num_classes, num_classes))) - print('# of {} data : {}'.format(dataset, len(dataloader.dataset))) + print("# of {} data : {}".format(dataset, len(dataloader.dataset))) predict_mat = {} output_set = torch.tensor([]) group_set = torch.tensor([], dtype=torch.long) target_set = torch.tensor([], dtype=torch.long) intermediate_feature_set = torch.tensor([]) - + with torch.no_grad(): for i, data in enumerate(dataloader): # Get the inputs @@ -156,9 +157,8 @@ def compute_confusion_matix(self, dataset='test', num_classes=2, labels = targets groups = groups.long() - if self.cuda: - inputs = inputs.cuda(self.device) - labels = labels.cuda(self.device) + inputs = inputs.cuda() + labels = labels.cuda() # forward @@ -178,21 +178,21 @@ def compute_confusion_matix(self, dataset='test', num_classes=2, mask = groups == i if len(labels[mask]) != 0: confu_mat[str(i)] += confusion_matrix( - labels[mask].cpu().numpy(), pred[mask].cpu().numpy(), - labels=[i for i in range(num_classes)]) + labels[mask].cpu().numpy(), pred[mask].cpu().numpy(), labels=[i for i in range(num_classes)] + ) - predict_mat['group_set'] = group_set.numpy() - predict_mat['target_set'] = target_set.numpy() - predict_mat['output_set'] = output_set.numpy() + predict_mat["group_set"] = group_set.numpy() + predict_mat["target_set"] = target_set.numpy() + predict_mat["output_set"] = output_set.numpy() if self.get_inter: - predict_mat['intermediate_feature_set'] = intermediate_feature_set.numpy() - - savepath = os.path.join(log_dir, log_name + '_{}_confu'.format(dataset)) - print('savepath', savepath) + predict_mat["intermediate_feature_set"] = intermediate_feature_set.numpy() + + savepath = os.path.join(log_dir, "{}_confu".format(dataset)) + print("savepath", savepath) savemat(savepath, confu_mat, appendmat=True) - savepath_pred = os.path.join(log_dir, log_name + '_{}_pred'.format(dataset)) + savepath_pred = os.path.join(log_dir, "{}_pred".format(dataset)) savemat(savepath_pred, predict_mat, appendmat=True) - print('Computed confusion matrix for {} dataset successfully!'.format(dataset)) + print("Computed confusion matrix for {} dataset successfully!".format(dataset)) return confu_mat diff --git a/MFD/trainer/vanilla_train.py b/MFD/trainer/vanilla_train.py index dca1dac..92d119c 100644 --- a/MFD/trainer/vanilla_train.py +++ b/MFD/trainer/vanilla_train.py @@ -44,9 +44,8 @@ def _train_epoch(self, epoch, train_loader, model): labels = targets - if self.cuda: - inputs = inputs.cuda(device=self.device) - labels = labels.cuda(device=self.device) + inputs = inputs.cuda() + labels = labels.cuda() outputs = model(inputs) loss = self.criterion(outputs, labels) diff --git a/MFD/utils.py b/MFD/utils.py index bbc4d1a..c088d24 100644 --- a/MFD/utils.py +++ b/MFD/utils.py @@ -1,36 +1,21 @@ +import os import torch import numpy as np -import random -import os def list_files(root, suffix, prefix=False): root = os.path.expanduser(root) - files = list( - filter( - lambda p: os.path.isfile(os.path.join(root, p)) and p.endswith(suffix), - os.listdir(root) - ) - ) + files = list(filter(lambda p: os.path.isfile(os.path.join(root, p)) and p.endswith(suffix), os.listdir(root))) if prefix is True: files = [os.path.join(root, d) for d in files] return files -def set_seed(seed): - torch.manual_seed(seed) - # torch.cuda.manual_seed(seed) - np.random.seed(seed) - random.seed(seed) - torch.backends.cudnn.benchmark = False - torch.backends.cudnn.deterministic = True - - def get_accuracy(outputs, labels, binary=False): - #if multi-label classification - if len(labels.size())>1: - outputs = (outputs>0.0).float() - correct = ((outputs==labels)).float().sum() + # if multi-label classification + if len(labels.size()) > 1: + outputs = (outputs > 0.0).float() + correct = ((outputs == labels)).float().sum() total = torch.tensor(labels.shape[0] * labels.shape[1], dtype=torch.float) avg = correct / total return avg.item() @@ -52,41 +37,30 @@ def check_log_dir(log_dir): def make_log_name(args): - log_name = args.model - - if args.mode == 'eval': - log_name = args.model_path.split('/')[-1] - # remove .pt from name - log_name = log_name[:-3] + log_name = f"{args.method}" + if args.dataset == "utkface": + log_name += f"-{args.dataset}_{args.sensitive}" else: - if args.pretrained: - log_name += '_pretrained' - log_name += '_seed{}_epochs{}_bs{}_lr{}'.format(args.seed, args.epochs, args.batch_size, args.lr) + log_name += f"-{args.dataset}" - if args.method == 'adv_debiasing': - log_name += '_advlamb{}_eta{}'.format(args.adv_lambda, args.eta) + log_name += f"-lr{args.lr}-bs{args.batch_size}-epochs{args.epochs}-seed{args.seed}" - elif args.method == 'scratch_mmd' or args.method == 'kd_mfd': - log_name += '_{}'.format(args.kernel) - log_name += '_sigma{}'.format(args.sigma) if args.kernel == 'rbf' else '' - log_name += '_jointfeature' if args.jointfeature else '' - log_name += '_lambf{}'.format(args.lambf) if args.method == 'scratch_mmd' else '' + if args.labelwise: + log_name += "-labelwise" - if args.labelwise: - log_name += '_labelwise' + if args.teacher_path is not None: + log_name += f"-temp{args.kd_temp}-lambh{args.lambh}-lambf{args.lambf}" - if args.teacher_path is not None: - log_name += '_temp{}'.format(args.kd_temp) - log_name += '_lambh{}_lambf{}'.format(args.lambh, args.lambf) + if args.no_annealing: + log_name += "-fixedlamb" - if args.no_annealing: - log_name += '_fixedlamb' - if args.dataset == 'celeba' and args.target != 'Attractive': - log_name += '_{}'.format(args.target) + if args.pretrained: + log_name += "-pretrained" - if args.dataset == 'utkface': - log_name += '_{}'.format(args.sensitive) + if args.method == "kd_mfd": + log_name += "-{}".format(args.kernel) + log_name += "-sigma{}".format(args.sigma) if args.kernel == "rbf" else "" + log_name += "-jointfeature" if args.jointfeature else "" return log_name - diff --git a/README.md b/README.md index 3b99db2..ce9ec2e 100644 --- a/README.md +++ b/README.md @@ -1,307 +1,149 @@ -# DL-Fairness-Study +# A Large-Scale Empirical Study on Improving the Fairness of Image Classification Models -This code repository contains all the data processing and code implementations for our work titled "A Large-scale Empirical Study on Improving the Fairness of Deep Learning Models." Our research focuses on fairness issues in deep learning and includes a comprehensive summary and experimental analysis of existing fairness-improving methods on image data. We have also presented some interesting findings. In the future, we will continue to explore effective ways to enhance model fairness on image data. +This is the implementation repository of our ISSTA 2024 paper: **A Large-Scale Empirical Study on Improving the Fairness of Image Classification Models**. -## Experimental Environment +## 1. Description -### Conda +Fairness has been a critical issue that affects the adoption of deep learning models in real practice. To improve model fairness, many existing methods have been proposed and evaluated to be effective in their own contexts. However, there is still no systematic evaluation among them for a comprehensive comparison under the same context, which makes it hard to understand the performance distinction among them, hindering the research progress and practical adoption of them. To fill this gap, this paper endeavours to conduct the first large-scale empirical study to comprehensively compare the performance of existing state-of-the-art fairness improving techniques. Specifically, we target the widely-used application scenario of image classification, and utilized three different datasets and five commonly-used performance metrics to assess in total 13 methods from diverse categories. Our findings reveal substantial variations in the performance of each method across different datasets and sensitive attributes, indicating over-fitting on specific datasets by many existing methods. Furthermore, different fairness evaluation metrics, due to their distinct focuses, yield significantly different assessment results. Overall, we observe that pre-processing methods and in-processing methods outperform post-processing methods, with pre-processing methods exhibiting the best performance. Our empirical study offers comprehensive recommendations for enhancing fairness in deep learning models. We approach the problem from multiple dimensions, aiming to provide a uniform evaluation platform and inspire researchers to explore more effective fairness solutions via a set of implications. -Conda is recommended for all configurations. [Miniconda](https://conda.io/miniconda.html) is sufficient if you do not already have conda installed. +![Summary of fairness improving methods.](./figures/methods.png) -Then, to create a new Python 3.8 environment, run: +## 2. Structure ```bash -conda create -n fairness python=3.8 -conda activate fairness +DL-Fairness-Study/ +|-- BM : implementation of US, OS, UW, BM, Adv, DI and BC+BB methods +|-- checkpoints : saved models +|-- data : image datasets +|-- FAAP : implementation of FAAP method +|-- FDR : implementation of FDR method +|-- figures : figures of experimental result analysis +|-- FLAC : implementation of FLAC method +|-- FR : implementation of FR-B and FR-P methods +|-- log : running log +|-- MFD : implementation of MFD method +|-- model_checkpoints : saved models +|-- plot : code to draw figures +|-- results : ten repeated experimental results +|-- scripts : running scripts +|-- arguments.py : uniform arguments of all studied methods +|-- helper.py : helper functions +|-- metrics.py : performance and fairness evaluation metrics +|-- README.md : user guide of our study +|-- requirements.txt : dependencies required of the experiment ``` -### PyTorch +## 3. Datasets -We have standardized the experimental environment for all methods, conducting experiments based on PyTorch. The installed versions and methods are as follows: +We selected `3` datasets for conducting the empirical study. The table below provides a summary of these datasets, including the sensitive attribute considered in the study, the labels of the classification tasks, and the studied methods that previously used the same settings. Additionally, we present the number of instances used for model training and testing in each dataset, following existing studies. -```bash -# CUDA 11.3 -conda install pytorch==1.10.1 torchvision==0.11.2 torchaudio==0.10.1 cudatoolkit=11.3 -c pytorch -c conda-forge -``` +![Summary of adopted benchmark datasets.](./figures/datasets.png) -### Requirements +Specifically, CelebA and UTKFace represent human-centric datasets that involve sensitive attributes (e.g., age and race) reflected in facial images, while CIFAR-10S is a more general dataset in fairness study, which introduces biases related to image colors of objects (non-facial images). They were previously used for evaluation by partial/all methods under different conditions, e.g., using different metrics. From the table we can also find that previous studies tend to employ different datasets, hindering their comprehensive comparison. In this study, we aim to provide an extensive study through a systematic evaluation by employing all of them, which vary in multiple perspectives. -Other necessary libraries and packages are installed as follows: +**NOTE:** All datasets used in our study could be obtained from their homepages ([CelebA](https://mmlab.ie.cuhk.edu.hk/projects/CelebA.html), [UTKFace](https://susanqq.github.io/UTKFace/), [CIFAR-10](https://www.cs.toronto.edu/~kriz/cifar.html)). Please note that CIFAR-10S dataset used in our study is constructed by [Wang *et al.*](https://arxiv.org/abs/1911.11834) based on CIFAR-10 dataset. -```bash -pip install -r requirements.txt -``` +## 4. Reproducibility -## Studied Methods in This Study +### 4.1. Environment -### Pre-processing +- Python: 3.8.18 +- PyTorch: 1.10.1 +- CUDA Version: 11.4 +- GPU: NVIDIA GeForce RTX 3090 +- OS: Linux (Ubuntu 20.04.6 LTS) +- CPU: Intel(R) Xeon(R) Gold 6326 CPU @ 2.90GHz -#### Undersampling (US) +To facilitate other researchers in reproducing our `DL-Fairness-Study`, we provide a `docker` image for the experiment. It can be easily obtained by the following command: ```bash -# CelebA -python train_celeba/train_celeba_us.py --task blonde --epochs 170 --lr 1e-4 --gpu 0 +docker pull junjie1003/fairness:latest -# UTKFace -python train_utk_face/train_utk_face_us.py --task age --epochs 400 --epochs_extra 400 --lr 1e-4 --gpu 3 -python train_utk_face/train_utk_face_us.py --task race --epochs 120 --epochs_extra 120 --lr 1e-4 --gpu 1 +docker run -it --name fairness --gpus all --net host -v /your/local/path/:/data --shm-size="200g" junjie1003/fairness:latest /bin/bash -# CIFAR-10S -python train_cifar10/train_cifar10_us.py --epochs 2000 --lr 0.1 --gpu 0 +cd /root/DL-Fairness-Study ``` -#### Oversampling (OS) - -```bash -# CelebA -python train_celeba/train_celeba_os.py --task blonde --epochs 4 --lr 1e-4 --gpu 0 - -# UTKFace -python train_utk_face/train_utk_face_os.py --task age --epochs 7 --lr 1e-4 --gpu 0 -python train_utk_face/train_utk_face_os.py --task race --epochs 10 --lr 1e-4 --gpu 1 +Then you will enter a container. Remember to change `/your/local/path/` to the real path.😊 -# CIFAR-10S -python train_cifar10/train_cifar10_os.py --epochs 100 --lr 0.1 --gpu 0 -``` +### 4.2. Demo -#### Upweighting (UW) +Here is a demo and you can run `scripts/demo.sh` to have a quick start: ```bash -# CelebA -python train_celeba/train_celeba_uw.py --task blonde --epochs 10 --lr 1e-4 --gpu 0 - -# UTKFace -python train_utk_face/train_utk_face_uw.py --task age --epochs 20 --lr 1e-4 --gpu 0 -python train_utk_face/train_utk_face_uw.py --task race --epochs 20 --lr 1e-4 --gpu 1 - -# CIFAR-10S -python train_cifar10/train_cifar10_uw.py --epochs 200 --lr 0.01 --gpu 0 +bash scripts/demo.sh ``` -#### Bias Mimicking (BM) +In the demo, we chose one representative method for each category in the `UTKFace-Race` dataset due to its low time cost. This allowed us to evaluate their accuracy and fairness, thereby demonstrating the variances in effectiveness among different method categories. -```bash -# CelebA -python train_celeba/train_celeba_bm.py --task blonde --epochs 10 --lr 1e-4 --lr_layer 1e-4 --gpu 0 --mode none -python train_celeba/train_celeba_bm.py --task blonde --epochs 10 --lr 1e-4 --lr_layer 1e-4 --gpu 1 --mode us -python train_celeba/train_celeba_bm.py --task blonde --epochs 10 --lr 1e-4 --lr_layer 1e-4 --gpu 2 --mode os -python train_celeba/train_celeba_bm.py --task blonde --epochs 10 --lr 1e-4 --lr_layer 1e-4 --gpu 3 --mode uw - -# UTKFace -python train_utk_face/train_utk_face_bm.py --task age --epochs 20 --lr 1e-4 --gpu 0 --mode none -python train_utk_face/train_utk_face_bm.py --task race --epochs 20 --lr 1e-4 --gpu 1 --mode none - -python train_utk_face/train_utk_face_bm.py --task age --epochs 20 --lr 1e-4 --gpu 0 --mode us -python train_utk_face/train_utk_face_bm.py --task race --epochs 20 --lr 1e-4 --gpu 1 --mode us - -python train_utk_face/train_utk_face_bm.py --task age --epochs 20 --lr 1e-4 --gpu 0 --mode os -python train_utk_face/train_utk_face_bm.py --task race --epochs 20 --lr 1e-4 --gpu 1 --mode os - -python train_utk_face/train_utk_face_bm.py --task age --epochs 20 --lr 1e-4 --gpu 0 --mode uw -python train_utk_face/train_utk_face_bm.py --task race --epochs 20 --lr 1e-4 --gpu 1 --mode uw - -# CIFAR-10S -python train_cifar10/train_cifar10_bm.py --epochs 200 --lr 0.1 --gpu 0 --mode none -python train_cifar10/train_cifar10_bm.py --epochs 200 --lr 0.1 --gpu 1 --mode us -python train_cifar10/train_cifar10_bm.py --epochs 200 --lr 0.1 --gpu 2 --mode os -python train_cifar10/train_cifar10_bm.py --epochs 200 --lr 0.1 --gpu 3 --mode uw -``` +### 4.3. Running Studied Methods -### In-processing +#### Training -#### Adversarial Training (Adv) +We provide scripts to train all the studied methods on `3` image datasets used in our study. You can execute them using the following commands: ```bash -# CelebA -python train_celeba/train_celeba_adv.py --task blonde --epochs 10 --lr 1e-4 --gpu 0 - -# UTKFace -python train_utk_face/train_utk_face_adv.py --task age --epochs 20 --lr 1e-4 --gpu 0 -python train_utk_face/train_utk_face_adv.py --task race --epochs 20 --lr 1e-4 --gpu 1 - -# CIFAR-10S -python train_cifar10/train_cifar10_adv.py --epochs 200 --lr 0.01 --gpu 0 +bash scripts/celeba.sh +bash scripts/utkface.sh +bash scripts/cifar10s.sh ``` -#### Domain Independent Training (DI) - -```bash -# CelebA -python train_celeba/train_celeba_di.py --task blonde --epochs 10 --lr 1e-4 --gpu 0 - -# UTKFace -python train_utk_face/train_utk_face_di.py --task age --epochs 20 --lr 1e-4 --gpu 0 -python train_utk_face/train_utk_face_di.py --task race --epochs 20 --lr 1e-4 --gpu 1 +Please note that you need to modify the GPU ID to match your machine when you run these scripts. -# CIFAR-10S -python train_cifar10/train_cifar10_di.py --epochs 200 --lr 0.1 --gpu 0 -``` +#### Evaluation -#### Bias-Contrastive and Bias-Balanced Learning (BC+BB) +After executing the training commands, you can evaluate the performance and fairness of these methods using your trained models. Additionally, you can utilize our saved models located in the `model_checkpoints` directory directly. Before you begin evaluation, simply move them to the `checkpoints` directory. ```bash -# CelebA -python train_celeba/train_celeba_bc.py --task blonde --epochs 10 --lr 1e-4 --gpu 0 - -# UTKFace -python train_utk_face/train_utk_face_bc.py --task age --epochs 20 --lr 1e-4 --gpu 0 -python train_utk_face/train_utk_face_bc.py --task race --epochs 20 --lr 1e-4 --gpu 1 - -# CIFAR-10S -python train_cifar10/train_cifar10_bc.py --epochs 200 --lr 0.1 --gpu 0 +cp -r model_checkpoints/* checkpoints ``` -#### FLAC +If you want to evaluate all methods, you can run the following command: ```bash -# CelebA -python train_celeba.py --task blonde --alpha 30000 --gpu 0 - -# UTKFace -python train_utk_face.py --task age --gpu 0 -python train_utk_face.py --task race --gpu 1 - -# CIFAR-10S -python train_cifar10s.py --gpu 0 +bash scripts/test_celeba.sh +bash scripts/test_utkface.sh +bash scripts/test_cifar10s.sh ``` -#### MMD-based Fair Distillation (MFD) - -```bash -# CelebA -# 1. Train a teacher model -CUDA_VISIBLE_DEVICES=0 python3 ./main.py --method scratch --dataset celeba --img-size 176 --repeat-time 1 > log/teacher_celeba_Blond_Hair.log +In our paper, we conducted 10 repeated experiments and recorded all the experimental results along with their mean and standard deviation in the `results` directory. The subsequent analysis and charts of experimental results are all based on these 10 repeated experiments. -# 2. Train a student model -CUDA_VISIBLE_DEVICES=0 python3 ./main.py --method kd_mfd --dataset celeba --labelwise --lambf 7 --lambh 0 --no-annealing --img-size 176 --teacher-path trained_models/230903/celeba/scratch/resnet_seed1_epochs50_bs128_lr0.001_Blond_Hair.pt > log/student_celeba_Blond_Hair.log +## 5. Experimental Results -# 3. Evaluate student model -CUDA_VISIBLE_DEVICES=0 python3 ./main.py --mode eval --method kd_mfd --dataset celeba --labelwise --lambf 7 --lambh 0 --no-annealing --img-size 176 --model-path trained_models/230903/celeba/kd_mfd/resnet_seed1_epochs50_bs128_lr0.001_rbf_sigma1.0_labelwise_temp3_lambh0.0_lambf7.0_fixedlamb_Blond_Hair.pt > log/eval_celeba_Blond_Hair.log +Please note that all the figures and tables in our paper are based on the results of 10 repeated experiments combined. -# UTKFace -# 1. Train a teacher model -CUDA_VISIBLE_DEVICES=1 python3 ./main.py --method scratch --dataset utkface --sensitive age --img-size 176 --pretrained --repeat-time 1 > log/teacher_utkface_age.log -CUDA_VISIBLE_DEVICES=2 python3 ./main.py --method scratch --dataset utkface --sensitive race --img-size 176 --pretrained --repeat-time 1 > log/teacher_utkface_race.log +(1) Result comparison among different studied methods. The values in each cell denote the mean and standard deviation of the fairness metrics obtained from multiple experiments for the current method and dataset setting. We use different colors to highlight the values of different metrics, the darker of the color, the larger of the value, and the worse of the performance. -# 2. Train a student model -CUDA_VISIBLE_DEVICES=1 python3 ./main.py --method kd_mfd --dataset utkface --sensitive age --labelwise --lambf 3 --lambh 0 --no-annealing --img-size 176 --teacher-path trained_models/230929/utkface/scratch/resnet_pretrained_seed1_epochs100_bs128_lr0.001_age.pt > log/student_utkface_age.log -CUDA_VISIBLE_DEVICES=2 python3 ./main.py --method kd_mfd --dataset utkface --sensitive race --labelwise --lambf 3 --lambh 0 --no-annealing --img-size 176 --teacher-path trained_models/230929/utkface/scratch/resnet_pretrained_seed1_epochs100_bs128_lr0.001_race.pt > log/student_utkface_race.log +![Result comparison among different studied methods.](./figures/fairness.png) -# 3. Evaluate student model -CUDA_VISIBLE_DEVICES=1 python3 ./main.py --mode eval --method kd_mfd --dataset utkface --sensitive age --labelwise --lambf 3 --lambh 0 --no-annealing --img-size 176 --model-path trained_models/230929/utkface/kd_mfd/resnet_seed1_epochs100_bs128_lr0.001_rbf_sigma1.0_labelwise_temp3_lambh0.0_lambf3.0_fixedlamb_age.pt > log/eval_utkface_age.log -CUDA_VISIBLE_DEVICES=2 python3 ./main.py --mode eval --method kd_mfd --dataset utkface --sensitive race --labelwise --lambf 3 --lambh 0 --no-annealing --img-size 176 --model-path trained_models/230929/utkface/kd_mfd/resnet_seed1_epochs100_bs128_lr0.001_rbf_sigma1.0_labelwise_temp3_lambh0.0_lambf3.0_fixedlamb_race.pt > log/eval_utkface_race.log +(2) Value distribution regarding accuracy metrics after applying different approaches on different datasets. -# CIFAR-10S -# 1. Train a teacher model -CUDA_VISIBLE_DEVICES=0 python3 ./main.py --method scratch --dataset cifar10s --img-size 32 --pretrained --repeat-time 1 > log/teacher_cifar10s.log +![Value distribution regarding accuracy metrics after applying different approaches on different datasets.](./figures/accuracy.png) -# 2. Train a student model -CUDA_VISIBLE_DEVICES=0 python3 ./main.py --method kd_mfd --dataset cifar10s --labelwise --lambf 3 --lambh 0 --no-annealing --img-size 32 --teacher-path trained_models/230929/cifar10s/scratch/resnet_pretrained_seed1_epochs100_bs128_lr0.001.pt > log/student_cifar10s.log - -# 3. Evaluate student model -CUDA_VISIBLE_DEVICES=0 python3 ./main.py --mode eval --method kd_mfd --dataset cifar10s --labelwise --lambf 3 --lambh 0 --no-annealing --img-size 32 --model-path trained_models/230929/cifar10s/kd_mfd/resnet_seed1_epochs100_bs128_lr0.001_rbf_sigma1.0_labelwise_temp3_lambh0.0_lambf3.0_fixedlamb.pt > log/eval_cifar10s.log -``` - -#### FDR +You can reproduce these boxplots by using our provided code `plot/boxplot_accuracy.py` and running the commands below: ```bash -# CelebA -CUDA_VISIBLE_DEVICES=0 python celeba.py --ft_lr 1e-3 --ft_epoch 1000 --alpha 2 --constraint EO > log/CelebA_BlondHair_EO.log -CUDA_VISIBLE_DEVICES=1 python celeba.py --ft_lr 1e-3 --ft_epoch 500 --alpha 5 --constraint AE > log/CelebA_BlondHair_AE.log -CUDA_VISIBLE_DEVICES=2 python celeba.py --ft_lr 1e-3 --ft_epoch 1000 --constraint MMF > log/CelebA_BlondHair_MMF.log - -# UTKFace -CUDA_VISIBLE_DEVICES=1 python utkface.py --ft_lr 1e-3 --ft_epoch 1500 --alpha 2 --constraint EO --sensitive age > log/UTKFace_Age_EO.log -CUDA_VISIBLE_DEVICES=2 python utkface.py --ft_lr 1e-3 --ft_epoch 1500 --alpha 2 --constraint EO --sensitive race > log/UTKFace_Race_EO.log - -CUDA_VISIBLE_DEVICES=0 python utkface.py --ft_lr 3e-3 --ft_epoch 1500 --alpha 5 --constraint AE --sensitive age > log/UTKFace_Age_AE.log -CUDA_VISIBLE_DEVICES=1 python utkface.py --ft_lr 3e-3 --ft_epoch 1500 --alpha 5 --constraint AE --sensitive race > log/UTKFace_Race_AE.log - -CUDA_VISIBLE_DEVICES=2 python utkface.py --ft_lr 1e-3 --ft_epoch 1000 --constraint MMF --sensitive age > log/UTKFace_Age_MMF.log -CUDA_VISIBLE_DEVICES=3 python utkface.py --ft_lr 1e-3 --ft_epoch 1000 --constraint MMF --sensitive race > log/UTKFace_Race_MMF.log - -# CIFAR-10S -CUDA_VISIBLE_DEVICES=3 python cifar10s.py --ft_lr 1e-3 --ft_epoch 1000 --alpha 2 --constraint EO > log/CIFAR-10S_EO.log -CUDA_VISIBLE_DEVICES=3 python cifar10s.py --ft_lr 1e-3 --ft_epoch 1000 --alpha 5 --constraint AE > log/CIFAR-10S_AE.log -CUDA_VISIBLE_DEVICES=3 python cifar10s.py --ft_lr 1e-3 --ft_epoch 1000 --constraint MMF > log/CIFAR-10S_MMF.log +cd plot +python boxplot_accuracy.py ``` -### Post-processing +(3) Pearson correlation across different metrics. -#### FairReprogram (FR) +![Pearson correlation across different metrics.](./figures/correlation.png) -Step 1: Standard Training +To generate the figure, you can run the `plot/pearson_correlation.py` code using the following command: ```bash -# CelebA -nohup python3 train.py --dataset celeba --method std --result-dir std --gpu 0 > log/celeba_std.log 2>&1 & -# UTKFace -nohup python3 train.py --dataset utkface --domain-attrs Age --method std --result-dir std --gpu 1 > log/utkface_age_std.log 2>&1 & -nohup python3 train.py --dataset utkface --domain-attrs Race --method std --result-dir std --gpu 2 > log/utkface_race_std.log 2>&1 & -# CIFAR-10S -nohup python3 train.py --dataset cifar10s --method std --result-dir std --resume --gpu 3 > log/cifar10s_std.log 2>&1 & +cd plot +python pearson_correlation.py ``` -Step 2: Reprogramming with Border Trigger - -```bash -# CelebA -nohup python3 train.py --dataset celeba --result-dir border --reprogram-size 184 --epochs 20 --adversary-with-logits --lmbda 10.0 --m repro --adversary-with-y --checkpoint std/std_resnet18_celeba_seed1_best.pth.tar --gpu 0 > log/celeba_border_eo.log 2>&1 & -# UTKFace -nohup python3 train.py --dataset utkface --domain-attrs Age --result-dir border --reprogram-size 184 --epochs 20 --adversary-with-logits --lmbda 10.0 --m repro --adversary-with-y --checkpoint std/std_resnet18_utkface_age_seed1_best.pth.tar --gpu 1 > log/utkface_age_border_eo.log 2>&1 & -nohup python3 train.py --dataset utkface --domain-attrs Race --result-dir border --reprogram-size 184 --epochs 20 --adversary-with-logits --lmbda 10.0 --m repro --adversary-with-y --checkpoint std/std_resnet18_utkface_race_seed1_best.pth.tar --gpu 2 > log/utkface_race_border_eo.log 2>&1 & -# CIFAR-10S -nohup python3 train.py --dataset cifar10s --result-dir border --reprogram-size 32 --epochs 20 --adversary-with-logits --lmbda 10.0 --m repro --adversary-with-y --checkpoint std/std_resnet18_cifar10s_seed1_best.pth.tar --gpu 0 > log/cifar10s_border_eo.log 2>&1 & -``` +(4) Average time cost per epoch of each method for improving model fairness (in seconds). -Step 3: Reprogramming with Patch Trigger +![Average time cost per epoch of each method for improving model fairness (in seconds).](./figures/time.png) -```bash -# CelebA -nohup python3 train.py --dataset celeba --result-dir patch --reprogram-size 90 --epochs 20 --adversary-with-logits --lmbda 10.0 --m rpatch --adversary-with-y --checkpoint std/std_resnet18_celeba_seed1_best.pth.tar --gpu 0 > log/celeba_patch_eo.log 2>&1 & -# UTKFace -nohup python3 train.py --dataset utkface --domain-attrs Age --result-dir patch --reprogram-size 80 --epochs 20 --adversary-with-logits --lmbda 10.0 --m rpatch --adversary-with-y --checkpoint std/std_resnet18_utkface_age_seed1_best.pth.tar --gpu 1 > log/utkface_age_patch_eo.log 2>&1 & -nohup python3 train.py --dataset utkface --domain-attrs Race --result-dir patch --reprogram-size 80 --epochs 20 --adversary-with-logits --lmbda 10.0 --m rpatch --adversary-with-y --checkpoint std/std_resnet18_utkface_race_seed1_best.pth.tar --gpu 2 > log/utkface_race_patch_eo.log 2>&1 & -# CIFAR-10S -nohup python3 train.py --dataset cifar10s --result-dir patch --reprogram-size 2 --epochs 20 --adversary-with-logits --lmbda 10.0 --m rpatch --adversary-with-y --checkpoint std/std_resnet18_cifar10s_seed1_best.pth.tar --gpu 3 > log/cifar10s_patch_eo.log 2>&1 & -``` +## 6. Acknowledgement -#### FAAP +We are deeply grateful to the authors of [Bias-Mimicking](https://github.com/mqraitem/Bias-Mimicking), [FLAC](https://github.com/gsarridis/FLAC), [Fair-Feature-Distillation-for-Visual-Recognition](https://github.com/DQle38/Fair-Feature-Distillation-for-Visual-Recognition), [Fairness-Finetuning](https://github.com/yuzhenmao/Fairness-Finetuning) and [Fairness-Reprogramming](https://github.com/UCSB-NLP-Chang/Fairness-Reprogramming) for making their code publicly available. It has enabled us to construct this repository based on their work. -Step 1: Train deployed models - -```bash -# CelebA -nohup python train_deployed_model.py --dataset celeba --img-size 224 --pretrained --gpu 0 > log/celeba_deployed.log 2>&1 & -# UTKFace -nohup python train_deployed_model.py --dataset utkface --sensitive age --img-size 224 --pretrained --gpu 0 > log/utkface_age_deployed.log 2>&1 & -nohup python train_deployed_model.py --dataset utkface --sensitive race --img-size 224 --pretrained --gpu 1 > log/utkface_race_deployed.log 2>&1 & -# CIFAR-10S -nohup python train_deployed_model.py --dataset cifar10s --img-size 32 --pretrained --gpu 1 > log/cifar10s_deployed.log 2>&1 & -``` - -Step 2: Training of FAAP - -```bash -# CelebA -nohup python faap.py --dataset celeba --lr 5e-4 --epochs 50 --batch-size 64 --img-size 224 --gpu 0 > log/celeba.log 2>&1 & -# UTKFace Age -nohup python faap.py --dataset utkface --sensitive age --lr 5e-4 --epochs 50 --batch-size 64 --img-size 224 --gpu 1 > log/utkface_age.log 2>&1 & -# UTKFace Race -nohup python faap.py --dataset utkface --sensitive race --lr 5e-4 --epochs 50 --batch-size 64 --img-size 224 --gpu 2 > log/utkface_race.log 2>&1 & -# CIFAR-10S -nohup python faap.py --dataset cifar10s --lr 5e-4 --epochs 50 --batch-size 64 --img-size 32 --gpu 3 > log/cifar10s.log 2>&1 & -``` - -Step 3: Test with adversarial examples - -```bash -# CelebA -python test_adversarial_examples.py --dataset celeba --lr 5e-4 --epochs 50 --batch-size 64 --img-size 224 --gpu 0 -# UTKFace Age -python test_adversarial_examples.py --dataset utkface --sensitive age --lr 5e-4 --epochs 50 --batch-size 64 --img-size 224 --gpu 1 -# UTKFace Race -python test_adversarial_examples.py --dataset utkface --sensitive race --lr 5e-4 --epochs 50 --batch-size 64 --img-size 224 --gpu 2 -# CIFAR-10S -python test_adversarial_examples.py --dataset cifar10s --lr 5e-4 --epochs 50 --batch-size 64 --img-size 32 --gpu 3 -``` +If you have any further questions, please feel free to contact [Junjie Yang](jjyang@tju.edu.cn), [Jiajun Jiang](jiangjiajun@tju.edu.cn), [Zeyu Sun](zeyu.zys@gmail.com) and [Junjie Chen](junjiechen@tju.edu.cn). diff --git a/arguments.py b/arguments.py new file mode 100644 index 0000000..02358ca --- /dev/null +++ b/arguments.py @@ -0,0 +1,99 @@ +import os +import torch +import argparse + + +def get_args(): + parser = argparse.ArgumentParser(description="Fairness") + parser.add_argument("--rs", action="store_true") + parser.add_argument("--resume", action="store_true") + parser.add_argument("--adversary-with-logits", action="store_true") + + parser.add_argument("--parallel", action="store_true", help="data parallel") + parser.add_argument("--labelwise", action="store_true", help="labelwise loader") + parser.add_argument("--jointfeature", action="store_true", help="mmd with both joint") + parser.add_argument("--pretrained", action="store_true", help="load the pre-trained model") + parser.add_argument("--checkpoint", action="store_true", help="load the trained model for testing") + parser.add_argument("--no-annealing", action="store_true", help="do not anneal lamb during training") + parser.add_argument("--get-inter", action="store_true", help="get penultimate features for TSNE visualization") + parser.add_argument( + "--adversary-with-y", + action="store_true", + help="True for Equalized Odds, target on [ED_PO1_AcrossZ], " "False for Demographic Parity, target on [ED_FR_AcrossZ].", + ) + + parser.add_argument("--bb", default=0, type=int) + parser.add_argument("--uw", default=1, type=int) + parser.add_argument("--aug", default=1, type=int) + parser.add_argument("--ecu", default=0, type=int) + parser.add_argument("--ratio", default=10, type=int) + parser.add_argument("--wd", default=2e-5, type=float) + parser.add_argument("--alpha", default=1, type=float) + parser.add_argument("--weight", default=0.01, type=float) + parser.add_argument("--epochs_extra", default=20, type=int) + parser.add_argument("--adversary-lr", default=1e-3, type=float) + parser.add_argument("--gender_classifier", default="./bias_capturing_classifiers/bcc_gender.pth", type=str) + parser.add_argument("--color_classifier", default="./bias_capturing_classifiers/bcc_cifar10s.pth", type=str) + + parser.add_argument("--lr", required=True, type=float, help="learning rate") + parser.add_argument("--batch-size", required=True, type=int, help="mini batch size") + parser.add_argument("--lr_layer", type=float, help="learning rate for the last layer") + parser.add_argument("--epochs", required=True, type=int, help="number of training epochs") + + parser.add_argument("--gpu", default=0, type=int, help="CUDA visible device") + parser.add_argument("--seed", default=1, type=int, help="seed for randomness") + parser.add_argument("--save_freq", default=200, type=int, help="save frequency") + parser.add_argument("--evalset", default="all", choices=["all", "train", "test"]) + parser.add_argument("--print_freq", default=300, type=int, help="print frequency") + parser.add_argument("--kd-temp", default=3, type=float, help="temperature for KD") + parser.add_argument("--sigma", default=1.0, type=float, help="sigma for rbf kernel") + parser.add_argument("--optimizer", default="Adam", type=str, choices=["SGD", "Adam"]) + parser.add_argument("--constraint", default="EO", type=str, help="fairness constraint") + parser.add_argument("--model-path", default=None, type=str, help="deployed model path") + parser.add_argument("--teacher-path", default=None, type=str, help="teacher model path") + parser.add_argument("--finetune-method", default="M2", type=str, help="finetune method") + parser.add_argument("--lambh", default=4, type=float, help="kd strength hyperparameter") + parser.add_argument("--img-size", default=224, type=int, help="image size for preprocessing") + parser.add_argument("--skew-ratio", default=0.95, type=float, help="skew ratio for cifar-10s") + parser.add_argument("--term", default=20, type=int, help="the period for recording train acc") + parser.add_argument("--repeat-time", default=1, type=int, help="the number of experimental repeats") + parser.add_argument("--lambf", default=1, type=float, help="feature distill strength hyperparameter") + parser.add_argument("--cbs", default=64, type=int, help="batch_size of dataloader for contrastive loss") + parser.add_argument("--training_ratio", default=2, type=float, help="training ratio for confusion loss") + parser.add_argument("--num-workers", default=8, type=int, help="the number of thread used in dataloader") + parser.add_argument("--target", default="Blond_Hair", type=str, help="target attribute for celeba dataset") + parser.add_argument("--sensitive", default="race", type=str, help="sensitive attribute for utkface dataset") + parser.add_argument("--lmbda", default=0.5, type=float, help="The coefficient of the adversarial loss applied to CE loss") + parser.add_argument( + "--reprogram-size", + default=200, + type=int, + help="This parameter has different meanings for different reprogramming methods. " + "For vanilla reprogramming method, the size of the resized image." + "For reprogram patch, the patch size." + "For optimization-based reprogram, the equivalent size of a patch for optimized pixels.", + ) + parser.add_argument( + "--trigger-data-num", + default=0, + type=int, + help="How many data do you want to use to train reprogram, default for using the whole training set!", + ) + + parser.add_argument("--model", default="resnet18", type=str, choices=["resnet18"]) + parser.add_argument("--method", default="scratch", type=str, choices=["scratch", "kd_mfd"]) + parser.add_argument("--dataset", default="celeba", type=str, choices=["celeba", "utkface", "cifar10s"]) + parser.add_argument("--kernel", default="rbf", type=str, choices=["rbf", "poly"], help="kernel for mmd") + parser.add_argument("--mode", default="none", type=str, help="mode for BM method", choices=["none", "us", "os", "uw"]) + parser.add_argument( + "--rmethod", + default="std", + type=str, + choices=["std", "adv", "repro", "rpatch", "roptim"], + help="Method: standard training, adv training, reprogram (vanilla, patch, optimization-based)", + ) + + args = parser.parse_args() + os.environ["CUDA_VISIBLE_DEVICES"] = str(args.gpu) + + return args diff --git a/figures/accuracy.png b/figures/accuracy.png new file mode 100644 index 0000000000000000000000000000000000000000..15e136bf0eaaa388b89c1b24a71d3d7aeae3e1d4 GIT binary patch literal 84527 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 literal 0 HcmV?d00001 diff --git a/figures/datasets.png b/figures/datasets.png new file mode 100644 index 0000000000000000000000000000000000000000..810c8d474bf6fb0820c8b2e4cf5c6ffd92ce0f19 GIT binary patch literal 28324 zcmdSAXIN8BxbF=DqI3nMcLC|u009C>?@gLWk&ZMa1f+x_0wP^{?;u?W1nIr^8hS@M zNa!_he4c&w-sgI+bFTBAZ|{e!WU|)GntNugduD$3e?ql16bbRD@h~tj2$hxObTBZm z&C$PqKYEBhru;bZLw{j{brfG=ln>MHpcB}(GU_rI7?n}@x9@P!>Bk?GjKCNe&shI{ zFqL(l|G~g;7E_j!dHu=sphgeoD|7ktI2DHdwa-66wtaCP-ms1l4w6~{HQL}ggz>lSo#Y`A|Twk~0)eg+9&=_rsV>dQ@sRnYv}A#9O3Uzn4pb2+ z>tn?KNC|X@f5GDa&yxZy>lpuD_V?PsUQvwy$c0V{2@ay@SQ*8Kh{%_g;S**1Ju@BhBI?xY9hW-XwGPpcMZwfKpACMhOO zuGYs6w7rN6Qz^-t0o?nXYg9pH@vUm`ve(t-Z06#{Y?rB}JJu=c0K8R(vMJn|PXG_i zIMo>uTV6fPtLtl~`qdoX;p7c|hGIyskhr!hc|b4b<>tO+;xQaa*WlrfqKF(JVgNOY zTEMCFJ5UElezli15~9g2>5||qm+h%a??5Ow0T34!4~1STa0%u5*G_RPNUI)9!C*% z$XZ(nLrT-1wXiU=o0ZP3w2{iw2Eqqz8=3WNiuH1+`CEXGun*k(w-eWm9`bvQa8Uw*y8h%YUxy@yL1=t8cq)z!kVn(;YNXheFmawLEY2P?pD>1SiSOjZNB{DM*Ab%lPfWK`Yi~9bVFzaw{p>kJ~;(FWf zdZ996g$lB-YUX49bi@u2$O|-7ne+W4KBZjaV4q%EGGF32Aam7dqD$UhX4ZNam}UUgUX1gKT(5+vt=d8UIagoNNp|H ztmTuHWav(;&JiFPZz!T}qZNKcSywI-Q~rS%$J^9%C%Vw~P$$SH)+vVL68&+Y#8b_vP}@orrdkk?`ZPb~+|JOnAv z$qX;%mh(gbGxkQyig|jLJJ<)VNK@5{e5B96xZ26eL;_KzacnfT;c9VgJDL$slhx{) z9bFkbs~lPvJP{@^ga))QW%znJ8CIj~*WkL@KgHRk{%!)<;JgHEFw@tR@XWcUdAG~p z1<76a4&RfTxahqwIQ8|E+MIBvIkFZ7OIUb z!)MtJrS5}v`6i|!jBu;R8j09H9q?|6$5(IG8SLm!B^+J&b^9IoOvUx%=1AI~Fp1%M zMsQ@BB=p7Y;d{tJaG|O$O?U@ufcsJ(YN}eI924b zXWjz6U*OqFbycxiyA~vhMd3ZAljXq0XQZ0=5-ykCX7fyqLAI)FgMGP9dem%gldIrhPUSy+90%06phQ?S`{gN)`giOb2w%pdxL&w!Z`RDdU( z!aE-bdz4!^@JdeN>CL29JPxUmgLk4K;5ytk*0MOB`VGW>F2)1kSWURf=4UlA;`C@A z^x1sA{gIul(c-o5?Dij_X`5XrNaim;rCwZ24jeH(#9RRszEhB){-Hb)OyIiN3ogD* z-JNG+F=jHM8i(g;HP>qx$IU0XRSt1%7<;vv`HJjV+AqGeQHiU@`s@{(F)ysE4Pl;c z>7P!Mgo#=jl2!ZNcE(PbwViC=&*{*R&Eo=)_G*tO@lVqtyktXkT9!e6zURYl`Odsw z)L-+O%)J_BCI#UR*C~A7kI?$^q6aRKulO(N(#_&MrP+hq1d5*9D zsej9D2KC+#p*W_UBF8x&VI=vyc=@_Vsj<^tbRWzR-zLAB=Xb)>ktlr3$`?<=a4RvQ zo?)!LJ+It+#>-Pz`^XoI!-tHh-|2YA58%H*IeIOT&DNaG4xNAB)nUjJaiW1_M~v4GNvc8<%bl1IoW%B^ zABxAKJ4G3>>@{bOx6)+lzd!a*}Z2E1g6|glrqYZV(`f-ehVu;$u&O%vZ(B(uv!G2X=}hxMvZ`(jADkZ(WA^Esai`_wTL zqdGDZ1WwOZ5^F7cs-k?1% z43oFNemfCoq5IH!;Qgl5bzc;*{%WM|lZm3_f!?5M!xumezwna0Ew`TyKp)rS;wb?A!exQ;7$bmSr#_iv-_0?;qs)fS zQ`;=xEg9z1G+5c_+_08Jp?lRj^RHn=ad50<$3 z^Ub5E!qDv}HFRZfY|7Kz@RN%J+TRq)mTaEew|v}{n9A%lQmdh_ZF_xbH*ndM+S!d` zZo!(hiW+LUJ-MO9d(4CAt(AF`r#u()X($YQ#5l(u0 zg8NV7q#~HOKB+47#vr4(xf08XoQnBA-^q&huxg3e`Tz2}9z3Q)jBDx;w-pCsm)NMy zfB)=Q7pyT4?1$LRm)dS#<*r+$z6ZpQyGsw-zwMDWCYlP>6)YCer82FP#HP^`xj z(*#b%2n<1Rwk$Jn375X%6@$vOSY&iR#HEx?@YV+)AE}p& zq}~%a88g%NJX^E-nKTEa>IWdiQs6~4q`eU@5~{HTW|AhHobp)Q)F-|kP)6h0v}1UF z^`xL~QkyrQOLjXpwN%N1zO(#j4~)B3?}@@ByrZw`SPZGW=FnB#Yzg-{G#lh@E7Zoo zNsW0}0uDDh92+JS16!%R{$27zh%=KH^oF6ugLL*QhT7{txyshE%G;ekzX?T1eU2j? zrBFyyBDI!q-(PzFP=2Czu*gl$IA7R5P=@+eeHOqvN49oq!`#GC@?EuUTMM&!K+;{`!w$MYLjlyj;AVCcQpO?NkH-Q_f_zHoWZsuccVmw=VQu_Iv7kO0pW zdKjPCTb|%eD%+RGW#Ur}@;zd!dV)zAv8ID*iN(j7{YqYj2aE1G2olsG*Yjejg0P@3 zTlj5Zqa14jW}VM0-JC${%=>!x$R7+L#0+n4U7)U^*Pq*pX#ZHfKc_Tr{bdmA9Lqqr z93PWXNi_k_`w&SR0rwKX-X>*Hvp_$2!?X~+Gjd1Wq2kbh&uv7-W@D4T3;P-d8R;p+FQ@7%v#}T?-X`S{?B9Z^|!r;RYOuKxo@`+YFs`>v7l58nJ=F zQGcgzq7|_MPO3!vIka(=g)RzBbRB>_v5CkOr(z@A_fjgR$Ch+uZt!>Z;?l;f;)|1T z`D&sz;OFm^L`Vs-$#Zk|4+W1cDo2v68CNJFkp>*W+tR!phIeu5Rz_ELWfYDC`0gS& zP6kGY)i_mS>i08bM)K)9ySY4j7tT*(iCVQnGsLdk^j72qEUQW7pA>1SD*CQL7P#&= zn|>+jrZ|0L#d+Nm2G+&FIv0_@aJ_n2`>LxHpR%_oB0$1WpVy>sCu|836_5@1G+eHW z6s1_y{*eE8N(5P4Rg$YNVhP>NX@F*YEDpCf-p!H?0ZUU?<;%*ZgwLpkg!~+OGR|nH zw5TNhzNEaN+uzi-tIuWJK2j)*l_LCw6E3~kLP@!kY>Oo@B|-DLD7W4$(fOfku)9^f zR7Pz%PX~Pwy)G!@&LSZQ{_;Rn-&dnxsqB09e7m~!qpJ_lQ{~jp@Dg5+O?;^rO_>j5 z_*s)HivPoF98+gl@0Lnn$YRRlGIAESa!50lUTZQ{`M;;`l2ayw#9=YZbQ`cKWvYJ; z{VYr6#-Pp`Nv`~0;~Kr_yKTEOY{68N9S%DzIl1DJ*TsF*3(LU5S#MSe@&366uJ8R| z>^r2s@kd)D&bHJ)PRKg(Au=oK?OHE8LT>G7;gLQ1^|bcIx*~Pjc|mA0AG}Nc_OZ3D zBDd6T;HgR6c7av5HXlKMbpq~rgPH}rSYHTVZx2%WK z8Lu}%5M?b_I<3>5(nxOAw8(~>OVx7rrUKc0BEB{jfua$H48K6lKtn}61kEjA++eBK zVNocI((QPk0>bjv0Ei`W`>0aR2+(bY=sD{C7Q1 z7Z>x&1xvm_>xqi)dU*S2vbOaKklMXm=FuaHAd5^g3=&Werftv|H^-6;YkFZH3LIRFDpQqzFCn$xM@z!A0rjV7j$wi{@$R(mT@_)2kJ_m#nCeVAoKZpdWZE7g7(Hz z{!eiZMG|tMZ$;U+e&*nBQv%tI*Vw0xNdBVO5eUkh72b%dS1@6Xf*``4wnUtI+Suq%OM<^4vk>KjhXP-g zao>mJdv9~m+04~FO>s-Re%dnL?#bF5wmtsLwX`Ur_+;R9aNT-d1gcIWAzl;P4>xtp zrZ$+m3Zn6c4Dyy)ObjQ-Rkv2 zb+3DC%LFkj)#zkjcK$^~$pE*!q^V#QXLr&YXm^r{HB0kntAA({fI%UjYRc_T7nJ5bvwy1D(BtBVYUo1MuU0Tp{pUTx!_EF1&HMkx=>D}H zZS(&-o6uvBS5GGQz3o4J0H^w=Q@Z~5$nSquoQ>@RehR*~Y0#sy30RBI3STjbuOr%? z3iiIVWpC^HY)^02Z*Mcv*3W&}mcqL*^sFoCAZzIGS2+#Z%JqLyC!&3d%fJRr-i%+K zqv_w9{q&*8MQ=yiR{v zWA(8^w)-W95E|)k_Gftv2~o8zsKqsen@q?O$ivtDcrD2I6vL$Hq+Fc%^z6@S$JBk1 zK*IguQ#Y+273x|A9!n6!ep?8Au^Y>)S-@6|2}TVl}d z=o-TD91UxxgtizZ#}Dw&Vyf$w&HV26!kW7GALcj9rY=&AYYG;8Q9r&3x0iJX7dN*g zGh&-hcX9DGRbRvqFIQg7ute>rqju`LmYSNlj+$yc&O>a^K^Mt4#p{l@roj$~a=JXo zssY6_?;8QDH`3H9N8=4gyyu6{ByJ{U6s4|?8@QU}7{;*L1WpZI-|Cz7SlQhz>S_30 zoCUgWpgtp~1WxnIHFAaOefx!X@O%Ekz`*rNTGvj&^?JjQ>zo_i>F)ifP@fRChIM#b z>Gw1uUMvVBT+x1+8P`eYbg}ug3-?WhePF$8ii!3jcaisLY=+BwUfpTL8%`;da+RBTdudK~wmWtAWTu&bDxMbDelfPxs3fUNJuZs)MrZes43henO zo1AhTHlCEf*B^4Z-^?s&#`ZOKKF_~qnxvU~U*1-0SwM;4hgES6u5FpB!({hH32FeM zniY=)VQ#V8DIUY}&uaU(-f!6|@@BRi!KNIS{CrMuYx9Ci=d6a#rX)u)%5D=x8$|NG z!0StvNAo|+E;)9>w;>bqwhhyjYzZ+3&1O*7^QkKZQze!laItOur_~jD$3Yc#=wTqJ zJYJsBCg1M2s_vu;NzHSMDfX1KoJTVxPu8=?neh}iqF&JL9G5mc8Ug8%&9dnjKd67> zby!cS;^&cG;F{;W_ldW721WPtWM)c1!jOjmROu8S?ALlR zvwNLAqco@ArZ$v?ZvK5sxWHapbD+Qtf6ma?3(1~Cll{8ByPg)UJ8QV1T<(5l`op`! z-3|ev&ri-lLIM{za%lRv`>s0E2v_Q6lkb@~Af((gu`x;V>6qHn4HF=~f_tULbm?+Z z;A!$~K!j5)7fj^O9XOikf_YgtCv5n<$P#iI&jUenMfuio4*XrBc2lL+XBcU6lukV^ z^@MBa)BCsC`>&t8a^`G&)bEEnw&yq`QR+*2iWB#k-@0EdP(-7}^sehgCqgZy^@rNf zXv&oA-NXI2CRi@v0w$G5=7Z`>M%&O~MO}72LX9P%-xnLobf0jZUhpcjQPosTjARhAuZa-n&A5T%rMj=HSC#?z7r;Xz2=ty>i=@{8 z;Kk`SH4B22MuMvHht?s!_kxs51&Wg{RvyBnGm|I%ie?mC#I0#&WInv#rsbTSF!7># z1u}K5UY=<#-h~#opF%6b@Or$h^SZjlEm-l$PtaI0@lisxHVH@eXSIE^T8ktoG`dZ{ zvpTMTPbY4h>OwxsEyJ8)3#NI!l*cuRGaP!|cf_W$r^g$W*5RFa>)bE`XGs>EsF>XO z%7_c))pyM*)n$J*$`tF%h!uTXmmoY7bw4$xXcnw6!Xs(BUI)JV{kC6rldRG=#i>o|_LuI3|xWQAmo~4fPjM ztUKX-Z%k!A*DJl_cob8ll*nfWG<>}?Th99|VgQGj6DsO`o)xgphs3}MAS>2sWR`}$V z;@-AS#kj=y&yVTI8DV_8`O#85fKBR)UYWW?;N#D(3QKW*adfVu-W4+m)w%M?U=WEg z6EXJK3`NxD{s%LtvNn~lle*nEjw7<3Ed|6(g@GZ?wLzinv?eTK#)JR2zFi?B;b`Kk z^l?VYGZm-Jqz{^hAuiU=tj$&FCkFMO`D7X@stSanhF6R?L|cAlH#X-`RXgG>t%SvC zU2$(uT13RD+sp#lu6y;N_C6NZj45MfRC6ZCPRZl+W8&HAzJA+Q0?hWT){mkadH4|O zhVTbPy2%=1uhF*dVwZxkuilNBGuE5nI)s^TPuwyz4oDh&FQ*d`;+9QB33>&W7k0m@ zINl7WylB5<7@@p>z13ND_N`lukebkBPG-htdt1mjFv3XP?as%-HpuG zi$n(382V0gLp;Q~oWc#+X3VY{1GFz&&~7ee#nf@fyFtC)^m_P?cdu}keqWpt%=Mn@ z@#sY4RE%+0#CZZH*%jb6KM;{WbcpAfw@!&GKB)eJv}Q^jzk&0G)&uL|LFb2NN({^4 z{wl*;3A`&Fj4ZbacL<}%*9iLrXPWVBr#~+fiY#M5Ra1;Y_7g4LJvO-&uc%mh(p-{0 zmnL6*A#VD{=s@Fu-^#ttX!j*VDUUgJjz7;t+gkRky%#jvH9Jo%e`R(yYAx>~Y>(2e zi5BKN7w)8y;Ftoy9oROa-gb};&ZHvD=Qgf@GxbYh3-b&A!nP*kZky$_XI!zdjP>9p z3(pd;A0OZaPAHmn`)e29A&|~P4QYASbA)K4-Oxs#_}bap^A$0;{hZVo1+9%>90(fY zA>M!RhbzLM_OMMDAz>hlK=2bu7X5~QW3)^fS~ywzqvAQXY{zyc5jC!}OaaF%n)stQ855B+ea*lRpGG>O{KLHyQDK z%-)7W_$R;ie2a*Q`A8`{vitR7*Wxmy)WC+}ROVcoP?bj8S1gB)&H|dyd@aZ(+=b6wO|4MF@#Ek1jf z(k;I1v!vK_;^883%{B@oDBr6VNyWcwPIO$?$(DU8qy39Xxo{jzoa3vWTd8A_q4~{8 ze`JhAi3?g``jCG2Gl%8&Y&3yMg?swtdw+Y}t+?*=mq~W~FFEZ8c`cXQlDx~{7C?7~tT!r^zs?l{*3Ue5|21VVL6I(G}G1Xc>Ahp~!qWgzYRv7bJ_j*}7 zyKZaM8nNQKzW5pCbTpqZYJh(5c78Zg7yZDupoTf19Zmra_KE$(ws3cHZoXD#aBw64 z4Rh_|IVs;0@>gIkuPJO)mK+F~>)QOqjhX11f@J88Zi)}7TRC2W$jq+OyIJ6~qS&%= z>*Fgn9Y4z1SR0c+`Kl{U1n7xLX!_iDk8OVyX>8SWEONmh#A_K9M!u(R6Q89`w7!T_ zeB^<$YfV&C0|JeRuU|ds6+L}NAXyR^EOW6dxM%UV_Bj>y@qq3W0bNAEcUhU-NgG9# z?GirOKxm-=E;ZP4P#yis=n@?~hZ4+*fMgeNYAP)uS@sR!RK}58eY3v(KtKPe&ve}J z5zlsxo~n%;5KR51U5fSwf;{7lYg|jha@X`puzoj`o zLe;=G-QADHPe!6`a<4Pv_CA&KVbDN>F}9FZxZzjaU%Uto8$bIGxOt)*>|52*`nvQi zX(72^1oNJV4CTBiiqnxEH};5gPLv^%v&@z=V|m}%740=0d>Z1xIUzjN7nIbKy%%3s zb6@N;-#Yz{Ax6FYFjwl&Whi?|i|pv%fmDM*{e=HFG$Q%$d%}U+RJbh7o($n~l~J9m znSnpvjhNO_!PU0+u48k`9K6&zyv%ef*o-aQ*kDObh6N!z&NkmL)$M^NpYSL~)0k5< zo_`tcd*;Hz3Ms8_uI@XRra$p6u;-YG?+-k+6Iy5V!k*>)3FEzA^h<_aqWUjaLO`z{ zN5s7Qayi@;7XJryUdUjaR>>zCcRA&EdA{#*f9^u85EM`&c7NF;HSBw`XEx${Q-K2B z%u3yr&W*H7=UtQ~niYWxsV6L36yl^#vx$d~{3c?qPW>+3;=38{|AbsE`xTF83^|wN zWIj61Ww@Cz9>zuDEM(ehhwPNFXJ#z=-W=#fhi;Kcj4Tg|*W^Wv*4dKgl_;$2PL=5W z;V4(Ga?;8$yDMpVbDQ$4ch3?`_si$XHJ@~Q?114{)Az?!55wDCeD6|KY>g=6S7^HB zda_G0UhZ(;M%DRh;ridoLs653QYKSer%GpGsFpuNEva<(7a=7Q{OM7a8=e40N=X8JOLH|)G>NK->xri_jc*VrEd)@4KUvym- z{ECoVmlIWsTKB6smrrraQO>;H#y=-)@;jSHX{F;cBq74s=BHoVNSs`t=KU(%{&Yv| z>1AA^9G36hA(}{xg+SYl*b;8c ztejq&089Wz%YT?;mEWED-H*UfF3nMZn-kPtCg1RqW@_?fwOO@hCh8=$=gXlVL?CH& znqI+T@n)t6r0-4V#Osu^`(Z9pBN^nGc-MitpZ2?}IHH+(20^yjtVwCX#}eB`r1dYg zcL*L2%kcT0N}-ljf{`!(n2qv$#)iOS-0CQHe!E${N6+@hfoN{3VjZ>sx@;pJ+B}vj z`PF6uzWN!pXLk8pq@+sYpm!a$)qJGx-3$5HF_O0|pP{n1MY#YMu{}oB_*Ydi^0gyg zu;UC=GchMZ9$?~Sa>&&usL1kvQ8G-cr=Y0)_9v2cE9~wYxO`U{%hP-kn89LLc{Qb5 zSbQRoM)~Y;q;|YdXoRsChjptz>HCt|CdU{INT)@$8JT;+ZO1yQOpuRM5jMT>M60ZdWrti28BQ7;o0vtTQ<1eiFCL9Q zv{snS-&DAohE9u5V_J2Gll5u33)sf)j>mEDBEy?sxR{&;-F$Q=qK&g_7`v)BxKuK8 zCxosiR~BUJZ`v;0HTZf<;_NZhg_jclRTfjrG5 z*Ki@B?s6aihascw`-}}fFfL8?CeimvRr$TNZmKTAUG~jI%G|qWBO@<1_>?$zgL{7yYZIe!AOZ*gd(w)=IDj9Y!vs6FJFLA^a8x>*t)Lt_t z6)rqg)LRd2t3hk<0+?tl{^5T@CV;V{Tv_Fw@%vrjN}qzDP3@6>#Q%`&C8@7npV7o- z&i))Q1WmLffAst(zAKWc7@y|Zx1SE%6yo8IviVP4UJ^kmS6e;l-)J{%uOsQq;z|vF zAUA!!@nLxK1Ji$Tsg210Oi%wZ)BkIwAP|ZZN@65qhZ4xchB(?|EF3E=*i4a^bgnxrVsm=mUR2 z2Gl#aZjR%OAIxi*rkh<%&%*SmOq<>8D?Ow%(4x##Pxh>X$DH71#0%*>BgEVt)s zh^v>ty2>LEJ4bU#?sNB8y~hL9vEx`skNd){XWkd+_pIpcOnqFT5mCQ4K{OX|R-Xd1 zDehk9=+ckDB>sK_UOg-)dY;b*`tX4llK*_!B;zBeR_%{KFa2G*kx?t-z3o_iL>0Y? zNP(K!ovKlg1alh2e5!gUy2oKQOF-`e>b@_vBbgQV)Ry6O@uD{yXbcPbnJOk)Kt+{C zV;dK(;T)`t{*xg^(s%9mUCJ;*VAxhcp7fY1>43SHuc!CqY!6{OlIG*}apSIYZwcgw zR>;~UJ?Z2ovHRD$7PC*sUB<%!mkoP&uBZ0w96kSF>ST#HE||+2H^oM9n%`+GgMr^F znn4N*rs7^ll*V{EKYWX~<#*paqK~p=n;r4J3Y*Yd^L1hsr{^OZKEaNfdRv=>U4_a=os=;BufB)Oav`Cmq>}oRGnAHU^bra1k#SS$ zB}PwXmVrM<>dn%`V%i0UIq2y0QtEuVyr+jwSAfW}lN1FioZKMlY)9&t3fYTdE{_aJ zo&mUn%FeuoO82c(;BD+-K~%Bx(_WiLlp)(#WmRzp{nOU3swrW^}}doU#tT`Se` z`pFBbLjR1H39wNift&0vAbSXp10}luR5AtoDmgtzpB3MIyKd?GD?)bo;xSGYW4ZBV zOq97RKgJgQn&16GUEZrbQdr-0=(iNOI;bOtFsNIiW5PggXdfPy8b8YY6ZYv6zR#yZvTQ>s`ydko_WEm$Ke^U zY+ZDPhlRW{BNq_bUZ!#|gK=%2q0x5Uu9|OIdqNsGl3YTxI)>hlmpIafM%l~CttIo& zjSad^v?NE84CYzE350lSG0~3Jh?J6w;EC?p%4Pedu-J8e@0FEMH+sF>_$&)UA$DkL z4+}!)yD!=k$$)CN7;%lJU%6cNM5Irlz_dWO%dCTFS>v7yjZBcJ$Hex$2Iq^et4h)- zY&u??--EyXeWr|f<7-S8S$@RiNN--XxAD6PU!-W0UJQyOXEFVHQ53yo z)eJaRHq16=(IHp!jmdzQ(qa;)$v|GDUN6=UGrZ9ki|T)U`!u%3P4kmE5v1$wjM+Hl z6RTB|UR#Zf(xpPHbrG{~D||}N!*OnZB{C=&; zYv!DZi6P?rHq#7jcU(fyywO!pVNVwYT%43ye12LwxlT6poP*H(Ou59th`5MG*ZRes zagYR@{GS%y`SDx9GpFAH*7G}ss9+Onp=nah5rcVm(k_%d5*LOS=yVH{FYtoOw@>9eA`rdqR!S7wY)TBIzrv@ z#T|_b{rum34y6HqIkQ+iWomER%>j5_&vxZ;-nOAv6Ohzi5tH9J+Wi^X7`ys703AGK zY94>ODw2-cmVUYrxpka^4-k1+-ym(Po_SyeV1`j8dkyu9v1~(NPwg2_hb42Xt5$a` z8q*ZLfFNvv5l2hl0D7G0F2#cer`PueH<_Occ!g=|0UMGq1s#cCiMr{_fES4s84^bE zQ&nNb=gJO={q=F#{hi1c9q6Z7pMZ!Zk|n~GR@tg!=h*-^GG54hSCpSQb_u=Z!~F^5 z_ryxSvF!-0+x@ICKFe_2yY#YVn3;|n@dH}C%ayos{f)0OtT~aa298k~RDZ5n`TinFTVlEWfsRq4;Ok^V z`b~6zdGOmiHoV;DAISuq1>Zm-01r8b--K@00`ZxF$93NC!IoCxvjFtcrZb`ckmFa* zuv8}Nv+KNq&%$Yeup*7==+TG0-9q@!bIu+!_ha>ZusQR4!1Iv~D?eG)lFCjz*e2Os z5Ck^C7})2n zs_1~6yAgoacmTA2K-r0KWX9GT-wMq=cte5Hqd!t(PcWuY9Pa9Hle8G@Rp!M-^JEMJ z(&7g+Ok(D12w|lXT~`I{f$Zbs&f?rG$qDlPEc+}|(fdY{$UnEW)y178VXarJt9=}4 z+d7_9;-^audJ-xjguH+avaedaM$tt*qP7H(4LSe%{xMSbk$xVWUy-2PJa?AfXM6R1 z=2!P*4atgTT9-#8+ymLNX94L8;TdiMrgM>Oik~2JOK3JsznIEq~daq%Jr7#^eL=RaTzW zGo}4OA?6;*H3#ljm=ybh=_LgiZB=iZ>KV*cjSIeZ6ZwvgjL-MpsjwSRjJ@P}odRQV)2PMCi0AWo zI@4Q56-4;rO!X#js;1N+n`Y1EUzZslLD4z5I-yPI>P#I7*_GZ5as;FP{pyf5-k2sS<6{{csw` z>E{3*UUhy+{b)~tLPO?oXWhqKkmP2ndqH{NXmxj+pywgh#VUl)#_e17obtx$-&u^G zCvVzy!PZ*FAag!}s*QT`Q1EqF+QiE*qgZaC!&b$(b=Pfm+yv?F)MB_M3Mg0jt9$)J z$j8GX%pTg7KVz#Yga8y#=}e1 zzJ1iqjZn7w!mwHR^lxb2!bQZcIvEuFbi@34C>73w^_0M%l}~ILWn|++5v2#fIDyT& zvMd%k9|7R_D%iN`bF+_9*1oa{Y+i4V?GKL#V7 zqg)0OsfgXM8oGZ-=1%nD{EYHZNgz_zDA2|9raf^ow(Vw~)7{06OiPnEjY0%2C3);O zG#YEX$*jL2HS&ATy!?eK1Y#eH3oXK>p`&=-*%o&svm{mkjBqL-+W7>`Hy$CZ$N-)- zU+3QxT#!kuZ*BElrDjZsj6m`b{KmSy(@%U>o8Oa$II{pZEBF-M$Xj z&Dt@lFl*7C8Z%tp>!+?Sz=8JHhdDbkoAg`ZAxSoZ07)lVdFe@a{dQNfO|Lk527z|(u)Gat9~Ob^s(TWH0?@1 zfsd+WX)W;zsc9X_050Fm@pn33rTfwdVIzruP|U~%3_nqe^p)Y5lzA|x?j(G%J|G7n z%F+6nDshWmKV3aD%YBTD8q%<}*eD;lBE6Ir^EMSRBs)+}lt5ew=8sUd*;>e4WzY9L zI-qYmC^0Cf-^L$NzES+(T?~MvQjH&#Ot}1*c)UVAXE0}U8j#!$fwPn`e1;AtF!H!1 zc@0R~4_MMYODoJ$r>m2=fObQ4kfqUcv2TqoluKNUun-Bm-E3opY6Xl@z*J($!B`#> z2JAfuxhh_K&|bmIeJ&g;eo?7NKl{(Nsut&VPZiW$jYC+I$SQR?dD=um=3hO>MPJl% z)5R@pg!jBL^V2f$uK>d_W2iY?U2NMTo%gTwL#2mf;>Vs%3Ztr3*K*p>)4yAM%^q`L14!31Ec4L`Xfg zZHM!N)FfL={hNMK6Bd8vA5p%V%Ue!jC6+5-L)V-lZ@vvll+k(0@ znGL%~SP%7Iae0X(kV|+nFSfpCev$LXc8)4^wQcl%`IZtTo>l*p2=2+ucE+$~S?jUz z=vKo4`QfRh*r`WdxpSFH|Rj;8*hdn9r;N4(#8$ifAA;{~7fUGP~eGn#4 z(tc(M`BhpNv?)MD)H>N(g2~+|Joz3`*A=K`r_gG&@O9ns#_VYk!|HEpHGcEQ95U$eBKD$RYL^OMD_|5=*6Bl}tATn8T267>P==8hT ze$OW9tzK6G-%g_e3?(kExgh`4w+b!-av!E9G9c46?emLwte;FZy=<3`FVT~a;fL=; z6D?gbmosNuUzREiank`8b`o)wa#i+_`Lj~Ihi#7ZKyf!O+Ap(e{9hWM_7sN3h^1Qt z^Rca>Uz&|bC(`;P^WrsQM9h+!yoQ4X$fd^bMx*I#a){Fz9s*)?Q~iW+jFf)ni`t^WZsgLy{W-3>a1^2ueVTvR5* zJXh4(Ducvk39G1z#?$dNJF4Smi17wEv#w$;5kzre?ROZaYIePbHHAnT=ga>ymAW7) znt7AAwdcU8ZU%Yt(taso*5-6GH~ZAIWTMbLjPF+^gLrh#jV1ff$4_Rn7bp@>^+cO@ z6UI;V>a3By0{J~>GZN@kV=6v;@$bZM#Q!mWlL<`ebl8}IayG))nU2V2`X`;FmsO>0 zruVZ7md+=x=ADUDJasOk%iyE?dXi%h?v~W){mB`T8Sr445=I@I0X=V;xT#Ok+V)0{|&X1PR zctHzYNZ8ur?#T)cjx<|ZATlfv>2adD`K=K>zvTMNSA`)ErZuP=2$Qv}CM!ZZR=|e3 zdY1BYkv*M_WdvEaIcLR1-d4>RMEhmaz3fUY{=mlZz1q*7e?VB0x~1gG5kF8tc&mgpO4ta?i80^$TxqbLrA{0lI=Kpg*h_Dzb6Nqn)_PucxtwT$!0%d zh;3u+-zp0js$wV{AeZT|m)DY6RtzF_Jlij@(GSzEYnUTD+J*txll1 z#2<-elnV;#+afjWyzmQj^Eaw;hpKV$yIBEA16!`nDoVU7p??AyiVsH|jP_CMEq5P% zk7!`1kLUaQsQU(&;rrh%sERCnC~8RjA^`c$%)80 z9I>g@vwu2sxqVAN0|+1-CFmrEZU@%VVmac$v3kv_NoTkm+1!I#X2AETb`g}b`{go2 zIkNTIl$J$vu)Bj7GQ{G9vDJ1^>z7sU63Zik76*&X90_&rbJiXVp&NX2v@%P#?W-Lv z&nASX`ROY~*@@}-6|Pr#v4O(leD@@uic&G#@2Qb zva{*fAy@cuvk%)fI~0YlZMEEXts$BZ6nf$fY`V5VGs+M6Z-3w0`zH2T#;PyMy^xwK zr?pR(UF25l&o7q@bFV2+AB=Z6d}|d4k5G3iS^?I4gdDu)4tblpD3=m~mcIg%isCK5 zN)&3bM-Pcp@Ga;#7q|5MhBtF)ni!o^b-%z8NRUuP(vER$I3c2?tmM3Xe0(!`NAMtL z#YDR#_cA8Uu4kqAc>~m8amEJ4n4>V;lC4k>foIO!;K_BTKQ|i_FKY&Dp#Q`i9{qP< zE&0~#VzH@*-ZRe&0H0WfLO)u$9QAu29Y~_~VN>^f(BlB~j{QO2&rZ?lpRS7v&&y33 z;G#%h(er*)KDx9po+koy`>K&JDGAu$85Hz`X(K4eGV^8-I(0?i3wc*5qS@$C4cRd0 zQNnF7R8$M}Nq9wHS5UUE6WlBGL#=Xi%g@WX(xc^8wBWW9;#vMQ0UB&w;lf-XnJ2M_ zB-qe(;yS4KiufQ=Fz}LgOAKtEAnmnbaPid(V?nmZ@>;;mWGdQT=k(NG2KVtlS)A1%I3+G{&xw`Qqq%m2&oi<(r}d z@_}Akqs1BQ7YzLxoBo8mIer%8NR0BtbhZlUTz=6CMtCyz>jJ0eKv^-XpZuI?0lK_< z&g4~*xIy~!v@T!{>Ey$m_&N6cFLW?}PAvy-ri@poIXZS_q$I!~aQ zENowh+Z#$}*$+FQ?H6mZoqyS@Eb|mdVj^yQ?77EyR}HG!EWyvKAW|tRKTg~IlJ6Nt zP}Y+t^xSQ(w;cAB?r%a@&34mpV<{bHjS>rNXJRh{*|iOW`AX*ULTel!=?e;?omS>(R9_L z3IQ7ip7OUyd49`q`#^&i(iOG8N5w|n=zBh~1{f?S$X`5fIz1cwTEKRKC+9<6L1b#X ze)h;trIy&qv%u%m!PgrHnFCr0(jLzs%WVm`_M1ZpxA$HBMqkdd*H9%Hvfn|x(Y@>c zsqCxcnta>7>5vjd>6Vg`W|NeT(MX5VCEW}J1Vp-}yJ0j+gF!cgF;XN38!aIq@D6|X z{k-*gpZ9tG+-JLX?K-aQ+;M*E=;}G%&Y)C^42OO92e}Y)TFgPGs|^seNS}>3M{tAM ztkZi?ou7_WNf)W)n=lxSpX9GQ^zW1>V62b?To7jW6MnXNn~S`hHdyv^p#pDuYn#)? zELMA(vGC5BIIm}>Xi_3*6TSDbX?1ZjwQd_ip}e7xsn)}#I*Rm9UXK9iil`!t7MQ0E zq~x~yQ?&tAW>_~!R8DDo%TxcuORn>zYs^isE>iZx9WX~uoy-Lg>i;;ld9!{+Z%dci z{^OpHQtna=Nv>>s!wU8|qH%BzGo}yGOZqbrWja@6AErUz(BLyb)x2qx8(H>4?cKQV za#MnWN}E{2=qW0d1Gs3joJo*N2;sODzma=^csJfprPU2JNCRxbDJ*fv*Qfy&7FAAR z9!60NpWG3-zWT>EMvZS?(&OOFb5`50a^gF)hUyQOk<1wcp>5iA;-S2617c=!GYp$f29aOpUQUBIgwXs2bsFmgwYJd@>C_Xom&|0x zFADG%xq1}prKlUVq(lkP=v5}h)F7>ux`mt0#vfr^17Tx*n5-^Fx%Eja&NQ|&JyG7A z`}XA8aAlZi`G+Zy+~;^8|1xK{Kd=2ih04`o7}17Y^jc5=dR{&U4_crWxjs-HxYieCzrW=jAgYj&QF+;N{a52?>zegkEq(`GJs>a&-Je8A8h7d zr@GJwv_hKVRZsn@lK zkA_wFw9H`Ib>V2x8&aU+m~i#)i>>mVdYOu|WWY?;(t`6#mjcS2D=Wfwcex?f$DFzwl=fG@0$Og=@p*CMi|CxJKbVuM%H` z-J~ZHurbQ7rjpm;L-!Jt;W5#$ds!mEZ99aSLUuyM#9@;u@e9E0AJy-LPbp@0WpOJ9?1(RdDLw2{sZW)LRP|&W z7psY^(b;SR^CqT2ooVgO)`D?v!f2%9twF@yZx%C_E;O0ev$#)LalGDMTl6t9jrp6* zE9iXP570YdffqQ=P(Qa?ED86=#F%u%Y2N0}@U=ifzC<*$A$NT_IvKyy`@|Q6ZE3csW{V0_2-STpIrox;v{rlXN+M zG+7k%spYG~-y11@jy7a9vABJ4bKHDCMIff&OgQcqj7)vXnGDpU*&ODjixdE@&ZZW|I(@en z>US1J29@@up|=x&?V5(6ooFE&zler|-3*H5@c2e7sjQ+L)`jPBKgu=eTKVGBD^sMQ z&4+yc3`JHkAdbDyvwQp`cwW5csWx?#)#-LSspouJk4FR*yD_fi*i#)A;vWh>bV1FF z%LvioP*n=o}ZC@{`Tm;NBvo_cI)&KGBi zN=QmwsSaC75=^3!+wyrURSNqlN3^F~qWk+uJUbKm_t3LVEFv^r0d+v!dX1h25O9u} z(v0Y2Ai`m~>87zs$Ls|0-~`&kds^*16R*QTo8~X_Q7|se1qkyipYi*|x%`&w+%}Yp zd!H-Av&Vs9hFfOXPT8?oK`tjpA)HFc=3U2ot&c)9Jh(!CRT5d@9=(hXH zCW#d+IAByl66%<5u%mDna!S#B2OYB_eX(4zw&5-YVoKX;)v#FmsO3FD?%|35U^s9u zYb~k^>RJ22G%pR-I@Kkbr~p|f-a&~tn<KSWJatA)vM_YjU^$(kRh=1us& zxN3egLm_M6&mJ@{fb}OpQo0;b1d_5s_ES&;e?Opp!BEhvnj)br=dnofmteHyq)@Jm zA+@4_3+qhU(#=*n3i_}pUWgt2a_M)brHSiKb{EvyUg~F3rT1{$u2{3*^YvkboJDW{ znIv4-k60(6Z?_o&tLkjno>X|M4B*Z-<@@H$nRq(=H|Zi4>Zk0!h}(|ozV|-+Q!qQz921!>?tQ~C z7p(k*)wpHQLjpfw;*Aq>e;;IkytyfzD- z#T?I%UjVTfR;vaev$l-s(@U}9UgDE9Ap0uO(%GIm=X z_3W*oq47XX=~KN^XXo;stIMB*we|Vyf5AhMpXeB}j)hw^NdEE)eiz4u?EJ`{4S9a` zRS188A#fuJc^+Y5Rsp$MvfE$03m}{IXDRy*$QcnaHOa8B8Wq>N)jMdQZ|J_$K2>RW zNYoC1ENPV!E?04UB7bE~vy(Ma<}fDFTd^KYr6-|bh0dm<+xL0daku5$-8+)F=RX&g z09KnuZX{>P!d~X;91E*UO|!DbY#!!k)ah;A5a)qZ4&lwVcs~+{GT32FPI!)Z)NQ%& z&V!vKO8N=2d{%HefrHMLL!MrD>G>Mmi)`Ufj=H!~z$oBu8|rS&2wBVQK)OF%a#H5x zM`q=Wg;*dM`) zQeS2#fmo4qvn;n&NS@DK^a^V$0*1l`Y+Igrob-3D=q9W?iy>KK7PN1vMUYs<3rg{H zV;Z-QmlF7w>f>b|b_U3F4`RoJSw*Run=#!szM3N4gxJl=W*OKXZ0_ph*2ekxY)c@N z_xRkTce$DOpBCwEbLQJUbWs&!+mXS?eWsR-0|psZ4Bv-?BMyD7;KS3jLduVITB`Z*yN{S ziw7H$<_Ijb8mt&0rrOtB@q`XFtN4~}DTzs1JgMdIwu#$c=T3o~JiPi=9Xnc9-82K< zm{AZDjed|>;%$5H_=h?2;nZWMnD*c?_P-nU#m8vTlXGw<>J$7$)_ z{Gxegd(V&LADH&PZD{}J^ZWzH{vWB2J138xyyQUxZT~!rPI$Zw9vaIp6iw;PXZ;H? z!%23}sjYk-p@o-!ul+CZ`rnG*9F0Uv!cO7ei74&Lg5Il)!3`L|%_+LQ=(Pj?yhCsT;Z&}{ zd$!?^8im8rcs_6No+mnY4@vz!*LPWDbw5WE9q4o#l-;|C7@x55+A2`zZW|rpP8$<+ zUUd9zcG}Lrgg~1KePg<>s1JtU;-><&yj-IzwcMv+bIXQD=OeOE*R57(lqR=Fl} zBml6w5q#0IvGh`{Pg9K3x2U=ha0ATwX|pUP0(dfR8bvS~wvcm`5K^ctHYvReRu4xh zBW~6Qs(V1fEmPZYBL42rzgx&;*XI@QwQK^4;;NkvrVt!?5)HpwH1|#O;sO;Gf(Vc- zHUSf8ArF!r*5B#*N9^`^BF18`#OD1$gL9xZa-g}PX3U{jB}AU*cKw%!!*OYrb>BO@o;_uh}5s`%bnvgQdr5(w?MO`*8UA-_~{2~~z zOu1hyJZ2k8s%%j)5Eh_vy>4iX&kB_tk}|glb7tD9iz##-auKJ8u>r#T1%dk1taJk@Xr*IFul)jmkwxHKMfOKxgG#4|tZ|Rc*T|3UM zeYt2z_71bjTPbL$vrRbiM78n2n6ZIz{#XRs6t3Pqs|ZP5XcXx-`s#kbqA|IltTz8ElN)M z=EZqtVZEAU9|88KzEa84VQkr;aSjVgDg!pX$;vC_hB|D>`5zg0r_@3qGkDtkoUC3^ zaUNC{DSVqhfUOT!jlH^T2me4G9J9l}kv2JtUKmiPPNGXxTGOGk5S5xwK9bn;XR93| zWo_Uu19K|l``UtIxiOd~jzy77>~zmT_|e}Qaq9EABpyOPCMW1*9V@m2R}2VKU8k86 zRO<+-JA^eQ4EEt#&@y3wl-@us??HC2R={%912eIi7lLwR3%eMn>c?ZV0QwPlcIE3_ zGlmnzvmW^~WQ_+Jx?m2pD39571?ElbcLSxPoVhO`tgY3cJ#+@(kY}@Gcu;tIkUQ8p ze@1XZHoKs;>xnY7Ul3iOfU*Z&D778Ql8!&M#h`TWSgxIR-ydYQkIX zwy_*qc2w?ds!}VMFg<@!UYiQ(7CC9Nt@s0>fgj|I>2sjN#Zn=g^=dX|sxYaNApBvb zB0-17E-ncFRZS4N`3mjUvf+w8_>cU}@*=@OeWUsCUqgLl#5sKCya(6G?~sA_z%Rw( zcsz@6?Nrkrdwrx4mCvHTx5O(&v}@ zq!1II>%{K*GvdU9c2TOuYC%i-9H6);^peVP1chX^d3uX^$dy$LL{grJ;=e*-`4h*4w z+JlmrNJbsho0HdX84{X}yn+q46PaBmItp=yzYn(JP#gYsy2*}qxK|v#UPGt)fwbOw z^uEN!Qj#H{9OM@U_<+TOeoy`kS(YJpulk`S3()cRE7S82ZDseuKs;5wA1xf{SK zxr!JpF1YS;b1G2pIU?#u#=NN}Heh%=gNECG&A5u*D!MmUh~g5wbIKk2CeztJ2mpw zGpSjZFbN16^m#&ROT1%PryH3%)mUMgSR6FrA{VNa=1OV2bQgUh!j=&VlEwFDm8>12T*x1)IgwjwBQ^K+<{;GvK%|O;v(-9pAM0 z%4hekES(QCUqztHX#dKlY8m;s!VQkZ>n_TTB$R#0&CwVm-8RWt0+aGS%`W!94?EAO z7^nK;T@Kzpgz0*7!1&DL@MKe^!wAF=DwwwIt^xJ_(;ywgRAAkGZ2tyN<#O$vf`{|O zUUpA6YtE=7$6NXq%Fom_Ox}T!%KX^vns7Hwq;c*tLSmTWdKQdw=5W}dJ|%7g&PCW< ze>BXW^*LNrO{Pc9*i1CSc6JE$y% zM$hSK^sfEB>0B@MkZI!*qiOX@4alHI-wG-!;n?swM+{;Dj~`+hM$zj$mu1m!kX>4_ z6dvf@u&48uC0b_|5xeuVM&Vo`lD)`-+fX_8in2T|@{HytA35}(a(V}G}u#D`Q zAiUA`_pCL}Iz@D@Il)~XEJell91T%4t90TJM=f`20a0O6(0TrYRLl$g0a~|F_fbEF z8`nroyU^oN@B4}2!_s@dMFr%uOeeznawZ~$@?zw(J^HJ}9Ln+hnV(ydH>I{~+z%-3 zPZMToXW#o#BqxzER~4-{eq;)37ltxD&lc^q$X=XaeqNpZzHFI{u(8bLwGUPZTi}Ak zg5d5AFo|BxJ7F~yANY8&(vP98)bi8i0%TiykbE=GD;2fyVi=@bG6kNcucc-ePas`S zl#RBzrkX`81ppkf$Y(=ZB+1W?a?JK*3_KdQN2;u;PGek%8QqDq1#s;xIQdWLsgE)+ z@op0MypA$Q9ScBqkNM7wv3YD4v@!^OzP?SO4Vk6nAxZw2UBipfv_F`lc%d^$Nx~KX zf-cU|3aXacZKcjCV^syiWYVD5WUhK&oc(4r$B09`mP&=rGtNzWZEi17GtTD3c%}>m zBrvv!^x*e?7Nx42OCv7%f{dMc1 zxo0tIJJ?rIyESiE+|Lv$C6y~pnm#m^#%-h}iC=}DaSgwk<@D?Q)&EyOuLqQsf|rQ7 zmyIqWt|o$2`to$7vJ@)D<>M>Lv%tye%%{A3B{ifWJIdz6_k-1S!EadbxK=1Rv!(6$ zWS$F8!wLxWyiL>v_DUz#U^i#NJg|@ zoo4r=lM5PVv=+#z9%8X_$qx_N(M7+{j#U6&PALit$I8P*@aT%2r(NJlG1KGsSj9n! zqaJRGG0}WWX!|G}f#hx9lU^Dv>vi2Iw#xU-CqV{E!_J!!_ z7vfO}24JGPxv*}i#J7ON8SUkKD`fAl5NFrs?^R9U(;y>hTli(r{Sty5-J5y-3sS4; zt%1}=4Qi}Ln&c%)+1AVor>P!ow;B?77Q5;qtRls%j#{t>rI>pv6)p%KewBeX?-0yc zjr?3FNagLL3ihnAE<^7JK`*7S70Ge}qXL%;WW=38`6sEe8FDaONNMPnl(&%5Hne2? z0WE!@P2%e6>v3sg15_mT4!2_7mVDkVu7gvaQINxn{H z!+ZTPqEA`f;Htyr+qgMp$HP5u2RkZ&{nT%%&G@AS8CcPbeiZP$N=zIqq2x7vV(K_U zh*Mvu`K&O`FtWj!69Mg8zd`morBmnnNzUBg&Kx+lQk@h^Zk<-blasO|#f^{jsDZJ4 zWsdG^E{>qjbip@aHc50^Z$40#4TS$|O)=w`XEQfo{#^uwMo4YeSKCMmk1~~-PG|b> z&M?VG^P?_3QqVd5MZbgx)B=yizUQx6|toyYLR%tFxh4g}9xWNQX zhNv)pm%W5-bX#FKXZ7|E@{+(2HKpicE>KzB!4Rj)86m6;k6*_AYWXBT351q!#qT=oMiZz-$m z_ZNvSpf$SLv;jl>LR&MM+!^o4o%_MWHdQDa>2{Vtxyw#tNgvwcw>+%PPdjXkGKizF zR$m<3tR0)l)!A-&X~ zZd60TO>?c0;WXtgYl2JK8af4n;HX7+wen`T?~TWygN&a=Vt-JDq6mH*#kp$4N4a>q zi~SkGUcgTyznkuHkiloh^UYufCZedg4=IYJ05L>PXkH*C?J1qyw#Y3afLKwZu7vw< zYiaTYUAk8V-Ie2o{K*QWz^rZJzNq;jCv5tf>Q#`vA|?z0Jloa8jzhW$WV67wlQbLy zadKv|u zD6bc8IYxS=?X^BxfvN{O_T{Isp!U_&+Xs5K8Z`%t#e*S2q2YO0rZ&I}P4tTx$PtzNE z-P^yl+qKa9V6`AYqV;8Dpwmxu`r!WEn2$ili$nUrJN!QIAB;O64e8Y13ElU>cPP-U z<{bu9?F7FQy#HfS-u>!&hN2s<3qQHTdQ2uBZkX*Pp9_b$_+vxX#LwBfx=qpeeYl6U z)3Ef#kKm2W+a~S)HVMuU)s(CEXeF4gnXb;uQn!2;OQWu>pyBj5kH^!M?Sdhjr5U6f zX)8^xSsS_zq+Cv(+*O+B5M2fo3ouNov{5Z7XA&^0KfUI=l<@%NuL|Xw{&AC&z_;N= zYwbD25A&3Q6&^U;G)SxFqr|1lsynsWcZ3@9*KHYxBLvG#_2wLXe~-9Yzkn-TKhP%A zp)c7@B7v0)A`CnEqIQXCZxh-F!HJR=I>Bm*`-e54!N|=#>a61l$*drPVfCHz3k22X z_w*Uvt4uwW^g{EO3WFZ(cg!xlUTHi01T^4j6T9M`<1sp= zccbkp{&c@&nim6h z=y+II^O{cCQ-NTnekrm7cIF1ZEHC zcp{~U=tev%gi*){Bhp#1GQfoJOaT~=b#}{ z0{LIuol{Rf3MWYy_jniMOWT`1{oWJlZCn4D>As^r`=oEt5kGn0nD)DESPKdUNAU)(sroAkd zNC`3D`zhw4GT!edNn~r4?Q!w;#3(DM^ZjuC`R{CJ(-a=IjARMozt~Xf_7g1&t2U^% zj_ZIeXAhZVpw-&ycBbmJ9wdoz+?z+#yj&Axqj=4ERLcs6>?E&p$plX=i|TZ_&P<>& zA|jjRGzeHZjd}CSEpsa&8X_92k;Jefb~Zti>L8hM@;EzPj@ggwZjElOqO*~%uW!V< zMpx_>O{5Guhkh1bL!ssjIq~8U#y-8 zCaA9&wN^@~!N1#?KhA)oNf1}5^jDI1yv1nzmu;MyE6*TX&$U@LbNmG;E?i9DHrsqF ziA!QcG|i5y<-9TxmA_6J?P i|9yOzo^8`DqnCLLhwn4QH}qsV3>5_pdB_XPu>S$cI9qH0 literal 0 HcmV?d00001 diff --git a/figures/fairness.png b/figures/fairness.png new file mode 100644 index 0000000000000000000000000000000000000000..89e553b61914c0ec3ea4972961ddf1fbaaee69f5 GIT binary patch literal 439627 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

0Y7Fc{FBtQhD*B2}}*#4FIzVNu#M} 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 S~b*Y3XA2D!7Q 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⋘4IN#uRja-9qXYmc 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

x*+_DpN&( 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 literal 0 HcmV?d00001 diff --git a/figures/time.png b/figures/time.png new file mode 100644 index 0000000000000000000000000000000000000000..b669a75df48d9be9628a7ea6f4010c8e122e5d87 GIT binary patch literal 61424 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

NQe80Zj%zk6E|7w9%q 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 literal 0 HcmV?d00001 diff --git a/helper.py b/helper.py index 3faf4d6..029f6d8 100644 --- a/helper.py +++ b/helper.py @@ -17,23 +17,7 @@ def set_seed(seed): cudnn.benchmark = False # set to False for final report -def make_log_name(args, model_name): - log_name = model_name - - if args.dataset == "celeba": - log_name += f"_{args.dataset}_{args.target.lower()}" - elif args.dataset == "utkface": - log_name += f"_{args.dataset}_{args.sensitive}" - else: - log_name += f"_{args.dataset}" - - log_name += f"_seed{args.seed}" - - return log_name - - def get_results(filename, metric): - # print(f"File name: {filename}") print(f"Metric name: {metric}") with open(filename, "r", encoding="UTF-8") as f: lines = f.readlines() @@ -49,7 +33,6 @@ def get_results(filename, metric): def get_metric_list(filename, metric): - with open(filename, "r", encoding="UTF-8") as f: lines = f.readlines() for line in lines: diff --git a/plot/boxplot_acc_celeba.pdf b/plot/boxplot_acc_celeba.pdf new file mode 100644 index 0000000000000000000000000000000000000000..a010cadd31e32b06df9763fc4346c1c657b5f279 GIT binary patch literal 33493 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 H5QqC;C1-5_ literal 0 HcmV?d00001 diff --git a/plot/boxplot_acc_cifar10s.pdf b/plot/boxplot_acc_cifar10s.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b05e90ac8e1a42f74914e9d6a1b6df09044ce1c2 GIT binary patch literal 33726 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

{h0`X! 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 sS@-mR)FOZS;{T}S|KFUJSn{6Yn+a literal 0 HcmV?d00001 diff --git a/figures/methods.png b/figures/methods.png new file mode 100644 index 0000000000000000000000000000000000000000..b6c1e319bad2edb69f8a482085abc561cc889f44 GIT binary patch literal 152800 zcmeFYcTkhv*EXu6pwjGgP!W(KNbevb(gdW0A_R~~2@((?ASIwi1w=r4Cm=mE>79rI zL0Ta68l=S}6iH~Ip5XI)-|u9na^{c zKXKv&v#!nqlM^S-F`PI-$8?sSHnMORewOxj(#u5q{)y5)ZUXJgX=e=sjT0xzqZs#} zo}qm|_d>_Y>%@s`0>^(Rbxm&lIdS4BSNDO2*(=-S1EXRAbov-|1}ipIG*=n`aJ=Lc z0FXIT)ckZHM*#Cd%QQiiD+cHm$;b5ZW!PKE54U7;PcHcly( zJb3L^Wu5D}9Nki}d#(xcgQs#z8&hnd!^F*xYe5)QRCk?mvLD%KK{45{g>QB?BVbLD zDkODNYA!K4+F4EU<#pYdTmSt6d#Y6)3jg<4+6VAcZtnl}f7-yEI5_;@13B+szWDs_ zfvU$WEdRQtZp^i=R*ioTVDBp`==^)&$!!LPe?L=~adGy4PAltw!z2o%5!_ZN-0#*s zK1)>Wza^46gWBya8(mvn?D>Bx2y`iypS1mNVPmefCI5eA0jsuon~vTL>ti>pYz6*H zLpkpM8nMS#Eln5<##(n+{3jsd_K`?6j{tZ{XfyqQ#!b-XPr6vM#Pr|QAoo^x`U2>=^t3tcmCY^wmlHS$34{ot2=-A zUcS^$y>91s`=$rw>Ym@LR{_<*wQ4QZoZN9z5_-pK+Zt|ZW1zh!d~4NE{x-c->keyj zmBF(m_ob@`zc}2lhii+g`M>y;72>9#Z#`=dKhXGg6N-a5TRXtFzA7`Eal7bBhIb&_fYvab%mXo;i7=lsL7>NSQx90 z>9=pnUGrlq9y*Se2{KwNEEAVRUf1FpJckPFe30djLXyJ=f6XwCZkLFhr)L}wP3R~u zX{DC{)>pWm_P%;jj+6EDSjH=I%*h(w-zt##i}zTru#d_yFsKGo$*TCpD~o^dsQvcc zTK9+<^;u5PEEfB-T5lrNa#VAlsWI=kPE9d$IX)6)-JKO8U$YVser7sX z2S0E_7T3Oq=rG9Zx~>tNGk~&z>{FHJp!b^kcx5|o2Y6SUYxC4*p^M0SEM%7Ks@huB zQ7@D32T9Qi{ouLl$K~0*)s`z{;g|pd3cR(0O}Vk(*5Mhbnt`~OMhdg;VWYE)O+)l) zCbAc*aoNtF7%t>_cJ~z6MmmVRZ8rS+#&m$!?Udb6Ktr3YUa<#3ryDP!Ui%S;{&qcZ z=NALX*U?+iz5WJnC0oD6$|2Bxl2EdEqm&JPolF6VJM>aTeYaPA$T|23N9iTiUa!Kc zJ1i`m9BkzJP=vYM6y#n={pwAbtGA9YYkE4$f|G5tf?M!$PWGHQ_50c;$};}HneLwW z{O~c)s@@ltP&WRsb5*&}Q;RWVo$<8$+EA9w2Twv?aj`6b)4g~7BAL|( zcc*6YFCQ;;ic%#Fn*%86n~m;Cx?j(eaw6@UQ|XK1m#DThnN1>-e&}1Y_={}aLn*G6 zU7)<0-%aI`cujoOk!zEBXopj?#%-=#7JqBrKB_~>lBC{%tpK+Mw%pcfg;^-%Cr%sJmb)OXWDimU2je;u<2p2J0jzrkt zDS)H!6D~bB+q{WSGBz$|3O_vZWxg_UhR1Vt%H1iO94J9^ABE>(@0u{NwgrzaHop4R zevkz84qa;^Yv(&$Y7-_pTzsm7D8cM*F-Ki0l3rjrx`Bp_9&Et6UQ>Abah znNIg59)qw(6+Qg%X8gGc6O+U1esTH>4&s}q32i=*^JXK^niS3mvF&csB1?1jqroAW z-=q*(-v>isn9*Un#@TezSEGXzoUeACJN>>MhUiBP#|g;NU~ zfAc%rBA3u8zsJhL`Etr<+6Y%02(ozqD&l%KKu^c?wItO<)nl0zG&5fz2L8y+Eptlz z9wl&&n=Pl&Tq#gZ{26X~;Qf)}7gMxLKSp(b9F9@n+Hw7wP<4grLYFg}gZ%}%cSFTS zs#Di|4PUx3af_J_F59GeO|bN3Yu@jVma>s$zw1``-o*?eZhqu>VN4{Dx0V$Z}X zc?l1go?5f@*EF{%`t5aC7a^uL0J5p_itEi|^jnFJeB?^JX}BZmzBUTo`EX#Em<;Jtna?k5VxtNu@?`%1D;W zLV08ZVYr$JfPdL1OPkxPg9%o1bwu690@1ltxKsQ%j!c^Q%2V@{e@fT}dP6TRL}w$g zaRUtaw}O&9bBabb$VdWHvZ_vu-fZEm9+jIBtx2_2>fGFBmfp8tdW-*lw$Zv>mwB)u zoyx#wY$dJmx>d3#i86b@T5Q{s8LMvLnW_`(f!Ze*LgrM1i}cErawPW9Co(M!m-)IK zmaZhA!#;&?d@69~2a0#=CHCUjZHBfN+PA)bl2F}j-?WSL6x*?O3z)oEcZuE6CLUFk zx7TM-l9A-vEX%-jmOlc!D}a^8Ru}@uw5@u(!@cC~8mrlQ>B z?ZzBNDDU74^I?f%1juys?lZm?->PCcLg!W-5~V+(<>!b{Y>8%YQLxDM9QG5ux+vJ? z0^nFRVPH~ynA_zE@C&Q5w@&)fOc0OFQxg4JmWvq`PQaAw4Du6iEr3&8yTZk!rYSK7E0DO_7DTu;oXHgX4R#ldDZLU z5#m%qi>rLs^Pqb!9De)!fUDaeE^>Ieu-YEQ?$F`DdK&|B@z2*=dJa0*ZDxTPSuCvS z6wRF@!Mcu!6gm>m*EC25Cg0Mj7Pw_qD!B%VM(Zs)*Hk~Z(kovp4yn3VWo+qWj{-k0 zZ&J!IGHXwUpWplagLP!hF#N6ZHO`hRWS0~DSy?ydgyJ4T^T+Qk9 zA1f{RR_Kjg(L=Fa1@efLRo%?NMmZkH6jc=reW~ETv!l*@w7<|^!LATz{>ki%*;}zh zgx^GYx;N+Gd4=|{IGED|>FyGx=$C0otb)jVKEki2TuNyAx245mA)9MPL~n~7l7m`A zRkHJ{IQ*K&oAN}}_+>zz{c;7@CL{DI;NUxMhbb5z0Ekc|CbQoi&v|yxeA>5i1L>DlA>DFQ0lEy|O z$|I2#lefBDGY8qayQ89`BI9rAV$CkXi!@Uc*~jwKoZ>IRQVb5B1>x6hmR*U@2iRN& z)j6>p_y9MLwlfrns_*KI+Wu!X>(NcfNAT;Td}+phRIWrvxqdlMn>rblO;h;$MeRo- zD{I5OGq@qV5woJZW((KiQyrTIBem&wpiXiMH~K<`^^wmfkV!o1zU|u3BKk4Fh*@{d z>}Q~APR0QFfnTX+OLm|ZFkz{&bbV885%r)MZfUr16sSns$@=NX%JwzhitytLcTDKQ z1p0Q?$F1e8JSU&p>l3{*x{o-Bs_I&~X$0mycBa5HzQ3{#n;F|KB+ zNnFc43O|n$PRjOEvW_lWH`Y=-R3#}aj(quW{mQWEaLOW66BDP+9Ik>R6O!9K@XJ}>~8AkayfA|)=2(F z(9dO!^4_?1BqXP2VN++J3<>Frj+&!DYEdFQrt3#}nE0O2j!SVjjiN1xg12t-*sYl! z>JKT8Ri(w?DZ&Zkz<3yFCSTn`M4eSJu|l2jIzJFWInW-?#`(nO%doPrh};$_76Dv! z751CYbbV(BXt$AX)S3NaYiAY%b~J&S_$|z3lY9|#1N`+!<3hhh8`&KsSVlD7A?SPN z_tN|ClRcD$gtsKoJ_En~SBTrA!HN-=86vLPrg5L@#xN+9&md#_8|CGFAMmrjxLKrR z<-$Rv=ZR6LbW98p!^&%%&v%G4ip8=3fyqnCL+W5yJC1C4y&#;da!GFlr+<0Rz<)?~ zmGaOx6V$b>H}o?%YTz>k#zVe&@|VnoR->RYJ$M64rzM{B2OD3OA;OsB2%xSYMP9@v zDvp@mR6m9|Ky#oCxM3GoKMB&a9bDQHiun27U{bXz z0<%lygWn>+Dx8FPx^j4^=jvc>`w__M>RgO-}B)Pm(-RbA;cZ7WWRi!9p~ zJ`y1ExKRSt+NByv6?}X8N@nSo%ULDYOsIaH^)iTa!X8myo0`(iDntAdr~rt`_gpkUO%a31w_bWYr!~&Mq-V1_rTEC&hBlRLJA>9U{Jzz!@MmZ zq&NXkey6~-Kd}^*_|};T?>bn0^Yc}-+*-dGkMvNw_1#2Jn_{(infVz4v8#iY#wdB` zI3u5*C^u}eG3y=ELPrNaPBcH>LRYGqsh@oA(!E3Orat|oW&q@lTqz~`4g+^wiIs_N z^P|(tvI(W6BCb$lw(JO$7dMgolN}8Ut@~^V{dEy4pWE{*uiC_uAV~oOkJ4KL0E)$v z`AR@_oCP5eSdlRhsPgKFZo6rMsiv3W_jAX8lx&BbDYP~$q)^SemrJ`^B-dPX$E0)$NU7(@(2xQpT{D0^AfEZEoh@|{ zRST#MHv0%TDsokM&&Y-p-AcVfFP=*dkK|^H1OnT;&*c$=4JvQ8AH8}PeYN5He-_bH zq!AFIX(oH9KZ?_jRuAUL(FaU?)~37$b6b;PTn6xn#2254ykSXPdx5~=8%WYV6j04g z&+p0b$e(G4+gHul`Pg<%J9w}*Y0u$}85Bm9r=_qInCm>Aje39jTarQ^lTp)LTRWy7KE zM`hpD(x4@3mG~b&X^zt!o{L)ASp=2A5jCD{Nz5qps7fW#pY5$Ssx*QG?zTV}I{I+}d9A)Fa~!5htAzGiyo6n8S~c8aT5gm% zFttIAW+TJXJElFX7bU49=ETYwyUc$tMjVCX0n8k|wq`By%gQ0enmFxQ+r; z;>|uqKTy-^tLR{U*gVTeT2AA$Ss8(Bl>6#|cIlyPu6)$+7l@WmnRxHr*79d;98UrW^nmO)Se+mrgsXW>yJ;q2J)M<5u&nxR=N;5tB8m%+ zwm-;o`VNToQmMi^dY^Q0C zeq^MZ|MzFsU%V!LIMsWt0dQfr^ZidPHXo!HLNJfLL>oavxV=mwJN%@br`u0PfG=<) z*JAoxJWTl^D5I>gZ-10wP*Hw*QA_n65PjzIvEto-+wE^0Y>VtEy^-_S@Ri(F>s6~> zC!o!9q5eNi{R30~s=h7drr?k1Ey5!nKp9d^9X1SUdnXG4Ez)w`^9yu+<kB20A8J)!i#1HomD{;MAAHIQPJxfSsuZwRs7mg1$(k%OdHiXH*auP*JX?ir+jsVSTW20lQe zg}fS70fYMGCA!XIUE7=fXmU>hkYAoQ&}ZHyv-dJOE=Q0&+>2xDP2q{h)t!8mAE9v+ zc<;W_-QZQ)zJ5M$(Jq61Be@Y!E}TKz)`vfyqtWkGCI#ue%9p+bD(UDs_6n4$nzzU$ zWM08r@)GKQ#>|s)A2s*5H`46cRt+PBoS)77PE=wd0MCK!$J2H=u5!mK2?ejd&RoB{ zRC%HH4GR}Dhluo7)WFy;XaB791NTAuE{GC`dDsdESG@1=Sv+RH*@Mgw%)s7hk%eREgc+@eG zqCH%X|Nee(bJTKkdumvfQBf=N>*~I#{F&zkoX?(&Do)mdWR|E6Ek6K)cj{l0sc2q1 zTI~VJZ2n&4dO(=Jc8nqkhi-WuDjX>R4iFnR+tO(3Fws$_l*e7R*0M_^9^|P>&4L(7fUH!tPc{8N}1=}$kn!ndW;mti#2 zMg#6<=K=wa9qm@Db%c*=lBbf^%p>9!+#_rNtuypW`v8)Yz1i@+58QN_WXyU%iaUh< zglu8zGya$=1##1=3g8F^>2Lk(I_(xLz?5+BPE>4gjnGrrN{lv|@%BOf45 zo(8lkp=rDJ*QnSsI&%aM^Wm1xp5(uPC|$3Mm2GY& zS6L05SJJ!?PIi+!8{l!24R?qf+n4+oQ-kBRjU8U3-8{)LoddJY=}9KJ)Q|rW)?sVMTS`}tQ=a*SpQVzx;C;0y(FSSoJ*v#rPM{jr09nPOjOmjl;$lF!*$PXJya)1W_ zwkh_W<2-jHC=rG7UhH!Hrm1GYDNUbSX=?^>0s@#b3yN+V1L|Lj71-An7Q)-kjd$Pz zhvMH)a`7f!hMyUfI>`wt10DoHc$1!}manW3ZW>KKhH9Hy(-s1d-HkFH+z|x^OK42C z-URsa(xT~48uXlk^-M*(m?}P;c23F5gG}^IS>m5}*#Iu2E{@!3bZ;yg@jE_hQMW^F z!G|$6!=6(TDE7RgO- z4NIM{{9ZBKez2E7lAI@j5|2!XUEaVHLt1?QLi2|+k>ZYps~y4EO!2ZoH6iAg|5@Rz z3zFngB>cfs$6KJw=ampttf`$%`U04JG-9FXiS~r#Q!BGbz}zWzQm1Gl1&=Agr6XE&qkpOCj`~dGENw~mZk}LTQ|17PF#ImN6=EdNl9)ek77y zq@Rx@#HKzpHwWHs>*qMfe!`@BI%zQdDiT3``#~3I{{|KOtDtznF;b3hpiN7#;=O5fg9J6-*LKY8_J#+bCFCV<6Ca;j8!K!tNM9$H}A_SnzqD)eZ%xe#TzwS!1opP5{+h#&%{VLB%oat zbwI8)Y&WtLq=p2+t{x_qalr-~y=k%Rs}1*HgC*al4j;fzqE~*wiVVD3!>|BQOC=lv-+ma{0mRt*<1QhO1Rf`Q**ILr=rMk1BqhxNNE~sPt)Qn^Q zVwIz3Z&yM2xeCn)4|16&0a}5idDHjt;TC}R%7J?Y@K`o?kqaW1{-}$*MM7r1+!!XU zs(D35k!$U86jj61D%p42mBvfO$86uyD~i-97(?67y@}NW;NN^qj=bOER>R+HZ&@wj z=A7g4@$%qwBic9O>%K@}6pH}AyY61;7pxJ0hprk;kzX&u?fY+fiE%4;F*!DszPZ@R z1)irV;xh^nv@~uWQC>KF8RTwcQOwWzE;W*wBseYngRoU&T(SHx!ytO5hxh8{c|t5k zs(s6RxKbF~Vs@bV0TO3HK9Q~ylt*AgBTo1Ymm5WSPWzoQX5;1^VWnSCc$g`RnFn!a zi!Um4JsRACLru&b_7t^i4h;Pxx#t6UkX^d=!GumS$Jewxh*7tfx0$A`#Uk|j(Y*Ar zX~Zq8Jn0v5kehHRgKxmL3b0mCkF*@k0IbHIb#bX*1q$K6353Axo)p>mmt!MtUa*+Z~(o zMq5RO0GL_G3i4y_2c*neK(XEuDQojn-uwM4>y;`UN&JZR_tYld!dN`R1K8=qQGu43 z{QblN->+ar0SrFS+11g<`Z%@7M-sP8sERE(yiHemVamCJzA-=3?uFURJC=Y`+V6`C zZx-BtfA8rhJtRx_vmtw+q;LirYR-D^=g7RKFBVgmerG3&gBs@=5`@JRD8sV>WnGERIsmD}_65OG9iE80c`>{OOu z76JIq7(8hx&xd|;{d>5b)xo1~UXmsBbd=INH_e7pWWpjT~HQ-7QzmmG!Ah0U~nSXH+^c%|-zV&KMO>~L}+ynnMUw;`w&;&%^d20)V7xg!ORH`AXy;Rn1!FGXqz)`?PiQ#a7r4T2Kk1!b{zeYwPL5zN2(k=jC4$TYw8Qzamfvok%PEGP6JmzDAXb)% z>c3kXV-`OBbP{+p;PXp-5GjWf0Xo|x9#=`h54e&WzY&DY+NHCP{5+=_ z2o4_)`ji^o=PO%)TjRf_J%2?(<=U+#lLkHcTsu7{Hzn8JHoRrTxUtFq&^l6$^omO? zkeKNEkipL?1v*QJ9#Jip@0AAbu03_}Pwb>s&O=%YOd9%VuO=_uGm7plY zh@zAXcTa=pB4|L%-vU}3q@v>cXoE> z+P67>B0q~O$npES{FexF3tY&}eq22PSy-^oJWr+*SoZAo>bavhtv>#fYRCB+QU!ZM z94%<~{^y0Qp)s9ep_KGgA&l{|$Pq8wT;j{oQ&Eq@(FMQ;+OcDP4x#ctw?DpQ;tT@= z*!N?cLY2ajq_gmhTL!WJe##YvvBCFc=A7|E!n}+Ex+VYOP58-{%Y+_>*Oz4V-(|9`VE?$~lj767 zi}cEiWBK_AnA1UOP9aC-@=1rQn zE(%}YKX}iEGEt=TPvulboTg{H`#a1k+N^_C<9ywv{*7OzoUWfL_I~i$DAxsS_qm#X zLB7$ppBX3wdo%t zI2LL;(CNVRzkfvgfc;KWz`qCnZxGu4S&@HVgng^v_5V7N?jQacmnsdUB>DdPX)$@T z|D2OHrz!ql%zcA%JJeJZ|{mGcQhqY zf-i8VHH4Or_WoiQb5y?tbym#-N*#ek5?(O%hWuUJc+bDqmi~{mxoZbqTx!`{RerTF z5YE6RuHsGOno;4E+9*4fT^P|Fw!hx`Yvl)gvetu-n|H=`W$@R)UYwuq6G4*XN(|M= zwESI@i(1^VBP#qPO(SGht#P|u??sz+ks8;gRCfOSU^QnG#4?K0_J_Jc@ZnS|KN}wq z=u-cuUz2nsGyet6huS6X*1FQ}pV4sPdwV(~E6}opgpEx!Cy5I*e{Ks3Tq6z-??2z!r^i9U2W~zQmyYXiuo1P>)2xzfNQG1cfn4^r2m7=x{__-pIj<&kvx;srMU#O31q|=M#d~+w; zR9YxqqFNvrw8I9^ULFA(k$0N&OhO<*5Vwc9X`U}W=fLo@*THH&KwBKmf(& zT&tgrwbj|BG0SXnyx4h?XhcD~qg+)ijc_;0;?4_o(iPo`?(4anm@$=912}f67Ts-f z;>ch^p+spgDGIc=Sk_c`2;uhp#2&geF}!9Ze*41WyCx35*{S;ZNb<3dddpMTAT#ga zFq7B}KE9SzwgQ-_G^i5WNZ8v4`AeLB(FhV;$nV^a2~xt2U$a^PY7U2uS|XWq5(y zbf)rBIj^!@_Q8MIH9Utp2Jp+hyjd-3VaPcs(_bH|kuRvNc@Q#Mn(kfP`ktS227tf} zgw1}pvspetn%h$x**rd3^IrIUqRI21*PH~7vDM*B8S(S?2J%j7OvLhf+y4$-*9o)a zM5S=k-mTPv9{ z(s&}?iD$CyQm$~@^R`x=-@4JCXQ`_9p`T&iu|F*P-zd%L3; zw8Mgy{|a<7Vk$lL=0-wt9>bTZ_sGDWZxMNceLm&t&X|lDwGj^Z;kTeT_RROf!yqX3 zy4$FudnK=a^tICs*gz8tR?7GWw^j@2#r+H;s`_3`qPE)h_izdG1U@xwo}bfEV5_qW zxpktYg*IPpiId(O#_m=^q*YMy{Gbr#kKd{9*Hynvp2Dzj?eUPN7M=2g ziwpEC?+Rj1p*Op=sbLK+mq*6)3_iEYq4J;j# z0M*;Hl!ksn%T9qAoHxV-7QxkUb9*u#- zO-OQ=pVUt=&&AY4$|6!tP^Qv9XoT$v=U|e@49Z_Or3Dx_irOtg?Jn>gW#=1?z~ zmo`yT+P$}fIb2={@N39F+FM0YX-Q-`BnJ<6rB$>4Q1($Q47%%`Tub9L@y*26=P z&}6%3YK)G2ji;&N$N6qwxf@X(YLs0fYKQjIjaZ2?!VdkG^Rm*?Qg9G{!OIPl9=NBw zCbDetB$B+jL`{Q0q#mkC8262rWo=rfZzOG4IfWh2&>}^V66=&m&kR8bh0am%fVZsl z_FiCFAvaXAW1SG|d=rA)3daprOvp8t7wsqFg=};5d5Fj+rbnF{SW7*mq9^>J=-wD6~*I%2e~T?oGbyx+c?iWd^Qf*h(IhsbZsYpbH#nmyId9{ zc{xf`o?3&4B|MH-gM9KU&L3JEY6^5xeRv$augeP-vms9kdFxe5l6%INe*0 zRVHEqAKX)Xp^pCsO7v-J9oHM>wtC9#ywVl;TD0x;I}~rc_(2`l+s&1ih(?`!pEJJC zhklK{%xBp{MI3}TzI_EN>tDVj@Iu=tPJ?$EODl|nuD1-HsbpF7Wrnu8oiEIr=c+MA zPuZ?r?#AQ`7<&4eeT14lMRoE^TGRV#<&pz!Ytz2@l=GPiqjQPnN@55O`z0i8CDVB# zKsFX~_0r;Zr2Sfun#tpFXgS3uSlup%pQr2YLh^=kPffxa8;Y|1t^6k+MnTri%ho8` zgZLRyKndDC3=l$uH%K*0`@}XGK7S(AA;LdtBC_^p`;|8zer-Rk^JSf>g14d|ZE5s> zEZ?b0#I_jlf^L^ADAit^)LEwjH<X`p(~xYz5-X# z=O|#jWj1ckqnUo;WRf6F%WpoIaaz_X-}R^{9*ZicPz41@>_ghTZqLuZ%tZ)D zRPhv(Y5e5TwMZz(!u|SRT89Xe=|p0z^VyA%N?DEXfd~)5%@wo7!LnKno*!|`g!(r! z(^`M(^%A8jm~+W}lkzi9P(|v&`N8S^5*7_BebAza#{ z2TXK4Qel~fj{9JRc--PUMD;nO)#R#!@_o>M+d8iPzAg=V5PFgmIB-#4BBS3}bb2Sx zE9PV5Y>j7DXe5ts@ZA8$y%`#TYX1Q~*3dX5NO**8k5?l?z<NnUpEj3YSh&SZ zbo)qif;IDV?b@Sj9b7ij=7Dam2Zk%O13g-fC6eQ7F!;()Sp>MqQz3wP8B2eq-?{&U zMrfV#+c%O1SjL|qquM6X96Z-(8E!Cal8ulq1))3b{UvxKmJcWWLfn@$f-c%HU^sK( zF~L9o(xleo>xkx@pK>Jjw|7pz>UiwxlrFqTxwL6{m2BRlBeU>Ig2Pd+mk#(A3r_K& z+V)&az-h^!$t6E}619X?7D!dAy)qO6rUntZEJoMN9Cc>Gyy#k2lor;_l)lkQUoc-k z@0X+dsbM}edfbY7$8v_is3LxckhV+j=4{&2Hvg3;cTUqlj^{b}pGFLTj)WLX^B;o{ zF-X63=yepk2{!NKMbpH-ofp6EQ(Dq6SSX+5-S>^~3{)U>_PEty_PC9v8Seq4aDY2~ zN%ZI!>rt2&`2OQVPvW}%o1=B#!w#PpwMJo#z2I?OIFG;!w!Zfv;>BH$p13y{GWUFw zsj1WlO5&9s9y}JjH~Sm`Isal4R%N-%-c*ANuZT&^DrApwX0OwJ9R21Eh?ymgAA2iZ z1Tl}Pf3D|~PRn4@*MQ9p=UwF&aaAiFK}O}=wA>{^*xg&-Lr%|GD9g_DW=)JpeV-y) zZmD11rJE)*!A&h^Fl~H$!tQSeQ`bWJtO1?bM5nToq^ZU^KZcUFtyPmVKBW&-_v&_Ccs~5i)q(6sZDpZ2Xh}X&L^ap=p zF_p0B?a122`q-1Y`+ffUDxxYpx9^RA3SShUHMRI2L@H;irH^Oo&+>0=c9ZUP@ax_y zap&+V0(CqHdh%qvqb;(Rkm^S_8k26nmxL@_pIIMt^heT$?@C=Q5lH zt9DQ652zr9WOLsQb?w zQu$}KgP+s`B~(6K`OZF*`&SPqOU93G1c#b zmjSH}MBK{O*_5ri*BSKt$-_Jcml@qjp#=)8m`^|#8x*d=<2OYIPW?(+?l90R^*UD` zQMk!$0s#r~hOAsaL^HNMrJOX=tWq7(?5V~TlK+N?IO^?GNah2O`dU)%;AfV2xz*$k z@hrnOlJf>1wbf*W2Y#jBq%T=uYcM77|3K1{7T6j|^bKv_z8FZ$yutK)2L3}@+rq|+ z7D4=I9TY;{bO;I0tSC^Lddxc(X?V7!{8~t;_Qgf;wUdZ)e5c2uFB}9x#@6%9v@X}ihpfw1Mo6kKMe9{-Kj{NmUH}gb+hyy zpXx4Q!%lB2z4jts>T{Io{EOp;KNF`<#=CxKx8JWn+{52UXjke;s&`B!f747n$rj28 z@LH#_-pyLrcd%6w;E>W)F9L8M%GL=wVU%e2l=r&*xXn;FsGS_NnQDhfX?D4tpo>>V zHzaF?YJZX3yO_RJgT&rx_HrNmcIpLpXC=UQN;cV)$Mimc*Mrj8C}7X0c#UbQr@IeZ zz9w134%L|M0Rgb+b92+FTwQY!wdU$p+DO8H!#b*T(bsLVN1E_$po$mA;AcCfwf9tq zW4v0;FGOa^=HPwyu6kb?Q=c-*8Jc}d_mT^xZ0;P!9Ow3cPkn_o?p3iV0V*y~Q%-7W z?Wb*qth9ZFz|~)vQg^pdP^%mZK_1_Ym-PvB>pL)v`0+O$CIh|IQWofV9s2L9u$=c^ zMkNBTq-Tr6l@nf{l%R&6v`tk4gTLmjR)V!Nydip%H`p?*Fmg^a*MT#2LCr6N=f%0i z6&@y!-FhoTAnSz4Os6<`oH}yGks`H&w#}2C@JQDnX}rDhCwkdE(GoxTy!h(I-$^C5 zD9B&DH(#oReJ#~)-zttylhN-sF@2muevlc1sf_eih0^VhiPKKMoJVVtopma85HR7` z!a%3*lJIF-m;@4IeHDzP|0M7Csxc&JeocS9BPV_gY8hztoXY4MiPiT=8M}gT$=*;( zyfiuHgv-?96b-XTY5iG~`icDQi{=~TwWuaO+Du~I*M%wQ64Uzw)Lx>);tkfBZ(E1zN#&wI3*3aLq^ zWsr^i@@rp%mz{U#8a=sh&z~+sH-V00rHIR3|7upm(3L^(q>w9!jg%G+M4R#(#Im1V{M_O`CvOYBg9-*9QmFZ-SJ zr*dWXLa+W{=4JYh{x@!2+LPyJt9rYsJYs;d8n!d_*LCY>0kS-Ddxw9^-?v3mYQ)a@ zeX3Ux;)b2=lvU#V+VY;+T3xbc2tuXF?DW%4%tBP|=zz+@ySxHPtY)x-C$;E<+}q)W zNbT_4ldC%_;GhO3++H*L<2dyex5S!wX9Zqd5S7+wlQWKGC^KlabbL1XVTp$f-Tk7v zH@J;cmK{r+Ra$&P6aS}!lbQPyhu7ZI;f(u*22s}T72(i?yCGv8mU&mC$MN$gc3*I_ z?s|id-m9ss_hjjDlX5qdW!3(Q?MUX(?O=Zv&8p*aiB1E{#s9#BYZT4d8x1{(z4RG*Aqrc~BCHdsP2)*6#HKY^yII>RLEz(XpHm z;JGb|NH%%x#pU;5etmxtZ@#zoEpw3U@5hwe-6sJl2wMxdzqoysFVzcWI!Ob~X&3gu zw$p(qWuI4jFAhpkO`w`JUz;J0iS<+mbh!jsCskRy)B2Gk7baTp^A9bLyxjEjN?DK` z_{#=`mb#rTRW{Kg`mJ}?wM4i8)$OL=-A}Fb#j$-pk#7RB+^0t*5jUeGO4JrgB~NKC z;9OlFi|2Pv7=8qCzcLw*zN2?YndyL7vTp@n$P&nVe=OyQ5SB|!riTbt>E2c z8f8R2tM`@b_08jxifZ|hzg`WBv%gJKZtekFoDM~@Cl^<^^0&9$L@=F7C-CqHpZ-o5 z7?&0k`1Rp5DEa>3Q9~=Qew&!a)aFU?k@boEgEB7yHkRazb|0O(>V@x{?r42Rcv)8| zxEdF(yxKDLG9f$g1XnRArT4%vuf{K%r8Tu4^v6Ic^fh_VS?+V-1*0eCL3J6I8pWH7 zTF{wvWVWMjhAS)BF~6nb7MCqpPb-gCEbG0W&Y!rf3#FvwD70oR6UC}+7i(y<)eWA| z3-Y>EvP=JwC9_C{R^g7ds2p}Nhl1ES`BL?1R{FQIK8J~UzY3(K8R+suaV5#~jiVl$ zK)#^Co_KmulXTNFrt=@Qfzb##AbW=BR^{{Y=UiW}|9(-E#a)rMv6^yx*mdX!iXX)u zEn>+)*>Al{dA#UFN|b7l)E`Ks&Ji-XoNOU-5TLX|NsC4gk~@nPU}mZ}Kas!hHKpZc zbkgsvHz#S_KEPf1l&@?g+nCrM} zhUh%XZm6X5Rzt~V*5i54aZr|g-=bj+INpz|vh8epNTm_jqh^}Uy#A&q?*oz3qh$y7 z2c?a5p&TFjE`0SSRFy+3TTUzKJ#`;EWQq1kLIgP_)4}hB$kH!vXnoG<%L7LbR^@U_ zUk_KQ1&gd6L*A$&XCBi#^d2%i^1Tdn=WmAUjE8AN02kiqkagk`^D2@UE>n3)cn|Qb z_s_Glm6#mda|;ye@VP8De^v66zGg}ebV;0HA^tW$Xv}AZmXmM1s!|N0?Y&-RI=3$+ ziRv*fu}!RlTLTW0miQ?Umno5}%9u@hUBS&lEp~)G3Rt8}6N{E|PXCj2oq0HfAfD!f ze%g&3GE#na+j`1ffx@C zsc|CbDHk;z+VkZe)nKiT(5xs{%CE`N$4Ua5uqF}zJMuj-zCP~<`;v~A5)qp1_x0I>4F+%b5v6li% zeKD2_`G8KV0USu)eXT8=!yKq228mKcWb@N=Qao&ey{dZ*$m1`U($I6`OE*xJU-}p& zf*cP@)pjlr?x#dbw%_5AjO611tY&&Nt{8lQ^X!UIXh{dnpCJ=8c#dIvT6}B_*r-*a zN?|#YUjo&X&Eiy*a!b0WcO{?2)i*GHT2Gdn%$N}lDP_AesGYmu13(Y`j9SS{ZX_;H zRgRj^qm$V5rmg}^aQ?-*yqWnukxxJQi(%Lxyh3p!1UI8m#w(|D2b&C%!KT-Q*}&AB z9=Rxt?x;%a2!9%@OXWzjAu;;9X;xxi@Uqv8po=N$!UgApWzp{I5|SlKWpZQ{6jrT(2ww8U;00OoY;ZS_%DL#sSPYw z5va}e5&&;E#ljv&J7%+k_Pz4{k=HkV!Mn$St08YQ5B9WioK5^@x^l34wL0{7=mXBf z-$LqYn^sE2-jDxG3>R%r^$z8%9OfeE7SqTxT9X?JYBg+}gZ%L`2WVexpE@bDPld#s za}lhSQXvr-g&}jSzS32GNAUDt_+7crizqoy-|pPFtjXo}e3|k0i^@{uK1NO}KmO=) zn@;WfBZ@k`{{lMxW(kHL zpyDE_p>d!t@}stSI=vwoCt*>9GLO@B7ozp|*`*IQVV{27nJC!)9CY6-e#l3lKN+6W z@Oj<+AG-kQFPW8PPJHon^I#G?-kGoAMTRD3Fob`vxZ%oO+q`{sSn_scK-9tg8FTB} zcjd6`XU1PXS>n<`WY?mm^8`Oj0w*q$d8{#c$Zbid$Y7>TX`Tt~_sNQR*%ql%A(vXz z8@v0Ba#iRTa}Op0in;km%6MP8@1tg*MDjhO4}Q{ai*6P2;7jCJYx_7LV*;4GGAL{! zPNIhD91~p#?H`+tewLbS%=142kx6`f#Q91nStr^zqzNCj#iyNaDweaZq?dtJvDU5S7Z_^bb8 z5u+kOHa8;clT(@FN%QFgt+a)dgrzCmCn=uBPyC3@x;{I&)El?A5q4?}K1_;4IPx{F@~wS0wa9ntf2xl<-l%>lZs@~3Vm6^dZV9pe-4z)}eDs!x z8QGAG8%#(3n^I5KRQ@*b7TaP_Fll$BzF-WvBq;~%~1#xCGe zxk}HRc(Oo4RxzJKM-tHr$`#j0Sg3_YjLB%MTs+3teqo|Y%g$#m=+bfL-mA-1kszU& z*IQqr$z~SuUEoigdKe|3@tWcWf5;aCyOeZuS~n@%?=5o5+>y`Q-B22*+~ya|lR?QU zAbDjSCERNl+HaqPz%Cffy-^i-wLvh5bRH`K*X>&dx-0DGG@?@RuQB-6d6I(m8L50Kr$km%ySt{(XQPM|x`G z7-%_l3KKv48!^E#3`;vARM`sOf5USB@NkW`_b_Jew>$pz*4}|iA^Vj-f9JrXv1IrZ z*C23oX1i~0I3-k~CLV1s)3l$o1GxsZFGW=wE@>HuF?0p`!IR0E95J1Kse^rtld)|j zrZ%R~&E?oxrl8f$*V&dcSvT2vDZsfz%)+Q3Jmwk{S||TT?b>VEO0-(2$UxLis$b7R zq4-TkV!TM^zYj@f#0S~Ba@)9n4lCSb4H8Y#^pixDssJhJgSB6cfvVoI)uyl4H__Ds z6Zi$Evr}`r?;51NsA8Q~E=eT8nIK?G+f`3w1?`6m~cv1PVw*Ku;Eb>CdD46&Me{e*lrdxgLDvH7LNclCTa8nM}63@Amv~o z_~!3+L+f(>phE=8TC1K3=4x2{(#it_GmNipbu~1JKsl-zEibD5zW|hmf-mAijbkqJ z88)2puxr)CiL)(Nml-<3W}*Qfoc$>+*m~G2(vljBkbnRi^FnM2AanUW7Z({*?taa2a}47#V-rHLvG^4B zY!l|JxwOC3H@_#bz~mg;;ESIR&(Ou3ly?5xX1!6#qnyZTGj`t8-qy`@#;c^Vyw+pd zMoO&LGBGDo7tKwz2itH-o&vz_CnNAKR#9tHtj}*lr+zA>{D_)0w`ds&Q>EHo(!%5bg3U2%A*vQ3A zYWa!K#-~909o#WbQsEEJUyI0F|IgU$JQw|i{7QAjA5Q2^8r}LVL*14iDtA6#5JREV zyey%IYpyeH85AsV^n6TfEg$N4h-F|!RyCMTbDOm-<1lD?p(zy*EnD{)jV?xZvu(#@ zIHx+ov?x6>0JDasUkIa7H2#Nl+ozBV@a{xH0%B5t;*Wh+Y*YVRPVcixc~ z2M=u=B-2GLdLQQ}DLdy6^DVqYUy9R|j9Bd4jV;GE2Gl4b6_OP0^X6U^aMaQ(1bhnu z&05hNVT3DDm^`bD3G9U!PRyNIHml_xAFLO6RS(b`$o#wGsZ7k-Oo^}Ys!NP=Nl&KH zr#o^q$gUrc-;$K+1jDUvHy04x&I@aQs7^CD_UbRm3Shp*R|hj#OC@lzUE=_UkamjvR!Q%Rn zhL{!?%xQ8j{`iH9Wq>4t5BP)5AB7j-0gqbW79c;>j}Q0|eN(_xHSbq_!Bu^+TPKu0 zhx3I$QB>iO%LMyo!hW5m<9-dT)K$%{+_e6}l;z+1VDvP->z7{@0g?6O`Q}&4sm&Qi z@?%;%e;PJHDpdFj!2}GnVp5Qru3BikpqA;Mshbr0MGM?PI;M zRFt=?mh6w}rYd9Cmkl1!soh(h^TU_=o(P|{k%r#Sj1Q=K0ReQBa*SxPf*vmV757w{ z%VXBcY956S)qT5@P6pyhia{yCv(Jt(R_*xeoYWmfb#qxgW>dQWFPb~)6rS5g8=_9Y z7NRwMMvYqa=1)1yv3mYptlU;ir}Y=o7LG1}dyd*nG}zscCX&pmO{lF1;^Mt(&7wR<>BDhjPt52`4D)bly?a;Da!Q53Gh!IesGqYBv1n=WsRnyW64MY%iCtED zL)*@(yDsmG1agozLjbR^=TlIDU~H&P@ZEaB5>Edu#cENZR9>Jj_8-&F5ZXF@`X0bif6=cE;OaUKLc8!5YDCmp-)x4X>ML ztX~4>nVEf6qJe$xkg;p><~`M|i;T}ABR*v*V%U!X8=!vt$km3je`Kl})yN!bh! z7do7q(vT6v?Ev?Gyr}?RK*EE^t`ODO%ULxAF>Y(#0Z!-%ZoRhLk@T@ig&P*9y$2o_ zAyK840i-k^E$RZkKHoFTn_;pN;ERV8`UFjVcK3Dw@>YA$0LkoTuJ2O$U*YJP1#uCkgYxN%rT$T0q2Av+u>3EUD)+#4SCfNfKB*6 zQtNR#6zKsgNz}xFuRvr(qELcot4ijF|8Cdj2O-~j-BaZe43OT)+qG&0qEl4oW}T`qr((X6EpUVj1psT+L5z(0MFc+j)rY|Y8}>g( zlH;Y1x<8vL1rxcHS~gR8H|5$VGQ^R4~zD33?iLrfL?swGe!syS}CjgPe$T;f6Oxw z^y*O$if^|zU#kUH8=C*z9<@ z-6J|M$9BUQA@cA<4)z+W@A6v7;QXkgVU&N9PdZ$gAu$yMM2(bHu3G?%sJ~8&z9{n$ z2={U>5FbI@XVPc;uacv5Wh0Ft-V@8xXx$JETK^_DN^`MH(;$D3Oj;h>hz>pi2@<44 zqJ|&A-VH8k|*U6uz zGbBZ#u+6Z{<;^4cQA5Vm7Vgb)e;kE7Pst})0odIEvP=B69mV?&-^$E^X}l)qcJ$&B zVJ&Vwkt5^*4Q%kv=uTt6b{VS4EZeX)E^^zLN!am~p>VTT1Zm8rg)sE z#;5<;It@E4{`i&%c0T);E1t2WQvh6VGQO1x`8U!;nQf){m*haGDRi$LZz0->>EUp@ zDSg{?yj8&0a${Cw=K!bb5^e8sAVmMYpK`U8+89Ee^QZ4_0D|mG0>2sCWGg@aK}X0w z=LVVokImd3d}Hs03kJxSy6ni%i89t%OXKuCI$^FBj;|e~*Mn}eA-5{%lnU!s`j`hT zDqM!YOiTCXd`M?Pc|>`W63>J%3L4#s+N`=)3%3W^zEtvOk>q zO`g6&siirb}e!teS0p=B}b!}l&zthbMjBYN6I@dQ`+l8 zk8G`C-Sye?cGW?8<{^#h5F6CXp5&jGFynH)o*&>7xEpHto3Qn{86lviBP2g!SzCLWfCqO$Tiz zCjJTOKj-5>`-0RCI-FV?;*tb0Sd(Af&2V$#J0#K%`$ji#Eun7ueL~Q?llYIp`=%kp z9FyIh&COT0+Cp2y2~{MZXMeTU?BVxeDE=)cc9)zb>1-J#$tLH!EMyxRdNW4 z*!kfXs^-Lf@I!7wTJ^x^;Pk_3bqWvl{64?HdKG@CHF)HKiB<>w(X3|x*oGEu4()Iu zv$rQ40OTh&kf3c@t+8$Y%yi!klw8tMN_qGBlO{~$dpmW*YUrG5%IpIbe8#SY4){(M z*OIyBHy{|yemw*S%kL#%BK9(GTqkATkQNx-@m;pkZ@g7Qdh6Si>{#T6s89Y?PNcbp zw-A(~DYL$Af`86RDs9XcbYBG`41YA3*c1oQKlb25NTa9!phO})tJ_0tYAP)<8B*7$~8tbl>9AJXEHKhYMHe7b( zrI`4w9hpHgnzk^G-*sl|>D&=!d?PXoQ3#@C#^U`};d=rHHOvW<639G70qec4cZT5jjw%|^p|4rpOC?aM*Us7RT)&e)`N!0nIK5{SWS zcU-#IWHKZDm~OA3x_B~VW%~ivC&_-3n;JB>SGQbz;)@7?@oPK%^rmvvQ_b8C)0wDZ z6LlNx`4mk;n|w_mSrQ!B(32%@8IGgl|ng^8o%G*1Mdnlfy3zp+U0BXY(F z7}iF$OZ9KY&7QS%Nul;PTsgdXt-{=-u15lW(v=SQMAUJ8cX^_`OkEclG~!@sCE$7? z(fm##YxbLg5IP(l&@e4()z^j`PJI^i8wk+2agOzTzg`u0$(1RXP_WJISd7vgKJR&w zcpN3~IQW?mHy#cPRBegrHdI;tQSQk~T()xztOvUWruce&!XU*kD~+x7-H)9X0bl82 zolpIt{9T-naa7hNZ|T;ltbYTTyPmJipbB^1`TdPr@7G18hYDccJb#U7dERzz#K~DW zJ68~+dG|y0uR`Pldli$D5M^nY6aT_RK-C+btrk-5JD)aqtV;hB?>7HD>&eifjGn?c z>k~P-2*F}xq?!|1y6;>1akd31q}t6D>D^nEU^h}oVu@RMRmJuj%c29F2=P@+;@XX56II!jEn`!e^>IhV56*Te(im~S z4a2JfL^U=1ZWQ4+$7DC1f4)G?D<3@Za5Am<@(wg5GQ%pYLv?IxbXTKd(6}h5U$!u0 zwC2n^k;Gr%FEfTSX15wmKKgt<)N^UhZ?3`xP6diBc zfUUyy#aS4KmIUNqh_(i=IBA*fD4ohr^*?sK8Yle5CPyHvd`j+4!wnJJqc%(22r13J zxg?+ZY6SGd;D?6=tmSIOtuxGgSEX#m?D{JF-UBzW>Y>9iY*WZi zyh3o}^$PmFkcRJfdwV51Nexf;>DY7R89$_Pj)gRX=!WBa42uJvp6N%GIsB8LwNJxp zk*6WFQAin`)U&FAHB1?awc3s__Zs>CFjudlh4wylnyPs z;Ot=I7@mneJx=%%-NQV9-q790ib8TwFF@NAW5fqy@|IH_bN-C_tnEY6H&7-lMI~;@ zS>n9rIR)66ZOUA0Q03v6^M9Im;AfE0VJ{{coKo{cuHnps^2Y6OWqT-1_8}i+W_mxy zqbyoC~Xu^3M5`0FU!Dv6vvw2Pv6Jvc?N2D zg$#qc`>!PwXWahCMN?0fUe|u|BV+){(<@Rc=&7E5SHETq0s(`rf9NPbmJl=}x!)}iS=&P7&jJzuCW)o_|ZVZ7A}vOlQi5Eke%VJnIR8YusF+}+R7%bj5V5&tITWlzv$f2wSi-V8bTMS(4< zqp3mYxxZ}VjjDb*s$)Q*o3){2u2Zh0F15x`>%CV`DQlSS%a{IN>HpkV#ep-tX44%5 zq@tju!FRwQd7q%%E0+>;jfAsCb9=cxSv8f$CuV^L+mP{9DLiAoLzIwYHZuxX}@~2P53kL#vw7sA&o1?JlJAPe#Ei`WyB_{yT^bONz*4Ua=!k?TiI1zVMqQ1^^fJd9UPsE=(0LiDHJSS`2w zsUOn$^=kP~*JSRyAaT3v`b?L6Si1!C03q9Mdlug3$Hc7kYv&-l*xn88o_u=9-qKdp zQp!@CZp;RHh^2-QdGOD?IZK#6_1c?IvM@Hddc(J=_lr8$w=a z5X};wfDz7@<}SbbOppn+hgxNV z&h|f!-@P|w{UY#77PnB0sxiK|J~aTCs+qOTQq&joHUD>~U2CaK8UXx7F*j{@BT#Mlb)F{?k;WHu`_9=tngs0uRS_-e`e1_uXeK z>rUeK*~x2$roo=KDup+-4hOLl9MN|0QD8$~<|eYuKX?a)4d1iq!E34(<=84CXHq$(c*&|IYD2ZHJF$FNYwoxCi9uym1X zS7@5PY$JsEN6`~?y>Cv1#4fksVaNS4J-uaPuQ5?Tv*Vt6a>_E-*bp3mj6>$@yh<_3 zgP;^^{F4{%(YkqJm?2`1Mbq-H3ykQ8$?8y(;LN*;@oM!AK6I$lL$PQa|0;|KW_K+K zK$JP8SJ(Ht{RS;P2mz&~Tj`ML)U#{=wTR^;C zB>x@8w_sHi4KqZye3rTN4ZjjYxHIL_k?QufsB3pBm4sB99I?hbm8vK0et0FzW2Sy9 z54tViRT)`r^MdDRAtN#tpJ%}SMqda(yA(--Fw}`oRi!UghPv;M`OV&*VwOH8eG0Ti zik4Cyv^!V`IZ3TI)3!}mQkM>mJSKZRQrlKAl+~vf=6U(cx_sD9li$vZMd3HxO*hAK z|3WJ`w7y;nyj}yglU(|vI9qqP^r9XXAP9L4U$?Z~Qn9xJP3Z?F_tB43BlhfL@716Q>J7z`?j8`Xa&=ot?YjXA|RzK2q|CCfW;b!>11rdMOZBM>IMR0d^@fMn(Zjy z%9%4yMXMJrWS zl*Vi?Zm^&G<2}{Vpeo2;s4_}|z_&U__nb0L0H(aU?vC%1DaF2(Yvbkc5E@2y^&#>D zJ-<&>AUehS$xh&hZAZS6-Q$cwHo*xbPY_09L!OI!z*gByv6xcg4`F^1@9`Bb;$gPz zZGQluy&u9N)b9z{S&Qan0==dAnvyo`d5v!+sC{MmfOK~d-KR65Xa z(AAQiTMx4X_LkHDeG;v3`?b+&Sh&Jm!FR;k6{%!f=4}9F#|WK1gpZ@j9?!GL0E?xl zoexv{O3RAPTQ`=_0>@jzbN6>bLsRRITOAKU$3(JxahF)H3!Pf}dOYV#RR*N)*((;z zxp1{VbtJM6-#b0Ez5X}xOEG{u>(!NkT3A43OR8w92|PVJD49)xOsP-ESo{t@6sn8u zz@pplmS!v#7_5QF*LsKi?a8?oxJyK~Syw}gG^fzp?3Pb9jjU|*Z^t#&wZa-m7^cGRaByDGh2Z<`6!5L&^C$x2?m#ojCx;)L4@c@P z7Y8BE*tPxm{hMIb;_RTS%EU&#dL~=i*g_ztew5TC#z{)M5bnPpn4UxC$T6(_uqUZT zd+d<04=KgheX@hl1j)5`0}xTJFI8h%ODo(lZM$)zK{*@uRJWQ{Fne;U7sz2j+V)Y$ z|7qf`Y{y=uy(U)g21itj}gW8>Vg z7d2)2(;^#v#;1aBQCyv-p4m#4v9Bon-`(>2y7X8y6ofC;5&NWlCd=-GYH+8~F`Ix0 z3F+!ZnG+CSlpJAgEO;sI>FRWY+QV)&JM|Uxlfjr9eWI^Gx6dS_PJKN1^8#{`^U6Nz z?L+D5hdkfGvU+cyIQ` zhMV63x4pZqD*Ns4MSupZ>F@46DHFG}fBiK3GU{SRLF_s;80q$W^0HL@djOR^nYOhxYkpW?Ln9~bhxxZYkH$9StDxZq$=;LxtO?e{c5iQUt5(vB;(6Ke0L?MbsxxUm zuwU`Q1d4mwLX3FZHsqZ-?$oXpv)CK&p9OA_gylf!OwCC{8Ni1H4R~%UHzBK=@%JtZ zQxa|?dXyQ;7ja$OLuaf8TKK#iV?Sy-Ujwu(iW|0CrvX>*xIrsvc;rx9CSfdI1~?k&?j@!zdc};*}po;gRfQhrwnu5S$bIYMjjY0V4|@w` zOc!zWMVX%b8PS*f4C&b2^6D{al4Qkz{Mc~V)wRb~X;;hs*l2hb!TDY*n6h&V3wVhP zs}HDIVT@?qUaPBbzhH&T{kZSOt~*H&2pNZoAk}7e0Zp~u(8aaA@^C975fd=#n7Ff= zL*?m;)O+HwkQTqi{Vi|r#4*CwlqJe(5Qt%hxz)ZT@%9C(l$Xf={Vod$P+isXQO)Rt%M0CYB8RyCc~8f}WwOBYhuU zzNw>Ix*C00PK@+ooXIq@*4n(=EOewp*H45+9Na_I7s>arpACA)=7Z}T6osiK#dApD zBBO%>bh%nlKEKz5j<@@aeN>!sw^n^$V0i4?3t|0YV@)HL2?emWY0Yd!t>#R{LrnZ) zO)=YV*_UV2(I0m@-!2rhEdmWnJM@oP{mhTKb68{;4m9c4z80mTj5LvylpNU{5|-JQ ze~0^-`ivqvy|r-p-0B+z(;@vFRYC9aF@!lcLn(4>M$KUTMMQvy~rv8g9NzNX@ySqNz;-RF0FuTpz;xq%Q& zec=n7T^F{tJBe5B_wGhttXe6N0H^gtxCy-Y-|cqo*`KdxvzC#d#q^&=fb=m#Eb9id z@l6d$5Q~o8r}_0*GshVVbAPVH&)iw~0*(!&^C|IPxM;RmTqK7ElhOX&jf)j9w9|CVL!>-KYL^BtbMxBUNIvusy7ZVJy80tC1hA^FcEex|s-wDx?DT>1$qkzaP> z1XEvdtC=E#h#CmAc1|HQdAR7ZF0-k&cBrdU;N_IcXM)n2QHQGycZKWI({Z>}hVjA4xbZ1{*EFRP@yngO?(mFj~aQM)K2d97Yi#~h$pMS(a+V!Em_Z}6j zSydfeah?tvS*pR+Rm(p7iP#X%^?3!huSn#rvs4|>@9;@Rw1pmHKJnv|pzk|)hy*%} z+c(C5a-GN3N{QM#vcR;`#hq7c=(hU0ACX;Xln-)s2LhtBbqjXnWt;55It!~MM>7+Q zcTmrE0AL>hZ1*V{%eRp!l<)Z5@nlEb(K2)1&G^rqCi7p48M$E8?mOUoIS$2GV@^5d zS5 z&jaA~K|poM0(q`Ydb~ititqqWo3?7KD0{M_@Wtcb>+KFw-hGw+*5I8u$IisW%5jU) z(GIWfvA-(Lm{}n3d6dD4_4Vq9@13ePmh6TKnVcsM6&!f0`ZsxYuM%Z)^oIy_ux+&* zsCTqXmOVKD*7Qh%S$S(pH~9gOw>7NZBP!YlSp3LbQ$;HM$gB-6@1{bv78?be2W->D z^WHvlnEcP8NG|2Zr1m(2@J45vyN$%kWdv_r0_0IQ@cz`x0@Y{z`(bhJsZEk@7#mc@ z5WMp(MKvE?JmU3d@B#Dj1rUx$vJ$Eo`2~x;b>d0?EHgUsk;NZ(6?oU0_?no!NDa@^ zFEbgy9Oaxcb~)u}c7`m=%$yJMML&ASy`Ur5GUDi*jX>WB&g7w;c^^3Fr?9@tPqZoE|4%KxVP&j!UYKB;a^N4D}UCAt* zL{!yw5`-O)5Y@rQ?OUWol0P7ZGbu5;XA8nE|0q?-V5c3H-^BbiG#1kk>%hHi;p{Rm z)+&$ZmA^IseWkyCkUZqkSe*z=MjO)lfT_#LkCUNaO_X=)bLpLuI*eoBsytcXcfIUz z+4`D9>LS0nFMr~rJ!3wIcP_z=KQkbIHLLTQWL@ZzHK2nhc9F4T^+Y< zWL-~g1-S6Pou&|9cTB+==WuabU>n^jJ*INXPT^CuAWXD1w$%q(DBt|K*qt~?DSQ0P z83DZ^z}*oVWxfN^tSltJ1q9)?DGN+`06wY~?*EC>5EBm_Jocs`loNy>rc}OoLH>fx zIky`g5a;In>O7MSxhE1OK|4rkwV`>qFHazte-5;puadW;^`pgPdIjB5d|JPGqXQy# z&%n}i+?cVS((Ds66n^$=tM5A1xCO#FW|tYuZf`C`e!J_F$}GF=^2BUQmq_88*Uz^} zxiNBLo=o~5yc$cYE7>J;j)D>Q&w?V?8#mS{GNgZY3qff()=vVlzy+@G58$TC?3ZYR zZww3Y@b6U**UO-S*rx{)IFh^7ww(-Fy3{?3re~tbZ`Y8=<9sU3TQm|8)tUM7fj$r9 z2GXQkaO>ZFv~Q0hIcSH8uhe75Sn_UFsEl(#v-?SN@lr+E%c=Q0T8vEO^7$Ldcqa?=UWg8CazOWC~hq?lL$MnnD1+($*?{Om1GhDMWC{;23X z;!NZ8*!I_3Eg3$m_*Yy3D~cpqxAn=J2Fr{RNPe{S?S|D#)04N%ls;c;*2X%gNyxGSETH^W5qC3*(c!zCZWo3Ddfay#I@9$r+OIJ<~W)uA4L|VUPRJ5Mq-BPMr{4tjx>MGA+?!SM#y!CrWnVheN-*ufJwxr;H7Ww&B(mD zj1$f@_BYCB@~Imx`fE|DS#L;=L||Lf@(qN`3gn~JPw4r^C>!Flg0#=QgA0M9O~;+m z=&jOa!(m*$Ice$LY6nk`-MM%uwD>+q;eN2zeGRSZXw z5dk?RuX&qM^$vcxs?=%^@Fl^R>lF%bV0p*RI7tgGMm^{4_8BDI*80@HT;=)TG9ZKr za4HlY)9p9})WXH{omlfAIztD1g30b?al?G(#wHjU9<6PqdpSAb56M*?a~2;J`N(e5 zy`eD}NNhxMnDFTtf za4>lhRcg$m;=g|IOB4LO2Er&Vn*cy)89E|;O$V|MJT6&=*!R-9qFfcb#)h4*3KG@Q zL>MzTe4E|BT*w-lhQgPLPu>rWxzP(0+6tksn)t^iyJ87{B^mEF`h}~jO2`Z>w(ih*5g{43l*hGr!D^W!c__e!&QM+j?gn=6&F`~|t8G0J{GBYQ zt7)q8WQM$4e_pZILxL!n^ZWG=q}+a(s&c1)VR@Hr=qEs`j9|P zLdkBR1mnO%NU8StYf8BK@$=RN;PmJGMMGYVS=bYLSZWzg_OJp>ll5$>>3^ub!fC2({g#zX}dhwT~iPrLp1&Q^AqxX-(i z^%EZ>gK!SXs;)zT*wC$p(-(uiwIP2tw>&)OMdP$0&frz(0dLlUM54+Ge&6Af*7;)8 z_Bqa*pX27+Rc#)gRP`3wi}Xc6xGvm2S#p+%c|uTnOjo<$G$w`fY;S&himJ|Vrkv3u zj-YqPIG7y2DeZ?0!_Sc6nC~63Q`?Wm;y6MXVu6`dWMbR}95<89lw(edXCg}kGXm(k ziPk2#W1w%Rn{=t9>pVh0=vl!JUBX8P~Eze5f6yA!Rb8-O?*D~qv~fB)0D=w%GB>*xCL zfBg$Hp@c*Q)K2>M?9A*+hkRI(F-V~Xh!);n zND{Zt9G82b%XM?e>-*Qv01fFLumHqY`xT^Vk zMG&^K>QM4;)^6ZoHC*yhUPv_L(E(uz706=(oXf|YM`GH}2p1(&+6?`1b{>tIASyAYmq_O5B+sCDDJdCO?h+urh~&8ox%0T6aRj=ipI-Gp2-gT;E-ixciu*4^q@HOh1aGu> zljeZq7U0e04{?8|* z5|1tk|NTMUTh;&Vd!l6h_czz{NhAh}nzn8~$jAu&&p)X|dB)SodYcXF8R!o?z<@#e zpIkrKsfHC_WZC7VjaLsTKmK2@x`aZ_EQdUjKje zIHB?2&0H{G{@m=&1#wE-yx2YpDl>K>t1s=gt>w(o&R&Q#a5__{D z-bb$MHkrQeL9JoGSq7lIh9oUmL#nH*joOY@W7ay@3?F@4ui#*$#&E8qFuuRPJV1&!SL$mM z1Fb8hMRR@)(vN7xm{yV;3^$XZ3&XGM7my_=^7*7B7?k>lnMIAK-ISJDhKZa~J6vkLH`J2kX$r;nm zz|^&Ix|yNcCLyAT2F(U%pI@KiV=x}@*e=;ImCuH}>RSu>xxNrE-EWGK&{xfKI{<9n zEiTktg6`vJBp+VYf4$D4eyww z;eIZo*)pu4V<70o@Y9S0WEWBn^-g?uav7j7sV0f8d0?Sqr@N{oKRp`EmBxLA22M#= zyx@Uqa`KM@XzIYkOa9glYcRaUK#^f3r!1XcJL-QCFAzRf)3j%woy9W9 z#wy@K%ME?%-(j%oNB^K%IMzB2%~Q|?21EK|CDfPL-n!l|!F7@QR|tkgN#935pjZ5S z_tvwl8s!Om@i`D6V8uuB#nPVeJ;$zlY4;*)gP|yU^!LoP;knNjE>19D52u4dg>T(n z=D*#RQXaIEht56W!B-jw6eIxVmM0i7T zWTJ|+f)|(il&CKuKE6wp#npgm%4|(Ypx+yx=2g5&(~zM$rYAZFpnbs zOdJ}_Zr;d#mPh6fN`?a_(nt2`bh9g3JNhp*hxRCQj&Q5Ao(JV2b%O6BTF4HMVMV7= zpT3`?o*-IkntdF4;Br^4)n1OaYvI1nHE#JgFIg;-M%`U}GCC|GI)_q8F*tN<-0}{EzI%N!KS($|?7= zQ5Yrn%)DT$;9pPw+R3i2K!>GLZywD??{kEY4$TeN-Lg+5>{CQHNAv0;3#b-r^=ZuX zNE>Bkqch+u-EuU!pE@%!vip=Aq={{@tR82IX^T=|1yA+o14Y$S{MJOI*u%q@RvA>{ zoP)Af7`+EyakyH+5V_L3M@w}{4+H0o*T57$N#DKYe4 z7Gn5CUqG7YNXrTQHT!x0Q=(G{QPsslHE+kbsrzciY8H4|gk685x}`!wW+Vr(W(H-B_ z*{>-e|4WAPy#_+o9}61iiz16s>LXqG2%p@tn1~8<(edTPjfFlV&pm_bw2oZgiB{1( zCUhgL*k^`w{n9fbCg@!0odTAZo7ten6A=wgQ+v|L?Lf)K@74Wz4-Q-qXJNS*RI0R50r+c+B*@;{7D`*3sXxo?+_KyG?CK*<6RuQS$loqkHOq zp{1uT^?yt)lx6Ue>uU+FHoz$)y}onkFcF5gjoRet(5DyWSa_v6BE-=)-) zI~kPh?e_sMhJ`B`M+(WwcG+A=rDDk7yi zFz}Z0b4c}Rq<&-n|3%e#2Q{^Yds{`pLQ_yWsE8CPQlvLUx&fsKND)Cwl+Z&65D>8; z5;{l?N(fboK!DKXC`7u1p3tNPLX*%5kZ1HaJ!%)a0lmaWB*CZ{!O|oj&;7-U3trk>7>&wP4}l!Jr6)nQW{Gszgoy zzLbE)L#2dPI|~6F#t#8;jJ)QS9a+yE3JLw9?{4RSz&xmO079g0Hjw<=8bbL#&=t_9 zaQXTVW}O9XtT=a&VArk9w!XU5=rwm_!1?X+Vt4Qd)Od$)38F&0@#7Y4r!yAor&%-e z7v#;y6yZUzJ{HrL6$SC2#RJnkMqC7@`SROVk!Vjnz0jj#KJWNnpz&7iTdlgYXK&ro zn_fSPu>Cozfi`{*K75EfZ;XGj?3yS>!ejG33pXp4Nrk-W!7kiSG~yU+Q5DuOLZ9il z*Y}ZYb%YgL`(-%B+61-y{y;d|ni2eu+zua?o}!f7{PxIW%?X9qR~9d`cgWd|U zaN@fvr8v9Ezi6;-o0TOQGqG#uVV8JHa+k2=o-QP}DPVq7) zu8sMJ2Q$k~pK+HNg#I9Xj_A%*22VPYelqynPDW5v2W|#d@`j&zc^OJj|NU6LZ~_nqqFC;Km2hBp+>_S}+r&F%lL zas{Lt`cH0Js)w1MkfY))06>}spdw2PzrMgt^AlEC&v>UioKio_c=18&?qNv>s-Mf{ z)6>znK&`jYysBQce5rie&e6U%EXt+aB>5s#hYPXIvmf^UK&^X7Hug2bDa@ckdQoP? zlySnaPbFC&hdxNQ=YE7Vnu{ph&-Cgk`O#Q`Sn9E!t(Rc27V20qZ_R}muDcPdDZ;Bw z=J@-Ht#{Iu5$KDHpVfPsIkAXtV4LT;JTRGEFJ~N4sj&aK*H|aE+aM(C%{6my1+|IA6~>bJ=)Xp0~=wT;bhrm_k}Q zZ?y>FRns~THjeJ|@(Oor)ONx6^@k`z;>#BD`EhZ{IERKOZNmo8o z!F(crw6=X>{;qF_;$&a4~_-TmG%NBEmAU zS(eHV&Bfm8{3sUcG^sG9NQZ2J7YA9y-dD2t^%yU7>Si#kFM}2@GAi6+xfB_CZ>ZV& z*+ZCM$hIrcuUO!P!s-^HCm?F(BZ`U2F)u^zJr3-XV`b9<<$P)mEl8X`)ETKUov7g_ z$p&QHxGNNmV%E;xr{aK`!@$?!H`046@|fW!XZsDW0#TJMW;+bzj!=?_?J2sy`7>mTx7rRe|`x=I_iR|5m*ZD1_#gK^_?WX5MOPCVDoM7lrC`+Q|&OM1lpCUqa4Y@FK;gZH0W%q6&{TC&WPd@g?k zEf;^;yiflt2GVsC-iljxwC(dZOfulm)c>C5vcHk9qw`jDC01C&n#sv_cpNk=!+T)R zx3jY{q-6SXddaHqOzn^I|Lf-@M2?|Xx51bHyhrw4FJCHjHhlDzrFZvA40`vZf}WxP z-`|$bUCnUXe=VI+Kuf2;?{3C5spH4%aqAMBLdWkMnj$(>;{2@olYCZ=Z~EFFjL-6a z3o@$o!b&x9|5V8bk!wyO+3*q;xnrZTp>bBjsPgVQaHEJ9Is8KApu*4aN_1x0Tubd` zHun6_nxty=KMxeWMMwX3dT&uES%rR`8S59|*OoiJHe^hEQ`CR_0Wp(-Sr(Rg*utkQ zIy74p!fsn4{)>OYCDUAm$!k$P?K6l6v$3PKTutynUGY)T>?kVC61zw~(eVV1r}-iV zs-0+oYgtWD*{7&xa^7H*aJ2j4&Dhsm;5*F9#PB6HRDrSA;p5M!jQ7)T6f$k3oA6X? za%@zsCI00^%=UE5V3^96yDAb%Y&#y2H5w$Vs>Z^t?@GwzHs5LPSA{)Pp!1eyQ<$L- z1fIyhUF;;n<@7ZkY@c56Rx4sFYJXt0dpW_jx;6UygDt|LByC)Q+sCMNcnhJr6(8VM z%E;7^uD+hty8{+Zd?S2u7kHy@I_!|;ZS+_DEPPv-Cq$Diz#QC{eG=8dS5h3a`O>KI zhqIhD-p6@!BS4;*x!lG_#tXzKnPy53yJAI^6hQ9QcwKeXyWk)uY_!WsZ0^E8LITO| z{qlhriReBKUwfwP{_-GNtL-9e8_9_@aRYjMWBhxn>sV1m?V@N=nPh#Yte&#*!Vm)I zqzjMFD3zRWwTo{ib3QPk+j93#{G9v6z-NILjO3QnPah6U0NQ|t$FP+JU)D)^9g-r@7%MYK(%LZwA7BOm{(_^zn&lsycH<|hz zM!Y`3wa~I}k-n#DrIan!EnJ{N7U@Q0DlayFDmMKPDwz?LL`I zWt@lQ^l4$}N^`r;Z4^PNhZpy+$6&}2h0_m}7TL)OJ1dEt&Ms;SY zEAk4`cryNjU-(C-9~Vdd2UK#Q+@Mju>QI36{n&d2$Osqq3WN=F@Y|vw)OT_x<()uv zv#-+|jbvlhoB3}-tg2*k+s~u;(%6hzmu)mr)4)NB>5iR;Ek|;P8(xB(+fie2!sR1% zL@(6O$Wm}cLQ2c=O+|SZ{Jv2eWC9O743xH9z1fqVojg$>w#ZuqKV{(fzV(ShEZ9Jv z!8B;-&O27Y4g)nFao(y=60w6;IJ^5kecs)4RzMK_!jAx^oZd9#NH!D}KQE>t1J2)G+$Ax;>&u&{*Y%#0wb{5|Ga=;f}$C zZ{)v3g5ca{g1=sgMNqGk0p2z~Kq_-j72$LKtHk|F1Y9YAV9)#wC1+`pUtC#Em$0Nw z%nh6(SzLVOOsaL~?+fkI6kAvs>+9&~^YnC2nB9#IxF6K3&S($S(5kRQ-d62WUoKpi zH?4qxDG4X3N|0&LW=G=PI&UMct?F=R%deWxC|a`&c5_)N!&WN~O=++tVNzS|v%bdJ z{Eqwt!odek88RE?8-a|>Eefu*9ynF)|L}76tmOd&39{6@N795c#A6|y>+YEw|G}KEqj?r~p2f;m8A{Co{SaYdRvy4?G1^{zlg~SI;iJg)Sd1k@FrnTI>ZzR`Drc=< zFzmyZA#5!KzV~S8i%g=lK4QI@+b7sRb)lr--fXKF**Vdtpvc`ABjaQbAtk1}rYs1T z;;D^fZmMejirr0JMD-XjqbZkeDT}fFSyPLi3fy3H=d6a0nrGkf=(ElxV4g%{v;!YC ze?>T3mf78V{%p8HV1eG(-F6*9xMn|&IWA|QrinI0yS!IGI@@t&oV@*G{*Q&dg(SR~ zpl(&wrJnwAw!cgD<^~N;&cCr@V6-g{1dVWSSV);bA%5guxlH&$mbtKLyjg}Vm8S{dOup6<{r@W#N6hAE=l02Kcn>gzouHag3A&)$MkN{HFL&Hegy(QlJZG8Qv>69P2 z1xHwPVD9F1?oW_u+710!q^LG8nMJUnx#gyVk3QUSqA9?_v_PZX&$2E;4i#k+uG}=k zHE(8F!PMd?Ok~!f;c`Df1;2c+l_%UvmRaV7t9A|POlyiv`_^9Yk-oWenOFmo{fTWI zb^FsGKFHM%G!Zux9>fi9>(JUHo4R~RoNAsCoAv&)MMc}Y9=9xwQgS39NApL6NId8^ zPVp&VqoDQ&a-~qFT76^$Qiko@m6d&MbKZ)^(~MT9ei{oF zZO|s{na-GdoZBstW&v6S^QCEz$pPOp9~RV)M$6)C;<4f9KI}%B@WZBWL1#WLyzTLc z`zjur#JlL^N7@1jbb}BMh}ef{DM(G>`laI<()}zA+|?H94x+JIVBxsrI2hc5ZGjKM zLX0?yyCrCYGu?C0GRa)zVB{%=jUwq|^9o2Ns1Bc9V3u#%xSdujTtYr{DP4t}JAKXr zFJF2;1$}_ZpH|wmD(Dyv>*fPbM7XTM2%_x5WuX*IK&&YNW;%T~We~#BJ!VN>t?w}v zeCNUf$xBoigjb%Ohz@`LL(aNU;Z*LlrgQ6k;~%xLgAYWKRRTr>jW%7Sg+k&VD@%=- zN?%kPf2Ep*NBM?ubNA1E^b`&y?y2e#7>!7FP~wl}>VmtelJ>2+nx8dN8{KWO%Y9P1 z4y#>;6Oip;V`8o@3+sDF$GxdLr=k&|*kwmFQ6YAL9UX3zwf%D}dN(TjI+vjt{98UH zc(=%cUEXU)5W9r-FybIw9V=B_=r&Xs%i2#(1^Rc-*Fuui9~x{&YhORUj1_+V5FUi0*=u738)+%Nd3Z8%d#<#cyf;rb?fZb~%-Tz56> zQqW~DOiaPF8ibf$=}h2)cnPv3Vi&kyl*vHSujKRnB!Nj~-4;xzeKMy13GEYD<1Hx= z(7@Nku(q7iRJCX50Ai{z^s|IEUX96f33IpeWcHXS_&Ooa$b&8KF<+U; z>~PiT>6y*lYYVv!D*c29+Jtfzzhz&+{V*lXM5t#HD|wV!mdS4v#B5q~353vJC0(+i z%5H+ehNQCm=G(og29FiIX~=Pp8%?%XRQ-3Onv_5{^#1_kYgu}M`et<*{XqRL>9$^N zWko_BxUsVlU)f)N_MUT^=egq`!JOW$JHx+LO>aB2QdF0~_=KLAF?cfCesZ*3w+oxk zr$RShm7l&MFPzUqW|RIXds?KaBf*cIymp1!y=q;d1TiLNfmOGuO$r))b)I#T{Paw# zL-zwx`GyI2V4B-ohhbL@VrzK?Ro!4+Ddn>*MJtcFjmAWs%_VJuTzLH2jr&Qm^KaMP z`gJ^%n(`Q~4R;5I=s#W%*yK;aHAb!I)|RvfFTk%;!uR(x=z@fG9cHo`z|rqYN}-%37ZJ=ydpWAO5Bi>W-g zYSjQ|H7dP){k_Er#HaO<$#y#jtq;A`Bb6-9V)m;L^GL`98CVL`fTh6Qiuyi9+>q2r zh|2~~H=SWHGU6`!O@hVt3b!d#z#kp;7*niI5n}7^QY+C6#%?}+V=r}@v@R}WW~|OA^X6hxoG_eQMU?$iw#3W!Z#=v--*xO2q+@tq1nM?+xv}MVpc&lmbY8kE z_-=c5+HDTq15fNxxoO~cUt%Sp`b*K27qnFIp!kAO%jNF?%}TP(R06TF;Q9`vrObBHJTp1 zSOY%nJNX+$sxNn+PpG~z*S}x&Z0iIsqyJMSDCgVIu(ORBoi8ku)V}>MZ7P22;&ENZ z7ry5|;86N``%Clc-&(R|Uxpd$^Uf_KGg{QO%OsEEsSLV2V)L@`A9; z5o3PO9)@82A!&))D<}y$l5iSo#VVAXy=KL-_o>JD;5M(CYNqm0T;Yf@(WNrPCl-P1smsKBf?EYo<%@0eC4O6oCe9 zW^NfPRP9Al?FT%6`#8nLP;DYk;A;v)CxO3kVU%mUJJ;ujkb7PH988R0*4Fp5{>;^6 zkBKc6EjLRRf59A-x}IvqzeKLREd4C3hD?kl^38mLiG2?&zWt}OIecG2a82#*IBcwS zva?<=t&c^YMBK^+9%XgEC$mpb8Q1JyChbNRE!yWpsol0H@ntGRy!_q=MDcv(5gJ7! zyrE{%IRWT4y{Ot;`nV4JEb-6O9f`i>BUMBZYQOt~RcEY1rJszUpKh7F;Ol>MvvEY7WCn^ zd$}@RAv2+fku?rBU9Z)m`m}i6-R>ABEMuE)?z3i1tTOXKsr?ygj5ZUDTaZehq>=_n8GPJJBdwfMc_M@YFFq#;qZA)7pF4+{=?`tA`&oUBoSVJB z_A^?W@?+Mia&P>v-`aAc$fEldv52;RZ?^mw_5aAoz9uQ6Gv!UL=StA(BYr7r0Cg6Y z%2|OV_59Yc*N8;*hyKH-TdjW2>~0>J#%(vJLBNK`XqZj4#zQ_L{o}I~RQ*TaZF19o z3nffZ?Amfg<#%hCRRgj|T!*P;Zuwmab%8X3Dd9TlmmzBG@XPZCgy!)mY%i>PMCT=M z9tqmVDmcW#`jd%JeR0{CP%16c`qjBL6I4j~puk>f3_b=%35hedgGO1hK6~_Tt$r>% zc)aNz35=^W)QK3wP00J%QMG9f1I>n*v)5AU;@F0>K9N^tKlljdYEIr!Mm=GCe_j16 zgtB&Q`7JQ2^>+7U-=v}V-fS_{4q_DxSsHj zMQ$`b9yT9$3G61bayWcVpg7TsO<27yBfZW8H%v8gL;$(qc@dd{+TYq2a;rXvg}C+azp*YYU3k~>}nS5>TX9*l_y71 zVz+9!_@CfHsX_0xqXviE#+cj0WPiPQi=a=Rqqrse=B5}S`HGOrU#Qr{?ceL>F`vF_Ehw@IJe7Nk z5Hz>z|G_aboo&38u)ZENG3;Y&chY1C{|yDIPy~k9$U#y7SYZh+cD#I0n?y@W6z8nU zfi0=|y(OVpWaGI~mHFE#e(f=ye5-0pF4n654i;>Iy}W{JL|B6QpT4;h7cx=y5WgU^ zPqL$&?kmCqRcR$ftl;yo_IOdwXR;wZt@YXzL%c#bTd2%ijD~uaM-0L6XsGerZ}&PE5UX&#vn7PIXJ;&6}tF z%c`RTOe=*IPyN&~difbXDHx*El%8+2$8!SMtE74`9ghKU$K%6-9uXS_M7^y~&mCX) ztT*6X-c%Tpq@^z?)uszngE}TIQ7!lv&A84`_XiT)jKwlhe}E0qeAbp44G0aiF@=^D z3Kh_kBl0Jigf?>=EjAF;4PG+8Xxq1JwNy`){^ z;H3c@;c`=%4Gv`|5iqJ}N&A408kkKY%(}mmo!Y8#+rpqxSsnBti`LfrxDU=&v-j3} zm9UqV@wl(s0C8ZIr`S5hbTJl|WA`;nvApU^`JF-CVo8cFvBgrhqP%@T5vx)4%2{i$ zJhl>1A;_ON4u5gsqS^ScafBM^w4~m*(~^1M;QZ``kPo*sHZUC8yvi8i1kd0S)3jd? z4ERPe5~rTph%9psftv7!idwz1q)WqLCcof$9Jxr#jM&8$X#=&3aQ0(5O)({S%p!T6 zZj}oo#+9lG#w)nNe-)bAr!ch@F7~MvIXX!+y-TN<<-vA6k}iN_QTpovcJKT&1iG=1 zxZ5vWitpAk?#gLo87ox;pJN)@*?U<0jIBZt8O(=5zrqS(QX5Uv0VQ@ zKQK|~xFHHflo0KVH)T9y`I{bxm2~d=_MxQpr}1#WLBF0Qy%HjzjUz9*!Ry-JrkC00 zcIOy0nbyUuKO4J&w0YER%zdNuS*;NsVbpqmeOdfG`HtrIM`OE5%iTR{iL!@Tt+$Qw z(RC}^A7>lE_jUW7E1i|;Ge+A-OHN##I5=gx4$PkpK>)%~Qvupdz5UAPnx{Qr3pE-B zH1pm1x$^3ngZ+3i#zx$DFxTDATveQ{3<55Qi(M>OqsG^y{b(-(W#4);pwL6(sR0BUe>uc<5l zm$h^f-vmo>gv;S9{UD`iB8&zL1yE*qT;RcmDc%1dC1QZ41?VZXDDxRwyMm&zN{8RW zly~;%8>Os=ZS+5;QRBA{8^UO-gR88phompIMeP~TJcIA6`-@?SKRH^vrbQDr^mY0Y z>dQF!4W_L{Ur0j*2+40}{GcYB6RlA?jG>nW^+ax*qaSG5HT3vMhOKUgdO@GaVBc@py0bmK zl-@(9WgQ4o50n-CGYG6}rO2)D2R~sksu@j)#Ovj&Ksa8r=WE~ePcprSPw62zH8jil z-NfFPCLbyst40;1yV>{$jx^B&Di6?7@aqneF+G)1=_Ga%y((;1#!5>BG^E(Rh}mLn zGKZPDXX@co%v_`_yUZIoE6cvD`9<`R zw-`Tox}sI_B0znlTctB*7~6Em9QL7#k@h&2;;BzrP)!{!SVO0^2Ygl0Z<+-X9!3rlaUVn_2t))sGWW%qd?u!2_7awyLovSt`e{ z38V3SrM!-qQ2nuTWaxPVD@s*;Jq8n-@=H|fK~{dsuqz>QFKbWYA_;Wp80J8qpjWr= zCHgz6E4`=jL$BJ*Q64%$-NC@yU^)Dx+BzQdHn z9MTBMIQPF$%9N)g{iTV)?HnZC19pUbBmVGDQ@#v!XzzL1W3D%%=yW_WffMooo2e=`!PSn3AsfGM7w}m#kyZBC`}LtlNktGZ z8Ud+M3_NR;kD7dGZ8^u=>^UF@KAZPQ*C(%;HrIgOoB{)byy&+t_d1qE6Vita?DXUjQ3@ z&J+ah4E5sut-fL1``akrI*pH^#eV!;NH#@8*5>|ECXycD z{pYB6Ko%kXINblkgHA}fY3FtAyr7}0h$BU6Y3NFwG!&x1p9>k$gD;yg5-V9wkSF(% z@{Ok2u~2H(g5w$OwGnTE}BEal|1H%Ng?vk!;?LUbhQn6?$KJCHhw`f2_%9CeH+j^lsFq zZDM2&6Mh;_itND)q*Ti1G*p9CKtQqv+$m7IP%dUET6VA9(L)D`Fkba;M5Ldq!IN%l zqBF1~tC;$>ZSkhde>fM$`b(B_yd2J=&H2~!QG1R&l10(d%SbFu$u;z>awSiaxWqH+zd zIu*iuAb6-Zny}s@tUsGPVXm`PyO4qU+?Y?9NRr%+J4Ew!==})p+mR>T;T@Pg{%7RE z(Gl|^hniiO!8@cf$ouIC%;MpVB$EWAJq`#5S7kGSe z(yKTfGPw;&T#t9jKy2+7T9By3OS>9fe$bzNaC*YNX@j=bxgY(X_j6~zw#6Pisf$FF z3qZ*~C34#b{&t`W<|1FC$JCA*ru}XUCmMY`_JH?Q?uoh24;8$PjrltLKb*#xJ<<0T zGjVeE)Dgf&#FcoQTa|qpTu4w(#&2v$mPTK}zfW+yr}gv9<{y9{)d-oUnI{Cy6P+gJ z-}Pya{k3?5;hTWiX_O&x`s5UjW)|8;K6sxXWq_vLg1|UY+}#)>}R!yOlAQ zuCnzuQXaht$V|Ea*>kFwqnGg%{C!Yvhf3_~+(CCfDxXZ07F9~Zo#7{yFXkx@n@S&+ zYakfYb?I@d$T-m==B~U+nof6)bDC2_p3BiMM{`t{xhhI*yZ3Dl(&a@64#K=Mx&QrG zGYIn8egz0{KU%S2j4`>s)rtLDT+?>GcWyrDP2$Momb0a z=T<*NL?jCf@b_Yh}7Rq+MTMXy`0@_I$-h2+{7_q?Vj> z@I)n{y}}Ok7JnzLx~DkI$V^7zWDVb|I(5Y--+0Xr4v#to^+beX91i^_BQc_w4mMV1 zfUt6Wne9Kr4*IauRHCIGU3;^%P-xkT~SG$I}A5#>#<}9I4M%{QMx9eO~h-}I7 z1?n9G{(+L{Ss(U(X0q6eX?~+ zrg`5Y3z`52vledymyNIKk+WWbb@)~aNxGTAlZzJqSQ~U4XvcH>@&OM#@yav%_d{ZmQZS1K- z8pEQ-dLdDErGhz`HujZ&nW-byB5U@Us`@2@Z^rJ-&%FlMm1dfdb(5NM;Pf7J_4=>* z)7poBn1&v%re50qH!1Xlz2%4}f9qQ4MuJc&9jEpn;NRtdqJWgetM=z|z$SdFDPL@b zgpTqbmRZ@&+^1jc{~=ZltdTWf8f!dR)mcgsyUehMEpE+zgG~T-9$P{h&VqT3tB**( zoDE5t1v(4mGkL!*^>pPd@6NjiTeFfve}6j1bhKvOGRxYCd;tO)z4bx_lE1@_%nJjd za~(6Vu?}h>;>f*Nq$+&hO8w4Q!0%53!4#}Y<#7N)a|wld`?lJ2V7u8@Q+hq#NKOmP z+L>ntGmfMg)IC)J=9*vuNOFG3dH+sJl{mo#{92@*c6wB&}AZp?id`%s!j)jHGV~OB^JU{ z`mkvk3-f8CY8enmrYn4)u|vk=VXDrqb$e)MD%?;c6{Wy5XI`L2<%LUk-dYh}j-Ne} z7?}G2{Nr^!w<}GP0`uw_YOv5-9Iv@P-nyh(DEsru&C4&FS;JEwIL%#RymRw;MO z2z6hmS)5k;mL3M6flZTJ{69jQxyvN6w*=-nchu-i9ge>)Ll2?GQoc8Zmo}A21ElT?$Yz2K_D-jva&3xav>}15<6A^q)-n+e3+@89Ve4g-&}dvIiEmIP=9Au%>r~We)gOb z9BjkgE)zj)*hq|NG786q0S)ZL(JtLbKgOJ(9ruPvl?Yn+`_0%xp~ zLU^jZgi0ndlUcdjQ-la3uekkx+`u2p;^uy}ho~tFh1E+kst-JQ^U3N`)tIUqY_&vOa_Bwg)*cRq9guF zRsQ`#1vh|XPyD5b+e+$2#gsVbPv8L5r@w@XG4O8jog=Cd#Rsw*g|E(yanTv*)ce2x zwLkeNtrpcf$qN`ymQx;U9%Y3!b_nK=?dW-e6|A`xCk9x=jF?vb?BaOBsUwk2m+v1= zt!nE1-#0fiJW66pU0?`0>ejt=`Ca&JW*mH~&6ugwz5#c5S6-8^P*CGdOnkWd0vR}j z`uzA{Zs^P7&R74NX#;d=DuAG;Qn~Y=@65OV1`ik9P%1mUrlBE!fYgiHQRqj3b;|Hx zfe0JWmh}G#ME>t`Fh|gEwCl5qffiQkTjvmhBFRp!m(d-O zHm`8f>8t37cOS>Z#vcC9zXmKfQGe&t8<0eA*12{vR-R#qCWe$miDuPThQgNWfQ2R0 zD(3jz+-e;nQz9QD06X2Kw&gJ5E0;IHxStH_pDLU6o$2>!KlY^! z3H3)7rT+P`biDlhtB()z+5ry&@T)FfsMw`*$C``MJsJfww8A_OR;&kb3uQ-+u}v@h zir|4%3ai31;#=uPATE^W%H~uH%5)`60~pq|$s9IKJG!nJM|&q*m^b8N?9q*>u><7U zghB!>LaF$@q_4mi%gW#8;cs^qJF?Ggy0@#mTb?BYtFLq8xcr>$a{R7oyn_A~Ta{_& zD&RjJ`X4#!`#R-+&8RDCjK4;YECMj9zMe10FybMu`PBMyiVj>_I! z8{u*Qd>lD7*3umzwAKav=az_M`ovRqP>b8hni}(X`%w=gS+^} zk)Yu>-&&YX?0N*_R(^67M_mq+eA|4tIstNgqV}l2)Ghrc_d8a<_nY$GVjv;Lr{x+; z(=Z3P%O*@9-3%VRZ#aIW29tOk_n5m3+s>!&@_O3t!fc}N_DUD*A^gX&&gN$~?Sq(4 za9!*R`kV+UHC@;CR_IQjiC7iLe5{zsH}}%dJtzxxM}r^w`>p}us+^-zI@oF zLF@WDglFchdryJJI_etu%#zSE)W->ON8l8ggcLU*aQ>&1o6PQWKiSvzT$mB-u@}Pp z?a1d>%sU31zuPMCPr7E*M$MW{V}cXB^W=}vmQzfO^A=Jmx3!NFghku%n@ucR>wIn6 zpCy>toksjMDZhFhvn@QLG;h78wx22nY}u1DcP`=6>!B;7d3X&WYrL#T7@(GSkL$h$ zS9Z-ZS_cmC83u-#RO=;6qc%P}WLC0r^UWs9U20`DiLTP5NG1mZblPV?2tiu82U=%r z*zx@cRq>f-N|XysoNe+s=o;TVO-2ENlj=tfL%77cJJb7B9YG%(20!tNFJlP)SEiwHs^#5QX4Zk@ZN^9-qRR}v`|QO5n@;=&FPbqyZ+LTaym zptqY!ZU7CNGNvVL*)yg0Z-rr+LZ5_QdLkw{hhJ+WN^DWo(zyQ zmowP%%)E@^Te+4$DkN7XHeaYbqa5Q~l3X^k?_iV?`Z#;6?FFajy9WP$(RqRw#MxcF z9Bq#=otc2NaN_3Ur9DgqyP=&FT&BP0aJM3t%vP^7V66}r zux?!o`rT4Gn&4%|??!#Z@65a$Qc*0UzO~aPxA5Vw{Bo5vRp()=d4sFQPpsXDFHy9e z0Kh;Kj_Ek6*r|&~8#yeIu2Iim&u8#DBNpztBamw)okuex0^J8$1fAiVEpaOklKBZe&(C!;I>eit1ng409b6sVt^aY1thukDko;-Z#wk=La^n*M zzP*x}kS=6aY0fk0yS3y~7vIzCiS9f_EK6*-;NygK`#UkYY#qZ7?|ot$l)vWiZ9DSG zO+K?Adtrk7RHa)?vV3mMEA+C;Q7oL+-F&<7pHl+7KhsynzCd2&O4|Eup7z*#DL4<&2>IltE!q&P?5Yn>$ORI;I^(dpw~+M3 zfD|+8)tj^O4ICABQ?K4k>@FLE^1%>sYG3F-AEz@;Gg4}Rr2Llz95RZQ?kZ1mZRlx9 zt`u}7DYBduFWB%|PUsn?*F2XM>Wn{(asF05?_{;Bm??W*_gL09k3!GOCMn?>aLuzB z3Cc=P%jyFil5A~3fBJ)_`*|}J%(E^yFe6FNjRtFnq7a2F0zs8BOo$NltV6t~|?Hid8 zbpRXMgl9sAXr^|m_K&+&jtz;TbVHfQ*pQpdcp1i%53W09xAf;$Fyt1V7@a9Cylskh zAq9N@YlBmZ-k=b-vIY2ewNf-qyo}!Tr-K`F?Kz>kliQUIchfMi-$wD3Pdn#t2Nwh5 zQP7}n^3V!1&(Vuw-Y^BD*evC;l;4#1xuwg#j^F!n&LE*?7Y$K&HuO1T_!snP_R=xT zUks=4ay^RiZz`!T!>3%VLA&#H9TxT{@28Nu;7J|nXRW6IOaGt3&^LiHSdnG$+XWy=SR%fwG0rAnH=`1)- zFbBw5+cYHrF@EK0f@Zf2uQ5ehFlK-eGEynDxAF~3=3e_jXuXGmv~mVS2dO#ndU&A% z-~1~`GmN~F`K9K?9k=GFsSa(tth6-&%rEE16w&p@;b}0?QeK4eU$Pd2vv@c!uxezs zsjyv-ofB*L7H!55;e<^({j{qKfW>d3r7?$#!N}b4(T%aA3m}N1;s(_j&w`dk39{{X zPGVCqCB^!PGQ&QyyYSt{@tK)_njhGx9i_cWQL5@04~Z%HN_~nJ=D`y7EBYLbmjMHw z`0BX2ri`k5StSCH(cnUrLTKbsJ@(u^Y##CZMLeRzIKk<^rsYO#8X##QO*=36Zgmc}?9R z03Z%BY27a+f|dK@1+E(L7<(CSt0!UHA-556gFJq>gV4?GiZS~h7hr}DSoj48 zG$*5F1+Y+3DEgzzqi3bhwX#`fJ(dEeq$@#xXD9No?XS*j;oD_H(9w?6>}o^yH~UkN z^OKJ3rzV8tI$mIe8~zwvF8+~u#lQ3D=ws-sQ!pV4x?nH2aB8seXWi}xw$7918743< zzcJ1(AMy47qV=ODuX3FxIqY}F1uQ+6T=!!O3)swR+BCExNWKITV=m=g_Q|>p|7;U6 zTH%ofTv#o8uaxZP=+&dQPD5g=?{G4RRtByUzS%+r81aTJ2|r@%$}Bj^T#Gm5u~VIZGLBH?`pew69-#Fr0=nx6oE{ewDtE>4pbJ>do%$=!)9I1 zbnqwmef;jsu(?ArM!F^=YjN=htgRXv5kypf^dTs=QlzQ-N>6g35|0I-Guk#DXdsv+ zJ@az<5b&r{c-LV-t~z}4zLsuq@|Nej7xi>E#c^J=EG%J<;Awvn$cQ) zuXZ`Bkcdqe7U$$es1BFefHo{4@rR%9r4Zi|X7ehQ$9u^xC?^_mqqbSjfUS`W{$|^r zdQd_TN4j_fXIc3#dB$JT@!S~EQ}^K_VtN#v&({63=G=O@{R>0HHOP_aGyX!%)65(Y zOs@Ag@)#4#>R;0n-M#yC?4Pr_m|vLbVX_lnruvDyyDiUD(O|bkbv4di<<-0K_`Z$d z+|!KIgt}KX*)VnUZ?7$RAGp?C9c%Qiyyx0*`Tn=pA+E;&EQa?*&gn47HfrzXu?e5F zu}2#5ubnxMnyq?eg5uoyd zZy&ln-mzV>Dp?L#*V6p%;{-=rJ;HwtCA@RV1q-^oaMb6EyI%bE#rftqOG3MO1H3kKeB228tEW~vMKQgF%B{nxNpr1{ayQ{obqUh%CNOo~#%2sDw< zQI&XOWSqY!^Wj&}1Q+chS8a|4A7pI$Ak=dccG$X#w#sr9=~Mk9keq^HS?J!Ku8Bs# zH=Ph53^36bXsz_&Lj$Ys9JG?mxc=j}2RC}jCP|N!Xvzw!vqVj^rNG_q9sZGscaR0! z(48>m%7UQsC4LeQ-EAb~`dAA8qAShXDn%3a%)L=4%|z#3xnOGHhTi+X;KLF=qzpc8 z?;4~DdERssi(N=qA$^p6ZLcETgO9Pn2)g%$C03F(uH_uOw+Il z)kSFSfV1O$)B4q>iNh%1gs9qK;Hyz2!o{`_c_u7s6aT!gJgU+q6|Qnv)U;QW;5%MP zU)T$b3s`WoF$u~DEFZVanp=BDWJ*3bG6og(SkA`y3kBX1_^xn3b;+f7ROfXBB(zG> zgy=bWCWuQD2TF9;&8&mp@*yaz!;!+ujuu#9`$-aehm$?}{0`45&8Y8l)JFYxY|6Lt zxnVMxeQ^O7Jzp1w$lXO+S!PMRR^j6?D813Q zU+n=sSBCNu3ng^X_q!=-KKuk#5rmI);dh*Ja(~p7p7b?|g4H#iobl0X8bWc3kR=Ja zp~wTR#DDMm{xcr>6N-p4#p$XlUt|Kqo7UPF_Z2`RgYn?#O16PS#rk2as=48`MFApe zy2Z3HrK9I9S~p>%BAs|6cThuN)$)oAwE^UmsnfCX3*iXY>0k?+u3I2awcyr6E)B0# z_VjG;hJ@||aK8jE=e;IOh`ho?ib0-52yzIsuh|mxG~HlTp&{+=BLG59R*0On5Li^` zd6+Z-;S)v>d|RHI14(_1|EJNrnJU*%*~WXuX-aND#YO!4>EIPtr}w{Vimt8<1_3WR z5iy$kj!@V+*cop;M-H{GE>j_lf0`3EwQ4rn_87XYKRU)n1&`V&al)c=chl4!OpOfG zeakfQ8RB&*p&${5dbJ)=8}DtH3fpC23_eVJ!>fuhPk*o6SP3y+z3ikSsg*gWyb^e? zeA#|6!C%F4!g&nb2qwP$o56>9IS4}*S2QVK$3ouVHmiyz9@A&JVb`fnHsFJf#pp$^ zETf){l`;uQ(G`VaT<{0TJH(ac{Gr>xWxw`MTg*chn2<{d^%_>Y0y)luE#^hrWG4g7 z>6J-N`ER#U+cQ&jS~5p{suf{L=3cq^3rXGDetN2CMTrvj=Kr^_4Lf zP+cJLXq^ItaF?)YC;)bRgpk3*RhHf2FTvHSV&WHF>2GHm_~jvg8bB2uiIROf+n?_4 zerhmGlfMy&L!5t}|44e+6C1U<-Z1>IF@-`Rvx-m=3qhDK;)BBG-$Tu}4Dt+a0HnK+ z-fM*NXFSd=9C(5#g1YBxco0JP&I24>9GwuvOZ@tj7tySHcvK`4l>tgv)$<|f<`Yu- zq0PQ2T-S0U98xAuU(O|^XjL@H3??y&EqLoOg{05_x$y18akRp4l5p(M!=-ZzR@I#f zjsvb~vzUSpO+FT0uL>Qx7N?ZS&A+aL%St5-KJ5EMLJ4@9#avYyzGGu#rT*UeYZ%Wj zs-YgnLBF?e-ayrEyj&Buxv7Z0U4}b%igahUJ4OJWaGOC^Lu2*K`|7cWn)+k6y`d?a zL-%2;S%N=q&NbdE7)M2Y+LdI}v>H$YQ7H8V!d+9A)od9ZhL5{1+TTT(J{rsf8j{Xa zx-AiE5!qDk&AICfD(REKL;Dh4Hjj{Ruu6FMyy#wxkc5`Z*Y3)d>=Kd2ST=33)WHlL zr^}2q6r0&;ayLZtt*KPB@iHHogVFZIfzkFAeJv4t(+yJ^@AEOlx`VXm&*2S&a@qC` z&UQ8uJAv@>=%|R|#(Tdb z_jsLxvJ$7jy%jy<^VvMSr+Q^Ux@1F_{pxaA-tAh8 z6i3~?5rx>~_U$VKxs=0(Lgt%AOdW-Fea{SHUmtsB@6EB$IB@D_b3h)+flJKDP3%ci zda?>u{TSD5RDHL$#fdx*Ar~3xP$d9B$<{F$=+7gmq)Sql27wEMlYY8Ep}mBb7wdtt zw!B>R1l7cSgS}9o&i}mUVu5Y-iqs7#8Cw`|CxfHFix5 z+dn{RT{C>VtF7IB7BbQ!w0Y*U6tP8mI#MLj09CTt#edV_{Q*+0MN_(=*g&G=ujEKL z+qpgS1*jC1siYco^1s8qHglPntZ>?jtDYjk669~=YI&?Q zO8t*oB}0#g#!17Pn$bjkvue%8Du5P}#yVmD*c}wdwyuv!GNaVYRW$XtF%12EIU_ZG z|8Ba@d3!a`P9$8$;i#sKyP-(Pq#iJ(po&<2`Nn0?XJ;Qy-*~Xv^Ln?Kzg>|lE+4-h zWr&syp8%0Z>n?5{-+X2{)()3s%fi2okP(IbR07)$A#?qKC)Mgvm2@B&$<~pw1uFRa zw6d>SsC$OHnJzJcjp5Pzm8jUC)Sts_{e`#x=D%aTd#jrVL_IE{<2o`th$GE4a4w(h zP6aXCFZYjPDkoQr)v7OHj?p)hwX{TOf>i}w2{DwIB`J|$XMeWT=i$_Kd#<0psBT48&+|Hg|Zcu zUfkGF1Sx`qE-D~RDIy(>G$kN41PB39umDk{LnzXuNS97P(S%+?2@s0X0)zxfXd#4r zE9~bv=X~!E_yNgUcbR+cnQN|@8OvWSf-r3^f1w*SAmNOA=0>w-j6}Ht`STOz$-i)O)RzlCT`KR?H*&dVYzzJ5RK6)OJlf0;-1P@m4jS z$eC5U6{;@vcS6f{a7K-8UiiC;_m28rvKJI5uOZFdBlLpvmJG||mQqyg<1@A+AE@&+`G>s?_;^|# z!M)LA(91ltT6Q=p^|5f$cx{L(B#*;(r^XmsPf>Qec+WwFr!z%&y4aL%@PX4^E4x(V zj!4Aj_k1N1fhe1>O5!#yxWF*8LWb|Ivq{cFYZuDCzUecP&bX1Ny!0`tL!Q(N$?;_O z`yfq!zUW!DBj=8~Vqm#njxoNzfEHK`Y9HoAecgR=@?f@7tHmo`RWXnz_UD4JT>eYm z5TvBJ`*dT_hJ_?@qqKuHkkB0vA%ej&*nj%>*TXefz2^Fiu$=^y?aPWK8{m@ z<^7xoPairC%lgoy|NObE&L_WnckF)=bIu(|HS~u+l&exk_ zC*DqS6!21b6@=iuyHJ%a5Lp9zJrk<6Wk3UgHdPQ?Ta!p_E!W2f|xp~FJ#oN-Ke2lJjUYJ`3ecTy(&a4YdZE2fy8VapUlvWQUXkd^#^=4?d*!nHQqz0)ki38CN!~Y*$ko0mZpy$F*UX+c+?(-GS0uZ+NaYIlBi|& zA}HTrk5!7yO@7y)W91*dVtkO&p!d#uKr)t?zWl8;b-CyAoFW&e!SLN`m81!iD}@#W zhvmyNM|@=m^Sbz^4G6CCq{mJzLN5n4?}Qbu*MD(cn0;edfW+p9ddL5i2CT55cuhjI z^vbb$l`p1?#QW&;g+NjU`)JauHtM_7Thu&^O5VLQJKWcB*crzwe=x&Xz=n|p?%}>E z4a)EpR5EiNd^H?L1^WQx1`?E+cktFBSQGVtzQCMXqK?xwzUL>MMqR8IBU&GHYyYg6 zH)&6nev#>|caG6vpXM(xQ+xi!5=03e;FhJqXJV?8!TO9J@7@`}mXetDms0vDM~6I< zXEa!>_d%Wp`!QfEjX^$tyWwe732(~c_(<{#vkjMoGBK2*sNlKDVvAtk?tpP+!aDf! zWQ|^7b;@JmRiEjG4Dj-b&!p-&q5Al^EaEA=Oumy3_if~d)?GAg^>FDPX%p?mSoE zJzfBEVrGEFprIzGVVT74kEXEu|FU7M4Yxa1yYKy+OeGu(Q#Rmw?ayO|+7B>pZ(H?X z5?TPMVKYxkS)i-13~^A7DasztfZyNiz!S_snR(yF^Ch9Od{kKjdr36qu}zxavxaBM z;M7b3b4wOsL##G$xyR0~b#CH)Cd15o&3s${xEg>X2WT#2o`nt39a{Hjq#Cq;FFbgx z3inzcoo`6Hw|6OLNlFzU|4l#ZM$32I?b2O0cs<#FhtybF1E-kL#liXJ3Fk+K8v|-S z!Nv2%O(!DN;nZruEBWQm=u*dXysCHzv4;A>>{#_VgVWUG?tY(Z1`0p%i-)I%Je>fN z8}bBRc)zM#M!wNw_)1{{N5tzk|0?Bmbt>UKljoT9gvUST`tz|ZZ)ow@ll58 z2%oV^)J~o2Je=zSQ!G1BSo~nHYN;q8IIo`7M7Pk`vIud#_2kI{i|d@{RIuXg?2kA6 z#Mw9eblG}&m#6LKwRjCs{&7&~a;yYam2VNDX-@opZ-t9^f?%X~<>1lXxt|tGj=R6N zidhM$ctRXaiZFSOl}VPPQ8h2S7X9A#wBdapYw6zn#RtJ3Pc!W3(pCS!nd$je6mJ*0 zuu4vAP^j_zyZq{8>qdTQlUrke#g|%BN&Kn&ODgreW~>=SFMB3^r)*fW!5h4WzX^0g z9afQd(fFdCx%K=0S#X}e&=J*Y`??=W;y`Uqk}Vz%0A73kP`C0fW&GqhT&1a+zX7C7 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