API Reference / automl /

surrogate.py

Model-guided sampling over one candidate's search space.

Where search_space decides what may be searched, this module decides where to look next inside that space. It is the piece that turns AutoML's inner loop from uniform random sampling into Bayesian optimization, and it does so with TuiML's own surrogate machinery: GaussianProcess and AcquisitionFunction are used directly, rather than a second implementation being written here.

Those two classes are deliberately independent of BayesianSearchCV, which is what makes the reuse possible: BayesianSearchCV owns its own cross-validation loop and refits, whereas AutoML must keep control of evaluation so that every trial shares one set of splits and contributes its fitted model to the ensemble pool. Borrowing the surrogate without the estimator gets both.

Overview

  1. ParameterEncoder maps a parameter dict to a fixed-length numeric
vector, because a GP needs points in \mathbb{R}^d and a search space is a mixture of numeric ranges and unordered categories.
  1. SurrogateSampler records every (params, score) observed, fits
the GP to them, scores a pool of random draws with the acquisition function, and returns the most promising draw.
  1. Until a few observations exist there is nothing to condition on, so the
sampler returns plain random draws and behaves exactly as before.

Notes

The encoding is the part that carries the modelling assumptions. Numeric ranges are scaled to [0, 1] so that one RBF length scale is meaningful across parameters of wildly different magnitudes, and log-scaled ranges are encoded in log space so that the surrogate sees the geometry the space was defined with. Categories are one-hot encoded rather than given an integer index, since an index would tell the GP that 'linear' is nearer 'poly' than 'rbf', which is not true of an unordered set.

Classes

ParameterEncoder

class automl.surrogate.ParameterEncoder

Encode parameter dicts as fixed-length numeric vectors for a GP.

Constructor
__init__(
    self,
    param_distributions: Dict[str, Any],
)

Parameters

param_distributions
dict
The mapping held by a ParameterDistribution: each value is a list of choices, or a (low, high) / (low, high, 'log') / (low, high, 'int') range tuple.

Attributes

columns_
list of tuple
One (name, kind, payload) entry per encoded column group, in encoding order. kind is "numeric" or "choice".
n_features_
int
Width of the encoded vector.
python
>>> from tuiml.automl.surrogate import ParameterEncoder
>>> encoder = ParameterEncoder({'C': (0.01, 100.0, 'log'),
...                             'kernel': ['linear', 'rbf']})
>>> encoder.n_features_
3
>>> encoder.encode({'C': 1.0, 'kernel': 'rbf'}).round(3).tolist()
[0.5, 0.0, 1.0]

Methods

encode (self, params: Dict[str, Any]) -> np.ndarray

Encode one parameter dict as a numeric vector.

Parameters
params
dict
A sampled configuration.
Returns
vector
np.ndarray of shape (n_features_,)
Numeric ranges scaled to :math:`[0, 1]` (in log space where the range is logarithmic), categories one-hot encoded. An absent or unrecognised value encodes as all-zero for its column group.
encode_many (self, rows: Sequence[Dict[str, Any]]) -> np.ndarray

Encode a sequence of parameter dicts as a matrix.

Parameters
rows
sequence of dict
Configurations to encode.
Returns
matrix
np.ndarray of shape (n_rows, n_features_)
One encoded vector per row.

SurrogateSampler

class automl.surrogate.SurrogateSampler

Suggest the next configuration for one candidate, GP-guided.

Holds the observation history for a single algorithm and proposes the draw the acquisition function rates highest. The first MIN_OBSERVATIONS suggestions are plain random draws, so early behaviour is identical to random search and the surrogate only takes over once it has something to learn from.
Constructor
__init__(
    self,
    space: ParameterDistribution,
    acquisition: str = 'ei',
    n_candidates: int = N_ACQUISITION_CANDIDATES,
)

Parameters

space
ParameterDistribution
The candidate's search space, from search_space_for.
acquisition
str = 'ei'
Acquisition policy, passed to AcquisitionFunction: 'ei', 'pi' or 'ucb'.
n_candidates
int = N_ACQUISITION_CANDIDATES
Random draws scored per suggestion.

Attributes

observations_
list of tuple
The (params, score) pairs recorded so far.
n_guided_
int
How many suggestions were chosen by the surrogate rather than drawn at random. Useful for confirming the surrogate actually engaged.
python
>>> from tuiml.automl.search_space import search_space_for
>>> from tuiml.automl.surrogate import SurrogateSampler
>>> from tuiml.registry import registry
>>> import numpy as np
>>> sampler = SurrogateSampler(search_space_for(registry.get('SVC')))
>>> rng = np.random.RandomState(0)
>>> params = sampler.suggest(rng)
>>> sorted(params)
['C', 'degree', 'kernel', 'tol']
>>> sampler.observe(params, 0.9)
>>> len(sampler.observations_)
1

Methods

observe (self, params: Dict[str, Any], score: Optional[float]) -> None

Record the score a configuration achieved.

Parameters
params
dict
The configuration that was evaluated.
score
float or None
Its score, higher being better. None (a failed trial) is ignored rather than treated as a bad score, since a crash says nothing about where the optimum lies.
suggest (self, rng: np.random.RandomState) -> Dict[str, Any]

Propose the next configuration to evaluate.

Parameters
rng
np.random.RandomState
Source of randomness, so a whole search stays reproducible from one seed.
Returns
params
dict
A random draw while the history is too short or the space has no encodable geometry, otherwise the draw maximising the acquisition function over the GP posterior.