예제 #1
0
    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)))
예제 #2
0
 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
예제 #3
0
    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
예제 #4
0
    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
예제 #5
0
    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)
예제 #6
0
    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