As seen from the picture above, the final step, after building a machine learning model, is to make the model available in production; in other words, model deployment. Model deployment means making your trained ML model available to end-users or other systems.

There are different methods for model deployment, however, this two-part story will cover only model deployment using Flask API on Heroku. In Part-1, we will prepare the necessary files required for deployment. Then in Part-2, we will upload these files on GitHub and make our app available on Heroku.

 

What is Flask API?

Let me start with the explanation of Flask API. Flask is a Python module for web frameworks that enable you to develop web applications easily. It is extensively documented and easy to use. It provides integrated unit testing support and a built-in development server and debugger.

 

flask-logo

 

Necessary Files for Deployment

 

In order to make our model ready for deployment, we will need the files below.

 

1. model.py: This file contains all the necessary codes for building a machine learning model to make predictions.

2. model.pkl: This file is the converted version of the model.py into a character stream using the pickle module. The pickled version of model.py contains all necessary information to reconstruct the model in another python script.

3. app.py: This is the main file for receiving required information for prediction through GUI or API calls and computing the predicted value and returning it.

4. request.py: The main function of this file is to call APIs defined in app.py by using the requests module, and to display the returned value.

5. Template folder: This folder contains an HTML template for user input, based on which our model will make predictions. If you want to add some styling, you can also put a CSS file here.

6. requirement.txt: This file tells Heroku which packages to install for your web app to run.

7. Procfile: Procfile is a simple text file that tells Heroku what kind of app you are running and how to serve it to users.

 

Step-1: Training and Tuning the Model

Now it is time to create these files in line with our dataset.

Firstly, we need to train a model and finally end up with a model.py file. model.py is a python file that is created when training the model. It consists of all codes necessary for our trained model to make predictions. In our case, I used RandomForestClassifier to train my model to predict the type of a tree (labeled as Cover_Type in the dataset) based on 5 features, which are Elevation, “Vertical_Distance_To_Hydrology, Horizontal_Distance_To_Roadways, Hillshade_Noon, and Horizontal_Distance_To_Fire_Points. Since our target (Cover_Type) labels range from 1 to 7, it is a multiclass classification problem.

 

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

 

import pickle dataset = pd.read_csv('final.csv') 

 

X=dataset.drop("Cover_Type", inplace=True)
y=dataset.Cover_Type

 

from sklearn.ensemble import RandomForestClassifier

 

classifier= RandomForestClassifier()
classifier.fit(X, y)

 

Step-2 : Pickling (Serialization)

After training and tuning the model, I converted it into a character stream using the pickle module. Pickling is one of the commonly used approaches for saving a model. The pickle module provides dump(), dumps(), load(), and loads() methods to save and read a model.

 

Saving a model using the pickle module is also called serialization. When a model is serialized, it can be reused to make predictions. And deserialization means loading or reading the model to reuse it.

 

pickle.dump(classifier, open('model.pkl','wb')) model=pickle.load(open("model.pkl", "rb"))

 

print(model.predict([[2788, 2, 3555,221, 2984]]))

 

Step-3 : Creating an app.py file

The third step is to create an app.py file. In this phase, model.pkl is deserialized using model = pickle.load(open(‘model.pkl’, ‘rb’)) and the main page is defined as return render_template(‘index.html’), which is the HTML file we will create to get user input. Using flask.request.form functionality, Flask extracts the data that is entered into the HTML form element. To sum up, this app.py receives JSON inputs, the values of the 5 features in our case, uses these inputs to make a prediction, and finally returns the prediction in JSON format.

 

import numpy as np
from flask import Flask, request, jsonify, render_template
import pickle

 

app = Flask(__name__)
model = pickle.load(open(‘model.pkl’, ‘rb’))

@app.route(‘/’)
def home():
return render_template(‘index.html’)

@app.route(‘/predict’,methods=[‘POST’])
def predict():

int_features = [int(x) for x in request.form.values()]
final_features = [np.array(int_features)]
prediction = model.predict(final_features)

output = prediction[0]

return render_template(‘index.html’, prediction_text=’Tree type is {}’.format(output))

@app.route(‘/results’,methods=[‘POST’])
def results():

data = request.get_json(force=True)
prediction = model.predict([np.array(list(data.values()))])

output = prediction[0]
return jsonify(output)

if __name__ == “__main__”:
app.run(debug=True)

 

 Step-4: Creating a request file

The next step is to create a request file. request.py is a simple python file that uses the request module to call APIs defined in app.py and displays the predicted value.

 

import requests 
url = 'http://localhost:5000/results'

 

r = requests.post(url,json={"Elevation":2434, "Vertical_Distance_To_Hydrology":80, "Horizontal_Distance_To_Roadways":234, "Hillshade_Noon":221, "Horizontal_Distance_To_Fire_Points":469})  

 

print(r.json())

 

Here we come to a step to create an HTML file that will display the desired output to users. HTML file provides a connection between the end-user and the model. Users can enter their inputs via HTML form element, from where Flask extracts them to make predictions. In our model, since all the features are numeric, “input_type”=numeric is used with min and max features. Finally submit type button is created to display the result.

 

<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<title>Tree Type Prediction</title>
<link href='https://fonts.googleapis.com/css?family=Pacifico' rel='stylesheet' type='text/css'><link href='https://fonts.googleapis.com/css?family=Arimo' rel='stylesheet' type='text/css'><link href='https://fonts.googleapis.com/css?family=Hind:300' rel='stylesheet' type='text/css'><link href='https://fonts.googleapis.com/css?family=Open+Sans+Condensed:300' rel='stylesheet' type='text/css'><link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}"> </head>
<body background="https://lh5.googleusercontent.com/proxy/4vbIAzfLtz2eDbQMOoU-AIu5sDST-dHmm9vaxN3VQyBjjH11o4VUWF4QEQfIO8oZ4a5Zy1lXDGSKWlIrDnokEATdPiNz4ho4beHMDhCPltozmdnc5Cac69cVH3WvIUJEF7M=s0-d">
<div class="login">
<h1 style="text-align:center">Tree Type Prediction</h1>

 

<form action=”{{ url_for(‘predict’)}}”method=”post”>
<h3 style=”text-align:center;”>Elevation</h3>
<p style=”text-align:center;”><input type=”number” name=”Elevation” min=”1859″ max= “3858” required=”required” /></p>

 

    <h3 style="text-align:center;">Vertical Distance to Hydrology</h3>        
<p style="text-align:center;"><input type="number" name="Vertical_Distance_To_Hydrology" min="-173" max= "254" required="required" /></p>

 

   <h3 style="text-align:center;">Horizontal Distance to Roadways</h3> 
<p style="text-align:center;"><input type="number" name="Horizontal_Distance_To_Roadways" min="0" max= "7117" required="required" /></p>

 

   <h3 style="text-align:center;">Hillshade Noon</h3> 
<p style="text-align:center;"><input type="number" name="Hillshade_Noon" min="0" max= "254" required="required" /></p>

 

<h3 style=”text-align:center;”>Horizontal Distance to Fire Points</h3>
<p style=”text-align:center;”><input type=”number” name=”Horizontal_Distance_To_Fire_Points” min=”0″ max=”7126″ required=”required” /></p>
<h2 style=”text-align:center;”></h2>
<p style=”text-align:center;”><button type=”submit” class=”btn btn-primary btn-block btn-large”>Predict Tree Type</button></p>

 

  </form>   <h2 style="text-align:center;">{{ prediction_text }}</h2>  
</div>
</body>
</html>

Step-5: Creating requirements.txt and Procfile for Heroku

In the last two steps, we need to create two files for Heroku to understand what kind of app we want and what the requirements are to run this app.

Let’s continue with the requirements.txt. The requirements.txt file is very crucial for your app to run properly. It tells Heroku which packages need to be installed when running the app. You can manually specify the packages to be installed by writing them down in requirement.txt or pipregs package can do it for you. If installed, pipreqs package generates a requirement.txt file that includes all necessary packages for your app.

 

Flask==1.1.1 
gunicorn==19.9.0
itsdangerous==1.1.0
Jinja2==2.10.1
MarkupSafe==1.1.1
Werkzeug==0.15.5
numpy>=1.9.2
scipy>=0.15.1
scikit-learn>=0.18
matplotlib>=1.4.3
pandas>=0.19

 

Finally, we can complete the steps by creating a Procfile. The Procfile is a simple text named Procfile without a file extension and must be located in your app’s root directory.

 

web: gunicorn app:app

 

The code shown above should be written in Procfile. The first app represents the python file that runs your application or the name of the module it is in. And the second app is the name of the python file we have created in the flask. (app=Flask__name__)

 

Now we have completed creating the necessary files for model deployment. Uploading these files to GitHub and how to create an app from them will be covered in Part-2.

 

To recap:

 

  • The last step of ML pipeline is deploying the model.
  • Model deployment means making your trained ML model available to end-users or other systems.
  • There are different methods to deploy a ML model, however, this story covers only model deployment using Flask on Heroku.
  • In Part-1 of this two-part story, we prepared the necessary files for model deployment. In Part-2, we will cover how to run your app in Heroku.