[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
+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