コード例 #1
0
ファイル: ga_dqn_tuner.py プロジェクト: lhutton1/ga-dqn-tuner
    def rl_mutate(self, transitions):
        """
        Mutate genes using DQN to suggest which knob to randomly mutate.
        Mutations happen inplace on the "transitions" that are input.
        """
        for i, transition in enumerate(transitions):
            gene = transition.gene
            next_gene = gene.copy()

            if len(self.visited) < len(self.space):
                action = self.mutation_agent.get_action(gene)
                # An action value of 0 means no mutation occurs
                if action != 0:
                    next_gene[action - 1] = np.random.randint(
                        self.dims[action - 1])

                # If next gene already visited, fallback to random mutation.
                while knob2point(next_gene, self.dims) in self.visited:
                    action = np.random.randint(len(self.dims))
                    next_gene[action] = np.random.randint(self.dims[action])

                transitions[i] = Transition(self.normalise_state(gene),
                                            self.normalise_state(next_gene),
                                            action, next_gene)
                self.visited.add(knob2point(gene, self.dims))
            else:
                break
コード例 #2
0
    def rl_mutate(self, transitions):
        """
        Mutate genes using DQN to suggest which knob to randomly mutate.
        Mutations happen inplace on the "transitions" that are input.
        """
        for i, transition in enumerate(transitions):
            gene = transition.gene
            next_gene = gene.copy()

            if len(self.visited) < len(self.space):
                action = self.mutation_agent.get_action(gene)
                # An action value of 0 means no mutation occurs
                if action != 0:
                    next_gene[action-1] = np.random.randint(self.dims[action-1])

                # If next gene already visited, fallback to random mutation.
                while knob2point(next_gene, self.dims) in self.visited:
                    action = np.random.randint(len(self.dims))
                    next_gene[action] = np.random.randint(
                        self.dims[action])

                transitions[i] = Transition(self.normalise_state(gene),
                                            self.normalise_state(next_gene),
                                            action, next_gene)
                self.visited.add(knob2point(gene, self.dims))
            else:
                break

        # Debugging
        occurrences = Counter(t.action for t in transitions)
        for action, occurrence in occurrences.items():
            marker_size = occurrence * 2
            self.action_plot_mutate.update_plot(self.mutation_step_count, action-1, marker_size)
コード例 #3
0
    def tune(self, n_trial, measure_option, early_stopping=None, callbacks=(), si_prefix="G"):
        """
        GADQNTuner requires custom tuning pipeline as it requires partial measurement of genes
        after crossover, before mutation.

        DISCLAIMER: In order to customise the tuning pipeline we had to reimplement the tune
                    function. This method is mostly taken from Tuner with the exception of
                    an implementation of a custom tuning pipeline.
        """
        measure_batch = create_measure_batch(self.task, measure_option)
        n_parallel = getattr(measure_batch, "n_parallel", 1)
        early_stopping = early_stopping or 1e9
        format_si_prefix(0, si_prefix)
        GLOBAL_SCOPE.in_tuning = True
        do_crossover = True

        self.mutation_agent, self.crossover_agent = self.create_rl_agents(
            self.discount, int(ceil(n_trial / 2)), self.hidden_sizes, self.learning_rate)

        while self.step_count < n_trial:
            if not self.has_next():
                break

            # Initialise a random population.
            if self.step_count < self.pop_size:
                for _ in range(self.pop_size):
                    gene = point2knob(np.random.randint(len(self.space)), self.dims)
                    while knob2point(gene, self.dims) in self.visited:
                        gene = point2knob(np.random.randint(len(self.space)), self.dims)
                    transition = Transition(None, None, None, gene)
                    self.population.append(transition)
                    self.visited.add(knob2point(gene, self.dims))
                self.measure_configs(self.population, n_parallel, measure_batch, callbacks)
                self.initial_score = np.mean([p.score for p in self.population])
                self.reserve_elites()

            # Apply GA-DQN tuning once initial population has been created.
            else:
                if do_crossover:
                    self.population.extend(self.elite_population)
                    self.reserve_elites()
                    self.crossover_update(n_parallel, measure_batch, callbacks)
                    do_crossover = False
                else:
                    self.mutate_update(n_parallel, measure_batch, callbacks)
                    do_crossover = True

            self.ttl = min(early_stopping + self.best_iter, n_trial) - self.step_count

            if self.step_count >= self.best_iter + early_stopping:
                logger.debug("Early stopped. Best iter: %d.", self.best_iter)
                break

        GLOBAL_SCOPE.in_tuning = False
        del measure_batch
