pulsatrix
Loading...
Searching...
No Matches
gp_bo.hpp
Go to the documentation of this file.
1
15#pragma once
16
17#include <algorithm>
18#include <cmath>
19#include <limits>
20#include <random>
21#include <stdexcept>
22#include <vector>
23
27#include "pulsatrix/trial.hpp"
28
29namespace pulsatrix {
30
33
40inline Configuration UnitCubeToConfiguration(const SearchSpace& space, const std::vector<float>& t) {
41 if (t.size() != space.size()) {
42 throw std::invalid_argument("UnitCubeToConfiguration: t.size() must equal space.size()");
43 }
44 Configuration config;
45 for (size_t i = 0; i < space.parameters().size(); ++i) {
46 const auto& spec = space.parameters()[i];
47 float u = t[i];
48 if (u < 0.0f || u > 1.0f) {
49 throw std::invalid_argument("UnitCubeToConfiguration: every t value must be in [0, 1]");
50 }
51 switch (spec.kind) {
53 config[spec.name] = spec.lower + static_cast<double>(u) * (spec.upper - spec.lower);
54 break;
56 double log_lower = std::log(spec.lower);
57 double log_upper = std::log(spec.upper);
58 config[spec.name] = std::exp(log_lower + static_cast<double>(u) * (log_upper - log_lower));
59 break;
60 }
61 default:
62 throw std::invalid_argument(
63 "UnitCubeToConfiguration: GP-BO supports only Continuous/LogUniform parameters "
64 "(Integer/Categorical are TPE's job)");
65 }
66 }
67 return config;
68}
69
81template <typename ObjectiveFn, typename RNG>
82std::vector<Trial> RunGPBOLoop(const SearchSpace& space, ObjectiveFn objective_fn,
83 size_t num_initial_random, size_t num_iterations,
84 AcquisitionKind acquisition, size_t num_candidates, RNG& rng) {
85 if (num_initial_random == 0) {
86 throw std::invalid_argument("RunGPBOLoop: num_initial_random must be >= 1");
87 }
88
89 std::vector<Trial> trials;
90 std::vector<std::vector<float>> observed_points;
91 std::vector<float> observed_values;
92 std::uniform_real_distribution<float> unit_dist(0.0f, 1.0f);
93
94 auto evaluate = [&](const std::vector<float>& t) {
95 Configuration config = UnitCubeToConfiguration(space, t);
96 Trial trial(config);
97 double value = objective_fn(config);
98 trial.RecordMetric("objective", value, 0);
99 trials.push_back(std::move(trial));
100 observed_points.push_back(t);
101 observed_values.push_back(static_cast<float>(value));
102 };
103
104 for (size_t i = 0; i < num_initial_random; ++i) {
105 std::vector<float> t(space.size());
106 for (auto& v : t) {
107 v = unit_dist(rng);
108 }
109 evaluate(t);
110 }
111
112 for (size_t iter = 0; iter < num_iterations; ++iter) {
113 GaussianProcessRegressor gp(/*sigma_f=*/1.0f, /*length_scale=*/0.3f, /*noise_variance=*/1e-6f);
114 gp.Fit(observed_points, observed_values);
115
116 float best_value = *std::max_element(observed_values.begin(), observed_values.end());
117
118 std::vector<float> best_candidate;
119 double best_score = -std::numeric_limits<double>::infinity();
120 for (size_t c = 0; c < num_candidates; ++c) {
121 std::vector<float> candidate(space.size());
122 for (auto& v : candidate) {
123 v = unit_dist(rng);
124 }
125 auto posterior = gp.Predict(candidate);
126 double score = 0.0;
127 switch (acquisition) {
129 score = ExpectedImprovement(posterior.mean, posterior.variance, best_value);
130 break;
132 score = ProbabilityOfImprovement(posterior.mean, posterior.variance, best_value);
133 break;
135 score = UpperConfidenceBound(posterior.mean, posterior.variance);
136 break;
137 }
138 if (score > best_score) {
139 best_score = score;
140 best_candidate = candidate;
141 }
142 }
143 evaluate(best_candidate);
144 }
145
146 return trials;
147}
148
149} // namespace pulsatrix
Bayesian-Optimization acquisition functions over a GP posterior: Expected Improvement,...
A fitted (or queryable-before-fitting-throws) Gaussian Process regressor with a squared-exponential k...
Definition gaussian_process.hpp:31
void Fit(std::vector< std::vector< float > > inputs, std::vector< float > targets)
Fits the GP to (inputs[i], targets[i]) observation pairs – computes and solves the training kernel ma...
Definition gaussian_process.hpp:62
Posterior Predict(const std::vector< float > &x) const
Predicts the posterior mean/variance at x, given the data passed to Fit.
Definition gaussian_process.hpp:107
Describes a hyperparameter search space as an ordered list of named, typed parameters....
Definition search_space.hpp:54
size_t size() const
Number of parameters in this search space.
Definition search_space.hpp:119
const std::vector< ParameterSpec > & parameters() const
Every parameter, in the order added.
Definition search_space.hpp:116
A configuration paired with the metric history observed while evaluating it (instantiate a network un...
Definition trial.hpp:31
void RecordMetric(std::string tag, double value, int step)
Records one metric observation.
Definition trial.hpp:39
Gaussian-Process regression surrogate for Bayesian Optimization – the "gaussian bands" techniq...
Definition acquisition_functions.hpp:16
std::vector< Trial > RunGPBOLoop(const SearchSpace &space, ObjectiveFn objective_fn, size_t num_initial_random, size_t num_iterations, AcquisitionKind acquisition, size_t num_candidates, RNG &rng)
Runs GP-BO: num_initial_random uniformly-random trials, then num_iterations trials each chosen by fit...
Definition gp_bo.hpp:82
std::map< std::string, ConfigValue > Configuration
A concrete hyperparameter configuration: parameter name -> concrete value.
Definition search_space.hpp:46
Configuration UnitCubeToConfiguration(const SearchSpace &space, const std::vector< float > &t)
Maps a unit-hypercube point (one value per parameter, each in [0, 1]) to a Configuration,...
Definition gp_bo.hpp:40
AcquisitionKind
Which acquisition function RunGPBOLoop maximizes over candidates each iteration.
Definition gp_bo.hpp:32
Typed hyperparameter search-space description: named parameters, each continuous, log-uniform,...
A single hyperparameter-optimization trial: the configuration tried, plus every metric value recorded...