Source code for sconce.monitors.base

from abc import ABC, abstractmethod
from torch import Tensor


[docs]class Monitor(ABC): """ Base class for monitors in sconce. A monitor is an object that a :py:class:`~sconce.trainer.Trainer` uses to record metrics during training or other tasks. This base class defines the interface that trainers use. Monitors can be composed together (using addition operator) to produce a :py:class:`~sconce.monitors.base.CompositeMonitor` object. Arguments: name (str): used to gain access to a monitor when it has been composed together into a :py:class:`~sconce.monitors.base.CompositeMonitor`. """ def __init__(self, name): self.name = name def _to_scalar(self, value): if isinstance(value, Tensor): try: return value.item() except ValueError: return value.data[0] else: return value
[docs] def start_session(self, num_steps, **kwargs): """ Called by a :py:class:`~sconce.trainer.Trainer` when starting a training/evaluation session. Arguments: num_steps (int): [1, inf) the number of update/evaluation steps to expect. **kwargs: must be accepted to allow for future use cases. """ pass
[docs] def end_session(self, **kwargs): """ Called by a :py:class:`~sconce.trainer.Trainer` when a training/evaluation session has ended. Arguments: **kwargs: must be accepted to allow for future use cases. """ pass
[docs] @abstractmethod def write(self, data, step, **kwargs): """ Called by a :py:class:`~sconce.trainer.Trainer` during a training/evaluation session just after the training/evaluation step. Arguments: data (dict): the output of the training/evaluation step. The keys may include, but are not limited to: {'training_loss', 'test_loss', 'learning_rate'}. step (float): (0.0, inf) the step that was just completed. Fractional steps are possible (see batch_multiplier option on :py:meth:`sconce.trainer.Trainer.train`). **kwargs: must be accepted to allow for future use cases. """ pass
def __add__(self, other): return CompositeMonitor(monitors=[self, other])
[docs]class CompositeMonitor(Monitor): """ A monitor composed of two or more monitors. Using this allows you to pass a single monitor object to a trainer method and have it use all of the composed monitors. Composed monitors can be accessed using their name like so: >>> from sconce import monitors >>> metric_names = {'training_loss': 'loss', 'test_loss': 'val_loss'} >>> stdout_monitor = monitors.StdoutMonitor(metric_names=metric_names) >>> dataframe_monitor = monitors.DataframeMonitor() >>> monitor = dataframe_monitor + stdout_monitor >>> monitor.dataframe_monitor <sconce.monitors.dataframe_monitor.DataframeMonitor at 0x7fb1fbd498d0> >>> dataframe_monitor is monitor.dataframe_monitor True Arguments: monitors (iterable of :py:class:`~sconce.monitors.base.Monitor`): the monitors you want to compose together. """ def __init__(self, monitors): super().__init__(name=None) self.monitors = [] for monitor in monitors: self.add_monitor(monitor)
[docs] def add_monitor(self, other): if isinstance(other, CompositeMonitor): for nested_monitor in other.monitors: self._add_monitor(nested_monitor) else: self._add_monitor(other)
def _add_monitor(self, other): if hasattr(self, other.name): raise RuntimeError("A monitor with the name " f"'{other.name}' cannot be added to this " "CompositeMonitor. Have you already added it?") else: self.monitors.append(other) setattr(self, other.name, other)
[docs] def start_session(self, num_steps, **kwargs): for monitor in self.monitors: monitor.start_session(num_steps, **kwargs)
[docs] def end_session(self, **kwargs): for monitor in self.monitors: monitor.end_session(**kwargs)
[docs] def write(self, data, step, **kwargs): for monitor in self.monitors: monitor.write(data, step, **kwargs)