Repository: Lightning-AI/pytorch-lightning

Issue:
logger is NoneType hence doesn't have any experiment or other functionality in a lightning module
## 🐛 Bug
When trying to use the logging abilities of lightning, I hit a wall, the default and tensorboard loggers both seem to stay uninitialized when calling ```trainer.fit(model)```, resulting in crashes everytime I try to log something.

### To Reproduce

Create a lightning module as such 
```
class SimpleRegressor(pl.LightningModule):
    ...
```

Use the logger anywhere to get this kind of stacktrace:


```
d:\Documents\projects\MetaWatch\MetaWatch\notebooks\audio-video-interest\simple_regressor.py in configure_optimizers(self)
    105         #see https://pytorch-lightning.readthedocs.io/en/latest/pytorch_lightning.core.lightning.html#pytorch_lightning.core.lightning.LightningModule.configure_optimizers
    106         # REQUIRED
--> 107         self.logger.experiment.add_hparams({'hidden_layer_size':self.hidden_layer_size,
    108                                             'linear_layer_size':self.linear_layer_size,
    109                                             'lstm_layers':self.lstm_layers})

AttributeError: 'NoneType' object has no attribute 'experiment'
```



#### Code sample
```
import pytorch_lightning as pl

class SimpleRegressor(pl.LightningModule):
    def __init__(self, cuda=False):
        super(SimpleRegressor, self).__init__()
        self.logger.experiment.add_hparams({'hidden_layer_size':1})
```

### Expected behavior

To log as described in the documentation.

### Environment
```
PyTorch version: 1.4.0
Is debug build: No
CUDA used to build PyTorch: 10.1

OS: Microsoft Windows 10 Pro    
GCC version: Could not collect  
CMake version: Could not collect

Python version: 3.7
Is CUDA available: Yes
CUDA runtime version: Could not collect
GPU models and configuration: GPU 0: GeForce GTX 970
Nvidia driver version: 441.12
cuDNN version: Could not collect

Versions of relevant libraries:
[pip3] numpy==1.18.1
[pip3] pytorch-lightning==0.6.0
[pip3] tinynumpy==1.2.1
[pip3] torch==1.4.0
[pip3] torchvision==0.4.1
[conda] Could not collect
```
### Additional context

<!-- Add any other context about the problem here. -->



Discussion:
Hey, thanks for your contribution! Great first issue!
Thanks for the issue! The intended way to acheive this is through a hook. When `__init__` is called on the `LightningModule`, the loggers won't have been created yet. I don't think there's any way to change that so we should update the docs to use a hook instead of `__init__`.

@PyTorchLightning/core-contributors any other thoughts on this?
it also doesn't work in other functions, I tried in the training step, in the configure_optimizers too

Resolving patch:
diff --git a/pytorch_lightning/loggers/__init__.py b/pytorch_lightning/loggers/__init__.py
--- a/pytorch_lightning/loggers/__init__.py
+++ b/pytorch_lightning/loggers/__init__.py
@@ -1,6 +1,7 @@
 """
 Lightning supports most popular logging frameworks (Tensorboard, comet, weights and biases, etc...).
-To use a logger, simply pass it into the trainer.
+To use a logger, simply pass it into the trainer. To use multiple loggers, simply pass in a ``list``
+or ``tuple`` of loggers.
 
 .. code-block:: python
 
@@ -14,14 +15,19 @@
     comet_logger = loggers.CometLogger()
     trainer = Trainer(logger=comet_logger)
 
-.. note:: All loggers log by default to `os.getcwd()`. To change the path without creating a logger set
-    Trainer(default_save_path='/your/path/to/save/checkpoints')
+    # or pass a list
+    tb_logger = loggers.TensorBoardLogger()
+    comet_logger = loggers.CometLogger()
+    trainer = Trainer(logger=[tb_logger, comet_logger])
+
+.. note:: All loggers log by default to ``os.getcwd()``. To change the path without creating a logger set
+    ``Trainer(default_save_path='/your/path/to/save/checkpoints')``
 
 Custom logger
 -------------
 
 You can implement your own logger by writing a class that inherits from
-`LightningLoggerBase`. Use the `rank_zero_only` decorator to make sure that
+``LightningLoggerBase``. Use the ``rank_zero_only`` decorator to make sure that
 only the first process in DDP training logs data.
 
 .. code-block:: python
@@ -52,13 +58,13 @@ def finalize(self, status):
             # finishes goes here
 
 
-If you write a logger than may be useful to others, please send
+If you write a logger that may be useful to others, please send
 a pull request to add it to Lighting!
 
 Using loggers
 -------------
 
-Call the logger anywhere from your LightningModule by doing:
+Call the logger anywhere except ``__init__`` in your LightningModule by doing:
 
 .. code-block:: python
 
@@ -69,6 +75,8 @@ def train_step(...):
     def any_lightning_module_function_or_hook(...):
         self.logger.experiment.add_histogram(...)
 
+Read more in the `Experiment Logging use case <./experiment_logging.html>`_.
+
 Supported Loggers
 -----------------
 """
@@ -77,7 +85,7 @@ def any_lightning_module_function_or_hook(...):
 from .base import LightningLoggerBase, LoggerCollection, rank_zero_only
 from .tensorboard import TensorBoardLogger
 
-__all__ = ['TensorBoardLogger', 'LoggerCollection']
+__all__ = ['TensorBoardLogger']
 
 try:
     # needed to prevent ImportError and duplicated logs.
diff --git a/pytorch_lightning/loggers/base.py b/pytorch_lightning/loggers/base.py
--- a/pytorch_lightning/loggers/base.py
+++ b/pytorch_lightning/loggers/base.py
@@ -100,6 +100,9 @@ def __init__(self, logger_iterable: Iterable[LightningLoggerBase]):
         super().__init__()
         self._logger_iterable = logger_iterable
 
+    def __getitem__(self, index: int) -> LightningLoggerBase:
+        return [logger for logger in self._logger_iterable][index]
+
     @property
     def experiment(self) -> List[Any]:
         return [logger.experiment() for logger in self._logger_iterable]
diff --git a/pytorch_lightning/trainer/trainer.py b/pytorch_lightning/trainer/trainer.py
--- a/pytorch_lightning/trainer/trainer.py
+++ b/pytorch_lightning/trainer/trainer.py
@@ -937,6 +937,9 @@ def fit(
             # feed to .fit()
 
         """
+        # bind logger
+        model.logger = self.logger
+
         # Fit begin callbacks
         self.on_fit_start()
 
@@ -1065,10 +1068,8 @@ def run_pretrain_routine(self, model: LightningModule):
         # set local properties on the model
         self.copy_trainer_model_properties(ref_model)
 
-        # link up experiment object
+        # log hyper-parameters
         if self.logger is not None:
-            ref_model.logger = self.logger
-
             # save exp to get started
             if hasattr(ref_model, "hparams"):
                 self.logger.log_hyperparams(ref_model.hparams)


Test patch: