Quickly Build and Deploy a Machine Learning App

A step-by-step guide to building and deploy your machine learning model using Python, Streamlit, and Heroku

Retin P Kumar
Geek Culture

--

Photo by Andrea De Santis on Unsplash

It's a great day and you’re now ready to build and deploy your first machine learning app.

But you’re skeptical about it.

No worries, today we will together build a machine learning app from scratch and deploy it on a cloud platform.

This article will help you build a machine learning app quickly using Streamlit and deploy it on the Heroku platform. This will help boost your confidence in building more machine learning apps with your own unique and innovative ideas.

So let’s begin.

Note that this article will have 3 parts:

Part 1: Building a model from scratch

Part 2: Creating an app for the model

Part 3: Deploying the model

Part 1: Building a model from scratch

We will be using the classic Iris Flower dataset from Scikit learn library for creating our Iris Flower Prediction App.

On to your jupyter notebooks folks.

Let’s import some libraries first.

In case, you don’t have any of these libraries installed in your system, you can do either of the following to get them:

Create a new cell in your jupyter notebook and type

!pip install “libraryname”

(don’t use the double quotes while mentioning the library name)

For example, if you want to install pandas, type

!pip install pandas

Open your system terminal/command prompt from the project directory where you have downloaded and saved the project files and type

pip install -r requirements.txt

You can find the files for this article at: https://github.com/Retinpkumar/Iris-flower

Once you’re done, let's proceed with importing the required libraries for creating our app.

# data manipulation
import numpy as np
import pandas as pd

# data transfer
import joblib

# raw dataset
from sklearn.datasets import load_iris

Now, let's load our dataset and view the keys corresponding to it.

iris = load_iris()
iris.keys()

We find that the dataset is being stored in the form of a dictionary inside the Sklearn datasets module. Let's access a few keys to get our required data.

‘DESCR’ key gives a detailed description of the dataset. But in order to view it in a proper format, let’s split the string with respect to newline char.

iris.DESCR.split("\n")

Wow. That’s a lot of information.

Feel free to go through it when you find the time. This same works for all the datasets within the Sklearn package.

Now let's create our data frame of features by accessing the ‘data’ variable

# creating dataframe
data = pd.DataFrame(iris.data, columns=iris.feature_names)
# printing observations
print(f"The data has {data.shape[1]} features and {data.shape[0]} observations.")
# checking first 5 observations
data.head()
png
Iris dataset (image by author)

Our data column looks a bit complicated. Let’s simplify it by creating a dictionary map.

data = data.rename(columns={
'sepal length (cm)':'sepal_length',
'sepal width (cm)':'sepal_width',
'petal length (cm)':'petal_length',
'petal width (cm)':'petal_width'
})
data.head()
png
Mapped columns (image by author)

Now, our data frame looks great. We can save it for further reference, but it's not required.

# save data if needed
data.to_csv('data.csv', index=False)

Now that we have our input features, let’s explore our target feature.

# explore target
iris.target

Seems like we have 3 different types of target classes (which is obvious).

So,

0 represents “Iris-Setosa”,

1 represents “Iris-Versicolour”, and

2 represents “Iris-Virginica”.

# add target to dataframe
data['Target'] = iris.target
data.head()
png
Datset with target (image by author)

Let’s have a check at the target composition

# check target composition
data['Target'].value_counts()
0 50
1 50
2 50
Name: Target, dtype: int64

That looks nice. We have equal representation from all the classes in our target feature.

Let’s have a quick check if any value is missing from our data.

# check missing values
data.isnull().any()
sepal_length False
sepal_width False
petal_length False
petal_width False
Target False
dtype: bool

Great... We don’t have any missing values in our dataset.

We will now split our data set into target feature ‘y’ and input features ‘X’.

# split data
y = data['Target']
X = data.drop(columns=['Target'], axis=1)

Now we will split our data into training and testing datasets.

We will create a test set that will be almost 25% of the total data size.

# create train and test sets
from sklearn.model_selection import train_test_split
train_X, test_X, train_y, test_y = train_test_split(X, y, test_size=0.25, random_state=7)

print(train_X.shape, test_X.shape, train_y.shape, test_y.shape)
(112, 4) (38, 4) (112,) (38,)

We will be using a Logistic regression model to make the classification prediction and hence we will be scaling our input features to make it easy for the algorithm to make predictions.

We will scale our training data first by calling the fit_transfer method so that the fit method will capture the parameters from the training data for transforming the testing data.

We can use the fit_transform method even for testing data as well, but if the testing data has only one row of input, then the fit method will fail to capture the parameters from the testing data.

Hence we use the parameters from the training data to scale the testing data.

Make sure that you save your scalar file after you have scaled your training data and use that to transform your testing data.

from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()

train_X_scaled = scaler.fit_transform(train_X) # scaling training data

#save scaler
joblib.dump(scaler, 'standard_scaler.sav')

test_X_scaled = scaler.transform(test_X) # scaling testing data
['standard_scaler.sav']

Let’s now import a Logistic Regression model from the Sklearn library and create a model object.

from sklearn.linear_model import LogisticRegression

model = LogisticRegression()

We are dealing with a multi-class classification problem where our target feature has three distinct classes.

By default, the Logistic regression model in Sklearn Library is enabled to handle multi-class classification tasks with the parameter multi_class being set to “auto” which will use the “multinomial” method for performing multi-class classification by default.

Hence for now we will proceed with a base model of Logistic regression for our problem.

For further reference, you can visit the following link

Let’s now fit our model and make predictions

# fitting model
model.fit(train_X_scaled, train_y)
LogisticRegression()# Making predictions using test data
y_pred = model.predict(test_X_scaled)

Now that we have made predictions using our test dataset, we will now calculate the accuracy metrics to see if our model is working well enough.

Since our objective is just to create a model and deploy it, we will not be proceeding with improving our accuracy or any other classification metrics.

# calculating accuracy
from sklearn.metrics import accuracy_score

accuracy = accuracy_score(test_y, y_pred)
accuracy
0.8947368421052632

Our model is working pretty fine.

So we will now save our model file so that we can import this file to create our app for deployment.

# save model
joblib.dump(model, 'model.sav')
['model.sav']

Part 2: Creating an app for the model

You know how I created and arrange the project files in the project directory do read this article on How to Organize your Data Science Project files

In this section, we will be focusing on creating our three main app files:

  1. app.py
  2. model.py
  3. scalar.py

Let’s begin with “model.py”

image.png
Creating model file (image by author)

This file will be used for making predictions using the input data from the user.

So we will create a function that takes in user input as its argument and returns a predicted value with the help of our saved model.

Now, we will create our “scalar.py”

image.png
Creating scaler file (image by author)

This file takes the input dataframe as its argument and returns a scaled input dataframe using our saved scalar object.

And finally, its time to create our “app.py”

We will be using Streamlit library for making our app.

Since we fed a dataframe as the input for creating the scalar object, we have to import pandas library to create a dataframe of user inputs. This dataframe has to be fed to our scalar object to generate a scaled version of user inputs for making the final prediction.

Hence we will import Streamlit and Pandas along with our model files in our “app.py”

image.png
Importing libraries (image by author)

We will set our app display page settings using st.set_page_config method from the streamlit library.

image.png
Setting app page configuration (image by author)

Use st.title to set a title text for the app form.

image-2.png
Giving app title (image by author)

Now, we will use st.form to create our user input form.

Inside the form, we will create a form header using st.header and input elements using st.number_input and st.slider.

Using input text field or slider object is completely your choice. I have implemented both just for the purpose of demonstration.

image.png
Creating app form (image by author)

So now that we have our form ready, let's proceed to process inputs and make predictions.

This should be self-explanatory, except for the st.balloons method which are nothing but a cool graphical illustration for our successful prediction.

image.png
Complete app (image by author)

If you’ve made it this far, pat yourself on the back.

You’ve now successfully made your first machine learning model for predicting Iris flower classes. Yay…

Now, to check if your app is working, open a terminal/command prompt in the project directory or use the CLI in your IDE and type

streamlit run app.py

Hurray… Now you can interact with your app in your default browser and make predictions.

Now, we will move on to part 3 where we will deploy our app on a cloud platform. For this, we will make use of GitHub and Heroku.

But before that, you would require a few other files as well.

Starting with the “requirements.txt” file for installing libraries.

For creating the “requirements.txt” file, open the terminal in your project directory and type

pip install pipreqs

to install pipreqs library. After you’re done with the installation, in your terminal, type

pipreqs --encoding=utf8  --debug  "path/to/project"

Make sure to enter the actual path to your project directory in the place of “path/to/project”.

This will automatically create “requirements.txt” for your project.

Other 3 important files

Now, inside your directory where you have your “app.py” and “requirements.txt” files, create 3 more files named: Procfile, runtime.txt, and setup.sh

Inside, “setup.sh”, type the following and save:

mkdir -p ~/.streamlit/
echo "\
[general]\n\
email = \"your-email@domain.com\"\n\
" > ~/.streamlit/credentials.toml
echo "\
[server]\n\
headless = true\n\
enableCORS=false\n\
port = $PORT\n\
" > ~/.streamlit/config.toml

Now, open your “Procfile”, and enter this and save:

web: sh setup.sh && streamlit run app.py

Then open your “runtime.txt” and enter your Python version as follows:

python-3.8.8

If you’re unsure about your python version, open your terminal and type:

python --version

Copy the text and paste. As simple as that.

Now over to deploying our model on a cloud platform.

Part 3: Deploying the Model

I will be skipping the part where you create a GitHub repo here as I assume that you know how to create a Github repository.

So, assuming that you have created your GitHub repo and uploaded all your project files from your local git to the project repo, now visit https://dashboard.heroku.com/apps and create a “New app” as follows:

image-3.png
Creating new app in Heroku (image by author)

Give your app a name and click Create App

image.png
Giving app name (image by author)

You will be now moved to a page that looks like this

image.png
Selecting deployment pipeline (image by author)

Click on that GitHub icon, enter your GitHub repo name in the search field and click “Search”. Then press “Connect”.

Now, you will see a few options that look like this:

image.png
Enabling automatic deploy (image by author)

Click “Enable Automatic Deploys” as this will make changes to your app as you modify your files related to the app in your GitHub repo.

Then, click “Deploy Branch” and wait for some time.

Meanwhile, you can enjoy watching your app getting deployed through this window.

image.png
Deploying the app (image by author)

After successful deployment, you will get to see something like this:

image.png
App successfully deployed (image by author)

Yay…

No. Wait...

Most of the time, you will receive an error and be redirected to this page:

image.png
Deployment error (image by author)

But don’t worry.

That’s just an error:503 which means the Heroku server isn’t ready to host your app. So, just give it some time and check back later. It will be deployed for sure.

For personal reasons, I will not be deploying my app, but you can get the codes in my GitHub repo here.

And if you could successfully get it deployed without any error, then Cheers!!!…

After successful deployment, the app should now look like this:

image.png
Final app (image by author)

Congrats!! Now you have successfully built a model from scratch and deployed it on a cloud platform.

And I hope you liked the article. Follow me for more actionable content and feel free to post your comments and valuable feedback

--

--