def get_random(self, num): print('random select ........') cand_iter = self.stack_random_cand( lambda: self.get_one_cand()) with open('ES_log.txt','a') as f: f.write('Population size is %d. We need %d.\n'%(len(self.candidates),num)) while len(self.candidates) < num: cand = next(cand_iter) if not self.is_legal(cand): continue self.candidates.append(cand) print('random {}/{}'.format(len(self.candidates), num)) '''get the performance of paths''' with open('paths.txt','w') as f: for cand in self.candidates: f.write(get_path_name(cand)+'\n') # evaluation in parallel print('Evaluating population ...') with open('paths_metric.txt','w') as f: f.write('This is a new file\n') os.system('mpiexec -n %d python Evolution/src/Search/tester_mpi.py --path_file paths.txt --total_num %d --supernet_checkpoint %s --flops_name %s --super_model_name %s' %(len(self.candidates),len(self.candidates),self.supernet_checkpoint, self.flops_name, self.super_model_name)) with open('paths_metric.txt','r') as f: path_metric_list = f.readlines() self.parse_metric(path_metric_list[1:]) print('random_num = {}'.format(len(self.candidates)))
def stack_random_cand(self, random_func, *, batchsize=10): while True: cands = [random_func() for _ in range(batchsize)] for cand in cands: cand_name = get_path_name(cand) if cand_name not in self.vis_dict: self.vis_dict[cand_name] = {} info = self.vis_dict[cand_name] for cand in cands: yield cand
def get_crossover(self, k, crossover_num): assert k in self.keep_top_k print('crossover ......') res = [] iter = 0 max_iters = 10 * crossover_num def random_func(): p1 = choice(self.keep_top_k[k]) p2 = choice(self.keep_top_k[k]) p = [None, {'cls':[None,[]], 'reg':[None,[]]}, None] p[0] = [choice([i, j]) for i, j in zip(p1[0], p2[0])] for idx_out, item_out in enumerate(zip(p1[1]['cls'],p2[1]['cls'])): if idx_out == 0: p[1]['cls'][0] = choice(item_out) else: list1, list2 = item_out for idx_in, item_in in enumerate(zip(list1, list2)): p[1]['cls'][1].append(choice(item_in)) for idx_out, item_out in enumerate(zip(p1[1]['reg'], p2[1]['reg'])): if idx_out == 0: p[1]['reg'][0] = choice(item_out) else: list1, list2 = item_out for idx_in, item_in in enumerate(zip(list1, list2)): p[1]['reg'][1].append(choice(item_in)) p[2] = choice((p1[2], p2[2])) return tuple(p) cand_iter = self.stack_random_cand(random_func) while len(res) < crossover_num and max_iters > 0: max_iters -= 1 cand = next(cand_iter) if not self.is_legal(cand): continue res.append(cand) print('crossover {}/{}'.format(len(res), crossover_num)) with open('paths.txt','w') as f: for cand in res: f.write(get_path_name(cand)+'\n') print('Evaluating crossover population ...') with open('paths_metric.txt','w') as f: f.write('This is a new file\n') os.system('mpiexec -n %d python Evolution/src/Search/tester_mpi.py --path_file paths.txt --total_num %d --supernet_checkpoint %s --flops_name %s --super_model_name %s' %(len(res), len(res), self.supernet_checkpoint, self.flops_name, self.super_model_name)) with open('paths_metric.txt','r') as f: path_metric_list = f.readlines() self.parse_metric(path_metric_list[1:]) print('crossover_num = {}'.format(len(res))) return res
def is_legal(self, cand): # assert isinstance(cand, tuple) and len(cand) == self.nr_layer assert isinstance(cand,tuple) and isinstance(cand[0],list) and isinstance(cand[1],dict) cand_name = get_path_name(cand) if cand_name not in self.vis_dict: self.vis_dict[cand_name] = {} info = self.vis_dict[cand_name] if 'visited' in info: return False if 'flops' not in info: info['flops'] = get_cand_flops(cand, mac_model_name=self.super_mac_model_name) print(cand_name, 'MACs: %.2f M'%(info['flops']/1e6)) if info['flops'] > self.flops_limit: print('flops limit exceed') return False info['visited'] = True return True
def search(self): with open('ES_time_log.txt','w') as f: f.write('Evolutionary Search begins.\n') print('population_num = {} select_num = {} mutation_num = {} crossover_num = {} random_num = {} max_epochs = {}'.format( self.population_num, self.select_num, self.mutation_num, self.crossover_num, self.population_num - self.mutation_num - self.crossover_num, self.max_epochs)) self.load_checkpoint() start = time.time() self.get_random(self.population_num) interval = time.time() - start with open('ES_time_log.txt','a') as f: f.write('Generating and Evaluating the initial population:\t%.2f mins.\n'%(interval / 60)) while self.epoch < self.max_epochs: print('epoch = {}'.format(self.epoch)) self.memory.append([]) for cand in self.candidates: self.memory[-1].append(cand) self.update_top_k( self.candidates, k=self.select_num, key=lambda x: self.vis_dict[get_path_name(x)]['acc']) self.update_top_k( self.candidates, k=50, key=lambda x: self.vis_dict[get_path_name(x)]['acc']) print('epoch = {} : top {} result'.format( self.epoch, len(self.keep_top_k[50]))) for i, cand in enumerate(self.keep_top_k[50]): print('No.{} {} Top-1 acc = {}'.format( i + 1, cand, self.vis_dict[get_path_name(cand)]['acc'])) ops = [i for i in cand] print(ops) # Mutation start_m = time.time() mutation = self.get_mutation( self.select_num, self.mutation_num, self.m_prob) interval_m = time.time() - start_m with open('ES_time_log.txt', 'a') as f: f.write('Epoch %d:\tMutation:\t%.2f mins.\n' % (self.epoch, interval_m / 60)) # CrossOver start_c = time.time() crossover = self.get_crossover(self.select_num, self.crossover_num) interval_c = time.time() - start_c with open('ES_time_log.txt', 'a') as f: f.write('Epoch %d:\tCrossOver:\t%.2f mins.\n' % (self.epoch, interval_c / 60)) self.candidates = mutation + crossover with open('ES_log.txt','a') as f: num_cand = len(self.candidates) f.write('Population size is %d\n'%num_cand) self.get_random(self.population_num) self.save_checkpoint(self.epoch) self.epoch += 1 '''2020.10.19 get the best path''' checkpoint_path = os.path.join(self.log_dir, 'checkpoint_%d.pth.tar'%(self.max_epochs-1)) info = torch.load(checkpoint_path)['vis_dict'] best_cand = sorted([cand for cand in info if 'acc' in info[cand]], key=lambda cand: info[cand]['acc'], reverse=True)[0] oup_filename = os.path.join(self.log_dir, 'best_path.txt') with open(oup_filename, 'w') as f: f.write(best_cand)
def get_mutation(self, k, mutation_num, m_prob): assert k in self.keep_top_k print('mutation ......') res = [] iter = 0 max_iters = mutation_num * 10 def random_func(): '''given one sample, get a mutated one''' # parse '''PAY ATTENTION! .copy() is necessary here, or self.keep_top_k will be modified!''' cand = choice(self.keep_top_k[k]) cand_b = deepcopy(cand[0]) cand_h_cls = deepcopy(cand[1]['cls']) cand_h_reg = deepcopy(cand[1]['reg']) cand_op = deepcopy(cand[2]) # mutatation '''backbone''' for stage_idx in range(len(self.sta_num)): for block_idx in range(self.sta_num[stage_idx]): if np.random.random_sample() < m_prob: cand_b[1+stage_idx][block_idx] = np.random.randint(6) '''cls head''' for i in range(9): if np.random.random_sample() < m_prob: if i == 0: cand_h_cls[0] = random.randint(0, 2) else: if i == 1: cand_h_cls[1][i-1] = random.randint(0, 1) else: cand_h_cls[1][i-1] = random.randint(0, 2) '''reg head''' for i in range(9): if np.random.random_sample() < m_prob: if i == 0: cand_h_reg[0] = random.randint(0, 2) else: if i == 1: cand_h_reg[1][i-1] = random.randint(0, 1) else: cand_h_reg[1][i-1] = random.randint(0, 2) '''output position''' if np.random.random_sample() < m_prob: cand_op[0] = random.randint(1,3) if np.random.random_sample() < m_prob: num_block = self.sta_num[cand_op[0]] cand_op[1] = random.randint(0, num_block - 1) # fuse cand_new = [None, None, None] cand_new[0] = cand_b cand_new[1] = {} cand_new[1]['cls'] = cand_h_cls cand_new[1]['reg'] = cand_h_reg cand_new[2] = cand_op return tuple(cand_new) cand_iter = self.stack_random_cand(random_func) while len(res) < mutation_num and max_iters > 0: max_iters -= 1 cand = next(cand_iter) if not self.is_legal(cand): continue res.append(cand) print('mutation {}/{}'.format(len(res), mutation_num)) with open('paths.txt','w') as f: for cand in res: f.write(get_path_name(cand)+'\n') print('Evaluating mutation population ...') with open('paths_metric.txt','w') as f: f.write('This is a new file\n') os.system('mpiexec -n %d python Evolution/src/Search/tester_mpi.py --path_file paths.txt --total_num %d --supernet_checkpoint %s --flops_name %s --super_model_name %s' %(len(res),len(res),self.supernet_checkpoint, self.flops_name, self.super_model_name)) with open('paths_metric.txt','r') as f: path_metric_list = f.readlines() self.parse_metric(path_metric_list[1:]) print('mutation_num = {}'.format(len(res))) return res