[Serve] RayServe TF, PyTorch, Sklearn Examples (#8156)

This commit is contained in:
Simon Mo
2020-04-28 22:24:55 -07:00
committed by GitHub
parent af3d3e778e
commit 101255f782
10 changed files with 441 additions and 3 deletions
+24
View File
@@ -63,3 +63,27 @@ py_test(
tags = ["exclusive"],
deps = [":serve_lib"]
)
py_test(
name = "tutorial_tensorflow",
size = "small",
srcs = glob(["examples/doc/*.py"]),
tags = ["exclusive"],
deps = [":serve_lib"]
)
py_test(
name = "tutorial_pytorch",
size = "small",
srcs = glob(["examples/doc/*.py"]),
tags = ["exclusive"],
deps = [":serve_lib"]
)
py_test(
name = "tutorial_sklearn",
size = "small",
srcs = glob(["examples/doc/*.py"]),
tags = ["exclusive"],
deps = [":serve_lib"]
)
@@ -0,0 +1,63 @@
# yapf: disable
# __doc_import_begin__
from ray import serve
from io import BytesIO
from PIL import Image
import requests
import torch
from torchvision import transforms
from torchvision.models import resnet18
# __doc_import_end__
# yapf: enable
# __doc_define_servable_begin__
class ImageModel:
def __init__(self):
self.model = resnet18(pretrained=True)
self.preprocessor = transforms.Compose([
transforms.Resize(224),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Lambda(lambda t: t[:3, ...]), # remove alpha channel
])
def __call__(self, flask_request):
image_payload_bytes = flask_request.data
pil_image = Image.open(BytesIO(image_payload_bytes))
print("[1/3] Parsed image data: {}".format(pil_image))
pil_images = [pil_image] # Our current batch size is one
input_tensor = torch.cat(
[self.preprocessor(i).unsqueeze(0) for i in pil_images])
print("[2/3] Images transformed, tensor shape {}".format(
input_tensor.shape))
with torch.no_grad():
output_tensor = self.model(input_tensor)
print("[3/3] Inference done!")
return {"class_index": int(torch.argmax(output_tensor[0]))}
# __doc_define_servable_end__
# __doc_deploy_begin__
serve.init()
serve.create_endpoint("predictor", "/image_predict", methods=["POST"])
serve.create_backend(ImageModel, "resnet18:v0")
serve.set_traffic("predictor", {"resnet18:v0": 1})
# __doc_deploy_end__
# __doc_query_begin__
ray_logo_bytes = requests.get(
"https://github.com/ray-project/ray/raw/"
"master/doc/source/images/ray_header_logo.png").content
resp = requests.post(
"http://localhost:8000/image_predict", data=ray_logo_bytes)
print(resp.json())
# Output
# {'class_index': 463}
# __doc_query_end__
@@ -0,0 +1,87 @@
# yapf: disable
# __doc_import_begin__
from ray import serve
import pickle
import json
import numpy as np
import requests
from sklearn.datasets import load_iris
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.metrics import mean_squared_error
# __doc_import_end__
# yapf: enable
# __doc_train_model_begin__
# Load data
data, target, target_names, description, feature_names, _ = load_iris().values(
)
# Instantiate 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:]
# Train and evaluate models
model.fit(train_x, train_y)
print("MSE:", mean_squared_error(model.predict(val_x), val_y))
# Save the model and label to file
with open("/tmp/iris_model_logistic_regression.pkl", "wb") as f:
pickle.dump(model, f)
with open("/tmp/iris_labels.json", "w") as f:
json.dump(target_names.tolist(), f)
# __doc_train_model_end__
# __doc_define_servable_begin__
class BoostingModel:
def __init__(self):
with open("/tmp/iris_model_logistic_regression.pkl", "rb") as f:
self.model = pickle.load(f)
with open("/tmp/iris_labels.json") as f:
self.label_list = json.load(f)
def __call__(self, flask_request):
payload = flask_request.json
print("Worker: received flask request with data", payload)
input_vector = [
payload["sepal length"],
payload["sepal width"],
payload["petal length"],
payload["petal width"],
]
prediction = self.model.predict([input_vector])[0]
human_name = self.label_list[prediction]
return {"result": human_name}
# __doc_define_servable_end__
# __doc_deploy_begin__
serve.init()
serve.create_endpoint("iris_classifier", "/regressor")
serve.create_backend(BoostingModel, "lr:v1")
serve.set_traffic("iris_classifier", {"lr:v1": 1})
# __doc_deploy_end__
# __doc_query_begin__
sample_request_input = {
"sepal length": 1.2,
"sepal width": 1.0,
"petal length": 1.1,
"petal width": 0.9,
}
response = requests.get(
"http://localhost:8000/regressor", json=sample_request_input)
print(response.text)
# Result:
# {
# "result": "versicolor"
# }
# __doc_query_end__
@@ -0,0 +1,86 @@
# yapf: disable
# __doc_import_begin__
from ray import serve
import os
import numpy as np
import requests
# __doc_import_end__
# yapf: enable
# __doc_train_model_begin__
TRAINED_MODEL_PATH = "/tmp/mnist_model.h5"
def train_and_save_model():
import tensorflow as tf
# Load mnist dataset
mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0
# Train a simple neural net model
model = tf.keras.models.Sequential([
tf.keras.layers.Flatten(input_shape=(28, 28)),
tf.keras.layers.Dense(128, activation="relu"),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Dense(10)
])
loss_fn = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
model.compile(optimizer="adam", loss=loss_fn, metrics=["accuracy"])
model.fit(x_train, y_train, epochs=1)
model.evaluate(x_test, y_test, verbose=2)
model.summary()
# Save the model in h5 format in local file system
model.save(TRAINED_MODEL_PATH)
if not os.path.exists(TRAINED_MODEL_PATH):
train_and_save_model()
# __doc_train_model_end__
# __doc_define_servable_begin__
class TFMnistModel:
def __init__(self, model_path):
import tensorflow as tf
self.model_path = model_path
self.model = tf.keras.models.load_model(model_path)
def __call__(self, flask_request):
# Step 1: transform HTTP request -> tensorflow input
# Here we define the request schema to be a json array.
input_array = np.array(flask_request.json["array"])
reshaped_array = input_array.reshape((1, 28, 28))
# Step 2: tensorflow input -> tensorflow output
prediction = self.model(reshaped_array)
# Step 3: tensorflow output -> web output
return {
"prediction": prediction.numpy().tolist(),
"file": self.model_path
}
# __doc_define_servable_end__
# __doc_deploy_begin__
serve.init()
serve.create_endpoint(endpoint_name="tf_classifier", route="/mnist")
serve.create_backend(TFMnistModel, "tf:v1", "/tmp/mnist_model.h5")
serve.set_traffic("tf_classifier", {"tf:v1": 1})
# __doc_deploy_end__
# __doc_query_begin__
resp = requests.get(
"http://localhost:8000/mnist",
json={"array": np.random.randn(28 * 28).tolist()})
print(resp.json())
# {
# "prediction": [[-1.504277229309082, ..., -6.793371200561523]],
# "file": "/tmp/mnist_model.h5"
# }
# __doc_query_end__