enable recursive parsing for single gpu inputs (#121)

* added tests

* added single gpu data transfer recursive

* added single gpu data transfer recursive

* added single gpu data transfer recursive

* added single gpu data transfer recursive

* added single gpu data transfer recursive

* added single gpu data transfer recursive
This commit is contained in:
William Falcon
2019-08-15 09:39:09 -04:00
committed by GitHub
parent 0f287ce5ea
commit db9254acbe
2 changed files with 57 additions and 6 deletions
+22 -6
View File
@@ -390,9 +390,8 @@ class Trainer(TrainerIO):
elif self.single_gpu:
# put inputs on gpu manually
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)
data_batch = self.transfer_batch_to_gpu(data_batch, gpu_id)
args[0] = data_batch
# do non dp, ddp step
output = model.validation_step(*args)
@@ -905,6 +904,24 @@ We recommend you switch to ddp if you want to use amp
blacklist = {'batch_nb', 'v_nb', 'gpu'}
return blacklist
def transfer_batch_to_gpu(self, batch, gpu_id):
# base case
if isinstance(batch, torch.Tensor):
return batch.cuda(gpu_id)
# when list
elif isinstance(batch, list):
for i, x in enumerate(batch):
batch[i] = self.transfer_batch_to_gpu(x, gpu_id)
return batch
# when dict
elif isinstance(batch, dict):
for k, v in batch.items():
batch[k] = self.transfer_batch_to_gpu(v, gpu_id)
return batch
def __tng_forward(self, data_batch, batch_nb, opt_idx):
"""
Handle forward for each training case (distributed, single gpu, etc...)
@@ -926,9 +943,8 @@ We recommend you switch to ddp if you want to use amp
output = self.model(*args)
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)
data_batch = self.transfer_batch_to_gpu(data_batch, gpu_id)
args[0] = data_batch
output = self.model.training_step(*args)
else:
+35
View File
@@ -26,6 +26,41 @@ np.random.seed(SEED)
# ------------------------------------------------------------------------
# TESTS
# ------------------------------------------------------------------------
def test_single_gpu_batch_parse():
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
trainer = Trainer()
# batch is just a tensor
batch = torch.rand(2, 3)
batch = trainer.transfer_batch_to_gpu(batch, 0)
assert batch.device.index == 0 and batch.type() == 'torch.cuda.FloatTensor'
# tensor list
batch = [torch.rand(2, 3), torch.rand(2, 3)]
batch = trainer.transfer_batch_to_gpu(batch, 0)
assert batch[0].device.index == 0 and batch[0].type() == 'torch.cuda.FloatTensor'
assert batch[1].device.index == 0 and batch[1].type() == 'torch.cuda.FloatTensor'
# tensor list of lists
batch = [[torch.rand(2, 3), torch.rand(2, 3)]]
batch = trainer.transfer_batch_to_gpu(batch, 0)
assert batch[0][0].device.index == 0 and batch[0][0].type() == 'torch.cuda.FloatTensor'
assert batch[0][1].device.index == 0 and batch[0][1].type() == 'torch.cuda.FloatTensor'
# tensor dict
batch = [{'a': torch.rand(2, 3), 'b': torch.rand(2, 3)}]
batch = trainer.transfer_batch_to_gpu(batch, 0)
assert batch[0]['a'].device.index == 0 and batch[0]['a'].type() == 'torch.cuda.FloatTensor'
assert batch[0]['b'].device.index == 0 and batch[0]['b'].type() == 'torch.cuda.FloatTensor'
def test_early_stopping_cpu_model():
"""