Deploying ML model to flask with joblib

In this blog, we will know how to deploy a Machine Learning model on a Flask App. In this blog, I am going to deploy a Simple Spam Classification Model to flask App.
If you have read before about deployment of the ML model you have heard of Pickle. This is most famous library for model deployment. But the question is, Is it most suitable in every case. The answer is no.
When we made a model with the sckit-learn classifiers, then Pickle faces some issues. These issues are also described in docs. But the Solution is the JOBLIB library. In this blog We will create a flask app and deploy the model in flask App with help of joblib.

from here you can download pre-trained model used in this blog. Models are in output file on kaggle- https://www.kaggle.com/thedeathcure/sms-spam-filtering. Model files are present in both format - model.joblib(joblib) and model.pkl (pickle) 

Create app.py 

https://gist.github.com/maze-runnar/4b455b2b2bdb0ba45c744da55dce5160
import requests
from flask import Flask, request,render_template
import sys

app = Flask(__name__)
app.config['DEBUG'] = True

// Your view goes here
if __name__ == "__main__":
app.run(debug = True)


create your view 


here I am using my pre-trained model so all libraries that are going to use in prediction with your model you have to import that. 

from sklearn import svm
from joblib import dump, load

## loading the model
clf = load('/home/saurabh/Desktop/smsspamcollection/frontend/model1.joblib') 

@app.route('/', methods = ["GET","POST"])
def index():
if(request.method == "POST"):
#city = request.form['city']
text_msg = request.form['sms']
my_msg = find_features(text_msg)
prediction =  clf.classify_many(my_msg)   ## make your prediction here 
x = ""
if(prediction[0] == 0):
x = "Not a spam, it's ok "
else:
x = "it's a spam" 
return render_template('mainpage.html',prediction = x)
else:
return render_template('mainpage.html')


In your templates the mainpage.html would be like -



<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<script src="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<!------ Include the above in your HEAD tag ---------->
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/all.css" integrity="sha384-lKuwvrZot6UHsBSfcMvOkWwlCMgc0TaWr+30HWe3a4ltaBwTZhyTEggF5tJv8tbt" crossorigin="anonymous">
<div class="container">
<style>
/* Style the body */
body {
  font-family: Arial;
  margin: 0;
}
/* Header/Logo Title */
.header {
  padding: 60px;
  text-align: center;
  background: orange;
  color: white;
  font-size: 30px;
}
/* Page Content */
.content {padding:20px;}
</style>
</head>
<body>
<div class="header">
  <h1>Spam Detector</h1>
  <p style="font-family: cursive;">98.79% Accuracy NaiveBayes Classifier</p>
</div>
<br/>
<style>
input[type=text], select {
  width: 100%;
  padding: 12px 20px;
  margin: 8px 0;
  display: inline-block;
  border: 1px solid #ccc;
  border-radius: 4px;
  box-sizing: border-box;
}
input[type=submit] {
  width: 30%;
  justify-content: center;
  background-color: orange;
  color: white;
  padding: 10px 20px;
  margin: 8px 0;
  border: none;
  border-radius: 15px 0 15px 0;
  cursor: pointer;
}
input[type=submit]:hover {
  background-color: #45a049;
 
}
div {
  border-radius: 5px;
 background-color: lightgrey;
  padding: 20px;
}
</style>
<div>
  <form action="/" method  = "post">
    <label for="fname" style="font-family: cursive;">Message</label>
    <input type="text" name = "sms" id="fname" name="firstname" placeholder="type message here ..">
    <br><br>  
    <div style="text-align:center;">
    <input type="submit" value="classify">
    </div>
  </form>
</div>
</body>
<!-------let's go and get that son of a b****----->
<div>
  <span style="color:red; font-family: cursive;font-size: 20px"><i>{{prediction}}</i></span>
</div>


Some Common Errors during Deployment 

Errors are inevitable when you try to go out of the box or try something new in development. 
The very common error is - 
ModuleNotFoundError: No module named 'sklearn.svm._classes'
The reason for this error is the version difference of sckit-learn. This occurs due to when you use pre-trained model or you trained a model on kaggle or colab and try to delay it on your local. Then you have to install same version of sckit-learn on your local too.
 
