| import os |
| import torch |
| import argparse |
| import torch.nn as nn |
| import numpy as np |
| from tqdm.auto import tqdm |
| from torch.utils.data import DataLoader |
| import torch.nn as nn |
| import torch |
| import random |
| from torch import nn |
| from torch.optim import * |
| from torch.optim.lr_scheduler import * |
| from torch.utils.data import DataLoader |
| from torchprofile import profile_macs |
| from torchvision.datasets import * |
| from torchvision.transforms import * |
| from proard.model_zoo import DYN_net |
| from proard.nas.accuracy_predictor import AccuracyPredictor,ResNetArchEncoder,RobustnessPredictor,MobileNetArchEncoder,Accuracy_Robustness_Predictor |
| from proard.nas.efficiency_predictor import ResNet50FLOPsModel,Mbv3FLOPsModel,ProxylessNASFLOPsModel |
| from proard.nas.search_algorithm import EvolutionFinder,DynIndividual_mbv,DynIndividual_res,DynRandomSampler,DynProblem_mbv,DynProblem_res,DynSampling,individual_to_arch_res,individual_to_arch_mbv |
| from utils.profile import trainable_param_num |
| from pymoo.core.individual import Individual |
| from pymoo.core.mutation import Mutation |
| from pymoo.core.population import Population |
| from pymoo.core.problem import Problem |
| from pymoo.core.sampling import Sampling |
| from pymoo.core.variable import Choice |
| from pymoo.operators.crossover.ux import UniformCrossover |
| from pymoo.operators.mutation.pm import PolynomialMutation |
| from pymoo.operators.mutation.rm import ChoiceRandomMutation |
| from pymoo.operators.selection.rnd import RandomSelection |
| from pymoo.operators.selection.tournament import TournamentSelection |
| from pymoo.algorithms.moo.nsga2 import NSGA2 |
| from pymoo.algorithms.moo.sms import SMSEMOA |
| from pymoo.algorithms.moo.spea2 import SPEA2 |
| from pymoo.optimize import minimize |
| from pymoo.termination import get_termination |
| from pymoo.termination.default import DefaultMultiObjectiveTermination |
| from pymoo.core.callback import Callback |
| from pymoo.util.display.column import Column |
| from pymoo.util.display.output import Output |
| from proard.classification.run_manager import ClassificationRunConfig, RunManager |
| parser = argparse.ArgumentParser() |
| parser.add_argument( |
| "-p", "--path", help="The path of cifar10", type=str, default="/dataset/cifar10" |
| ) |
| parser.add_argument("-g", "--gpu", help="The gpu(s) to use", type=str, default="all") |
| parser.add_argument( |
| "-b", |
| "--batch-size", |
| help="The batch on every device for validation", |
| type=int, |
| default=100, |
| ) |
| parser.add_argument("-j", "--workers", help="Number of workers", type=int, default=20) |
| parser.add_argument( |
| "-n", |
| "--net", |
| metavar="DYNNET", |
| default="ResNet50", |
| choices=[ |
| "ResNet50", |
| "MBV3", |
| "ProxylessNASNet", |
| ], |
| help="dynamic networks", |
| ) |
| parser.add_argument( |
| "--dataset", type=str, default="cifar10" ,choices=["cifar10", "cifar100", "imagenet"] |
| ) |
| parser.add_argument( |
| "--attack", type=str, default="linf-pgd" ,choices=['fgsm', 'linf-pgd', 'fgm', 'l2-pgd', 'linf-df', 'l2-df', 'linf-apgd', 'l2-apgd','squar_attack','autoattack','apgd_ce'] |
| ) |
| parser.add_argument("--train_criterion", type=str, default="trades",choices=["trades","sat","mart","hat"]) |
| parser.add_argument( |
| "--robust_mode", type=bool, default=True |
| ) |
| args = parser.parse_args() |
| if args.gpu == "all": |
| device_list = range(torch.cuda.device_count()) |
| args.gpu = ",".join(str(_) for _ in device_list) |
| else: |
| device_list = [int(_) for _ in args.gpu.split(",")] |
| os.environ["CUDA_VISIBLE_DEVICES"] = args.gpu |
| args.batch_size = args.batch_size * max(len(device_list), 1) |
| run_config = ClassificationRunConfig(attack_type=args.attack, dataset= args.dataset, test_batch_size=args.batch_size, n_worker=args.workers,robust_mode=args.robust_mode) |
| dyn_network = DYN_net(args.net,args.robust_mode,args.dataset,args.train_criterion, pretrained=True,run_config=run_config) |
| if args.net == "ResNet50": |
| efficiency_predictor = ResNet50FLOPsModel(dyn_network) |
| arch = ResNetArchEncoder(image_size_list=[32],depth_list=[0,1,2],expand_list=[0.2,0.25,0.35],width_mult_list=[0.65,0.8,1.0]) |
| accuracy_robustness_predictor = Accuracy_Robustness_Predictor(arch) |
| accuracy_robustness_predictor.load_state_dict(torch.load("./acc_rob_data_{}_{}_{}/src/model_acc_rob.pth".format(args.dataset,args.net,args.train_criterion))) |
| elif args.net == "MBV3": |
| efficiency_predictor = Mbv3FLOPsModel(dyn_network) |
| arch = MobileNetArchEncoder(image_size_list=[32],depth_list=[2,3,4],expand_list=[3,4,6],ks_list=[3,5,7]) |
| accuracy_robustness_predictor = Accuracy_Robustness_Predictor(arch) |
| accuracy_robustness_predictor.load_state_dict(torch.load("./acc_rob_data_{}_{}_{}/src/model_acc_rob.pth".format(args.dataset,args.net,args.train_criterion))) |
| elif args.net == "ProxylessNASNet": |
| efficiency_predictor = ProxylessNASFLOPsModel(dyn_network) |
| arch = MobileNetArchEncoder(image_size_list=[32],depth_list=[2,3,4],expand_list=[3,4,6],width_mult_list=[3,5,7]) |
| accuracy_robustness_predictor = Accuracy_Robustness_Predictor(arch) |
| accuracy_robustness_predictor.load_state_dict(torch.load("./acc_rob_data_{}_{}_{}/src/model_acc_rob.pth".format(args.dataset,args.net,args.train_criterion))) |
| |
| dyn_sampler = DynRandomSampler(arch, efficiency_predictor) |
| |
| |
| |
| |
| |
|
|
| """ Hyperparameters |
| - P: size of the population in each generation (number of individuals) |
| - N: number of generations to run the algorithm |
| - mutate_prob: probability of gene mutation in the evolutionary search |
| """ |
| P = 100 |
| N = 100 |
| mutation_prob = 0.5 |
|
|
|
|
| |
| if args.net == 'ResNet50': |
| search_space = { |
| 'e': [0.2, 0.25, 0.35], |
| 'd': [0, 1, 2], |
| 'w': [0 ,1 ,2], |
| 'image_size': [32] |
| } |
| else: |
| search_space = { |
| 'ks': [3, 5, 7], |
| 'e': [3, 4, 6], |
| 'd': [2, 3, 4], |
| 'image_size': [32] |
| } |
|
|
| |
| |
| num_blocks = arch.max_n_blocks |
| num_stages = arch.n_stage |
| Flops_constraints = 1600 |
| if args.net == "ResNet50": |
| problem = DynProblem_res(efficiency_predictor, accuracy_robustness_predictor, num_blocks, num_stages, search_space,Flops_constraints) |
| else: |
| problem = DynProblem_mbv(efficiency_predictor, accuracy_robustness_predictor, num_blocks, num_stages, search_space,Flops_constraints) |
|
|
|
|
|
|
|
|
|
|
| mutation_rc = ChoiceRandomMutation(prob=1.0, prob_var=0.1) |
| crossover_ux = UniformCrossover(prob=1.0) |
| |
| |
| |
| |
| termination_default = DefaultMultiObjectiveTermination( |
| xtol=1e-8, cvtol=1e-6, ftol=0.0025, period=30, n_max_gen=1000, n_max_evals=100000 |
| ) |
| termination_gen = get_termination("n_gen", N) |
| np.random.seed(42) |
| random.seed(42) |
| if args.net=="ResNet50": |
| init_pop = Population(individuals=[DynIndividual_res(dyn_sampler.random_sample(), accuracy_robustness_predictor) for _ in range(P)]) |
| else: |
| init_pop = Population(individuals=[DynIndividual_mbv(dyn_sampler.random_sample(), accuracy_robustness_predictor) for _ in range(P)]) |
|
|
| algorithm = NSGA2( |
| pop_size=P, |
| sampling=DynSampling(), |
| |
| crossover=crossover_ux, |
| mutation=mutation_rc, |
| |
| |
| |
| |
| ) |
| res_nsga2 = minimize( |
| problem, |
| algorithm, |
| termination=termination_gen, |
| seed=1, |
| |
| verbose=False, |
| save_history=True, |
| ) |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
|
|
| |
| |
|
|
|
|
| np.savetxt("./results/acc_gen0.csv", 100-res_nsga2.history[0].pop.get('F')[:,0], delimiter=",") |
|
|
| np.savetxt("./results/acc_gen99.csv", 100-res_nsga2.history[99].pop.get('F')[:,0], delimiter=",") |
| np.savetxt("./results/rob_gen0.csv", 100-res_nsga2.history[0].pop.get('F')[:,1], delimiter=",") |
|
|
| np.savetxt("./results/rob_gen99.csv", 100-res_nsga2.history[99].pop.get('F')[:,1], delimiter=",") |
| np.savetxt("./results/flops_gen99.csv", res_nsga2.history[99].pop.get('G'), delimiter=",") |
|
|
| |
|
|
| from matplotlib import pyplot as plt |
| from matplotlib.ticker import FormatStrFormatter |
| from matplotlib.ticker import AutoMinorLocator, MultipleLocator |
| |
| x_min, x_max, y_min, y_max = 80, 93, 47, 56 |
| ax_limits = [x_min, x_max, y_min, y_max] |
| |
| |
| fig, ax = plt.subplots(dpi=600) |
| gen0 = 0 |
| gen1 = 99 |
| print(100-res_nsga2.history[gen1].pop.get('F')[:,0], 100 - res_nsga2.history[gen1].pop.get('F')[:,1]) |
| |
| |
| ax.plot(100-res_nsga2.history[gen0].pop.get('F')[:,0], 100 - res_nsga2.history[gen0].pop.get('F')[:,1] , 'o', label=f'Population at generation #{gen0+1}', color='red', alpha=0.5) |
| ax.plot(100-res_nsga2.history[gen1].pop.get('F')[:,0], 100 - res_nsga2.history[gen1].pop.get('F')[:,1] , 'o', label=f'Population at generation #{gen1+1}', color='green', alpha=0.5) |
| |
| |
| |
| |
| ax.grid(True, linestyle=':') |
| ax.set_xlabel('Accuracy (%)') |
| ax.set_ylabel('Robustness (%)') |
| ax.set_title('NSGA-II solutions progression For Fixed number of FLOPs'), |
| ax.legend() |
| |
| |
| ax.xaxis.set_major_locator(MultipleLocator(1)) |
| ax.xaxis.set_minor_locator(MultipleLocator(1)) |
| |
| ax.yaxis.set_major_locator(MultipleLocator(1)) |
| ax.yaxis.set_minor_locator(MultipleLocator(1)) |
| |
| ax.set(xlim=(ax_limits[0], ax_limits[1]), ylim=(ax_limits[2], ax_limits[3])) |
| |
| plt.savefig('nsga2_pop_progression_debug.png') |
| fig.set_dpi(100) |
| |
|
|
|
|
|
|
| |
|
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |