Deploy scikit-learn model with Turi Predictive Services

Deploying models created using scikit-learn in a Turi Predictive Service is very easy. This notebook walks you through the step-by-step process. The notebook has three sections:

  1. Create a Predictive Service
  2. Create a scikit-learn model and deploy it to a Predictive Service
  3. Query the model through CURL or a Predictive Service Client

If you are deploying a model in an existing Predictive Service instance you can go to step two directly.

Prerequisites

Apart from GraphLab Create you will, naturally, need scikit-learn installed in your current Python environment. The most straightforward way to do that is to use conda:

conda install scikit-learn

You will also need a valid AWS account in order to set up a predictive service.

Step one: Create a Predictive Service

This section shows you how to deploy a Predictive Service to EC2. The EC2 instances used by the Predictive Service will be launched in your own AWS account, so you will be responsible for the cost.

To create a Predictive Service in Amazon AWS, we first configure the EC2 Config object, which contains the configuration parameters required for launching a Predictive Service cluster in EC2. These fields are optional and include the region, instance type, CIDR rules etc. Predictive Service uses this configuration for service creation.

Having configured our EC2 Config object, we're ready to launch a Predictive Service Deployment, There are a few aspects of the Predictive Service that can be customized:

  • Number of nodes in the service - By default the number of hosts (num_hosts) is 1. To obtain good cache utility and high availability, we recommended setting num_hosts to at least 3.
  • State path to persist service state and service logs. This is a s3 location.
  • Port to be used by the server.
  • Other settings, such as SSL credentials etc.

The following code snippet shows you how to create a Predictive Service. You will have to replace the ps_state_path and credentials for your Predictive Service.


In [ ]:
import graphlab as gl

# make sure to replace the following with your own information
ps_state_path = 's3://<your-bucket-name>/predictive_service/ps'

# Create an EC2 config
# You can either specify your AWS credentials using environment variables, or
# set them as arguments to this object's constructor
ec2_config = gl.deploy.Ec2Config(
    aws_access_key_id='<your access key>',
    aws_secret_access_key='<your secret key>')

# use the EC2 config to launch a new Predictive Service
# num_hosts specifies how many hosts the Predictive Service cluster has. You can scale up and down later after initial creation.
ps = gl.deploy.predictive_service.create(
    name='sklearn-predictive-service',
    ec2_config=ec2_config,
    state_path=ps_state_path,
    num_hosts=1)

In [5]:
# once the Predictive Service is successfully created, you can query the service status
ps.get_status()


Out[5]:
[{u'cache': {u'healthy': True, u'num_keys': 0, u'type': u'local'},
  u'dns_name': u'ec2-52-34-231-117.us-west-2.compute.amazonaws.com',
  u'id': u'i-992d1540',
  u'models': [],
  u'num_hosts': 1,
  u'reason': u'N/A',
  u'service_version': u'1.7.1',
  u'state': u'InService'}]

Step two: Create a scikit-learn model and deploy to Predictive Service

Let's train a simple random forest model and deploy it in the Predictive Service


In [6]:
from sklearn.ensemble import RandomForestClassifier
X = [[0, 0], [1, 1]]
Y = [0, 1]
clf = RandomForestClassifier(n_estimators=10)
clf = clf.fit(X, Y)

We can expose the trained model as a REST endpoint in the Predictive Service. This will allow other applications to consume the predictions from the model.

In order to do that, we wrap the model object in a Python function and add it to the Predictive Service. In the function you may add your own logic for transform input to the model, ensemble different models or manipulate output before returning. Checkout our user guide for more details.

The result of the function needs to be a JSON serializable object.


In [7]:
def classify(x):
    prediction = clf.predict(x)

    # convert into a json serializable value
    return list(prediction)

# add your predictive function that wraps scikit-learn model
ps.add('classify', classify)


[INFO] Endpoint 'classify' is added. Use apply_changes() to deploy all pending changes, or continue with other modification.

You may do a test query before really deploying it to production. This will help detect errors in the function before deploying it the Predictive Service.

The response to a query is a JSON object with the following keys:

* response: is the actual response from the query;
* uuid: is the unique identifier for your query. The 'uuid' is useful when you need to correlated the query with other data you potentially have for future model tuning.
* version: is the model version. This is useful when you are updating model and you want to know exactly which version served your query

In [8]:
ps.test_query('classify', x=[[0,0],[1,1]])


