-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'feature-wandb-integration' into features-sfluegel
# Conflicts: # chebai/preprocessing/reader.py # chebai/trainer/InnerCVTrainer.py
- Loading branch information
Showing
14 changed files
with
435 additions
and
221 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
from lightning.pytorch.callbacks.model_checkpoint import ModelCheckpoint | ||
from lightning.fabric.utilities.types import _PATH | ||
from lightning.pytorch.loggers import WandbLogger | ||
from lightning.pytorch import Trainer, LightningModule | ||
import os | ||
from lightning.fabric.utilities.cloud_io import _is_dir | ||
from lightning.pytorch.utilities.rank_zero import rank_zero_info | ||
|
||
class CustomModelCheckpoint(ModelCheckpoint): | ||
"""Checkpoint class that resolves checkpoint paths s.t. for the CustomLogger, checkpoints get saved to the | ||
same directory as the other logs""" | ||
|
||
def setup(self, trainer: "Trainer", pl_module: "LightningModule", stage: str) -> None: | ||
"""Same as in parent class, duplicated to be able to call self.__resolve_ckpt_dir""" | ||
if self.dirpath is not None: | ||
self.dirpath = None | ||
dirpath = self.__resolve_ckpt_dir(trainer) | ||
dirpath = trainer.strategy.broadcast(dirpath) | ||
self.dirpath = dirpath | ||
if trainer.is_global_zero and stage == "fit": | ||
self.__warn_if_dir_not_empty(self.dirpath) | ||
|
||
def __warn_if_dir_not_empty(self, dirpath: _PATH) -> None: | ||
"""Same as in parent class, duplicated because method in parent class is not accessible""" | ||
if self.save_top_k != 0 and _is_dir(self._fs, dirpath, strict=True) and len(self._fs.ls(dirpath)) > 0: | ||
rank_zero_warn(f"Checkpoint directory {dirpath} exists and is not empty.") | ||
|
||
def __resolve_ckpt_dir(self, trainer: "Trainer") -> _PATH: | ||
"""Determines model checkpoint save directory at runtime. Reference attributes from the trainer's logger to | ||
determine where to save checkpoints. The path for saving weights is set in this priority: | ||
1. The ``ModelCheckpoint``'s ``dirpath`` if passed in | ||
2. The ``Logger``'s ``log_dir`` if the trainer has loggers | ||
3. The ``Trainer``'s ``default_root_dir`` if the trainer has no loggers | ||
The path gets extended with subdirectory "checkpoints". | ||
""" | ||
print(f'Resolving checkpoint dir (custom)') | ||
if self.dirpath is not None: | ||
# short circuit if dirpath was passed to ModelCheckpoint | ||
return self.dirpath | ||
if len(trainer.loggers) > 0: | ||
if trainer.loggers[0].save_dir is not None: | ||
save_dir = trainer.loggers[0].save_dir | ||
else: | ||
save_dir = trainer.default_root_dir | ||
name = trainer.loggers[0].name | ||
version = trainer.loggers[0].version | ||
version = version if isinstance(version, str) else f"version_{version}" | ||
logger = trainer.loggers[0] | ||
if isinstance(logger, WandbLogger): | ||
ckpt_path = os.path.join(logger.experiment.dir, "checkpoints") | ||
else: | ||
ckpt_path = os.path.join(save_dir, str(name), version, "checkpoints") | ||
else: | ||
# if no loggers, use default_root_dir | ||
ckpt_path = os.path.join(trainer.default_root_dir, "checkpoints") | ||
|
||
print(f'Now using checkpoint path {ckpt_path}') | ||
return ckpt_path |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
from datetime import datetime | ||
from typing import Optional, Union, Literal | ||
|
||
import wandb | ||
from lightning.fabric.utilities.types import _PATH | ||
from lightning.pytorch.loggers import WandbLogger | ||
import os | ||
|
||
|
||
class CustomLogger(WandbLogger): | ||
"""Adds support for custom naming of runs and cross-validation""" | ||
|
||
def __init__(self, save_dir: _PATH, name: str = "logs", version: Optional[Union[int, str]] = None, prefix: str = "", | ||
fold: Optional[int] = None, project: Optional[str] = None, entity: Optional[str] = None, | ||
offline: bool = False, | ||
log_model: Union[Literal["all"], bool] = False, **kwargs): | ||
if version is None: | ||
version = f'{datetime.now():%y%m%d-%H%M}' | ||
self._version = version | ||
self._name = name | ||
self._fold = fold | ||
super().__init__(name=self.name, save_dir=save_dir, version=None, prefix=prefix, | ||
log_model=log_model, entity=entity, project=project, offline=offline, **kwargs) | ||
|
||
@property | ||
def name(self) -> Optional[str]: | ||
name = f'{self._name}_{self.version}' | ||
if self._fold is not None: | ||
name += f'_fold{self._fold}' | ||
return name | ||
|
||
@property | ||
def version(self) -> Optional[str]: | ||
return self._version | ||
|
||
@property | ||
def root_dir(self) -> Optional[str]: | ||
return os.path.join(self.save_dir, self.name) | ||
|
||
@property | ||
def log_dir(self) -> str: | ||
version = self.version if isinstance(self.version, str) else f"version_{self.version}" | ||
if self._fold is None: | ||
return os.path.join(self.root_dir, version) | ||
return os.path.join(self.root_dir, version, f'fold_{self._fold}') | ||
|
||
def set_fold(self, fold: int): | ||
if fold != self._fold: | ||
self._fold = fold | ||
# start new experiment | ||
wandb.finish() | ||
self._wandb_init['name'] = self.name | ||
self._name = self.name | ||
self._experiment = None | ||
_ = self.experiment | ||
|
||
@property | ||
def fold(self): | ||
return self._fold |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.