tests / code /multimodal_serve.py
chriskasparaws's picture
Upload 10 files
c5aa5a6 verified
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