def send_metric(self, channel_name, x, y=None, timestamp=None): x, y = self._get_valid_x_y(x, y) if not is_float(y): raise InvalidChannelValue(expected_type='float', actual_type=type(y).__name__) value = ChannelValue(x, dict(numeric_value=y), timestamp) self._channels_values_sender.send(channel_name, 'numeric', value)
def _get_valid_x_y(x, y): if x is None: raise NoChannelValue() if y is None: y = x x = None elif not is_float(x): raise InvalidChannelValue(expected_type='float', actual_type=type(x).__name__) return x, y
def _convert_to_api_parameters(self, raw_params): Parameter = self.backend_swagger_client.get_model('Parameter') params = [] for name, value in raw_params.items(): parameter_type = 'double' if is_float(value) else 'string' params.append( Parameter(id=str(uuid.uuid4()), name=name, parameterType=parameter_type, value=str(value))) return params
def _get_valid_x_y(x, y): """ The goal of this function is to allow user to call experiment.log_* with any of: - single parameter treated as y value - both parameters (named/unnamed) - single named y parameter If intended X-coordinate is provided, it is validated to be a float value """ if x is None and y is None: raise NoChannelValue() if x is None and y is not None: return None, y if x is not None and y is None: return None, x if x is not None and y is not None: if not is_float(x): raise InvalidChannelValue(expected_type='float', actual_type=type(x).__name__) return x, y
def log_metric(self, log_name, x, y=None, timestamp=None): """Log metrics (numeric values) in Neptune | If a log with provided ``log_name`` does not exist, it is created automatically. | If log exists (determined by ``log_name``), then new value is appended to it. Args: log_name (:obj:`str`): The name of log, i.e. `mse`, `loss`, `accuracy`. x (:obj:`double`): Depending, whether ``y`` parameter is passed: * ``y`` not passed: The value of the log (data-point). * ``y`` passed: Index of log entry being appended. Must be strictly increasing. y (:obj:`double`, optional, default is ``None``): The value of the log (data-point). timestamp (:obj:`time`, optional, default is ``None``): Timestamp to be associated with log entry. Must be Unix time. If ``None`` is passed, `time.time() <https://docs.python.org/3.6/library/time.html#time.time>`_ (Python 3.6 example) is invoked to obtain timestamp. Example: Assuming that `experiment` is an instance of :class:`~neptune.experiments.Experiment` and 'accuracy' log does not exists: .. code:: python3 # Both calls below have the same effect # Common invocation, providing log name and value experiment.log_metric('accuracy', 0.5) experiment.log_metric('accuracy', 0.65) experiment.log_metric('accuracy', 0.8) # Providing both x and y params experiment.log_metric('accuracy', 0, 0.5) experiment.log_metric('accuracy', 1, 0.65) experiment.log_metric('accuracy', 2, 0.8) Note: For efficiency, logs are uploaded in batches via a queue. Hence, if you log a lot of data, you may experience slight delays in Neptune web application. Note: Passing either ``x`` or ``y`` coordinate as NaN or +/-inf causes this log entry to be ignored. Warning is printed to ``stdout``. """ x, y = self._get_valid_x_y(x, y) if not is_float(y): raise InvalidChannelValue(expected_type='float', actual_type=type(y).__name__) if is_nan_or_inf(y): _logger.warning( 'Invalid metric value: %s for channel %s. ' 'Metrics with nan or +/-inf values will not be sent to server', y, log_name) elif x is not None and is_nan_or_inf(x): _logger.warning( 'Invalid metric x-coordinate: %s for channel %s. ' 'Metrics with nan or +/-inf x-coordinates will not be sent to server', x, log_name) else: value = ChannelValue(x, dict(numeric_value=y), timestamp) self._channels_values_sender.send(log_name, ChannelType.NUMERIC.value, value)