We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
CheckpointSaver: incorrect labelling of final model
**Describe the bug**
When using a `CheckpointSaver` among the validation handlers, the argument `save_final=True` results in every epoch being stored under `net_final_iteration=1.pt` when `final_filename=None`. I interpret the docs (`default to checkpoint_final_iteration=N.pt`) that the file will be renamed after each completed epoch.

**To Reproduce**
add `save_final=True` to the `CheckpointHandler` in the Lung Segmentation Tutorial

**Expected behavior**
`net_final_iteration=1.pt` ->  `net_final_iteration=2.pt` -> ... ->  `net_final_iteration=MAX_EPOCHS.pt`

**Screenshots**
The logging function also prints incorrect iteration numbers:

```
INFO:ignite.engine.engine.SupervisedEvaluator:Train completed, saved final checkpoint: net_final_iteration=1.pt
...
INFO:ignite.engine.engine.SupervisedEvaluator:Train completed, saved final checkpoint: net_final_iteration=1.pt
...
INFO:ignite.engine.engine.SupervisedEvaluator:Train completed, saved final checkpoint: net_final_iteration=1.pt
```

**Environment**

Ensuring you use the relevant python executable, please paste the output of:

```
MONAI version: 0.3.0+95.g535561e
Python version: 3.8.6 | packaged by conda-forge | (default, Oct  7 2020, 18:42:56)  [Clang 10.0.1 ]
OS version: Darwin (19.6.0)
Numpy version: 1.19.2
Pytorch version: 1.7.0
MONAI flags: HAS_EXT = False, USE_COMPILED = False

Optional dependencies:
Pytorch Ignite version: 0.4.2
Nibabel version: 3.2.0
scikit-image version: NOT INSTALLED or UNKNOWN VERSION.
Pillow version: 8.0.1
Tensorboard version: 2.4.0
gdown version: NOT INSTALLED or UNKNOWN VERSION.
TorchVision version: 0.8.1
ITK version: NOT INSTALLED or UNKNOWN VERSION.
tqdm version: 4.53.0
lmdb version: NOT INSTALLED or UNKNOWN VERSION.

For details about installing the optional dependencies, please visit:
    https://docs.monai.io/en/latest/installation.html#installing-the-recommended-dependencies
```

**Additional context**
Using `SupervisedEvaluator` and `SupervisedTrainer`.

--- 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_saver.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 from typing import TYPE_CHECKING, Dict, Optional
14 
15 from monai.utils import exact_version, optional_import
16 
17 Events, _ = optional_import("ignite.engine", "0.4.2", exact_version, "Events")
18 Checkpoint, _ = optional_import("ignite.handlers", "0.4.2", exact_version, "Checkpoint")
19 BaseSaveHandler, _ = optional_import("ignite.handlers.checkpoint", "0.4.2", exact_version, "BaseSaveHandler")
20 
21 if TYPE_CHECKING:
22     from ignite.engine import Engine
23     from ignite.handlers import DiskSaver
24 else:
25     Engine, _ = optional_import("ignite.engine", "0.4.2", exact_version, "Engine")
26     DiskSaver, _ = optional_import("ignite.handlers", "0.4.2", exact_version, "DiskSaver")
27 
28 
29 class CheckpointSaver:
30     """
31     CheckpointSaver acts as an Ignite handler to save checkpoint data into files.
32     It supports to save according to metrics result, epoch number, iteration number
33     and last model or exception.
34 
35     Args:
36         save_dir: the target directory to save the checkpoints.
37         save_dict: source objects that save to the checkpoint. examples::
38 
39             {'network': net, 'optimizer': optimizer, 'lr_scheduler': lr_scheduler}
40 
41         name: identifier of logging.logger to use, if None, defaulting to ``engine.logger``.
42         file_prefix: prefix for the filenames to which objects will be saved.
43         save_final: whether to save checkpoint or session at final iteration or exception.
44             If checkpoints are to be saved when an exception is raised, put this handler before
45             `StatsHandler` in the handler list, because the logic with Ignite can only trigger
46             the first attached handler for `EXCEPTION_RAISED` event.
47         final_filename: set a fixed filename to save the final model if `save_final=True`.
48             If None, default to `checkpoint_final_iteration=N.pt`.
49         save_key_metric: whether to save checkpoint or session when the value of key_metric is
50             higher than all the previous values during training.keep 4 decimal places of metric,
51             checkpoint name is: {file_prefix}_key_metric=0.XXXX.pth.
52         key_metric_name: the name of key_metric in ignite metrics dictionary.
53             If None, use `engine.state.key_metric` instead.
54         key_metric_n_saved: save top N checkpoints or sessions, sorted by the value of key
55             metric in descending order.
56         key_metric_filename: set a fixed filename to set the best metric model, if not None,
57             `key_metric_n_saved` should be 1 and only keep the best metric model.
58         epoch_level: save checkpoint during training for every N epochs or every N iterations.
59             `True` is epoch level, `False` is iteration level.
60         save_interval: save checkpoint every N epochs, default is 0 to save no checkpoint.
61         n_saved: save latest N checkpoints of epoch level or iteration level, 'None' is to save all.
62 
63     Note:
64         CheckpointHandler can be used during training, validation or evaluation.
65         example of saved files:
66 
67             - checkpoint_iteration=400.pt
68             - checkpoint_iteration=800.pt
69             - checkpoint_epoch=1.pt
70             - checkpoint_final_iteration=1000.pt
71             - checkpoint_key_metric=0.9387.pt
72 
73     """
74 
75     def __init__(
76         self,
77         save_dir: str,
78         save_dict: Dict,
79         name: Optional[str] = None,
80         file_prefix: str = "",
81         save_final: bool = False,
82         final_filename: Optional[str] = None,
83         save_key_metric: bool = False,
84         key_metric_name: Optional[str] = None,
85         key_metric_n_saved: int = 1,
86         key_metric_filename: Optional[str] = None,
87         epoch_level: bool = True,
88         save_interval: int = 0,
89         n_saved: Optional[int] = None,
90     ) -> None:
91         assert save_dir is not None, "must provide directory to save the checkpoints."
92         self.save_dir = save_dir
93         assert save_dict is not None and len(save_dict) > 0, "must provide source objects to save."
94         self.save_dict = save_dict
95         self.logger = logging.getLogger(name)
96         self.epoch_level = epoch_level
97         self.save_interval = save_interval
98         self._final_checkpoint = self._key_metric_checkpoint = self._interval_checkpoint = None
99         self._name = name
100 
101         class _DiskSaver(DiskSaver):
102             """
103             Enhance the DiskSaver to support fixed filename.
104 
105             """
106 
107             def __init__(self, dirname: str, filename: Optional[str] = None):
108                 super().__init__(dirname=dirname, require_empty=False)
109                 self.filename = filename
110 
111             def __call__(self, checkpoint: Dict, filename: str, metadata: Optional[Dict] = None) -> None:
112                 if self.filename is not None:
113                     filename = self.filename
114                 super().__call__(checkpoint=checkpoint, filename=filename, metadata=metadata)
115 
116             def remove(self, filename: str) -> None:
117                 if self.filename is not None:
118                     filename = self.filename
119                 super().remove(filename=filename)
120 
121         if save_final:
122 
123             def _final_func(engine: Engine):
124                 return engine.state.iteration
125 
126             self._final_checkpoint = Checkpoint(
127                 to_save=self.save_dict,
128                 save_handler=_DiskSaver(dirname=self.save_dir, filename=final_filename),
129                 filename_prefix=file_prefix,
130                 score_function=_final_func,
131                 score_name="final_iteration",
132             )
133 
134         if save_key_metric:
135 
136             def _score_func(engine: Engine):
137                 if isinstance(key_metric_name, str):
138                     metric_name = key_metric_name
139                 elif hasattr(engine.state, "key_metric_name") and isinstance(engine.state.key_metric_name, str):
140                     metric_name = engine.state.key_metric_name
141                 else:
142                     raise ValueError(
143                         f"Incompatible values: save_key_metric=True and key_metric_name={key_metric_name}."
144                     )
145                 return round(engine.state.metrics[metric_name], 4)
146 
147             if key_metric_filename is not None and key_metric_n_saved > 1:
148                 raise ValueError("if using fixed filename to save the best metric model, we should only save 1 model.")
149 
150             self._key_metric_checkpoint = Checkpoint(
151                 to_save=self.save_dict,
152                 save_handler=_DiskSaver(dirname=self.save_dir, filename=key_metric_filename),
153                 filename_prefix=file_prefix,
154                 score_function=_score_func,
155                 score_name="key_metric",
156                 n_saved=key_metric_n_saved,
157             )
158 
159         if save_interval > 0:
160 
161             def _interval_func(engine: Engine):
162                 return engine.state.epoch if self.epoch_level else engine.state.iteration
163 
164             self._interval_checkpoint = Checkpoint(
165                 to_save=self.save_dict,
166                 save_handler=_DiskSaver(dirname=self.save_dir),
167                 filename_prefix=file_prefix,
168                 score_function=_interval_func,
169                 score_name="epoch" if self.epoch_level else "iteration",
170                 n_saved=n_saved,
171             )
172 
173     def attach(self, engine: Engine) -> None:
174         """
175         Args:
176             engine: Ignite Engine, it can be a trainer, validator or evaluator.
177         """
178         if self._name is None:
179             self.logger = engine.logger
180         if self._final_checkpoint is not None:
181             engine.add_event_handler(Events.COMPLETED, self.completed)
182             engine.add_event_handler(Events.EXCEPTION_RAISED, self.exception_raised)
183         if self._key_metric_checkpoint is not None:
184             engine.add_event_handler(Events.EPOCH_COMPLETED, self.metrics_completed)
185         if self._interval_checkpoint is not None:
186             if self.epoch_level:
187                 engine.add_event_handler(Events.EPOCH_COMPLETED(every=self.save_interval), self.interval_completed)
188             else:
189                 engine.add_event_handler(Events.ITERATION_COMPLETED(every=self.save_interval), self.interval_completed)
190 
191     def completed(self, engine: Engine) -> None:
192         """Callback for train or validation/evaluation completed Event.
193         Save final checkpoint if configure save_final is True.
194 
195         Args:
196             engine: Ignite Engine, it can be a trainer, validator or evaluator.
197         """
198         assert callable(self._final_checkpoint), "Error: _final_checkpoint function not specified."
199         self._final_checkpoint(engine)
200         assert self.logger is not None
201         assert hasattr(self.logger, "info"), "Error, provided logger has not info attribute."
202         self.logger.info(f"Train completed, saved final checkpoint: {self._final_checkpoint.last_checkpoint}")
203 
204     def exception_raised(self, engine: Engine, e: Exception) -> None:
205         """Callback for train or validation/evaluation exception raised Event.
206         Save current data as final checkpoint if configure save_final is True. This callback may be skipped
207         because the logic with Ignite can only trigger the first attached handler for `EXCEPTION_RAISED` event.
208 
209         Args:
210             engine: Ignite Engine, it can be a trainer, validator or evaluator.
211             e: the exception caught in Ignite during engine.run().
212         """
213         assert callable(self._final_checkpoint), "Error: _final_checkpoint function not specified."
214         self._final_checkpoint(engine)
215         assert self.logger is not None
216         assert hasattr(self.logger, "info"), "Error, provided logger has not info attribute."
217         self.logger.info(f"Exception_raised, saved exception checkpoint: {self._final_checkpoint.last_checkpoint}")
218         raise e
219 
220     def metrics_completed(self, engine: Engine) -> None:
221         """Callback to compare metrics and save models in train or validation when epoch completed.
222 
223         Args:
224             engine: Ignite Engine, it can be a trainer, validator or evaluator.
225         """
226         assert callable(self._key_metric_checkpoint), "Error: _key_metric_checkpoint function not specified."
227         self._key_metric_checkpoint(engine)
228 
229     def interval_completed(self, engine: Engine) -> None:
230         """Callback for train epoch/iteration completed Event.
231         Save checkpoint if configure save_interval = N
232 
233         Args:
234             engine: Ignite Engine, it can be a trainer, validator or evaluator.
235         """
236         assert callable(self._interval_checkpoint), "Error: _interval_checkpoint function not specified."
237         self._interval_checkpoint(engine)
238         assert self.logger is not None
239         assert hasattr(self.logger, "info"), "Error, provided logger has not info attribute."
240         if self.epoch_level:
241             self.logger.info(f"Saved checkpoint at epoch: {engine.state.epoch}")
242         else:
243             self.logger.info(f"Saved checkpoint at iteration: {engine.state.iteration}")
244
```
--- 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()

```

diff --git a/monai/handlers/checkpoint_saver.py b/monai/handlers/checkpoint_saver.py
--- a/monai/handlers/checkpoint_saver.py
+++ b/monai/handlers/checkpoint_saver.py
@@ -188,6 +188,13 @@
             else:
                 engine.add_event_handler(Events.ITERATION_COMPLETED(every=self.save_interval), self.interval_completed)
 
+    def _delete_previous_final_ckpt(self):
+        saved = self._final_checkpoint._saved
+        if len(saved) > 0:
+            item = saved.pop(0)
+            self._final_checkpoint.save_handler.remove(item.filename)
+            self.logger.info(f"Deleted previous saved final checkpoint: {item.filename}")
+
     def completed(self, engine: Engine) -> None:
         """Callback for train or validation/evaluation completed Event.
         Save final checkpoint if configure save_final is True.
@@ -196,6 +203,8 @@
             engine: Ignite Engine, it can be a trainer, validator or evaluator.
         """
         assert callable(self._final_checkpoint), "Error: _final_checkpoint function not specified."
+        # delete previous saved final checkpoint if existing
+        self._delete_previous_final_ckpt()
         self._final_checkpoint(engine)
         assert self.logger is not None
         assert hasattr(self.logger, "info"), "Error, provided logger has not info attribute."
