This would be the first part of a three part write up on deploying Machine Learning cloud on a server-less cloud environment. In each of the three parts – I would be focusing on deploying to the GCP, Azure and AWS environments respectively.
Code
The very first step would be to get the ML code ready for the deployment. There are two parts to the code. The first part is the code that I would put into the cloud environment – that would make my ML models available as a REST API service. In this code, I don’t do any model training. I just call joblib files that contain the pre-trained models and the data-cleaning / pre-processing steps that handle the inbound data : before feeding them into the models for predicting.
Here is that code:
import numpy as np
import pandas as pd
import requests
import joblib
from google.cloud import storage
def predictor(request):
if request.method == 'GET':
return 'Welcome to Rajivs Car Price Predictor'
if request.method == 'POST':
data = pd.DataFrame(request.get_json(force=True))
data2 = pd.get_dummies(data)
##Open Blob stored model
storage_client = storage.Client()
bucket = storage_client.get_bucket('rajivs-car-price-predictor')
blob = bucket.blob('models/lr_checkpoint.joblib')
blob.download_to_filename('/tmp/model.joblib')
model = joblib.load(open('/tmp/model.joblib', 'rb'))
###Start working with model
lr_obj = model['model']
modelcolumns_obj = model['modelcolumns']
data2 = data2.reindex(columns=modelcolumns_obj, fill_value=0)
pred1 = lr_obj.predict(data2)
output_text = "Text:" + str(data2) + "\nPredicted Class Is: " + str(pred1)
return output_text
As you can see from the above code – this is about a car price predictor model. The training and testing data for this model can be found here
And here is the code that goes to create the joblib file
import pandas as pd
import numpy as np
import sklearn
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score
#
infile = pd.read_csv('CarPrice_Assignment.csv')
infile.drop(['car_ID', 'symboling', 'CarName'], axis=1, inplace=True)
#
X = infile.drop('price', axis=1)
Y = infile['price']
#
X = pd.get_dummies(X)
model_columns = list(X.columns)
#
x_train, x_test, y_train, y_test = train_test_split(X, Y, test_size=0.2, random_state=5)
#
lr = LinearRegression().fit(x_train, y_train)
y_pred = lr.predict(x_test)
r2_score(y_pred, y_test)
#
###Serialize Joblib
!pip install joblib
import joblib
#
scikit_version = sklearn.__version__
scikit_version
#
regressor_model = {}
regressor_model['modelcolumns'] = model_columns
regressor_model['model'] = lr
regressor_model['sklearn_version'] = scikit_version
regressor_model['accuracy'] = r2_score
#
filename = 'models/lr_checkpoint.joblib'
joblib.dump(regressor_model, filename)
Also I mentioned above – the lr_checkpoint.joblib contains the model and the pre-processing encoding data transformers. In this case I’ve used one-hot encoding. The model itself is a simple linear-regression model. Here is what the joblib looks like:
{'modelcolumns': ['wheelbase',
'carlength',
'carwidth',
'carheight',
'curbweight',
'enginesize',
'boreratio',
'stroke',
'compressionratio',
'horsepower',
'peakrpm',
'citympg',
'highwaympg',
'fueltype_diesel',
'fueltype_gas',
'aspiration_std',
'aspiration_turbo',
'doornumber_four',
'doornumber_two',
'carbody_convertible',
'carbody_hardtop',
'carbody_hatchback',
'carbody_sedan',
'carbody_wagon',
'drivewheel_4wd',
'drivewheel_fwd',
'drivewheel_rwd',
'enginelocation_front',
'enginelocation_rear',
'enginetype_dohc',
'enginetype_dohcv',
'enginetype_l',
'enginetype_ohc',
'enginetype_ohcf',
'enginetype_ohcv',
'enginetype_rotor',
'cylindernumber_eight',
'cylindernumber_five',
'cylindernumber_four',
'cylindernumber_six',
'cylindernumber_three',
'cylindernumber_twelve',
'cylindernumber_two',
'fuelsystem_1bbl',
'fuelsystem_2bbl',
'fuelsystem_4bbl',
'fuelsystem_idi',
'fuelsystem_mfi',
'fuelsystem_mpfi',
'fuelsystem_spdi',
'fuelsystem_spfi'],
'sklearn_version': '0.19.1',
'accuracy': <function sklearn.metrics.regression.r2_score(y_true, y_pred, sample_weight=None, multioutput='uniform_average')>,
'model': LinearRegression(copy_X=True, fit_intercept=True, n_jobs=1, normalize=False)}
Cloud Deployment Steps
Here are the various steps listed below to make your ML model available on the GCP cloud, as a REST API service : leveraging GCP’s server-less setup.
Step 1 : Account Creation
You can use your gmail account to sign up to the GCP platform . Once there you would have to create a ‘project’. This is like a folder where all the resources that you need for a project can reside.
Once created the login dashboard would look like this – with the project (which I’ve highlighted in red underlining )
Step 2 : Uploading models to Google Cloud Storage bucket
Go to the hamburger icon on the top left and follow the navigation options mentioned below:
You can then create your storage in the next screen that appears like this:
In my case I’ve created a storage space called rajivs-car-price-predictor like this. The configuration parameters that I’ve used are seen below as well
Next you can create a folder in the storage space. In my case I have created something called as models
Finally click on Upload Files and upload the joblib file. In our case lr_checkpoint.joblib
Step 3 : Create a Server-less function
The first step here is to create a function. For this you click on the hamburger icon on the top left and choose the option Cloud Functions as shown below:
Create a new Cloud Function
In the above default screen that appears – I make changes which eventually reflect as below. Please note that I choose Runtime option of Python.
After creating the Function – the General tab would show like this for me:
Trigger shows me details of the type of trigger and the end-point URL of the REST API
Essentially the trigger function is a key part of a server-less environment. What it simply means is that when an inbound HTTP request comes to the end-point URL – then the application comes on and serves the inbound request.
The Source tab looks like this. This is where the triggering code/function is pasted. When you click the expand button – then you can see the full code – as shown in the screen below:
If you notice, in the above screen there is an option for Function to Execute which shows the function inside the code that would execute.
The requirements.txt option takes the dependent packages that are needed to execute our code/function. Here is what I’ve given
Finally once this is all done – you would need to test it out. As you know, we have the test data in the CarPrice_Test file (refer the initial parts of this write up – above). We need to convert it into json format. You can use any online csv to json converter. I used this
Post conversion – the json data looks like this. I’ve made it easy for you to just copy the json from here below 🙂 🙂
[
{
"car_ID": 191,
"symboling": 3,
"CarName": "vw rabbit",
"fueltype": "gas",
"aspiration": "std",
"doornumber": "two",
"carbody": "hatchback",
"drivewheel": "fwd",
"enginelocation": "front",
"wheelbase": 94.5,
"carlength": 165.7,
"carwidth": 64,
"carheight": 51.4,
"curbweight": 2221,
"enginetype": "ohc",
"cylindernumber": "four",
"enginesize": 109,
"fuelsystem": "mpfi",
"boreratio": 3.19,
"stroke": 3.4,
"compressionratio": 8.5,
"horsepower": 90,
"peakrpm": 5500,
"citympg": 24,
"highwaympg": 29
},
{
"car_ID": 192,
"symboling": 0,
"CarName": "volkswagen rabbit",
"fueltype": "gas",
"aspiration": "std",
"doornumber": "four",
"carbody": "sedan",
"drivewheel": "fwd",
"enginelocation": "front",
"wheelbase": 100.4,
"carlength": 180.2,
"carwidth": 66.9,
"carheight": 55.1,
"curbweight": 2661,
"enginetype": "ohc",
"cylindernumber": "five",
"enginesize": 136,
"fuelsystem": "mpfi",
"boreratio": 3.19,
"stroke": 3.4,
"compressionratio": 8.5,
"horsepower": 110,
"peakrpm": 5500,
"citympg": 19,
"highwaympg": 24
},
{
"car_ID": 193,
"symboling": 0,
"CarName": "volkswagen rabbit custom",
"fueltype": "diesel",
"aspiration": "turbo",
"doornumber": "four",
"carbody": "sedan",
"drivewheel": "fwd",
"enginelocation": "front",
"wheelbase": 100.4,
"carlength": 180.2,
"carwidth": 66.9,
"carheight": 55.1,
"curbweight": 2579,
"enginetype": "ohc",
"cylindernumber": "four",
"enginesize": 97,
"fuelsystem": "idi",
"boreratio": 3.01,
"stroke": 3.4,
"compressionratio": 23,
"horsepower": 68,
"peakrpm": 4500,
"citympg": 33,
"highwaympg": 38
},
{
"car_ID": 194,
"symboling": 0,
"CarName": "volkswagen dasher",
"fueltype": "gas",
"aspiration": "std",
"doornumber": "four",
"carbody": "wagon",
"drivewheel": "fwd",
"enginelocation": "front",
"wheelbase": 100.4,
"carlength": 183.1,
"carwidth": 66.9,
"carheight": 55.1,
"curbweight": 2563,
"enginetype": "ohc",
"cylindernumber": "four",
"enginesize": 109,
"fuelsystem": "mpfi",
"boreratio": 3.19,
"stroke": 3.4,
"compressionratio": 9,
"horsepower": 88,
"peakrpm": 5500,
"citympg": 25,
"highwaympg": 31
},
{
"car_ID": 195,
"symboling": -2,
"CarName": "volvo 145e (sw)",
"fueltype": "gas",
"aspiration": "std",
"doornumber": "four",
"carbody": "sedan",
"drivewheel": "rwd",
"enginelocation": "front",
"wheelbase": 104.3,
"carlength": 188.8,
"carwidth": 67.2,
"carheight": 56.2,
"curbweight": 2912,
"enginetype": "ohc",
"cylindernumber": "four",
"enginesize": 141,
"fuelsystem": "mpfi",
"boreratio": 3.78,
"stroke": 3.15,
"compressionratio": 9.5,
"horsepower": 114,
"peakrpm": 5400,
"citympg": 23,
"highwaympg": 28
},
{
"car_ID": 196,
"symboling": -1,
"CarName": "volvo 144ea",
"fueltype": "gas",
"aspiration": "std",
"doornumber": "four",
"carbody": "wagon",
"drivewheel": "rwd",
"enginelocation": "front",
"wheelbase": 104.3,
"carlength": 188.8,
"carwidth": 67.2,
"carheight": 57.5,
"curbweight": 3034,
"enginetype": "ohc",
"cylindernumber": "four",
"enginesize": 141,
"fuelsystem": "mpfi",
"boreratio": 3.78,
"stroke": 3.15,
"compressionratio": 9.5,
"horsepower": 114,
"peakrpm": 5400,
"citympg": 23,
"highwaympg": 28
},
{
"car_ID": 197,
"symboling": -2,
"CarName": "volvo 244dl",
"fueltype": "gas",
"aspiration": "std",
"doornumber": "four",
"carbody": "sedan",
"drivewheel": "rwd",
"enginelocation": "front",
"wheelbase": 104.3,
"carlength": 188.8,
"carwidth": 67.2,
"carheight": 56.2,
"curbweight": 2935,
"enginetype": "ohc",
"cylindernumber": "four",
"enginesize": 141,
"fuelsystem": "mpfi",
"boreratio": 3.78,
"stroke": 3.15,
"compressionratio": 9.5,
"horsepower": 114,
"peakrpm": 5400,
"citympg": 24,
"highwaympg": 28
},
{
"car_ID": 198,
"symboling": -1,
"CarName": "volvo 245",
"fueltype": "gas",
"aspiration": "std",
"doornumber": "four",
"carbody": "wagon",
"drivewheel": "rwd",
"enginelocation": "front",
"wheelbase": 104.3,
"carlength": 188.8,
"carwidth": 67.2,
"carheight": 57.5,
"curbweight": 3042,
"enginetype": "ohc",
"cylindernumber": "four",
"enginesize": 141,
"fuelsystem": "mpfi",
"boreratio": 3.78,
"stroke": 3.15,
"compressionratio": 9.5,
"horsepower": 114,
"peakrpm": 5400,
"citympg": 24,
"highwaympg": 28
},
{
"car_ID": 199,
"symboling": -2,
"CarName": "volvo 264gl",
"fueltype": "gas",
"aspiration": "turbo",
"doornumber": "four",
"carbody": "sedan",
"drivewheel": "rwd",
"enginelocation": "front",
"wheelbase": 104.3,
"carlength": 188.8,
"carwidth": 67.2,
"carheight": 56.2,
"curbweight": 3045,
"enginetype": "ohc",
"cylindernumber": "four",
"enginesize": 130,
"fuelsystem": "mpfi",
"boreratio": 3.62,
"stroke": 3.15,
"compressionratio": 7.5,
"horsepower": 162,
"peakrpm": 5100,
"citympg": 17,
"highwaympg": 22
},
{
"car_ID": 200,
"symboling": -1,
"CarName": "volvo diesel",
"fueltype": "gas",
"aspiration": "turbo",
"doornumber": "four",
"carbody": "wagon",
"drivewheel": "rwd",
"enginelocation": "front",
"wheelbase": 104.3,
"carlength": 188.8,
"carwidth": 67.2,
"carheight": 57.5,
"curbweight": 3157,
"enginetype": "ohc",
"cylindernumber": "four",
"enginesize": 130,
"fuelsystem": "mpfi",
"boreratio": 3.62,
"stroke": 3.15,
"compressionratio": 7.5,
"horsepower": 162,
"peakrpm": 5100,
"citympg": 17,
"highwaympg": 22
},
{
"car_ID": 201,
"symboling": -1,
"CarName": "volvo 145e (sw)",
"fueltype": "gas",
"aspiration": "std",
"doornumber": "four",
"carbody": "sedan",
"drivewheel": "rwd",
"enginelocation": "front",
"wheelbase": 109.1,
"carlength": 188.8,
"carwidth": 68.9,
"carheight": 55.5,
"curbweight": 2952,
"enginetype": "ohc",
"cylindernumber": "four",
"enginesize": 141,
"fuelsystem": "mpfi",
"boreratio": 3.78,
"stroke": 3.15,
"compressionratio": 9.5,
"horsepower": 114,
"peakrpm": 5400,
"citympg": 23,
"highwaympg": 28
},
{
"car_ID": 202,
"symboling": -1,
"CarName": "volvo 144ea",
"fueltype": "gas",
"aspiration": "turbo",
"doornumber": "four",
"carbody": "sedan",
"drivewheel": "rwd",
"enginelocation": "front",
"wheelbase": 109.1,
"carlength": 188.8,
"carwidth": 68.8,
"carheight": 55.5,
"curbweight": 3049,
"enginetype": "ohc",
"cylindernumber": "four",
"enginesize": 141,
"fuelsystem": "mpfi",
"boreratio": 3.78,
"stroke": 3.15,
"compressionratio": 8.7,
"horsepower": 160,
"peakrpm": 5300,
"citympg": 19,
"highwaympg": 25
},
{
"car_ID": 203,
"symboling": -1,
"CarName": "volvo 244dl",
"fueltype": "gas",
"aspiration": "std",
"doornumber": "four",
"carbody": "sedan",
"drivewheel": "rwd",
"enginelocation": "front",
"wheelbase": 109.1,
"carlength": 188.8,
"carwidth": 68.9,
"carheight": 55.5,
"curbweight": 3012,
"enginetype": "ohcv",
"cylindernumber": "six",
"enginesize": 173,
"fuelsystem": "mpfi",
"boreratio": 3.58,
"stroke": 2.87,
"compressionratio": 8.8,
"horsepower": 134,
"peakrpm": 5500,
"citympg": 18,
"highwaympg": 23
},
{
"car_ID": 204,
"symboling": -1,
"CarName": "volvo 246",
"fueltype": "diesel",
"aspiration": "turbo",
"doornumber": "four",
"carbody": "sedan",
"drivewheel": "rwd",
"enginelocation": "front",
"wheelbase": 109.1,
"carlength": 188.8,
"carwidth": 68.9,
"carheight": 55.5,
"curbweight": 3217,
"enginetype": "ohc",
"cylindernumber": "six",
"enginesize": 145,
"fuelsystem": "idi",
"boreratio": 3.01,
"stroke": 3.4,
"compressionratio": 23,
"horsepower": 106,
"peakrpm": 4800,
"citympg": 26,
"highwaympg": 27
},
{
"car_ID": 205,
"symboling": -1,
"CarName": "volvo 264gl",
"fueltype": "gas",
"aspiration": "turbo",
"doornumber": "four",
"carbody": "sedan",
"drivewheel": "rwd",
"enginelocation": "front",
"wheelbase": 109.1,
"carlength": 188.8,
"carwidth": 68.9,
"carheight": 55.5,
"curbweight": 3062,
"enginetype": "ohc",
"cylindernumber": "four",
"enginesize": 141,
"fuelsystem": "mpfi",
"boreratio": 3.78,
"stroke": 3.15,
"compressionratio": 9.5,
"horsepower": 114,
"peakrpm": 5400,
"citympg": 19,
"highwaympg": 25
}
]
Just copy it and go to the Testing tab . Paste the data in the Triggering Event block and click on the Test the Function option . If everything goes well – you should see the results below like this:
So with this your ML model is up and running as a REST API. In my case the end-point URL is
https://us-east4-cellular-scion-174517.cloudfunctions.net/rajivs-car-price-predictor
Step 4: Executing the functions
You can write a python code to call this end-point URL by passing the JSON data from above. Alternatively the URL can be called directly from a command prompt window using the CURL command. Both the options are given below
C:\Users\Downloads>curl -XPOST https://us-east4-cellular-scion-174517.cloudfunctions.net/rajivs-car-price-predictor -H 'Content-Type: application/json' -d @csvjson_car.json
Text: wheelbase carlength ... fuelsystem_spdi fuelsystem_spfi
0 94.5 165.7 ... 0 0
1 100.4 180.2 ... 0 0
2 100.4 180.2 ... 0 0
3 100.4 183.1 ... 0 0
4 104.3 188.8 ... 0 0
5 104.3 188.8 ... 0 0
6 104.3 188.8 ... 0 0
7 104.3 188.8 ... 0 0
8 104.3 188.8 ... 0 0
9 104.3 188.8 ... 0 0
10 109.1 188.8 ... 0 0
11 109.1 188.8 ... 0 0
12 109.1 188.8 ... 0 0
13 109.1 188.8 ... 0 0
14 109.1 188.8 ... 0 0
[15 rows x 51 columns]
Predicted Class Is: [ 8253.3133604 17209.8376059 11720.08805184 10921.55049779
17570.61807531 16800.3912296 17514.86191495 16686.43160539
20261.03487173 19452.00571679 18477.28088201 21379.32759567
19237.53456025 24269.07612228 20455.51980398]curl: (6) Could not resolve host: application
In my case I first downloaded the json into a file called csvjson_car.json into the Downloads folder. Then I navigated to that folder from the command prompt and then executed the above
CURL command curl -XPOST https://us-east4-cellular-scion-174517.cloudfunctions.net/rajivs-car-price-predictor -H 'Content-Type: application/json' -d @csvjson_car.json
The below example shows how it is done in a jupyter notebook
import requests
import json
#
endpoint2 = "https://us-east4-cellular-scion-174517.cloudfunctions.net/rajivs-car-price-predictor"
headers = {'Content-Type': 'applicaton/json'}
with open("csvjson_car.json", "r") as read_file:
developer = json.load(read_file)
response = requests.post(endpoint2, headers=headers, json=developer)
#
response.content