コード例 #4
0
ファイル: ga_tuner.py プロジェクト: lhutton1/ga-dqn-tuner
    def __init__(self,
                 task,
                 pop_size=100,
                 elite_num=3,
                 mutation_prob=0.1,
                 debug=False):
        super(GATuner, self).__init__(task)

        # algorithm configurations
        self.pop_size = pop_size
        self.elite_num = elite_num
        self.mutation_prob = mutation_prob

        assert elite_num <= pop_size, "The number of elites must be less than population size"

        # space info
        self.space = task.config_space
        self.dim_keys = []
        self.dims = []
        for k, v in self.space.space_map.items():
            self.dim_keys.append(k)
            self.dims.append(len(v))

        self.visited = set([])

        # current generation
        self.genes = []
        self.scores = []
        self.elites = []
        self.elite_scores = []
        self.trial_pt = 0
        self.steps = 0

        # random initialization
        self.pop_size = min(self.pop_size, len(self.space))
        self.elite_num = min(self.pop_size, self.elite_num)
        for _ in range(self.pop_size):
            tmp_gene = point2knob(np.random.randint(len(self.space)),
                                  self.dims)
            while knob2point(tmp_gene, self.dims) in self.visited:
                tmp_gene = point2knob(np.random.randint(len(self.space)),
                                      self.dims)

            self.genes.append(tmp_gene)
            self.visited.add(knob2point(tmp_gene, self.dims))

        self.debug = debug
        if self.debug:
            plt.ion()
            self.best_score_plot = DynamicPlot("Best score", "steps",
                                               "best score")
            self.average_score_plot = DynamicPlot("Average score", "steps",
                                                  "average score")
            self.action_plot = DynamicScatterPlot("Action selection", "steps",
                                                  "action value")
コード例 #5
0
ファイル: ga_tuner.py プロジェクト: lhutton1/ga-dqn-tuner
    def next_batch(self, batch_size):
        ret = []
        for _ in range(batch_size):
            gene = self.genes[self.trial_pt % self.pop_size]
            self.trial_pt += 1
            ret.append(self.space.get(knob2point(gene, self.dims)))

        return ret
コード例 #6
0
ファイル: ga_dqn_tuner.py プロジェクト: lhutton1/ga-dqn-tuner
    def measure_configs(self, transitions, n_parallel, measure_batch,
                        callbacks):
        """
        Measure results for current population.
        """
        for i in range(ceil(len(transitions) / n_parallel)):
            configs = []
            batch_size = min(n_parallel, len(transitions) - (i * n_parallel))
            transitions_offset = (i * n_parallel) - 1

            # Get configs
            for j in range(transitions_offset,
                           transitions_offset + batch_size):
                gene = transitions[j].gene
                configs.append(self.space.get(knob2point(gene, self.dims)))

            # Measure batch
            inputs = [
                MeasureInput(self.task.target, self.task, config)
                for config in configs
            ]
            results, end_time = measure_batch(inputs)

            # Unpack result
            for j in range(len(results)):
                self.step_count += 1
                transition = transitions[transitions_offset + j]
                input, result = inputs[j], results[j]
                transition.input = inputs[j]
                transition.result = results[j]
                transition.score = input.task.flop / np.mean(
                    result.costs) if result.error_no == 0 else 0.0
                self.scores.append(transition.score)

                # Update best
                if transition.score > self.best_flops:
                    self.best_flops = transition.score
                    self.best_config = transition.input.config
                    self.best_measure_pair = (transition.input,
                                              transition.result)
                    self.best_iter = self.step_count

        for callback in callbacks:
            inputs = [t.input for t in transitions]
            results = [t.result for t in transitions]
            callback(self, inputs, results)
