Repository: Project-MONAI/MONAI

Issue:
CheckpointSaver logs wrong filenames when final_filename is set; doesnt log saving of key metric checkpoint
**Describe the bug**
When final_filename is set during CheckpointSaver creation it still uses the default name for logging. The correct (the set name) is used for saving. If save key metric is set, the saving of best metric Checkpoint is not logged at all

**To Reproduce**
Steps to reproduce the behavior:
1. Create CheckpointSaver and set final_filename, save_key_metric etc. (see screenshot)
2. Run CheckpointSaver until Checkpoint is saved and look at logged output

**Expected behavior**
Use correct filename for saved final checkpoint and log saving/deletion of best metric checkpoint

**Screenshots**
![image](https://user-images.githubusercontent.com/65398308/219693518-b52ec820-7837-4abc-8d2d-eb438dfb7c8b.png)
![image](https://user-images.githubusercontent.com/65398308/219693416-441c6693-bd8b-404e-b68e-d38c2106cec3.png)

**Environment**

================================
Printing MONAI config...
================================
MONAI version: 1.1.0
Numpy version: 1.24.2
Pytorch version: 1.13.1+cu117
MONAI flags: HAS_EXT = False, USE_COMPILED = False, USE_META_DICT = False
MONAI rev id: a2ec3752f54bfc3b40e7952234fbeb5452ed63e3
MONAI __file__: C:\Users\jakob\miniconda3\envs\sr3915\lib\site-packages\monai\__init__.py

Optional dependencies:
Pytorch Ignite version: 0.4.10
Nibabel version: 5.0.0
scikit-image version: 0.19.3
Pillow version: 9.4.0
Tensorboard version: NOT INSTALLED or UNKNOWN VERSION.
gdown version: NOT INSTALLED or UNKNOWN VERSION.
TorchVision version: 0.14.1+cu117
tqdm version: 4.64.1
lmdb version: NOT INSTALLED or UNKNOWN VERSION.
psutil version: 5.9.4
pandas version: 1.5.3
einops version: NOT INSTALLED or UNKNOWN VERSION.
transformers version: 4.26.0
mlflow version: NOT INSTALLED or UNKNOWN VERSION.
pynrrd 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


================================
Printing system config...
================================
System: Windows
Win32 version: ('10', '10.0.19045', 'SP0', 'Multiprocessor Free')
Win32 edition: Core
Platform: Windows-10-10.0.19045-SP0
Processor: Intel64 Family 6 Model 94 Stepping 3, GenuineIntel
Machine: AMD64
Python version: 3.9.15
Process name: python.exe
Command: ['C:\\Users\\jakob\\miniconda3\\envs\\sr3915\\python.exe', '-c', 'import monai; monai.config.print_debug_info()']
Open files: [popenfile(path='C:\\Program Files\\WindowsApps\\Microsoft.LanguageExperiencePackde-DE_19041.56.184.0_neutral__8wekyb3d8bbwe\\Windows\\System32\\de-DE\\tzres.dll.mui', fd=-1), popenfile(path='C:\\Program Files\\WindowsApps\\Microsoft.LanguageExperiencePackde-DE_19041.56.184.0_neutral__8wekyb3d8bbwe\\Windows\\System32\\de-DE\\kernel32.dll.mui', fd=-1), popenfile(path='C:\\Program Files\\WindowsApps\\Microsoft.LanguageExperiencePackde-DE_19041.56.184.0_neutral__8wekyb3d8bbwe\\Windows\\System32\\de-DE\\KernelBase.dll.mui', fd=-1)]
Num physical CPUs: 4
Num logical CPUs: 8
Num usable CPUs: 8
CPU usage (%): [8.1, 1.3, 8.5, 2.1, 4.3, 1.7, 4.3, 78.2]
CPU freq. (MHz): 4001
Load avg. in last 1, 5, 15 mins (%): [0.0, 0.0, 0.0]
Disk usage (%): 81.0
Avg. sensor temp. (Celsius): UNKNOWN for given OS
Total physical memory (GB): 16.0
Available memory (GB): 6.9
Used memory (GB): 9.0

================================
Printing GPU config...
================================
Num GPUs: 1
Has CUDA: True
CUDA version: 11.7
cuDNN enabled: True
cuDNN version: 8500
Current device: 0
Library compiled for CUDA architectures: ['sm_37', 'sm_50', 'sm_60', 'sm_61', 'sm_70', 'sm_75', 'sm_80', 'sm_86', 'compute_37']
GPU 0 Name: NVIDIA GeForce GTX 1060 6GB
GPU 0 Is integrated: False
GPU 0 Is multi GPU board: False
GPU 0 Multi processor count: 10
GPU 0 Total memory (GB): 6.0
GPU 0 CUDA capability (maj.min): 6.1



CheckpointSaver logs wrong filenames when final_filename is set; doesnt log saving of key metric checkpoint
**Describe the bug**
When final_filename is set during CheckpointSaver creation it still uses the default name for logging. The correct (the set name) is used for saving. If save key metric is set, the saving of best metric Checkpoint is not logged at all

**To Reproduce**
Steps to reproduce the behavior:
1. Create CheckpointSaver and set final_filename, save_key_metric etc. (see screenshot)
2. Run CheckpointSaver until Checkpoint is saved and look at logged output

**Expected behavior**
Use correct filename for saved final checkpoint and log saving/deletion of best metric checkpoint

**Screenshots**
![image](https://user-images.githubusercontent.com/65398308/219693518-b52ec820-7837-4abc-8d2d-eb438dfb7c8b.png)
![image](https://user-images.githubusercontent.com/65398308/219693416-441c6693-bd8b-404e-b68e-d38c2106cec3.png)

**Environment**

================================
Printing MONAI config...
================================
MONAI version: 1.1.0
Numpy version: 1.24.2
Pytorch version: 1.13.1+cu117
MONAI flags: HAS_EXT = False, USE_COMPILED = False, USE_META_DICT = False
MONAI rev id: a2ec3752f54bfc3b40e7952234fbeb5452ed63e3
MONAI __file__: C:\Users\jakob\miniconda3\envs\sr3915\lib\site-packages\monai\__init__.py

Optional dependencies:
Pytorch Ignite version: 0.4.10
Nibabel version: 5.0.0
scikit-image version: 0.19.3
Pillow version: 9.4.0
Tensorboard version: NOT INSTALLED or UNKNOWN VERSION.
gdown version: NOT INSTALLED or UNKNOWN VERSION.
TorchVision version: 0.14.1+cu117
tqdm version: 4.64.1
lmdb version: NOT INSTALLED or UNKNOWN VERSION.
psutil version: 5.9.4
pandas version: 1.5.3
einops version: NOT INSTALLED or UNKNOWN VERSION.
transformers version: 4.26.0
mlflow version: NOT INSTALLED or UNKNOWN VERSION.
pynrrd 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


================================
Printing system config...
================================
System: Windows
Win32 version: ('10', '10.0.19045', 'SP0', 'Multiprocessor Free')
Win32 edition: Core
Platform: Windows-10-10.0.19045-SP0
Processor: Intel64 Family 6 Model 94 Stepping 3, GenuineIntel
Machine: AMD64
Python version: 3.9.15
Process name: python.exe
Command: ['C:\\Users\\jakob\\miniconda3\\envs\\sr3915\\python.exe', '-c', 'import monai; monai.config.print_debug_info()']
Open files: [popenfile(path='C:\\Program Files\\WindowsApps\\Microsoft.LanguageExperiencePackde-DE_19041.56.184.0_neutral__8wekyb3d8bbwe\\Windows\\System32\\de-DE\\tzres.dll.mui', fd=-1), popenfile(path='C:\\Program Files\\WindowsApps\\Microsoft.LanguageExperiencePackde-DE_19041.56.184.0_neutral__8wekyb3d8bbwe\\Windows\\System32\\de-DE\\kernel32.dll.mui', fd=-1), popenfile(path='C:\\Program Files\\WindowsApps\\Microsoft.LanguageExperiencePackde-DE_19041.56.184.0_neutral__8wekyb3d8bbwe\\Windows\\System32\\de-DE\\KernelBase.dll.mui', fd=-1)]
Num physical CPUs: 4
Num logical CPUs: 8
Num usable CPUs: 8
CPU usage (%): [8.1, 1.3, 8.5, 2.1, 4.3, 1.7, 4.3, 78.2]
CPU freq. (MHz): 4001
Load avg. in last 1, 5, 15 mins (%): [0.0, 0.0, 0.0]
Disk usage (%): 81.0
Avg. sensor temp. (Celsius): UNKNOWN for given OS
Total physical memory (GB): 16.0
Available memory (GB): 6.9
Used memory (GB): 9.0

================================
Printing GPU config...
================================
Num GPUs: 1
Has CUDA: True
CUDA version: 11.7
cuDNN enabled: True
cuDNN version: 8500
Current device: 0
Library compiled for CUDA architectures: ['sm_37', 'sm_50', 'sm_60', 'sm_61', 'sm_70', 'sm_75', 'sm_80', 'sm_86', 'compute_37']
GPU 0 Name: NVIDIA GeForce GTX 1060 6GB
GPU 0 Is integrated: False
GPU 0 Is multi GPU board: False
GPU 0 Multi processor count: 10
GPU 0 Total memory (GB): 6.0
GPU 0 CUDA capability (maj.min): 6.1





Discussion:

Resolving patch:
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
@@ -12,6 +12,7 @@
 from __future__ import annotations
 
 import logging
+import os
 import warnings
 from collections.abc import Mapping
 from typing import TYPE_CHECKING, Any
@@ -118,6 +119,7 @@ def __init__(
         self._key_metric_checkpoint: Checkpoint | None = None
         self._interval_checkpoint: Checkpoint | None = None
         self._name = name
+        self._final_filename = final_filename
 
         class _DiskSaver(DiskSaver):
             """
@@ -148,7 +150,7 @@ def _final_func(engine: Engine) -> Any:
 
             self._final_checkpoint = Checkpoint(
                 to_save=self.save_dict,
-                save_handler=_DiskSaver(dirname=self.save_dir, filename=final_filename),
+                save_handler=_DiskSaver(dirname=self.save_dir, filename=self._final_filename),
                 filename_prefix=file_prefix,
                 score_function=_final_func,
                 score_name="final_iteration",
@@ -271,7 +273,11 @@ def completed(self, engine: Engine) -> None:
             raise AssertionError
         if not hasattr(self.logger, "info"):
             raise AssertionError("Error, provided logger has not info attribute.")
-        self.logger.info(f"Train completed, saved final checkpoint: {self._final_checkpoint.last_checkpoint}")
+        if self._final_filename is not None:
+            _final_checkpoint_path = os.path.join(self.save_dir, self._final_filename)
+        else:
+            _final_checkpoint_path = self._final_checkpoint.last_checkpoint  # type: ignore[assignment]
+        self.logger.info(f"Train completed, saved final checkpoint: {_final_checkpoint_path}")
 
     def exception_raised(self, engine: Engine, e: Exception) -> None:
         """Callback for train or validation/evaluation exception raised Event.
@@ -291,7 +297,11 @@ def exception_raised(self, engine: Engine, e: Exception) -> None:
             raise AssertionError
         if not hasattr(self.logger, "info"):
             raise AssertionError("Error, provided logger has not info attribute.")
-        self.logger.info(f"Exception raised, saved the last checkpoint: {self._final_checkpoint.last_checkpoint}")
+        if self._final_filename is not None:
+            _final_checkpoint_path = os.path.join(self.save_dir, self._final_filename)
+        else:
+            _final_checkpoint_path = self._final_checkpoint.last_checkpoint  # type: ignore[assignment]
+        self.logger.info(f"Exception raised, saved the last checkpoint: {_final_checkpoint_path}")
         raise e
 
     def metrics_completed(self, engine: Engine) -> None:


Test patch: