Skip to content

Expected improvement

smac.acquisition.function.expected_improvement #

EI #

EI(xi: float = 0.0, log: bool = False)

Bases: AbstractAcquisitionFunction

The Expected Improvement (EI) criterion is used to decide where to evaluate a function f(x) next. The goal is to balance exploration and exploitation. Expected Improvement (with or without function values in log space) acquisition function

:math:EI(X) := \mathbb{E}\left[ \max\{0, f(\mathbf{X^+}) - f_{t+1}(\mathbf{X}) - \xi \} \right], with :math:f(X^+) as the best location.

Reference for EI: Jones, D.R. and Schonlau, M. and Welch, W.J. (1998). Efficient Global Optimization of Expensive Black-Box Functions. Journal of Global Optimization 13, 455–492

Reference for logEI: Hutter, F. and Hoos, H. and Leyton-Brown, K. and Murphy, K. (2009). An experimental investigation of model-based parameter optimisation: SPO and beyond. In: Conference on Genetic and Evolutionary Computation

The logEI implemententation is based on the derivation of the orginal equation by: Watanabe, S. (2024). Derivation of Closed Form of Expected Improvement for Gaussian Process Trained on Log-Transformed Objective. arxiv.org/abs/2411.18095

Parameters#

xi : float, defaults to 0.0 Controls the balance between exploration and exploitation of the acquisition function. log : bool, defaults to False Whether the function values are in log-space.

Attributes#

_xi : float Exploration-exloitation trade-off parameter. _log: bool Function values in log-space or not. _eta : float Current incumbent function value (best value observed so far).

Source code in smac/acquisition/function/expected_improvement.py
def __init__(
    self,
    xi: float = 0.0,
    log: bool = False,
) -> None:
    super(EI, self).__init__()

    self._xi: float = xi
    self._log: bool = log
    self._eta: float | None = None

model property writable #

model: AbstractModel | None

Return the used surrogate model in the acquisition function.

__call__ #

__call__(configurations: list[Configuration]) -> ndarray

Compute the acquisition value for a given configuration.

Parameters#

configurations : list[Configuration] The configurations where the acquisition function should be evaluated.

Returns#

np.ndarray [N, 1] Acquisition values for X

Source code in smac/acquisition/function/abstract_acquisition_function.py
def __call__(self, configurations: list[Configuration]) -> np.ndarray:
    """Compute the acquisition value for a given configuration.

    Parameters
    ----------
    configurations : list[Configuration]
        The configurations where the acquisition function should be evaluated.

    Returns
    -------
    np.ndarray [N, 1]
        Acquisition values for X
    """
    X = convert_configurations_to_array(configurations)
    if len(X.shape) == 1:
        X = X[np.newaxis, :]

    acq = self._compute(X)
    if np.any(np.isnan(acq)):
        idx = np.where(np.isnan(acq))[0]
        acq[idx, :] = -np.finfo(float).max

    return acq

update #

update(model: AbstractModel, **kwargs: Any) -> None

Update the acquisition function attributes required for calculation.

This method will be called after fitting the model, but before maximizing the acquisition function. As an examples, EI uses it to update the current fmin. The default implementation only updates the attributes of the acquisition function which are already present.

Calls _update to update the acquisition function attributes.

Parameters#

model : AbstractModel The model which was used to fit the data. kwargs : Any Additional arguments to update the specific acquisition function.

Source code in smac/acquisition/function/abstract_acquisition_function.py
def update(self, model: AbstractModel, **kwargs: Any) -> None:
    """Update the acquisition function attributes required for calculation.

    This method will be called after fitting the model, but before maximizing the acquisition
    function. As an examples, EI uses it to update the current fmin. The default implementation only updates the
    attributes of the acquisition function which are already present.

    Calls `_update` to update the acquisition function attributes.

    Parameters
    ----------
    model : AbstractModel
        The model which was used to fit the data.
    kwargs : Any
        Additional arguments to update the specific acquisition function.
    """
    self.model = model
    self._update(**kwargs)

EIPS #

EIPS(xi: float = 0.0)

Bases: EI

Expected Improvement per Second acquisition function

:math:EI(X) := \frac{\mathbb{E}\left[\max\{0,f(\mathbf{X^+})-f_{t+1}(\mathbf{X})-\xi\right]\}]}{np.log(r(x))}, with :math:f(X^+) as the best location and :math:r(x) as runtime.

Parameters#

xi : float, defaults to 0.0 Controls the balance between exploration and exploitation of the acquisition function.

Source code in smac/acquisition/function/expected_improvement.py
def __init__(self, xi: float = 0.0) -> None:
    super(EIPS, self).__init__(xi=xi)

model property writable #

model: AbstractModel | None

Return the used surrogate model in the acquisition function.

__call__ #

__call__(configurations: list[Configuration]) -> ndarray

Compute the acquisition value for a given configuration.

Parameters#

configurations : list[Configuration] The configurations where the acquisition function should be evaluated.

Returns#

np.ndarray [N, 1] Acquisition values for X

Source code in smac/acquisition/function/abstract_acquisition_function.py
def __call__(self, configurations: list[Configuration]) -> np.ndarray:
    """Compute the acquisition value for a given configuration.

    Parameters
    ----------
    configurations : list[Configuration]
        The configurations where the acquisition function should be evaluated.

    Returns
    -------
    np.ndarray [N, 1]
        Acquisition values for X
    """
    X = convert_configurations_to_array(configurations)
    if len(X.shape) == 1:
        X = X[np.newaxis, :]

    acq = self._compute(X)
    if np.any(np.isnan(acq)):
        idx = np.where(np.isnan(acq))[0]
        acq[idx, :] = -np.finfo(float).max

    return acq

update #

update(model: AbstractModel, **kwargs: Any) -> None

Update the acquisition function attributes required for calculation.

This method will be called after fitting the model, but before maximizing the acquisition function. As an examples, EI uses it to update the current fmin. The default implementation only updates the attributes of the acquisition function which are already present.

Calls _update to update the acquisition function attributes.

Parameters#

model : AbstractModel The model which was used to fit the data. kwargs : Any Additional arguments to update the specific acquisition function.

Source code in smac/acquisition/function/abstract_acquisition_function.py
def update(self, model: AbstractModel, **kwargs: Any) -> None:
    """Update the acquisition function attributes required for calculation.

    This method will be called after fitting the model, but before maximizing the acquisition
    function. As an examples, EI uses it to update the current fmin. The default implementation only updates the
    attributes of the acquisition function which are already present.

    Calls `_update` to update the acquisition function attributes.

    Parameters
    ----------
    model : AbstractModel
        The model which was used to fit the data.
    kwargs : Any
        Additional arguments to update the specific acquisition function.
    """
    self.model = model
    self._update(**kwargs)