Repository: Lightning-AI/pytorch-lightning

Issue:
LightningModule.load_from_checkpoint not working with .ckpt from 0.7.6
## 🐛 Bug

Trying to use an old experiment .ckpt (generated with ModelCheckpoint(monitor="val_loss", mode="min') in 0.7.6) results in an error when trying to load.

### To Reproduce

Steps to reproduce the behavior:

1. Train something with 0.7.6 and save checkpoint with the checkpoint callback
2. Try to load checkpoint with 0.8.1

```
Trying to load: ckpts/MNIST_0.7.6epoch=4.ckpt with PL version: 0.8.1
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-36a7290b43c6> in <module>()
     35 selected_ckpt = glob(os.path.join("ckpts", "*.ckpt"))[0]
     36 print(f"Trying to load: {selected_ckpt} with PL version: {pl.__version__}")
---> 37 LitClassifier.load_from_checkpoint(selected_ckpt)

1 frames
/usr/local/lib/python3.6/dist-packages/pytorch_lightning/core/saving.py in load_from_checkpoint(cls, checkpoint_path, map_location, hparams_file, tags_csv, *args, **kwargs)
    169         checkpoint[cls.CHECKPOINT_HYPER_PARAMS_KEY].update(kwargs)
    170 
--> 171         model = cls._load_model_state(checkpoint, *args, **kwargs)
    172         return model
    173 

/usr/local/lib/python3.6/dist-packages/pytorch_lightning/core/saving.py in _load_model_state(cls, checkpoint, *args, **kwargs)
    184 
    185             if cls.CHECKPOINT_HYPER_PARAMS_TYPE in checkpoint:
--> 186                 model_args = checkpoint[cls.CHECKPOINT_HYPER_PARAMS_TYPE](model_args)
    187 
    188             args_name = checkpoint.get(cls.CHECKPOINT_HYPER_PARAMS_NAME)

TypeError: 'str' object is not callable
```

Here is a Colab notebook reproducing the issue: https://colab.research.google.com/drive/1s7SzG3EkLJZOmUOkb0mJ85zDcOxBcDLG?usp=sharing

Maybe this is related to the changes in hparams recently?
It happened in my local enviroment and in Google Colab's enviroment.
I was able to load the checkpoint after downgrading to 0.7.6 without problems.

### Expected behavior

Being able to use old .ckpts.

### Environment

 - PyTorch Version (e.g., 1.0): 1.5
 - OS (e.g., Linux): Ubuntu 18.04
 - How you installed PyTorch (`conda`, `pip`, source): pip
 - Build command you used (if compiling from source):
 - Python version: 3.6.9
 - CUDA/cuDNN version: 10.2
 - GPU models and configuration: 1060
 - Any other relevant information:

Also happened in the Colab enviroment.


LightningModule.load_from_checkpoint not working with .ckpt from 0.7.6
## 🐛 Bug

Trying to use an old experiment .ckpt (generated with ModelCheckpoint(monitor="val_loss", mode="min') in 0.7.6) results in an error when trying to load.

### To Reproduce

Steps to reproduce the behavior:

1. Train something with 0.7.6 and save checkpoint with the checkpoint callback
2. Try to load checkpoint with 0.8.1

```
Trying to load: ckpts/MNIST_0.7.6epoch=4.ckpt with PL version: 0.8.1
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-36a7290b43c6> in <module>()
     35 selected_ckpt = glob(os.path.join("ckpts", "*.ckpt"))[0]
     36 print(f"Trying to load: {selected_ckpt} with PL version: {pl.__version__}")
---> 37 LitClassifier.load_from_checkpoint(selected_ckpt)

1 frames
/usr/local/lib/python3.6/dist-packages/pytorch_lightning/core/saving.py in load_from_checkpoint(cls, checkpoint_path, map_location, hparams_file, tags_csv, *args, **kwargs)
    169         checkpoint[cls.CHECKPOINT_HYPER_PARAMS_KEY].update(kwargs)
    170 
--> 171         model = cls._load_model_state(checkpoint, *args, **kwargs)
    172         return model
    173 

/usr/local/lib/python3.6/dist-packages/pytorch_lightning/core/saving.py in _load_model_state(cls, checkpoint, *args, **kwargs)
    184 
    185             if cls.CHECKPOINT_HYPER_PARAMS_TYPE in checkpoint:
--> 186                 model_args = checkpoint[cls.CHECKPOINT_HYPER_PARAMS_TYPE](model_args)
    187 
    188             args_name = checkpoint.get(cls.CHECKPOINT_HYPER_PARAMS_NAME)

TypeError: 'str' object is not callable
```

Here is a Colab notebook reproducing the issue: https://colab.research.google.com/drive/1s7SzG3EkLJZOmUOkb0mJ85zDcOxBcDLG?usp=sharing

Maybe this is related to the changes in hparams recently?
It happened in my local enviroment and in Google Colab's enviroment.
I was able to load the checkpoint after downgrading to 0.7.6 without problems.

### Expected behavior

Being able to use old .ckpts.

### Environment

 - PyTorch Version (e.g., 1.0): 1.5
 - OS (e.g., Linux): Ubuntu 18.04
 - How you installed PyTorch (`conda`, `pip`, source): pip
 - Build command you used (if compiling from source):
 - Python version: 3.6.9
 - CUDA/cuDNN version: 10.2
 - GPU models and configuration: 1060
 - Any other relevant information:

Also happened in the Colab enviroment.




Discussion:
Added a Google Colab notebook reproducing the issue.
Added a Google Colab notebook reproducing the issue.

Resolving patch:
diff --git a/pytorch_lightning/core/saving.py b/pytorch_lightning/core/saving.py
--- a/pytorch_lightning/core/saving.py
+++ b/pytorch_lightning/core/saving.py
@@ -180,8 +180,7 @@ def _load_model_state(cls, checkpoint: Dict[str, Any], *cls_args, **cls_kwargs):
                 if hparam_key in checkpoint:
                     model_args.update(checkpoint[hparam_key])
 
-            if cls.CHECKPOINT_HYPER_PARAMS_TYPE in checkpoint:
-                model_args = checkpoint[cls.CHECKPOINT_HYPER_PARAMS_TYPE](model_args)
+            model_args = _convert_loaded_hparams(model_args, checkpoint.get(cls.CHECKPOINT_HYPER_PARAMS_TYPE))
 
             args_name = checkpoint.get(cls.CHECKPOINT_HYPER_PARAMS_NAME)
             cls_spec = inspect.getfullargspec(cls.__init__)
@@ -248,6 +247,18 @@ def on_hpc_load(self, checkpoint: Dict[str, Any]) -> None:
         """
 
 
+def _convert_loaded_hparams(model_args: dict, hparams_type: Union[Callable, str] = None) -> object:
+    """Convert hparams according given type in callable or string (past) format"""
+    # if not hparams type define
+    if not hparams_type:
+        return model_args
+    # if past checkpoint loaded, convert str to callable
+    if isinstance(hparams_type, str):
+        hparams_type = AttributeDict
+    # convert hparams
+    return hparams_type(model_args)
+
+
 def update_hparams(hparams: dict, updates: dict) -> None:
     """
     Overrides hparams with new values


Test patch:
diff --git a/tests/models/test_hparams.py b/tests/models/test_hparams.py
--- a/tests/models/test_hparams.py
+++ b/tests/models/test_hparams.py
@@ -268,6 +268,7 @@ def test_collect_init_arguments(tmpdir, cls):
     # verify that the checkpoint saved the correct values
     trainer = Trainer(default_root_dir=tmpdir, max_epochs=2, overfit_batches=0.5)
     trainer.fit(model)
+
     raw_checkpoint_path = _raw_checkpoint_path(trainer)
 
     raw_checkpoint = torch.load(raw_checkpoint_path)
@@ -391,6 +392,7 @@ def test_load_past_checkpoint(tmpdir, past_key):
     raw_checkpoint_path = _raw_checkpoint_path(trainer)
     raw_checkpoint = torch.load(raw_checkpoint_path)
     raw_checkpoint[past_key] = raw_checkpoint[LightningModule.CHECKPOINT_HYPER_PARAMS_KEY]
+    raw_checkpoint['hparams_type'] = 'Namespace'
     raw_checkpoint[past_key]['batch_size'] = -17
     del raw_checkpoint[LightningModule.CHECKPOINT_HYPER_PARAMS_KEY]
     # save back the checkpoint