How to deploy Machine Learning model using Flask
Published: 2021-03-23 05:53:37

Creating a machine learning model and doing predictions sounds cool. But, that’s not very useful for anyone if it’s only available on their machine. so in this tutorial, we are going to create a simple machine learning model and deploy the model into production using a Flask REST API. If you don't know much about REST API's please refer to my [this](https://dev.to/atultyagi612/how-to-build-simple-restful-apis-with-python-and-flask-j8j) article.

When a data machine learning engineer or a data scientist develops a machine learning model using Scikit-Learn, TensorFlow, or using any other tool the main goal is to make it available in production.

Deployment of machine learning models into production means making your models available to the end-users. This article makes you get started with putting your trained machine learning models into production using Flask API.

We are going to use RandomForestClassifier to predict the Quality of Red wine. we only create a simple model and save it into a file using pickle.

## Why flask?
* It is easy to use
* Integrated unit testing support.
* Faster than Django.

Before we get started I assume that you know about how to create a machine learning model using scikit-learn.

## Dependencies
```python
* scikit-learn
* Pandas
* Numpy
* flask
* pickle
```
## Data 
you can get data from [this](https://www.kaggle.com/uciml/red-wine-quality-cortez-et-al-2009) Kaggle dataset that we are going to use in creating the ML model.
## Let's go

### Make a ML model
first, we are going to create a simple ML model and convert the model which is in the form of a python object into a character stream using pickling.
```python
# Import Dependencies
import pandas as pd
import numpy as np
import pickle
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score

# Import data from csv file
data=pd.read_csv('winequality-red.csv')

# Split data into output and input
x=data.iloc[:,:-1]
y=data.iloc[:,-1:]

# Split data into train and test
x_train,x_test,y_train,y_test=train_test_split(x,np.array(y).flatten(),test_size=0.1,random_state=1)
model =RandomForestClassifier()
model.fit(x_train,y_train)

predic=model.predict(x_test)
accuracy_score(y_test,predic)

# Save model using pickle
pickle.dump(model, open('model.pkl','wb'))
```
Now a file `model.pkl` is created in your folder.

## Rest API
Now create a restful API using a flask that takes inputs from the user and predicts the output using the ML model. If you don't know how to create a restful API using flask please refer to my [this](https://dev.to/atultyagi612/how-to-build-simple-restful-apis-with-python-and-flask-j8j) article.
file:`app.py`
```python
from flask import Flask, jsonify
from flask_restful import Resource, Api, reqparse
import pickle

app=Flask(__name__)
api=Api(app)

data_arg=reqparse.RequestParser()
data_arg.add_argument("id" , type=str)
# load ML model
model=pickle.load(open('model.pkl', 'rb'))
class predict(Resource):
    def __init__(self):
        self.model1 = model
    def post(self):
        # parse data from post request
        args = data_arg.parse_args()
        # convert string into int list
        temp=args.id.strip('][').split(',')
        temp = [float(i) for i in temp]
        # predict output
        out=self.model1.predict([temp])
        # Return prediction
        return jsonify({"message":  int(out)})
api.add_resource(predict, '/')


if __name__ == '__main__':
    app.run(debug=True)
```
Now our API is ready. now it's time to create a web page to take input from the user.

## Front end 
file:`front.html`
HTML page:-
```javascript
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
</head>

<body>
    <form id="form_id" onsubmit="sub(event)">
        <div class="form-group">
            <h1>Red Wine Quality  prediction</h1>
            <div class="element">
                <label for="inputPassword5">fixed acidity</label>
                <input type="number"  min="4.6" max="16"step="0.00001"class="form-control" value=10.4>
            </div>
            <div class="element">
                <label for="inputPassword5">volatile acidity</label>
                <input type="number"  min="0.12" max="1.6"step="0.00001"class="form-control" value=0.55>
            </div>
            <div class="element">
                <label for="inputPassword5">citric acid</label>
                <input type="number"  min="0" max="1"step="0.0000001"class="form-control" value=0.23>
            </div>
            <div class="element">
                <label for="inputPassword5">residual sugar</label>
                <input type="number"  min="0.9" max="15.5"step="0.00001"class="form-control" value=2.7>
            </div>
            <div class="element">
                <label for="inputPassword5">chlorides</label>
                <input type="number"  min="0.012" max="0.61"step="0.00001"class="form-control" value=0.091>
            </div>
            <div class="element">
                <label for="inputPassword5">free sulfur dioxide</label>
                <input type="number"  min="1" max="72"step="1"class="form-control" value=18>
            </div>
            <div class="element">
                <label for="inputPassword5">total sulfur dioxide</label>
                <input type="number"  min="6" max="278"step="1"class="form-control" value=48>
            </div>
            <div class="element">
                <label for="inputPassword5">density</label>
                <input type="number"  min="0.98" max="10"step="0.00001"class="form-control" value=0.9994>
            </div>
            <div class="element">
                <label for="inputPassword5">pH</label>
                <input type="number"  min="2.74" max="4.01"step="0.000001"class="form-control" value=3.22>
            </div>
            <div class="element">
                <label for="inputPassword5">sulphates</label>
                <input type="number"  min="0.33" max="2"step="0.000001"class="form-control" value=0.64>
            </div>
            <div class="element">
                <label for="inputPassword5">alcohol</label>
                <input type="number"  min="8.4" max="14.9"step="0.000001"class="form-control" value=10.3>
            </div>
            
            
        </div>
        <input type="submit">
    </form>
    <p id="demo"></p>
</body>

</html>
```
Now add styling to the page
```javascript
<style>
    #form_id{
        display: flex;
    flex-direction: column;
    align-items: center;
    }

    .form-group{
        width: 50%;
        margin-top: 50px;
    }
    #demo{
        text-align: center;
        color: firebrick;
    font-size: larger;
    font-weight: 900;

    }
</style>
```
Now it's time for the main and the last part and javascript functions that take data from the HTML form and send it to the restful API using XMLHttpRequest.
```javascript
 <script>
        let out=""
        function loadDoc(data) {
            var xhttp = new XMLHttpRequest();
            xhttp.onreadystatechange = function () {
                console.log(this.responseText)
                if (this.readyState == 4 && this.status == 200) {
                    out=JSON.parse(this.responseText).message
                    document.getElementById("demo").innerHTML = ` Result => ${out}`;
                }
            };
            xhttp.open("POST", "http://127.0.0.1:5000/.", true);
            xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
            xhttp.send(`id=${data}`);
        }
        var myForm=""
        let ouput_data=[]
        function sub(e){
            ouput_data=[]
            e.preventDefault();
            console.log("Done")
            myForm = document.getElementById('form_id');
            for(let i=0;i<11;i++){
                ouput_data.push(myForm.elements[i].value)
            }
            senddata(ouput_data)
        }
        function senddata(dat){
            let temp="["+dat.toString()+"]"
            loadDoc(temp)
            
        }
    </script>
```
## Result
Now run you run your rest API `app.py`.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p5bbw9n11fssncibicxd.jpg)
Next, run your` front.html`  using your IDE for mine its visual studio code.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8bo1lp8hhaflpgrpt75o.jpg)
Now fill the form and press the Submit button at the end of the form. The result is:-
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z6h92cwjol3cc7mi1oyv.jpg)
You may also get an error in your console like:-`Access to XMLHttpRequest at 'http://127.0.0.1:5000/' from origin 'null' has been blocked by CORS policy: The 'Access-Control-Allow-Origin'`
Use [this](https://chrome.google.com/webstore/detail/allow-cors-access-control/lhobafahddgcelffkeicbaginigeejlf) chrome extension this will resolve the issue.
## Conclusion 
This article shows a very simple way to deploy machine learning models. I used Random Forest Classifier to predict the Quality of Red Wine. One can use the knowledge gained in this blog to make some cool models and take them into production so that others can appreciate their work. I hope you find this article useful and able to learn new things from it.

Thank you for reading👏