Skip to content

Commit 96ccb0f

Browse files
orchidmajumderJonathan Esterhazy
authored andcommitted
add inference pipelines and SparkML serving
1 parent d8c055b commit 96ccb0f

22 files changed

+972
-50
lines changed

CHANGELOG.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,4 +363,4 @@ CHANGELOG
363363
1.0.0
364364
=====
365365

366-
* Initial commit
366+
* Initial commit

README.rst

Lines changed: 79 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,15 @@ Table of Contents
3232
4. `TensorFlow SageMaker Estimators <#tensorflow-sagemaker-estimators>`__
3333
5. `Chainer SageMaker Estimators <#chainer-sagemaker-estimators>`__
3434
6. `PyTorch SageMaker Estimators <#pytorch-sagemaker-estimators>`__
35-
7. `AWS SageMaker Estimators <#aws-sagemaker-estimators>`__
36-
8. `BYO Docker Containers with SageMaker Estimators <#byo-docker-containers-with-sagemaker-estimators>`__
37-
9. `SageMaker Automatic Model Tuning <#sagemaker-automatic-model-tuning>`__
38-
10. `SageMaker Batch Transform <#sagemaker-batch-transform>`__
39-
11. `Secure Training and Inference with VPC <#secure-training-and-inference-with-vpc>`__
40-
12. `BYO Model <#byo-model>`__
41-
13. `SageMaker Workflow <#sagemaker-workflow>`__
35+
7. `SageMaker SparkML Serving <#sagemaker-sparkml-serving>`__
36+
8. `AWS SageMaker Estimators <#aws-sagemaker-estimators>`__
37+
9. `BYO Docker Containers with SageMaker Estimators <#byo-docker-containers-with-sagemaker-estimators>`__
38+
10. `SageMaker Automatic Model Tuning <#sagemaker-automatic-model-tuning>`__
39+
11. `SageMaker Batch Transform <#sagemaker-batch-transform>`__
40+
12. `Secure Training and Inference with VPC <#secure-training-and-inference-with-vpc>`__
41+
13. `BYO Model <#byo-model>`__
42+
14. `Inference Pipelines <#inference-pipelines>`__
43+
15. `SageMaker Workflow <#sagemaker-workflow>`__
4244

4345