pip install -U sckit-learn==0.22.1

mine model used this version. I tried this and error resolved. So keep the versions in mind.
Once again just for revision - 

## loading the model

clf = load('/home/saurabh/Desktop/smsspamcollection/frontend/model1.joblib') 
prediction =  clf.classify_many(my_msg)   ## make your prediction here 

Complete app.py to use with my model - 
import requests
from flask import Flask, request,render_template
import sys
import nltk
import sklearn
import pandas
import numpy
import pandas as pd
import numpy as np
from sklearn.preprocessing import LabelEncoder
#import pickle ##load pre-trained model using pickle..
from nltk.tokenize import word_tokenize

from sklearn import model_selection
from nltk.classify.scikitlearn import SklearnClassifier#SVM classsifier (support vector machine)
from sklearn.svm import SVC
from sklearn.metrics import classification_report, accuracy_score, confusion_matrix



app = Flask(__name__)
app.config['DEBUG'] = True

df = pd.read_table('/home/saurabh/Desktop/smsspamcollection/SMSSpamCollection', header=None, encoding='utf-8') 

classes = df[0]

#from sklearn.preprocessing import LabelEncoder
# so convert spam to 1 and ham tabso 0
encoder = LabelEncoder()
y = encoder.fit_transform(classes)

text_messages = df[1]
processed = text_messages.str.replace(r'^.+@[^\.].*\.[a-z]{2,}$',
                                 'emailaddress')
# Replace URLs with 'webaddress'
# you can use any regex expression they are basically taken from the wikipedia

processed = processed.str.replace(r'^http\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(/\S*)?$',
                                  'webaddress')
# Replace money symbols with 'moneysymb' (£ can by typed with ALT key + 156)
# you can use any regex expression they are basically taken from the wikipedia

processed = processed.str.replace(r'£|\$', 'moneysymb')
    
# Replace 10 digit phone numbers (formats include paranthesis, spaces, no spaces, dashes) with 'phonenumber'
# you can use any regex expression they are basically taken from the wikipedia

processed = processed.str.replace(r'^\(?[\d]{3}\)?[\s-]?[\d]{3}[\s-]?[\d]{4}$',
                                  'phonenumbr')
# Replace numbers with 'numbr'
# you can use any regex expression they are basically taken from the wikipedia

processed = processed.str.replace(r'\d+(\.\d+)?', 'numbr')
# Remove punctuation
# you can use any regex expression they are basically taken from the wikipedia

processed = processed.str.replace(r'[^\w\d\s]', ' ')

# Replace whitespace between terms with a single space
processed = processed.str.replace(r'\s+', ' ')

# Remove leading and trailing whitespace
processed = processed.str.replace(r'^\s+|\s+?$', '')


processed = processed.str.lower()
from nltk.corpus import stopwords
s = stopwords.words('english')

processed = processed.apply(lambda x: ' '.join(term for term in x.split() if term not in s))


ps = nltk.PorterStemmer() # it removes the synonyms and similar sounding words..

processed = processed.apply(lambda x: ' '.join(ps.stem(term) for term in x.split()))
all_words = []

for message in processed:
    words = word_tokenize(message)
    for w in words:
        all_words.append(w)

all_words = nltk.FreqDist(all_words)

word_features = list(all_words.keys())



def find_features(message):
    words = word_tokenize(message)
    features = {}
    for word in word_features:
        features[word] = (word in words)

    return features

from sklearn import svm
from joblib import dump, load


clf = load('/home/saurabh/Desktop/smsspamcollection/frontend/model1.joblib') 

@app.route('/', methods = ["GET","POST"])
def index():
	if(request.method == "POST"):
		#city = request.form['city']
		text_msg = request.form['sms']
		my_msg = find_features(text_msg)
		prediction =  clf.classify_many(my_msg)
		x = ""
		if(prediction[0] == 0):
			x = "Not a spam, it's ok "
		else:
			x = "it's a spam" 
		return render_template('mainpage.html',prediction = x)
	else:
		return render_template('mainpage.html')	


@app.route('/aboutme')
def about():
	return render_template('aboutme.html')



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


Comments

Popular posts from this blog

Amazon Web Services

Hacker Rank all java and python problem solutions

Google Code-In mentorship experience :)