[tune] Simplify API (#4234)

Uses `tune.run` to execute experiments as preferred API.

@noahgolmant

This does not break backwards compat, but will slowly internalize `Experiment`. 

In a separate PR, Tune schedulers should only support 1 running experiment at a time.
This commit is contained in:
Richard Liaw
2019-03-17 13:03:32 -07:00
committed by GitHub
parent 20a155d03d
commit ea5a6f8455
34 changed files with 523 additions and 589 deletions
+1 -1
View File
@@ -14,7 +14,7 @@ General Examples
- `async_hyperband_example <https://github.com/ray-project/ray/blob/master/python/ray/tune/examples/async_hyperband_example.py>`__:
Example of using a Trainable class with AsyncHyperBandScheduler.
- `hyperband_example <https://github.com/ray-project/ray/blob/master/python/ray/tune/examples/hyperband_example.py>`__:
Example of using a Trainable class with HyperBandScheduler. Also uses the Experiment class API for specifying the experiment configuration.
Example of using a Trainable class with HyperBandScheduler.
- `hyperopt_example <https://github.com/ray-project/ray/blob/master/python/ray/tune/examples/hyperopt_example.py>`__:
Optimizes a basic function using the function-based API and the HyperOptSearch (SearchAlgorithm wrapper for HyperOpt TPE).
Also uses the AsyncHyperBandScheduler.
+7 -7
View File
@@ -5,7 +5,7 @@ By default, Tune schedules trials in serial order with the ``FIFOScheduler`` cla
.. code-block:: python
tune.run_experiments({...}, scheduler=AsyncHyperBandScheduler())
tune.run( ... , scheduler=AsyncHyperBandScheduler())
Tune includes distributed implementations of early stopping algorithms such as `Median Stopping Rule <https://research.google.com/pubs/pub46180.html>`__, `HyperBand <https://arxiv.org/abs/1603.06560>`__, and an `asynchronous version of HyperBand <https://openreview.net/forum?id=S1Y7OOlRZ>`__. These algorithms are very resource efficient and can outperform Bayesian Optimization methods in `many cases <https://people.eecs.berkeley.edu/~kjamieson/hyperband.html>`__. Currently, all schedulers take in a ``reward_attr``, which is assumed to be maximized.
@@ -19,7 +19,7 @@ Current Available Trial Schedulers:
Population Based Training (PBT)
-------------------------------
Tune includes a distributed implementation of `Population Based Training (PBT) <https://deepmind.com/blog/population-based-training-neural-networks>`__. This can be enabled by setting the ``scheduler`` parameter of ``run_experiments``, e.g.
Tune includes a distributed implementation of `Population Based Training (PBT) <https://deepmind.com/blog/population-based-training-neural-networks>`__. This can be enabled by setting the ``scheduler`` parameter of ``tune.run``, e.g.
.. code-block:: python
@@ -32,7 +32,7 @@ Tune includes a distributed implementation of `Population Based Training (PBT) <
"alpha": lambda: random.uniform(0.0, 1.0),
...
})
run_experiments({...}, scheduler=pbt_scheduler)
tune.run( ... , scheduler=pbt_scheduler)
When the PBT scheduler is enabled, each trial variant is treated as a member of the population. Periodically, top-performing trials are checkpointed (this requires your Trainable to support `checkpointing <tune-usage.html#trial-checkpointing>`__). Low-performing trials clone the checkpoints of top performers and perturb the configurations in the hope of discovering an even better variation.
@@ -46,7 +46,7 @@ You can run this `toy PBT example <https://github.com/ray-project/ray/blob/maste
Asynchronous HyperBand
----------------------
The `asynchronous version of HyperBand <https://openreview.net/forum?id=S1Y7OOlRZ>`__ scheduler can be used by setting the ``scheduler`` parameter of ``run_experiments``, e.g.
The `asynchronous version of HyperBand <https://openreview.net/forum?id=S1Y7OOlRZ>`__ scheduler can be used by setting the ``scheduler`` parameter of ``tune.run``, e.g.
.. code-block:: python
@@ -57,7 +57,7 @@ The `asynchronous version of HyperBand <https://openreview.net/forum?id=S1Y7OOlR
grace_period=10,
reduction_factor=3,
brackets=3)
run_experiments({...}, scheduler=async_hb_scheduler)
tune.run( ... , scheduler=async_hb_scheduler)
Compared to the original version of HyperBand, this implementation provides better parallelism and avoids straggler issues during eliminations. An example of this can be found in `async_hyperband_example.py <https://github.com/ray-project/ray/blob/master/python/ray/tune/examples/async_hyperband_example.py>`__. **We recommend using this over the standard HyperBand scheduler.**
@@ -73,7 +73,7 @@ Tune also implements the `standard version of HyperBand <https://arxiv.org/abs/1
.. code-block:: python
run_experiments({...}, scheduler=HyperBandScheduler())
tune.run( ... , scheduler=HyperBandScheduler())
An example of this can be found in `hyperband_example.py <https://github.com/ray-project/ray/blob/master/python/ray/tune/examples/hyperband_example.py>`__. The progress of one such HyperBand run is shown below.
@@ -143,7 +143,7 @@ The Median Stopping Rule implements the simple strategy of stopping a trial if i
.. code-block:: python
run_experiments({...}, scheduler=MedianStoppingRule())
tune.run( ... , scheduler=MedianStoppingRule())
.. autoclass:: ray.tune.schedulers.MedianStoppingRule
:noindex:
+7 -7
View File
@@ -7,7 +7,7 @@ You can utilize these search algorithms as follows:
.. code-block:: python
run_experiments(experiments, search_alg=SearchAlgorithm(...))
tune.run(my_function, search_alg=SearchAlgorithm(...))
Currently, Tune offers the following search algorithms (and library integrations):
@@ -22,7 +22,7 @@ Currently, Tune offers the following search algorithms (and library integrations
Variant Generation (Grid Search/Random Search)
----------------------------------------------
By default, Tune uses the `default search space and variant generation process <tune-usage.html#tune-search-space-default>`__ to create and queue trials. This supports random search and grid search as specified by the ``config`` parameter of the Experiment.
By default, Tune uses the `default search space and variant generation process <tune-usage.html#tune-search-space-default>`__ to create and queue trials. This supports random search and grid search as specified by the ``config`` parameter of ``tune.run``.
.. autoclass:: ray.tune.suggest.BasicVariantGenerator
:show-inheritance:
@@ -46,7 +46,7 @@ This algorithm requires `setting a search space and defining a utility function
.. code-block:: python
run_experiments(experiment_config, search_alg=BayesOptSearch(bayesopt_space, utility_kwargs=utility_params, ... ))
tune.run(... , search_alg=BayesOptSearch(bayesopt_space, utility_kwargs=utility_params, ... ))
An example of this can be found in `bayesopt_example.py <https://github.com/ray-project/ray/blob/master/python/ray/tune/examples/bayesopt_example.py>`__.
@@ -69,7 +69,7 @@ This algorithm requires using the `HyperOpt search space specification <https://
.. code-block:: python
run_experiments(experiment_config, search_alg=HyperOptSearch(hyperopt_space, ... ))
tune.run(... , search_alg=HyperOptSearch(hyperopt_space, ... ))
An example of this can be found in `hyperopt_example.py <https://github.com/ray-project/ray/blob/master/python/ray/tune/examples/hyperopt_example.py>`__.
@@ -98,7 +98,7 @@ This algorithm requires using the `SigOpt experiment and space specification <ht
.. code-block:: python
run_experiments(experiment_config, search_alg=SigOptSearch(sigopt_space, ... ))
tune.run(... , search_alg=SigOptSearch(sigopt_space, ... ))
An example of this can be found in `sigopt_example.py <https://github.com/ray-project/ray/blob/master/python/ray/tune/examples/sigopt_example.py>`__.
@@ -123,7 +123,7 @@ This algorithm requires using an optimizer provided by ``nevergrad``, of which t
.. code-block:: python
run_experiments(experiment_config, search_alg=NevergradSearch(optimizer, parameter_names, ... ))
tune.run(... , search_alg=NevergradSearch(optimizer, parameter_names, ... ))
An example of this can be found in `nevergrad_example.py <https://github.com/ray-project/ray/blob/master/python/ray/tune/examples/nevergrad_example.py>`__.
@@ -147,7 +147,7 @@ This algorithm requires using the `Scikit-Optimize ask and tell interface <https
.. code-block:: python
optimizer = Optimizer(dimension, ...)
run_experiments(experiment_config, search_alg=SkOptSearch(optimizer, parameter_names, ... ))
tune.run(... , search_alg=SkOptSearch(optimizer, parameter_names, ... ))
An example of this can be found in `skopt_example.py <https://github.com/ray-project/ray/blob/master/python/ray/tune/examples/skopt_example.py>`__.
+68 -113
View File
@@ -62,43 +62,12 @@ Both the Trainable and function-based API will have `autofilled metrics <tune-us
See the `experiment specification <tune-usage.html#specifying-experiments>`__ section on how to specify and execute your training.
Specifying Experiments
~~~~~~~~~~~~~~~~~~~~~~
Launching an Experiment
~~~~~~~~~~~~~~~~~~~~~~~
There are two ways to specify the configuration for an experiment - one via Python and one via JSON.
Tune provides a ``run`` function that generates and runs the trials.
**Using Python**: specify a configuration is to create an Experiment object.
.. autoclass:: ray.tune.Experiment
:noindex:
An example of this can be found in `hyperband_example.py <https://github.com/ray-project/ray/blob/master/python/ray/tune/examples/hyperband_example.py>`__.
**Using JSON/Dict**: This uses the same fields as the ``ray.tune.Experiment``, except the experiment name is the key of the top level
dictionary. Tune will convert the dict into an ``ray.tune.Experiment`` object.
.. code-block:: python
experiment_spec = {
"my_experiment_name": {
"run": my_func,
"stop": { "mean_accuracy": 100 },
"config": {
"alpha": tune.grid_search([0.2, 0.4, 0.6]),
"beta": tune.grid_search([1, 2]),
},
"resources_per_trial": { "cpu": 1, "gpu": 0 },
"num_samples": 10,
"local_dir": "~/ray_results",
"upload_dir": "s3://your_bucket/path",
"checkpoint_freq": 10,
"max_failures": 2
}
}
Tune provides a ``run_experiments`` function that generates and runs the trials.
.. autofunction:: ray.tune.run_experiments
.. autofunction:: ray.tune.run
:noindex:
This function will report status on the command line until all Trials stop:
@@ -117,14 +86,11 @@ This function will report status on the command line until all Trials stop:
- train_func_5_lr=0.6,momentum=2: TERMINATED [pid=6809], 10 s, 2164 ts, 100 acc
An example of this can be found in `async_hyperband_example.py <https://github.com/ray-project/ray/blob/master/python/ray/tune/examples/async_hyperband_example.py>`__.
Custom Trial Names
~~~~~~~~~~~~~~~~~~
To specify custom trial names, you can pass use the ``trial_name_creator`` argument
in the Experiment object. This takes a function with the following signature, and
to `tune.run`. This takes a function with the following signature, and
be sure to wrap it with `tune.function`:
.. code-block:: python
@@ -139,9 +105,9 @@ be sure to wrap it with `tune.function`:
"""
return str(trial)
exp = Experiment(
tune.run(
MyTrainableClass,
name="hyperband_test",
run=MyTrainableClass,
num_samples=1,
trial_name_creator=tune.function(trial_name_string)
)
@@ -166,19 +132,18 @@ The following shows grid search over two nested parameters combined with random
.. code-block:: python
:emphasize-lines: 4-11
run_experiments({
"my_experiment_name": {
"run": my_trainable,
"config": {
"alpha": tune.sample_from(lambda spec: np.random.uniform(100)),
"beta": tune.sample_from(lambda spec: spec.config.alpha * np.random.normal()),
"nn_layers": [
tune.grid_search([16, 64, 256]),
tune.grid_search([16, 64, 256]),
],
}
tune.run(
my_trainable,
name="my_trainable",
config={
"alpha": tune.sample_from(lambda spec: np.random.uniform(100)),
"beta": tune.sample_from(lambda spec: spec.config.alpha * np.random.normal()),
"nn_layers": [
tune.grid_search([16, 64, 256]),
tune.grid_search([16, 64, 256]),
],
}
})
)
.. note::
@@ -194,22 +159,21 @@ By default, each random variable and grid search point is sampled once. To take
.. code-block:: python
:emphasize-lines: 12
run_experiments({
"my_experiment_name": {
"run": my_trainable,
"config": {
"alpha": tune.sample_from(lambda spec: np.random.uniform(100)),
"beta": tune.sample_from(lambda spec: spec.config.alpha * np.random.normal()),
"nn_layers": [
tune.grid_search([16, 64, 256]),
tune.grid_search([16, 64, 256]),
],
},
"num_samples": 10
}
})
tune.run(
my_trainable,
name="my_trainable",
config={
"alpha": tune.sample_from(lambda spec: np.random.uniform(100)),
"beta": tune.sample_from(lambda spec: spec.config.alpha * np.random.normal()),
"nn_layers": [
tune.grid_search([16, 64, 256]),
tune.grid_search([16, 64, 256]),
],
},
num_samples=10
)
E.g. in the above, ``"num_samples": 10`` repeats the 3x3 grid search 10 times, for a total of 90 trials, each with randomly sampled values of ``alpha`` and ``beta``.
E.g. in the above, ``num_samples=10`` repeats the 3x3 grid search 10 times, for a total of 90 trials, each with randomly sampled values of ``alpha`` and ``beta``.
Using GPUs (Resource Allocation)
@@ -228,16 +192,15 @@ If your trainable function / class creates further Ray actors or tasks that also
.. code-block:: python
:emphasize-lines: 4-8
run_experiments({
"my_experiment_name": {
"run": my_trainable,
"resources_per_trial": {
"cpu": 1,
"gpu": 1,
"extra_gpu": 4
}
tune.run(
my_trainable,
name="my_trainable",
resources_per_trial={
"cpu": 1,
"gpu": 1,
"extra_gpu": 4
}
})
)
Trial Checkpointing
@@ -268,18 +231,16 @@ For TensorFlow model training, this would look something like this `(full tensor
return self.saver.restore(self.sess, path)
Additionally, checkpointing can be used to provide fault-tolerance for experiments. This can be enabled by setting ``checkpoint_freq: N`` and ``max_failures: M`` to checkpoint trials every *N* iterations and recover from up to *M* crashes per trial, e.g.:
Additionally, checkpointing can be used to provide fault-tolerance for experiments. This can be enabled by setting ``checkpoint_freq=N`` and ``max_failures=M`` to checkpoint trials every *N* iterations and recover from up to *M* crashes per trial, e.g.:
.. code-block:: python
:emphasize-lines: 4,5
run_experiments({
"my_experiment_name": {
"run": my_trainable
"checkpoint_freq": 10,
"max_failures": 5,
},
})
tune.run(
my_trainable,
checkpoint_freq=10,
max_failures=5,
)
The checkpoint_freq may not coincide with the exact end of an experiment. If you want a checkpoint to be created at the end
of a trial, you can additionally set the checkpoint_at_end to True. An example is shown below:
@@ -287,14 +248,13 @@ of a trial, you can additionally set the checkpoint_at_end to True. An example i
.. code-block:: python
:emphasize-lines: 5
run_experiments({
"my_experiment_name": {
"run": my_trainable
"checkpoint_freq": 10,
"checkpoint_at_end": True,
"max_failures": 5,
},
})
tune.run(
my_trainable,
checkpoint_freq=10,
checkpoint_at_end=True,
max_failures=5,
)
Recovering From Failures (Experimental)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -307,13 +267,12 @@ E.g.:
.. code-block:: python
run_experiments({
"my_experiment_name": {
"run": my_trainable
"checkpoint_freq": 10,
"local_dir": "~/path/to/results"
},
}, resume=True)
tune.run(
my_trainable,
checkpoint_freq=10,
local_dir="~/path/to/results",
resume=True
)
Upon a second run, this will restore the entire experiment state from ``~/path/to/results/my_experiment_name``. Importantly, any changes to the experiment specification upon resume will be ignored.
@@ -329,7 +288,7 @@ You often will want to compute a large object (e.g., training data, model weight
.. code-block:: python
import ray
from ray.tune import run_experiments
from ray import tune
from ray.tune.util import pin_in_object_store, get_pinned_object
import numpy as np
@@ -343,11 +302,8 @@ You often will want to compute a large object (e.g., training data, model weight
X = get_pinned_object(X_id)
# use X
run_experiments({
"my_experiment_name": {
"run": f
}
})
tune.run(f)
Auto-Filled Results
-------------------
@@ -411,16 +367,15 @@ Finally, to view the results with a `parallel coordinates visualization <https:/
Custom Loggers
~~~~~~~~~~~~~~
You can pass in your own logging mechanisms to output logs in custom formats
via the Experiment object as follows:
You can pass in your own logging mechanisms to output logs in custom formats as follows:
.. code-block:: python
from ray.tune.logger import DEFAULT_LOGGERS
exp = Experiment(
tune.run(
MyTrainableClass
name="experiment_name",
run=MyTrainableClass,
loggers=DEFAULT_LOGGERS + (CustomLogger1, CustomLogger2)
)
@@ -454,9 +409,9 @@ be wrapped with ``tune.function``):
sync_process = subprocess.Popen(sync_cmd, shell=True)
sync_process.wait()
exp = Experiment(
tune.run(
MyTrainableClass,
name="experiment_name",
run=MyTrainableClass,
sync_function=tune.function(custom_sync_func)
)
@@ -470,7 +425,7 @@ To allow Tune to receive and respond to your API calls, you have to start your e
.. code-block:: python
run_experiments({...}, with_server=True, server_port=4321)
tune.run(..., with_server=True, server_port=4321)
The easiest way to use the Tune Client API is with the built-in TuneClient. To use TuneClient, verify that you have the ``requests`` library installed:
+7 -8
View File
@@ -58,7 +58,7 @@ Tune uses Ray as a backend, so we will first import and initialize Ray.
.. code-block:: python
import ray
import ray.tune as tune
from ray import tune
ray.init()
@@ -82,13 +82,12 @@ For the function you wish to tune, pass in a ``reporter`` object:
.. code-block:: python
all_trials = tune.run_experiments({
"my_experiment": {
"run": train_func,
"stop": {"mean_accuracy": 99},
"config": {"momentum": tune.grid_search([0.1, 0.2])}
}
})
all_trials = tune.run(
train_func,
name="quick-start",
stop={"mean_accuracy": 99},
config={"momentum": tune.grid_search([0.1, 0.2])}
)
Tune can be used anywhere Ray can, e.g. on your laptop with ``ray.init()`` embedded in a Python script, or in an `auto-scaling cluster <autoscaling.html>`__ for massive parallelism.
+2 -2
View File
@@ -3,7 +3,7 @@ from __future__ import division
from __future__ import print_function
from ray.tune.error import TuneError
from ray.tune.tune import run_experiments
from ray.tune.tune import run_experiments, run
from ray.tune.experiment import Experiment
from ray.tune.registry import register_env, register_trainable
from ray.tune.trainable import Trainable
@@ -11,6 +11,6 @@ from ray.tune.suggest import grid_search, function, sample_from
__all__ = [
"Trainable", "TuneError", "grid_search", "register_env",
"register_trainable", "run_experiments", "Experiment", "function",
"register_trainable", "run", "run_experiments", "Experiment", "function",
"sample_from"
]
@@ -12,7 +12,7 @@ import random
import numpy as np
import ray
from ray.tune import Trainable, run_experiments, sample_from
from ray.tune import Trainable, run, sample_from
from ray.tune.schedulers import AsyncHyperBandScheduler
@@ -63,24 +63,21 @@ if __name__ == "__main__":
grace_period=5,
max_t=100)
run_experiments(
{
"asynchyperband_test": {
"run": MyTrainableClass,
"stop": {
"training_iteration": 1 if args.smoke_test else 99999
},
"num_samples": 20,
"resources_per_trial": {
"cpu": 1,
"gpu": 0
},
"config": {
"width": sample_from(
lambda spec: 10 + int(90 * random.random())),
"height": sample_from(
lambda spec: int(100 * random.random())),
},
}
},
scheduler=ahb)
run(MyTrainableClass,
name="asynchyperband_test",
scheduler=ahb,
**{
"stop": {
"training_iteration": 1 if args.smoke_test else 99999
},
"num_samples": 20,
"resources_per_trial": {
"cpu": 1,
"gpu": 0
},
"config": {
"width": sample_from(
lambda spec: 10 + int(90 * random.random())),
"height": sample_from(lambda spec: int(100 * random.random())),
},
})
+12 -13
View File
@@ -7,7 +7,7 @@ from __future__ import division
from __future__ import print_function
import ray
from ray.tune import run_experiments, register_trainable
from ray.tune import run
from ray.tune.schedulers import AsyncHyperBandScheduler
from ray.tune.suggest import BayesOptSearch
@@ -32,20 +32,15 @@ if __name__ == "__main__":
args, _ = parser.parse_known_args()
ray.init()
register_trainable("exp", easy_objective)
space = {'width': (0, 20), 'height': (-100, 100)}
config = {
"my_exp": {
"run": "exp",
"num_samples": 10 if args.smoke_test else 1000,
"config": {
"iterations": 100,
},
"stop": {
"timesteps_total": 100
},
"num_samples": 10 if args.smoke_test else 1000,
"config": {
"iterations": 100,
},
"stop": {
"timesteps_total": 100
}
}
algo = BayesOptSearch(
@@ -58,4 +53,8 @@ if __name__ == "__main__":
"xi": 0.0
})
scheduler = AsyncHyperBandScheduler(reward_attr="neg_mean_loss")
run_experiments(config, search_alg=algo, scheduler=scheduler)
run(easy_objective,
name="my_exp",
search_alg=algo,
scheduler=scheduler,
**config)
+7 -12
View File
@@ -7,7 +7,7 @@ from __future__ import division
from __future__ import print_function
import ray
from ray.tune import run_experiments, register_trainable
from ray.tune import run
from ray.tune.schedulers import AsyncHyperBandScheduler
from ray.tune.automl import GeneticSearch
from ray.tune.automl import ContinuousSpace, DiscreteSpace, SearchSpace
@@ -36,8 +36,6 @@ if __name__ == "__main__":
args, _ = parser.parse_known_args()
ray.init()
register_trainable("exp", michalewicz_function)
space = SearchSpace({
ContinuousSpace('x1', 0, 4, 100),
ContinuousSpace('x2', -2, 2, 100),
@@ -46,18 +44,15 @@ if __name__ == "__main__":
DiscreteSpace('x5', [-1, 0, 1, 2, 3]),
})
config = {
"my_exp": {
"run": "exp",
"stop": {
"training_iteration": 100
},
}
}
config = {"stop": {"training_iteration": 100}}
algo = GeneticSearch(
space,
reward_attr="neg_mean_loss",
max_generation=2 if args.smoke_test else 10,
population_size=10 if args.smoke_test else 50)
scheduler = AsyncHyperBandScheduler(reward_attr="neg_mean_loss")
run_experiments(config, search_alg=algo, scheduler=scheduler)
run(michalewicz_function,
name="my_exp",
search_alg=algo,
scheduler=scheduler,
**config)
@@ -12,7 +12,7 @@ import random
import numpy as np
import ray
from ray.tune import Trainable, run_experiments, Experiment, sample_from
from ray.tune import Trainable, run, Experiment, sample_from
from ray.tune.schedulers import HyperBandScheduler
@@ -71,4 +71,4 @@ if __name__ == "__main__":
"height": sample_from(lambda spec: int(100 * random.random()))
})
run_experiments(exp, scheduler=hyperband)
run(exp, scheduler=hyperband)
+9 -14
View File
@@ -7,7 +7,7 @@ from __future__ import division
from __future__ import print_function
import ray
from ray.tune import run_experiments, register_trainable
from ray.tune import run
from ray.tune.schedulers import AsyncHyperBandScheduler
from ray.tune.suggest import HyperOptSearch
@@ -35,8 +35,6 @@ if __name__ == "__main__":
args, _ = parser.parse_known_args()
ray.init()
register_trainable("exp", easy_objective)
space = {
'width': hp.uniform('width', 0, 20),
'height': hp.uniform('height', -100, 100),
@@ -57,16 +55,13 @@ if __name__ == "__main__":
]
config = {
"my_exp": {
"run": "exp",
"num_samples": 10 if args.smoke_test else 1000,
"config": {
"iterations": 100,
},
"stop": {
"timesteps_total": 100
},
}
"num_samples": 10 if args.smoke_test else 1000,
"config": {
"iterations": 100,
},
"stop": {
"timesteps_total": 100
},
}
algo = HyperOptSearch(
space,
@@ -74,4 +69,4 @@ if __name__ == "__main__":
reward_attr="neg_mean_loss",
points_to_evaluate=current_best_params)
scheduler = AsyncHyperBandScheduler(reward_attr="neg_mean_loss")
run_experiments(config, search_alg=algo, scheduler=scheduler)
run(easy_objective, search_alg=algo, scheduler=scheduler, **config)
+2 -2
View File
@@ -13,7 +13,7 @@ import numpy as np
import ray
from ray import tune
from ray.tune import Trainable, run_experiments, Experiment
from ray.tune import Trainable, run, Experiment
class TestLogger(tune.logger.Logger):
@@ -74,4 +74,4 @@ if __name__ == "__main__":
"height": tune.sample_from(lambda spec: int(100 * random.random()))
})
trials = run_experiments(exp)
trials = run(exp)
+24 -24
View File
@@ -165,28 +165,28 @@ if __name__ == "__main__":
reward_attr="neg_mean_loss",
max_t=400,
grace_period=20)
tune.register_trainable("train_mnist",
lambda cfg, rprtr: train_mnist(args, cfg, rprtr))
tune.run_experiments(
{
"exp": {
"stop": {
"mean_accuracy": 0.98,
"training_iteration": 1 if args.smoke_test else 20
},
"resources_per_trial": {
"cpu": 3,
"gpu": int(not args.no_cuda)
},
"run": "train_mnist",
"num_samples": 1 if args.smoke_test else 10,
"config": {
"lr": tune.sample_from(
lambda spec: np.random.uniform(0.001, 0.1)),
"momentum": tune.sample_from(
lambda spec: np.random.uniform(0.1, 0.9)),
}
}
},
tune.register_trainable(
"TRAIN_FN",
lambda config, reporter: train_mnist(args, config, reporter))
tune.run(
"TRAIN_FN",
name="exp",
verbose=0,
scheduler=sched)
scheduler=sched,
**{
"stop": {
"mean_accuracy": 0.98,
"training_iteration": 1 if args.smoke_test else 20
},
"resources_per_trial": {
"cpu": 3,
"gpu": int(not args.no_cuda)
},
"num_samples": 1 if args.smoke_test else 10,
"config": {
"lr": tune.sample_from(
lambda spec: np.random.uniform(0.001, 0.1)),
"momentum": tune.sample_from(
lambda spec: np.random.uniform(0.1, 0.9)),
}
})
@@ -177,28 +177,26 @@ if __name__ == "__main__":
ray.init()
sched = HyperBandScheduler(
time_attr="training_iteration", reward_attr="neg_mean_loss")
tune.run_experiments(
{
"exp": {
"stop": {
"mean_accuracy": 0.95,
"training_iteration": 1 if args.smoke_test else 20,
},
"resources_per_trial": {
"cpu": 3,
"gpu": int(not args.no_cuda)
},
"run": TrainMNIST,
"num_samples": 1 if args.smoke_test else 20,
"checkpoint_at_end": True,
"config": {
"args": args,
"lr": tune.sample_from(
lambda spec: np.random.uniform(0.001, 0.1)),
"momentum": tune.sample_from(
lambda spec: np.random.uniform(0.1, 0.9)),
}
}
},
tune.run(
TrainMNIST,
verbose=0,
scheduler=sched)
scheduler=sched,
**{
"stop": {
"mean_accuracy": 0.95,
"training_iteration": 1 if args.smoke_test else 20,
},
"resources_per_trial": {
"cpu": 3,
"gpu": int(not args.no_cuda)
},
"num_samples": 1 if args.smoke_test else 20,
"checkpoint_at_end": True,
"config": {
"args": args,
"lr": tune.sample_from(
lambda spec: np.random.uniform(0.001, 0.1)),
"momentum": tune.sample_from(
lambda spec: np.random.uniform(0.1, 0.9)),
}
})
+12 -13
View File
@@ -7,7 +7,7 @@ from __future__ import division
from __future__ import print_function
import ray
from ray.tune import run_experiments, register_trainable
from ray.tune import run
from ray.tune.schedulers import AsyncHyperBandScheduler
from ray.tune.suggest import NevergradSearch
@@ -33,18 +33,13 @@ if __name__ == "__main__":
args, _ = parser.parse_known_args()
ray.init()
register_trainable("exp", easy_objective)
config = {
"nevergrad": {
"run": "exp",
"num_samples": 10 if args.smoke_test else 50,
"config": {
"iterations": 100,
},
"stop": {
"timesteps_total": 100
},
"num_samples": 10 if args.smoke_test else 50,
"config": {
"iterations": 100,
},
"stop": {
"timesteps_total": 100
}
}
optimizer = optimizerlib.OnePlusOne(dimension=2)
@@ -53,4 +48,8 @@ if __name__ == "__main__":
max_concurrent=4,
reward_attr="neg_mean_loss")
scheduler = AsyncHyperBandScheduler(reward_attr="neg_mean_loss")
run_experiments(config, search_alg=algo, scheduler=scheduler)
run(easy_objective,
name="nevergrad",
search_alg=algo,
scheduler=scheduler,
**config)
+14 -16
View File
@@ -11,7 +11,7 @@ import random
import time
import ray
from ray.tune import Trainable, run_experiments
from ray.tune import Trainable, run
from ray.tune.schedulers import PopulationBasedTraining
@@ -81,20 +81,18 @@ if __name__ == "__main__":
})
# Try to find the best factor 1 and factor 2
run_experiments(
{
"pbt_test": {
"run": MyTrainableClass,
"stop": {
"training_iteration": 20 if args.smoke_test else 99999
},
"num_samples": 10,
"config": {
"factor_1": 4.0,
"factor_2": 1.0,
},
}
},
run(MyTrainableClass,
name="pbt_test",
scheduler=pbt,
reuse_actors=True,
verbose=False)
verbose=False,
**{
"stop": {
"training_iteration": 20 if args.smoke_test else 99999
},
"num_samples": 10,
"config": {
"factor_1": 4.0,
"factor_2": 1.0,
},
})
+26 -27
View File
@@ -13,7 +13,7 @@ from __future__ import print_function
import random
import ray
from ray.tune import run_experiments, sample_from
from ray.tune import run, sample_from
from ray.tune.schedulers import PopulationBasedTraining
if __name__ == "__main__":
@@ -45,31 +45,30 @@ if __name__ == "__main__":
custom_explore_fn=explore)
ray.init()
run_experiments(
{
"pbt_humanoid_test": {
"run": "PPO",
"env": "Humanoid-v1",
"num_samples": 8,
"config": {
"kl_coeff": 1.0,
"num_workers": 8,
"num_gpus": 1,
"model": {
"free_log_std": True
},
# These params are tuned from a fixed starting value.
"lambda": 0.95,
"clip_param": 0.2,
"lr": 1e-4,
# These params start off randomly drawn from a set.
"num_sgd_iter": sample_from(
lambda spec: random.choice([10, 20, 30])),
"sgd_minibatch_size": sample_from(
lambda spec: random.choice([128, 512, 2048])),
"train_batch_size": sample_from(
lambda spec: random.choice([10000, 20000, 40000]))
run(
"PPO",
name="pbt_humanoid_test",
scheduler=pbt,
**{
"env": "Humanoid-v1",
"num_samples": 8,
"config": {
"kl_coeff": 1.0,
"num_workers": 8,
"num_gpus": 1,
"model": {
"free_log_std": True
},
# These params are tuned from a fixed starting value.
"lambda": 0.95,
"clip_param": 0.2,
"lr": 1e-4,
# These params start off randomly drawn from a set.
"num_sgd_iter": sample_from(
lambda spec: random.choice([10, 20, 30])),
"sgd_minibatch_size": sample_from(
lambda spec: random.choice([128, 512, 2048])),
"train_batch_size": sample_from(
lambda spec: random.choice([10000, 20000, 40000]))
},
},
scheduler=pbt)
})
@@ -23,7 +23,7 @@ from tensorflow.python.keras.models import Model
from tensorflow.python.keras.preprocessing.image import ImageDataGenerator
import ray
from ray.tune import grid_search, run_experiments, sample_from
from ray.tune import grid_search, run, sample_from
from ray.tune import Trainable
from ray.tune.schedulers import PopulationBasedTraining
@@ -180,7 +180,6 @@ if __name__ == "__main__":
args, _ = parser.parse_known_args()
train_spec = {
"run": Cifar10Model,
"resources_per_trial": {
"cpu": 1,
"gpu": 1
@@ -213,4 +212,4 @@ if __name__ == "__main__":
"dropout": lambda _: np.random.uniform(0, 1),
})
run_experiments({"pbt_cifar10": train_spec}, scheduler=pbt)
run(Cifar10Model, name="pbt_cifar10", scheduler=pbt, **train_spec)
+13 -14
View File
@@ -7,7 +7,7 @@ from __future__ import division
from __future__ import print_function
import ray
from ray.tune import run_experiments, register_trainable
from ray.tune import run
from ray.tune.schedulers import AsyncHyperBandScheduler
from ray.tune.suggest import SigOptSearch
@@ -36,8 +36,6 @@ if __name__ == "__main__":
args, _ = parser.parse_known_args()
ray.init()
register_trainable("exp", easy_objective)
space = [
{
'name': 'width',
@@ -58,16 +56,13 @@ if __name__ == "__main__":
]
config = {
"my_exp": {
"run": "exp",
"num_samples": 10 if args.smoke_test else 1000,
"config": {
"iterations": 100,
},
"stop": {
"timesteps_total": 100
},
}
"num_samples": 10 if args.smoke_test else 1000,
"config": {
"iterations": 100,
},
"stop": {
"timesteps_total": 100
},
}
algo = SigOptSearch(
space,
@@ -75,4 +70,8 @@ if __name__ == "__main__":
max_concurrent=1,
reward_attr="neg_mean_loss")
scheduler = AsyncHyperBandScheduler(reward_attr="neg_mean_loss")
run_experiments(config, search_alg=algo, scheduler=scheduler)
run(easy_objective,
name="my_exp",
search_alg=algo,
scheduler=scheduler,
**config)
+18 -15
View File
@@ -7,7 +7,7 @@ from __future__ import division
from __future__ import print_function
import ray
from ray.tune import run_experiments, register_trainable
from ray.tune import run
from ray.tune.schedulers import AsyncHyperBandScheduler
from ray.tune.suggest import SkOptSearch
@@ -33,19 +33,14 @@ if __name__ == "__main__":
args, _ = parser.parse_known_args()
ray.init()
register_trainable("exp", easy_objective)
config = {
"skopt_exp": {
"run": "exp",
"num_samples": 10 if args.smoke_test else 50,
"config": {
"iterations": 100,
},
"stop": {
"timesteps_total": 100
},
}
"num_samples": 10 if args.smoke_test else 50,
"config": {
"iterations": 100,
},
"stop": {
"timesteps_total": 100
},
}
optimizer = Optimizer([(0, 20), (-100, 100)])
previously_run_params = [[10, 0], [15, -20]]
@@ -57,7 +52,11 @@ if __name__ == "__main__":
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)
run(easy_objective,
name="skopt_exp_with_warmstart",
search_alg=algo,
scheduler=scheduler,
**config)
# Now run the experiment without known rewards
@@ -67,4 +66,8 @@ if __name__ == "__main__":
reward_attr="neg_mean_loss",
points_to_evaluate=previously_run_params)
scheduler = AsyncHyperBandScheduler(reward_attr="neg_mean_loss")
run_experiments(config, search_alg=algo, scheduler=scheduler)
run(easy_objective,
name="skopt_exp",
search_alg=algo,
scheduler=scheduler,
**config)
@@ -33,7 +33,7 @@ import tempfile
import time
import ray
from ray.tune import grid_search, run_experiments
from ray.tune import grid_search, run
from tensorflow.examples.tutorials.mnist import input_data
@@ -219,7 +219,6 @@ if __name__ == "__main__":
args, _ = parser.parse_known_args()
mnist_spec = {
'run': train,
'num_samples': 10,
'stop': {
'mean_accuracy': 0.99,
@@ -237,12 +236,11 @@ if __name__ == "__main__":
ray.init()
from ray.tune.schedulers import AsyncHyperBandScheduler
run_experiments(
{
'tune_mnist_test': mnist_spec
},
run(train,
name='tune_mnist_test',
scheduler=AsyncHyperBandScheduler(
time_attr="timesteps_total",
reward_attr="mean_accuracy",
max_t=600,
))
),
**mnist_spec)
+29 -28
View File
@@ -176,32 +176,33 @@ if __name__ == "__main__":
reward_attr="mean_accuracy",
max_t=400,
grace_period=20)
tune.register_trainable("train_mnist",
lambda cfg, rprtr: train_mnist(args, cfg, rprtr))
tune.run_experiments(
{
"exp": {
"stop": {
"mean_accuracy": 0.99,
"timesteps_total": 10 if args.smoke_test else 300
},
"run": "train_mnist",
"num_samples": 1 if args.smoke_test else 10,
"resources_per_trial": {
"cpu": args.threads,
"gpu": 0.5 if args.use_gpu else 0
},
"config": {
"lr": tune.sample_from(
lambda spec: np.random.uniform(0.001, 0.1)),
"momentum": tune.sample_from(
lambda spec: np.random.uniform(0.1, 0.9)),
"hidden": tune.sample_from(
lambda spec: np.random.randint(32, 512)),
"dropout1": tune.sample_from(
lambda spec: np.random.uniform(0.2, 0.8)),
}
}
},
tune.register_trainable(
"TRAIN_FN",
lambda config, reporter: train_mnist(args, config, reporter))
tune.run(
"TRAIN_FN",
name="exp",
verbose=0,
scheduler=sched)
scheduler=sched,
**{
"stop": {
"mean_accuracy": 0.99,
"timesteps_total": 10 if args.smoke_test else 300
},
"num_samples": 1 if args.smoke_test else 10,
"resources_per_trial": {
"cpu": args.threads,
"gpu": 0.5 if args.use_gpu else 0
},
"config": {
"lr": tune.sample_from(
lambda spec: np.random.uniform(0.001, 0.1)),
"momentum": tune.sample_from(
lambda spec: np.random.uniform(0.1, 0.9)),
"hidden": tune.sample_from(
lambda spec: np.random.randint(32, 512)),
"dropout1": tune.sample_from(
lambda spec: np.random.uniform(0.2, 0.8)),
}
})
+3 -3
View File
@@ -33,7 +33,8 @@ import tempfile
import time
import ray
from ray.tune import grid_search, run_experiments, register_trainable
from ray import tune
from ray.tune import grid_search, register_trainable
from tensorflow.examples.tutorials.mnist import input_data
import numpy as np
@@ -221,7 +222,6 @@ if __name__ == "__main__":
register_trainable('train_mnist', train)
mnist_spec = {
'run': 'train_mnist',
'stop': {
'mean_accuracy': 0.99,
'time_total_s': 600,
@@ -238,4 +238,4 @@ if __name__ == "__main__":
mnist_spec['stop']['training_iteration'] = 2
ray.init()
run_experiments({'tune_mnist_test': mnist_spec})
tune.run('train_mnist', name='tune_mnist_test', **mnist_spec)
@@ -30,8 +30,8 @@ import argparse
import time
import ray
from ray.tune import grid_search, run_experiments, register_trainable, \
Trainable, sample_from
from ray import tune
from ray.tune import grid_search, Trainable, sample_from
from ray.tune.schedulers import HyperBandScheduler
from tensorflow.examples.tutorials.mnist import input_data
@@ -214,10 +214,7 @@ if __name__ == "__main__":
parser.add_argument(
'--smoke-test', action='store_true', help='Finish quickly for testing')
args, _ = parser.parse_known_args()
register_trainable("my_class", TrainMNIST)
mnist_spec = {
'run': 'my_class',
'stop': {
'mean_accuracy': 0.99,
'time_total_s': 600,
@@ -238,4 +235,8 @@ if __name__ == "__main__":
hyperband = HyperBandScheduler(
time_attr="training_iteration", reward_attr="mean_accuracy", max_t=10)
run_experiments({'mnist_hyperband_test': mnist_spec}, scheduler=hyperband)
tune.run(
TrainMNIST,
name='mnist_hyperband_test',
scheduler=hyperband,
**mnist_spec)
+7 -60
View File
@@ -35,59 +35,7 @@ def _raise_deprecation_note(deprecated, replacement, soft=False):
class Experiment(object):
"""Tracks experiment specifications.
Parameters:
name (str): Name of experiment.
run (function|class|str): The algorithm or model to train.
This may refer to the name of a built-on algorithm
(e.g. RLLib's DQN or PPO), a user-defined trainable
function or class, or the string identifier of a
trainable function or class registered in the tune registry.
stop (dict): The stopping criteria. The keys may be any field in
the return result of 'train()', whichever is reached first.
Defaults to empty dict.
config (dict): Algorithm-specific configuration for Tune variant
generation (e.g. env, hyperparams). Defaults to empty dict.
Custom search algorithms may ignore this.
resources_per_trial (dict): Machine resources to allocate per trial,
e.g. ``{"cpu": 64, "gpu": 8}``. Note that GPUs will not be
assigned unless you specify them here. Defaults to 1 CPU and 0
GPUs in ``Trainable.default_resource_request()``.
num_samples (int): Number of times to sample from the
hyperparameter space. Defaults to 1. If `grid_search` is
provided as an argument, the grid will be repeated
`num_samples` of times.
local_dir (str): Local dir to save training results to.
Defaults to ``~/ray_results``.
upload_dir (str): Optional URI to sync training results
to (e.g. ``s3://bucket``).
trial_name_creator (func): Optional function for generating
the trial string representation.
loggers (list): List of logger creators to be used with
each Trial. If None, defaults to ray.tune.logger.DEFAULT_LOGGERS.
See `ray/tune/logger.py`.
sync_function (func|str): Function for syncing the local_dir to
upload_dir. If string, then it must be a string template for
syncer to run. If not provided, the sync command defaults
to standard S3 or gsutil sync comamnds.
checkpoint_freq (int): How many training iterations between
checkpoints. A value of 0 (default) disables checkpointing.
checkpoint_at_end (bool): Whether to checkpoint at the end of the
experiment regardless of the checkpoint_freq. Default is False.
export_formats (list): List of formats that exported at the end of
the experiment. Default is None.
max_failures (int): Try to recover a trial from its last
checkpoint at least this many times. Only applies if
checkpointing is enabled. Setting to -1 will lead to infinite
recovery retries. Defaults to 3.
restore (str): Path to checkpoint. Only makes sense to set if
running 1 trial. Defaults to None.
repeat: Deprecated and will be removed in future versions of
Ray. Use `num_samples` instead.
trial_resources: Deprecated and will be removed in future versions of
Ray. Use `resources_per_trial` instead.
custom_loggers: Deprecated and will be removed in future versions of
Ray. Use `loggers` instead.
Implicitly registers the Trainable if needed.
Examples:
>>> experiment_spec = Experiment(
@@ -107,7 +55,6 @@ class Experiment(object):
>>> upload_dir="s3://your_bucket/path",
>>> checkpoint_freq=10,
>>> max_failures=2)
"""
def __init__(self,
@@ -121,7 +68,6 @@ class Experiment(object):
upload_dir=None,
trial_name_creator=None,
loggers=None,
custom_loggers=None,
sync_function=None,
checkpoint_freq=0,
checkpoint_at_end=False,
@@ -129,7 +75,8 @@ class Experiment(object):
max_failures=3,
restore=None,
repeat=None,
trial_resources=None):
trial_resources=None,
custom_loggers=None):
if sync_function:
assert upload_dir, "Need `upload_dir` if sync_function given."
@@ -137,13 +84,13 @@ class Experiment(object):
_raise_deprecation_note("repeat", "num_samples", soft=False)
if trial_resources:
_raise_deprecation_note(
"trial_resources", "resources_per_trial", soft=True)
resources_per_trial = trial_resources
"trial_resources", "resources_per_trial", soft=False)
if custom_loggers:
_raise_deprecation_note("custom_loggers", "loggers", soft=False)
run_identifier = Experiment._register_if_needed(run)
spec = {
"run": Experiment._register_if_needed(run),
"run": run_identifier,
"stop": stop or {},
"config": config or {},
"resources_per_trial": resources_per_trial,
@@ -160,7 +107,7 @@ class Experiment(object):
"restore": restore
}
self.name = name
self.name = name or run_identifier
self.spec = spec
@classmethod
+2 -2
View File
@@ -368,7 +368,7 @@ class RayTrialExecutor(TrialExecutor):
if not resources or "CPU" not in resources:
raise TuneError("Cluster resources cannot be detected. "
"You can resume this experiment by passing in "
"`resume=True` to `run_experiments`.")
"`resume=True` to `run`.")
resources = resources.copy()
num_cpus = resources.pop("CPU")
@@ -418,7 +418,7 @@ class RayTrialExecutor(TrialExecutor):
"may appear to hang until enough resources are added to the "
"cluster (e.g., via autoscaling). You can disable this "
"behavior by specifying `queue_trials=False` in "
"ray.tune.run_experiments().")
"ray.tune.run().")
return True
return False
-9
View File
@@ -38,15 +38,6 @@ class BayesOptSearch(SuggestionAlgorithm):
>>> 'width': (0, 20),
>>> 'height': (-100, 100),
>>> }
>>> config = {
>>> "my_exp": {
>>> "run": "exp",
>>> "num_samples": 10 if args.smoke_test else 1000,
>>> "stop": {
>>> "training_iteration": 100
>>> },
>>> }
>>> }
>>> algo = BayesOptSearch(
>>> space, max_concurrent=4, reward_attr="neg_mean_loss")
"""
-9
View File
@@ -55,15 +55,6 @@ class HyperOptSearch(SuggestionAlgorithm):
>>> 'height': 0,
>>> 'activation': 0, # The index of "relu"
>>> }]
>>> config = {
>>> "my_exp": {
>>> "run": "exp",
>>> "num_samples": 10 if args.smoke_test else 1000,
>>> "stop": {
>>> "training_iteration": 100
>>> },
>>> }
>>> }
>>> algo = HyperOptSearch(
>>> space, max_concurrent=4, reward_attr="neg_mean_loss",
>>> points_to_evaluate=current_best_params)
-9
View File
@@ -32,15 +32,6 @@ class NevergradSearch(SuggestionAlgorithm):
Example:
>>> from nevergrad.optimization import optimizerlib
>>> optimizer = optimizerlib.OnePlusOne(dimension=1, budget=100)
>>> config = {
>>> "my_exp": {
>>> "run": "exp",
>>> "num_samples": 10,
>>> "stop": {
>>> "training_iteration": 100
>>> },
>>> }
>>> }
>>> algo = NevergradSearch(
>>> optimizer, max_concurrent=4, reward_attr="neg_mean_loss")
"""
+1 -10
View File
@@ -48,17 +48,8 @@ class SigOptSearch(SuggestionAlgorithm):
>>> },
>>> },
>>> ]
>>> config = {
>>> "my_exp": {
>>> "run": "exp",
>>> "num_samples": 10 if args.smoke_test else 1000,
>>> "stop": {
>>> "training_iteration": 100
>>> },
>>> }
>>> }
>>> algo = SigOptSearch(
>>> parameters, name="SigOpt Example Experiment",
>>> space, name="SigOpt Example Experiment",
>>> max_concurrent=1, reward_attr="neg_mean_loss")
"""
-9
View File
@@ -70,15 +70,6 @@ class SkOptSearch(SuggestionAlgorithm):
>>> from skopt import Optimizer
>>> optimizer = Optimizer([(0,20),(-100,100)])
>>> current_best_params = [[10, 0], [15, -20]]
>>> config = {
>>> "my_exp": {
>>> "run": "exp",
>>> "num_samples": 10,
>>> "stop": {
>>> "training_iteration": 100
>>> },
>>> }
>>> }
>>> algo = SkOptSearch(optimizer,
>>> ["width", "height"],
>>> max_concurrent=4,
@@ -743,22 +743,6 @@ class RunExperimentTest(unittest.TestCase):
self.assertRaises(TuneError, fail_trial)
def testDeprecatedResources(self):
class train(Trainable):
def _train(self):
return {"timesteps_this_iter": 1, "done": True}
trials = run_experiments({
"foo": {
"run": train,
"trial_resources": {
"cpu": 1
}
}
})
for trial in trials:
self.assertEqual(trial.status, Trial.TERMINATED)
def testCustomResources(self):
ray.shutdown()
ray.init(resources={"hi": 3})
+1 -1
View File
@@ -245,7 +245,7 @@ class TrialRunner(object):
("Insufficient cluster resources to launch trial: "
"trial requested {} but the cluster has only {}. "
"Pass `queue_trials=True` in "
"ray.tune.run_experiments() or on the command "
"ray.tune.run() or on the command "
"line to queue trials until the cluster scales "
"up. {}").format(
trial.resources.summary_string(),
+194 -81
View File
@@ -8,7 +8,7 @@ import os
import time
from ray.tune.error import TuneError
from ray.tune.experiment import convert_to_experiment_list
from ray.tune.experiment import convert_to_experiment_list, Experiment
from ray.tune.suggest import BasicVariantGenerator
from ray.tune.trial import Trial, DEBUG_PRINT_INTERVAL
from ray.tune.log_sync import wait_for_log_sync
@@ -35,39 +35,113 @@ def _make_scheduler(args):
args.scheduler, _SCHEDULERS.keys()))
def _find_checkpoint_dir(exp_list):
assert exp_list, "Experiments must be specified via `run_experiments`"
exp = exp_list[0]
# TODO(rliaw): Make sure this is resolved earlier.
def _find_checkpoint_dir(exp):
# TODO(rliaw): Make sure the checkpoint_dir is resolved earlier.
# Right now it is resolved somewhere far down the trial generation process
return os.path.join(exp.spec["local_dir"], exp.name)
def try_restore_runner(checkpoint_dir, search_alg, scheduler, trial_executor):
new_runner = None
try:
new_runner = TrialRunner.restore(checkpoint_dir, search_alg, scheduler,
trial_executor)
except Exception:
logger.exception("Runner restore failed. Restarting experiment.")
return new_runner
def _prompt_restore(checkpoint_dir, resume):
restore = False
if TrialRunner.checkpoint_exists(checkpoint_dir):
if resume == "prompt":
msg = ("Found incomplete experiment at {}. "
"Would you like to resume it?".format(checkpoint_dir))
restore = click.confirm(msg, default=False)
if restore:
logger.info("Tip: to always resume, "
"pass resume=True to run()")
else:
logger.info("Tip: to always start a new experiment, "
"pass resume=False to run()")
elif resume:
restore = True
else:
logger.info("Tip: to resume incomplete experiments, "
"pass resume='prompt' or resume=True to run()")
else:
logger.info(
"Did not find checkpoint file in {}.".format(checkpoint_dir))
return restore
def run_experiments(experiments,
search_alg=None,
scheduler=None,
with_server=False,
server_port=TuneServer.DEFAULT_PORT,
verbose=2,
resume=False,
queue_trials=False,
reuse_actors=False,
trial_executor=None,
raise_on_failed_trial=True):
"""Runs and blocks until all trials finish.
def run(run_or_experiment,
name=None,
stop=None,
config=None,
resources_per_trial=None,
num_samples=1,
local_dir=None,
upload_dir=None,
trial_name_creator=None,
loggers=None,
sync_function=None,
checkpoint_freq=0,
checkpoint_at_end=False,
export_formats=None,
max_failures=3,
restore=None,
search_alg=None,
scheduler=None,
with_server=False,
server_port=TuneServer.DEFAULT_PORT,
verbose=2,
resume=False,
queue_trials=False,
reuse_actors=False,
trial_executor=None,
raise_on_failed_trial=True):
"""Executes training.
Args:
experiments (Experiment | list | dict): Experiments to run. Will be
passed to `search_alg` via `add_configurations`.
run_or_experiment (function|class|str|Experiment): If
function|class|str, this is the algorithm or model to train.
This may refer to the name of a built-on algorithm
(e.g. RLLib's DQN or PPO), a user-defined trainable
function or class, or the string identifier of a
trainable function or class registered in the tune registry.
If Experiment, then Tune will execute training based on
Experiment.spec.
name (str): Name of experiment.
stop (dict): The stopping criteria. The keys may be any field in
the return result of 'train()', whichever is reached first.
Defaults to empty dict.
config (dict): Algorithm-specific configuration for Tune variant
generation (e.g. env, hyperparams). Defaults to empty dict.
Custom search algorithms may ignore this.
resources_per_trial (dict): Machine resources to allocate per trial,
e.g. ``{"cpu": 64, "gpu": 8}``. Note that GPUs will not be
assigned unless you specify them here. Defaults to 1 CPU and 0
GPUs in ``Trainable.default_resource_request()``.
num_samples (int): Number of times to sample from the
hyperparameter space. Defaults to 1. If `grid_search` is
provided as an argument, the grid will be repeated
`num_samples` of times.
local_dir (str): Local dir to save training results to.
Defaults to ``~/ray_results``.
upload_dir (str): Optional URI to sync training results
to (e.g. ``s3://bucket``).
trial_name_creator (func): Optional function for generating
the trial string representation.
loggers (list): List of logger creators to be used with
each Trial. If None, defaults to ray.tune.logger.DEFAULT_LOGGERS.
See `ray/tune/logger.py`.
sync_function (func|str): Function for syncing the local_dir to
upload_dir. If string, then it must be a string template for
syncer to run. If not provided, the sync command defaults
to standard S3 or gsutil sync comamnds.
checkpoint_freq (int): How many training iterations between
checkpoints. A value of 0 (default) disables checkpointing.
checkpoint_at_end (bool): Whether to checkpoint at the end of the
experiment regardless of the checkpoint_freq. Default is False.
export_formats (list): List of formats that exported at the end of
the experiment. Default is None.
max_failures (int): Try to recover a trial from its last
checkpoint at least this many times. Only applies if
checkpointing is enabled. Setting to -1 will lead to infinite
recovery retries. Defaults to 3.
restore (str): Path to checkpoint. Only makes sense to set if
running 1 trial. Defaults to None.
search_alg (SearchAlgorithm): Search Algorithm. Defaults to
BasicVariantGenerator.
scheduler (TrialScheduler): Scheduler for executing
@@ -93,70 +167,54 @@ def run_experiments(experiments,
raise_on_failed_trial (bool): Raise TuneError if there exists failed
trial (of ERROR state) when the experiments complete.
Examples:
>>> experiment_spec = Experiment("experiment", my_func)
>>> run_experiments(experiments=experiment_spec)
>>> experiment_spec = {"experiment": {"run": my_func}}
>>> run_experiments(experiments=experiment_spec)
>>> run_experiments(
>>> experiments=experiment_spec,
>>> scheduler=MedianStoppingRule(...))
>>> run_experiments(
>>> experiments=experiment_spec,
>>> search_alg=SearchAlgorithm(),
>>> scheduler=MedianStoppingRule(...))
Returns:
List of Trial objects, holding data for each executed trial.
List of Trial objects.
Raises:
TuneError if any trials failed and `raise_on_failed_trial` is True.
Examples:
>>> tune.run(mytrainable, scheduler=PopulationBasedTraining())
>>> tune.run(mytrainable, num_samples=5, reuse_actors=True)
>>> tune.run(
"PG",
num_samples=5,
config={
"env": "CartPole-v0",
"lr": tune.sample_from(lambda _: np.random.rand())
}
)
"""
# This is important to do this here
# because it schematize the experiments
# and it conducts the implicit registration.
experiments = convert_to_experiment_list(experiments)
checkpoint_dir = _find_checkpoint_dir(experiments)
experiment = run_or_experiment
if not isinstance(run_or_experiment, Experiment):
experiment = Experiment(
name, run_or_experiment, stop, config, resources_per_trial,
num_samples, local_dir, upload_dir, trial_name_creator, loggers,
sync_function, checkpoint_freq, checkpoint_at_end, export_formats,
max_failures, restore)
else:
logger.debug("Ignoring some parameters passed into tune.run.")
checkpoint_dir = _find_checkpoint_dir(experiment)
should_restore = _prompt_restore(checkpoint_dir, resume)
runner = None
restore = False
if TrialRunner.checkpoint_exists(checkpoint_dir):
if resume == "prompt":
msg = ("Found incomplete experiment at {}. "
"Would you like to resume it?".format(checkpoint_dir))
restore = click.confirm(msg, default=False)
if restore:
logger.info("Tip: to always resume, "
"pass resume=True to run_experiments()")
else:
logger.info("Tip: to always start a new experiment, "
"pass resume=False to run_experiments()")
elif resume:
restore = True
else:
logger.info(
"Tip: to resume incomplete experiments, "
"pass resume='prompt' or resume=True to run_experiments()")
else:
logger.info(
"Did not find checkpoint file in {}.".format(checkpoint_dir))
if restore:
runner = try_restore_runner(checkpoint_dir, search_alg, scheduler,
trial_executor)
if should_restore:
try:
runner = TrialRunner.restore(checkpoint_dir, search_alg, scheduler,
trial_executor)
except Exception:
logger.exception("Runner restore failed. Restarting experiment.")
else:
logger.info("Starting a new experiment.")
if not runner:
if scheduler is None:
scheduler = FIFOScheduler()
scheduler = scheduler or FIFOScheduler()
search_alg = search_alg or BasicVariantGenerator()
if search_alg is None:
search_alg = BasicVariantGenerator()
search_alg.add_configurations(experiments)
search_alg.add_configurations([experiment])
runner = TrialRunner(
search_alg,
@@ -197,3 +255,58 @@ def run_experiments(experiments,
logger.error("Trials did not complete: %s", errored_trials)
return runner.get_trials()
def run_experiments(experiments,
search_alg=None,
scheduler=None,
with_server=False,
server_port=TuneServer.DEFAULT_PORT,
verbose=2,
resume=False,
queue_trials=False,
reuse_actors=False,
trial_executor=None,
raise_on_failed_trial=True):
"""Runs and blocks until all trials finish.
Examples:
>>> experiment_spec = Experiment("experiment", my_func)
>>> run_experiments(experiments=experiment_spec)
>>> experiment_spec = {"experiment": {"run": my_func}}
>>> run_experiments(experiments=experiment_spec)
>>> run_experiments(
>>> experiments=experiment_spec,
>>> scheduler=MedianStoppingRule(...))
>>> run_experiments(
>>> experiments=experiment_spec,
>>> search_alg=SearchAlgorithm(),
>>> scheduler=MedianStoppingRule(...))
Returns:
List of Trial objects, holding data for each executed trial.
"""
# This is important to do this here
# because it schematize the experiments
# and it conducts the implicit registration.
experiments = convert_to_experiment_list(experiments)
trials = []
for exp in experiments:
trials += run(
exp,
search_alg=search_alg,
scheduler=scheduler,
with_server=with_server,
server_port=server_port,
verbose=verbose,
resume=resume,
queue_trials=queue_trials,
reuse_actors=reuse_actors,
trial_executor=trial_executor,
raise_on_failed_trial=raise_on_failed_trial)
return trials