def log_text(self, log_name, x, y=None, timestamp=None): """Log text data 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`, `my_text_data`, `timing_info`. x (:obj:`double` or :obj:`str`): Depending, whether ``y`` parameter is passed: * ``y`` not passed: The value of the log (data-point). Must be ``str``. * ``y`` passed: Index of log entry being appended. Must be strictly increasing. y (:obj:`str`, 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`: .. code:: python3 # common case, where log name and data are passed neptune.log_text('my_text_data', str(data_item)) # log_name, x and timestamp are passed neptune.log_text(log_name='logging_losses_as_text', x=str(val_loss), timestamp=1560430912) 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 ``x`` 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 x is not None and is_nan_or_inf(x): x = None if not isinstance(y, six.string_types): raise InvalidChannelValue(expected_type="str", actual_type=type(y).__name__) if 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(text_value=y), timestamp) self._channels_values_sender.send(log_name, ChannelType.TEXT.value, value)
def log_image(self, log_name, x, y=None, image_name=None, description=None, timestamp=None): """Log image data 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. `bboxes`, `visualisations`, `sample_images`. x (:obj:`double`): Depending, whether ``y`` parameter is passed: * ``y`` not passed: The value of the log (data-point). See ``y`` parameter. * ``y`` passed: Index of log entry being appended. Must be strictly increasing. y (multiple types supported, optional, default is ``None``): The value of the log (data-point). Can be one of the following types: * :obj:`PIL image` `Pillow docs <https://pillow.readthedocs.io/en/latest/reference/Image.html#image-module>`_ * :obj:`matplotlib.figure.Figure` `Matplotlib 3.1.1 docs <https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.figure.Figure.html>`_ * :obj:`str` - path to image file * 2-dimensional :obj:`numpy.array` - interpreted as grayscale image * 3-dimensional :obj:`numpy.array` - behavior depends on last dimension * if last dimension is 1 - interpreted as grayscale image * if last dimension is 3 - interpreted as RGB image * if last dimension is 4 - interpreted as RGBA image image_name (:obj:`str`, optional, default is ``None``): Image name description (:obj:`str`, optional, default is ``None``): Image description 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`: .. code:: python3 # path to image file experiment.log_image('bbox_images', 'pictures/image.png') experiment.log_image('bbox_images', x=5, 'pictures/image.png') experiment.log_image('bbox_images', 'pictures/image.png', image_name='difficult_case') # PIL image img = PIL.Image.new('RGB', (60, 30), color = 'red') experiment.log_image('fig', img) # 2d numpy array array = numpy.random.rand(300, 200)*255 experiment.log_image('fig', array) # 3d grayscale array array = numpy.random.rand(300, 200, 1)*255 experiment.log_image('fig', array) # 3d RGB array array = numpy.random.rand(300, 200, 3)*255 experiment.log_image('fig', array) # 3d RGBA array array = numpy.random.rand(300, 200, 4)*255 experiment.log_image('fig', array) # matplotlib figure example 1 from matplotlib import pyplot pyplot.plot([1, 2, 3, 4]) pyplot.ylabel('some numbers') experiment.log_image('plots', plt.gcf()) # matplotlib figure example 2 from matplotlib import pyplot import numpy numpy.random.seed(19680801) data = numpy.random.randn(2, 100) figure, axs = pyplot.subplots(2, 2, figsize=(5, 5)) axs[0, 0].hist(data[0]) axs[1, 0].scatter(data[0], data[1]) axs[0, 1].plot(data[0], data[1]) axs[1, 1].hist2d(data[0], data[1]) experiment.log_image('diagrams', figure) 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 ``x`` coordinate as NaN or +/-inf causes this log entry to be ignored. Warning is printed to ``stdout``. Warning: Only images up to 2MB are supported. Larger files will not be logged to Neptune. """ x, y = self._get_valid_x_y(x, y) if x is not None and is_nan_or_inf(x): x = None image_content = get_image_content(y) if len(image_content) > self.IMAGE_SIZE_LIMIT: _logger.warning( 'Your image is larger than 2MB. Neptune supports logging images smaller than 2MB. ' 'Resize or increase compression of this image') image_content = None input_image = dict(name=image_name, description=description) if image_content: input_image['data'] = base64.b64encode(image_content).decode( 'utf-8') if 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(image_value=input_image), timestamp) self._channels_values_sender.send(log_name, ChannelType.IMAGE.value, value)
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)