[tune] Search alg checkpointing during training (#9803)

Co-authored-by: krfricke <krfricke@users.noreply.github.com>
This commit is contained in:
Richard Liaw
2020-08-03 15:07:31 -07:00
committed by GitHub
co-authored by krfricke
parent db09f70315
commit c6404e8cf6
11 changed files with 320 additions and 45 deletions
+4 -4
View File
@@ -270,16 +270,16 @@ class BayesOptSearch(Searcher):
"""Register given tuple of params and results."""
self.optimizer.register(params, self._metric_op * result[self.metric])
def save(self, checkpoint_dir):
def save(self, checkpoint_path):
"""Storing current optimizer state."""
with open(checkpoint_dir, "wb") as f:
with open(checkpoint_path, "wb") as f:
pickle.dump(
(self.optimizer, self._buffered_trial_results,
self._total_random_search_trials, self._config_counter), f)
def restore(self, checkpoint_dir):
def restore(self, checkpoint_path):
"""Restoring current optimizer state."""
with open(checkpoint_dir, "rb") as f:
with open(checkpoint_path, "rb") as f:
(self.optimizer, self._buffered_trial_results,
self._total_random_search_trials,
self._config_counter) = pickle.load(f)
+4 -4
View File
@@ -212,13 +212,13 @@ class HyperOptSearch(Searcher):
t for t in self._hpopt_trials.trials if t["tid"] == hyperopt_tid
][0]
def save(self, checkpoint_dir):
def save(self, checkpoint_path):
trials_object = (self._hpopt_trials, self.rstate.get_state())
with open(checkpoint_dir, "wb") as outputFile:
with open(checkpoint_path, "wb") as outputFile:
pickle.dump(trials_object, outputFile)
def restore(self, checkpoint_dir):
with open(checkpoint_dir, "rb") as inputFile:
def restore(self, checkpoint_path):
with open(checkpoint_path, "rb") as inputFile:
trials_object = pickle.load(inputFile)
self._hpopt_trials = trials_object[0]
self.rstate.set_state(trials_object[1])
+4 -4
View File
@@ -137,13 +137,13 @@ class NevergradSearch(Searcher):
self._nevergrad_opt.tell(ng_trial_info,
self._metric_op * result[self._metric])
def save(self, checkpoint_dir):
def save(self, checkpoint_path):
trials_object = (self._nevergrad_opt, self._parameters)
with open(checkpoint_dir, "wb") as outputFile:
with open(checkpoint_path, "wb") as outputFile:
pickle.dump(trials_object, outputFile)
def restore(self, checkpoint_dir):
with open(checkpoint_dir, "rb") as inputFile:
def restore(self, checkpoint_path):
with open(checkpoint_path, "rb") as inputFile:
trials_object = pickle.load(inputFile)
self._nevergrad_opt = trials_object[0]
self._parameters = trials_object[1]
+6
View File
@@ -62,3 +62,9 @@ class SearchAlgorithm:
def set_finished(self):
"""Marks the search algorithm as finished."""
self._finished = True
def save(self, *args):
pass
def restore(self, *args):
pass
+4 -4
View File
@@ -130,13 +130,13 @@ class SigOptSearch(Searcher):
failed=True, suggestion=self._live_trial_mapping[trial_id].id)
del self._live_trial_mapping[trial_id]
def save(self, checkpoint_dir):
def save(self, checkpoint_path):
trials_object = (self.conn, self.experiment)
with open(checkpoint_dir, "wb") as outputFile:
with open(checkpoint_path, "wb") as outputFile:
pickle.dump(trials_object, outputFile)
def restore(self, checkpoint_dir):
with open(checkpoint_dir, "rb") as inputFile:
def restore(self, checkpoint_path):
with open(checkpoint_path, "rb") as inputFile:
trials_object = pickle.load(inputFile)
self.conn = trials_object[0]
self.experiment = trials_object[1]
+4 -4
View File
@@ -157,13 +157,13 @@ class SkOptSearch(Searcher):
self._skopt_opt.tell(skopt_trial_info,
self._metric_op * result[self._metric])
def save(self, checkpoint_dir):
def save(self, checkpoint_path):
trials_object = (self._initial_points, self._skopt_opt)
with open(checkpoint_dir, "wb") as outputFile:
with open(checkpoint_path, "wb") as outputFile:
pickle.dump(trials_object, outputFile)
def restore(self, checkpoint_dir):
with open(checkpoint_dir, "rb") as inputFile:
def restore(self, checkpoint_path):
with open(checkpoint_path, "rb") as inputFile:
trials_object = pickle.load(inputFile)
self._initial_points = trials_object[0]
self._skopt_opt = trials_object[1]
+106 -4
View File
@@ -1,5 +1,6 @@
import copy
import logging
import os
from ray.tune.error import TuneError
from ray.tune.experiment import convert_to_experiment_list
@@ -58,6 +59,7 @@ class Searcher:
"""
FINISHED = "FINISHED"
CKPT_FILE = "searcher-state.pkl"
def __init__(self,
metric="episode_reward_mean",
@@ -130,14 +132,108 @@ class Searcher:
"""
raise NotImplementedError
def save(self, checkpoint_dir):
"""Save function for this object."""
def save(self, checkpoint_path):
"""Save state to path for this search algorithm.
Args:
checkpoint_path (str): File where the search algorithm
state is saved. This path should be used later when
restoring from file.
Example:
.. code-block:: python
search_alg = Searcher(...)
analysis = tune.run(
cost,
num_samples=5,
search_alg=search_alg,
name=self.experiment_name,
local_dir=self.tmpdir)
search_alg.save("./my_favorite_path.pkl")
.. versionchanged:: 0.8.7
Save is automatically called by `tune.run`. You can use
`restore_from_dir` to restore from an experiment directory
such as `~/ray_results/trainable`.
"""
raise NotImplementedError
def restore(self, checkpoint_dir):
"""Restore function for this object."""
def restore(self, checkpoint_path):
"""Restore state for this search algorithm
Args:
checkpoint_path (str): File where the search algorithm
state is saved. This path should be the same
as the one provided to "save".
Example:
.. code-block:: python
search_alg.save("./my_favorite_path.pkl")
search_alg2 = Searcher(...)
search_alg2 = ConcurrencyLimiter(search_alg2, 1)
search_alg2.restore(checkpoint_path)
tune.run(cost, num_samples=5, search_alg=search_alg2)
"""
raise NotImplementedError
def save_to_dir(self, checkpoint_dir):
"""Automatically saves the given searcher to the checkpoint_dir.
This is automatically used by tune.run during a Tune job.
"""
tmp_search_ckpt_path = os.path.join(checkpoint_dir,
".tmp_searcher_ckpt")
success = True
try:
self.save(tmp_search_ckpt_path)
except NotImplementedError as e:
logger.warning(e)
success = False
if success and os.path.exists(tmp_search_ckpt_path):
os.rename(tmp_search_ckpt_path,
os.path.join(checkpoint_dir, Searcher.CKPT_FILE))
def restore_from_dir(self, checkpoint_dir):
"""Restores the state of a searcher from a given checkpoint_dir.
Typically, you should use this function to restore from an
experiment directory such as `~/ray_results/trainable`.
.. code-block:: python
experiment_1 = tune.run(
cost,
num_samples=5,
search_alg=search_alg,
verbose=0,
name=self.experiment_name,
local_dir="~/my_results")
search_alg2 = Searcher()
search_alg2.restore_from_dir(
os.path.join("~/my_results", self.experiment_name)
"""
checkpoint_path = os.path.join(checkpoint_dir, Searcher.CKPT_FILE)
if os.path.exists(checkpoint_path):
self.restore(checkpoint_path)
else:
raise FileNotFoundError(
"{filename} not found in {directory}. Unable to restore "
"searcher state from directory.".format(
filename=Searcher.CKPT_FILE, directory=checkpoint_dir))
@property
def metric(self):
"""The training result objective value attribute."""
@@ -294,6 +390,12 @@ class SearchGenerator(SearchAlgorithm):
def is_finished(self):
return self._counter >= self._total_samples or self._finished
def save(self, checkpoint_path):
self.searcher.save(checkpoint_path)
def restore(self, checkpoint_path):
self.searcher.restore(checkpoint_path)
class _MockSearcher(Searcher):
def __init__(self, **kwargs):
+4 -4
View File
@@ -133,12 +133,12 @@ class ZOOptSearch(Searcher):
del self._live_trial_mapping[trial_id]
def save(self, checkpoint_dir):
def save(self, checkpoint_path):
trials_object = self.optimizer
with open(checkpoint_dir, "wb") as output:
with open(checkpoint_path, "wb") as output:
pickle.dump(trials_object, output)
def restore(self, checkpoint_dir):
with open(checkpoint_dir, "rb") as input:
def restore(self, checkpoint_path):
with open(checkpoint_path, "rb") as input:
trials_object = pickle.load(input)
self.optimizer = trials_object