Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Tune] Update on support initial parameters for SkOpt search algorithm #4345

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion python/ray/tune/examples/skopt_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,13 @@ def easy_objective(config, reporter):
}
}
optimizer = Optimizer([(0, 20), (-100, 100)])
previously_run_params = [[10, 0], [15, -20]]
known_rewards = [-189, -1144]
algo = SkOptSearch(
optimizer, ["width", "height"],
max_concurrent=4,
reward_attr="neg_mean_loss")
reward_attr="neg_mean_loss",
points_to_evaluate=previously_run_params,
evaluated_rewards=known_rewards)
scheduler = AsyncHyperBandScheduler(reward_attr="neg_mean_loss")
run_experiments(config, search_alg=algo, scheduler=scheduler)
64 changes: 60 additions & 4 deletions python/ray/tune/suggest/skopt.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import numbers
from collections import Iterable

try:
import skopt
Expand All @@ -24,10 +26,23 @@ class SkOptSearch(SuggestionAlgorithm):
to 10.
reward_attr (str): The training result objective value attribute.
This refers to an increasing value.
points_to_evaluate (list of lists): A list of trials you'd like to run
first before sampling from the optimiser, e.g. these could be
parameter configurations you already know work well to help
the optimiser select good values. Each trial is a list of the
parameters of that trial using the order definition given
to the optimiser (see example below)
evaluated_rewards (list): If you have previously evaluated the
parameters passed in as points_to_evaluate you can avoid
re-running those trials by passing in the reward attributes
as a list so the optimiser can be told the results without
needing to re-compute the trial. Must be the same length as
points_to_evaluate. (See skopt_example.py)

Example:
>>> from skopt import Optimizer
>>> optimizer = Optimizer([(0,20),(-100,100)])
>>> current_best_params = [[10, 0], [15, -20]]
>>> config = {
>>> "my_exp": {
>>> "run": "exp",
Expand All @@ -39,30 +54,71 @@ class SkOptSearch(SuggestionAlgorithm):
>>> }
>>> algo = SkOptSearch(optimizer,
>>> ["width", "height"], max_concurrent=4,
>>> reward_attr="neg_mean_loss")
>>> reward_attr="neg_mean_loss", points_to_evaluate=current_best_params)
"""

def __init__(self,
optimizer,
parameter_names,
max_concurrent=10,
reward_attr="episode_reward_mean",
points_to_evaluate=None,
evaluated_rewards=None,
**kwargs):
assert skopt is not None, """skopt must be installed!
You can install Skopt with the command:
`pip install scikit-optimize`."""
assert type(max_concurrent) is int and max_concurrent > 0
`pip install scikit-optimize`."""
assert type(max_concurrent) is int and max_concurrent > 0
if points_to_evaluate:
self._validate_points_to_evaluate(points_to_evaluate, len(parameter_names))
if evaluated_rewards:
self._validate_evaluated_rewards(evaluated_rewards)
self._initial_points = []
if points_to_evaluate and evaluated_rewards:
if len(points_to_evaluate) != len(evaluated_rewards):
raise ValueError(
"`points_to_evaluate` and `evaluated_rewards` should have the same length"
)
optimizer.tell(points_to_evaluate, evaluated_rewards)
elif points_to_evaluate:
self._initial_points = points_to_evaluate
self._max_concurrent = max_concurrent
self._parameters = parameter_names
self._reward_attr = reward_attr
self._skopt_opt = optimizer
self._live_trial_mapping = {}
super(SkOptSearch, self).__init__(**kwargs)

def _validate_points_to_evaluate(self, points, dimension):
if not isinstance(points, list):
raise TypeError(
"`points_to_evaluate` should be a list, but got %s" %
type(points))
for point in points:
if not isinstance(point, list):
raise TypeError(
"`points_to_evaluate` should be a list, but got %s" %
type(point))
if len(point) != dimension:
raise TypeError(
"""each point in `points_to_evaluate` should
have the same dimensions as `parameter_names`"""
)

def _validate_evaluated_rewards(self, rewards):
if not isinstance(rewards, list):
raise TypeError(
"`evaluated_rewards` should be a list, but got %s" %
type(points_to_evaluate))

def _suggest(self, trial_id):
if self._num_live_trials() >= self._max_concurrent:
return None
suggested_config = self._skopt_opt.ask()
if self._initial_points:
suggested_config = self._initial_points[0]
del self._initial_points[0]
else:
suggested_config = self._skopt_opt.ask()
self._live_trial_mapping[trial_id] = suggested_config
return dict(zip(self._parameters, suggested_config))

Expand Down