Repository: ray-project/ray

Issue:
[tune] Incomplete schedulers dict in tune.py
### What is the problem?

The `_SCHEDULERS` dict in `tune/tune.py` only has 4 of the available schedulers. As a result only these 4 are available in rllib's train.py which uses the dict (in the `_make_schedulers` function)

*Ray version and other system information (Python version, TensorFlow version, OS):*
Ray 0.8.5, but still present in master.

### Reproduction (REQUIRED)
Please provide a script that can be run to reproduce the issue. The script should have **no external library dependencies** (i.e., use fake or mock data / environments):

See `rllib/train.py`, which uses the `_make_schedulers` function from tune.py.

If we cannot run your script, we cannot fix your issue.

- [x] I have verified my script runs in a clean environment and reproduces the issue.
- [ ] I have verified the issue also occurs with the [latest wheels](https://docs.ray.io/en/latest/installation.html).



Discussion:
Hi @ttumiel thanks for raising this; would you be willing to contribute a fix?

Let me know - thanks in advance!
Sure!

Resolving patch:
diff --git a/python/ray/tune/schedulers/__init__.py b/python/ray/tune/schedulers/__init__.py
--- a/python/ray/tune/schedulers/__init__.py
+++ b/python/ray/tune/schedulers/__init__.py
@@ -10,8 +10,6 @@
 
 def create_scheduler(
         scheduler,
-        metric=None,
-        mode=None,
         **kwargs,
 ):
     """Instantiate a scheduler based on the given string.
@@ -20,45 +18,25 @@ def create_scheduler(
 
     Args:
         scheduler (str): The scheduler to use.
-        metric (str): The training result objective value attribute. Stopping
-            procedures will use this attribute.
-        mode (str): One of {min, max}. Determines whether objective is
-            minimizing or maximizing the metric attribute.
-        **kwargs: Additional parameters.
+        **kwargs: Scheduler parameters.
             These keyword arguments will be passed to the initialization
-            function of the chosen class.
+            function of the chosen scheduler.
     Returns:
         ray.tune.schedulers.trial_scheduler.TrialScheduler: The scheduler.
     Example:
-        >>> scheduler = tune.create_scheduler('pbt')
+        >>> scheduler = tune.create_scheduler('pbt', **pbt_kwargs)
     """
 
-    def _import_async_hyperband_scheduler():
-        from ray.tune.schedulers import AsyncHyperBandScheduler
-        return AsyncHyperBandScheduler
-
-    def _import_median_stopping_rule_scheduler():
-        from ray.tune.schedulers import MedianStoppingRule
-        return MedianStoppingRule
-
-    def _import_hyperband_scheduler():
-        from ray.tune.schedulers import HyperBandScheduler
-        return HyperBandScheduler
-
-    def _import_hb_bohb_scheduler():
-        from ray.tune.schedulers import HyperBandForBOHB
-        return HyperBandForBOHB
-
-    def _import_pbt_search():
-        from ray.tune.schedulers import PopulationBasedTraining
-        return PopulationBasedTraining
-
     SCHEDULER_IMPORT = {
-        "async_hyperband": _import_async_hyperband_scheduler,
-        "median_stopping_rule": _import_median_stopping_rule_scheduler,
-        "hyperband": _import_hyperband_scheduler,
-        "hb_bohb": _import_hb_bohb_scheduler,
-        "pbt": _import_pbt_search,
+        "fifo": FIFOScheduler,
+        "async_hyperband": AsyncHyperBandScheduler,
+        "asynchyperband": AsyncHyperBandScheduler,
+        "median_stopping_rule": MedianStoppingRule,
+        "medianstopping": MedianStoppingRule,
+        "hyperband": HyperBandScheduler,
+        "hb_bohb": HyperBandForBOHB,
+        "pbt": PopulationBasedTraining,
+        "pbt_replay": PopulationBasedTrainingReplay,
     }
     scheduler = scheduler.lower()
     if scheduler not in SCHEDULER_IMPORT:
@@ -66,8 +44,8 @@ def _import_pbt_search():
             f"Search alg must be one of {list(SCHEDULER_IMPORT)}. "
             f"Got: {scheduler}")
 
-    SchedulerClass = SCHEDULER_IMPORT[scheduler]()
-    return SchedulerClass(metric=metric, mode=mode, **kwargs)
+    SchedulerClass = SCHEDULER_IMPORT[scheduler]
+    return SchedulerClass(**kwargs)
 
 
 __all__ = [
diff --git a/python/ray/tune/tune.py b/python/ray/tune/tune.py
--- a/python/ray/tune/tune.py
+++ b/python/ray/tune/tune.py
@@ -14,18 +14,10 @@
 from ray.tune.syncer import wait_for_sync, set_sync_periods, SyncConfig
 from ray.tune.trial_runner import TrialRunner
 from ray.tune.progress_reporter import CLIReporter, JupyterNotebookReporter
-from ray.tune.schedulers import (HyperBandScheduler, AsyncHyperBandScheduler,
-                                 FIFOScheduler, MedianStoppingRule)
+from ray.tune.schedulers import FIFOScheduler
 
 logger = logging.getLogger(__name__)
 
-_SCHEDULERS = {
-    "FIFO": FIFOScheduler,
-    "MedianStopping": MedianStoppingRule,
-    "HyperBand": HyperBandScheduler,
-    "AsyncHyperBand": AsyncHyperBandScheduler,
-}
-
 try:
     class_name = get_ipython().__class__.__name__
     IS_NOTEBOOK = True if "Terminal" not in class_name else False
@@ -33,14 +25,6 @@
     IS_NOTEBOOK = False
 
 
-def _make_scheduler(args):
-    if args.scheduler in _SCHEDULERS:
-        return _SCHEDULERS[args.scheduler](**args.scheduler_config)
-    else:
-        raise TuneError("Unknown scheduler: {}, should be one of {}".format(
-            args.scheduler, _SCHEDULERS.keys()))
-
-
 def _check_default_resources_override(run_identifier):
     if not isinstance(run_identifier, str):
         # If obscure dtype, assume it is overriden.
diff --git a/rllib/train.py b/rllib/train.py
--- a/rllib/train.py
+++ b/rllib/train.py
@@ -10,7 +10,8 @@
 from ray.tune.config_parser import make_parser
 from ray.tune.result import DEFAULT_RESULTS_DIR
 from ray.tune.resources import resources_to_json
-from ray.tune.tune import _make_scheduler, run_experiments
+from ray.tune.tune import run_experiments
+from ray.tune.schedulers import create_scheduler
 from ray.rllib.utils.framework import try_import_tf, try_import_torch
 
 # Try to import both backends for flag checking/warnings.
@@ -207,7 +208,7 @@ def run(args, parser):
 
     run_experiments(
         experiments,
-        scheduler=_make_scheduler(args),
+        scheduler=create_scheduler(args.scheduler, **args.scheduler_config),
         resume=args.resume,
         queue_trials=args.queue_trials,
         verbose=verbose,


Test patch: