Repository: pytorch/ignite

Issue:
Maybe unintended changes in ModelCheckpoint 
## ❓ Questions/Help/Support

I have been using ignite for quite some time now and recently I came across a change from the ModelCheckpoint I'm aware of the BC with v0.3.0.
Still I want to know if it was the intended behavior.

Before we would be able to do something like this to save parameters and optimizer:
``` python3
import torch
from ignite.engine import Engine
from ignite.handlers import ModelCheckpoint
trainer = Engine(lambda batch: None)
handler = ModelCheckpoint('/tmp/models', 'myprefix', n_saved=None, create_dir=True)
model = torch.nn.Linear(3, 3)
optimizer = torch.optim.SGD(model.parameters(), lr=1e-3)
trainer.add_event_handler(Events.EPOCH_COMPLETED(every=2), handler, {"weights": model, "optimizer": optimizer})
```

This will save two files the optimizer `/tmp/models/myprefix_optimizer_{iteration}.pth` and the weights `/tmp/models/myprefix_weights_{iteration}.pth`.
With the breaking change now this is not working anymore because of these lines I think:
https://github.com/pytorch/ignite/blob/39c4a8e2ef9a2a6c3a6109abc395ad39316349d8/ignite/handlers/checkpoint.py#L212-L224
The filename is `/tmp/models/myprefix_checkpoint_{iteration}.pth` and contains the weights and the optimizer state_dict.

To have the same behavior I have to "duplicate" the last line like this
```python3
trainer.add_event_handler(Events.EPOCH_COMPLETED(every=2), handler, {"weights": model})
trainer.add_event_handler(Events.EPOCH_COMPLETED(every=2), handler, {"optimizer": optimizer})
```

Is this the new intended behavior for saving state_dict ?


<!-- If you have a question, please checkout other issues labelled as "question" (https://github.com/pytorch/ignite/issues?q=is%3Aissue+is%3Aopen+label%3Aquestion) -->
<!-- If your question is not listed above or you need a support or help, please provide a description-->
<!-- If you prefer, you can also reach out us on [Discussion Forum](https://discuss.pytorch.org/) adding tag "ignite". -->



Discussion:
@czotti since v0.3.0 `ModelCheckpoint` and `Checkpoint` store all objects to save in a single file instead of multiple files in previous versions. ([test](https://github.com/pytorch/ignite/blob/39c4a8e2ef9a2a6c3a6109abc395ad39316349d8/tests/ignite/handlers/test_checkpoint.py#L675))
Idea is to simplify the loading of all objects to resume a training with a single `torch.load`:
```python
to_load = {"model": model, ...}
checkpoint = torch.load(checkpoint_fp)
Checkpoint.load_objects(to_load=to_load, checkpoint=checkpoint)
```
Yes, to save in multiple files, we need to add the handler two times as you suggest.
What do you think ?

HTH
Oh I didn't know you could load the checkpoint like this, it's fine to me. Maybe add this code snippet in the documentation to show how to load the checkpoints because at first I was doing it by hand like this
```python
checkpoint = torch.load(checkpoint_fp)
model.load_state_dict(checkpoint["model"])
optimizer.load_state_dict(checkpoint["optimizer"])
```
 or with a for loop like the `load_objects` if I have more state_dict to load.
@czotti good idea, thanks ! Seems like `Checkpoint.load_objects` is not picked by sphinx to render the docs.

PS: if you would like to contribute to Ignite by improving our docs, do not hesitate to send a PR, it would be very helpful for us !

Resolving patch:
diff --git a/ignite/handlers/checkpoint.py b/ignite/handlers/checkpoint.py
--- a/ignite/handlers/checkpoint.py
+++ b/ignite/handlers/checkpoint.py
@@ -246,6 +246,26 @@ def _check_objects(objs: Mapping, attr: str) -> None:
     def load_objects(to_load: Mapping, checkpoint: Mapping, **kwargs) -> None:
         """Helper method to apply `load_state_dict` on the objects from `to_load` using states from `checkpoint`.
 
+        Exemples:
+
+        .. code-block:: python
+
+            import torch
+            from ignite.engine import Engine, Events
+            from ignite.handlers import ModelCheckpoint, Checkpoint
+            trainer = Engine(lambda engine, batch: None)
+            handler = ModelCheckpoint('/tmp/models', 'myprefix', n_saved=None, create_dir=True)
+            model = torch.nn.Linear(3, 3)
+            optimizer = torch.optim.SGD(model.parameters(), lr=1e-3)
+            to_save = {"weights": model, "optimizer": optimizer}
+            trainer.add_event_handler(Events.EPOCH_COMPLETED(every=2), handler, to_save)
+            trainer.run(torch.randn(10, 1), 5)
+
+            to_load = to_save
+            checkpoint_fp = "/tmp/models/myprefix_checkpoint_40.pth"
+            checkpoint = torch.load(checkpoint_fp)
+            Checkpoint.load_objects(to_load=to_load, checkpoint=checkpoint)
+
         Args:
             to_load (Mapping): a dictionary with objects, e.g. `{"model": model, "optimizer": optimizer, ...}`
             checkpoint (Mapping): a dictionary with state_dicts to load, e.g. `{"model": model_state_dict,
@@ -291,7 +311,9 @@ class DiskSaver:
         require_empty (bool, optional): If True, will raise exception if there are any files in the directory 'dirname'.
     """
 
-    def __init__(self, dirname: str, atomic: bool = True, create_dir: bool = True, require_empty: bool = True):
+    def __init__(
+        self, dirname: str, atomic: bool = True, create_dir: bool = True, require_empty: bool = True,
+    ):
         self.dirname = os.path.expanduser(dirname)
         self._atomic = atomic
         if create_dir:
@@ -429,7 +451,7 @@ def __init__(
                 # No choice
                 raise ValueError(msg)
 
-        disk_saver = DiskSaver(dirname, atomic=atomic, create_dir=create_dir, require_empty=require_empty)
+        disk_saver = DiskSaver(dirname, atomic=atomic, create_dir=create_dir, require_empty=require_empty,)
 
         if score_function is None and score_name is not None:
             raise ValueError("If `score_name` is provided, then `score_function` " "should be also provided.")


Test patch: