-
Notifications
You must be signed in to change notification settings - Fork 52
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the main concern I have is with regards to dependencies. Please take a look!
cc @krfricke
tune_sklearn/tune_search.py
Outdated
if (search_optimization not in set(available_optimizations.values()) | ||
) and (not isinstance(search_optimization, type) | ||
or not issubclass(search_optimization, Searcher)): | ||
raise ValueError( | ||
"Search optimization must be one of " | ||
f"{', '.join(list(available_optimizations.values()))} " | ||
"or a ray.tune.suggest.Searcher class.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, does this mean we are not allowed to pass a custom Searcher object?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I couldn't figure out a good way to pass an already initialized object, as I have detailed in description - tl;dr there is no enforcement of attributes on Searcher subclassses, so while a solution using objects would be possible with the Searchers present in Tune, it may not work with user-defined ones - unless we do enforcement ourselves here, by forcing the object to have _metric
and _mode
attributes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, so Tune uses set_search_properties()
to set the search space, metric, and mode of a search algorithm. The Searcher
base class also has a _metric
and _mode
attribute. Can't we assume that custom searchers always implement that interface?
Custom searchers were not possible to use before with tune-sklearn, right? Thus, now would be a good time to define and enforce properties of these custom searchers
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd think that would need to be enforced in Ray Tune itself, but we can check it here for now. In that case, I'll make it so that an object is passed instead of a class
if run_args["scheduler"]: | ||
if hasattr(run_args["scheduler"], "_metric") and hasattr( | ||
run_args["scheduler"], "_mode"): | ||
run_args["scheduler"]._metric = search_kwargs["metric"] | ||
run_args["scheduler"]._mode = search_kwargs["mode"] | ||
else: | ||
warnings.warn( | ||
"Could not set `_metric` and `_mode` attributes " | ||
f"on Scheduler {run_args['scheduler']}. " | ||
"This may cause an exception later! " | ||
"Ensure your Scheduler initializes with those " | ||
"attributes.", UserWarning) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there some way of setting this, like with set_search_properties
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't use set_search_properties
as that would cause issues when it's passed to tune.run
, which calls it itself - and it expects an object which hadn't had it called before
Sorry for the slow reply!
If I had a custom Searcher, how would I pass it in to TuneSearchCV with custom arguments? I actually think we could just check if |
@richardliaw You'd pass custom Searcher args as kwargs in TuneSearchCV - however now that we've talked it through it will probably be much cleaner to pass Searcher objects instead and enforce those attributes on them. I'll change it after holidays here :) |
I had a look at it and using objects is not as straightforward. The issue is that if a user passes an algo specific search space, it can't be passed directly to Therefore, if we want to allow users to pass Searcher instances, instead of classes as I first proposed, we would need to force the user to use only Tune search spaces with them. What are your thoughts on solving this? I agree that passing classes instead of instances is not intuitive but I am not sure what'd be a solution that would not have us prevent allowing algo specific search space objects. This is how passing a Searcher class with arguments would look like:
|
@Yard1 could you help me understand the following questions? Under the object searcher proposal:
|
|
One use case I'd like to support is the search algorithm restoration. This allows people to use learnings from past optimization jobs to speed up new ones. This would require access to the search algorithm object (Searcher.restore()). Ideally, we would have the following:
My understanding is that 3 is the controversial one? Though actually a quick skim of code tells me that you can actually pass space without setting metric/mode for many search algs. |
So there are two ways of configuring searchers. Either through class OptunaSearch(Searcher):
def __init__(self,
space: Optional[Union[Dict, List[Tuple]]] = None,
metric: Optional[str] = None,
mode: Optional[str] = None,
points_to_evaluate: Optional[List[Dict]] = None,
sampler: Optional[BaseSampler] = None):
# ...
if isinstance(space, dict) and space:
resolved_vars, domain_vars, grid_vars = parse_spec_vars(space)
if domain_vars or grid_vars:
logger.warning(
UNRESOLVED_SEARCH_SPACE.format(
par="space", cls=type(self)))
space = self.convert_search_space(space)
self._space = space
# ...
if self._space:
self._setup_study(mode)
def set_search_properties(self, metric: Optional[str], mode: Optional[str],
config: Dict) -> bool:
if self._space:
return False
space = self.convert_search_space(config)
self._space = space
if metric:
self._metric = metric
if mode:
self._mode = mode
self._setup_study(mode)
return True If the space is set in
It is not possible to eg. set just the space in I see two solutions:
I hope this clears it up, sorry for the confusion. The gist is that it's only possible to either set space, metric and mode all at once in |
Hmm ok thanks for the clarification! What about we go with:
But also make it so that we don't actually need to specify it twice (i.e., you can leave the one in TuneSearchCV empty?) |
So the properties defined in the Searcher should overwrite the ones in TuneSearchCV? The ones in TuneSearchCV also used for early stopping (Scheluders). |
Ah, no. Ok to make it simple, how about you just make sure everyone has to have the same for now, and we can think about overriding later? TuneSearchCV mode/metric has to be set, and Scheduler/Searchers will also have to be set if passed in. |
Sure, let me get on that |
It's now using instances while enforcing consistency between TuneSearchCV and the Searcher. |
searcher = HEBOSearch() | ||
|
||
# It is also possible to use user-defined Searchers, as long as | ||
# they inherit from ray.tune.suggest.Searcher and have the following | ||
# attributes: _space, _metric, _mode | ||
|
||
tune_search = TuneSearchCV( | ||
clf, param_distributions, n_trials=3, search_optimization=searcher) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so in this case you don't need to specify metric/mode (because it's automatic)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If metric, mode and space are unspecified in the Searcher, then the ones defined in TuneSearchCV will be used (and it has its default ones)
if hasattr(run_args["scheduler"], "_metric") and hasattr( | ||
run_args["scheduler"], "_mode"): | ||
run_args["scheduler"]._metric = search_kwargs["metric"] | ||
run_args["scheduler"]._mode = search_kwargs["mode"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's raise an issue on ray-project/ray for this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice this looks great!
@Yard1 could you look into the test and see if this is related? |
@richardliaw CI is failing due to Optuna - I believe the version is wrong, I'll check - but it shouldn't be related to this. |
@richardliaw Mode is now configurable and release CI passes (it was installing a version of Optuna that was too old) |
Great work @Yard1 ! |
This PR:
refit
parameter were not being enforced as intendedmetric
andmode
from Searchers/Schedulers totune.run
where possibleThere are no API breaking changes and CI should pass.
The reason why a Searcher subclass is passed instead of an object is that I can't see a good way of handling various parameters inside it. For example, someone may pass an object with
_metric
and_mode
already set which would cause issues if those keys were passed totune.run
- but it's also not possible to just check for those attributes as there's no requirement of them being there. Forcing the user to pass a class instead (while still allowing them to instantiate it with custom kwargs) seemed like the best solution.