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 send_text(self, channel_name, x, y=None, timestamp=None):
        x, y = self._get_valid_x_y(x, y)

        if not isinstance(y, six.string_types):
            raise InvalidChannelValue(expected_type='str', actual_type=type(y).__name__)

        value = ChannelValue(x, dict(text_value=y), timestamp)
        self._channels_values_sender.send(channel_name, 'text', value)
Example #3
0
    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)
Example #4
0
    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
Example #5
0
def get_image_content(image):
    if isinstance(image, six.string_types):
        if not os.path.exists(image):
            raise FileNotFound(image)
        with open(image, 'rb') as image_file:
            return image_file.read()

    elif isinstance(image, Image.Image):
        with io.BytesIO() as image_buffer:
            image.save(image_buffer, format='PNG')
            return image_buffer.getvalue()

    raise InvalidChannelValue(expected_type='image',
                              actual_type=type(image).__name__)
Example #6
0
    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
Example #7
0
def get_image_content(image):
    if isinstance(image, six.string_types):
        if not os.path.exists(image):
            raise FileNotFound(image)
        with open(image, 'rb') as image_file:
            return image_file.read()

    elif isinstance(image, numpy.ndarray):
        shape = image.shape
        if len(shape) == 2:
            return _get_pil_image_data(
                Image.fromarray(image.astype(numpy.uint8)))
        if len(shape) == 3:
            if shape[2] == 1:
                array2d = numpy.array([[col[0] for col in row]
                                       for row in image])
                return _get_pil_image_data(
                    Image.fromarray(array2d.astype(numpy.uint8)))
            if shape[2] in (3, 4):
                return _get_pil_image_data(
                    Image.fromarray(image.astype(numpy.uint8)))
        raise ValueError(
            "Incorrect size of numpy.ndarray. Should be 2-dimensional or"
            "3-dimensional with 3rd dimension of size 1, 3 or 4.")

    elif isinstance(image, Image.Image):
        return _get_pil_image_data(image)

    else:
        try:
            from matplotlib import figure
            if isinstance(image, figure.Figure):
                return _get_pil_image_data(_figure_to_pil_image(image))
        except ImportError:
            pass

    raise InvalidChannelValue(expected_type='image',
                              actual_type=type(image).__name__)
Example #8
0
def get_image_content(image):
    if isinstance(image, six.string_types):
        if not os.path.exists(image):
            raise FileNotFound(image)
        with open(image, 'rb') as image_file:
            return image_file.read()

    elif isinstance(image, numpy.ndarray):
        return _get_numpy_as_image(image)

    elif isinstance(image, Image.Image):
        return _get_pil_image_data(image)

    else:
        try:
            from matplotlib import figure
            if isinstance(image, figure.Figure):
                return _get_figure_as_image(image)
        except ImportError:
            pass

        try:
            from torch import Tensor as TorchTensor
            if isinstance(image, TorchTensor):
                return _get_numpy_as_image(image.detach().numpy())
        except ImportError:
            pass

        try:
            from tensorflow import Tensor as TensorflowTensor
            if isinstance(image, TensorflowTensor):
                return _get_numpy_as_image(image.numpy())
        except ImportError:
            pass

    raise InvalidChannelValue(expected_type='image', actual_type=type(image).__name__)
Example #9
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)