mirror of
https://github.com/wassname/ray.git
synced 2026-07-15 11:25:40 +08:00
[SGD] Dataset API (#7839)
This commit is contained in:
@@ -138,7 +138,9 @@ class TorchRunner:
|
||||
def setup_components(self):
|
||||
"""Runs the creator functions without any distributed coordination."""
|
||||
logger.debug("Loading data.")
|
||||
self._initialize_dataloaders()
|
||||
if self.data_creator and callable(self.data_creator):
|
||||
self._initialize_dataloaders()
|
||||
|
||||
logger.debug("Creating model")
|
||||
self.models = self.model_creator(self.config)
|
||||
if not isinstance(self.models, Iterable):
|
||||
@@ -181,7 +183,11 @@ class TorchRunner:
|
||||
"""Finds a free port on the current node."""
|
||||
return utils.find_free_port()
|
||||
|
||||
def train_epoch(self, num_steps=None, profile=False, info=None):
|
||||
def train_epoch(self,
|
||||
num_steps=None,
|
||||
profile=False,
|
||||
info=None,
|
||||
iterator=None):
|
||||
"""Runs a training epoch and updates the model parameters."""
|
||||
logger.debug("Begin Training Step {}".format(self.epochs + 1))
|
||||
info = info or {}
|
||||
@@ -193,9 +199,18 @@ class TorchRunner:
|
||||
SCHEDULER_STEP: self.scheduler_step_freq
|
||||
})
|
||||
with self.timers.record("train_epoch"):
|
||||
iterator = self.train_loader
|
||||
if iterator is None:
|
||||
iterator = iter(self.train_loader)
|
||||
else:
|
||||
# Dataset will provide us with a list of tuples but we
|
||||
# need two lists.
|
||||
def format_batch(batch):
|
||||
features, targets = zip(*batch)
|
||||
return torch.cat(features), torch.cat(targets)
|
||||
|
||||
iterator = map(format_batch, iterator)
|
||||
if num_steps:
|
||||
iterator = itertools.islice(iter(self.train_loader), num_steps)
|
||||
iterator = itertools.islice(iterator, num_steps)
|
||||
train_stats = self.training_operator.train_epoch(iterator, info)
|
||||
|
||||
self.epochs += 1
|
||||
|
||||
@@ -17,6 +17,7 @@ from ray.util.sgd.torch.distributed_torch_runner import (
|
||||
from ray.util.sgd.utils import check_for_failure, NUM_SAMPLES, BATCH_SIZE
|
||||
from ray.util.sgd.torch.torch_runner import TorchRunner
|
||||
from ray.util.sgd.torch.constants import VALID_SCHEDULER_STEP
|
||||
from ray.util.sgd.data import Dataset
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
RESIZE_COOLDOWN_S = 10
|
||||
@@ -194,11 +195,9 @@ class TorchTrainer:
|
||||
"For more information, see "
|
||||
"https://github.com/pytorch/examples/issues/467."))
|
||||
|
||||
if not (callable(model_creator) and callable(optimizer_creator)
|
||||
and callable(data_creator)):
|
||||
if not (callable(model_creator) and callable(optimizer_creator)):
|
||||
raise ValueError(
|
||||
"Must provide a callable model_creator, optimizer_creator, "
|
||||
"and data_creator.")
|
||||
"Must provide a callable model_creator and optimizer_creator.")
|
||||
|
||||
if num_replicas is not None:
|
||||
raise DeprecationWarning(
|
||||
@@ -379,7 +378,8 @@ class TorchTrainer:
|
||||
profile=False,
|
||||
reduce_results=True,
|
||||
max_retries=3,
|
||||
info=None):
|
||||
info=None,
|
||||
dataset=None):
|
||||
"""Runs a training epoch.
|
||||
|
||||
Calls `operator.train_epoch()` on N parallel workers simultaneously
|
||||
@@ -405,6 +405,8 @@ class TorchTrainer:
|
||||
in case of shared cluster usage. Defaults to 3.
|
||||
info (dict): Optional dictionary passed to the training
|
||||
operator for ``train_epoch`` and ``train_batch``.
|
||||
dataset (Dataset): Optional dataset to train with. If specified,
|
||||
the dataloader passed in via data_creator will be ignored.
|
||||
|
||||
Returns:
|
||||
(dict | list) A dictionary of metrics for training.
|
||||
@@ -414,11 +416,14 @@ class TorchTrainer:
|
||||
length will be equal to ``num_workers``.
|
||||
"""
|
||||
assert max_retries >= 0, "`max_retries` must be non-negative."
|
||||
assert isinstance(dataset, Dataset) is not None \
|
||||
or self.data_creator, \
|
||||
"Must specify either a data creator or a dataset"
|
||||
if self._should_resize():
|
||||
logger.info("Resize opportunity detected. Attempting to scale up.")
|
||||
self._resize_workers()
|
||||
success, worker_stats = self._train_epoch(
|
||||
num_steps=num_steps, profile=profile, info=info)
|
||||
num_steps=num_steps, profile=profile, info=info, dataset=dataset)
|
||||
# Fault handling
|
||||
for i in range(max_retries):
|
||||
if success:
|
||||
@@ -429,7 +434,10 @@ class TorchTrainer:
|
||||
logger.info("Retrying training step with %d workers." %
|
||||
(len(self.remote_workers) + 1))
|
||||
success, worker_stats = self._train_epoch(
|
||||
num_steps=num_steps, profile=profile, info=info)
|
||||
num_steps=num_steps,
|
||||
profile=profile,
|
||||
info=info,
|
||||
dataset=dataset)
|
||||
if not success:
|
||||
raise RuntimeError("Training run failed.")
|
||||
|
||||
@@ -452,14 +460,26 @@ class TorchTrainer:
|
||||
stats[stat_key] = worker_stats[0][stat_key]
|
||||
return stats
|
||||
|
||||
def _train_epoch(self, num_steps=None, profile=False, info=None):
|
||||
def _train_epoch(self,
|
||||
num_steps=None,
|
||||
profile=False,
|
||||
info=None,
|
||||
dataset=None):
|
||||
params = dict(num_steps=num_steps, profile=profile, info=info)
|
||||
|
||||
remote_worker_stats = [
|
||||
w.train_epoch.remote(**params) for w in self.remote_workers
|
||||
]
|
||||
remote_worker_stats = []
|
||||
if dataset:
|
||||
dataset.set_num_shards(self.max_replicas)
|
||||
for i, w in enumerate(self.remote_workers):
|
||||
params = dict(num_steps=num_steps, profile=profile, info=info)
|
||||
if dataset:
|
||||
params["iterator"] = dataset.get_shard(i)
|
||||
stats = w.train_epoch.remote(**params)
|
||||
remote_worker_stats.append(stats)
|
||||
|
||||
try:
|
||||
if dataset:
|
||||
params["iterator"] = dataset.get_shard(
|
||||
len(self.remote_workers))
|
||||
local_worker_stats = self.local_worker.train_epoch(**params)
|
||||
except RuntimeError as err:
|
||||
if "gloo" in err.args[0] and "Timed out" in err.args[0]:
|
||||
|
||||
Reference in New Issue
Block a user