def test_1d_analytic_ei_edge_cases(self): """Test cases where analytic EI would attempt to compute 0/0 without variance lower bounds.""" base_coord = numpy.array([0.5]) point1 = SamplePoint(base_coord, -1.809342, 0) point2 = SamplePoint(base_coord * 2.0, -1.09342, 0) # First a symmetric case: only one historical point data = HistoricalData(base_coord.size, [point1]) hyperparameters = numpy.array([0.2, 0.3]) covariance = SquareExponential(hyperparameters) gaussian_process = GaussianProcess(covariance, data) point_to_sample = base_coord ei_eval = ExpectedImprovement(gaussian_process, point_to_sample) ei = ei_eval.compute_expected_improvement() grad_ei = ei_eval.compute_grad_expected_improvement() self.assert_scalar_within_relative(ei, 0.0, 1.0e-15) self.assert_vector_within_relative(grad_ei, numpy.zeros(grad_ei.shape), 1.0e-15) shifts = (1.0e-15, 4.0e-11, 3.14e-6, 8.89e-1, 2.71) self._check_ei_symmetry(ei_eval, point_to_sample, shifts) # Now introduce some asymmetry with a second point # Right side has a larger objetive value, so the EI minimum # is shifted *slightly* to the left of best_so_far. gaussian_process.add_sampled_points([point2]) shift = 3.0e-12 ei_eval = ExpectedImprovement(gaussian_process, point_to_sample - shift) ei = ei_eval.compute_expected_improvement() grad_ei = ei_eval.compute_grad_expected_improvement() self.assert_scalar_within_relative(ei, 0.0, 1.0e-15) self.assert_vector_within_relative(grad_ei, numpy.zeros(grad_ei.shape), 1.0e-15)
def test_multistart_qei_expected_improvement_dfo(self): """Check that multistart optimization (BFGS) can find the optimum point to sample (using 2-EI).""" numpy.random.seed(7860) index = numpy.argmax(numpy.greater_equal(self.num_sampled_list, 20)) domain, gaussian_process = self.gp_test_environments[index] tolerance = 6.0e-5 num_multistarts = 3 # Expand the domain so that we are definitely not doing constrained optimization expanded_domain = TensorProductDomain([ClosedInterval(-4.0, 3.0)] * self.dim) num_to_sample = 2 repeated_domain = RepeatedDomain(num_to_sample, expanded_domain) num_mc_iterations = 100000 # Just any random point that won't be optimal points_to_sample = repeated_domain.generate_random_point_in_domain() ei_eval = ExpectedImprovement(gaussian_process, points_to_sample, num_mc_iterations=num_mc_iterations) # Compute EI and its gradient for the sake of comparison ei_initial = ei_eval.compute_expected_improvement() ei_optimizer = LBFGSBOptimizer(repeated_domain, ei_eval, self.BFGS_parameters) best_point = multistart_expected_improvement_optimization( ei_optimizer, num_multistarts, num_to_sample) # Check that gradients are "small" or on border. MC is very inaccurate near 0, so use finite difference # gradient instead. ei_eval.current_point = best_point ei_final = ei_eval.compute_expected_improvement() finite_diff_grad = numpy.zeros(best_point.shape) h_value = 0.00001 for i in range(best_point.shape[0]): for j in range(best_point.shape[1]): best_point[i, j] += h_value ei_eval.current_point = best_point ei_upper = ei_eval.compute_expected_improvement() best_point[i, j] -= 2 * h_value ei_eval.current_point = best_point ei_lower = ei_eval.compute_expected_improvement() best_point[i, j] += h_value finite_diff_grad[i, j] = (ei_upper - ei_lower) / (2 * h_value) self.assert_vector_within_relative(finite_diff_grad, numpy.zeros(finite_diff_grad.shape), tolerance) # Check that output is in the domain assert repeated_domain.check_point_inside(best_point) is True # Since we didn't really converge to the optimal EI (too costly), do some other sanity checks # EI should have improved assert ei_final >= ei_initial
def test_multistart_monte_carlo_expected_improvement_optimization(self): """Check that multistart optimization (gradient descent) can find the optimum point to sample (using 2-EI).""" numpy.random.seed(7858) # TODO(271): Monte Carlo only works for this seed index = numpy.argmax(numpy.greater_equal(self.num_sampled_list, 20)) domain, gaussian_process = self.gp_test_environments[index] max_num_steps = 75 # this is *too few* steps; we configure it this way so the test will run quickly max_num_restarts = 5 num_steps_averaged = 50 gamma = 0.2 pre_mult = 1.5 max_relative_change = 1.0 tolerance = 3.0e-2 # really large tolerance b/c converging with monte-carlo (esp in Python) is expensive gd_parameters = GradientDescentParameters( max_num_steps, max_num_restarts, num_steps_averaged, gamma, pre_mult, max_relative_change, tolerance, ) num_multistarts = 2 # Expand the domain so that we are definitely not doing constrained optimization expanded_domain = TensorProductDomain([ClosedInterval(-4.0, 2.0)] * self.dim) num_to_sample = 2 repeated_domain = RepeatedDomain(num_to_sample, expanded_domain) num_mc_iterations = 10000 # Just any random point that won't be optimal points_to_sample = repeated_domain.generate_random_point_in_domain() ei_eval = ExpectedImprovement(gaussian_process, points_to_sample, num_mc_iterations=num_mc_iterations) # Compute EI and its gradient for the sake of comparison ei_initial = ei_eval.compute_expected_improvement(force_monte_carlo=True) # TODO(271) Monte Carlo only works for this seed grad_ei_initial = ei_eval.compute_grad_expected_improvement() ei_optimizer = GradientDescentOptimizer(repeated_domain, ei_eval, gd_parameters) best_point = multistart_expected_improvement_optimization(ei_optimizer, num_multistarts, num_to_sample) # Check that gradients are "small" ei_eval.current_point = best_point ei_final = ei_eval.compute_expected_improvement(force_monte_carlo=True) # TODO(271) Monte Carlo only works for this seed grad_ei_final = ei_eval.compute_grad_expected_improvement() self.assert_vector_within_relative(grad_ei_final, numpy.zeros(grad_ei_final.shape), tolerance) # Check that output is in the domain assert repeated_domain.check_point_inside(best_point) is True # Since we didn't really converge to the optimal EI (too costly), do some other sanity checks # EI should have improved assert ei_final >= ei_initial # grad EI should have improved for index in numpy.ndindex(grad_ei_final.shape): assert numpy.fabs(grad_ei_final[index]) <= numpy.fabs(grad_ei_initial[index])
def test_multistart_analytic_expected_improvement_optimization(self): """Check that multistart optimization (gradient descent) can find the optimum point to sample (using 1D analytic EI).""" numpy.random.seed(3148) index = numpy.argmax(numpy.greater_equal(self.num_sampled_list, 20)) domain, gaussian_process = self.gp_test_environments[index] max_num_steps = 200 # this is generally *too few* steps; we configure it this way so the test will run quickly max_num_restarts = 5 num_steps_averaged = 0 gamma = 0.2 pre_mult = 1.5 max_relative_change = 1.0 tolerance = 1.0e-7 gd_parameters = GradientDescentParameters( max_num_steps, max_num_restarts, num_steps_averaged, gamma, pre_mult, max_relative_change, tolerance, ) num_multistarts = 3 points_to_sample = domain.generate_random_point_in_domain() ei_eval = ExpectedImprovement(gaussian_process, points_to_sample) # expand the domain so that we are definitely not doing constrained optimization expanded_domain = TensorProductDomain([ClosedInterval(-4.0, 2.0)] * self.dim) num_to_sample = 1 repeated_domain = RepeatedDomain(ei_eval.num_to_sample, expanded_domain) ei_optimizer = GradientDescentOptimizer(repeated_domain, ei_eval, gd_parameters) best_point = multistart_expected_improvement_optimization( ei_optimizer, num_multistarts, num_to_sample) # Check that gradients are small ei_eval.current_point = best_point gradient = ei_eval.compute_grad_expected_improvement() self.assert_vector_within_relative(gradient, numpy.zeros(gradient.shape), tolerance) # Check that output is in the domain assert repeated_domain.check_point_inside(best_point) is True
def optimize(self, all_x): """ :param all_x: :return: (best_point, found_point_successfully) """ ei_evaluator = ExpectedImprovement(self._gp) ei_vals = numpy.zeros(len(all_x)) for i in range(len(ei_vals)): ei_evaluator.set_current_point(all_x[i, :].reshape((1, -1))) print ei_evaluator.num_to_sample ei_vals[i] = ei_evaluator.compute_expected_improvement() best_ei = numpy.amax(ei_vals) if best_ei > 0: return all_x[numpy.argmax(best_ei), :], True else: return all_x[numpy.random.randint(low=0, high=len(best_ei), size=1 ), :], False
def test_evaluate_ei_at_points(self): """Check that ``evaluate_expected_improvement_at_point_list`` computes and orders results correctly (using 1D analytic EI).""" index = numpy.argmax(numpy.greater_equal(self.num_sampled_list, 5)) domain, gaussian_process = self.gp_test_environments[index] points_to_sample = domain.generate_random_point_in_domain() ei_eval = ExpectedImprovement(gaussian_process, points_to_sample) num_to_eval = 10 # Add in a newaxis to make num_to_sample explicitly 1 points_to_evaluate = domain.generate_uniform_random_points_in_domain(num_to_eval)[:, numpy.newaxis, :] test_values = ei_eval.evaluate_at_point_list(points_to_evaluate) for i, value in enumerate(test_values): ei_eval.current_point = points_to_evaluate[i, ...] truth = ei_eval.compute_expected_improvement() assert value == truth
def optimize_with_ego(gp, domain_bounds, num_multistart): expected_improvement_evaluator = ExpectedImprovement(gp) search_domain = pythonTensorProductDomain( [ClosedInterval(bound[0], bound[1]) for bound in domain_bounds]) start_points = search_domain.generate_uniform_random_points_in_domain( num_multistart) min_negative_ei = numpy.inf def negative_ego_func(x): expected_improvement_evaluator.set_current_point(x.reshape((1, -1))) return -1.0 * expected_improvement_evaluator.compute_expected_improvement( ) for start_point in start_points: x, f = bfgs_optimization(start_point, negative_ego_func, domain_bounds) if min_negative_ei > f: min_negative_ei = f point_to_sample = x return point_to_sample, -min_negative_ei
def test_expected_improvement_and_gradient(self): """Test EI by comparing the vectorized and "naive" versions. With the same RNG state, these two functions should return identical output. We use a fairly low number of monte-carlo iterations since we are not trying to converge; just check for consistency. .. Note:: this is not a particularly good test. It relies on the "naive" version being easier to verify manually and only checks for consistency between the naive and vectorized versions. """ num_points_p_q_list = ((1, 0), (1, 1), (2, 1), (1, 4), (5, 3)) ei_tolerance = 10.0 * numpy.finfo(numpy.float64).eps grad_ei_tolerance = 1.0e-13 numpy.random.seed(78532) for test_case in self.gp_test_environments: domain, gaussian_process = test_case for num_to_sample, num_being_sampled in num_points_p_q_list: points_to_sample = domain.generate_uniform_random_points_in_domain(num_to_sample) points_being_sampled = domain.generate_uniform_random_points_in_domain(num_being_sampled) union_of_points = numpy.reshape(numpy.append(points_to_sample, points_being_sampled), (num_to_sample + num_being_sampled, self.dim)) ei_eval = ExpectedImprovement( gaussian_process, points_to_sample, points_being_sampled=points_being_sampled, num_mc_iterations=self.num_mc_iterations, ) # Compute quantities required for EI mu_star = ei_eval._gaussian_process.compute_mean_of_points(union_of_points) var_star = ei_eval._gaussian_process.compute_variance_of_points(union_of_points) # Check EI # Save state first to restore at the end (o/w other "random" events will get screwed up) rng_state = numpy.random.get_state() numpy.random.seed(self.rng_seed) ei_vectorized = ei_eval._compute_expected_improvement_monte_carlo(mu_star, var_star) numpy.random.seed(self.rng_seed) ei_naive = ei_eval._compute_expected_improvement_monte_carlo_naive(mu_star, var_star) self.assert_scalar_within_relative(ei_vectorized, ei_naive, ei_tolerance) # Compute quantities required for grad EI grad_mu = ei_eval._gaussian_process.compute_grad_mean_of_points( union_of_points, num_derivatives=num_to_sample, ) grad_chol_decomp = ei_eval._gaussian_process.compute_grad_cholesky_variance_of_points( union_of_points, num_derivatives=num_to_sample, ) # Check grad EI numpy.random.seed(self.rng_seed) grad_ei_vectorized = ei_eval._compute_grad_expected_improvement_monte_carlo( mu_star, var_star, grad_mu, grad_chol_decomp, ) numpy.random.seed(self.rng_seed) grad_ei_naive = ei_eval._compute_grad_expected_improvement_monte_carlo_naive( mu_star, var_star, grad_mu, grad_chol_decomp, ) self.assert_vector_within_relative(grad_ei_vectorized, grad_ei_naive, grad_ei_tolerance) # Restore state numpy.random.set_state(rng_state)
# data containers for pickle storage list_best = [] list_cost = [] list_sampled_IS = [] list_sampled_points = [] list_sampled_vals = [] list_noise_var = [] list_raw_voi = [] best_sampled_val = np.amin(problem.hist_data._points_sampled_value) truth_at_init_best_sampled = problem.obj_func_min.evaluate( problem.truth_is, problem.hist_data.points_sampled[ np.argmin(problem.hist_data._points_sampled_value), :]) truth_at_best_sampled = truth_at_init_best_sampled total_cost = 0.0 for ego_n in range(problem.num_iterations): expected_improvement_evaluator = ExpectedImprovement(ego_gp) min_negative_ei = np.inf def negative_ego_func(x): expected_improvement_evaluator.set_current_point(x.reshape((1, -1))) return -1.0 * expected_improvement_evaluator.compute_expected_improvement( ) def negative_ego_grad_func(x): expected_improvement_evaluator.set_current_point(x.reshape((1, -1))) return -1.0 * expected_improvement_evaluator.compute_grad_expected_improvement( )[0, :] def min_negative_ego_func(start_point): return bfgs_optimization_grad(start_point, negative_ego_func, negative_ego_grad_func,