tests / code /multimodal_serve.py
chriskasparaws's picture
Upload 10 files
c5aa5a6 verified
Raw
History Blame Contribute Delete
4.12 kB
import ast
import json
import os
import numpy as np
import pandas as pd
from autogluon.multimodal import MultiModalPredictor
from constants import (
ALLOWED_INPUT_FORMATS,
ALLOWED_OUTPUT_FORMATS,
BRACKET_FORMATTER,
COMMA_DELIMITER,
IMAGE_COLUMN_NAME,
JSON_FORMAT,
LABELS,
NUM_GPU,
PREDICTED_LABEL,
PROBABILITIES,
PROBABILITY,
SAGEMAKER_INFERENCE_OUTPUT,
)
from utils import infer_type_and_cast_value
INFERENCE_OUTPUT = (
infer_type_and_cast_value(os.getenv(SAGEMAKER_INFERENCE_OUTPUT))
if SAGEMAKER_INFERENCE_OUTPUT in os.environ
else [PREDICTED_LABEL]
)
NUM_GPUS = infer_type_and_cast_value(os.getenv(NUM_GPU))
def generate_single_csv_line_inference_selection(data):
"""Generate a single csv line response.
:param data: list of output generated from the model
:return: csv line for the predictions
"""
contents: str
for single_prediction in data:
contents = (
BRACKET_FORMATTER.format(single_prediction)
if isinstance(single_prediction, list)
else str(single_prediction)
)
return contents
def model_fn(model_dir):
"""Load model from previously saved artifact.
:param model_dir: local path to the model directory
:return: loaded model
"""
predictor = MultiModalPredictor.load(model_dir)
if NUM_GPUS is not None:
predictor._config.env.num_gpus = NUM_GPUS
return predictor
def convert_to_json_compatible_type(value):
"""Convert the input value to a JSON compatible type.
:param value: input value
:return: JSON compatible value
"""
string_value = "{}".format(value)
try:
return ast.literal_eval(string_value)
except Exception:
return string_value
def transform_fn(model, request_body, input_content_type, output_content_type):
"""Transform function for serving inference requests.
If INFERENCE_OUTPUT is provided, then the predictions are generated in the requested format and concatenated in the
same order. Otherwise, prediction_labels are generated by default.
:param model: loaded model
:param request_body: request body
:param input_content_type: content type of the input
:param output_content_type: content type of the response
:return: prediction response
"""
if input_content_type.lower() not in ALLOWED_INPUT_FORMATS:
raise Exception(
f"{input_content_type} input content type not supported. Supported formats are {ALLOWED_INPUT_FORMATS}"
)
if output_content_type.lower() not in ALLOWED_OUTPUT_FORMATS:
raise Exception(
f"{output_content_type} output content type not supported. Supported formats are {ALLOWED_OUTPUT_FORMATS}"
)
data = pd.DataFrame({IMAGE_COLUMN_NAME: [request_body]})
result_dict = dict()
result = []
inference_output_list = (
INFERENCE_OUTPUT if isinstance(INFERENCE_OUTPUT, list) else [INFERENCE_OUTPUT]
)
for output_type in inference_output_list:
if output_type == PREDICTED_LABEL:
prediction = model.predict(data)
result_dict[PREDICTED_LABEL] = convert_to_json_compatible_type(prediction.squeeze())
elif output_type == PROBABILITIES:
predict_probs = model.predict_proba(data)
prediction = predict_probs.to_numpy()
result_dict[PROBABILITIES] = predict_probs.squeeze().tolist()
elif output_type == LABELS:
labels = model.class_labels
prediction = np.array([labels]).astype("str")
result_dict[LABELS] = labels.tolist()
else:
predict_probabilities = model.predict_proba(data).to_numpy()
prediction = np.max(predict_probabilities, axis=1)
result_dict[PROBABILITY] = prediction.squeeze().tolist()
result.append(generate_single_csv_line_inference_selection(prediction.tolist()))
response = COMMA_DELIMITER.join(result)
if output_content_type == JSON_FORMAT:
response = json.dumps(result_dict)
return response, output_content_type