## @package experiment_util # Module caffe2.python.experiment_util import datetime import time import logging import socket import abc from collections import OrderedDict from future.utils import viewkeys, viewvalues ''' Utilities for logging experiment run stats, such as accuracy and loss over time for different runs. Runtime arguments are stored in the log. Optionally, ModelTrainerLog calls out to a logger to log to an external log destination. ''' class ExternalLogger(object): __metaclass__ = abc.ABCMeta @abc.abstractmethod def set_runtime_args(self, runtime_args): """ Set runtime arguments for the logger. runtime_args: dict of runtime arguments. """ raise NotImplementedError( 'Must define set_runtime_args function to use this base class' ) @abc.abstractmethod def log(self, log_dict): """ log a dict of key/values to an external destination log_dict: input dict """ raise NotImplementedError( 'Must define log function to use this base class' ) class ModelTrainerLog(): def __init__(self, expname, runtime_args, external_loggers=None): now = datetime.datetime.fromtimestamp(time.time()) self.experiment_id = \ "{}_{}".format(expname, now.strftime('%Y%m%d_%H%M%S')) self.filename = "{}.log".format(self.experiment_id) self.logstr("# %s" % str(runtime_args)) self.headers = None self.start_time = time.time() self.last_time = self.start_time self.last_input_count = 0 self.external_loggers = None if external_loggers is not None: self.external_loggers = external_loggers if not isinstance(runtime_args, dict): runtime_args = dict(vars(runtime_args)) runtime_args['experiment_id'] = self.experiment_id runtime_args['hostname'] = socket.gethostname() for logger in self.external_loggers: logger.set_runtime_args(runtime_args) else: self.external_loggers = [] def logstr(self, str): with open(self.filename, "a") as f: f.write(str + "\n") f.close() logging.getLogger("experiment_logger").info(str) def log(self, input_count, batch_count, additional_values): logdict = OrderedDict() delta_t = time.time() - self.last_time delta_count = input_count - self.last_input_count self.last_time = time.time() self.last_input_count = input_count logdict['time_spent'] = delta_t logdict['cumulative_time_spent'] = time.time() - self.start_time logdict['input_count'] = delta_count logdict['cumulative_input_count'] = input_count logdict['cumulative_batch_count'] = batch_count if delta_t > 0: logdict['inputs_per_sec'] = delta_count / delta_t else: logdict['inputs_per_sec'] = 0.0 for k in sorted(viewkeys(additional_values)): logdict[k] = additional_values[k] # Write the headers if they are not written yet if self.headers is None: self.headers = list(viewkeys(logdict)) self.logstr(",".join(self.headers)) self.logstr(",".join(str(v) for v in viewvalues(logdict))) for logger in self.external_loggers: try: logger.log(logdict) except Exception as e: logging.warning( "Failed to call ExternalLogger: {}".format(e), e)