Skip to content

Commit

Permalink
Added a hands-on self-containted MLflow/Ray Serve deployment example (r…
Browse files Browse the repository at this point in the history
  • Loading branch information
dmatrix authored and simonsays1980 committed Feb 27, 2022
1 parent 0087777 commit 585ab66
Showing 1 changed file with 149 additions and 0 deletions.
149 changes: 149 additions & 0 deletions doc/source/serve/ml-models.rst
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,155 @@ To serve multiple different MLflow models in the same program, use the ``name``
The above approach will work for any model registry, not just MLflow.
Namely, load the model from the registry in ``__init__``, and forward the request to the model in ``__call__``.

For a complete hands-on and seamless integration with MLflow, try this self-contained example on your laptop.
But first install ``mlflow``.

.. code-block:: bash
pip install mlflow
.. code-block:: python
# This brief example shows how to deploy models saved in a model registry such as
# MLflow to Ray Serve, using the simple Ray Serve deployment APIs. You can peruse
# the saved models' metrics and parameters in MLflow ui.
#
import json
import numpy as np
import pandas as pd
import requests
import os
import tempfile
from sklearn.datasets import load_iris
from sklearn.ensemble import GradientBoostingClassifier
from mlflow.tracking import MlflowClient
from ray import serve
import mlflow
def create_and_save_model():
# load Iris data
iris_data = load_iris()
data, target, target_names = (iris_data['data'],
iris_data['target'],
iris_data['target_names'])
# Instantiate a model
model = GradientBoostingClassifier()
# Training and validation split
np.random.shuffle(data), np.random.shuffle(target)
train_x, train_y = data[:100], target[:100]
val_x, val_y = data[100:], target[100:]
# Create labels list as file
LABEL_PATH = os.path.join(tempfile.gettempdir(), "iris_labels.json")
with open(LABEL_PATH, "w") as f:
json.dump(target_names.tolist(), f)
# Train the model and save our label list as an MLflow artifact
# mlflow.sklearn.autolog automatically logs all parameters and metrics during
# the training.
mlflow.sklearn.autolog()
with mlflow.start_run() as run:
model.fit(train_x, train_y)
# Log label list as a artifact
mlflow.log_artifact(LABEL_PATH, artifact_path="labels")
return run.info.run_id
#
# Create our Ray Serve deployment class
#
@serve.deployment(route_prefix="/regressor")
class BoostingModel:
def __init__(self, uri):
# Load the model and label artifact from the local
# Mlflow model registry as a PyFunc Model
self.model = mlflow.pyfunc.load_model(model_uri=uri)
# Download the artifact list of labels
local_dir = "/tmp/artifact_downloads"
if not os.path.exists(local_dir):
os.mkdir(local_dir)
client = MlflowClient()
local_path = f"{client.download_artifacts(run_id, 'labels', local_dir)}/iris_labels.json"
with open(local_path, "r") as f:
self.label_list = json.load(f)
async def __call__(self, starlette_request):
payload = await starlette_request.json()
print(f"Worker: received Starlette request with data: {payload}")
# Get the input vector from the payload
input_vector = [
payload["sepal length"],
payload["sepal width"],
payload["petal length"],
payload["petal width"],
]
# Convert the input vector in a Pandas DataFrame for prediction since
# an MLflow PythonFunc model, model.predict(...), takes pandas DataFrame
prediction = self.model.predict(pd.DataFrame([input_vector]))[0]
human_name = self.label_list[prediction]
return {"result": human_name}
if __name__ == '__main__':
# Train and save the model artifacts in MLflow.
# Here our MLflow model registry is local file
# directory ./mlruns
run_id = create_and_save_model()
# Start the Ray Serve instance
serve.start()
# Construct model uri to load the model from our model registry
uri = f"runs:/{run_id}/model"
# Deploy our model.
BoostingModel.deploy(uri)
# Send in a request for labels types virginica, setosa, versicolor
sample_request_inputs = [{
"sepal length": 6.3,
"sepal width": 3.3,
"petal length": 6.0,
"petal width": 2.5},
{
"sepal length": 5.1,
"sepal width": 3.5,
"petal length": 1.4,
"petal width": 0.2},
{
"sepal length": 6.4,
"sepal width": 3.2,
"petal length": 4.5,
"petal width": 1.5},
]
for input_request in sample_request_inputs:
response = requests.get("http://localhost:8000/regressor",
json=input_request)
print(response.text)
print("Launch MLflow ui to see the model parameters, metrics, and artifacts: `mlflow ui` from current directory.")
#output
#{
# "result": "versicolor"
#}
#{
# "result": "virginica"
#}
#{
# "result": "setosa"
#}
#
# Launch MLflow ui to see the model parameters, metrics, and artifacts: `mlflow ui` from current directory.
For an even more hands-off and seamless integration with MLflow, check out the
`Ray Serve MLflow deployment plugin <https://github.com/ray-project/mlflow-ray-serve>`__. A full
tutorial is available `here <https://github.com/mlflow/mlflow/tree/master/examples/ray_serve>`__.
Expand Down

0 comments on commit 585ab66

Please sign in to comment.