Example #1
0
    def advance(self, evaluator: Evaluator):
        self.iteration += 1
        logger.info("Starting SPSA iteration %d." % self.iteration)

        if self.parameters is None:
            self.parameters = evaluator.problem.initial

        # Calculate objective
        if self.compute_objective:
            annotations = { "type": "objective" }
            objective_identifier = evaluator.submit(self.parameters, annotations = annotations)

        # Update step lengths
        gradient_length = self.gradient_factor / (self.iteration + self.gradient_offset)**self.gradient_exponent
        perturbation_length = self.perturbation_factor / self.iteration**self.perturbation_exponent

        # Sample direction from Rademacher distribution
        direction = self.random.randint(0, 2, len(self.parameters)) - 0.5

        annotations = {
            "gradient_length": gradient_length,
            "perturbation_length": perturbation_length,
            "direction": direction,
            "type": "gradient"
        }

        # Schedule samples
        positive_parameters = np.copy(self.parameters)
        positive_parameters += direction * perturbation_length
        annotations = deep_merge.merge(annotations, { "type": "positive_gradient" })
        positive_identifier = evaluator.submit(positive_parameters, annotations = annotations)

        negative_parameters = np.copy(self.parameters)
        negative_parameters -= direction * perturbation_length
        annotations = deep_merge.merge(annotations, { "type": "negative_gradient" })
        negative_identifier = evaluator.submit(negative_parameters, annotations = annotations)

        # Wait for gradient run results
        evaluator.wait()

        if self.compute_objective:
            evaluator.clean(objective_identifier)

        positive_objective, positive_state = evaluator.get(positive_identifier)
        evaluator.clean(positive_identifier)

        negative_objective, negative_state = evaluator.get(negative_identifier)
        evaluator.clean(negative_identifier)

        g_k = (positive_objective - negative_objective) / (2.0 * perturbation_length)
        g_k *= direction**-1

        # Update state
        self.parameters -= gradient_length * g_k
Example #2
0
def test_rosenbrock_evaluation():
    simulator = RosenbrockSimulator()

    evaluator = Evaluator(problem = RosenbrockProblem(3), simulator = simulator)
    identifier = evaluator.submit([1, 1, 1])
    assert evaluator.get(identifier)[0] == 0.0

    evaluator = Evaluator(problem = RosenbrockProblem(5), simulator = simulator)
    identifier = evaluator.submit([-1, 1, 1, 1, 1])
    assert evaluator.get(identifier)[0] == 4.0

    evaluator = Evaluator(problem = RosenbrockProblem(4), simulator = simulator)

    identifier1 = evaluator.submit([-1, 1, 1, 1])
    assert evaluator.get(identifier1)[0] == 4.0

    identifier2 = evaluator.submit([-1, 1, 2, 1])
    assert evaluator.get(identifier2)[0] != 4.0
Example #3
0
    def advance(self, evaluator: Evaluator):
        self.iteration += 1
        logger.info("Starting Random Walk iteration %d" % self.iteration)

        parameters = [np.array([
            bounds[0] + self.random.random() * (bounds[1] - bounds[0]) # TODO: Not demterinistic!
            for bounds in self.bounds
        ]) for k in range(self.parallel)]

        identifiers = [evaluator.submit(p) for p in parameters]

        evaluator.wait(identifiers)
        evaluator.clean()
