import warnings
import pandas as pd
from skopt import Optimizer
from .tuner import Tuner
from .tuner_exceptions import ParameterError
from evalml.utils.logger import get_logger
logger = get_logger(__file__)
[docs]class SKOptTuner(Tuner):
"""Bayesian Optimizer"""
[docs] def __init__(self, pipeline_hyperparameter_ranges, random_state=0):
""" Init SkOptTuner
Arguments:
pipeline_hyperparameter_ranges (dict): a set of hyperparameter ranges corresponding to a pipeline's parameters
random_state (int, np.random.RandomState): The random state
"""
super().__init__(pipeline_hyperparameter_ranges, random_state=random_state)
self.opt = Optimizer(self._search_space_ranges, "ET", acq_optimizer="sampling", random_state=random_state)
[docs] def add(self, pipeline_parameters, score):
""" Add score to sample
Arguments:
pipeline_parameters (dict): a dict of the parameters used to evaluate a pipeline
score (float): the score obtained by evaluating the pipeline with the provided parameters
Returns:
None
"""
# skip adding nan scores
if pd.isnull(score):
return
flat_parameter_values = self._convert_to_flat_parameters(pipeline_parameters)
try:
self.opt.tell(flat_parameter_values, score)
except Exception as e:
logger.debug('SKOpt tuner received error during add. Score: {}\nParameters: {}\nFlat parameter values: {}\nError: {}'
.format(pipeline_parameters, score, flat_parameter_values, e))
if str(e) == "'<=' not supported between instances of 'int' and 'NoneType'":
msg = "Invalid parameters specified to SKOptTuner.add: parameters {} error {}" \
.format(pipeline_parameters, str(e))
logger.error(msg)
raise ParameterError(msg)
raise(e)
[docs] def propose(self):
"""Returns a suggested set of parameters to train and score a pipeline with, based off the search space dimensions and prior samples.
Returns:
dict: proposed pipeline parameters
"""
with warnings.catch_warnings():
warnings.simplefilter('ignore')
flat_parameters = self.opt.ask()
return self._convert_to_pipeline_parameters(flat_parameters)