|
| 1 | +"""The strategy that uses a minimizer method for searching through the parameter space.""" |
| 2 | + |
| 3 | +from kernel_tuner.util import StopCriterionReached |
| 4 | +from kernel_tuner.searchspace import Searchspace |
| 5 | +from kernel_tuner.strategies.common import ( |
| 6 | + CostFunc, |
| 7 | + get_options, |
| 8 | + scale_from_params, |
| 9 | + get_strategy_docstring, |
| 10 | +) |
| 11 | + |
| 12 | +supported_methods = ["forest", "gbrt", "gp", "dummy"] |
| 13 | + |
| 14 | +_options = dict( |
| 15 | + method=(f"Local optimization algorithm to use, choose any from {supported_methods}", "gp"), |
| 16 | + options=("Options passed to the skopt method as kwargs.", dict()), |
| 17 | + popsize=("Number of initial samples. If `None`, let skopt choose the initial population", None), |
| 18 | + maxiter=("Maximum number of times to repeat the method until the budget is exhausted.", 1), |
| 19 | +) |
| 20 | + |
| 21 | +def tune(searchspace: Searchspace, runner, tuning_options): |
| 22 | + import skopt |
| 23 | + |
| 24 | + cost_func = CostFunc(searchspace, tuning_options, runner, scaling=True, invalid_value=1e9) |
| 25 | + bounds, _, eps = cost_func.get_bounds_x0_eps() |
| 26 | + |
| 27 | + method, skopt_options, popsize, maxiter = get_options(tuning_options.strategy_options, _options) |
| 28 | + |
| 29 | + # Get maximum number of evaluations |
| 30 | + max_fevals = searchspace.size |
| 31 | + if "max_fevals" in tuning_options: |
| 32 | + max_fevals = min(tuning_options["max_fevals"], max_fevals) |
| 33 | + |
| 34 | + # Set the maximum number of calls to 100 times the maximum number of evaluations. |
| 35 | + # Not all calls by skopt will result in an evaluation, due to restrictions or |
| 36 | + # since different calls might map to the same configuration. |
| 37 | + if "n_calls" not in skopt_options: |
| 38 | + skopt_options["n_calls"] = 100 * max_fevals |
| 39 | + |
| 40 | + # If the initial population size is specified, we select `popsize` samples |
| 41 | + # from the search space. This is more efficient than letting skopt select |
| 42 | + # the samples as it is not aware of restrictions. |
| 43 | + if popsize: |
| 44 | + x0 = searchspace.get_random_sample(min(popsize, max_fevals)) |
| 45 | + skopt_options["x0"] = [list(scale_from_params(x, searchspace.tune_params, eps)) for x in x0] |
| 46 | + |
| 47 | + |
| 48 | + opt_result = None |
| 49 | + |
| 50 | + try: |
| 51 | + for _ in range(maxiter): |
| 52 | + if method == "dummy": |
| 53 | + opt_result = skopt.dummy_minimize(cost_func, bounds, **skopt_options) |
| 54 | + elif method == "forest": |
| 55 | + opt_result = skopt.forest_minimize(cost_func, bounds, **skopt_options) |
| 56 | + elif method == "gp": |
| 57 | + opt_result = skopt.gp_minimize(cost_func, bounds, **skopt_options) |
| 58 | + elif method == "gbrt": |
| 59 | + opt_result = skopt.gbrt_minimize(cost_func, bounds, **skopt_options) |
| 60 | + else: |
| 61 | + raise ValueError(f"invalid skopt method: {method}") |
| 62 | + except StopCriterionReached as e: |
| 63 | + if tuning_options.verbose: |
| 64 | + print(e) |
| 65 | + |
| 66 | + if opt_result and tuning_options.verbose: |
| 67 | + print(opt_result.message) |
| 68 | + |
| 69 | + return cost_func.results |
| 70 | + |
| 71 | + |
| 72 | +tune.__doc__ = get_strategy_docstring("skopt minimize", _options) |
0 commit comments