@@ -211,6 +220,8 @@
             e: the exception caught in Ignite during engine.run().
         """
         assert callable(self._final_checkpoint), "Error: _final_checkpoint function not specified."
+        # delete previous saved final checkpoint if existing
+        self._delete_previous_final_ckpt()
         self._final_checkpoint(engine)
         assert self.logger is not None
         assert hasattr(self.logger, "info"), "Error, provided logger has not info attribute."

{"golden_diff": "diff --git a/monai/handlers/checkpoint_saver.py b/monai/handlers/checkpoint_saver.py\n--- a/monai/handlers/checkpoint_saver.py\n+++ b/monai/handlers/checkpoint_saver.py\n@@ -188,6 +188,13 @@\n             else:\n                 engine.add_event_handler(Events.ITERATION_COMPLETED(every=self.save_interval), self.interval_completed)\n \n+    def _delete_previous_final_ckpt(self):\n+        saved = self._final_checkpoint._saved\n+        if len(saved) > 0:\n+            item = saved.pop(0)\n+            self._final_checkpoint.save_handler.remove(item.filename)\n+            self.logger.info(f\"Deleted previous saved final checkpoint: {item.filename}\")\n+\n     def completed(self, engine: Engine) -> None:\n         \"\"\"Callback for train or validation/evaluation completed Event.\n         Save final checkpoint if configure save_final is True.\n@@ -196,6 +203,8 @@\n             engine: Ignite Engine, it can be a trainer, validator or evaluator.\n         \"\"\"\n         assert callable(self._final_checkpoint), \"Error: _final_checkpoint function not specified.\"\n+        # delete previous saved final checkpoint if existing\n+        self._delete_previous_final_ckpt()\n         self._final_checkpoint(engine)\n         assert self.logger is not None\n         assert hasattr(self.logger, \"info\"), \"Error, provided logger has not info attribute.\"\n@@ -211,6 +220,8 @@\n             e: the exception caught in Ignite during engine.run().\n         \"\"\"\n         assert callable(self._final_checkpoint), \"Error: _final_checkpoint function not specified.\"\n+        # delete previous saved final checkpoint if existing\n+        self._delete_previous_final_ckpt()\n         self._final_checkpoint(engine)\n         assert self.logger is not None\n         assert hasattr(self.logger, \"info\"), \"Error, provided logger has not info attribute.\"\n", "issue": "CheckpointSaver: incorrect labelling of final model\n**Describe the bug**\r\nWhen using a `CheckpointSaver` among the validation handlers, the argument `save_final=True` results in every epoch being stored under `net_final_iteration=1.pt` when `final_filename=None`. I interpret the docs (`default to checkpoint_final_iteration=N.pt`) that the file will be renamed after each completed epoch.\r\n\r\n**To Reproduce**\r\nadd `save_final=True` to the `CheckpointHandler` in the Lung Segmentation Tutorial\r\n\r\n**Expected behavior**\r\n`net_final_iteration=1.pt` ->  `net_final_iteration=2.pt` -> ... ->  `net_final_iteration=MAX_EPOCHS.pt`\r\n\r\n**Screenshots**\r\nThe logging function also prints incorrect iteration numbers:\r\n\r\n```\r\nINFO:ignite.engine.engine.SupervisedEvaluator:Train completed, saved final checkpoint: net_final_iteration=1.pt\r\n...\r\nINFO:ignite.engine.engine.SupervisedEvaluator:Train completed, saved final checkpoint: net_final_iteration=1.pt\r\n...\r\nINFO:ignite.engine.engine.SupervisedEvaluator:Train completed, saved final checkpoint: net_final_iteration=1.pt\r\n```\r\n\r\n**Environment**\r\n\r\nEnsuring you use the relevant python executable, please paste the output of:\r\n\r\n```\r\nMONAI version: 0.3.0+95.g535561e\r\nPython version: 3.8.6 | packaged by conda-forge | (default, Oct  7 2020, 18:42:56)  [Clang 10.0.1 ]\r\nOS version: Darwin (19.6.0)\r\nNumpy version: 1.19.2\r\nPytorch version: 1.7.0\r\nMONAI flags: HAS_EXT = False, USE_COMPILED = False\r\n\r\nOptional dependencies:\r\nPytorch Ignite version: 0.4.2\r\nNibabel version: 3.2.0\r\nscikit-image version: NOT INSTALLED or UNKNOWN VERSION.\r\nPillow version: 8.0.1\r\nTensorboard version: 2.4.0\r\ngdown version: NOT INSTALLED or UNKNOWN VERSION.\r\nTorchVision version: 0.8.1\r\nITK version: NOT INSTALLED or UNKNOWN VERSION.\r\ntqdm version: 4.53.0\r\nlmdb version: NOT INSTALLED or UNKNOWN VERSION.\r\n\r\nFor details about installing the optional dependencies, please visit:\r\n    https://docs.monai.io/en/latest/installation.html#installing-the-recommended-dependencies\r\n```\r\n\r\n**Additional context**\r\nUsing `SupervisedEvaluator` and `SupervisedTrainer`.\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\nfrom typing import TYPE_CHECKING, Dict, Optional\n\nfrom monai.utils import exact_version, optional_import\n\nEvents, _ = optional_import(\"ignite.engine\", \"0.4.2\", exact_version, \"Events\")\nCheckpoint, _ = optional_import(\"ignite.handlers\", \"0.4.2\", exact_version, \"Checkpoint\")\nBaseSaveHandler, _ = optional_import(\"ignite.handlers.checkpoint\", \"0.4.2\", exact_version, \"BaseSaveHandler\")\n\nif TYPE_CHECKING:\n    from ignite.engine import Engine\n    from ignite.handlers import DiskSaver\nelse:\n    Engine, _ = optional_import(\"ignite.engine\", \"0.4.2\", exact_version, \"Engine\")\n    DiskSaver, _ = optional_import(\"ignite.handlers\", \"0.4.2\", exact_version, \"DiskSaver\")\n\n\nclass CheckpointSaver:\n    \"\"\"\n    CheckpointSaver acts as an Ignite handler to save checkpoint data into files.\n    It supports to save according to metrics result, epoch number, iteration number\n    and last model or exception.\n\n    Args:\n        save_dir: the target directory to save the checkpoints.\n        save_dict: source objects that save to the checkpoint. examples::\n\n            {'network': net, 'optimizer': optimizer, 'lr_scheduler': lr_scheduler}\n\n        name: identifier of logging.logger to use, if None, defaulting to ``engine.logger``.\n        file_prefix: prefix for the filenames to which objects will be saved.\n        save_final: whether to save checkpoint or session at final iteration or exception.\n            If checkpoints are to be saved when an exception is raised, put this handler before\n            `StatsHandler` in the handler list, because the logic with Ignite can only trigger\n            the first attached handler for `EXCEPTION_RAISED` event.\n        final_filename: set a fixed filename to save the final model if `save_final=True`.\n            If None, default to `checkpoint_final_iteration=N.pt`.\n        save_key_metric: whether to save checkpoint or session when the value of key_metric is\n            higher than all the previous values during training.keep 4 decimal places of metric,\n            checkpoint name is: {file_prefix}_key_metric=0.XXXX.pth.\n        key_metric_name: the name of key_metric in ignite metrics dictionary.\n            If None, use `engine.state.key_metric` instead.\n        key_metric_n_saved: save top N checkpoints or sessions, sorted by the value of key\n            metric in descending order.\n        key_metric_filename: set a fixed filename to set the best metric model, if not None,\n            `key_metric_n_saved` should be 1 and only keep the best metric model.\n        epoch_level: save checkpoint during training for every N epochs or every N iterations.\n            `True` is epoch level, `False` is iteration level.\n        save_interval: save checkpoint every N epochs, default is 0 to save no checkpoint.\n        n_saved: save latest N checkpoints of epoch level or iteration level, 'None' is to save all.\n\n    Note:\n        CheckpointHandler can be used during training, validation or evaluation.\n        example of saved files:\n\n            - checkpoint_iteration=400.pt\n            - checkpoint_iteration=800.pt\n            - checkpoint_epoch=1.pt\n            - checkpoint_final_iteration=1000.pt\n            - checkpoint_key_metric=0.9387.pt\n\n    \"\"\"\n\n    def __init__(\n        self,\n        save_dir: str,\n        save_dict: Dict,\n        name: Optional[str] = None,\n        file_prefix: str = \"\",\n        save_final: bool = False,\n        final_filename: Optional[str] = None,\n        save_key_metric: bool = False,\n        key_metric_name: Optional[str] = None,\n        key_metric_n_saved: int = 1,\n        key_metric_filename: Optional[str] = None,\n        epoch_level: bool = True,\n        save_interval: int = 0,\n        n_saved: Optional[int] = None,\n    ) -> None:\n        assert save_dir is not None, \"must provide directory to save the checkpoints.\"\n        self.save_dir = save_dir\n        assert save_dict is not None and len(save_dict) > 0, \"must provide source objects to save.\"\n        self.save_dict = save_dict\n        self.logger = logging.getLogger(name)\n        self.epoch_level = epoch_level\n        self.save_interval = save_interval\n        self._final_checkpoint = self._key_metric_checkpoint = self._interval_checkpoint = None\n        self._name = name\n\n        class _DiskSaver(DiskSaver):\n            \"\"\"\n            Enhance the DiskSaver to support fixed filename.\n\n            \"\"\"\n\n            def __init__(self, dirname: str, filename: Optional[str] = None):\n                super().__init__(dirname=dirname, require_empty=False)\n                self.filename = filename\n\n            def __call__(self, checkpoint: Dict, filename: str, metadata: Optional[Dict] = None) -> None:\n                if self.filename is not None:\n                    filename = self.filename\n                super().__call__(checkpoint=checkpoint, filename=filename, metadata=metadata)\n\n            def remove(self, filename: str) -> None:\n                if self.filename is not None:\n                    filename = self.filename\n                super().remove(filename=filename)\n\n        if save_final:\n\n            def _final_func(engine: Engine):\n                return engine.state.iteration\n\n            self._final_checkpoint = Checkpoint(\n                to_save=self.save_dict,\n                save_handler=_DiskSaver(dirname=self.save_dir, filename=final_filename),\n                filename_prefix=file_prefix,\n                score_function=_final_func,\n                score_name=\"final_iteration\",\n            )\n\n        if save_key_metric:\n\n            def _score_func(engine: Engine):\n                if isinstance(key_metric_name, str):\n                    metric_name = key_metric_name\n                elif hasattr(engine.state, \"key_metric_name\") and isinstance(engine.state.key_metric_name, str):\n                    metric_name = engine.state.key_metric_name\n                else:\n                    raise ValueError(\n                        f\"Incompatible values: save_key_metric=True and key_metric_name={key_metric_name}.\"\n                    )\n                return round(engine.state.metrics[metric_name], 4)\n\n            if key_metric_filename is not None and key_metric_n_saved > 1:\n                raise ValueError(\"if using fixed filename to save the best metric model, we should only save 1 model.\")\n\n            self._key_metric_checkpoint = Checkpoint(\n                to_save=self.save_dict,\n                save_handler=_DiskSaver(dirname=self.save_dir, filename=key_metric_filename),\n                filename_prefix=file_prefix,\n                score_function=_score_func,\n                score_name=\"key_metric\",\n                n_saved=key_metric_n_saved,\n            )\n\n        if save_interval > 0:\n\n            def _interval_func(engine: Engine):\n                return engine.state.epoch if self.epoch_level else engine.state.iteration\n\n            self._interval_checkpoint = Checkpoint(\n                to_save=self.save_dict,\n                save_handler=_DiskSaver(dirname=self.save_dir),\n                filename_prefix=file_prefix,\n                score_function=_interval_func,\n                score_name=\"epoch\" if self.epoch_level else \"iteration\",\n                n_saved=n_saved,\n            )\n\n    def attach(self, engine: Engine) -> None:\n        \"\"\"\n        Args:\n            engine: Ignite Engine, it can be a trainer, validator or evaluator.\n        \"\"\"\n        if self._name is None:\n            self.logger = engine.logger\n        if self._final_checkpoint is not None:\n            engine.add_event_handler(Events.COMPLETED, self.completed)\n            engine.add_event_handler(Events.EXCEPTION_RAISED, self.exception_raised)\n        if self._key_metric_checkpoint is not None:\n            engine.add_event_handler(Events.EPOCH_COMPLETED, self.metrics_completed)\n        if self._interval_checkpoint is not None:\n            if self.epoch_level:\n                engine.add_event_handler(Events.EPOCH_COMPLETED(every=self.save_interval), self.interval_completed)\n            else:\n                engine.add_event_handler(Events.ITERATION_COMPLETED(every=self.save_interval), self.interval_completed)\n\n    def completed(self, engine: Engine) -> None:\n        \"\"\"Callback for train or validation/evaluation completed Event.\n        Save final checkpoint if configure save_final is True.\n\n        Args:\n            engine: Ignite Engine, it can be a trainer, validator or evaluator.\n        \"\"\"\n        assert callable(self._final_checkpoint), \"Error: _final_checkpoint function not specified.\"\n        self._final_checkpoint(engine)\n        assert self.logger is not None\n        assert hasattr(self.logger, \"info\"), \"Error, provided logger has not info attribute.\"\n        self.logger.info(f\"Train completed, saved final checkpoint: {self._final_checkpoint.last_checkpoint}\")\n\n    def exception_raised(self, engine: Engine, e: Exception) -> None:\n        \"\"\"Callback for train or validation/evaluation exception raised Event.\n        Save current data as final checkpoint if configure save_final is True. This callback may be skipped\n        because the logic with Ignite can only trigger the first attached handler for `EXCEPTION_RAISED` event.\n\n        Args:\n            engine: Ignite Engine, it can be a trainer, validator or evaluator.\n            e: the exception caught in Ignite during engine.run().\n        \"\"\"\n        assert callable(self._final_checkpoint), \"Error: _final_checkpoint function not specified.\"\n        self._final_checkpoint(engine)\n        assert self.logger is not None\n        assert hasattr(self.logger, \"info\"), \"Error, provided logger has not info attribute.\"\n        self.logger.info(f\"Exception_raised, saved exception checkpoint: {self._final_checkpoint.last_checkpoint}\")\n        raise e\n\n    def metrics_completed(self, engine: Engine) -> None:\n        \"\"\"Callback to compare metrics and save models in train or validation when epoch completed.\n\n        Args:\n            engine: Ignite Engine, it can be a trainer, validator or evaluator.\n        \"\"\"\n        assert callable(self._key_metric_checkpoint), \"Error: _key_metric_checkpoint function not specified.\"\n        self._key_metric_checkpoint(engine)\n\n    def interval_completed(self, engine: Engine) -> None:\n        \"\"\"Callback for train epoch/iteration completed Event.\n        Save checkpoint if configure save_interval = N\n\n        Args:\n            engine: Ignite Engine, it can be a trainer, validator or evaluator.\n        \"\"\"\n        assert callable(self._interval_checkpoint), \"Error: _interval_checkpoint function not specified.\"\n        self._interval_checkpoint(engine)\n        assert self.logger is not None\n        assert hasattr(self.logger, \"info\"), \"Error, provided logger has not info attribute.\"\n        if self.epoch_level:\n            self.logger.info(f\"Saved checkpoint at epoch: {engine.state.epoch}\")\n        else:\n            self.logger.info(f\"Saved checkpoint at iteration: {engine.state.iteration}\")\n", "path": "monai/handlers/checkpoint_saver.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\nfrom typing import TYPE_CHECKING, Dict, Optional\n\nfrom monai.utils import exact_version, optional_import\n\nEvents, _ = optional_import(\"ignite.engine\", \"0.4.2\", exact_version, \"Events\")\nCheckpoint, _ = optional_import(\"ignite.handlers\", \"0.4.2\", exact_version, \"Checkpoint\")\nBaseSaveHandler, _ = optional_import(\"ignite.handlers.checkpoint\", \"0.4.2\", exact_version, \"BaseSaveHandler\")\n\nif TYPE_CHECKING:\n    from ignite.engine import Engine\n    from ignite.handlers import DiskSaver\nelse:\n    Engine, _ = optional_import(\"ignite.engine\", \"0.4.2\", exact_version, \"Engine\")\n    DiskSaver, _ = optional_import(\"ignite.handlers\", \"0.4.2\", exact_version, \"DiskSaver\")\n\n\nclass CheckpointSaver:\n    \"\"\"\n    CheckpointSaver acts as an Ignite handler to save checkpoint data into files.\n    It supports to save according to metrics result, epoch number, iteration number\n    and last model or exception.\n\n    Args:\n        save_dir: the target directory to save the checkpoints.\n        save_dict: source objects that save to the checkpoint. examples::\n\n            {'network': net, 'optimizer': optimizer, 'lr_scheduler': lr_scheduler}\n\n        name: identifier of logging.logger to use, if None, defaulting to ``engine.logger``.\n        file_prefix: prefix for the filenames to which objects will be saved.\n        save_final: whether to save checkpoint or session at final iteration or exception.\n            If checkpoints are to be saved when an exception is raised, put this handler before\n            `StatsHandler` in the handler list, because the logic with Ignite can only trigger\n            the first attached handler for `EXCEPTION_RAISED` event.\n        final_filename: set a fixed filename to save the final model if `save_final=True`.\n            If None, default to `checkpoint_final_iteration=N.pt`.\n        save_key_metric: whether to save checkpoint or session when the value of key_metric is\n            higher than all the previous values during training.keep 4 decimal places of metric,\n            checkpoint name is: {file_prefix}_key_metric=0.XXXX.pth.\n        key_metric_name: the name of key_metric in ignite metrics dictionary.\n            If None, use `engine.state.key_metric` instead.\n        key_metric_n_saved: save top N checkpoints or sessions, sorted by the value of key\n            metric in descending order.\n        key_metric_filename: set a fixed filename to set the best metric model, if not None,\n            `key_metric_n_saved` should be 1 and only keep the best metric model.\n        epoch_level: save checkpoint during training for every N epochs or every N iterations.\n            `True` is epoch level, `False` is iteration level.\n        save_interval: save checkpoint every N epochs, default is 0 to save no checkpoint.\n        n_saved: save latest N checkpoints of epoch level or iteration level, 'None' is to save all.\n\n    Note:\n        CheckpointHandler can be used during training, validation or evaluation.\n        example of saved files:\n\n            - checkpoint_iteration=400.pt\n            - checkpoint_iteration=800.pt\n            - checkpoint_epoch=1.pt\n            - checkpoint_final_iteration=1000.pt\n            - checkpoint_key_metric=0.9387.pt\n\n    \"\"\"\n\n    def __init__(\n        self,\n        save_dir: str,\n        save_dict: Dict,\n        name: Optional[str] = None,\n        file_prefix: str = \"\",\n        save_final: bool = False,\n        final_filename: Optional[str] = None,\n        save_key_metric: bool = False,\n        key_metric_name: Optional[str] = None,\n        key_metric_n_saved: int = 1,\n        key_metric_filename: Optional[str] = None,\n        epoch_level: bool = True,\n        save_interval: int = 0,\n        n_saved: Optional[int] = None,\n    ) -> None:\n        assert save_dir is not None, \"must provide directory to save the checkpoints.\"\n        self.save_dir = save_dir\n        assert save_dict is not None and len(save_dict) > 0, \"must provide source objects to save.\"\n        self.save_dict = save_dict\n        self.logger = logging.getLogger(name)\n        self.epoch_level = epoch_level\n        self.save_interval = save_interval\n        self._final_checkpoint = self._key_metric_checkpoint = self._interval_checkpoint = None\n        self._name = name\n\n        class _DiskSaver(DiskSaver):\n            \"\"\"\n            Enhance the DiskSaver to support fixed filename.\n\n            \"\"\"\n\n            def __init__(self, dirname: str, filename: Optional[str] = None):\n                super().__init__(dirname=dirname, require_empty=False)\n                self.filename = filename\n\n            def __call__(self, checkpoint: Dict, filename: str, metadata: Optional[Dict] = None) -> None:\n                if self.filename is not None:\n                    filename = self.filename\n                super().__call__(checkpoint=checkpoint, filename=filename, metadata=metadata)\n\n            def remove(self, filename: str) -> None:\n                if self.filename is not None:\n                    filename = self.filename\n                super().remove(filename=filename)\n\n        if save_final:\n\n            def _final_func(engine: Engine):\n                return engine.state.iteration\n\n            self._final_checkpoint = Checkpoint(\n                to_save=self.save_dict,\n                save_handler=_DiskSaver(dirname=self.save_dir, filename=final_filename),\n                filename_prefix=file_prefix,\n                score_function=_final_func,\n                score_name=\"final_iteration\",\n            )\n\n        if save_key_metric:\n\n            def _score_func(engine: Engine):\n                if isinstance(key_metric_name, str):\n                    metric_name = key_metric_name\n                elif hasattr(engine.state, \"key_metric_name\") and isinstance(engine.state.key_metric_name, str):\n                    metric_name = engine.state.key_metric_name\n                else:\n                    raise ValueError(\n                        f\"Incompatible values: save_key_metric=True and key_metric_name={key_metric_name}.\"\n                    )\n                return round(engine.state.metrics[metric_name], 4)\n\n            if key_metric_filename is not None and key_metric_n_saved > 1:\n                raise ValueError(\"if using fixed filename to save the best metric model, we should only save 1 model.\")\n\n            self._key_metric_checkpoint = Checkpoint(\n                to_save=self.save_dict,\n                save_handler=_DiskSaver(dirname=self.save_dir, filename=key_metric_filename),\n                filename_prefix=file_prefix,\n                score_function=_score_func,\n                score_name=\"key_metric\",\n                n_saved=key_metric_n_saved,\n            )\n\n        if save_interval > 0:\n\n            def _interval_func(engine: Engine):\n                return engine.state.epoch if self.epoch_level else engine.state.iteration\n\n            self._interval_checkpoint = Checkpoint(\n                to_save=self.save_dict,\n                save_handler=_DiskSaver(dirname=self.save_dir),\n                filename_prefix=file_prefix,\n                score_function=_interval_func,\n                score_name=\"epoch\" if self.epoch_level else \"iteration\",\n                n_saved=n_saved,\n            )\n\n    def attach(self, engine: Engine) -> None:\n        \"\"\"\n        Args:\n            engine: Ignite Engine, it can be a trainer, validator or evaluator.\n        \"\"\"\n        if self._name is None:\n            self.logger = engine.logger\n        if self._final_checkpoint is not None:\n            engine.add_event_handler(Events.COMPLETED, self.completed)\n            engine.add_event_handler(Events.EXCEPTION_RAISED, self.exception_raised)\n        if self._key_metric_checkpoint is not None:\n            engine.add_event_handler(Events.EPOCH_COMPLETED, self.metrics_completed)\n        if self._interval_checkpoint is not None:\n            if self.epoch_level:\n                engine.add_event_handler(Events.EPOCH_COMPLETED(every=self.save_interval), self.interval_completed)\n            else:\n                engine.add_event_handler(Events.ITERATION_COMPLETED(every=self.save_interval), self.interval_completed)\n\n    def _delete_previous_final_ckpt(self):\n        saved = self._final_checkpoint._saved\n        if len(saved) > 0:\n            item = saved.pop(0)\n            self._final_checkpoint.save_handler.remove(item.filename)\n            self.logger.info(f\"Deleted previous saved final checkpoint: {item.filename}\")\n\n    def completed(self, engine: Engine) -> None:\n        \"\"\"Callback for train or validation/evaluation completed Event.\n        Save final checkpoint if configure save_final is True.\n\n        Args:\n            engine: Ignite Engine, it can be a trainer, validator or evaluator.\n        \"\"\"\n        assert callable(self._final_checkpoint), \"Error: _final_checkpoint function not specified.\"\n        # delete previous saved final checkpoint if existing\n        self._delete_previous_final_ckpt()\n        self._final_checkpoint(engine)\n        assert self.logger is not None\n        assert hasattr(self.logger, \"info\"), \"Error, provided logger has not info attribute.\"\n        self.logger.info(f\"Train completed, saved final checkpoint: {self._final_checkpoint.last_checkpoint}\")\n\n    def exception_raised(self, engine: Engine, e: Exception) -> None:\n        \"\"\"Callback for train or validation/evaluation exception raised Event.\n        Save current data as final checkpoint if configure save_final is True. This callback may be skipped\n        because the logic with Ignite can only trigger the first attached handler for `EXCEPTION_RAISED` event.\n\n        Args:\n            engine: Ignite Engine, it can be a trainer, validator or evaluator.\n            e: the exception caught in Ignite during engine.run().\n        \"\"\"\n        assert callable(self._final_checkpoint), \"Error: _final_checkpoint function not specified.\"\n        # delete previous saved final checkpoint if existing\n        self._delete_previous_final_ckpt()\n        self._final_checkpoint(engine)\n        assert self.logger is not None\n        assert hasattr(self.logger, \"info\"), \"Error, provided logger has not info attribute.\"\n        self.logger.info(f\"Exception_raised, saved exception checkpoint: {self._final_checkpoint.last_checkpoint}\")\n        raise e\n\n    def metrics_completed(self, engine: Engine) -> None:\n        \"\"\"Callback to compare metrics and save models in train or validation when epoch completed.\n\n        Args:\n            engine: Ignite Engine, it can be a trainer, validator or evaluator.\n        \"\"\"\n        assert callable(self._key_metric_checkpoint), \"Error: _key_metric_checkpoint function not specified.\"\n        self._key_metric_checkpoint(engine)\n\n    def interval_completed(self, engine: Engine) -> None:\n        \"\"\"Callback for train epoch/iteration completed Event.\n        Save checkpoint if configure save_interval = N\n\n        Args:\n            engine: Ignite Engine, it can be a trainer, validator or evaluator.\n        \"\"\"\n        assert callable(self._interval_checkpoint), \"Error: _interval_checkpoint function not specified.\"\n        self._interval_checkpoint(engine)\n        assert self.logger is not None\n        assert hasattr(self.logger, \"info\"), \"Error, provided logger has not info attribute.\"\n        if self.epoch_level:\n            self.logger.info(f\"Saved checkpoint at epoch: {engine.state.epoch}\")\n        else:\n            self.logger.info(f\"Saved checkpoint at iteration: {engine.state.iteration}\")\n", "path": "monai/handlers/checkpoint_saver.py"}]}