Example #4
0
    def advance(self, evaluator: Evaluator):
        if self.iteration == 0:
            logger.info("Initializing Opdyts")

            self.initial_identifier = evaluator.submit(self.initial_parameters,
                { "iterations": 1 }, { "type": "initial", "transient": True }
            )
            self.initial_objective, self.initial_state = evaluator.get(self.initial_identifier)

        self.iteration += 1
        logger.info("Starting Opdyts iteration %d" % self.iteration)

        # Create new set of candidate parameters
        candidate_parameters = np.zeros((self.candidate_set_size, self.number_of_parameters))

        for c in range(0, self.candidate_set_size, 2):
            direction = self.random.random_sample(size = (self.number_of_parameters,)) * 2.0 - 1.0
            candidate_parameters[c] = self.initial_parameters + direction * self.perturbation_length
            candidate_parameters[c + 1] = self.initial_parameters + direction * self.perturbation_length

        # Find initial candiate states
        candidate_identifiers = []
        candidate_states = np.zeros((self.candidate_set_size, self.number_of_states))
        candidate_deltas = np.zeros((self.candidate_set_size, self.number_of_states))
        candidate_objectives = np.zeros((self.candidate_set_size,))
        candidate_transitions = np.ones((self.candidate_set_size,))

        annotations = {
            "type": "candidate", "v": self.v, "w": self.w,
            "transient": True, "iteration": self.iteration
        }

        for c in range(self.candidate_set_size):
            candidate_annotations = copy.copy(annotations)
            candidate_annotations.update({ "candidate": c })

            candidate_identifiers.append(evaluator.submit(candidate_parameters[c], {
                #"iterations": transition_iterations,
                "restart": self.initial_identifier
            }, candidate_annotations))

        evaluator.wait()

        for c in range(self.candidate_set_size):
            candidate_objectives[c], candidate_states[c] = evaluator.get(candidate_identifiers[c])
            candidate_deltas[c] = candidate_states[c] - self.initial_state

        # Advance candidates
        local_adaptation_transient_performance = []
        local_adaptation_equilibrium_gap = []
        local_adaptation_uniformity_gap = []

        while np.max(candidate_transitions) < self.number_of_transitions:
            # Approximate selection problem
            selection_problem = ApproximateSelectionProblem(self.v, self.w, candidate_deltas, candidate_objectives)
            alpha = selection_problem.solve()

            transient_performance = selection_problem.get_transient_performance(alpha)
            equilibrium_gap = selection_problem.get_equilibrium_gap(alpha)
            uniformity_gap = selection_problem.get_uniformity_gap(alpha)

            local_adaptation_transient_performance.append(transient_performance)
            local_adaptation_equilibrium_gap.append(equilibrium_gap)
            local_adaptation_uniformity_gap.append(uniformity_gap)

            logger.info(
                "Transient performance: %f, Equilibirum gap: %f, Uniformity_gap: %f",
                transient_performance, equilibrium_gap, uniformity_gap)

            cumulative_alpha = np.cumsum(alpha)
            c = np.sum(self.random.random_sample() > cumulative_alpha) # TODO: Not deterministic!

            logger.info("Transitioning candidate %d", c)
            candidate_transitions[c] += 1
            transient = candidate_transitions[c] < self.number_of_transitions

            annotations.update({
                "type": "transition",
                "candidate": c, "transient_performance": transient_performance,
                "equilibrium_gap": equilibrium_gap, "uniformity_gap": uniformity_gap,
                "transient": transient
            })

            # Advance selected candidate
            identifier = evaluator.submit(candidate_parameters[c], {
                #"iterations": transition_iterations,
                "restart": candidate_identifiers[c]
            }, annotations)

            new_objective, new_state = evaluator.get(identifier)
            evaluator.clean(candidate_identifiers[c])

            candidate_deltas[c] = new_state - candidate_states[c]
            candidate_states[c], candidate_objectives[c] = new_state, new_objective
            candidate_identifiers[c] = identifier

        index = np.argmax(candidate_transitions)
        logger.info("Solved selection problem with candidate %d", index)

        for c in range(self.candidate_set_size):
            if c != index:
                evaluator.clean(candidate_identifiers[c])

        evaluator.clean(self.initial_identifier)
        self.initial_identifier = candidate_identifiers[index]
        self.initial_state = candidate_states[index]
        self.initial_parameters = candidate_parameters[index]

        self.adaptation_selection_performance.append(candidate_objectives[index])
        self.adaptation_transient_performance.append(np.array(local_adaptation_transient_performance))
        self.adaptation_equilibrium_gap.append(np.array(local_adaptation_equilibrium_gap))
        self.adaptation_uniformity_gap.append(np.array(local_adaptation_uniformity_gap))

        adaptation_problem = AdaptationProblem(self.adaptation_weight, self.adaptation_selection_performance, self.adaptation_transient_performance, self.adaptation_equilibrium_gap, self.adaptation_uniformity_gap)
        self.v, self.w = adaptation_problem.solve()

        logger.info("Solved Adaptation Problem. v = %f, w = %f", self.v, self.w)
