You built an ML with TensorFlow or Sci-kit learn and now want it deployed on a website. This article is a quick guide on loading an ML model in Python and using it to make predictions on a web app with Flask. This is based on my image classifier app found on my GitHub Fabio-RibeiroB/image_classifier_app: App to classify happy or sad images (github.com). In this app, the user uploads a file and presses predict. Specifically, the user uploads images for binary classification. It all depends on your model. You can change this code to upload CSV data instead, for example.
I appreciate this article is high-level and lacking detail. It is more than an outline to make it as short-form as possible. To see more, check out my aforementioned repo on GitHub. Anyway, let’s begin.
Save and Load
Let’s say you have a Sequential model that you compiled.
model = Sequential()
....some model
....
model.compile(....)
Now save the model, for example, as a .h5 file. I saved mine in a “models” folder. You can also use pickle
to dump and load models as .pkl files.
from tensorflow.keras.models import load_model
import os
model.save(os.path.join('models','model.h5'))
Now load it in your Flask app.
from flask import Flask, render_template, request, redirect, flash, session # useful flask modules
from werkzeug.utils import secure_filename # security
import logging
logging.basicConfig(level=logging.DEBUG)
logging.info('program starting')
from tensorflow.keras.models import load_model
model = load_model('models/model.h5') # loaded model
Static Uploads Folder
We also need a folder where we can upload data for the model. Make a directory called static, and within that, a directory called uploads.
UPLOAD_FOLDER = './static/uploads'
ALLOWED_EXTENSIONS = {'png', 'jgp', 'jpeg'} # change depending on model
app = Flask(__name__)
app.secret_key = b'somesecretkey'
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
def allowed_file(filename):
"""
Check the uploaded data is correct format
""""
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
Routes and Prediction
Now I create the necessary routes in your app that makes a prediction. We will later make a home.html will allow us to start a prediction. The predict.html page shows the results.
@app.route('/')
def home():
return render_template('home.html')
@app.route('/predict', methods=['POST'])
def predict():
file = request.files('file')
# check uploaded file is okay in upload folder
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
data_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
file. save(data_path) # save data
# read data in for example with pandas
prediction = model.predict(data) # in my example prediction is one number, a probability.
# remember to delete file after use
os.remove(data_path)
return render_template('predict.html', data=prediction)
if __name__ == "__main__":
app.run(debug=True)
The above code saves the valid data in the uploads folder and loads the data. For example, you could load your data into a pandas data frame. The /predict route passes the prediction variable containing a single prediction. The prediction variable is passed to predict.html to render the result on the web page. If your model outputs a lot of predictions, like a CSV of predictions, these lines will need to be modified. You probably want the user to download the predictions as a CSV instead of displaying the results on the screen. In this case, you need a download button in your HTML.
However, continuing my example, we have a home page called home.html with a form for the user to upload data. I simply removed the rest of my HTML tags to declutter the code snippet below. See my repo for the entire HTML file.
In home.html
<form method="POST" action="{{url_for('home')}}" enctype=multipart/form-data>
<input type=file name=file>
<input type=submit value=predict>
</form>
And now for prediction.html. This page will simply output the results with a back button.
{{data}}
<form>
<input type="button" value="Try again" on click="history.back()">
</form>
Flask run, and the app should be running in local host.