From 85df5aae5617726409ce4627f69e118f7ac9ac2d Mon Sep 17 00:00:00 2001 From: Nicki Skafte Date: Tue, 28 Jan 2020 10:07:07 +0100 Subject: [PATCH 01/20] new way of passing dataloaders --- pytorch_lightning/trainer/trainer.py | 54 +++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/pytorch_lightning/trainer/trainer.py b/pytorch_lightning/trainer/trainer.py index e1c1464c73cf8..b4be5662c6ba5 100644 --- a/pytorch_lightning/trainer/trainer.py +++ b/pytorch_lightning/trainer/trainer.py @@ -713,17 +713,61 @@ def tng_tqdm_dic(self): # ----------------------------- # MODEL TRAINING # ----------------------------- - def fit(self, model): + def fit(self, model, train_dataloader=None, val_dataloader=None, test_dataloader=None): r""" Runs the full optimization routine. - Example:: + Args: + model (:class:`.LightningModule'): Model to fit. + Example:: - trainer = Trainer() - model = LightningModule() + trainer = Trainer() + model = LightningModule() + trainer.fit(model) + + train_dataloader: A Pytorch DataLoader with training samples. If the model has + a predefined train_dataloader method this will be skipped. + + val_dataloader: A Pytorch DataLoader with validation samples. If the model has + a predefined val_dataloader method this will be skipped + + test_dataloader: A Pytorch DataLoader with test samples. If the model has a + a predefined test_dataloader method this will be skipped - trainer.fit() """ + if train_dataloader: + if isinstance(train_dataloader, torch.utils.data.DataLoader): + if model.train_dataloader() is None: + model.train_dataloader = lambda: train_dataloader + else: + logging.info('Model has predefined train_dataloader, ' \ + 'will skip the train_dataloader passed to fit method') + else: + raise ValueError('train_dataloader needs to be an instance' \ + 'of torch.utils.data.DataLoader') + + if val_dataloader: + if isinstance(val_dataloader, torch.utils.data.DataLoader): + if model.val_dataloader() is None: + model.val_dataloader = lambda: val_dataloader + else: + logging.info('Model has predefined val_dataloader, ' \ + 'will skip the val_dataloader passed to fit method ') + else: + raise ValueError('val_dataloader needs to be an instance ' \ + 'of torch.utils.data.DataLoader') + + if test_dataloader: + if isinstance(test_dataloader, torch.utils.data.DataLoader): + if model.test_dataloader() is None: + model.test_dataloader = lambda: test_dataloader + else: + logging.info('Model has predefined test_dataloader,' \ + 'will skip the test_dataloader passed to fit method ') + else: + raise ValueError('test_dataloader needs to be an instance' \ + 'of torch.utils.data.DataLoader') + # when using multi-node or DDP within a node start each module in a separate process if self.use_ddp2: task = int(os.environ['SLURM_LOCALID']) From e03ff633622b4cf759a2dde6835ee812ef62e59a Mon Sep 17 00:00:00 2001 From: Nicki Skafte Date: Tue, 28 Jan 2020 10:42:36 +0100 Subject: [PATCH 02/20] fixed docs --- pytorch_lightning/trainer/trainer.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pytorch_lightning/trainer/trainer.py b/pytorch_lightning/trainer/trainer.py index b4be5662c6ba5..53a2716661347 100644 --- a/pytorch_lightning/trainer/trainer.py +++ b/pytorch_lightning/trainer/trainer.py @@ -718,20 +718,23 @@ def fit(self, model, train_dataloader=None, val_dataloader=None, test_dataloader Runs the full optimization routine. Args: - model (:class:`.LightningModule'): Model to fit. + model (LightningModule): Model to fit. Example:: trainer = Trainer() model = LightningModule() trainer.fit(model) - train_dataloader: A Pytorch DataLoader with training samples. If the model has + train_dataloader (:class:`.torch.utils.data.DataLoader`): A Pytorch + DataLoader with training samples. If the model has a predefined train_dataloader method this will be skipped. - val_dataloader: A Pytorch DataLoader with validation samples. If the model has + val_dataloader (:class:`.torch.utils.data.DataLoader`): A Pytorch + DataLoader with validation samples. If the model has a predefined val_dataloader method this will be skipped - test_dataloader: A Pytorch DataLoader with test samples. If the model has a + test_dataloader (:class:`.torch.utils.data.DataLoader`): A Pytorch + DataLoader with test samples. If the model has a a predefined test_dataloader method this will be skipped """ From e8e5779057b30dfa29bd0bbe8e27fa2710a733ef Mon Sep 17 00:00:00 2001 From: Nicki Skafte Date: Tue, 28 Jan 2020 11:12:22 +0100 Subject: [PATCH 03/20] fixed codestyle to follow flake8 --- pytorch_lightning/trainer/trainer.py | 48 ++++++++++++++-------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/pytorch_lightning/trainer/trainer.py b/pytorch_lightning/trainer/trainer.py index 53a2716661347..f5b1f954f8a2f 100644 --- a/pytorch_lightning/trainer/trainer.py +++ b/pytorch_lightning/trainer/trainer.py @@ -719,22 +719,22 @@ def fit(self, model, train_dataloader=None, val_dataloader=None, test_dataloader Args: model (LightningModule): Model to fit. - Example:: + Example:: - trainer = Trainer() - model = LightningModule() - trainer.fit(model) + trainer = Trainer() + model = LightningModule() + trainer.fit(model) - train_dataloader (:class:`.torch.utils.data.DataLoader`): A Pytorch - DataLoader with training samples. If the model has + train_dataloader (:class:`.torch.utils.data.DataLoader`): A Pytorch + DataLoader with training samples. If the model has a predefined train_dataloader method this will be skipped. - val_dataloader (:class:`.torch.utils.data.DataLoader`): A Pytorch - DataLoader with validation samples. If the model has - a predefined val_dataloader method this will be skipped + val_dataloader (:class:`.torch.utils.data.DataLoader`): A Pytorch + DataLoader with validation samples. If the model has + a predefined val_dataloader method this will be skipped - test_dataloader (:class:`.torch.utils.data.DataLoader`): A Pytorch - DataLoader with test samples. If the model has a + test_dataloader (:class:`.torch.utils.data.DataLoader`): A Pytorch + DataLoader with test samples. If the model has a a predefined test_dataloader method this will be skipped """ @@ -743,10 +743,10 @@ def fit(self, model, train_dataloader=None, val_dataloader=None, test_dataloader if model.train_dataloader() is None: model.train_dataloader = lambda: train_dataloader else: - logging.info('Model has predefined train_dataloader, ' \ - 'will skip the train_dataloader passed to fit method') + logging.info('Model has predefined train_dataloader, ' + 'will skip the train_dataloader passed to fit method') else: - raise ValueError('train_dataloader needs to be an instance' \ + raise ValueError('train_dataloader needs to be an instance' 'of torch.utils.data.DataLoader') if val_dataloader: @@ -754,21 +754,21 @@ def fit(self, model, train_dataloader=None, val_dataloader=None, test_dataloader if model.val_dataloader() is None: model.val_dataloader = lambda: val_dataloader else: - logging.info('Model has predefined val_dataloader, ' \ + logging.info('Model has predefined val_dataloader, ' 'will skip the val_dataloader passed to fit method ') else: - raise ValueError('val_dataloader needs to be an instance ' \ + raise ValueError('val_dataloader needs to be an instance ' 'of torch.utils.data.DataLoader') if test_dataloader: - if isinstance(test_dataloader, torch.utils.data.DataLoader): - if model.test_dataloader() is None: - model.test_dataloader = lambda: test_dataloader - else: - logging.info('Model has predefined test_dataloader,' \ - 'will skip the test_dataloader passed to fit method ') - else: - raise ValueError('test_dataloader needs to be an instance' \ + if isinstance(test_dataloader, torch.utils.data.DataLoader): + if model.test_dataloader() is None: + model.test_dataloader = lambda: test_dataloader + else: + logging.info('Model has predefined test_dataloader,' + 'will skip the test_dataloader passed to fit method ') + else: + raise ValueError('test_dataloader needs to be an instance' 'of torch.utils.data.DataLoader') # when using multi-node or DDP within a node start each module in a separate process From 5fd48af6491940f0341aa0c5ed898010f8fe6423 Mon Sep 17 00:00:00 2001 From: Nicki Skafte Date: Thu, 30 Jan 2020 16:29:51 +0100 Subject: [PATCH 04/20] allow val/test be list of dataloaders and smarter checking --- pytorch_lightning/core/decorators.py | 3 +- pytorch_lightning/trainer/trainer.py | 79 +++++++++++++++------------- 2 files changed, 43 insertions(+), 39 deletions(-) diff --git a/pytorch_lightning/core/decorators.py b/pytorch_lightning/core/decorators.py index aeea1a7e44256..0b0ee53c0d907 100644 --- a/pytorch_lightning/core/decorators.py +++ b/pytorch_lightning/core/decorators.py @@ -9,9 +9,8 @@ def data_loader(fn): :return: """ - wraps(fn) attr_name = '_lazy_' + fn.__name__ - + @wraps(fn) def _get_data_loader(self): try: value = getattr(self, attr_name) diff --git a/pytorch_lightning/trainer/trainer.py b/pytorch_lightning/trainer/trainer.py index f5b1f954f8a2f..222a36a5258d1 100644 --- a/pytorch_lightning/trainer/trainer.py +++ b/pytorch_lightning/trainer/trainer.py @@ -19,7 +19,7 @@ parse_gpu_ids, determine_root_gpu_device ) - +from pytorch_lightning.core.lightning import LightningModule from pytorch_lightning.trainer.evaluation_loop import TrainerEvaluationLoopMixin from pytorch_lightning.trainer.logging import TrainerLoggingMixin from pytorch_lightning.trainer.model_hooks import TrainerModelHooksMixin @@ -729,47 +729,21 @@ def fit(self, model, train_dataloader=None, val_dataloader=None, test_dataloader DataLoader with training samples. If the model has a predefined train_dataloader method this will be skipped. - val_dataloader (:class:`.torch.utils.data.DataLoader`): A Pytorch - DataLoader with validation samples. If the model has + val_dataloader (:class:`.torch.utils.data.DataLoader`): Either a single + Pytorch Dataloader or a list of them, specifying validation samples. If the model has a predefined val_dataloader method this will be skipped - test_dataloader (:class:`.torch.utils.data.DataLoader`): A Pytorch - DataLoader with test samples. If the model has a - a predefined test_dataloader method this will be skipped + test_dataloader (:class:`.torch.utils.data.DataLoader`): Either a single + Pytorch Dataloader or a list of them, specifying validation samples. If the model has + a predefined val_dataloader method this will be skipped """ - if train_dataloader: - if isinstance(train_dataloader, torch.utils.data.DataLoader): - if model.train_dataloader() is None: - model.train_dataloader = lambda: train_dataloader - else: - logging.info('Model has predefined train_dataloader, ' - 'will skip the train_dataloader passed to fit method') - else: - raise ValueError('train_dataloader needs to be an instance' - 'of torch.utils.data.DataLoader') - if val_dataloader: - if isinstance(val_dataloader, torch.utils.data.DataLoader): - if model.val_dataloader() is None: - model.val_dataloader = lambda: val_dataloader - else: - logging.info('Model has predefined val_dataloader, ' - 'will skip the val_dataloader passed to fit method ') - else: - raise ValueError('val_dataloader needs to be an instance ' - 'of torch.utils.data.DataLoader') - - if test_dataloader: - if isinstance(test_dataloader, torch.utils.data.DataLoader): - if model.test_dataloader() is None: - model.test_dataloader = lambda: test_dataloader - else: - logging.info('Model has predefined test_dataloader,' - 'will skip the test_dataloader passed to fit method ') - else: - raise ValueError('test_dataloader needs to be an instance' - 'of torch.utils.data.DataLoader') + # Update the dataloader attributes of the model with the ones supplied here, + # if they are not already defined in model + _set_dataloader(model, train_dataloader, 'train_dataloader') + _set_dataloader(model, val_dataloader, 'val_dataloader') + _set_dataloader(model, test_dataloader, 'test_dataloader') # when using multi-node or DDP within a node start each module in a separate process if self.use_ddp2: @@ -958,3 +932,34 @@ def test(self, model=None): self.fit(model) else: self.run_evaluation(test=True) + + +def _set_dataloader(model, dataloader, attribute): + r''' Check dataloaders passed to .fit() method if they are pytorch DataLoader + objects and whether or not we should overright the corresponding dataloader + in the model ''' + + # Check if attribute comes directly from base class or + # derived in user subclass + if LightningModule.__qualname__ in getattr(model, attribute).__qualname__: + # Val and test should be list of dataloaders + dataloader = dataloader if attribute == 'train_dataloader' or \ + (attribute != 'train_dataloader' and isinstance(dataloader, list)) else [dataloader] + + # Check if input is correct + if isinstance(dataloader, torch.utils.data.DataLoader) or \ + isinstance(dataloader, list) and all(isinstance(d, torch.utils.data.DataLoader) for d in dataloader): + + # Overwrite abstract methods + dl = lambda: dataloader + dl.__name__ = attribute + setattr(model, attribute, dl) + + elif dataloader: + raise ValueError(f'`{attribute}` needs to be an instance of' + '`torch.utils.data.DataLoader` or a list of, instead got' + f'`{dataloader}`') + + else: + logging.info(f'Model has predefined `{attribute}`,' + f'will skip `{attribute}` passed to fit method') From 1ca000331fb81e91ab8813d27b8215b1ee8bf0a3 Mon Sep 17 00:00:00 2001 From: Nicki Skafte Date: Thu, 13 Feb 2020 15:08:29 +0100 Subject: [PATCH 05/20] added test --- pytorch_lightning/core/lightning.py | 3 +- pytorch_lightning/testing/__init__.py | 3 +- pytorch_lightning/testing/model_base.py | 20 +++-- pytorch_lightning/trainer/trainer.py | 31 ++++++-- tests/test_trainer.py | 101 +++++++++++++++++++++++- 5 files changed, 140 insertions(+), 18 deletions(-) diff --git a/pytorch_lightning/core/lightning.py b/pytorch_lightning/core/lightning.py index 23757110c4aa8..1833b3202596f 100644 --- a/pytorch_lightning/core/lightning.py +++ b/pytorch_lightning/core/lightning.py @@ -858,7 +858,6 @@ def tbptt_split_batch(self, batch, split_size): return splits @data_loader - @abstractmethod def train_dataloader(self): """Implement a PyTorch DataLoader @@ -884,8 +883,8 @@ def train_dataloader(self): ) return loader - """ + return None @data_loader def tng_dataloader(self): diff --git a/pytorch_lightning/testing/__init__.py b/pytorch_lightning/testing/__init__.py index 326f67caf118a..561ea9da04bb2 100644 --- a/pytorch_lightning/testing/__init__.py +++ b/pytorch_lightning/testing/__init__.py @@ -1,5 +1,6 @@ from .model import LightningTestModel -from .model_base import LightningTestModelBase +from .model_base import (LightningTestModelBase, + LightningTestModelBaseWithoutDataloader) from .model_mixins import ( LightningValidationStepMixin, LightningValidationMixin, diff --git a/pytorch_lightning/testing/model_base.py b/pytorch_lightning/testing/model_base.py index 9baaf17640336..562e4c6d5a2fb 100644 --- a/pytorch_lightning/testing/model_base.py +++ b/pytorch_lightning/testing/model_base.py @@ -36,7 +36,7 @@ def __init__(self, root, train=True, transform=None, target_transform=None, self.targets = self.targets[:num_samples] -class LightningTestModelBase(LightningModule): +class _LightningTestModelBase(LightningModule): """ Base LightningModule for testing. Implements only the required interface @@ -48,7 +48,7 @@ def __init__(self, hparams, force_remove_distributed_sampler=False): :param hparams: """ # init superclass - super(LightningTestModelBase, self).__init__() + super(_LightningTestModelBase, self).__init__() self.hparams = hparams self.batch_size = hparams.batch_size @@ -178,10 +178,6 @@ def _dataloader(self, train): return loader - @data_loader - def train_dataloader(self): - return self._dataloader(train=True) - @staticmethod def add_model_specific_args(parent_parser, root_dir): # pragma: no cover """ @@ -218,3 +214,15 @@ def add_model_specific_args(parent_parser, root_dir): # pragma: no cover options=[32, 64, 128, 256], tunable=False, help='batch size will be divided over all gpus being used across all nodes') return parser + + +class LightningTestModelBase(_LightningTestModelBase): + """ with pre-defined train dataloader """ + @data_loader + def train_dataloader(self): + return self._dataloader(train=True) + + +class LightningTestModelBaseWithoutDataloader(_LightningTestModelBase): + """ without pre-defined train dataloader """ + pass diff --git a/pytorch_lightning/trainer/trainer.py b/pytorch_lightning/trainer/trainer.py index 222a36a5258d1..5e83ac632d781 100644 --- a/pytorch_lightning/trainer/trainer.py +++ b/pytorch_lightning/trainer/trainer.py @@ -719,11 +719,6 @@ def fit(self, model, train_dataloader=None, val_dataloader=None, test_dataloader Args: model (LightningModule): Model to fit. - Example:: - - trainer = Trainer() - model = LightningModule() - trainer.fit(model) train_dataloader (:class:`.torch.utils.data.DataLoader`): A Pytorch DataLoader with training samples. If the model has @@ -737,6 +732,26 @@ def fit(self, model, train_dataloader=None, val_dataloader=None, test_dataloader Pytorch Dataloader or a list of them, specifying validation samples. If the model has a predefined val_dataloader method this will be skipped + Example:: + + # Option 1, + # Basic usecase, dataloaders defined as part of the model + trainer = Trainer() + model = LightningModule() + trainer.fit(model) + + # Option 2 + # Dataloaders passed to fit method + train, val, test = DataLoader(...), DataLoader(...), DataLoader(...) + trainer = Trainer() + model = LightningModule() + trainer.fit(model, train_dataloader=train, + val_dataloader=val, test_dataloader=test) + + # Option 1 & 2 can be mixed, for example the training set can be + # defined as part of the model, and validation/test can then be + # feed to .fit() + """ # Update the dataloader attributes of the model with the ones supplied here, @@ -938,7 +953,7 @@ def _set_dataloader(model, dataloader, attribute): r''' Check dataloaders passed to .fit() method if they are pytorch DataLoader objects and whether or not we should overright the corresponding dataloader in the model ''' - + # Check if attribute comes directly from base class or # derived in user subclass if LightningModule.__qualname__ in getattr(model, attribute).__qualname__: @@ -948,14 +963,14 @@ def _set_dataloader(model, dataloader, attribute): # Check if input is correct if isinstance(dataloader, torch.utils.data.DataLoader) or \ - isinstance(dataloader, list) and all(isinstance(d, torch.utils.data.DataLoader) for d in dataloader): + (isinstance(dataloader, list) and all(isinstance(d, torch.utils.data.DataLoader) for d in dataloader)): # Overwrite abstract methods dl = lambda: dataloader dl.__name__ = attribute setattr(model, attribute, dl) - elif dataloader: + elif not dataloader and dataloader != [None]: raise ValueError(f'`{attribute}` needs to be an instance of' '`torch.utils.data.DataLoader` or a list of, instead got' f'`{dataloader}`') diff --git a/tests/test_trainer.py b/tests/test_trainer.py index ddc74b40f8ca4..6fb50b5bed6d0 100644 --- a/tests/test_trainer.py +++ b/tests/test_trainer.py @@ -11,6 +11,7 @@ from pytorch_lightning.testing import ( LightningTestModel, LightningTestModelBase, + LightningTestModelBaseWithoutDataloader, LightningValidationStepMixin, LightningValidationMultipleDataloadersMixin, LightningTestMultipleDataloadersMixin, @@ -367,7 +368,7 @@ class CurrentTestModel( # verify there are 2 val loaders assert len(trainer.get_val_dataloaders()) == 2, \ - 'Multiple val_dataloaders not initiated properly' + 'Multiple val_dataloade not initiated properly' # make sure predictions are good for each val set for dataloader in trainer.get_val_dataloaders(): @@ -411,5 +412,103 @@ class CurrentTestModel( trainer.test() +def test_dataloaders_passed_to_fit(tmpdir): + """Verify that dataloaders can be passed to fit""" + tutils.reset_seed() + + class CurrentTestModel( + LightningTestModelBaseWithoutDataloader + ): + pass + + hparams = tutils.get_hparams() + + # logger file to get meta + trainer_options = dict( + default_save_path=tmpdir, + max_epochs=1, + val_percent_check=0.1, + train_percent_check=0.2 + ) + + # fit model + # only train passed to fit + model = CurrentTestModel(hparams) + trainer = Trainer(**trainer_options) + fit_options = dict(train_dataloader=model._dataloader(train=True)) + results = trainer.fit(model, **fit_options) + + # train, val passed to fit + model = CurrentTestModel(hparams) + trainer = Trainer(**trainer_options) + fit_options = dict(train_dataloader=model._dataloader(train=True), + val_dataloader=model._dataloader(train=False)) + results = trainer.fit(model, **fit_options) + assert len(trainer.get_val_dataloaders()) == 1, \ + 'val_dataloaders not initiated properly' + + # train, val and test passed to fit + model = CurrentTestModel(hparams) + trainer = Trainer(**trainer_options) + fit_options = dict(train_dataloader=model._dataloader(train=True), + val_dataloader=model._dataloader(train=False), + test_dataloader=model._dataloader(train=False)) + results = trainer.fit(model, **fit_options) + assert len(trainer.get_val_dataloaders()) == 1, \ + 'val_dataloaders not initiated properly' + assert len(trainer.get_test_dataloaders()) == 1, \ + 'test_dataloaders not initiated properly' + + # train, multiple val and multiple test passed to fit + model = CurrentTestModel(hparams) + trainer = Trainer(**trainer_options) + fit_options = dict(train_dataloader=model._dataloader(train=True), + val_dataloader=[model._dataloader(train=False), + model._dataloader(train=False)], + test_dataloader=[model._dataloader(train=False), + model._dataloader(train=False)]) + results = trainer.fit(model, **fit_options) + + assert len(trainer.get_val_dataloaders()) == 2, \ + 'Multiple val_dataloaders not initiated properly' + assert len(trainer.get_test_dataloaders()) == 2, \ + 'Multiple test_dataloaders not initiated properly' + + +def test_mixing_of_dataloader_options(tmpdir): + """Verify that dataloaders can be passed to fit""" + tutils.reset_seed() + + class CurrentTestModel( + LightningTestModelBase + ): + pass + + hparams = tutils.get_hparams() + model = CurrentTestModel(hparams) + + # logger file to get meta + trainer_options = dict( + default_save_path=tmpdir, + max_epochs=1, + val_percent_check=0.1, + train_percent_check=0.2 + ) + + # fit model + trainer = Trainer(**trainer_options) + fit_options = dict(val_dataloader=model._dataloader(train=False)) + results = trainer.fit(model, **fit_options) + + # fit model + trainer = Trainer(**trainer_options) + fit_options = dict(val_dataloader=model._dataloader(train=False), + test_dataloader=model._dataloader(train=False)) + results = trainer.fit(model, **fit_options) + assert len(trainer.get_val_dataloaders()) == 1, \ + 'val_dataloaders not initiated properly' + assert len(trainer.get_test_dataloaders()) == 1, \ + 'test_dataloaders not initiated properly' + # if __name__ == '__main__': # pytest.main([__file__]) From d113c3d4ff8aea30f419ee433ec3957a008a9043 Mon Sep 17 00:00:00 2001 From: Nicki Skafte Date: Thu, 13 Feb 2020 15:30:55 +0100 Subject: [PATCH 06/20] fix flake error --- pytorch_lightning/trainer/trainer.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pytorch_lightning/trainer/trainer.py b/pytorch_lightning/trainer/trainer.py index bdb6bbdced900..1846bf327a1d8 100644 --- a/pytorch_lightning/trainer/trainer.py +++ b/pytorch_lightning/trainer/trainer.py @@ -977,7 +977,7 @@ def _set_dataloader(model, dataloader, attribute): r''' Check dataloaders passed to .fit() method if they are pytorch DataLoader objects and whether or not we should overright the corresponding dataloader in the model ''' - + # Check if attribute comes directly from base class or # derived in user subclass if LightningModule.__qualname__ in getattr(model, attribute).__qualname__: @@ -1000,5 +1000,5 @@ def _set_dataloader(model, dataloader, attribute): f'`{dataloader}`') else: - logging.info(f'Model has predefined `{attribute}`,' - f'will skip `{attribute}` passed to fit method') + warnings.warn(f'Model has predefined `{attribute}`,' + f'will skip `{attribute}` passed to fit method') From 1f8f0b9941663c6cf8de2f153c1927be018fdd0c Mon Sep 17 00:00:00 2001 From: Nicki Skafte Date: Thu, 13 Feb 2020 15:41:05 +0100 Subject: [PATCH 07/20] fix linking to new test model --- tests/models/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/models/__init__.py b/tests/models/__init__.py index 5da8521e0f618..c4831e51223a1 100644 --- a/tests/models/__init__.py +++ b/tests/models/__init__.py @@ -2,7 +2,8 @@ import torch -from .base import LightningTestModelBase +from .base import (LightningTestModelBase, + LightningTestModelBaseWithoutDataloader) from .mixins import ( LightningValidationStepMixin, LightningValidationMixin, From 270eca4f3bdbd2e9a42d18bc33fda5743100f89f Mon Sep 17 00:00:00 2001 From: Nicki Skafte Date: Fri, 14 Feb 2020 16:38:10 +0100 Subject: [PATCH 08/20] split into multiple test --- tests/test_trainer.py | 65 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 3 deletions(-) diff --git a/tests/test_trainer.py b/tests/test_trainer.py index 4c6dd47ef191a..5062d8c608e26 100644 --- a/tests/test_trainer.py +++ b/tests/test_trainer.py @@ -412,8 +412,8 @@ class CurrentTestModel( trainer.test() -def test_dataloaders_passed_to_fit(tmpdir): - """Verify that dataloaders can be passed to fit""" +def test_train_dataloaders_passed_to_fit(tmpdir): + """ Verify that train dataloader can be passed to fit """ tutils.reset_seed() class CurrentTestModel( @@ -431,13 +431,32 @@ class CurrentTestModel( train_percent_check=0.2 ) - # fit model # only train passed to fit model = CurrentTestModel(hparams) trainer = Trainer(**trainer_options) fit_options = dict(train_dataloader=model._dataloader(train=True)) results = trainer.fit(model, **fit_options) + +def test_train_val_dataloaders_passed_to_fit(tmpdir): + """ Verify that train & val dataloader can be passed to fit """ + tutils.reset_seed() + + class CurrentTestModel( + LightningTestModelBaseWithoutDataloader + ): + pass + + hparams = tutils.get_hparams() + + # logger file to get meta + trainer_options = dict( + default_save_path=tmpdir, + max_epochs=1, + val_percent_check=0.1, + train_percent_check=0.2 + ) + # train, val passed to fit model = CurrentTestModel(hparams) trainer = Trainer(**trainer_options) @@ -447,6 +466,26 @@ class CurrentTestModel( assert len(trainer.get_val_dataloaders()) == 1, \ 'val_dataloaders not initiated properly' + +def test_all_dataloaders_passed_to_fit(tmpdir): + """ Verify train, val & test dataloader can be passed to fit """ + tutils.reset_seed() + + class CurrentTestModel( + LightningTestModelBaseWithoutDataloader + ): + pass + + hparams = tutils.get_hparams() + + # logger file to get meta + trainer_options = dict( + default_save_path=tmpdir, + max_epochs=1, + val_percent_check=0.1, + train_percent_check=0.2 + ) + # train, val and test passed to fit model = CurrentTestModel(hparams) trainer = Trainer(**trainer_options) @@ -459,6 +498,26 @@ class CurrentTestModel( assert len(trainer.get_test_dataloaders()) == 1, \ 'test_dataloaders not initiated properly' + +def test_multiple_dataloaders_passed_to_fit(tmpdir): + """ Verify that multiple val & test dataloaders can be passed to fit """ + tutils.reset_seed() + + class CurrentTestModel( + LightningTestModelBaseWithoutDataloader + ): + pass + + hparams = tutils.get_hparams() + + # logger file to get meta + trainer_options = dict( + default_save_path=tmpdir, + max_epochs=1, + val_percent_check=0.1, + train_percent_check=0.2 + ) + # train, multiple val and multiple test passed to fit model = CurrentTestModel(hparams) trainer = Trainer(**trainer_options) From 0f2c503f785bcb87ad4aaae519f3ff9b79d8bbd2 Mon Sep 17 00:00:00 2001 From: Nicki Skafte Date: Fri, 14 Feb 2020 16:43:22 +0100 Subject: [PATCH 09/20] fix naming and typo --- tests/models/base.py | 8 ++++---- tests/test_trainer.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/models/base.py b/tests/models/base.py index 11362444b9d1b..d33f0118dfd05 100644 --- a/tests/models/base.py +++ b/tests/models/base.py @@ -36,7 +36,7 @@ def __init__(self, root, train=True, transform=None, target_transform=None, self.targets = self.targets[:num_samples] -class _LightningTestModelBase(LightningModule): +class TestModelBase(LightningModule): """ Base LightningModule for testing. Implements only the required interface @@ -48,7 +48,7 @@ def __init__(self, hparams, force_remove_distributed_sampler=False): :param hparams: """ # init superclass - super(_LightningTestModelBase, self).__init__() + super(TestModelBase, self).__init__() self.hparams = hparams self.batch_size = hparams.batch_size @@ -216,13 +216,13 @@ def add_model_specific_args(parent_parser, root_dir): # pragma: no cover return parser -class LightningTestModelBase(_LightningTestModelBase): +class LightningTestModelBase(TestModelBase): """ with pre-defined train dataloader """ @data_loader def train_dataloader(self): return self._dataloader(train=True) -class LightningTestModelBaseWithoutDataloader(_LightningTestModelBase): +class LightningTestModelBaseWithoutDataloader(TestModelBase): """ without pre-defined train dataloader """ pass diff --git a/tests/test_trainer.py b/tests/test_trainer.py index 5062d8c608e26..c9e784227afe9 100644 --- a/tests/test_trainer.py +++ b/tests/test_trainer.py @@ -368,7 +368,7 @@ class CurrentTestModel( # verify there are 2 val loaders assert len(trainer.get_val_dataloaders()) == 2, \ - 'Multiple val_dataloade not initiated properly' + 'Multiple val_dataloaders not initiated properly' # make sure predictions are good for each val set for dataloader in trainer.get_val_dataloaders(): From 5dc9730d529f5ed7da521b9e242b4138880f8e17 Mon Sep 17 00:00:00 2001 From: Nicki Skafte Date: Fri, 14 Feb 2020 17:22:47 +0100 Subject: [PATCH 10/20] minor documentation changes --- pytorch_lightning/trainer/trainer.flac | 0 pytorch_lightning/trainer/trainer.py | 22 +++++++++++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) create mode 100644 pytorch_lightning/trainer/trainer.flac diff --git a/pytorch_lightning/trainer/trainer.flac b/pytorch_lightning/trainer/trainer.flac new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/pytorch_lightning/trainer/trainer.py b/pytorch_lightning/trainer/trainer.py index 1846bf327a1d8..44014d0d7b163 100644 --- a/pytorch_lightning/trainer/trainer.py +++ b/pytorch_lightning/trainer/trainer.py @@ -974,10 +974,22 @@ def test(self, model=None): def _set_dataloader(model, dataloader, attribute): - r''' Check dataloaders passed to .fit() method if they are pytorch DataLoader - objects and whether or not we should overright the corresponding dataloader - in the model ''' + r''' + Check dataloaders passed to .fit() method if they are pytorch DataLoader + objects and whether or not we should overright the corresponding dataloader + in the model + Args: + model (LightningModule): The model to check + + dataloader: If a pytorch dataloader (or a list of pytorch dataloaders) + is passed, it will be incorporate into the model as model.attribute. + If attribute alreay exist it will warn the userpass. If not a + dataloader will throw an error + + attribute (str): The attribute to save the dataloader under + + ''' # Check if attribute comes directly from base class or # derived in user subclass if LightningModule.__qualname__ in getattr(model, attribute).__qualname__: @@ -996,8 +1008,8 @@ def _set_dataloader(model, dataloader, attribute): elif not dataloader and dataloader != [None]: raise ValueError(f'`{attribute}` needs to be an instance of' - '`torch.utils.data.DataLoader` or a list of, instead got' - f'`{dataloader}`') + '`torch.utils.data.DataLoader` or a list of' + f'DataLoaders, instead got {dataloader}`') else: warnings.warn(f'Model has predefined `{attribute}`,' From f1bdd1268e0145e6d7f707fee69fea9e6d3b56ea Mon Sep 17 00:00:00 2001 From: Nicki Skafte Date: Fri, 14 Feb 2020 17:26:49 +0100 Subject: [PATCH 11/20] remove random file --- pytorch_lightning/trainer/trainer.flac | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 pytorch_lightning/trainer/trainer.flac diff --git a/pytorch_lightning/trainer/trainer.flac b/pytorch_lightning/trainer/trainer.flac deleted file mode 100644 index e69de29bb2d1d..0000000000000 From 7201221e10367bf647d127964d9f956a9f2a2e12 Mon Sep 17 00:00:00 2001 From: William Falcon Date: Sun, 16 Feb 2020 11:11:16 -0500 Subject: [PATCH 12/20] Update trainer.py --- pytorch_lightning/trainer/trainer.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pytorch_lightning/trainer/trainer.py b/pytorch_lightning/trainer/trainer.py index 44014d0d7b163..8db9e261ff5ee 100644 --- a/pytorch_lightning/trainer/trainer.py +++ b/pytorch_lightning/trainer/trainer.py @@ -756,13 +756,16 @@ def fit(self, model, train_dataloader=None, val_dataloader=None, test_dataloader Example:: # Option 1, - # Basic usecase, dataloaders defined as part of the model + # Define the train_dataloader(), test_dataloader() and val_dataloader() functions + # in the lightningModule + # RECOMMENDED FOR MOST RESEARCH AND APPLICATIONS TO MAINTAIN READABILITY trainer = Trainer() model = LightningModule() trainer.fit(model) # Option 2 - # Dataloaders passed to fit method + # in certain production cases we might want to pass different datasets to the same model + # Recommended for PRODUCTION SYSTEMS train, val, test = DataLoader(...), DataLoader(...), DataLoader(...) trainer = Trainer() model = LightningModule() From 47aa11528168095114742f07f1ce80d5f7c48405 Mon Sep 17 00:00:00 2001 From: William Falcon Date: Sun, 16 Feb 2020 11:13:29 -0500 Subject: [PATCH 13/20] Update trainer.py --- pytorch_lightning/trainer/trainer.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pytorch_lightning/trainer/trainer.py b/pytorch_lightning/trainer/trainer.py index 8db9e261ff5ee..153d2010bdcda 100644 --- a/pytorch_lightning/trainer/trainer.py +++ b/pytorch_lightning/trainer/trainer.py @@ -746,17 +746,17 @@ def fit(self, model, train_dataloader=None, val_dataloader=None, test_dataloader a predefined train_dataloader method this will be skipped. val_dataloader (:class:`.torch.utils.data.DataLoader`): Either a single - Pytorch Dataloader or a list of them, specifying validation samples. If the model has - a predefined val_dataloader method this will be skipped + Pytorch Dataloader or a list of them, specifying validation samples. + If the model has a predefined val_dataloader method this will be skipped test_dataloader (:class:`.torch.utils.data.DataLoader`): Either a single - Pytorch Dataloader or a list of them, specifying validation samples. If the model has - a predefined val_dataloader method this will be skipped + Pytorch Dataloader or a list of them, specifying validation samples. + If the model has a predefined val_dataloader method this will be skipped Example:: # Option 1, - # Define the train_dataloader(), test_dataloader() and val_dataloader() functions + # Define the train_dataloader(), test_dataloader() and val_dataloader() fxs # in the lightningModule # RECOMMENDED FOR MOST RESEARCH AND APPLICATIONS TO MAINTAIN READABILITY trainer = Trainer() @@ -764,7 +764,7 @@ def fit(self, model, train_dataloader=None, val_dataloader=None, test_dataloader trainer.fit(model) # Option 2 - # in certain production cases we might want to pass different datasets to the same model + # in production cases we might want to pass different datasets to the same model # Recommended for PRODUCTION SYSTEMS train, val, test = DataLoader(...), DataLoader(...), DataLoader(...) trainer = Trainer() From 40de10061522782a4e9a1a12cb3f1dfcdbe7bfd7 Mon Sep 17 00:00:00 2001 From: William Falcon Date: Sun, 16 Feb 2020 11:22:36 -0500 Subject: [PATCH 14/20] Update trainer.py --- pytorch_lightning/trainer/trainer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pytorch_lightning/trainer/trainer.py b/pytorch_lightning/trainer/trainer.py index 153d2010bdcda..93c5b0ba5003b 100644 --- a/pytorch_lightning/trainer/trainer.py +++ b/pytorch_lightning/trainer/trainer.py @@ -746,11 +746,11 @@ def fit(self, model, train_dataloader=None, val_dataloader=None, test_dataloader a predefined train_dataloader method this will be skipped. val_dataloader (:class:`.torch.utils.data.DataLoader`): Either a single - Pytorch Dataloader or a list of them, specifying validation samples. + Pytorch Dataloader or a list of them, specifying validation samples. If the model has a predefined val_dataloader method this will be skipped test_dataloader (:class:`.torch.utils.data.DataLoader`): Either a single - Pytorch Dataloader or a list of them, specifying validation samples. + Pytorch Dataloader or a list of them, specifying validation samples. If the model has a predefined val_dataloader method this will be skipped Example:: From 868865d897e6bb3a505d1418c978c9a247432f02 Mon Sep 17 00:00:00 2001 From: William Falcon Date: Sun, 16 Feb 2020 11:26:09 -0500 Subject: [PATCH 15/20] Update trainer.py --- pytorch_lightning/trainer/trainer.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pytorch_lightning/trainer/trainer.py b/pytorch_lightning/trainer/trainer.py index 93c5b0ba5003b..98f20a79bd73c 100644 --- a/pytorch_lightning/trainer/trainer.py +++ b/pytorch_lightning/trainer/trainer.py @@ -1000,9 +1000,12 @@ def _set_dataloader(model, dataloader, attribute): dataloader = dataloader if attribute == 'train_dataloader' or \ (attribute != 'train_dataloader' and isinstance(dataloader, list)) else [dataloader] - # Check if input is correct - if isinstance(dataloader, torch.utils.data.DataLoader) or \ - (isinstance(dataloader, list) and all(isinstance(d, torch.utils.data.DataLoader) for d in dataloader)): + # Check we are given valid dataloaders + is_dataloader = isinstance(dataloader, torch.utils.data.DataLoader) + is_dataloader_list = (isinstance(dataloader, list) + if is_dataloader_list: + valid_loaders = all(isinstance(d, torch.utils.data.DataLoader) for d in dataloader)) + if is_dataloader or is_dataloader_list and valid_loaders: # Overwrite abstract methods dl = lambda: dataloader From 600c1784b3c6232241ea7f3af7aeca0238776c5e Mon Sep 17 00:00:00 2001 From: William Falcon Date: Sun, 16 Feb 2020 11:27:14 -0500 Subject: [PATCH 16/20] Update trainer.py --- pytorch_lightning/trainer/trainer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pytorch_lightning/trainer/trainer.py b/pytorch_lightning/trainer/trainer.py index 98f20a79bd73c..f472160f35831 100644 --- a/pytorch_lightning/trainer/trainer.py +++ b/pytorch_lightning/trainer/trainer.py @@ -1002,9 +1002,9 @@ def _set_dataloader(model, dataloader, attribute): # Check we are given valid dataloaders is_dataloader = isinstance(dataloader, torch.utils.data.DataLoader) - is_dataloader_list = (isinstance(dataloader, list) + is_dataloader_list = isinstance(dataloader, list) if is_dataloader_list: - valid_loaders = all(isinstance(d, torch.utils.data.DataLoader) for d in dataloader)) + valid_loaders = all(isinstance(d, torch.utils.data.DataLoader) for d in dataloader) if is_dataloader or is_dataloader_list and valid_loaders: # Overwrite abstract methods From de7821bc53e77697b967518af850b6738b72cd9c Mon Sep 17 00:00:00 2001 From: William Falcon Date: Sun, 16 Feb 2020 11:27:49 -0500 Subject: [PATCH 17/20] Update trainer.py --- pytorch_lightning/trainer/trainer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytorch_lightning/trainer/trainer.py b/pytorch_lightning/trainer/trainer.py index f472160f35831..9334ac5822a95 100644 --- a/pytorch_lightning/trainer/trainer.py +++ b/pytorch_lightning/trainer/trainer.py @@ -1005,7 +1005,7 @@ def _set_dataloader(model, dataloader, attribute): is_dataloader_list = isinstance(dataloader, list) if is_dataloader_list: valid_loaders = all(isinstance(d, torch.utils.data.DataLoader) for d in dataloader) - if is_dataloader or is_dataloader_list and valid_loaders: + if is_dataloader or is_dataloader_list and valid_loaders: # Overwrite abstract methods dl = lambda: dataloader From ec404912dd29118684c252f34a69738843bd35f7 Mon Sep 17 00:00:00 2001 From: Nicki Skafte Date: Mon, 17 Feb 2020 13:35:56 +0100 Subject: [PATCH 18/20] better error/warning message --- pytorch_lightning/trainer/trainer.py | 12 ++++++------ tests/test_trainer.py | 15 ++++++++------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/pytorch_lightning/trainer/trainer.py b/pytorch_lightning/trainer/trainer.py index 9334ac5822a95..81f07a7276729 100644 --- a/pytorch_lightning/trainer/trainer.py +++ b/pytorch_lightning/trainer/trainer.py @@ -1012,11 +1012,11 @@ def _set_dataloader(model, dataloader, attribute): dl.__name__ = attribute setattr(model, attribute, dl) - elif not dataloader and dataloader != [None]: - raise ValueError(f'`{attribute}` needs to be an instance of' - '`torch.utils.data.DataLoader` or a list of' - f'DataLoaders, instead got {dataloader}`') + elif dataloader and dataloader != [None]: + raise ValueError(f'`{attribute}` needs to be an instance of ' + '`torch.utils.data.DataLoader` or a list of ' + 'DataLoaders, instead got %r`' % dataloader) - else: + elif dataloader: # if default (None) is passed, do not warn the user warnings.warn(f'Model has predefined `{attribute}`,' - f'will skip `{attribute}` passed to fit method') + f'will skip `{attribute}={dataloader}` passed to fit method') diff --git a/tests/test_trainer.py b/tests/test_trainer.py index c9e784227afe9..2cf7adf34c1da 100644 --- a/tests/test_trainer.py +++ b/tests/test_trainer.py @@ -464,7 +464,7 @@ class CurrentTestModel( val_dataloader=model._dataloader(train=False)) results = trainer.fit(model, **fit_options) assert len(trainer.get_val_dataloaders()) == 1, \ - 'val_dataloaders not initiated properly' + f'`val_dataloaders` not initiated properly, got {trainer.get_val_dataloaders()}' def test_all_dataloaders_passed_to_fit(tmpdir): @@ -493,10 +493,11 @@ class CurrentTestModel( val_dataloader=model._dataloader(train=False), test_dataloader=model._dataloader(train=False)) results = trainer.fit(model, **fit_options) + assert len(trainer.get_val_dataloaders()) == 1, \ - 'val_dataloaders not initiated properly' + f'`val_dataloaders` not initiated properly, got {trainer.get_val_dataloaders()}' assert len(trainer.get_test_dataloaders()) == 1, \ - 'test_dataloaders not initiated properly' + f'`test_dataloaders` not initiated properly, got {trainer.get_test_dataloaders()}' def test_multiple_dataloaders_passed_to_fit(tmpdir): @@ -529,9 +530,9 @@ class CurrentTestModel( results = trainer.fit(model, **fit_options) assert len(trainer.get_val_dataloaders()) == 2, \ - 'Multiple val_dataloaders not initiated properly' + f'Multiple `val_dataloaders` not initiated properly, got {trainer.get_val_dataloaders()}' assert len(trainer.get_test_dataloaders()) == 2, \ - 'Multiple test_dataloaders not initiated properly' + f'Multiple `test_dataloaders` not initiated properly, got {trainer.get_test_dataloaders()}' def test_mixing_of_dataloader_options(tmpdir): @@ -565,9 +566,9 @@ class CurrentTestModel( test_dataloader=model._dataloader(train=False)) results = trainer.fit(model, **fit_options) assert len(trainer.get_val_dataloaders()) == 1, \ - 'val_dataloaders not initiated properly' + f'`val_dataloaders` not initiated properly, got {trainer.get_val_dataloaders()}' assert len(trainer.get_test_dataloaders()) == 1, \ - 'test_dataloaders not initiated properly' + f'`test_dataloaders` not initiated properly, got {trainer.get_test_dataloaders()}' # if __name__ == '__main__': # pytest.main([__file__]) From 69517164f5dc249e224b389d9a9c7a23390a819d Mon Sep 17 00:00:00 2001 From: Nicki Skafte Date: Tue, 18 Feb 2020 08:11:28 +0100 Subject: [PATCH 19/20] final adjustments --- pytorch_lightning/trainer/trainer.py | 2 +- tests/models/__init__.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/pytorch_lightning/trainer/trainer.py b/pytorch_lightning/trainer/trainer.py index 81f07a7276729..489eda85dda3c 100644 --- a/pytorch_lightning/trainer/trainer.py +++ b/pytorch_lightning/trainer/trainer.py @@ -1019,4 +1019,4 @@ def _set_dataloader(model, dataloader, attribute): elif dataloader: # if default (None) is passed, do not warn the user warnings.warn(f'Model has predefined `{attribute}`,' - f'will skip `{attribute}={dataloader}` passed to fit method') + f' will skip `{attribute}={dataloader}` passed to fit method.') diff --git a/tests/models/__init__.py b/tests/models/__init__.py index c4831e51223a1..3e6424bd4982a 100644 --- a/tests/models/__init__.py +++ b/tests/models/__init__.py @@ -2,8 +2,7 @@ import torch -from .base import (LightningTestModelBase, - LightningTestModelBaseWithoutDataloader) +from .base import LightningTestModelBase, LightningTestModelBaseWithoutDataloader from .mixins import ( LightningValidationStepMixin, LightningValidationMixin, From 77e0d92f56a3dcaee4ae5d77049cf8b07e583bb3 Mon Sep 17 00:00:00 2001 From: Nicki Skafte Date: Tue, 18 Feb 2020 08:17:21 +0100 Subject: [PATCH 20/20] update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9069b116ffb3c..cfc5e2d89b4e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). - Added a tool for profiling training runs ([#782](https://github.com/PyTorchLightning/pytorch-lightning/pull/782)) - Improved flexibility for naming of TensorBoard logs, can now set `version` to a `str` to just save to that directory, and use `name=''` to prevent experiment-name directory ([#804](https://github.com/PyTorchLightning/pytorch-lightning/pull/804)) - Added option to specify `step` key when logging metrics ([#808](https://github.com/PyTorchLightning/pytorch-lightning/pull/808)) +- Added `train_dataloader`, `val_dataloader` and `test_dataloader` arguments to `Trainer.fit()`, for alternative data parsing ([#759]([https://github.com/PyTorchLightning/pytorch-lightning/pull/759])) ### Changed - Changed default TQDM to use `tqdm.auto` for prettier outputs in IPython notebooks ([#752](https://github.com/PyTorchLightning/pytorch-lightning/pull/752)) - Changed `pytorch_lightning.logging` to `pytorch_lightning.loggers` ([#767](https://github.com/PyTorchLightning/pytorch-lightning/pull/767))