diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f5f0df6ff..cb39df02a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -527,6 +527,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). - Deprecated `Trainer.devices` in favor of `Trainer.num_devices` and `Trainer.device_ids` ([#12151](https://github.com/PyTorchLightning/pytorch-lightning/pull/12151)) +- Deprecated `Trainer.root_gpu` in favor of `Trainer.strategy.root_device.index` when GPU is used. ([#12262](https://github.com/PyTorchLightning/pytorch-lightning/pull/12262)) + + ### Removed - Removed deprecated parameter `method` in `pytorch_lightning.utilities.model_helpers.is_overridden` ([#10507](https://github.com/PyTorchLightning/pytorch-lightning/pull/10507)) @@ -714,6 +717,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). - Removed public attribute `sync_batchnorm` from strategies ([#11754](https://github.com/PyTorchLightning/pytorch-lightning/pull/11754)) +- Removed `AcceleratorConnector.root_gpu` property ([#12262](https://github.com/PyTorchLightning/pytorch-lightning/pull/12262)) + + ### Fixed - Fixed an issue where `ModelCheckpoint` could delete older checkpoints when `dirpath` has changed during resumed training ([#12045](https://github.com/PyTorchLightning/pytorch-lightning/pull/12045)) diff --git a/pytorch_lightning/trainer/connectors/accelerator_connector.py b/pytorch_lightning/trainer/connectors/accelerator_connector.py index 807eb979e4..566bf68d78 100644 --- a/pytorch_lightning/trainer/connectors/accelerator_connector.py +++ b/pytorch_lightning/trainer/connectors/accelerator_connector.py @@ -788,14 +788,6 @@ class AcceleratorConnector: def num_processes(self) -> int: return self.devices if self.devices is not None else 1 - @property - def root_gpu(self) -> Optional[int]: - return ( - self.strategy.root_device.index - if not isinstance(self.accelerator, (IPUAccelerator, TPUAccelerator)) - else None - ) - @property def devices(self) -> int: if isinstance(self.strategy, SingleDeviceStrategy): diff --git a/pytorch_lightning/trainer/trainer.py b/pytorch_lightning/trainer/trainer.py index dac1d4c6a2..0972d3c7db 100644 --- a/pytorch_lightning/trainer/trainer.py +++ b/pytorch_lightning/trainer/trainer.py @@ -2055,7 +2055,11 @@ class Trainer( @property def root_gpu(self) -> Optional[int]: - return self._accelerator_connector.root_gpu + rank_zero_deprecation( + "`Trainer.root_gpu` is deprecated in v1.6 and will be removed in v1.8. " + "Please use `Trainer.strategy.root_device.index` instead." + ) + return self.strategy.root_device.index if isinstance(self.accelerator, GPUAccelerator) else None @property def tpu_cores(self) -> int: diff --git a/tests/deprecated_api/test_remove_1-8.py b/tests/deprecated_api/test_remove_1-8.py index 101f711619..1b1fd6f015 100644 --- a/tests/deprecated_api/test_remove_1-8.py +++ b/tests/deprecated_api/test_remove_1-8.py @@ -887,3 +887,41 @@ def test_trainer_config_device_ids(): " Please use `Trainer.num_devices` or `Trainer.device_ids` to get device information instead." ): trainer.devices == 2 + + +@pytest.mark.parametrize( + ["gpus", "expected_root_gpu", "strategy"], + [ + pytest.param(None, None, "ddp", id="None is None"), + pytest.param(0, None, "ddp", id="O gpus, expect gpu root device to be None."), + pytest.param(1, 0, "ddp", id="1 gpu, expect gpu root device to be 0."), + pytest.param(-1, 0, "ddp", id="-1 - use all gpus, expect gpu root device to be 0."), + pytest.param("-1", 0, "ddp", id="'-1' - use all gpus, expect gpu root device to be 0."), + pytest.param(3, 0, "ddp", id="3 gpus, expect gpu root device to be 0.(backend:ddp)"), + ], +) +def test_root_gpu_property(monkeypatch, gpus, expected_root_gpu, strategy): + monkeypatch.setattr(torch.cuda, "is_available", lambda: True) + monkeypatch.setattr(torch.cuda, "device_count", lambda: 16) + with pytest.deprecated_call( + match="`Trainer.root_gpu` is deprecated in v1.6 and will be removed in v1.8. " + "Please use `Trainer.strategy.root_device.index` instead." + ): + assert Trainer(gpus=gpus, strategy=strategy).root_gpu == expected_root_gpu + + +@pytest.mark.parametrize( + ["gpus", "expected_root_gpu", "strategy"], + [ + pytest.param(None, None, None, id="None is None"), + pytest.param(None, None, "ddp", id="None is None"), + pytest.param(0, None, "ddp", id="None is None"), + ], +) +def test_root_gpu_property_0_passing(monkeypatch, gpus, expected_root_gpu, strategy): + monkeypatch.setattr(torch.cuda, "device_count", lambda: 0) + with pytest.deprecated_call( + match="`Trainer.root_gpu` is deprecated in v1.6 and will be removed in v1.8. " + "Please use `Trainer.strategy.root_device.index` instead." + ): + assert Trainer(gpus=gpus, strategy=strategy).root_gpu == expected_root_gpu diff --git a/tests/models/data/horovod/train_default_model.py b/tests/models/data/horovod/train_default_model.py index 4527f337af..6679e0edac 100644 --- a/tests/models/data/horovod/train_default_model.py +++ b/tests/models/data/horovod/train_default_model.py @@ -101,8 +101,8 @@ def run_test_from_config(trainer_options, on_gpu, check_size=True): if on_gpu: trainer = Trainer(gpus=1, strategy="horovod", max_epochs=1) - # Test the root_gpu property - assert trainer.root_gpu == hvd.local_rank() + # test root gpu index + assert trainer.strategy.root_device.index == hvd.local_rank() if __name__ == "__main__": diff --git a/tests/models/test_gpu.py b/tests/models/test_gpu.py index d17322e191..6dab3fb60d 100644 --- a/tests/models/test_gpu.py +++ b/tests/models/test_gpu.py @@ -118,33 +118,6 @@ def test_trainer_num_gpu_0(mocked_device_count_0, gpus, expected_num_gpus, strat assert Trainer(gpus=gpus, strategy=strategy).num_gpus == expected_num_gpus -@pytest.mark.parametrize( - ["gpus", "expected_root_gpu", "strategy"], - [ - pytest.param(None, None, "ddp", id="None is None"), - pytest.param(0, None, "ddp", id="O gpus, expect gpu root device to be None."), - pytest.param(1, 0, "ddp", id="1 gpu, expect gpu root device to be 0."), - pytest.param(-1, 0, "ddp", id="-1 - use all gpus, expect gpu root device to be 0."), - pytest.param("-1", 0, "ddp", id="'-1' - use all gpus, expect gpu root device to be 0."), - pytest.param(3, 0, "ddp", id="3 gpus, expect gpu root device to be 0.(backend:ddp)"), - ], -) -def test_root_gpu_property(mocked_device_count, gpus, expected_root_gpu, strategy): - assert Trainer(gpus=gpus, strategy=strategy).root_gpu == expected_root_gpu - - -@pytest.mark.parametrize( - ["gpus", "expected_root_gpu", "strategy"], - [ - pytest.param(None, None, None, id="None is None"), - pytest.param(None, None, "ddp", id="None is None"), - pytest.param(0, None, "ddp", id="None is None"), - ], -) -def test_root_gpu_property_0_passing(mocked_device_count_0, gpus, expected_root_gpu, strategy): - assert Trainer(gpus=gpus, strategy=strategy).root_gpu == expected_root_gpu - - # Asking for a gpu when non are available will result in a MisconfigurationException @pytest.mark.parametrize( ["gpus", "expected_root_gpu", "strategy"],