Source code for bayesmark.random_search

# Copyright (c) 2019 Uber Technologies, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""A baseline random search in our standardized optimizer interface. Useful for baselines.
"""
import numpy as np

from bayesmark import np_util
from bayesmark.space import JointSpace


[docs]def suggest_dict(X, y, meta, n_suggestions=1, random=np_util.random): """Stateless function to create suggestions for next query point in random search optimization. This implements the API for general structures of different data types. Parameters ---------- X : list(dict) Places where the objective function has already been evaluated. Not actually used in random search. y : :class:`numpy:numpy.ndarray`, shape (n,) Corresponding values where objective has been evaluated. Not actually used in random search. meta : dict(str, dict) Configuration of the optimization variables. See API description. n_suggestions : int Desired number of parallel suggestions in the output random : :class:`numpy:numpy.random.RandomState` Optionally pass in random stream for reproducibility. Returns ------- next_guess : list(dict) List of `n_suggestions` suggestions to evaluate the objective function. Each suggestion is a dictionary where each key corresponds to a parameter being optimized. """ # Warp and get bounds space_x = JointSpace(meta) X_warped = space_x.warp(X) bounds = space_x.get_bounds() _, n_params = _check_x_y(X_warped, y, allow_impute=True) lb, ub = _check_bounds(bounds, n_params) # Get the suggestion suggest_x = random.uniform(lb, ub, size=(n_suggestions, n_params)) # Unwarp next_guess = space_x.unwarp(suggest_x) return next_guess
def _check_x_y(X, y, allow_impute=False): # pragma: validator """Input validation for `suggest` routine.""" if not (np.ndim(X) == 2): raise ValueError("X must be 2-dimensional got %s." % str(np.shape(X))) n_obs, n_params = np.shape(X) assert n_params >= 1, "We do not support suggest on empty space." if not (np.shape(y) == (n_obs,)): raise ValueError("y must be %s not %s." % (str((n_obs,)), str(np.shape(y)))) if not np.all(np.isfinite(X)): raise ValueError("X must be finite.") n_real_obs = n_obs if allow_impute: if not np.all(np.isfinite(y) | np.isnan(y)): raise ValueError("y can't contain infs even with data imputation.") n_real_obs = np.sum(np.isfinite(y)) else: if not np.all(np.isfinite(y)): raise ValueError("y must be finite when data imputation not used.") return n_real_obs, n_params def _check_bounds(bounds, n_params): # pragma: validator """Input validation for `suggest` routine.""" if not (np.shape(bounds) == (n_params, 2)): raise ValueError("bounds must have shape %s not %s." % (str((n_params, 2)), str(np.shape(bounds)))) lb, ub = np.asarray(bounds).T if not (np.all(np.isfinite(lb)) and np.all(np.isfinite(ub))): raise ValueError("bounds must be finite.") if not (np.all(lb <= ub)): raise ValueError("lower bound must be less than upper bound.") return lb, ub