DEC 6, 2018
I wanted to get some content on this blog, so here's a tutorial on how to deploy a Scikit-learn model to the cloud. This allows us to use the model with web site such as React or a mobile app!
I started with the iris dataset to make things easy to get up and going. Here are some examples of the data that is included in the data set.
It consists of three species of flowers. Each flower has its own sepals and petals with a length and width.
We're going to be creating a fairly simple classifier.
import numpy as npimport pandas as pdfrom sklearn.model_selection import train_test_splitfrom sklearn.preprocessing import StandardScalerfrom sklearn.neighbors import KNeighborsClassifierdef get_classifier():url = "https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data"# Assign column names to the datasetnames = ['sepal-length', 'sepal-width', 'petal-length', 'petal-width', 'Class']# Read dataset to pandas dataframedataset = pd.read_csv(url, names=names)# Set features (x) and labels (y)X = dataset.iloc[:, :-1].valuesy = dataset.iloc[:, 4].values# Split the data into training and testingX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.20)# Fit the scalerscaler = StandardScaler()scaler.fit(X_train)# Apply the scaler to the data (0 to 1)X_train = scaler.transform(X_train)X_test = scaler.transform(X_test)# Create the classifierclassifier = KNeighborsClassifier(n_neighbors=10)classifier.fit(X_train, y_train)# We'll need to use the scaler and the classifier laterreturn scaler, classifier
We'll be using flask for our python server! Fun fact: Don't use flask for a sites that need to handle a lot of traffic. It was actually created as an April's fool joke.. But for our purposes, it'll work fine!
Here's the code to create a bare minimum server:
from flask import Flask, request# initialize the flask appapp = Flask(__name__)@app.route('/')def hello_world():return "Hello World!"if __name__ == '__main__':app.run(debug=True,host='0.0.0.0')
Now, let's pull in our classifier so that we can use with with requests.
from classifier import get_classifier# build the classifierscaler, classifier = get_classifier()
Now, let's add a route for our predictions
import json@app.route('/predict')def make_prediction():if not request.get_json():abort(400)request_data = request.get_json()s_l = float(request_data.get("sepal_length"))s_w = float(request_data.get("sepal_width"))p_l = float(request_data.get("petal_length"))p_w = float(request_data.get("petal_width"))x = [[s_l, s_w, p_l, p_w]]x_transformed = scaler.transform(x)result = classifier.predict(x_transformed)return str(result[0])
See the final code for the server in server.py
.
After paying for a server, you could set up the server, install python and all the necessary requirements. But that's a pain for everyone.
To make it easier, we're going to build a Docker container that contains everything the server needs to run.
Here is the Dockerfile that describes how we want the server to run.
FROM ubuntu:latestRUN apt-get update -yRUN apt-get install -y python-pip python-dev build-essentialCOPY . /appWORKDIR /appRUN pip install -r requirements.txtENTRYPOINT ["python"]CMD ["server.py"]
While in the directory of your server and Dockerfile, type
docker build -t my-name/my-model .^ ^container name location of Dockerfile
You can then push that docker container up to docker hub by typing
docker push my-name/my-model
Then pull the container down on your server (such as AWS, Digital Ocean, or GCP)
docker pull my-name/my-model
Then start the server on that machine!
docker run -d -p 5000:5000 --restart unless-stopped my-name/my-model
You can then request your site by calling a POST request at {host}:5000/predict
or just by running on your local machine at localhost:5000/predict
. I would recommend using Postman with application/json as the request body type. Below are some examples of requests that can be sent and their corresponding predictions!
{"sepal_length": 6,"sepal_width": 2.8,"petal_length": 4,"petal_width": 1.3}
{"sepal_length": 7,"sepal_width": 3,"petal_length": 6,"petal_width": 2}
{"sepal_length": 5,"sepal_width": 4,"petal_length": 1,"petal_width": 0.3}