Skip to content

Commit

Permalink
Allow for parameters which are fixed (so will not be tuned.)
Browse files Browse the repository at this point in the history
Add a negative log likelihood for Gaussian processes.
  • Loading branch information
akleeman committed Jul 24, 2018
1 parent decc845 commit 61a849c
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 13 deletions.
20 changes: 13 additions & 7 deletions albatross/core/parameter_handling_mixin.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ struct Parameter {

bool is_valid() const { return within_bounds(); }

bool is_fixed() const { return has_prior() && prior->is_fixed(); }

double prior_log_likelihood() const {
if (has_prior()) {
return prior->log_pdf(value);
Expand Down Expand Up @@ -219,7 +221,9 @@ class ParameterHandlingMixin {
std::vector<ParameterValue> x;
const ParameterStore params = get_params();
for (const auto &pair : params) {
x.push_back(pair.second.value);
if (!pair.second.is_fixed()) {
x.push_back(pair.second.value);
}
}
return x;
}
Expand Down Expand Up @@ -247,14 +251,16 @@ class ParameterHandlingMixin {
}

void set_params_from_vector(const std::vector<ParameterValue> &x) {
const std::size_t n = x.size();
const ParameterStore params = get_params();
assert(n == static_cast<std::size_t>(params.size()));

const std::vector<ParameterKey> param_names = map_keys(params);
for (std::size_t i = 0; i < n; i++) {
unchecked_set_param(param_names[i], x[i]);
std::size_t i = 0;
for (const auto &pair : params) {
if (!pair.second.is_fixed()) {
unchecked_set_param(pair.first, x[i]);
i++;
}
}
// Make sure we used all the parameters that were passed in.
assert(x.size() == i);
}

ParameterValue get_param_value(const ParameterKey &name) const {
Expand Down
39 changes: 34 additions & 5 deletions albatross/core/priors.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class Prior {
virtual std::string get_name() const = 0;
virtual double lower_bound() const { return -LARGE_VAL; }
virtual double upper_bound() const { return LARGE_VAL; }
virtual bool is_fixed() const { return false; }
virtual bool operator==(const Prior &other) const {
return typeid(*this) == typeid(other);
}
Expand All @@ -55,6 +56,18 @@ class UninformativePrior : public Prior {
}
};

class FixedPrior : public Prior {
public:
std::string get_name() const override { return "fixed"; };
double log_pdf(double x) const override { return 0.; }

bool is_fixed() const override { return true; }

template <typename Archive> void serialize(Archive &archive) {
archive(cereal::base_class<Prior>(this));
}
};

class PositivePrior : public Prior {
public:
double log_pdf(double x) const override { return x > 0. ? 0. : -LARGE_VAL; }
Expand All @@ -67,6 +80,18 @@ class PositivePrior : public Prior {
}
};

class NonNegativePrior : public Prior {
public:
double log_pdf(double x) const override { return x >= 0. ? 0. : -LARGE_VAL; }
std::string get_name() const override { return "non_negative"; };
double lower_bound() const override { return 0.; }
double upper_bound() const override { return LARGE_VAL; }

template <typename Archive> void serialize(Archive &archive) {
archive(cereal::base_class<Prior>(this));
}
};

class UniformPrior : public Prior {
public:
UniformPrior(double lower = 0., double upper = 1.)
Expand Down Expand Up @@ -166,10 +191,14 @@ class LogNormalPrior : public Prior {

} // namespace albatross

CEREAL_REGISTER_TYPE(albatross::UninformativePrior);
CEREAL_REGISTER_TYPE(albatross::PositivePrior);
CEREAL_REGISTER_TYPE(albatross::UniformPrior);
CEREAL_REGISTER_TYPE(albatross::GaussianPrior);
CEREAL_REGISTER_TYPE(albatross::LogNormalPrior);
CEREAL_REGISTER_TYPE_WITH_NAME(albatross::UninformativePrior,
"uninformative_prior");
CEREAL_REGISTER_TYPE_WITH_NAME(albatross::PositivePrior, "positive_prior");
CEREAL_REGISTER_TYPE_WITH_NAME(albatross::NonNegativePrior,
"non_negative_prior");
CEREAL_REGISTER_TYPE_WITH_NAME(albatross::FixedPrior, "fixed_prior");
CEREAL_REGISTER_TYPE_WITH_NAME(albatross::UniformPrior, "uniform_prior");
CEREAL_REGISTER_TYPE_WITH_NAME(albatross::GaussianPrior, "gaussian_prior");
CEREAL_REGISTER_TYPE_WITH_NAME(albatross::LogNormalPrior, "log_normal_prior");

#endif
1 change: 0 additions & 1 deletion albatross/evaluate.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ static inline double
negative_log_likelihood(const Eigen::VectorXd &deviation,
const Eigen::LDLT<_MatrixType, _UpLo> &ldlt) {
const auto diag = ldlt.vectorD();
const auto L = ldlt.matrixL();
const double rank = static_cast<double>(diag.size());
const double mahalanobis = deviation.dot(ldlt.solve(deviation));
const double log_det = log_sum(diag);
Expand Down
16 changes: 16 additions & 0 deletions albatross/tuning_metrics.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,22 @@ inline double gp_fast_loo_nll(const RegressionDataset<FeatureType> &dataset,
model->prior_log_likelihood();
}

template <typename FeatureType, typename SubFeatureType = FeatureType>
inline double gp_nll(const RegressionDataset<FeatureType> &dataset,
RegressionModel<FeatureType> *model) {
using SerializableGP =
SerializableRegressionModel<FeatureType,
GaussianProcessFit<SubFeatureType>>;
SerializableGP *gp_model = static_cast<SerializableGP *>(model);
gp_model->fit(dataset);
GaussianProcessFit<SubFeatureType> model_fit = gp_model->get_fit();

double nll =
negative_log_likelihood(dataset.targets.mean, model_fit.train_ldlt);
nll -= model->prior_log_likelihood();
return nll;
}

inline double loo_nll(const RegressionDataset<double> &dataset,
RegressionModel<double> *model) {
auto loo_folds = leave_one_out(dataset);
Expand Down
31 changes: 31 additions & 0 deletions tests/test_parameter_handling_mixin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,37 @@ TEST(test_parameter_handler, test_get_set_from_vector) {
original_handler.get_params_as_vector());
}

/*
* Test the helper functions that let you get and set parameters from
* a vector of values.
*/
TEST(test_parameter_handler, test_get_set_from_vector_with_fixed) {
const ParameterStore expected = {
{"1", 4.},
{"2", 5.},
{"foo", {1., std::make_shared<FixedPrior>()}},
{"3", 6.}};
const std::vector<ParameterValue> expected_param_vector = {4., 5., 6.};

ParameterStore original(expected);
original["1"] = 1.;
original["2"] = 2.;
original["foo"] = {-2., std::make_shared<FixedPrior>()};
original["3"] = 3.;
const std::vector<ParameterValue> original_param_vector = {1., 2., 3.};
MockParameterHandler original_handler(original);

// Make sure we start with the parameter vector we'd expect, even though
// it was initialized out of order.
expect_parameter_vector_equal(original_param_vector,
original_handler.get_params_as_vector());

// Now set the parameters using a new vector and make sure they stick
original_handler.set_params_from_vector(expected_param_vector);
expect_parameter_vector_equal(expected_param_vector,
original_handler.get_params_as_vector());
}

TEST(test_parameter_handler, test_prior_log_likelihood) {
auto p = TestParameterHandler();

Expand Down

0 comments on commit 61a849c

Please sign in to comment.