4446
Installing the SageMaker Python SDK
@@ -374,7 +376,7 @@ For more information, see `TensorFlow SageMaker Estimators and Models`_.
374376
375377
376378
Chainer SageMaker Estimators
377-
-------------------------------
379+
----------------------------
378380
379381
By using Chainer SageMaker ``Estimators``, you can train and host Chainer models on Amazon SageMaker.
380382
@@ -390,7 +392,7 @@ For more information about Chainer SageMaker ``Estimators``, see `Chainer SageM
390392
391393
392394
PyTorch SageMaker Estimators
393-
-------------------------------
395+
----------------------------
394396
395397
With PyTorch SageMaker ``Estimators``, you can train and host PyTorch models on Amazon SageMaker.
396398
@@ -408,6 +410,39 @@ For more information about PyTorch SageMaker ``Estimators``, see `PyTorch SageMa
408410
.. _PyTorch SageMaker Estimators and Models: src/sagemaker/pytorch/README.rst
409411
410412
413+
SageMaker SparkML Serving
414+
-------------------------
415+
416+
With SageMaker SparkML Serving, you can now perform predictions against a SparkML Model in SageMaker.
417+
In order to host a SparkML model in SageMaker, it should be serialized with ``MLeap`` library.
418+
419+
For more information on MLeap, see https://github.com/combust/mleap .
420+
421+
Supported major version of Spark: 2.2 (MLeap version - 0.9.6)
422+
423+
Here is an example on how to create an instance of ``SparkMLModel`` class and use ``deploy()`` method to create an
424+
endpoint which can be used to perform prediction against your trained SparkML Model.
425+
426+
.. code:: python
427+
428+
sparkml_model = SparkMLModel(model_data='s3://path/to/model.tar.gz', env={'SAGEMAKER_SPARKML_SCHEMA': schema})
429+
model_name = 'sparkml-model'
430+
endpoint_name = 'sparkml-endpoint'
431+
predictor = sparkml_model.deploy(initial_instance_count=1, instance_type='ml.c4.xlarge', endpoint_name=endpoint_name)
432+
433+
Once the model is deployed, we can invoke the endpoint with a ``CSV`` payload like this:
434+
435+
.. code:: python
436+
437+
payload = 'field_1,field_2,field_3,field_4,field_5'
438+
predictor.predict(payload)
439+
440+
441+
For more information about the different ``content-type`` and ``Accept`` formats as well as the structure of the
442+
``schema`` that SageMaker SparkML Serving recognizes, please see `SageMaker SparkML Serving Container`_.
443+
444+
.. _SageMaker SparkML Serving Container: https://github.com/aws/sagemaker-sparkml-serving-container
445+
411446
AWS SageMaker Estimators
412447
------------------------
413448
Amazon SageMaker provides several built-in machine learning algorithms that you can use to solve a variety of problems.
@@ -709,11 +744,45 @@ This returns a predictor the same way an ``Estimator`` does when ``deploy()`` is
709744
A full example is available in the `Amazon SageMaker examples repository <https://github.com/awslabs/amazon-sagemaker-examples/tree/master/advanced_functionality/mxnet_mnist_byom>`__.
710745
711746
747+
Inference Pipelines
748+
-------------------
749+
You can create a Pipeline for realtime or batch inference comprising of one or multiple model containers. This will help
750+
you to deploy an ML pipeline behind a single endpoint and you can have one API call perform pre-processing, model-scoring
751+
and post-processing on your data before returning it back as the response.
752+
753+
For this, you have to create a ``PipelineModel`` which will take a list of ``Model`` objects. Calling ``deploy()`` on the
754+
``PipelineModel`` will provide you with an endpoint which can be invoked to perform the prediction on a data point against
755+
the ML Pipeline.
756+
757+
.. code:: python
758+
759+
xgb_image = get_image_uri(sess.boto_region_name, 'xgboost', repo_version="latest")
760+
xgb_model = Model(model_data='s3://path/to/model.tar.gz', image=xgb_image)
761+
sparkml_model = SparkMLModel(model_data='s3://path/to/model.tar.gz', env={'SAGEMAKER_SPARKML_SCHEMA': schema})
762+
763+
model_name = 'inference-pipeline-model'
764+
endpoint_name = 'inference-pipeline-endpoint'
765+
sm_model = PipelineModel(name=model_name, role=sagemaker_role, models=[sparkml_model, xgb_model])
766+
767+
This will define a ``PipelineModel`` consisting of SparkML model and an XGBoost model stacked sequentially. For more
768+
information about how to train an XGBoost model, please refer to the XGBoost notebook here_.
769+
770+
.. _here: https://docs.aws.amazon.com/sagemaker/latest/dg/xgboost.html#xgboost-sample-notebooks
771+
772+
.. code:: python
773+
774+
sm_model.deploy(initial_instance_count=1, instance_type='ml.c5.xlarge', endpoint_name=endpoint_name)
775+
776+
This returns a predictor the same way an ``Estimator`` does when ``deploy()`` is called. Whenever you make an inference
777+
request using this predictor, you should pass the data that the first container expects and the predictor will return the
778+
output from the last container.
779+
780+
712781
SageMaker Workflow
713782
------------------
714783
715784
You can use Apache Airflow to author, schedule and monitor SageMaker workflow.
716785
717786
For more information, see `SageMaker Workflow in Apache Airflow`_.
718787
719-
.. _SageMaker Workflow in Apache Airflow: src/sagemaker/workflow/README.rst
788+
.. _SageMaker Workflow in Apache Airflow: src/sagemaker/workflow/README.rst

doc/pipeline.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
PipelineModel
2+
-------------
3+
4+
.. autoclass:: sagemaker.pipeline.PipelineModel
5+
:members:
6+
:undoc-members:
7+
:show-inheritance:

doc/sagemaker.sparkml.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
SparkML Serving
2+
===============
3+
4+
SparkML Model
5+
-------------
6+
7+
.. autoclass:: sagemaker.sparkml.model.SparkMLModel
8+
:members:
9+
:undoc-members:
10+
:show-inheritance:
11+
12+
SparkML Predictor
13+
-----------------
14+
15+
.. autoclass:: sagemaker.sparkml.model.SparkMLPredictor
16+
:members:
17+
:undoc-members:
18+
:show-inheritance:

src/sagemaker/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,10 @@
3030
from sagemaker.local.local_session import LocalSession # noqa: F401
3131

3232
from sagemaker.model import Model # noqa: F401
33+
from sagemaker.pipeline import PipelineModel # noqa: F401
3334
from sagemaker.predictor import RealTimePredictor # noqa: F401
3435
from sagemaker.session import Session # noqa: F401
35-
from sagemaker.session import container_def # noqa: F401
36+
from sagemaker.session import container_def, pipeline_container_def # noqa: F401
3637
from sagemaker.session import production_variant # noqa: F401
3738
from sagemaker.session import s3_input # noqa: F401
3839
from sagemaker.session import get_execution_role # noqa: F401

