ML on Server-less Cloud : Part 1 GCP Cloud

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.

Option to create a new project

Once created the login dashboard would look like this – with the project (which I’ve highlighted in red underlining )

GCP Home Dashboard

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

Default Screen

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:

General

Trigger shows me details of the type of trigger and the end-point URL of the REST API

Trigger

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

Requirements

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

Leave a comment