예제 #1
0
def test_decode(content_type):
    mock_decoder = Mock()
    with patch.dict(decoder._decoder_map, {content_type: mock_decoder},
                    clear=True):
        decoder.decode(42, content_type)

        mock_decoder.assert_called_once_with(42)
    def input_fn(self, input_data, content_type):
        """A default input_fn that can handle JSON, CSV and NPZ formats.

        Args:
            input_data: the request payload serialized in the content_type format
            content_type: the request content_type

        Returns: input_data deserialized into Numpy Array (Batch_size, width, height, channel)for tensorflow model
        """
        input_data = decoder.decode(input_data, content_type)
        input_data = input_data / 255 
        return decoder.decode(input_data, content_type)
def input_fn(input_data, content_type):
    """A default input_fn that can handle JSON, CSV and NPZ formats.

    this is custom in that it doesn't do the pytorch tensor serialization here
    but instead lets the face_detect model handle necessary preprocessing in the
    predict step.

    additionally, we hijack the 'text/csv' and 'application/json' content_type
    modes:

        + content_type == 'text/csv': treat `input_data` as an s3 path
            `{bucket}/{key path}` and load the image directly using boto3 and
            cv2.
        + content_type == 'application/json': parse `input_data` for a `bucket`
            and a `key` attribute, and do the same as we do in CSV. if they are
            not found, try and parse the data with the sagemaker default
            `decoder.decode` method

    We lose the built-in functionality for CSV, but it is arguably the worst
    way to transfer the data anyway (npy is much better, and json at least
    allows the multi-dimensional arrays to stay multi-dimensional).

    note: application/json will also probably fail and receive a

        HTTP/1.1 413 Request Entity Too Large

    error (a standard size image as json is about 30M)

    Args:
        input_data: the request payload serialized in the content_type format
        content_type: the request content_type

    Returns: numpy array.

    """
    if content_type == content_types.CSV:
        i = input_data.find('/')
        bucket, key = input_data[:i], input_data[i + 1:]
        # the [None] adds a dimension so it can be used in batched_detect
        return load_s3_image(bucket=bucket, key=key)[None]
    elif content_type == content_types.JSON:
        try:
            j = json.loads(input_data)
            # the [None] adds a dimension so it can be used in batched_detect
            return load_s3_image(bucket=j['bucket'], key=j['key'])[None]
        except (KeyError, TypeError):
            return decoder.decode(input_data, content_type)
    else:
        return decoder.decode(input_data, content_type)
예제 #4
0
    def default_input_fn(self, input_data, content_type):
        """Take request data and deserialize it into an MXNet NDArray for prediction.
        When an InvokeEndpoint operation is made against an Endpoint running SageMaker model server,
        the model server receives two pieces of information:

            - The request's content type, for example "application/json"
            - The request data

        The ``input_fn`` is responsible for preprocessing request data before prediction.

        Args:
            input_data (obj): the request data
            content_type (str): the request's content type

        Returns:
            mxnet.nd.array: an MXNet NDArray

        Raises:
            sagemaker_inference.errors.UnsupportedFormatError: if an unsupported content type is used.

        """
        if content_type in self.VALID_CONTENT_TYPES:
            np_array = decoder.decode(input_data, content_type)
            return mx.nd.array(np_array).as_in_context(get_default_context())
        else:
            raise errors.UnsupportedFormatError(content_type)
예제 #5
0
def input_fn(request_body, request_content_type):
    """
    Converts image from NPY format to numpy.
    """
    logger.info(f"Handling inputs...Content type is {request_content_type}")

    try:
        if "application/x-npy" in request_content_type:
            input_object = decoder.decode(request_body, CONTENT_TYPE_NPY)
        elif "jpeg" in request_content_type:
            nparr = np.frombuffer(request_body, np.uint8)
            img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
            input_object = np.asarray(img)
        else:
            raise Exception(
                f"Unsupported request content type {request_content_type}")
    except Exception as e:
        logger.error("Input deserialization failed...")
        logger.error(e)
        return None

    logger.info("Input deserialization completed...")
    logger.info(
        f"Input object type is {type(input_object)} and shape {input_object.shape}"
    )

    return input_object
