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
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
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()
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)
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")
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