I have evaluation function, which return score based on p1,p2,p3,p4,p5.
So i need to find out best value for params (all int).
Of course eval_func more complicated than just p1+p2+p3+p4+p5.
I’m a bit lost in all configs, any suggestion how to implement this ?
Is there any other option?
If I use num_samples it’s slower at least x1000 times then using Optuna directly.
For example, 1000 trials with optuna complete in 47 seconds.
But using ray it’s took > 1 hour.
Am I right in this case every time ray will pick random points. Is there a way ray will try use best values accordingly to previous trials ? Or such magic doesn’t exists ?
Regarding 1, we did a couple of improvements in recent weeks to speed this up. Which version of Ray are you currently using? It seems your evaluation function takes less than a second to complete, is that correct? I’m just asking because we specifically want to make sure large scale experiments work smoothly, and if it doesn’t work for you we’re happy to look into this further.
Regarding 2, point selection depends on the search algorithm you use. In the example you are using OptunaSearch, which uses Tree-Parzen estimators per default. This sampler should pick points according to results it observed in previous trials. In fact, all search algorithms except for grid search and random search (default if you pass no search_alg argument) should adapt to previously seen evaluations.
I’m using ray, version 1.2.0.dev0 (from git). Eval function take roughly 0.005 ms.
If I can help anyhow, I’m gladly will send debug info.
Here is a simple example, best hyperparameters should be ‘p1’: 100, ‘p2’: 100. But 9 out of 10 times I run it, best values found by ray it’s way away of being ‘p1’: 100, ‘p2’: 100. What am I doing wrong?
import ray
from ray import tune
from ray.tune.suggest import ConcurrencyLimiter
from ray.tune.suggest.optuna import OptunaSearch
def easy_objective(config):
p1, p2 = config["p1"], config["p2"]
print('P1', p1, 'P2', p2)
return {'score': p1+p2}
if __name__ == "__main__":
ray.init(configure_logging=False)
algo = OptunaSearch()
algo = ConcurrencyLimiter(algo, max_concurrent=1)
analysis = tune.run(
easy_objective,
num_samples=20,
metric="score",
mode="max",
search_alg=algo,
config={
"iters": 10,
"p1": tune.randint(0, 100),
"p2": tune.randint(0, 100),
})
print("Best hyperparameters found were: ", analysis.best_config)
So a good way to speed up your training is to enable reuse_actors=True in tune.run():
import time
import ray
from ray import tune
from ray.tune.suggest import ConcurrencyLimiter
from ray.tune.suggest.optuna import OptunaSearch
def easy_objective(config):
p1, p2 = config["p1"], config["p2"]
print('P1', p1, 'P2', p2)
return {'score': p1+p2}
if __name__ == "__main__":
ray.init(configure_logging=False)
algo = OptunaSearch()
algo = ConcurrencyLimiter(algo, max_concurrent=1)
start_time = time.time()
analysis = tune.run(
easy_objective,
num_samples=100,
metric="score",
mode="max",
search_alg=algo,
config={
"iters": 10,
"p1": tune.randint(0, 100),
"p2": tune.randint(0, 100),
},
reuse_actors=True)
time_taken = time.time() - start_time
print(f"Took {time_taken:.2f} seconds.")
print("Best hyperparameters found were: ", analysis.best_config)
When training 100 trials Without reuse_actors: Took 32.28 seconds. With reuse_actors: Took 2.44 seconds.
On my MacBook, 1000 trials with this trainable take 27.07 seconds.
Regarding your second question, 100 trials finds the best solution easily:
Best hyperparameters found were: {'iters': 10, 'p1': 100, 'p2': 100}
With 10 trials this is sometimes a bit off (e.g. {'iters': 10, 'p1': 89, 'p2': 78}). Most search algorithms try random sampling at first and then converge to a more accurate representation of the objective function. I’d have to look closer into Optuna’s implementation. Generally you shouldn’t get results that are too far off after a number of trials (say, 20 or 30 or so).