prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  model checkpoint saver/loader dictionary
  **Describe the bug**
  when `save_dict` of `monai.handlers.CheckpointSaver` is a dictionary with a single item,
  loading the file with `monai.handlers.CheckpointLoader` raises an error. 
  
  **To Reproduce**
  To reproduce the issue:
  ```python
  import logging
  import sys
  
  import torch
  from ignite.engine import Engine
  
  from monai.handlers import CheckpointLoader, CheckpointSaver
  
  logging.basicConfig(stream=sys.stdout, level=logging.INFO)
  
  net = torch.nn.PReLU()
  engine = Engine(lambda e, b: None)
  
  CheckpointSaver(save_dir=".", save_dict={"net": net}, save_final=True).attach(engine)
  engine.run([0] * 8, max_epochs=5)
  
  CheckpointLoader(load_path="./net_final_iteration=40.pth", load_dict={"net": net}).attach(engine)
  engine.run([0] * 8, max_epochs=1)
  ```
  the output (showing loader failure) is:
  ```
  INFO:ignite.engine.engine.Engine:Engine run starting with max_epochs=5.
  INFO:ignite.engine.engine.Engine:Epoch[1] Complete. Time taken: 00:00:00
  INFO:ignite.engine.engine.Engine:Epoch[2] Complete. Time taken: 00:00:00
  INFO:ignite.engine.engine.Engine:Epoch[3] Complete. Time taken: 00:00:00
  INFO:ignite.engine.engine.Engine:Epoch[4] Complete. Time taken: 00:00:00
  INFO:ignite.engine.engine.Engine:Epoch[5] Complete. Time taken: 00:00:00
  INFO:ignite.engine.engine.Engine:Train completed, saved final checkpoint: ./net_final_iteration=40.pth
  INFO:ignite.engine.engine.Engine:Engine run complete. Time taken 00:00:00
  INFO:ignite.engine.engine.Engine:Engine run starting with max_epochs=1.
  ERROR:ignite.engine.engine.Engine:Engine run is terminating due to exception: Object labeled by 'net' from `to_load` is not found in the checkpoint.
  INFO:ignite.engine.engine.Engine:Exception_raised, saved exception checkpoint: ./net_final_iteration=40.pth
  ```
  
  **Expected behavior**
  the loader should be able to read this dict structure, to be consistent with the case of  `save_dict` where the dict has more than one item, example:
  ```python
  logging.basicConfig(stream=sys.stdout, level=logging.INFO)
  
  net = torch.nn.PReLU()
  engine = Engine(lambda e, b: None)
  
  CheckpointSaver(save_dir=".", save_dict={"net": net, 'net1': net}, save_final=True).attach(engine)
  engine.run([0] * 8, max_epochs=5)
  
  CheckpointLoader(load_path="./checkpoint_final_iteration=40.pth", load_dict={"net": net}).attach(engine)
  engine.run([0] * 8, max_epochs=1)
  ```
  this example uses `{"net": net, 'net1': net}` and the output is expected:
  ```
  INFO:ignite.engine.engine.Engine:Engine run starting with max_epochs=5.
  INFO:ignite.engine.engine.Engine:Epoch[1] Complete. Time taken: 00:00:00
  INFO:ignite.engine.engine.Engine:Epoch[2] Complete. Time taken: 00:00:00
  INFO:ignite.engine.engine.Engine:Epoch[3] Complete. Time taken: 00:00:00
  INFO:ignite.engine.engine.Engine:Epoch[4] Complete. Time taken: 00:00:00
  INFO:ignite.engine.engine.Engine:Epoch[5] Complete. Time taken: 00:00:00
  INFO:ignite.engine.engine.Engine:Train completed, saved final checkpoint: ./checkpoint_final_iteration=40.pth
  INFO:ignite.engine.engine.Engine:Engine run complete. Time taken 00:00:00
  INFO:ignite.engine.engine.Engine:Engine run starting with max_epochs=1.
  INFO:ignite.engine.engine.Engine:Restored all variables from ./checkpoint_final_iteration=40.pth
  INFO:ignite.engine.engine.Engine:Epoch[1] Complete. Time taken: 00:00:00
  INFO:ignite.engine.engine.Engine:Train completed, saved final checkpoint: ./checkpoint_final_iteration=40.pth
  INFO:ignite.engine.engine.Engine:Engine run complete. Time taken 00:00:00
  ```
  
  **Environment (please complete the following information):**
   - OS macos
   - Python version 3.6
   - MONAI version 1d73f65f3a1c2bf47fb769cf21b0329acfabd114
  
  **Additional context**
  see also https://github.com/pytorch/ignite/issues/770
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `monai/handlers/checkpoint_loader.py`
  Content:
  ```
  1 # Copyright 2020 MONAI Consortium
  2 # Licensed under the Apache License, Version 2.0 (the "License");
  3 # you may not use this file except in compliance with the License.
  4 # You may obtain a copy of the License at
  5 #     http://www.apache.org/licenses/LICENSE-2.0
  6 # Unless required by applicable law or agreed to in writing, software
  7 # distributed under the License is distributed on an "AS IS" BASIS,
  8 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9 # See the License for the specific language governing permissions and
  10 # limitations under the License.
  11 
  12 import logging
  13 import torch
  14 from ignite.engine import Events
  15 from ignite.handlers import Checkpoint
  16 
  17 
  18 class CheckpointLoader:
  19     """
  20     CheckpointLoader acts as an Ignite handler to load checkpoint data from file.
  21     It can load variables for network, optimizer, lr_scheduler.
  22     And also can restore training if load the state_dict of Ignite engine.
  23 
  24     Args:
  25         load_path (str): the file path of checkpoint, it should be a PyTorch pth file.
  26         load_dict (dict): target objects that load checkpoint to. examples::
  27 
  28             {'network': net, 'optimizer': optimizer, 'engine', engine}
  29 
  30         name (str): identifier of logging.logger to use, if None, defaulting to ``engine.logger``.
  31 
  32     """
  33 
  34     def __init__(self, load_path, load_dict, name=None):
  35         assert load_path is not None, "must provide clear path to load checkpoint."
  36         self.load_path = load_path
  37         assert load_dict is not None and len(load_dict) > 0, "must provide target objects to load."
  38         self.logger = None if name is None else logging.getLogger(name)
  39         for k, v in load_dict.items():
  40             if hasattr(v, "module"):
  41                 load_dict[k] = v.module
  42         self.load_dict = load_dict
  43 
  44     def attach(self, engine):
  45         if self.logger is None:
  46             self.logger = engine.logger
  47         return engine.add_event_handler(Events.STARTED, self)
  48 
  49     def __call__(self, engine):
  50         checkpoint = torch.load(self.load_path)
  51         Checkpoint.load_objects(to_load=self.load_dict, checkpoint=checkpoint)
  52         self.logger.info(f"Restored all variables from {self.load_path}")
  53
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/monai/handlers/checkpoint_loader.py b/monai/handlers/checkpoint_loader.py
  --- a/monai/handlers/checkpoint_loader.py
  +++ b/monai/handlers/checkpoint_loader.py
  @@ -19,7 +19,9 @@
       """
       CheckpointLoader acts as an Ignite handler to load checkpoint data from file.
       It can load variables for network, optimizer, lr_scheduler.
  -    And also can restore training if load the state_dict of Ignite engine.
  +    If saving checkpoint after `torch.nn.DataParallel`, need to save `model.module` instead
  +    as PyTorch recommended and then use this loader to load the model.
  +    And also can restore training session if load the state_dict of Ignite engine.
   
       Args:
           load_path (str): the file path of checkpoint, it should be a PyTorch pth file.
  @@ -48,5 +50,10 @@
   
       def __call__(self, engine):
           checkpoint = torch.load(self.load_path)
  +        if len(self.load_dict) == 1:
  +            key = list(self.load_dict.keys())[0]
  +            if not (key in checkpoint):
  +                checkpoint = {key: checkpoint}
  +
           Checkpoint.load_objects(to_load=self.load_dict, checkpoint=checkpoint)
           self.logger.info(f"Restored all variables from {self.load_path}")
  
verification_info: {"golden_diff": "diff --git a/monai/handlers/checkpoint_loader.py b/monai/handlers/checkpoint_loader.py\n--- a/monai/handlers/checkpoint_loader.py\n+++ b/monai/handlers/checkpoint_loader.py\n@@ -19,7 +19,9 @@\n     \"\"\"\n     CheckpointLoader acts as an Ignite handler to load checkpoint data from file.\n     It can load variables for network, optimizer, lr_scheduler.\n-    And also can restore training if load the state_dict of Ignite engine.\n+    If saving checkpoint after `torch.nn.DataParallel`, need to save `model.module` instead\n+    as PyTorch recommended and then use this loader to load the model.\n+    And also can restore training session if load the state_dict of Ignite engine.\n \n     Args:\n         load_path (str): the file path of checkpoint, it should be a PyTorch pth file.\n@@ -48,5 +50,10 @@\n \n     def __call__(self, engine):\n         checkpoint = torch.load(self.load_path)\n+        if len(self.load_dict) == 1:\n+            key = list(self.load_dict.keys())[0]\n+            if not (key in checkpoint):\n+                checkpoint = {key: checkpoint}\n+\n         Checkpoint.load_objects(to_load=self.load_dict, checkpoint=checkpoint)\n         self.logger.info(f\"Restored all variables from {self.load_path}\")\n", "issue": "model checkpoint saver/loader dictionary\n**Describe the bug**\r\nwhen `save_dict` of `monai.handlers.CheckpointSaver` is a dictionary with a single item,\r\nloading the file with `monai.handlers.CheckpointLoader` raises an error. \r\n\r\n**To Reproduce**\r\nTo reproduce the issue:\r\n```python\r\nimport logging\r\nimport sys\r\n\r\nimport torch\r\nfrom ignite.engine import Engine\r\n\r\nfrom monai.handlers import CheckpointLoader, CheckpointSaver\r\n\r\nlogging.basicConfig(stream=sys.stdout, level=logging.INFO)\r\n\r\nnet = torch.nn.PReLU()\r\nengine = Engine(lambda e, b: None)\r\n\r\nCheckpointSaver(save_dir=\".\", save_dict={\"net\": net}, save_final=True).attach(engine)\r\nengine.run([0] * 8, max_epochs=5)\r\n\r\nCheckpointLoader(load_path=\"./net_final_iteration=40.pth\", load_dict={\"net\": net}).attach(engine)\r\nengine.run([0] * 8, max_epochs=1)\r\n```\r\nthe output (showing loader failure) is:\r\n```\r\nINFO:ignite.engine.engine.Engine:Engine run starting with max_epochs=5.\r\nINFO:ignite.engine.engine.Engine:Epoch[1] Complete. Time taken: 00:00:00\r\nINFO:ignite.engine.engine.Engine:Epoch[2] Complete. Time taken: 00:00:00\r\nINFO:ignite.engine.engine.Engine:Epoch[3] Complete. Time taken: 00:00:00\r\nINFO:ignite.engine.engine.Engine:Epoch[4] Complete. Time taken: 00:00:00\r\nINFO:ignite.engine.engine.Engine:Epoch[5] Complete. Time taken: 00:00:00\r\nINFO:ignite.engine.engine.Engine:Train completed, saved final checkpoint: ./net_final_iteration=40.pth\r\nINFO:ignite.engine.engine.Engine:Engine run complete. Time taken 00:00:00\r\nINFO:ignite.engine.engine.Engine:Engine run starting with max_epochs=1.\r\nERROR:ignite.engine.engine.Engine:Engine run is terminating due to exception: Object labeled by 'net' from `to_load` is not found in the checkpoint.\r\nINFO:ignite.engine.engine.Engine:Exception_raised, saved exception checkpoint: ./net_final_iteration=40.pth\r\n```\r\n\r\n**Expected behavior**\r\nthe loader should be able to read this dict structure, to be consistent with the case of  `save_dict` where the dict has more than one item, example:\r\n```python\r\nlogging.basicConfig(stream=sys.stdout, level=logging.INFO)\r\n\r\nnet = torch.nn.PReLU()\r\nengine = Engine(lambda e, b: None)\r\n\r\nCheckpointSaver(save_dir=\".\", save_dict={\"net\": net, 'net1': net}, save_final=True).attach(engine)\r\nengine.run([0] * 8, max_epochs=5)\r\n\r\nCheckpointLoader(load_path=\"./checkpoint_final_iteration=40.pth\", load_dict={\"net\": net}).attach(engine)\r\nengine.run([0] * 8, max_epochs=1)\r\n```\r\nthis example uses `{\"net\": net, 'net1': net}` and the output is expected:\r\n```\r\nINFO:ignite.engine.engine.Engine:Engine run starting with max_epochs=5.\r\nINFO:ignite.engine.engine.Engine:Epoch[1] Complete. Time taken: 00:00:00\r\nINFO:ignite.engine.engine.Engine:Epoch[2] Complete. Time taken: 00:00:00\r\nINFO:ignite.engine.engine.Engine:Epoch[3] Complete. Time taken: 00:00:00\r\nINFO:ignite.engine.engine.Engine:Epoch[4] Complete. Time taken: 00:00:00\r\nINFO:ignite.engine.engine.Engine:Epoch[5] Complete. Time taken: 00:00:00\r\nINFO:ignite.engine.engine.Engine:Train completed, saved final checkpoint: ./checkpoint_final_iteration=40.pth\r\nINFO:ignite.engine.engine.Engine:Engine run complete. Time taken 00:00:00\r\nINFO:ignite.engine.engine.Engine:Engine run starting with max_epochs=1.\r\nINFO:ignite.engine.engine.Engine:Restored all variables from ./checkpoint_final_iteration=40.pth\r\nINFO:ignite.engine.engine.Engine:Epoch[1] Complete. Time taken: 00:00:00\r\nINFO:ignite.engine.engine.Engine:Train completed, saved final checkpoint: ./checkpoint_final_iteration=40.pth\r\nINFO:ignite.engine.engine.Engine:Engine run complete. Time taken 00:00:00\r\n```\r\n\r\n**Environment (please complete the following information):**\r\n - OS macos\r\n - Python version 3.6\r\n - MONAI version 1d73f65f3a1c2bf47fb769cf21b0329acfabd114\r\n\r\n**Additional context**\r\nsee also https://github.com/pytorch/ignite/issues/770\n", "before_files": [{"content": "# Copyright 2020 MONAI Consortium\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#     http://www.apache.org/licenses/LICENSE-2.0\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport logging\nimport torch\nfrom ignite.engine import Events\nfrom ignite.handlers import Checkpoint\n\n\nclass CheckpointLoader:\n    \"\"\"\n    CheckpointLoader acts as an Ignite handler to load checkpoint data from file.\n    It can load variables for network, optimizer, lr_scheduler.\n    And also can restore training if load the state_dict of Ignite engine.\n\n    Args:\n        load_path (str): the file path of checkpoint, it should be a PyTorch pth file.\n        load_dict (dict): target objects that load checkpoint to. examples::\n\n            {'network': net, 'optimizer': optimizer, 'engine', engine}\n\n        name (str): identifier of logging.logger to use, if None, defaulting to ``engine.logger``.\n\n    \"\"\"\n\n    def __init__(self, load_path, load_dict, name=None):\n        assert load_path is not None, \"must provide clear path to load checkpoint.\"\n        self.load_path = load_path\n        assert load_dict is not None and len(load_dict) > 0, \"must provide target objects to load.\"\n        self.logger = None if name is None else logging.getLogger(name)\n        for k, v in load_dict.items():\n            if hasattr(v, \"module\"):\n                load_dict[k] = v.module\n        self.load_dict = load_dict\n\n    def attach(self, engine):\n        if self.logger is None:\n            self.logger = engine.logger\n        return engine.add_event_handler(Events.STARTED, self)\n\n    def __call__(self, engine):\n        checkpoint = torch.load(self.load_path)\n        Checkpoint.load_objects(to_load=self.load_dict, checkpoint=checkpoint)\n        self.logger.info(f\"Restored all variables from {self.load_path}\")\n", "path": "monai/handlers/checkpoint_loader.py"}], "after_files": [{"content": "# Copyright 2020 MONAI Consortium\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#     http://www.apache.org/licenses/LICENSE-2.0\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport logging\nimport torch\nfrom ignite.engine import Events\nfrom ignite.handlers import Checkpoint\n\n\nclass CheckpointLoader:\n    \"\"\"\n    CheckpointLoader acts as an Ignite handler to load checkpoint data from file.\n    It can load variables for network, optimizer, lr_scheduler.\n    If saving checkpoint after `torch.nn.DataParallel`, need to save `model.module` instead\n    as PyTorch recommended and then use this loader to load the model.\n    And also can restore training session if load the state_dict of Ignite engine.\n\n    Args:\n        load_path (str): the file path of checkpoint, it should be a PyTorch pth file.\n        load_dict (dict): target objects that load checkpoint to. examples::\n\n            {'network': net, 'optimizer': optimizer, 'engine', engine}\n\n        name (str): identifier of logging.logger to use, if None, defaulting to ``engine.logger``.\n\n    \"\"\"\n\n    def __init__(self, load_path, load_dict, name=None):\n        assert load_path is not None, \"must provide clear path to load checkpoint.\"\n        self.load_path = load_path\n        assert load_dict is not None and len(load_dict) > 0, \"must provide target objects to load.\"\n        self.logger = None if name is None else logging.getLogger(name)\n        for k, v in load_dict.items():\n            if hasattr(v, \"module\"):\n                load_dict[k] = v.module\n        self.load_dict = load_dict\n\n    def attach(self, engine):\n        if self.logger is None:\n            self.logger = engine.logger\n        return engine.add_event_handler(Events.STARTED, self)\n\n    def __call__(self, engine):\n        checkpoint = torch.load(self.load_path)\n        if len(self.load_dict) == 1:\n            key = list(self.load_dict.keys())[0]\n            if not (key in checkpoint):\n                checkpoint = {key: checkpoint}\n\n        Checkpoint.load_objects(to_load=self.load_dict, checkpoint=checkpoint)\n        self.logger.info(f\"Restored all variables from {self.load_path}\")\n", "path": "monai/handlers/checkpoint_loader.py"}]}