2020-02-25 19:52:39 +00:00
|
|
|
import argparse
|
|
|
|
from abc import ABC, abstractmethod
|
2019-09-27 16:05:29 +00:00
|
|
|
from functools import wraps
|
2020-02-25 19:52:39 +00:00
|
|
|
from typing import Union, Optional, Dict, Iterable, Any, Callable, List
|
2019-09-27 16:05:29 +00:00
|
|
|
|
|
|
|
|
2020-02-25 19:52:39 +00:00
|
|
|
def rank_zero_only(fn: Callable):
|
2019-12-08 00:25:12 +00:00
|
|
|
"""Decorate a logger method to run it only on the process with rank 0.
|
2019-09-27 16:05:29 +00:00
|
|
|
|
2020-02-25 19:52:39 +00:00
|
|
|
Args:
|
|
|
|
fn: Function to decorate
|
2019-09-27 16:05:29 +00:00
|
|
|
"""
|
|
|
|
|
|
|
|
@wraps(fn)
|
|
|
|
def wrapped_fn(self, *args, **kwargs):
|
|
|
|
if self.rank == 0:
|
|
|
|
fn(self, *args, **kwargs)
|
|
|
|
|
|
|
|
return wrapped_fn
|
|
|
|
|
|
|
|
|
2019-12-08 00:25:12 +00:00
|
|
|
class LightningLoggerBase(ABC):
|
|
|
|
"""Base class for experiment loggers."""
|
2019-09-27 16:05:29 +00:00
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
self._rank = 0
|
|
|
|
|
2019-12-08 00:25:12 +00:00
|
|
|
@property
|
2020-02-25 19:52:39 +00:00
|
|
|
@abstractmethod
|
|
|
|
def experiment(self) -> Any:
|
|
|
|
"""Return the experiment object associated with this logger"""
|
|
|
|
pass
|
2019-12-08 00:25:12 +00:00
|
|
|
|
2020-02-25 19:52:39 +00:00
|
|
|
@abstractmethod
|
|
|
|
def log_metrics(self, metrics: Dict[str, float], step: Optional[int] = None):
|
2019-12-04 11:57:10 +00:00
|
|
|
"""Record metrics.
|
2019-09-27 16:05:29 +00:00
|
|
|
|
2020-02-25 19:52:39 +00:00
|
|
|
Args:
|
|
|
|
metrics: Dictionary with metric names as keys and measured quantities as values
|
|
|
|
step: Step number at which the metrics should be recorded
|
2019-09-27 16:05:29 +00:00
|
|
|
"""
|
2020-02-25 19:52:39 +00:00
|
|
|
pass
|
2019-09-27 16:05:29 +00:00
|
|
|
|
2020-02-25 19:52:39 +00:00
|
|
|
@abstractmethod
|
|
|
|
def log_hyperparams(self, params: argparse.Namespace):
|
2019-12-08 00:25:12 +00:00
|
|
|
"""Record hyperparameters.
|
2019-09-27 16:05:29 +00:00
|
|
|
|
2020-02-25 19:52:39 +00:00
|
|
|
Args:
|
|
|
|
params: argparse.Namespace containing the hyperparameters
|
2019-09-27 16:05:29 +00:00
|
|
|
"""
|
2020-02-25 19:52:39 +00:00
|
|
|
pass
|
2019-09-27 16:05:29 +00:00
|
|
|
|
|
|
|
def save(self):
|
2019-12-08 00:25:12 +00:00
|
|
|
"""Save log data."""
|
2020-02-25 19:52:39 +00:00
|
|
|
pass
|
2019-09-27 16:05:29 +00:00
|
|
|
|
2020-02-25 19:52:39 +00:00
|
|
|
def finalize(self, status: str):
|
2019-12-08 00:25:12 +00:00
|
|
|
"""Do any processing that is necessary to finalize an experiment.
|
2019-09-27 16:05:29 +00:00
|
|
|
|
2020-02-25 19:52:39 +00:00
|
|
|
Args:
|
|
|
|
status: Status that the experiment finished with (e.g. success, failed, aborted)
|
2019-09-27 16:05:29 +00:00
|
|
|
"""
|
2020-02-25 19:52:39 +00:00
|
|
|
pass
|
2019-09-27 16:05:29 +00:00
|
|
|
|
|
|
|
def close(self):
|
2019-12-08 00:25:12 +00:00
|
|
|
"""Do any cleanup that is necessary to close an experiment."""
|
2020-02-25 19:52:39 +00:00
|
|
|
pass
|
2019-09-27 16:05:29 +00:00
|
|
|
|
|
|
|
@property
|
2020-02-25 19:52:39 +00:00
|
|
|
def rank(self) -> int:
|
2019-12-08 00:25:12 +00:00
|
|
|
"""Process rank. In general, metrics should only be logged by the process with rank 0."""
|
2019-09-27 16:05:29 +00:00
|
|
|
return self._rank
|
|
|
|
|
|
|
|
@rank.setter
|
2020-02-25 19:52:39 +00:00
|
|
|
def rank(self, value: int):
|
2019-12-08 00:25:12 +00:00
|
|
|
"""Set the process rank."""
|
2019-09-27 16:05:29 +00:00
|
|
|
self._rank = value
|
|
|
|
|
2019-11-05 15:41:59 +00:00
|
|
|
@property
|
2020-02-25 19:52:39 +00:00
|
|
|
@abstractmethod
|
|
|
|
def name(self) -> str:
|
2019-12-08 00:25:12 +00:00
|
|
|
"""Return the experiment name."""
|
2020-02-25 19:52:39 +00:00
|
|
|
pass
|
2019-11-05 15:41:59 +00:00
|
|
|
|
2019-09-27 16:05:29 +00:00
|
|
|
@property
|
2020-02-25 19:52:39 +00:00
|
|
|
@abstractmethod
|
|
|
|
def version(self) -> Union[int, str]:
|
2019-12-08 00:25:12 +00:00
|
|
|
"""Return the experiment version."""
|
2020-02-25 19:52:39 +00:00
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
class LoggerCollection(LightningLoggerBase):
|
|
|
|
"""The `LoggerCollection` class is used to iterate all logging actions over the given `logger_iterable`.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
logger_iterable: An iterable collection of loggers
|
|
|
|
"""
|
|
|
|
|
|
|
|
def __init__(self, logger_iterable: Iterable[LightningLoggerBase]):
|
|
|
|
super().__init__()
|
|
|
|
self._logger_iterable = logger_iterable
|
|
|
|
|
|
|
|
@property
|
|
|
|
def experiment(self) -> List[Any]:
|
|
|
|
return [logger.experiment() for logger in self._logger_iterable]
|
|
|
|
|
|
|
|
def log_metrics(self, metrics: Dict[str, float], step: Optional[int] = None):
|
|
|
|
[logger.log_metrics(metrics, step) for logger in self._logger_iterable]
|
|
|
|
|
|
|
|
def log_hyperparams(self, params: argparse.Namespace):
|
|
|
|
[logger.log_hyperparams(params) for logger in self._logger_iterable]
|
|
|
|
|
|
|
|
def save(self):
|
|
|
|
[logger.save() for logger in self._logger_iterable]
|
|
|
|
|
|
|
|
def finalize(self, status: str):
|
|
|
|
[logger.finalize(status) for logger in self._logger_iterable]
|
|
|
|
|
|
|
|
def close(self):
|
|
|
|
[logger.close() for logger in self._logger_iterable]
|
|
|
|
|
|
|
|
@property
|
|
|
|
def rank(self) -> int:
|
|
|
|
return self._rank
|
|
|
|
|
|
|
|
@rank.setter
|
|
|
|
def rank(self, value: int):
|
|
|
|
self._rank = value
|
|
|
|
for logger in self._logger_iterable:
|
|
|
|
logger.rank = value
|
|
|
|
|
|
|
|
@property
|
|
|
|
def name(self) -> str:
|
|
|
|
return '_'.join([str(logger.name) for logger in self._logger_iterable])
|
|
|
|
|
|
|
|
@property
|
|
|
|
def version(self) -> str:
|
|
|
|
return '_'.join([str(logger.version) for logger in self._logger_iterable])
|