コード例 #7
0
    def update(self, inputs, results):
        # Update results without fitting model
        self.train_ct = len(self.xs)
        super().update(inputs, results)
        if len(self.visited) >= self.next_update:
            # Fit model with adaptive sampler
            self.train_ct = -1
            super().update([], [])
            assert (self.train_ct == 0)

            maximums = self.trials
            print("  >> Adaptive Sampling of %d samples.." % len(maximums))
            samples = [point2knob(config, self.dims) for config in maximums]
            reduced_samples = self.sampler.sample(samples, self.dims)
            maximums = [
                knob2point(sample, self.dims) for sample in reduced_samples
            ]

            print("  >> Adaptive Sampling: Reducing samples to %d" %
                  len(maximums))
            self.trails = maximums
            self.next_update += len(maximums)
コード例 #8
0
ファイル: ga_tuner.py プロジェクト: lhutton1/ga-dqn-tuner
    def update(self, inputs, results):
        for i, (inp, res) in enumerate(zip(inputs, results)):
            if res.error_no == 0:
                y = inp.task.flop / np.mean(res.costs)
                self.scores.append(y)
            else:
                self.scores.append(0.0)

            if self.debug:
                self.best_score_plot.update_plot(
                    self.steps + i, round(self.best_flops / 1000000000, 2))
                self.average_score_plot.update_plot(
                    self.steps + i,
                    round(np.mean(self.scores[-100:]) / 1e9, 2))

        self.steps += len(results)

        if len(self.scores) >= len(self.genes) and len(self.visited) < len(
                self.space):
            genes = self.genes + self.elites
            scores = np.array(self.scores[:len(self.genes)] +
                              self.elite_scores)

            # reserve elite
            self.elites, self.elite_scores = [], []
            elite_indexes = np.argpartition(scores,
                                            -self.elite_num)[-self.elite_num:]
            for ind in elite_indexes:
                self.elites.append(genes[ind])
                self.elite_scores.append(scores[ind])

            # cross over
            indices = np.arange(len(genes))
            scores += 1e-8
            scores /= np.max(scores)
            probs = scores / np.sum(scores)
            tmp_genes = []
            for _ in range(self.pop_size):
                p1, p2 = np.random.choice(indices,
                                          size=2,
                                          replace=False,
                                          p=probs)
                p1, p2 = genes[p1], genes[p2]
                point = np.random.randint(len(self.dims))
                tmp_gene = p1[:point] + p2[point:]
                tmp_genes.append(tmp_gene)

            # mutation
            next_genes = []
            transitions = []
            for tmp_gene in tmp_genes:
                for j, dim in enumerate(self.dims):
                    if np.random.random() < self.mutation_prob:
                        tmp_gene[j] = np.random.randint(dim)

                if len(self.visited) < len(self.space):
                    j = -1
                    while knob2point(tmp_gene, self.dims) in self.visited:
                        j = np.random.randint(len(self.dims))
                        tmp_gene[j] = np.random.randint(self.dims[j])  # pylint: disable=invalid-sequence-index
                    next_genes.append(tmp_gene)
                    transitions.append(j)
                    self.visited.add(knob2point(tmp_gene, self.dims))
                else:
                    break

            if self.debug:
                occurrences = Counter(transitions)
                for action, occurrence in occurrences.items():
                    marker_size = occurrence * 2
                    self.action_plot.update_plot(self.steps, action,
                                                 marker_size)

            self.genes = next_genes
            self.trial_pt = 0
            self.scores = []