def build_model(self): self.args.share_param = False self.with_retrain = True self.args.shared_initial_step = 0 if self.args.search_mode == "macro": # generate model description in macro way (generate entire network description) from graphnas.search_space import MacroSearchSpace search_space_cls = MacroSearchSpace() self.search_space = search_space_cls.get_search_space() # layers_of_child_model is 2 self.action_list = search_space_cls.generate_action_list( self.args.layers_of_child_model) # build RNN controller from graphnas.graphnas_controller import SimpleNASController self.controller = SimpleNASController( self.args, action_list=self.action_list, search_space=self.search_space, cuda=self.args.cuda) if self.args.dataset in ["cora", "citeseer", "pubmed"]: # implements based on dgl self.submodel_manager = CitationGNNManager(self.args) if self.args.dataset in ["Cora", "Citeseer", "Pubmed"]: # implements based on pyg self.submodel_manager = GeoCitationManager(self.args) if self.args.search_mode == "micro": self.args.format = "micro" self.args.predict_hyper = True if not hasattr(self.args, "num_of_cell"): self.args.num_of_cell = 2 from graphnas_variants.micro_graphnas.micro_search_space import IncrementSearchSpace search_space_cls = IncrementSearchSpace() search_space = search_space_cls.get_search_space() from graphnas.graphnas_controller import SimpleNASController from graphnas_variants.micro_graphnas.micro_model_manager import MicroCitationManager self.submodel_manager = MicroCitationManager(self.args) self.search_space = search_space action_list = search_space_cls.generate_action_list( cell=self.args.num_of_cell) if hasattr(self.args, "predict_hyper") and self.args.predict_hyper: self.action_list = action_list + [ "learning_rate", "dropout", "weight_decay", "hidden_unit" ] else: self.action_list = action_list self.controller = SimpleNASController( self.args, action_list=self.action_list, search_space=self.search_space, cuda=self.args.cuda) if self.cuda: self.controller.cuda() if self.cuda: self.controller.cuda()
def build_model(self): if self.args.search_mode == "macro": search_space_cls = MacroSearchSpace() self.search_space = search_space_cls.get_search_space() self.action_list = search_space_cls.generate_action_list( self.args.layers_of_child_model) # build RNN controller if self.args.dataset in ["cora", "citeseer", "pubmed"]: # implements based on dgl self.submodel_manager = CitationGNNManager(self.args) if self.args.dataset in ["Cora", "Citeseer", "Pubmed", "CS", "Physics", "Computers", "Photo"]: # implements based on pyg self.submodel_manager = GeoCitationManager(self.args) print("Search space:") print(self.search_space) print("Generated Action List: ") print(self.action_list)
def build_model(self): self.args.share_param = False self.with_retrain = True self.args.shared_initial_step = 0 if self.args.search_mode == "macro": # generate model description in macro way (generate entire network description) from graphnas.search_space import MacroSearchSpace search_space_cls = MacroSearchSpace() self.search_space = search_space_cls.get_search_space() self.action_list = search_space_cls.generate_action_list(self.args.layers_of_child_model) # build RNN controller from graphnas.graphnas_controller import SimpleNASController self.controller = SimpleNASController(self.args, action_list=self.action_list, search_space=self.search_space, cuda=self.args.cuda) if self.args.dataset in ["Cora", "Citeseer", "Pubmed"]: # implements based on pyg self.submodel_manager = GeoCitationManager(self.args) if self.cuda: self.controller.cuda()
def eval(chromosome): args = build_args() dataset_list = ["Citeseer", "Pubmed", "cora"] base_list = [ "pyg", "pyg", "dgl", ] for dataset, actions, base in zip(dataset_list, chromosome, base_list): # if dataset == "cora": # continue args.dataset = dataset if base == "dgl": manager = CitationGNNManager(args) else: manager = GeoCitationManager(args) val_acc, test_acc = manager.evaluate(actions) print(test_acc) print("_" * 80) return test_acc
def build_model(self): if self.args.search_mode == "macro": # generate model description in macro way # (generate entire network description) search_space_cls = MacroSearchSpace() self.search_space = search_space_cls.get_search_space() self.action_list = search_space_cls.generate_action_list( self.args.layers_of_child_model) # build RNN controller if self.args.dataset in ["cora", "citeseer", "pubmed"]: # implements based on dgl self.submodel_manager = CitationGNNManager(self.args) if self.args.dataset in [ "Cora", "Citeseer", "Pubmed", "CS", "Physics", "Computers", "Photo" ]: # implements based on pyg self.submodel_manager = GeoCitationManager(self.args) if self.args.search_mode == "micro": self.args.format = "micro" self.args.predict_hyper = True if not hasattr(self.args, "num_of_cell"): self.args.num_of_cell = 2 search_space_cls = IncrementSearchSpace() search_space = search_space_cls.get_search_space() self.submodel_manager = MicroCitationManager(self.args) self.search_space = search_space action_list = search_space_cls.generate_action_list( cell=self.args.num_of_cell) if hasattr(self.args, "predict_hyper") and self.args.predict_hyper: self.action_list = action_list + [ "learning_rate", "dropout", "weight_decay", "hidden_unit" ] else: self.action_list = action_list print("Search space:") print(self.search_space) print("Generated Action List: ") print(self.action_list)
if __name__ == "__main__": args = build_args() gnn_list = [ ['gat', 'sum', 'linear', 4, 128, 'linear', 'sum', 'elu', 8, 6], ['gcn', 'sum', 'tanh', 6, 64, 'cos', 'sum', 'tanh', 6, 3], ['const', 'sum', 'relu6', 2, 128, 'gat', 'sum', 'linear', 2, 7], ] dataset_list = ["Citeseer", "Pubmed", "cora"] base_list = [ "pyg", "pyg", "dgl", ] for dataset, actions, base in zip(dataset_list, gnn_list, base_list): # if dataset == "cora": # continue args.dataset = dataset if base == "dgl": manager = CitationGNNManager(args) else: manager = GeoCitationManager(args) test_scores_list = [] for i in range(100): val_acc, test_acc = manager.evaluate(actions) test_scores_list.append(test_acc) print("_" * 80) test_scores_list.sort() print(dataset, np.mean(test_scores_list[5:-5]), np.std(test_scores_list[5:-5]))
class Trainer(object): """Manage the training process""" def __init__(self, args): """ Constructor for training algorithm. Build sub-model manager and controller. Build optimizer and cross entropy loss for controller. Args: args: From command line, picked up by `argparse`. """ self.args = args self.build_model() # build controller and sub-model def _construct_action(self, actions): structure_list = [] for single_action in actions: structure = [] print('single_chromosome:', single_action) for action, action_name in zip(single_action, self.action_list): predicted_actions = self.search_space[action_name][action] structure.append(predicted_actions) structure_list.append(structure) return structure_list def build_model(self): if self.args.search_mode == "macro": search_space_cls = MacroSearchSpace() self.search_space = search_space_cls.get_search_space() self.action_list = search_space_cls.generate_action_list( self.args.layers_of_child_model) # build RNN controller if self.args.dataset in ["cora", "citeseer", "pubmed"]: # implements based on dgl self.submodel_manager = CitationGNNManager(self.args) if self.args.dataset in ["Cora", "Citeseer", "Pubmed", "CS", "Physics", "Computers", "Photo"]: # implements based on pyg self.submodel_manager = GeoCitationManager(self.args) print("Search space:") print(self.search_space) print("Generated Action List: ") print(self.action_list) # 基于搜索空间,对结构空间进行数字编码,并使用随机初始化获得个体组建种群 def _generate_random_individual(self): ind = [] # 每个action operator 使用数字编码,对每个action 随机采样 for action in self.action_list: ind.append(np.random.randint(0, len(self.search_space[action]))) return ind # 基于个体编码进行解码还原成GNN结构列表,为GNN建模做准备 def _construct_action(self, actions): structure_list = [] for single_action in actions: structure = [] print('single_chromosome:', single_action) for action, action_name in zip(single_action, self.action_list): predicted_actions = self.search_space[action_name][action] structure.append(predicted_actions) structure_list.append(structure) return structure_list def form_gnn_info(self, gnn): if self.args.search_mode == "micro": actual_action = {} if self.args.predict_hyper: actual_action["action"] = gnn[:-4] actual_action["hyper_param"] = gnn[-4:] else: actual_action["action"] = gnn actual_action["hyper_param"] = [0.005, 0.8, 5e-5, 128] return actual_action return gnn def derive_from_history(self): with open(self.args.dataset + self.args.submanager_log_file) as f: lines = f.readlines() results = [] for line in lines: actions = line[:line.index(";")] val_score = line.split(";")[-1] results.append((actions, val_score)) results.sort(key=lambda x: x[-1], reverse=True) best_structure = "" best_score = 0 for actions in results[:5]: actions = eval(actions[0]) np.random.seed(123) torch.manual_seed(123) torch.cuda.manual_seed_all(123) val_scores_list = [] for i in range(20): val_acc, test_acc = self.submodel_manager.evaluate(actions) val_scores_list.append(val_acc) tmp_score = np.mean(val_scores_list) if tmp_score > best_score: best_score = tmp_score best_structure = actions print("best structure:" + str(best_structure)) # train from scratch to get the final score np.random.seed(123) torch.manual_seed(123) torch.cuda.manual_seed_all(123) test_scores_list = [] for i in range(100): # manager.shuffle_data() val_acc, test_acc = self.submodel_manager.evaluate(best_structure) test_scores_list.append(test_acc) print(f"best results: {best_structure}: {np.mean(test_scores_list):.8f} +/- {np.std(test_scores_list)}") return best_structure
# sys.path.extend(['/GraphNAS']) from graphnas_variants.macro_graphnas.pyg.pyg_gnn_model_manager import GeoCitationManager from eval_scripts.semi.eval_designed_gnn import build_args torch.manual_seed(123) torch.cuda.manual_seed_all(123) if __name__ == "__main__": args = build_args() gnn_list = [[ 'generalized_linear', 'sum', 'leaky_relu', 6, 16, 'gat', 'sum', 'leaky_relu', 1, 7 ], ['gat_sym', 'sum', 'linear', 4, 256, 'cos', 'sum', 'softplus', 2, 6], [ 'const', 'sum', 'relu', 4, 32, 'generalized_linear', 'sum', 'leaky_relu', 8, 3 ]] dataset_list = ["Cora", "Citeseer", "Pubmed"] for dataset, actions in zip(dataset_list, gnn_list): args.dataset = dataset manager = GeoCitationManager(args) test_scores_list = [] for i in range(100): val_acc, test_acc = manager.evaluate(actions) test_scores_list.append(test_acc) print("_" * 80) test_scores_list.sort() print(dataset, np.mean(test_scores_list[5:-5]), np.std(test_scores_list[5:-5]))
class RL_Trainer(object): def __init__(self, args): self.args = args self.controller_step = 0 # counter for controller self.cuda = args.cuda self.epoch = 0 self.start_epoch = 0 self.max_length = self.args.shared_rnn_max_length self.with_retrain = False self.submodel_manager = None self.controller = None self.build_model() # build controller and sub-model self.RL_train_time = [] self.RL_search_time = [] self.RL_train_acc = [] self.RL_search_acc = [] controller_optimizer = _get_optimizer(self.args.controller_optim) self.controller_optim = controller_optimizer(self.controller.parameters(), lr=self.args.controller_lr) if self.args.mode == "derive": self.load_model() def build_model(self): self.args.share_param = False self.with_retrain = True self.args.shared_initial_step = 0 if self.args.search_mode == "macro": # generate model description in macro way (generate entire network description) from graphnas.search_space import MacroSearchSpace search_space_cls = MacroSearchSpace() self.search_space = search_space_cls.get_search_space() self.action_list = search_space_cls.generate_action_list(self.args.layers_of_child_model) # build RNN controller from graphnas.graphnas_controller import SimpleNASController self.controller = SimpleNASController(self.args, action_list=self.action_list, search_space=self.search_space, cuda=self.args.cuda) if self.args.dataset in ["Cora", "Citeseer", "Pubmed"]: # implements based on pyg self.submodel_manager = GeoCitationManager(self.args) if self.cuda: self.controller.cuda() def form_gnn_info(self, gnn): if self.args.search_mode == "micro": actual_action = {} if self.args.predict_hyper: actual_action["action"] = gnn[:-4] actual_action["hyper_param"] = gnn[-4:] else: actual_action["action"] = gnn actual_action["hyper_param"] = [0.005, 0.8, 5e-5, 128] return actual_action return gnn def train(self, action_list): model_path = "/home/jerry/experiment/RL_nas/graphnas/Citeseer" # Training the controller if not os.listdir(model_path):# 判断保存controler模型的文件夹是否为空,为空返回False,反之为Ture self.train_controller() print("*" * 35, "using controller search the initialize population", "*" * 35) populations, accuracies = self.derive(self.args.population_size, action_list) print("*" * 35, "the search DONE", "*" * 35) self.save_model() else: self.load_model() # 每次加载step序号最大controler模型search print("*" * 35, "using controller search the initialize population", "*" * 35) populations, accuracies = self.derive(self.args.population_size, action_list) print("*" * 35, "the search DONE", "*" * 35) return populations, accuracies def derive(self, sample_num, action_list): if sample_num is None and self.args.derive_from_history: return self.derive_from_history() else: if sample_num is None: sample_num = self.args.derive_num_sample gnn_list, _, entropies = self.controller.sample(sample_num, with_details=True) accuracies = [] epoch = 0 for action in gnn_list: once_RL_search_start_time = time.time() gnn = self.form_gnn_info(action) reward = self.submodel_manager.test_with_param(gnn, format=self.args.format, with_retrain=self.with_retrain) acc_score = reward[1] accuracies.append(acc_score) once_RL_search_end_time = time.time() print("the", epoch, "epcoh controller train time: ", once_RL_search_end_time - once_RL_search_start_time, 's') if epoch == 0: self.RL_search_time.append(once_RL_search_start_time) self.RL_search_time.append(once_RL_search_end_time) self.RL_search_acc.append(acc_score) else: self.RL_search_time.append(once_RL_search_end_time) self.RL_search_acc.append(acc_score) epoch += 1 father_path = path_get()[0] experiment_data_save("controler_search.txt", self.RL_search_time, self.RL_search_acc) print("all RL search time list: ", self.RL_search_time) print("all RL search acc list: ", self.RL_search_acc) for individual, ind_acc in zip(gnn_list, accuracies): print("individual:", individual, " val_score:", ind_acc) # gnn_structure 基因编码 population = [] for gnn_structure in gnn_list: i = 0 single = [] for operator, action_name in zip(gnn_structure, action_list): if i == 9: operator = 8 i += 1 single.append(self.search_space[action_name].index(operator)) population.append(single) return population, accuracies def save_model(self): torch.save(self.controller.state_dict(), self.controller_path) torch.save(self.controller_optim.state_dict(), self.controller_optimizer_path) logger.info(f'[*] SAVED: {self.controller_path}') epochs, shared_steps, controller_steps = self.get_saved_models_info() for epoch in epochs[:-self.args.max_save_num]: paths = glob.glob( os.path.join(self.args.dataset, f'*_epoch{epoch}_*.pth')) for path in paths: utils.remove_file(path) def load_model(self): epochs, shared_steps, controller_steps = self.get_saved_models_info() if len(epochs) == 0: logger.info(f'[!] No checkpoint found in {self.args.dataset}...') return self.epoch = self.start_epoch = max(epochs) self.controller_step = max(controller_steps) self.controller.load_state_dict( torch.load(self.controller_path)) self.controller_optim.load_state_dict( torch.load(self.controller_optimizer_path)) logger.info(f'[*] LOADED: {self.controller_path}') def get_reward(self, gnn_list, entropies, hidden): """ Computes the reward of a single sampled model on validation data. """ if not isinstance(entropies, np.ndarray): entropies = entropies.data.cpu().numpy() if isinstance(gnn_list, dict): gnn_list = [gnn_list] if isinstance(gnn_list[0], list) or isinstance(gnn_list[0], dict): pass else: gnn_list = [gnn_list] # when structure_list is one structure reward_list = [] for gnn in gnn_list: gnn = self.form_gnn_info(gnn) reward = self.submodel_manager.test_with_param(gnn, format=self.args.format, with_retrain=self.with_retrain) if reward is None: # cuda error hanppened reward = 0 else: rewards = reward[0]#奖励计算正确 reward_list.append(rewards) acc_validation = reward[1] if self.args.entropy_mode == 'reward': rewards = reward_list + self.args.entropy_coeff * entropies elif self.args.entropy_mode == 'regularizer': rewards = reward_list * np.ones_like(entropies) else: raise NotImplementedError(f'Unkown entropy mode: {self.args.entropy_mode}') return rewards, hidden, acc_validation def train_controller(self): """ Train controller to find better structure. """ print("*" * 35, "training controller", "*" * 35) model = self.controller model.train() baseline = None adv_history = [] entropy_history = [] reward_history = [] hidden = self.controller.init_hidden(self.args.batch_size) total_loss = 0 for step in range(self.args.controller_max_step): #contraller训练一次的时间 once_controller_train_start_time = time.time() # sample graphnas structure_list, log_probs, entropies = self.controller.sample(with_details=True) # calculate reward np_entropies = entropies.data.cpu().numpy() results = self.get_reward(structure_list, np_entropies, hidden) torch.cuda.empty_cache() if results: # has reward rewards, hidden, acc = results else: continue # discount if 1 > self.args.discount > 0: rewards = discount(rewards, self.args.discount) reward_history.extend(rewards) entropy_history.extend(np_entropies) # moving average baseline if baseline is None: baseline = rewards else: decay = self.args.ema_baseline_decay baseline = decay * baseline + (1 - decay) * rewards adv = rewards - baseline history.append(adv) adv = scale(adv, scale_value=0.5) adv_history.extend(adv) adv = utils.get_variable(adv, self.cuda, requires_grad=False) # policy loss loss = -log_probs * adv if self.args.entropy_mode == 'regularizer': loss -= self.args.entropy_coeff * entropies loss = loss.sum() # or loss.mean() # update self.controller_optim.zero_grad() loss.backward() if self.args.controller_grad_clip > 0: torch.nn.utils.clip_grad_norm(model.parameters(), self.args.controller_grad_clip) self.controller_optim.step() total_loss += utils.to_item(loss.data) self.controller_step += 1 torch.cuda.empty_cache() once_controller_train_end_time = time.time() print("the", step, "epcoh controller train time: ", once_controller_train_end_time-once_controller_train_start_time, "s") if step == 0: self.RL_train_time.append(once_controller_train_start_time) self.RL_train_time.append(once_controller_train_end_time) self.RL_train_acc.append(acc) else: self.RL_train_time.append(once_controller_train_end_time) self.RL_train_acc.append(acc) print("all RL train time list: ", self.RL_train_time) print("all RL train acc list: ", self.RL_train_acc) print("*" * 35, "training controller over", "*" * 35) experiment_data_save("controler_train.txt", self.RL_train_time, self.RL_train_acc) def evaluate(self, gnn): """ Evaluate a structure on the validation set. """ self.controller.eval() gnn = self.form_gnn_info(gnn) results = self.submodel_manager.retrain(gnn, format=self.args.format) if results: reward, scores = results else: return logger.info(f'eval | {gnn} | reward: {reward:8.2f} | scores: {scores:8.2f}') @property def model_info_filename(self): return f"{self.args.dataset}_{self.args.search_mode}_{self.args.format}_results.txt" @property def controller_path(self): return f'{self.args.dataset}/controller_epoch{self.epoch}_step{self.controller_step}.pth' @property def controller_optimizer_path(self): return f'{self.args.dataset}/controller_epoch{self.epoch}_step{self.controller_step}_optimizer.pth' def get_saved_models_info(self): paths = glob.glob(os.path.join(self.args.dataset, '*.pth')) paths.sort() def get_numbers(items, delimiter, idx, replace_word, must_contain=''): return list(set([int( name.split(delimiter)[idx].replace(replace_word, '')) for name in items if must_contain in name])) basenames = [os.path.basename(path.rsplit('.', 1)[0]) for path in paths] epochs = get_numbers(basenames, '_', 1, 'epoch') shared_steps = get_numbers(basenames, '_', 2, 'step', 'shared') controller_steps = get_numbers(basenames, '_', 2, 'step', 'controller') epochs.sort() shared_steps.sort() controller_steps.sort() return epochs, shared_steps, controller_steps
class Evolution_Trainer(object): """ This class implements the Asyncronous Aging Evolution, proposed by Real et. al. on: Regularized Evolution for Image Classifier Architecture Search available on: https://arxiv.org/abs/1802.01548 """ def __init__(self, args): self.cycle = 0 self.args = args self.random_seed = args.random_seed self.population = [] self.accuracies = [] self.population_size = args.population_size self.population_history = [] self.accuracies_history = [] self.sample_size = args.sample_size self.cycles = args.cycles self.init_time = 0 self.ev_train_time = [] self.ev_acc = [] self.ev_random_initial_time = [] self.ev_random_acc = [] self.build_model() # self.__initialize_population_Random() # 种子初始化初始化由初始化函数实现 # random初始化种群 # if self.args.initialize_mode == "random": # # 如果random_population已存在则不再初始化 # if not os.path.exists("random_population.txt"): # self.__initialize_population_Random() # else: # print("*" * 35, "random_population DONE", "*" * 35) def build_model(self): if self.args.search_mode == "macro": search_space_cls = MacroSearchSpace() self.search_space = search_space_cls.get_search_space() self.action_list = search_space_cls.generate_action_list( self.args.layers_of_child_model) # build RNN controller if self.args.dataset in ["cora", "citeseer", "pubmed"]: # implements based on dgl self.submodel_manager = CitationGNNManager(self.args) if self.args.dataset in [ "Cora", "Citeseer", "Pubmed", "CS", "Physics", "Computers", "Photo" ]: # implements based on pyg self.submodel_manager = GeoCitationManager(self.args) print("Search space:") print(self.search_space) print("Generated Action List: ") print(self.action_list) def _generate_random_individual(self): ind = [] # 每个action operator 使用数字编码,对每个action 随机采样 for action in self.action_list: ind.append(np.random.randint(0, len(self.search_space[action]))) return ind def _construct_action(self, actions): structure_list = [] for single_action in actions: structure = [] print('single_chromosome:', single_action) for action, action_name in zip(single_action, self.action_list): predicted_actions = self.search_space[action_name][action] structure.append(predicted_actions) structure_list.append(structure) return structure_list def form_gnn_info(self, gnn): if self.args.search_mode == "micro": actual_action = {} if self.args.predict_hyper: actual_action["action"] = gnn[:-4] actual_action["hyper_param"] = gnn[-4:] else: actual_action["action"] = gnn actual_action["hyper_param"] = [0.005, 0.8, 5e-5, 128] return actual_action return gnn @ray.method(num_returns=2) def initialize_population_Random(self): print("\n\n===== Random initialize the populations =====") # 随机初始化种群 start_initial_population_time = time.time() epoch = 0 while len(self.population) < self.population_size: once_random_initialize_start_time = time.time() individual = self._generate_random_individual() ind_actions = self._construct_action([individual ]) # 将基因编码解码为GNN结构空间list gnn = self.form_gnn_info(ind_actions[0]) _, ind_acc = self.submodel_manager.train(gnn, format=self.args.format) print("individual:", individual, " val_score:", ind_acc) self.accuracies.append( ind_acc) # 将种群中每个个体的acc_scores存入accuraies list self.population.append( individual) # 将种群中每个个体的基因存入 populations list once_random_initialize_end_time = time.time() print( "the", epoch, "epcoh random initialize time: ", once_random_initialize_end_time - once_random_initialize_start_time, 's') if epoch == 0: self.ev_random_initial_time.append( once_random_initialize_start_time) self.ev_random_initial_time.append( once_random_initialize_end_time) self.ev_random_acc.append(ind_acc) else: self.ev_random_initial_time.append( once_random_initialize_end_time) self.ev_random_acc.append(ind_acc) epoch += 1 end_initial_pop_time = time.time() self.init_time = end_initial_pop_time - start_initial_population_time # 计算初始化过程所需时间 print("Time elapsed initializing population: " + str(self.init_time), 's') print("===== Random initialize populations DONE ====") print("all random initialize time list: ", self.ev_random_initial_time) print("all random initialize population acc list: ", self.ev_random_acc) self.experiment_data_save( self.args.initialize_mode + "_" + self.args.dataset + "_" + self.args.evolution_sesd_name + ".txt", self.ev_random_initial_time, self.ev_random_acc) self.population_save( self.args.dataset + "_" + self.args.evolution_sesd_name + "_population.txt", self.population, self.accuracies) return self.population, self.accuracies def derive_from_population(self): population = self._construct_action(self.population) best_score_index, _ = self._get_best_individual_accuracy( self.accuracies) best_structure = self.form_gnn_info(population[best_score_index]) print("[DERIVE] Best Structure:", str(best_structure)) # train from scratch to get the final score np.random.seed(self.random_seed) torch.manual_seed(self.random_seed) torch.cuda.manual_seed_all(self.random_seed) test_scores_list = [] for i in range(10): # run 10 times to get Mean and Stddev val_acc, test_acc = self.submodel_manager.evaluate(best_structure) test_scores_list.append(test_acc) print("[DERIVE] Best Results: ", best_structure, ": ", np.mean(test_scores_list), "+/-", np.std(test_scores_list)) def _get_best_individual_accuracy(self, accs): max_acc_index = 0 max_acc = -1 for index, acc in enumerate(accs): if acc > max_acc: max_acc = acc max_acc_index = index return max_acc_index, max_acc def experiment_data_save(self, name, time_list, acc_list): path = self.path_get()[1] with open(path + "/" + name, "w") as f: f.write(str(time_list)) f.write("\n" + str(acc_list)) print("the ", name, " have written") def population_save(self, name, population, accuracies): path = self.path_get()[1] with open(path + "/" + name, "w") as f: f.write(str(population)) f.write("\n" + str(accuracies)) print("the ", name, " have written") def population_read(self, name): path = self.path_get()[1] with open(path + "/" + name, "r") as f: all_data = f.readlines() population = all_data[0][:-1] accuracies = all_data[1] population = json.loads(population) accuracies = json.loads(accuracies) return population, accuracies def path_get(self): # 当前文件目录 current_path = os.path.abspath('') # 当前文件夹父目录 father_path = os.path.abspath(os.path.dirname(current_path)) # corpus_path = os.path.join(father_path, corpus) return father_path, current_path @ray.method(num_returns=4) def train(self, history_population, history_validation_accuracy): # 传入history_population, history_validation_accuracy参数,为child fitness 做准备 print("\n\n===== Evolution ====") # 从相应的目录中读取遗传种子自己的population与accuracies,进行本次进化操作 population, accuracies = self.population_read( self.args.dataset + "_" + self.args.evolution_sesd_name + "_population.txt") child_acc_list = [] print("the original populations:\n", population) print("the original accuracies:\n", accuracies) print("[POPULATION STATS] Mean/Median/Best: ", np.mean(accuracies), np.median(accuracies), np.max(accuracies)) # 选择 获取parents parents_list = self._selection(population, accuracies) # 交叉 获取step2 child child_list = self._crossover(parents_list) # 变异 获取step2 child child_list = self._mutation(child_list) # 变异结束, 计算child_list中history_population中没有的gnn的acc # 已经存在history_population的gnn,直接从history_acc中获取 # 计算 child_gnn中的gnn的fitness for child_gnn in child_list: if child_gnn in history_population: child_acc = history_validation_accuracy[ history_population.index(child_gnn)] else: child_acc = self._fitness_computation([child_gnn]) child_acc_list.append(child_acc) return child_list, child_acc_list, population, accuracies def _fitness_computation(self, child_list): """ 在acc计算前,判断history_population中是否包含了child gnn结构,如果包含,不再计算acc 直接从history_val_acc中获取 """ for child in child_list: child_actions = self._construct_action([child]) gnn = self.form_gnn_info(child_actions[0]) _, child_acc = self.submodel_manager.train(gnn, format=self.args.format) return child_acc def _selection(self, population, accuracies): if self.args.selection_mode == "random": parent_list = [] index_list = [index for index in range(len(population))] parent_index = np.random.choice(index_list, self.sample_size, replace=False) for index in parent_index: parent_list.append(population[index].copy()) elif self.args.selection_mode == "wheel": print("wheel select") # 基于fitness计算采样概率: fitness = np.array(accuracies) fitness_probility = fitness / sum(fitness) fitness_probility = fitness_probility.tolist() index_list = [index for index in range(len(fitness))] parent_list = [] # 如果self.sample_size不是偶数,需要处理 if self.sample_size % 2 != 0: self.sample_size += 1 # 基于fitness概率采样 parent_index = np.random.choice(index_list, self.sample_size, replace=False, p=fitness_probility) for index in parent_index: parent_list.append(population[index].copy()) elif self.args.selection_mode == "wheel_reverse": print("wheel select") # 基于fitness计算反向采样概率: fitness_reverse = 1 - np.array(accuracies) fitness_probility_reverse = fitness_reverse / sum(fitness_reverse) fitness_probility_reverse = fitness_probility_reverse.tolist() index_list = [index for index in range(len(fitness_reverse))] parent_list = [] # 如果self.sample_size不是偶数,需要处理 if self.sample_size % 2 != 0: self.sample_size += 1 # 基于fitness概率采样 parent_index = np.random.choice(index_list, self.sample_size, replace=False, p=fitness_probility_reverse) for index in parent_index: parent_list.append(population[index].copy()) print("the parent_list:\n", parent_list) return parent_list def _crossover(self, parents): if self.args.crossover_mode == "single_point_crossover": print("crossover operator") child_list = [] #单点交叉 while parents: # step1:从parents list中无放回的取出一对父母 parent_1 = parents.pop() parent_2 = parents.pop() # step2:测量parent长度,随机确定交叉点: crossover_point = np.random.randint(1, len(parent_1)) # step3:对父母染色体进行交叉得到子代: # 交叉操作判断 corssover_op = np.random.choice( [True, False], 1, p=[self.args.crossover_p, 1 - self.args.crossover_p])[0] if corssover_op: child_1 = parent_1[:crossover_point] + parent_2[ crossover_point:] child_2 = parent_2[:crossover_point] + parent_1[ crossover_point:] else: child_1 = parent_1 child_2 = parent_2 child_list.append(child_1) child_list.append(child_2) print("the child_list:\n", child_list) return child_list def _mutation(self, child_list): if self.args.mutation_mode == "single_point_mutation": print("mutation operator") for index in range(len(child_list)): # 对于index的child是否发生变异判断 mutation_op = np.random.choice( [True, False], 1, p=[self.args.mutation_p, 1 - self.args.mutation_p])[0] if mutation_op: # 对索引号为Index的child 随机选择可能的变异点 position_to_mutate = np.random.randint( len(child_list[index])) sp_list = self.search_space[ self.action_list[position_to_mutate]] child_list[index][position_to_mutate] = np.random.randint( 0, len(sp_list)) print("the child_list:\n", child_list) return child_list