Skip to content

Commit 787f04c

Browse files
authored
feature: MME support (#42)
* Set model_dir based on SAGEMAKER_MULTI_MODEL env variable * Adapt to MMS format * Update Dockerfile * Update build artifacts * Format with black and fix pylint violation * Fix filenames for build artifacts * Download models in Dockerfile * Fix directory for build artifacts * Update directories for downloaded models in Dockerfile * Set WORKDIR back to root after downloading models in Dockerfile * Update directories for downloaded models in MXNet multi-model integration tests * Update Dockerfile with sagemaker_inference tarball and remove SAGEMAKER_HANDLER * Add sagemaker_inference tarball * Replace SAGEMAKER_HANDLER * Rename model files to default model name * Create model archive if MME not enabled * Update sagemaker_inference tarball * Get the model_dir from the context * Update default handler service unit tests * Update sagemaker_mxnet_inference tarball (modified HandlerService) * Revert change to Transformer.transform * Update call to validate_and_initialize in Transformer.transform and update unit tests * Update build artifact tarballs * Update sagemaker_mxnet_inference tarball * Temporarily skip test_mxnet_multi_model.py::test_load_model_multiple_times to isolate bug * Fix model names in integ test * Temporarily skip test_load_model_multiple_times and test_invocation * Remove skip on test_load_model_multiple_times * Remove test_invocation since default_inference_handler does not implement input_fn to deserialize image * Fix flake8 violation
1 parent fe1a1fd commit 787f04c

16 files changed

+66
-370
lines changed

src/sagemaker_inference/default_handler_service.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,14 @@ def handle(self, data, context):
4343
with the context set appropriately.
4444
4545
"""
46+
self.initialize(context)
47+
4648
return self._service.transform(data, context)
4749

48-
def initialize(self):
50+
def initialize(self, context):
4951
"""Calls the Transformer method that validates the user module against
5052
the SageMaker inference contract.
5153
"""
52-
self._service.validate_and_initialize()
54+
properties = context.system_properties
55+
model_dir = properties.get("model_dir")
56+
self._service.validate_and_initialize(model_dir=model_dir)

src/sagemaker_inference/environment.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,11 @@
2929

3030
base_dir = os.environ.get(parameters.BASE_PATH_ENV, SAGEMAKER_BASE_PATH) # type: str
3131

32-
model_dir = os.path.join(base_dir, "model") # type: str
33-
"""str: the directory where models should be saved, e.g., /opt/ml/model/"""
32+
if os.environ.get(parameters.MULTI_MODEL_ENV) == "true":
33+
model_dir = os.path.join(base_dir, "models") # type: str
34+
else:
35+
model_dir = os.path.join(base_dir, "model") # type: str
36+
# str: the directory where models should be saved, e.g., /opt/ml/model/
3437

3538
code_dir = os.path.join(model_dir, "code") # type: str
3639
"""str: the path of the user's code directory, e.g., /opt/ml/model/code/"""

src/sagemaker_inference/model_server.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ def start_model_server(handler_service=DEFAULT_HANDLER_SERVICE):
7070
if ENABLE_MULTI_MODEL:
7171
if not os.getenv("SAGEMAKER_HANDLER"):
7272
os.environ["SAGEMAKER_HANDLER"] = handler_service
73+
_set_python_path()
7374
else:
7475
_adapt_to_mms_format(handler_service)
7576

src/sagemaker_inference/parameters.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,4 @@
2222
MODEL_SERVER_TIMEOUT_ENV = "SAGEMAKER_MODEL_SERVER_TIMEOUT" # type: str
2323
BIND_TO_PORT_ENV = "SAGEMAKER_BIND_TO_PORT" # type: str
2424
SAFE_PORT_RANGE_ENV = "SAGEMAKER_SAFE_PORT_RANGE" # type: str
25+
MULTI_MODEL_ENV = "SAGEMAKER_MULTI_MODEL" # type: str

src/sagemaker_inference/transformer.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,9 @@ def transform(self, data, context):
105105
with the context set appropriately.
106106
"""
107107
try:
108-
self.validate_and_initialize()
108+
properties = context.system_properties
109+
model_dir = properties.get("model_dir")
110+
self.validate_and_initialize(model_dir=model_dir)
109111

110112
input_data = data[0].get("body")
111113

@@ -141,7 +143,7 @@ def transform(self, data, context):
141143
context, GenericInferenceToolkitError(http_client.INTERNAL_SERVER_ERROR, str(e))
142144
)
143145

144-
def validate_and_initialize(self): # type: () -> None
146+
def validate_and_initialize(self, model_dir=environment.model_dir): # type: () -> None
145147
"""Validates the user module against the SageMaker inference contract.
146148
147149
Load the model as defined by the ``model_fn`` to prepare handling predictions.
@@ -150,7 +152,7 @@ def validate_and_initialize(self): # type: () -> None
150152
if not self._initialized:
151153
self._environment = environment.Environment()
152154
self._validate_user_module_and_set_functions()
153-
self._model = self._model_fn(environment.model_dir)
155+
self._model = self._model_fn(model_dir)
154156
self._initialized = True
155157

156158
def _validate_user_module_and_set_functions(self):

test/container/mxnet/Dockerfile

Lines changed: 28 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,11 @@ LABEL com.amazonaws.sagemaker.capabilities.accept-bind-to-port=true
1010
LABEL com.amazonaws.sagemaker.capabilities.multi-models=true
1111

1212
ARG MMS_VERSION=1.0.8
13-
ARG MX_URL=https://aws-mxnet-pypi.s3-us-west-2.amazonaws.com/1.6.0/aws_mxnet_mkl-1.6.0rc0-py2.py3-none-manylinux1_x86_64.whl
13+
ARG MX_URL=https://aws-mxnet-pypi.s3-us-west-2.amazonaws.com/1.6.0/aws_mxnet_mkl-1.6.0-py2.py3-none-manylinux1_x86_64.whl
1414
ARG PYTHON=python3
1515
ARG PYTHON_PIP=python3-pip
1616
ARG PIP=pip3
1717
ARG PYTHON_VERSION=3.6.8
18-
ARG PIP_VERSION=19.3.1
1918

2019
ENV PYTHONDONTWRITEBYTECODE=1 \
2120
PYTHONUNBUFFERED=1 \
@@ -63,21 +62,24 @@ RUN wget https://www.python.org/ftp/python/$PYTHON_VERSION/Python-$PYTHON_VERSIO
6362
RUN ln -s $(which ${PYTHON}) /usr/local/bin/python
6463

6564
RUN ${PIP} --no-cache-dir install --upgrade \
66-
pip==${PIP_VERSION} \
65+
pip \
6766
setuptools
6867

6968
WORKDIR /
7069

71-
COPY mxnet/sagemaker_mxnet_serving_container.tar.gz /sagemaker_mxnet_serving_container.tar.gz
70+
COPY mxnet/sagemaker_mxnet_inference.tar.gz /sagemaker_mxnet_inference.tar.gz
71+
COPY mxnet/sagemaker_inference.tar.gz /sagemaker_inference.tar.gz
7272

7373
RUN ${PIP} install --no-cache-dir \
7474
${MX_URL} \
75+
git+git://github.com/dmlc/[email protected] \
7576
mxnet-model-server==$MMS_VERSION \
7677
keras-mxnet==2.2.4.1 \
7778
numpy==1.17.4 \
7879
onnx==1.4.1 \
79-
/sagemaker_mxnet_serving_container.tar.gz \
80-
&& rm /sagemaker_mxnet_serving_container.tar.gz
80+
/sagemaker_mxnet_inference.tar.gz \
81+
/sagemaker_inference.tar.gz \
82+
&& rm /sagemaker_mxnet_inference.tar.gz /sagemaker_inference.tar.gz
8183

8284
# This is here to make our installed version of OpenCV work.
8385
# https://stackoverflow.com/questions/29274638/opencv-libdc1394-error-failed-to-initialize-libdc1394
@@ -87,45 +89,34 @@ RUN ln -s /dev/null /dev/raw1394
8789
##################################
8890
# download models to model_store
8991
##################################
90-
RUN mkdir resnet_152 \
91-
&& cd resnet_152 \
92-
&& wget -O resnet-152-0000.params http://data.mxnet.io/models/imagenet/resnet/152-layers/resnet-152-0000.params \
93-
&& wget -O resnet-152-symbol.json http://data.mxnet.io/models/imagenet/resnet/152-layers/resnet-152-symbol.json \
92+
WORKDIR /opt/ml/models/resnet_152/model
93+
RUN wget -O model-0000.params http://data.mxnet.io/models/imagenet/resnet/152-layers/resnet-152-0000.params \
94+
&& wget -O model-symbol.json http://data.mxnet.io/models/imagenet/resnet/152-layers/resnet-152-symbol.json \
9495
&& wget -O synset.txt http://data.mxnet.io/models/imagenet/synset.txt \
95-
&& echo '[{"shape": [1, 3, 224, 224], "name": "data"}]' > resnet-152-shapes.json \
96-
&& cd ..
96+
&& echo '[{"shape": [1, 3, 224, 224], "name": "data"}]' > model-shapes.json \
97+
&& cd /
9798

98-
RUN mkdir resnet_18 \
99-
&& cd resnet_18 \
100-
&& wget -O resnet-18-0000.params http://data.mxnet.io/models/imagenet/resnet/18-layers/resnet-18-0000.params \
101-
&& wget -O resnet-18-symbol.json http://data.mxnet.io/models/imagenet/resnet/18-layers/resnet-18-symbol.json \
99+
WORKDIR /opt/ml/models/resnet_18/model
100+
RUN wget -O model-0000.params http://data.mxnet.io/models/imagenet/resnet/18-layers/resnet-18-0000.params \
101+
&& wget -O model-symbol.json http://data.mxnet.io/models/imagenet/resnet/18-layers/resnet-18-symbol.json \
102102
&& wget -O synset.txt http://data.mxnet.io/models/imagenet/synset.txt \
103-
&& echo '[{"shape": [1, 3, 224, 224], "name": "data"}]' > resnet-18-shapes.json \
104-
&& cd ..
103+
&& echo '[{"shape": [1, 3, 224, 224], "name": "data"}]' > model-shapes.json \
104+
&& cd /
105105

106-
ENV PYTHONDONTWRITEBYTECODE=1 \
107-
PYTHONUNBUFFERED=1 \
108-
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:/usr/local/lib" \
109-
PYTHONIOENCODING=UTF-8 \
110-
LANG=C.UTF-8 \
111-
LC_ALL=C.UTF-8
106+
WORKDIR /
112107

113108
RUN useradd -m model-server \
114-
&& mkdir -p /home/model-server/tmp \
115-
&& chown -R model-server /home/model-server
116-
117-
#################################################
118-
# custom_entrypoint uses custom_handler_service
119-
#################################################
120-
COPY mxnet/custom_handler.py /usr/local/bin/custom_handler.py
121-
COPY mxnet/custom_entrypoint.py /usr/local/bin/dockerd-entrypoint.py
109+
&& mkdir -p /home/model-server/tmp \
110+
&& chown -R model-server /home/model-server
111+
112+
COPY mxnet/mms_entrypoint.py /usr/local/bin/dockerd_entrypoint.py
122113
COPY mxnet/config.properties /home/model-server
123-
COPY mxnet/deep_learning_container.py /usr/local/bin/deep_learning_container.py
114+
COPY mxnet/inference.py /opt/ml/models/code/inference.py
115+
116+
RUN chmod +x /usr/local/bin/dockerd_entrypoint.py
124117

125-
RUN chmod +x /usr/local/bin/dockerd-entrypoint.py && \
126-
chmod +x /usr/local/bin/deep_learning_container.py
118+
RUN curl https://aws-dlc-licenses.s3.amazonaws.com/aws-mxnet-1.6.0/license.txt -o /license.txt
127119

128120
EXPOSE 8080 8081
129-
ENV TEMP=/home/model-server/tmp
130-
ENTRYPOINT ["python", "/usr/local/bin/dockerd-entrypoint.py"]
121+
ENTRYPOINT ["python", "/usr/local/bin/dockerd_entrypoint.py"]
131122
CMD ["mxnet-model-server", "--start", "--mms-config", "/home/model-server/config.properties"]

test/container/mxnet/custom_handler.py

Lines changed: 0 additions & 164 deletions
This file was deleted.

0 commit comments

Comments
 (0)