def __init__( self, consider_prior=True, # type: bool prior_weight=1.0, # type: float consider_magic_clip=True, # type: bool consider_endpoints=False, # type: bool n_startup_trials=10, # type: int n_ei_candidates=24, # type: int gamma=default_gamma, # type: Callable[[int], int] weights=default_weights, # type: Callable[[int], np.ndarray] seed=None, # type: Optional[int] ): # type: (...) -> None self._parzen_estimator_parameters = _ParzenEstimatorParameters( consider_prior, prior_weight, consider_magic_clip, consider_endpoints, weights ) self._prior_weight = prior_weight self._n_startup_trials = n_startup_trials self._n_ei_candidates = n_ei_candidates self._gamma = gamma self._weights = weights self._rng = np.random.RandomState(seed) self._random_sampler = RandomSampler(seed=seed)
def test_suggest_with_step_parzen_estimator(multivariate: bool) -> None: parameters = _ParzenEstimatorParameters( consider_prior=False, prior_weight=0.0, consider_magic_clip=False, consider_endpoints=False, weights=lambda x: np.arange(x) + 1.0, multivariate=multivariate, ) # Define search space for distribution with step argument and true ranges search_space = { "c": distributions.DiscreteUniformDistribution(low=1.0, high=7.0, q=3.0), "d": distributions.IntUniformDistribution(low=1, high=5, step=2), } multivariate_samples = {"c": np.array([4]), "d": np.array([3])} valid_ranges = { "c": set(np.arange(1.0, 10.0, 3.0)), "d": set(np.arange(1, 7, 2)) } sigmas0 = 1 if multivariate else None with patch(_PRECOMPUTE_SIGMAS0, return_value=sigmas0): mpe = _ParzenEstimator(multivariate_samples, search_space, parameters) # Draw 10 samples, and check if all valid values are sampled. output_samples = mpe.sample(np.random.RandomState(0), 10) for param_name in output_samples: assert set(output_samples[param_name]) == valid_ranges[param_name]
def test_calculate_shape_check(mus: np.ndarray, prior: bool, magic_clip: bool, endpoints: bool) -> None: parameters = _ParzenEstimatorParameters( prior_weight=1.0, consider_prior=prior, consider_magic_clip=magic_clip, consider_endpoints=endpoints, weights=default_weights, multivariate=False, ) mpe = _ParzenEstimator({"a": mus}, {"a": distributions.UniformDistribution(-1.0, 1.0)}, parameters) s_weights, s_mus, s_sigmas = mpe._weights, mpe._mus["a"], mpe._sigmas["a"] # Result contains an additional value for a prior distribution if prior is True or # len(mus) == 0 (in this case, prior is always used). assert s_mus is not None assert s_sigmas is not None assert len( s_weights) == len(mus) + int(prior) if len(mus) > 0 else len(mus) + 1 assert len( s_mus) == len(mus) + int(prior) if len(mus) > 0 else len(mus) + 1 assert len( s_sigmas) == len(mus) + int(prior) if len(mus) > 0 else len(mus) + 1
def test_sample_parzen_estimator(multivariate: bool) -> None: parameters = _ParzenEstimatorParameters( consider_prior=False, prior_weight=0.0, consider_magic_clip=False, consider_endpoints=False, weights=lambda x: np.arange(x) + 1.0, multivariate=multivariate, ) sigmas0 = 1e-8 if multivariate else None with patch(_PRECOMPUTE_SIGMAS0, return_value=sigmas0): mpe = _ParzenEstimator(MULTIVARIATE_SAMPLES, SEARCH_SPACE, parameters) # Test the shape of the samples. output_samples = mpe.sample(np.random.RandomState(0), 3) for param_name in output_samples: assert output_samples[param_name].shape == (3, ) # Test the values of the output for multivariate case. # As we set ``consider_prior`` = False and pre-computed sigma to be 1e-8, # the samples almost equals to the input ``MULTIVARIATE_SAMPLES``. output_samples = mpe.sample(np.random.RandomState(0), 1) if multivariate: for param_name, samples in output_samples.items(): np.testing.assert_almost_equal( samples, MULTIVARIATE_SAMPLES[param_name], decimal=2, err_msg="parameter {}".format(param_name), ) # Test the output when the seeds are fixed. assert output_samples == mpe.sample(np.random.RandomState(0), 1)
def __init__( self, consider_prior: bool = True, prior_weight: float = 1.0, consider_magic_clip: bool = True, consider_endpoints: bool = False, n_startup_trials: int = 10, n_ei_candidates: int = 24, gamma: Callable[[int], int] = default_gamma, weights: Callable[[int], np.ndarray] = default_weights, seed: Optional[int] = None, *, multivariate: bool = False, group: bool = False, warn_independent_sampling: bool = True, ) -> None: self._parzen_estimator_parameters = _ParzenEstimatorParameters( consider_prior, prior_weight, consider_magic_clip, consider_endpoints, weights) self._prior_weight = prior_weight self._n_startup_trials = n_startup_trials self._n_ei_candidates = n_ei_candidates self._gamma = gamma self._weights = weights self._warn_independent_sampling = warn_independent_sampling self._rng = np.random.RandomState(seed) self._random_sampler = RandomSampler(seed=seed) self._multivariate = multivariate self._group = group self._group_decomposed_search_space: Optional[ _GroupDecomposedSearchSpace] = None self._search_space_group: Optional[_SearchSpaceGroup] = None self._search_space = IntersectionSearchSpace(include_pruned=True) if multivariate: warnings.warn( "``multivariate`` option is an experimental feature." " The interface can change in the future.", ExperimentalWarning, ) if group: if not multivariate: raise ValueError( "``group`` option can only be enabled when ``multivariate`` is enabled." ) warnings.warn( "``group`` option is an experimental feature." " The interface can change in the future.", ExperimentalWarning, ) self._group_decomposed_search_space = _GroupDecomposedSearchSpace( True)
def test_invalid_weights(weights: Callable[[int], np.ndarray]) -> None: parameters = _ParzenEstimatorParameters( prior_weight=1.0, consider_prior=False, consider_magic_clip=False, consider_endpoints=False, weights=weights, multivariate=False, ) with pytest.raises(ValueError): _ParzenEstimator({"a": np.asarray([0.0])}, {"a": distributions.FloatDistribution(-1.0, 1.0)}, parameters)
def test_invalid_prior_weight(prior_weight: float, mus: np.ndarray) -> None: parameters = _ParzenEstimatorParameters( prior_weight=prior_weight, consider_prior=True, consider_magic_clip=False, consider_endpoints=False, weights=default_weights, multivariate=False, ) mpe = _ParzenEstimator({"a": mus}, {"a": distributions.FloatDistribution(-1.0, 1.0)}, parameters) weights = mpe._weights assert len(weights) == len(mus) + 1 # TODO(HideakiImamura): After modifying the body to raise an error, modify the test as well. if prior_weight is None: assert all([np.isnan(w) for w in weights])
def test_log_pdf_multivariate_parzen_estimator() -> None: parameters = _ParzenEstimatorParameters( consider_prior=False, prior_weight=1.0, consider_magic_clip=True, consider_endpoints=True, weights=lambda x: np.arange(x) + 1.0, ) # Parzen estimator almost becomes mixture of Dirac measures. with patch(_PRECOMPUTE_SIGMAS0, return_value=1e-8 * np.ones(1)): mpe = _MultivariateParzenEstimator(MULTIVARIATE_SAMPLES, SEARCH_SPACE, parameters) log_pdf = mpe.log_pdf(MULTIVARIATE_SAMPLES) output_multivariate_samples = mpe.sample(np.random.RandomState(0), 100) output_log_pdf = mpe.log_pdf(output_multivariate_samples) # The likelihood of the previous observations is a positive value, and that of the points # sampled by the Parzen estimator is almost zero. assert np.all(log_pdf >= output_log_pdf)
def test_calculate(mus: np.ndarray, flags: Dict[str, bool], expected: Dict[str, List[float]]) -> None: parameters = _ParzenEstimatorParameters( prior_weight=1.0, consider_prior=flags["prior"], consider_magic_clip=flags["magic_clip"], consider_endpoints=flags["endpoints"], weights=default_weights, multivariate=False, ) mpe = _ParzenEstimator({"a": mus}, {"a": distributions.UniformDistribution(-1.0, 1.0)}, parameters) s_weights, s_mus, s_sigmas = mpe._weights, mpe._mus["a"], mpe._sigmas["a"] # Result contains an additional value for a prior distribution if consider_prior is True. np.testing.assert_almost_equal(s_weights, expected["weights"]) np.testing.assert_almost_equal(s_mus, expected["mus"]) np.testing.assert_almost_equal(s_sigmas, expected["sigmas"])
def __init__( self, consider_prior: bool = True, prior_weight: float = 1.0, consider_magic_clip: bool = True, consider_endpoints: bool = False, n_startup_trials: int = 10, n_ei_candidates: int = 24, gamma: Callable[[int], int] = default_gamma, weights: Callable[[int], np.ndarray] = default_weights, seed: Optional[int] = None, *, multivariate: bool = False, warn_independent_sampling: bool = True, ) -> None: self._parzen_estimator_parameters = _ParzenEstimatorParameters( consider_prior, prior_weight, consider_magic_clip, consider_endpoints, weights) self._prior_weight = prior_weight self._n_startup_trials = n_startup_trials self._n_ei_candidates = n_ei_candidates self._gamma = gamma self._weights = weights self._warn_independent_sampling = warn_independent_sampling self._rng = np.random.RandomState(seed) self._random_sampler = RandomSampler(seed=seed) self._multivariate = multivariate self._search_space = IntersectionSearchSpace() if multivariate: warnings.warn( "``multivariate`` option is an experimental feature." " The interface can change in the future.", ExperimentalWarning, )
def __init__( self, consider_prior: bool = True, prior_weight: float = 1.0, consider_magic_clip: bool = True, consider_endpoints: bool = False, n_startup_trials: int = 10, n_ei_candidates: int = 24, gamma: Callable[[int], int] = default_gamma, weights: Callable[[int], np.ndarray] = default_weights, seed: Optional[int] = None, ) -> None: self._parzen_estimator_parameters = _ParzenEstimatorParameters( consider_prior, prior_weight, consider_magic_clip, consider_endpoints, weights ) self._prior_weight = prior_weight self._n_startup_trials = n_startup_trials self._n_ei_candidates = n_ei_candidates self._gamma = gamma self._weights = weights self._rng = np.random.RandomState(seed) self._random_sampler = RandomSampler(seed=seed)
def _sample_mo_numerical( self, study: optuna.study.Study, trial: optuna.trial.FrozenTrial, low: float, high: float, below: np.ndarray, above: np.ndarray, q: Optional[float] = None, is_log: bool = False, ) -> float: if is_log: low = np.log(low) high = np.log(high) below = np.log(below) above = np.log(above) size = (self._n_ehvi_candidates,) weights_below: Callable[[int], np.ndarray] weights_below = lambda _: np.asarray( # NOQA study._storage.get_trial(trial._trial_id).system_attrs[_WEIGHTS_BELOW_KEY], dtype=float, ) parzen_estimator_parameters_below = _ParzenEstimatorParameters( self._parzen_estimator_parameters.consider_prior, self._parzen_estimator_parameters.prior_weight, self._parzen_estimator_parameters.consider_magic_clip, self._parzen_estimator_parameters.consider_endpoints, weights_below, ) parzen_estimator_below = _ParzenEstimator( mus=below, low=low, high=high, parameters=parzen_estimator_parameters_below ) samples_below = self._sample_from_gmm( parzen_estimator=parzen_estimator_below, low=low, high=high, q=q, size=size, ) log_likelihoods_below = self._gmm_log_pdf( samples=samples_below, parzen_estimator=parzen_estimator_below, low=low, high=high, q=q, ) weights_above = self._weights parzen_estimator_parameters_above = _ParzenEstimatorParameters( self._parzen_estimator_parameters.consider_prior, self._parzen_estimator_parameters.prior_weight, self._parzen_estimator_parameters.consider_magic_clip, self._parzen_estimator_parameters.consider_endpoints, weights_above, ) parzen_estimator_above = _ParzenEstimator( mus=above, low=low, high=high, parameters=parzen_estimator_parameters_above ) log_likelihoods_above = self._gmm_log_pdf( samples=samples_below, parzen_estimator=parzen_estimator_above, low=low, high=high, q=q, ) ret = float( TPESampler._compare( samples=samples_below, log_l=log_likelihoods_below, log_g=log_likelihoods_above )[0] ) return math.exp(ret) if is_log else ret
def test_init_parzen_estimator(consider_prior: bool, multivariate: bool) -> None: parameters = _ParzenEstimatorParameters( consider_prior=consider_prior, prior_weight=1.0, consider_magic_clip=False, consider_endpoints=False, weights=lambda x: np.arange(x) + 1.0, multivariate=multivariate, ) sigmas0 = 1 if multivariate else None with patch(_PRECOMPUTE_SIGMAS0, return_value=sigmas0): mpe = _ParzenEstimator(MULTIVARIATE_SAMPLES, SEARCH_SPACE, parameters) weights = np.array([1] + consider_prior * [1], dtype=float) weights /= weights.sum() q = {"a": None, "b": None, "c": 3.0, "d": 1.0, "e": None, "f": None} low = { "a": 1.0, "b": np.log(1.0), "c": -0.5, "d": 0.5, "e": np.log(0.5), "f": None } high = { "a": 100.0, "b": np.log(100.0), "c": 101.5, "d": 100.5, "e": np.log(100.5), "f": None } assert np.all(mpe._weights == weights) assert mpe._q == q assert mpe._low == low assert mpe._high == high expected_sigmas_univariate = { "a": [49.5 if consider_prior else 99.0] + consider_prior * [99.0], "b": [np.log(100) / 2 if consider_prior else np.log(100.0)] + consider_prior * [np.log(100)], "c": [49.5 if consider_prior else 100.5] + consider_prior * [102.0], "d": [49.5 if consider_prior else 99.5] + consider_prior * [100.0], "e": [(np.log(100.5) + np.log(0.5)) / 2 if consider_prior else np.log(100.5) ] + consider_prior * [np.log(100.5) - np.log(0.5)], "f": None, } expected_sigmas_multivariate = { "a": [99.0] + consider_prior * [99.0], "b": [np.log(100.0)] + consider_prior * [np.log(100)], "c": [102.0] + consider_prior * [102.0], "d": [100.0] + consider_prior * [100.0], "e": [np.log(100.5) - np.log(0.5)] + consider_prior * [np.log(100.5) - np.log(0.5)], "f": None, } expected_mus = { "a": [1.0] + consider_prior * [50.5], "b": [np.log(1.0)] + consider_prior * [np.log(100) / 2.0], "c": [1.0] + consider_prior * [50.5], "d": [1.0] + consider_prior * [50.5], "e": [np.log(1.0)] + consider_prior * [(np.log(100.5) + np.log(0.5)) / 2.0], "f": None, } expected_categorical_weights = { "a": None, "b": None, "c": None, "d": None, "e": None, "f": np.array([[0.2, 0.6, 0.2], [1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0]]) if consider_prior else np.array([[0.25, 0.5, 0.25]]), } for param_name in mpe._sigmas: np.testing.assert_equal( mpe._sigmas[param_name], expected_sigmas_multivariate[param_name] if multivariate else expected_sigmas_univariate[param_name], err_msg='parameter "{}"'.format(param_name), ) np.testing.assert_equal( mpe._mus[param_name], expected_mus[param_name], err_msg="parameter: {}".format(param_name), ) np.testing.assert_equal( mpe._categorical_weights[param_name], expected_categorical_weights[param_name], err_msg="parameter: {}".format(param_name), )
def _sample_mo_numerical( self, study: "multi_objective.study.MultiObjectiveStudy", trial: "multi_objective.trial.FrozenMultiObjectiveTrial", low: float, high: float, below: np.ndarray, above: np.ndarray, q: Optional[float] = None, is_log: bool = False, ) -> float: if is_log: low = np.log(low) high = np.log(high) below = np.log(below) above = np.log(above) size = (self._n_ehvi_candidates, ) if self._weights is _default_weights_above: weights_below = study._storage.get_trial( trial._trial_id).system_attrs[_WEIGHTS_BELOW_KEY] else: weights_below = self._weights parzen_estimator_parameters_below = _ParzenEstimatorParameters( self._parzen_estimator_parameters.consider_prior, self._parzen_estimator_parameters.prior_weight, self._parzen_estimator_parameters.consider_magic_clip, self._parzen_estimator_parameters.consider_endpoints, weights_below, ) parzen_estimator_below = _ParzenEstimator( mus=below, low=low, high=high, parameters=parzen_estimator_parameters_below) samples_below = self._sample_from_gmm( parzen_estimator=parzen_estimator_below, low=low, high=high, q=q, size=size, ) log_likelihoods_below = self._gmm_log_pdf( samples=samples_below, parzen_estimator=parzen_estimator_below, low=low, high=high, q=q, ) weights_above = self._weights parzen_estimator_parameters_above = _ParzenEstimatorParameters( self._parzen_estimator_parameters.consider_prior, self._parzen_estimator_parameters.prior_weight, self._parzen_estimator_parameters.consider_magic_clip, self._parzen_estimator_parameters.consider_endpoints, weights_above, ) parzen_estimator_above = _ParzenEstimator( mus=above, low=low, high=high, parameters=parzen_estimator_parameters_above) log_likelihoods_above = self._gmm_log_pdf( samples=samples_below, parzen_estimator=parzen_estimator_above, low=low, high=high, q=q, ) ret = float( TPESampler._compare(samples=samples_below, log_l=log_likelihoods_below, log_g=log_likelihoods_above)[0]) return math.exp(ret) if is_log else ret