This commit is contained in:
William Falcon
2019-08-07 16:02:04 -04:00
3 changed files with 72 additions and 2 deletions
+1 -1
View File
@@ -172,7 +172,7 @@ def training_step(self, data_batch, batch_nb):
# define your own forward and loss calculation # define your own forward and loss calculation
hidden_states = self.encoder(x) hidden_states = self.encoder(x)
# even as complex as a seq-2seq + attn model # even as complex as a seq-2-seq + attn model
# (this is just a toy, non-working example to illustrate) # (this is just a toy, non-working example to illustrate)
start_token = '<SOS>' start_token = '<SOS>'
last_hidden = torch.zeros(...) last_hidden = torch.zeros(...)
+43 -1
View File
@@ -105,7 +105,7 @@ class Trainer(TrainerIO):
:param log_save_interval: :param log_save_interval:
:param add_log_row_interval: :param add_log_row_interval:
:param distributed_backend: :param distributed_backend:
'np' to use DistributedParallel, 'dp' to use DistributedDataParallel 'do' to use DistributedParallel, 'dp' to use DistributedDataParallel, 'n' to use none
:param use_amp: :param use_amp:
:param print_nan_grads: :param print_nan_grads:
:param print_weights_summary: :param print_weights_summary:
@@ -147,6 +147,7 @@ class Trainer(TrainerIO):
self.node_rank = 0 self.node_rank = 0
self.use_ddp = False self.use_ddp = False
self.use_dp = False self.use_dp = False
self.single_gpu = False
# training bookeeping # training bookeeping
self.total_batch_nb = 0 self.total_batch_nb = 0
@@ -194,6 +195,12 @@ class Trainer(TrainerIO):
'To silence this warning set distributed_backend=ddp' 'To silence this warning set distributed_backend=ddp'
warnings.warn(w) warnings.warn(w)
# remove dp and ddp when requesting single gpu
if self.data_parallel_device_ids is not None and len(self.data_parallel_device_ids) == 1:
self.use_ddp = False
self.use_dp = False
self.single_gpu = True
# extract SLURM flag vars # extract SLURM flag vars
# whenever we have the correct number of tasks, we let slurm manage processes # whenever we have the correct number of tasks, we let slurm manage processes
# otherwise we launch the required number of processes # otherwise we launch the required number of processes
@@ -385,6 +392,13 @@ class Trainer(TrainerIO):
output = model(data_batch, batch_i) output = model(data_batch, batch_i)
output = reduce_distributed_output(output, len(self.data_parallel_device_ids)) output = reduce_distributed_output(output, len(self.data_parallel_device_ids))
elif self.single_gpu:
gpu_id = self.data_parallel_device_ids[0]
for i, x in enumerate(data_batch):
if isinstance(x, torch.Tensor):
data_batch[i] = x.cuda(gpu_id)
output = model.validation_step(data_batch, batch_i)
else: else:
output = model.validation_step(data_batch, batch_i) output = model.validation_step(data_batch, batch_i)
@@ -463,6 +477,9 @@ If you're not using SLURM, ignore this message!
elif self.use_dp: elif self.use_dp:
self.__dp_train(model) self.__dp_train(model)
elif self.single_gpu:
self.__single_gpu_train(model)
# ON CPU # ON CPU
else: else:
# run through amp wrapper # run through amp wrapper
@@ -482,6 +499,24 @@ If you're not using SLURM, ignore this message!
# used for testing or when we need to know that training succeeded # used for testing or when we need to know that training succeeded
return 1 return 1
def __single_gpu_train(self, model):
# CHOOSE OPTIMIZER
# allow for lr schedulers as well
self.optimizers = model.configure_optimizers()
if len(self.optimizers) == 2:
self.optimizers, self.lr_schedulers = self.optimizers
model.cuda(self.data_parallel_device_ids[0])
if self.use_amp:
# An example
model, optimizers = amp.initialize(
model, self.optimizers, opt_level=self.amp_level,
)
self.optimizers = optimizers
self.__run_pretrain_routine(model)
def __dp_train(self, model): def __dp_train(self, model):
# CHOOSE OPTIMIZER # CHOOSE OPTIMIZER
@@ -814,6 +849,13 @@ We recommend you switch to ddp if you want to use amp
elif self.use_dp: elif self.use_dp:
output = self.model(data_batch, batch_nb) output = self.model(data_batch, batch_nb)
output = reduce_distributed_output(output, len(self.data_parallel_device_ids)) output = reduce_distributed_output(output, len(self.data_parallel_device_ids))
elif self.single_gpu:
gpu_id = self.data_parallel_device_ids[0]
for i, x in enumerate(data_batch):
if isinstance(x, torch.Tensor):
data_batch[i] = x.cuda(gpu_id)
output = self.model.training_step(data_batch, batch_nb)
else: else:
output = self.model.training_step(data_batch, batch_nb) output = self.model.training_step(data_batch, batch_nb)
+28
View File
@@ -27,6 +27,34 @@ np.random.seed(SEED)
# TESTS # TESTS
# ------------------------------------------------------------------------ # ------------------------------------------------------------------------
def test_amp_single_gpu():
"""
Make sure DDP + AMP work
:return:
"""
if not torch.cuda.is_available():
warnings.warn('test_amp_gpu_ddp cannot run.'
'Rerun on a GPU node to run this test')
return
if not torch.cuda.device_count() > 1:
warnings.warn('test_amp_gpu_ddp cannot run.'
'Rerun on a node with 2+ GPUs to run this test')
return
hparams = get_hparams()
model = LightningTestModel(hparams)
trainer_options = dict(
progress_bar=True,
max_nb_epochs=1,
gpus=[0],
distributed_backend='dp',
use_amp=True
)
run_gpu_model_test(trainer_options, model, hparams)
def test_cpu_restore_training(): def test_cpu_restore_training():
""" """
Verify continue training session on CPU Verify continue training session on CPU