Develop and Deploy an Image Classifier using Flask – Part 2

In Part 1 of this series, we covered how to train a deep learning model to classify images using convolutional neural networks (CNNs). We used the popular Keras framework to build and train the model on a dataset of labeled images.

Now that we have a working image classification model, let‘s explore how to deploy it as a web service so that other applications can utilize it. In this article, we‘ll walk through the process of building a REST API with the Flask web framework to expose our trained image classifier to the world!

Why Create a REST API?

A REST (REpresentational State Transfer) API is a way to expose the functionality of your application over the web using HTTP requests and responses. The key idea behind REST is that everything is modeled as a resource that can be created, read, updated, or deleted using standard HTTP methods (POST, GET, PUT, DELETE).

In our case, we want to provide an interface for other applications to send an image to our trained classifier and receive the predicted class label in response. This is a perfect use case for a REST API. By wrapping our classifier in a web service, we make it accessible to a variety of clients regardless of their programming language or platform.

Some benefits of using a REST API for deploying machine learning models include:

  • Loose coupling: The API provides a layer of abstraction between the model and the applications that consume it. This allows you to update or even replace the model implementation without affecting the clients.

  • Language agnostic: REST APIs typically use JSON (JavaScript Object Notation) for request/response data. This lightweight, human-readable format can be parsed by almost any programming language, making the API accessible to a wide range of clients.

  • Scalability: REST APIs are stateless, meaning the server doesn‘t need to store any information about the client between requests. This makes it easy to scale the API horizontally by adding more servers to handle increased traffic.

  • Flexibility: APIs allow you to build modular, composable software by breaking it down into small, reusable services. You can deploy the image classifier as a standalone microservice to be used in various applications.

Why Flask?

Flask is a popular Python web framework for building web applications and APIs. It provides a simple, intuitive way to map URLs to Python functions and handle HTTP requests and responses.

Flask logo

Flask is a great fit for exposing machine learning models as web services for several reasons:

  • Lightweight: Flask has minimal dependencies and overhead compared to more feature-heavy frameworks like Django. This makes it well-suited for deploying ML models as standalone microservices.

  • Flexible: Flask provides the basic building blocks for handling HTTP requests and responses but doesn‘t make too many decisions for you. This allows you to structure the application in a way that makes sense for your model and use case.

  • Easy to learn: Flask has excellent documentation and a gentle learning curve. This makes it accessible to data scientists and ML engineers who may not have extensive web development experience.

  • Extensible: Flask supports a wide ecosystem of extensions for common tasks like database access, user authentication, caching, and more. As you add features to your web service, Flask makes it easy to expand.

Here are some real-world examples of companies using Flask to build machine learning powered applications:

  • Netflix uses Flask to build internal tools for organizing machine learning experiments and A/B testing at scale. [source]

  • Lyft uses Flask to power parts of its fraud detection pipeline for identifying fake accounts and payment fraud. [source]

  • Reddit uses Flask to serve machine learning models in production for tasks like ad relevance prediction and content recommendations. [source]

Implementing the Flask API

Now that we understand the motivation behind creating a REST API and why Flask is a good choice, let‘s dive into actually building it! We‘ll continue where we left off in Part 1 with a trained Keras image classification model.

Project Structure

Here‘s the directory structure for our Flask project:

flask-image-classifier/
├── app.py
├── templates/
│   └── index.html
└── static/
└── models/
    └── keras_model.h5
  • app.py – This is where we‘ll write the Flask application code.
  • templates/ – HTML templates for rendering the web UI.
  • static/ – Any static assets like CSS, JavaScript, or images used in the UI.
  • models/ – Serialized trained model files.

Loading the Model

We start by loading our trained Keras model into memory in app.py:

from tensorflow.keras.models import load_model

model = load_model(‘models/keras_model.h5‘)

We use the load_model function to deserialize the model architecture and weights from the saved .h5 file. Make sure to replace ‘models/keras_model.h5‘ with the actual path to your model file.

Initializing the Flask App

Next, we create a Flask application instance:

from flask import Flask

app = Flask(__name__)

The Flask constructor takes the name of the current Python module as an argument. This is used to determine the root path for the application.

Defining Routes

In Flask, routes define the URL paths that the application will respond to. We‘ll create two routes:

  1. ‘/‘ – Displays a web form where the user can upload an image and get a prediction.
  2. ‘/predict‘ – Accepts a POST request with the image file and returns the classifier output.

Here‘s the implementation:

from flask import request, jsonify, render_template

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


