-
Notifications
You must be signed in to change notification settings - Fork 101
Feature: Support multiple inference.py files and universal inference.… #228
Changes from all commits
116fb22
a20d398
35cef64
5cde4a4
46328d1
195239d
0b44c19
50b1d79
002292a
96346a9
00ef7fd
55a6336
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,7 @@ | |
import os | ||
import subprocess | ||
import grpc | ||
import sys | ||
|
||
import falcon | ||
import requests | ||
|
@@ -26,8 +27,8 @@ | |
import tfs_utils | ||
|
||
SAGEMAKER_MULTI_MODEL_ENABLED = os.environ.get("SAGEMAKER_MULTI_MODEL", "false").lower() == "true" | ||
MODEL_DIR = "models" if SAGEMAKER_MULTI_MODEL_ENABLED else "model" | ||
INFERENCE_SCRIPT_PATH = f"/opt/ml/{MODEL_DIR}/code/inference.py" | ||
MODEL_DIR = "" if SAGEMAKER_MULTI_MODEL_ENABLED else "model/" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why needs to change the dir structures? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The problem with this path is that This problem has been highlighted in other Github issues (#212 and #211) as well and a PR (#215) was created to solve the issue but it was not merged. We can use the path |
||
INFERENCE_SCRIPT_PATH = f"/opt/ml/{MODEL_DIR}code/inference.py" | ||
|
||
SAGEMAKER_BATCHING_ENABLED = os.environ.get("SAGEMAKER_TFS_ENABLE_BATCHING", "false").lower() | ||
MODEL_CONFIG_FILE_PATH = "/sagemaker/model-config.cfg" | ||
|
@@ -77,6 +78,7 @@ def __init__(self): | |
# between each grpc port and channel | ||
self._setup_channel(grpc_port) | ||
|
||
self._default_handlers_enabled = False | ||
if os.path.exists(INFERENCE_SCRIPT_PATH): | ||
# Single-Model Mode & Multi-Model Mode both use one inference.py | ||
self._handler, self._input_handler, self._output_handler = self._import_handlers() | ||
|
@@ -85,6 +87,7 @@ def __init__(self): | |
) | ||
else: | ||
self._handlers = default_handler | ||
self._default_handlers_enabled = True | ||
|
||
self._tfs_enable_batching = SAGEMAKER_BATCHING_ENABLED == "true" | ||
self._tfs_default_model_name = os.environ.get("TFS_DEFAULT_MODEL_NAME", "None") | ||
|
@@ -143,6 +146,7 @@ def _handle_load_model_post(self, res, data): # noqa: C901 | |
# validate model files are in the specified base_path | ||
if self.validate_model_dir(base_path): | ||
try: | ||
self._import_custom_modules(model_name) | ||
tfs_config = tfs_utils.create_tfs_config_individual_model(model_name, base_path) | ||
tfs_config_file = "/sagemaker/tfs-config/{}/model-config.cfg".format(model_name) | ||
log.info("tensorflow serving model config: \n%s\n", tfs_config) | ||
|
@@ -221,6 +225,17 @@ def _handle_load_model_post(self, res, data): # noqa: C901 | |
} | ||
) | ||
|
||
def _import_custom_modules(self, model_name): | ||
inference_script_path = "/opt/ml/models/{}/model/code/inference.py".format(model_name) | ||
python_lib_path = "/opt/ml/models/{}/model/code/lib".format(model_name) | ||
if os.path.exists(python_lib_path): | ||
log.info("add Python code library path") | ||
sys.path.append(python_lib_path) | ||
if os.path.exists(inference_script_path): | ||
handler, input_handler, output_handler = self._import_handlers(inference_script_path) | ||
model_handlers = self._make_handler(handler, input_handler, output_handler) | ||
self.model_handlers[model_name] = model_handlers | ||
|
||
def _cleanup_config_file(self, config_file): | ||
if os.path.exists(config_file): | ||
os.remove(config_file) | ||
|
@@ -264,8 +279,20 @@ def _handle_invocation_post(self, req, res, model_name=None): | |
|
||
try: | ||
res.status = falcon.HTTP_200 | ||
|
||
res.body, res.content_type = self._handlers(data, context) | ||
handlers = self._handlers | ||
if SAGEMAKER_MULTI_MODEL_ENABLED and model_name in self.model_handlers: | ||
inference_script_path = "/opt/ml/models/{}/model/code/" \ | ||
"inference.py".format(model_name) | ||
log.info("Inference script found at path {}.".format(inference_script_path)) | ||
log.info("Inference script exists, importing handlers.") | ||
handlers = self.model_handlers[model_name] | ||
elif not self._default_handlers_enabled: | ||
log.info("Universal inference script found at path " | ||
"{}.".format(INFERENCE_SCRIPT_PATH)) | ||
log.info("Universal inference script exists, importing handlers.") | ||
else: | ||
log.info("Inference script does not exist, using default handlers.") | ||
res.body, res.content_type = handlers(data, context) | ||
except Exception as e: # pylint: disable=broad-except | ||
log.exception("exception handling request: {}".format(e)) | ||
res.status = falcon.HTTP_500 | ||
|
@@ -276,8 +303,7 @@ def _setup_channel(self, grpc_port): | |
log.info("Creating grpc channel for port: %s", grpc_port) | ||
self._channels[grpc_port] = grpc.insecure_channel("localhost:{}".format(grpc_port)) | ||
|
||
def _import_handlers(self): | ||
inference_script = INFERENCE_SCRIPT_PATH | ||
def _import_handlers(self, inference_script=INFERENCE_SCRIPT_PATH): | ||
spec = importlib.util.spec_from_file_location("inference", inference_script) | ||
inference = importlib.util.module_from_spec(spec) | ||
spec.loader.exec_module(inference) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How to provide model specific inference.py via SM SDK MME? Can you provide add notebook in SM examples?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can create a notebook for SM examples which will demonstrate the usage of model-specific inference.py files.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated the directory structure