Example #5
0
    def advance(self, evaluator: Evaluator):
        if self.iteration == 0:
            self.mean = np.copy(self.initial_values).reshape((self.N, 1))

        self.iteration += 1
        logger.info("Starting CMA-ES iteration %d." % self.iteration)

        annotations = {
            "mean": self.mean,
            "covariance": self.C,
            "pc": self.pc,
            "ps": self.ps,
            "sigma": self.sigma
        }

        self.counteval += self.L

        candidate_parameters = self.sigma * np.dot(
            (self.random.normal(size=(self.N, self.L)) *
             self.D[:, np.newaxis]).T, self.B) + self.mean.T

        candidate_identifiers = [
            evaluator.submit(parameters, annotations=annotations)
            for parameters in candidate_parameters
        ]

        # Wait for samples
        evaluator.wait()

        # Obtain fitness
        candidate_objectives = np.array([
            evaluator.get(identifier)[0]  # We minimize!
            for identifier in candidate_identifiers
        ])

        # Cleanup
        for identifier in candidate_identifiers:
            evaluator.clean(identifier)

        sorter = np.argsort(candidate_objectives)

        candidate_objectives = candidate_objectives[sorter]
        candidate_parameters = candidate_parameters[sorter, :]

        # Update mean
        previous_mean = self.mean
        self.mean = np.sum(candidate_parameters[:self.mu] *
                           self.weights[:, np.newaxis],
                           axis=0).reshape((self.N, 1))

        # Update evolution paths
        psa = (1.0 - self.cs) * self.ps
        psb = np.sqrt(self.cs * (2.0 - self.cs) * self.mueff) * np.dot(
            self.invsqrtC, self.mean - previous_mean) / self.sigma
        self.ps = psa + psb

        hsig = la.norm(
            self.ps) / np.sqrt(1.0 -
                               (1.0 - self.cs)**(2.0 * self.counteval / self.L)
                               ) / self.chiN < 1.4 + 2.0 / (self.N + 1.0)
        pca = (1.0 - self.cc) * self.pc
        pcb = hsig * np.sqrt(self.cc * (2.0 - self.cc) * self.mueff) * (
            self.mean - previous_mean) / self.sigma
        self.pc = pca + pcb

        # Adapt covariance matrix
        artmp = (1.0 / self.sigma) * (candidate_parameters[:self.mu].T -
                                      previous_mean)

        Ca = (1.0 - self.c1 - self.cmu) * self.C
        Cb = self.c1 * (np.dot(self.pc, self.pc.T) + (not hsig) * self.cc *
                        (2.0 - self.cc) * self.C)
        Cc = self.cmu * np.dot(artmp, np.dot(np.diag(self.weights), artmp.T))
        C = Ca + Cb + Cc

        # Adapt step size
        self.sigma = self.sigma * np.exp(
            (self.cs / self.damps) * (la.norm(self.ps) / self.chiN - 1.0))

        if self.counteval - self.eigeneval > self.L / (
                self.c1 + self.cmu) / self.N / 10.0:
            self.eigeneval = self.counteval

            self.C = np.triu(self.C) + np.triu(self.C, 1).T
            d, self.B = la.eig(self.C)

            self.D = np.sqrt(d)
            Dm = np.diag(1.0 / np.sqrt(d))

            self.invsqrtC = np.dot(self.B.T, np.dot(Dm, self.B))

        if np.max(self.D) > 1e7 * np.min(self.D):
            logger.warning("Condition exceeds 1e14")
Example #6
0
    def advance(self, evaluator: Evaluator):
        self.iteration += 1
        logger.info("Starting FDSA iteration %d." % self.iteration)

        # Calculate objective
        if self.compute_objective:
            annotations = {"type": "objective"}
            objective_identifier = evaluator.submit(self.parameters,
                                                    annotations=annotations)

        # Update lengths
        gradient_length = self.gradient_factor / (
            self.iteration + self.gradient_offset)**self.gradient_exponent
        perturbation_length = self.perturbation_factor / self.iteration**self.perturbation_exponent

        annotations = {
            "gradient_length": gradient_length,
            "perturbation_length": perturbation_length,
            "type": "gradient"
        }

        # I) Calculate gradients
        gradient = np.zeros((len(self.parameters), ))
        gradient_information = []

        # Schedule all necessary runs
        for d in range(len(self.parameters)):
            annotations = deep_merge.merge(annotations, {"dimension": d})

            positive_parameters = np.copy(self.parameters)
            positive_parameters[d] += perturbation_length
            annotations = deep_merge.merge(annotations,
                                           {"type": "positive_gradient"})
            positive_identifier = evaluator.submit(positive_parameters,
                                                   annotations=annotations)

            negative_parameters = np.copy(self.parameters)
            negative_parameters[d] -= perturbation_length
            annotations = deep_merge.merge(annotations,
                                           {"sign": "negative_gradient"})
            negative_identifier = evaluator.submit(negative_parameters,
                                                   annotations=annotations)

            gradient_information.append(
                (positive_parameters, positive_identifier, negative_parameters,
                 negative_identifier))

        # Wait for gradient run results
        evaluator.wait()

        if self.compute_objective:
            evaluator.clean(objective_identifier)

        for d, item in enumerate(gradient_information):
            positive_parameters, positive_identifier, negative_parameters, negative_identifier = item

            positive_objective, positive_state = evaluator.get(
                positive_identifier)
            evaluator.clean(positive_identifier)

            negative_objective, negative_state = evaluator.get(
                negative_identifier)
            evaluator.clean(negative_identifier)

            gradient[d] = (positive_objective -
                           negative_objective) / (2.0 * perturbation_length)

        # II) Update state
        self.parameters -= gradient_length * gradient