Example #1
0
    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)
Example #2
0
    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)
Example #3
0
    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)