@app.route(‘/predict‘, methods=[‘POST‘])
def predict():
    # Get the file from the POST request
    file = request.files[‘file‘]

    # Read the image
    img = Image.open(file.stream)

    # Preprocess the image
    img = img.resize((224, 224))
    img = img.convert(‘RGB‘)
    x = image.img_to_array(img)
    x = np.expand_dims(x, axis=0)
    x = preprocess_input(x)

    # Make the prediction
    preds = model.predict(x)
    result = decode_predictions(preds, top=1)[0][0]

    return jsonify({
        ‘prediction‘: result[1], 
        ‘probability‘: float(result[2])
    })

Let‘s break this down:

  • The index route renders the index.html template which contains the file upload form.

  • The predict route is mapped to the URL path ‘/predict‘ and accepts POST requests. This means it will be called when the form is submitted.

  • We access the uploaded image file via request.files[‘file‘]. This assumes the file input in the HTML form has the name attribute ‘file‘.

  • We then read the image data, preprocess it (resize, convert to RGB, normalize), and expand dimensions to get it into the shape expected by our Keras model.

  • We use the loaded model to generate a prediction on the preprocessed image. The decode_predictions function maps the class probabilities output by the model to human-readable labels.

  • Finally, we return the top predicted label and probability as a JSON object using Flask‘s jsonify function. Returning JSON makes the API response easy to consume from JavaScript or any other language.

The HTML Template

The index.html template renders the file upload form:

<!doctype html>
<html>
<head>
    <title>Image Classifier</title>
</head>
<body>

    <form action="/predict" method="post" enctype="multipart/form-data">
        <input type="file" name="file">
        <input type="submit" value="Predict">
    </form>

    {% if prediction %}
    <h2>Prediction</h2>
    <p>{{ prediction }} ({{ probability }})</p>
    {% endif %}
</body>
</html>

This basic HTML page displays a file input and a submit button. When the form is submitted, it sends a POST request to the ‘/predict‘ URL with the selected image file.

We use the Jinja templating engine to conditionally render the prediction result. The {% if prediction %} block only displays if the prediction variable exists in the template context. This allows us to show the prediction on the same page after the form is submitted.

Running the App

Now that we have all the pieces in place, let‘s run the Flask development server and test it out! Add this to the bottom of app.py:

if __name__ == ‘__main__‘:
    app.run()

Then execute the script:

$ python app.py

Navigate to http://localhost:5000 in your web browser and you should see the file upload form. Choose an image, click "Predict", and you‘ll get the model‘s top class prediction and probability.

Congratulations, you just deployed an image classification model as a web service with Flask!

Taking It Further

We‘ve covered the basics of building a REST API for a machine learning model with Flask. But there are many ways you can expand and improve this example:

  • Security: Our basic API doesn‘t include any authentication or access control. In a real-world application, you‘d want to add user authentication and possibly rate limiting to prevent abuse. Flask extensions like Flask-JWT and Flask-Limiter can help with this.

  • Deployment: So far we‘ve just run the Flask server locally. To make the API accessible to real users, you‘ll need to deploy it to a web hosting platform. Heroku and AWS Elastic Beanstalk are popular choices that make it easy to deploy Flask applications.

  • Scalability: As your API gets more traffic, you may need to scale it to handle the load. Strategies for scaling Flask applications include using a production-grade WSGI server like Gunicorn, running multiple Flask instances behind a load balancer, and caching frequent responses with Redis.

  • Containerization: To make your application easy to deploy and scale, you can package it in a Docker container. This bundles your application code, dependencies, and runtime environment into a single, portable unit. Check out the official Python Docker image to get started.

  • API Documentation: As you add more functionality to your API, it‘s important to maintain clear, accurate documentation. Tools like Swagger and ReDoc can automatically generate interactive API documentation from your Flask code.

Conclusion

In this article, we saw how to use the Flask web framework to deploy a Keras image classification model as a REST API. We covered the basic structure of a Flask application, how to define routes for handling requests, and how to preprocess and pass input data to a machine learning model.

We‘ve only scratched the surface of what‘s possible with Flask and machine learning. You can use the same approach to deploy all sorts of models, from simple regression to complex deep learning, as web services. This allows you to quickly productionize your machine learning projects and integrate them with other software systems.

By packaging machine learning models as REST APIs, you can build intelligent applications that are modular, scalable, and accessible to a wide range of clients. This is a key skill for data scientists and software engineers working on real-world ML systems.

I hope this tutorial has been helpful! The complete source code is available on GitHub. Feel free to use it as a starting point for your own projects. If you have any questions or feedback, let me know in the comments.

How useful was this post?

Click on a star to rate it!

Average rating 0 / 5. Vote count: 0

No votes so far! Be the first to rate this post.

Similar Posts