[INFO] Input data serializable.
[INFO] Trying to serve classify
[INFO] Query results serializable.
Out[8]:
{u'response': [0, 1],
 u'uuid': u'9277467f-fc55-40ee-8125-403f95660840',
 u'version': 1}

It is as expected, let us apply the changes and the predictive model is ready to go!


In [ ]:
# This will push the custom query to the Predictive Service. Since the update is asynchronous, you may need to wait 
# a little while before the model is fully deployed.
ps.apply_changes()

Check status and make sure the deployed custom predictive object is fully operational:


In [10]:
# There are other variable way of query status, check API document for more details
ps.get_status('model')


Out[10]:
name expected version type reason node.i-992d1540
classify 1 model N/A 1 (Loaded successfully)
[? rows x 5 columns]
Note: Only the head of the SFrame is printed. This SFrame is lazily evaluated.
You can use len(sf) to force materialization.

In [11]:
# test query to make sure the model works fine
ps.query('classify', x=[[0,0],[1,1]])


Out[11]:
{u'from_cache': False,
 u'model': u'classify',
 u'response': [0, 1],
 u'uuid': u'05c773c5-a3e0-4783-bca6-a8925fb20a0c',
 u'version': 1}

Now other applications can interact with our model! In the next section we will illustrate how to consume the model. We can also use other APIs like ps.update() to update a model and ps.remove() to remove a model.

Turi Predictive Services includes a stand-alone Python client for those who just want to query a running service. We will show you how to use the client in the following section. The client takes a configuration file containing the endpoint of the Predictive Service and API key used by client. You can generate the Python client configuration using the following call and hand off the configuration file to your consumer.


In [ ]:
# Generate a client configuration file for Predictive Service Client to consume
# It is a good practice to config a CNAME entry in your DNS provider to have a well known endpoint
# like https://models.companyname.com to point to the Predictive Service so that the consumer of
# the Predictive Service do not need to change their code when you make modifications to your
# Predictive Service
# Here we use None only for demo purpose
ps.save_client_config(file_path='/tmp/ps_client.conf', predictive_service_cname = None)

Once generated, the ps_client.conf file may be passed along to your client side developer. We will show you how to use the file in next section.

Step three: query the model through REST api and Python client

Query through REST

The model query is exposed through REST API. The endpoints URL is:

http(s)://<your-ps-endpoint-base>/query/<model-name>

You can find out the endpoint URL base by simply printing the ps object, and copying the Load Balancer DNS Name.

The HTTP call for querying a model or method is a POST call, requiring a JSON-serialized string in the following format as payload:

{ "data": <parameters to model or custom method> }

You also need a valid API key, which you can retreive through ps.api_key.

Here is a sample curl command to query the classify method that we deployed in this notebook:

curl -u api_key:<your-api-key> -d '{"data": {"x": [[0,0],[1,1]]}}'
    http://<your-ps-endpoint-base>/query/classify

Query through Python

We also ship a Python client package that you may easily consume the model. To install the package, do:

pip install GraphLab-Service-Client  

After that you may consume the Predictive Model:


In [14]:
from graphlab_service_client import PredictiveServiceClient

# the configuration is saved through ps.save_client_config()
client = PredictiveServiceClient(config_file='/tmp/ps_client.conf')

client.query('classify', x=[[0,0], [1,1]])


Out[14]:
{u'from_cache': True,
 u'model': u'classify',
 u'response': [0, 1],
 u'uuid': u'661f8381-e01c-414c-9fe6-4738bfaa28c2',
 u'version': 1}

Shutting down the predictive service

If you don't need to keep you predictive service around for further tasks, make sure to terminate it to avoid incurring unnecessary costs:


In [15]:
ps.terminate_service()


[INFO] Deleting load balancer: sklearn-predictive-service
[INFO] Terminating EC2 host(s) [u'i-992d1540'] in us-west-2
[INFO] Deleting state data.
[INFO] Deleting s3 state data.
[INFO] Deleting keys: []
[INFO] Deleting keys: [u'user/scikit-ps/predictive_objects/classify/1/pickle_archive', u'user/scikit-ps-new/predictive_objects/classify/1/version']
[INFO] Deleted reference to PredictiveService('sklearn-predictive-service') from current session.

Where to go from here

This notebook gives you a peek at what Turi Predictive Service can offer. For a more detailed look at the functionalities in the Turi Predictive Service, checkout out user guide for more details. If you have any questions, post it in our forum and we are happy to assist you!