src/sagemaker/fw_registry.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License"). You
4+
# may not use this file except in compliance with the License. A copy of
5+
# the License is located at
6+
#
7+
# http://aws.amazon.com/apache2.0/
8+
#
9+
# or in the "license" file accompanying this file. This file is
10+
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11+
# ANY KIND, either express or implied. See the License for the specific
12+
# language governing permissions and limitations under the License.
13+
from __future__ import absolute_import
14+
import logging
15+
16+
image_registry_map = {
17+
"us-west-1": {
18+
"sparkml-serving": "746614075791",
19+
"scikit-learn": "746614075791"
20+
},
21+
"us-west-2": {
22+
"sparkml-serving": "246618743249",
23+
"scikit-learn": "246618743249"
24+
},
25+
"us-east-1": {
26+
"sparkml-serving": "683313688378",
27+
"scikit-learn": "683313688378"
28+
},
29+
"us-east-2": {
30+
"sparkml-serving": "257758044811",
31+
"scikit-learn": "257758044811"
32+
},
33+
"ap-northeast-1": {
34+
"sparkml-serving": "354813040037",
35+
"scikit-learn": "354813040037"
36+
},
37+
"ap-northeast-2": {
38+
"sparkml-serving": "366743142698",
39+
"scikit-learn": "366743142698"
40+
},
41+
"ap-southeast-1": {
42+
"sparkml-serving": "121021644041",
43+
"scikit-learn": "121021644041"
44+
},
45+
"ap-southeast-2": {
46+
"sparkml-serving": "783357654285",
47+
"scikit-learn": "783357654285"
48+
},
49+
"ap-south-1": {
50+
"sparkml-serving": "720646828776",
51+
"scikit-learn": "720646828776"
52+
},
53+
"eu-west-1": {
54+
"sparkml-serving": "141502667606",
55+
"scikit-learn": "141502667606"
56+
},
57+
"eu-west-2": {
58+
"sparkml-serving": "764974769150",
59+
"scikit-learn": "764974769150"
60+
},
61+
"eu-central-1": {
62+
"sparkml-serving": "492215442770",
63+
"scikit-learn": "492215442770"
64+
},
65+
"ca-central-1": {
66+
"sparkml-serving": "341280168497",
67+
"scikit-learn": "341280168497"
68+
},
69+
"us-gov-west-1": {
70+
"sparkml-serving": "414596584902",
71+
"scikit-learn": "414596584902"
72+
}
73+
}
74+
75+
76+
def registry(region_name, framework=None):
77+
"""
78+
Return docker registry for the given AWS region for the given framework.
79+
This is only used for SparkML and Scikit-learn for now.
80+
"""
81+
try:
82+
account_id = image_registry_map[region_name][framework]
83+
return "{}.dkr.ecr.{}.amazonaws.com".format(account_id, region_name)
84+
except KeyError:
85+
logging.error("The specific image or region does not exist")
86+
raise

src/sagemaker/model.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,13 @@
1515
import logging
1616

1717
import sagemaker
18-
19-
from sagemaker import local
20-
from sagemaker import fw_utils
21-
from sagemaker import session
22-
from sagemaker import utils
18+
from sagemaker import fw_utils, local, session, utils
2319

2420

2521
class Model(object):
2622
"""A SageMaker ``Model`` that can be deployed to an ``Endpoint``."""
2723

28-
def __init__(self, model_data, image, role, predictor_cls=None, env=None, name=None, vpc_config=None,
24+
def __init__(self, model_data, image, role=None, predictor_cls=None, env=None, name=None, vpc_config=None,
2925
sagemaker_session=None):
3026
"""Initialize an SageMaker ``Model``.
3127
@@ -34,8 +30,9 @@ def __init__(self, model_data, image, role, predictor_cls=None, env=None, name=N
3430
image (str): A Docker image URI.
3531
role (str): An AWS IAM role (either name or full ARN). The Amazon SageMaker training jobs and APIs
3632
that create Amazon SageMaker endpoints use this role to access training data and model artifacts.
37-
After the endpoint is created, the inference code might use the IAM role,
38-
if it needs to access an AWS resource.
33+
After the endpoint is created, the inference code might use the IAM role if it needs to access some AWS
34+
resources. It can be null if this is being used to create a Model to pass to a ``PipelineModel`` which
35+
has its own Role field. (default: None)
3936
predictor_cls (callable[string, sagemaker.session.Session]): A function to call to create
4037
a predictor (default: None). If not None, ``deploy`` will return the result of invoking
4138
this function on the created endpoint name.
@@ -89,6 +86,7 @@ def deploy(self, initial_instance_count, instance_type, endpoint_name=None, tags
8986
``Endpoint`` created from this ``Model``.
9087
endpoint_name (str): The name of the endpoint to create (default: None).
9188
If not specified, a unique endpoint name will be created.
89+
tags(List[dict[str, str]]): The list of tags to attach to this specific endpoint.
9290
9391
Returns:
9492
callable[string, sagemaker.session.Session] or None: Invocation of ``self.predictor_cls`` on
@@ -102,6 +100,8 @@ def deploy(self, initial_instance_count, instance_type, endpoint_name=None, tags
102100

103101
container_def = self.prepare_container_def(instance_type)
104102
self.name = self.name or utils.name_from_image(container_def['Image'])
103+
if self.role is None:
104+
raise ValueError("Role can not be null for deploying a model")
105105
self.sagemaker_session.create_model(self.name, self.role, container_def, vpc_config=self.vpc_config)
106106
production_variant = sagemaker.production_variant(self.name, instance_type, initial_instance_count)
107107
self.endpoint_name = endpoint_name or self.name

0 commit comments

Comments
 (0)