예제 #6
0
    def default_input_fn(self, input_data, content_type, model=None):
        """Take request data and deserialize it into an object for prediction.
        When an InvokeEndpoint operation is made against an Endpoint running SageMaker model server,
        the model server receives two pieces of information:

            - The request's content type, for example "application/json"
            - The request data

        The ``input_fn`` is responsible for preprocessing request data before prediction.

        Args:
            input_data (obj): the request data
            content_type (str): the request's content type
            model (obj): an MXNet model

        Returns:
            mxnet.io.NDArrayIter: data ready for prediction.

        Raises:
            sagemaker_inference.errors.UnsupportedFormatError: if an unsupported content type is used.

        """
        if content_type not in self.VALID_CONTENT_TYPES:
            raise errors.UnsupportedFormatError(content_type)

        np_array = decoder.decode(input_data, content_type)
        ndarray = mx.nd.array(np_array).as_in_context(get_default_context())

        # We require model to only have one input
        [data_shape] = model.data_shapes

        # Reshape flattened CSV as specified by the model
        if content_type == content_types.CSV:
            _, target_shape = data_shape
            ndarray = ndarray.reshape(target_shape)

        # Batch size is first dimension of model input
        model_batch_size = data_shape[1][0]
        pad_rows = max(0, model_batch_size - ndarray.shape[0])

        # If ndarray has fewer rows than model_batch_size, then pad it with zeros.
        if pad_rows:
            padding_shape = tuple([pad_rows] + list(ndarray.shape[1:]))
            padding = mx.ndarray.zeros(shape=padding_shape)
            ndarray = mx.ndarray.concat(ndarray, padding, dim=0)

        model_input = mx.io.NDArrayIter(ndarray,
                                        batch_size=model_batch_size,
                                        last_batch_handle='pad')

        if pad_rows:
            # Update the getpad method on the model_input data iterator to return the amount of
            # padding. MXNet will ignore the last getpad() rows during Module predict.
            def _getpad():
                return pad_rows

            model_input.getpad = _getpad

        return model_input
예제 #7
0
def input_fn(input_data, content_type):

    np_array = decoder.decode(input_data, content_type)
    tensor = torch.FloatTensor(
        np_array
    ) if content_type in content_types.UTF8_TYPES else torch.from_numpy(
        np_array).float()
    return tensor
예제 #8
0
    def default_input_fn(self, input_data, content_type):  # pylint: disable=no-self-use
        """Function responsible for deserializing the input data into an object for prediction.

        Args:
            input_data (obj): the request data.
            content_type (str): the request content type.

        Returns:
            obj: data ready for prediction.

        """
        return decoder.decode(input_data, content_type)
예제 #9
0
    def default_input_fn(self, input_data, content_type):
        """A default input_fn that can handle JSON, CSV and NPZ formats.

        Args:
            input_data: the request payload serialized in the content_type format
            content_type: the request content_type

        Returns: input_data deserialized into torch.FloatTensor or torch.cuda.FloatTensor,
            depending if cuda is available.
        """
        np_array = decoder.decode(input_data, content_type)
        tensor = torch.FloatTensor(
            np_array) if content_type in content_types.UTF8_TYPES else torch.from_numpy(np_array)
        return tensor.to(device)
예제 #10
0
 def default_input_fn(input_data, content_type):
     """Takes request data and de-serializes the data into an object for prediction.
         When an InvokeEndpoint operation is made against an Endpoint running SageMaker model server,
         the model server receives two pieces of information:
             - The request Content-Type, for example "application/json"
             - The request data, which is at most 5 MB (5 * 1024 * 1024 bytes) in size.
         The input_fn is responsible to take the request data and pre-process it before prediction.
     Args:
         input_data (obj): the request data.
         content_type (str): the request Content-Type.
     Returns:
         (obj): data ready for prediction.
     """
     np_array = decoder.decode(input_data, content_type)
     if len(np_array.shape) == 1:
         np_array = np_array.reshape(1, -1)
     return np_array.astype(np.float32) if content_type in content_types.UTF8_TYPES else np_array
예제 #11
0
 def default_input_fn(self, input_data, content_type):
     if content_type != "text/csv":
         raise Exception("Invalid content-type: %s" % content_type)
     return decoder.decode(input_data, content_type).reshape(1, -1)
예제 #12
0
def test_decode_error():
    with pytest.raises(errors.UnsupportedFormatError):
        decoder.decode(42, content_types.OCTET_STREAM)