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)
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)
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
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
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
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)
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)
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
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)
def test_decode_error(): with pytest.raises(errors.UnsupportedFormatError): decoder.decode(42, content_types.OCTET_STREAM)