Source code for smac.epm.multi_objective_epm

from abc import abstractmethod
from typing import Any, Dict, List, Optional, Tuple

import numpy as np

from smac.configspace import ConfigurationSpace
from smac.epm.base_epm import BaseEPM

__copyright__ = "Copyright 2021, AutoML.org Freiburg-Hannover"
__license__ = "3-clause BSD"


[docs]class MultiObjectiveEPM(BaseEPM): """Wrapper for the surrogate models to predict multiple targets. Only a list with the target names and the types array for the underlying model are mandatory. All other hyperparameters to model can be passed via kwargs. Consult the documentation of the corresponding model for the hyperparameters and their meanings. Parameters ---------- target_names : list List of str, each entry is the name of one target dimension. Length of the list will be ``n_objectives``. types : List[int] Specifies the number of categorical values of an input dimension where the i-th entry corresponds to the i-th input dimension. Let's say we have 2 dimension where the first dimension consists of 3 different categorical choices and the second dimension is continuous than we have to pass [3, 0]. Note that we count starting from 0. bounds : List[Tuple[float, float]] bounds of input dimensions: (lower, uppper) for continuous dims; (n_cat, np.nan) for categorical dims instance_features : np.ndarray (I, K) Contains the K dimensional instance features of I different instances pca_components : float Number of components to keep when using PCA to reduce dimensionality of instance features. Requires to set n_feats (> pca_dims). model_kwargs: Optional[Dict[str, Any]]: arguments for initialing estimators Attributes ---------- target_names: target names num_targets: int number of targets estimators: List[BaseEPM] a list of estimators predicting different target values """ def __init__( self, target_names: List[str], configspace: ConfigurationSpace, types: List[int], bounds: List[Tuple[float, float]], seed: int, instance_features: Optional[np.ndarray] = None, pca_components: Optional[int] = None, model_kwargs: Optional[Dict[str, Any]] = None, ) -> None: super().__init__( configspace=configspace, bounds=bounds, types=types, seed=seed, instance_features=instance_features, pca_components=pca_components, ) if model_kwargs is None: model_kwargs = {} self.target_names = target_names self.num_targets = len(self.target_names) self.estimators: List[BaseEPM] = self.construct_estimators(configspace, types, bounds, model_kwargs)
[docs] @abstractmethod def construct_estimators( self, configspace: ConfigurationSpace, types: List[int], bounds: List[Tuple[float, float]], model_kwargs: Dict[str, Any], ) -> List[BaseEPM]: """ Construct a list of estimators. The number of the estimators equals 'self.num_targets' Parameters ---------- configspace : ConfigurationSpace Configuration space to tune for. types : List[int] Specifies the number of categorical values of an input dimension where the i-th entry corresponds to the i-th input dimension. Let's say we have 2 dimension where the first dimension consists of 3 different categorical choices and the second dimension is continuous than we have to pass [3, 0]. Note that we count starting from 0. bounds : List[Tuple[float, float]] bounds of input dimensions: (lower, uppper) for continuous dims; (n_cat, np.nan) for categorical dims model_kwargs : Dict[str, Any] model kwargs for initializing models Returns ------- estimators: List[BaseEPM] A list of estimators """ raise NotImplementedError
def _train(self, X: np.ndarray, Y: np.ndarray) -> "MultiObjectiveEPM": """Trains the models on X and y. Parameters ---------- X : np.ndarray [n_samples, n_features (config + instance features)] Input data points. Y : np.ndarray [n_samples, n_objectives] The corresponding target values. n_objectives must match the number of target names specified in the constructor. Returns ------- self """ if len(self.estimators) == 0: raise ValueError("The list of estimators for this model is empty!") for i, estimator in enumerate(self.estimators): estimator.train(X, Y[:, i]) return self def _predict(self, X: np.ndarray, cov_return_type: Optional[str] = "diagonal_cov") -> Tuple[np.ndarray, np.ndarray]: """Predict means and variances for given X. Parameters ---------- X : np.ndarray of shape = [n_samples, n_features (config + instance features)] cov_return_type: Optional[str] Specifies what to return along with the mean. Refer ``predict()`` for more information. Returns ------- means : np.ndarray of shape = [n_samples, n_objectives] Predictive mean vars : np.ndarray of shape = [n_samples, n_objectives] Predictive variance """ if cov_return_type != "diagonal_cov": raise ValueError("'cov_return_type' can only take 'diagonal_cov' for this model") mean = np.zeros((X.shape[0], self.num_targets)) var = np.zeros((X.shape[0], self.num_targets)) for i, estimator in enumerate(self.estimators): m, v = estimator.predict(X) assert v is not None # please mypy mean[:, i] = m.flatten() var[:, i] = v.flatten() return mean, var
[docs] def predict_marginalized_over_instances(self, X: np.ndarray) -> Tuple[np.ndarray, np.ndarray]: """Predict mean and variance marginalized over all instances. Returns the predictive mean and variance marginalised over all instances for a set of configurations. Parameters ---------- X : np.ndarray of shape = [n_features (config), ] Returns ------- means : np.ndarray of shape = [n_samples, n_objectives] Predictive mean vars : np.ndarray of shape = [n_samples, n_objectives] Predictive variance """ mean = np.zeros((X.shape[0], self.num_targets)) var = np.zeros((X.shape[0], self.num_targets)) for i, estimator in enumerate(self.estimators): m, v = estimator.predict_marginalized_over_instances(X) mean[:, i] = m.flatten() var[:, i] = v.flatten() return mean, var