In the previous subsection, we have seen how to work with the applications module of the Keras deep learning library, providing both deep learning model definitions and pre-trained weights for a number of popular architectures.
In this subsection, we are going to see how to create a deep learning REST API based on one of these pre-trained architectures.
The Keras deep learning REST API is a single file named keras_server.py. The code for this script can be seen next:
# Import required packages:
from keras.applications import nasnet, NASNetMobile
from keras.preprocessing.image import img_to_array
from keras.applications import imagenet_utils
from PIL import Image
import numpy as np
import flask
import io
import tensorflow as tf
# Initialize Flask app, Keras model and graph:
app = flask.Flask(__name__)
graph = None
model = None
def load_model():
# Get default graph:
global graph
graph = tf.get_default_graph()
# Load the pre-trained Keras model(pre-trained on ImageNet):
global model
model = NASNetMobile(weights="imagenet")
def preprocessing_image(image, target):
# Make sure the image mode is RGB:
if image.mode != "RGB":
image = image.convert("RGB")
# Resize the input image:
image = image.resize(target)
# Convert PIL format to numpy array:
image = img_to_array(image)
# Convert the image/images into batch format:
image = np.expand_dims(image, axis=0)
# Pre-process (prepare) the image using the specific architecture:
image = nasnet.preprocess_input(image)
# Return the image:
return image
@app.route("/predict", methods=["POST"])
def predict():
# Initialize result:
result = {"success": False}
if flask.request.method == "POST":
if flask.request.files.get("image"):
# Read input image in PIL format:
image = flask.request.files["image"].read()
image = Image.open(io.BytesIO(image))
# Pre-process the image to be classified:
image = preprocessing_image(image, target=(224, 224))
# Classify the input image:
with graph.as_default():
predictions = model.predict(image)
results = imagenet_utils.decode_predictions(predictions)
result["predictions"] = []
# Add the predictions to the result:
for (imagenet_id, label, prob) in results[0]:
r = {"label": label, "probability": float(prob)}
result["predictions"].append(r)
# At this point we can say that the request was dispatched successfully:
result["success"] = True
# Return result as a JSON response:
return flask.jsonify(result)
@app.route("/")
def home():
# Initialize result:
result = {"success": True}
# Return result as a JSON response:
return flask.jsonify(result)
if __name__ == "__main__":
print("Loading Keras pre-trained model")
load_model()
print("Starting")
app.run()
The first step is to import the required packages, as follows:
# Import required packages:
from keras.applications import nasnet, NASNetMobile
from keras.preprocessing.image import img_to_array
from keras.applications import imagenet_utils
from PIL import Image
import numpy as np
import flask
import io
import tensorflow as tf
The next step is to initialize the Flask application, our model, and the computation graph, like so:
# Initialize Flask app, Keras model and graph:
app = flask.Flask(__name__)
graph = None
model = None
We define the load_model() function, which is responsible for creating the architecture and loading the required weights:
def load_model():
# Get default graph:
global graph
graph = tf.get_default_graph()
# Load the pre-trained Keras model(pre-trained on ImageNet):
global model
model = NASNetMobile(weights="imagenet")
As it can be seen, NASNetMobile weights are loaded.
We also define the preprocessing_image() function, as follows:
def preprocessing_image(image, target):
# Make sure the image mode is RGB:
if image.mode != "RGB":
image = image.convert("RGB")
# Resize the input image:
image = image.resize(target)
# Convert PIL format to numpy array:
image = img_to_array(image)
# Convert the image/images into batch format:
image = np.expand_dims(image, axis=0)
# Pre-process (prepare) the image using the specific architecture:
image = nasnet.preprocess_input(image)
# Return the image:
return image
This function prepares the input image—converts the image to RGB, resizes it, converts the image/images into the batch format and, finally, preprocesses it using the specific architecture.
Finally, we use the route() decorator to bind predict() function to the /predict URL. predict() function processes the requests and returns the predictions to the clients, like so:
@app.route("/predict", methods=["POST"])
def predict():
# Initialize result:
result = {"success": False}
if flask.request.method == "POST":
if flask.request.files.get("image"):
# Read input image in PIL format:
image = flask.request.files["image"].read()
image = Image.open(io.BytesIO(image))
# Pre-process the image to be classified:
image = preprocessing_image(image, target=(224, 224))
# Classify the input image:
with graph.as_default():
predictions = model.predict(image)
results = imagenet_utils.decode_predictions(predictions)
result["predictions"] = []
# Add the predictions to the result:
for (imagenet_id, label, prob) in results[0]:
r = {"label": label, "probability": float(prob)}
result["predictions"].append(r)
# At this point we can say that the request was dispatched successfully:
result["success"] = True
# Return result as a JSON response:
return flask.jsonify(result)
The first step when processing the image—in the predict() function—is to read the input image in PIL format. Next, we preprocess the image and pass it through the network to get the predictions. Finally, we add the predictions to the result, and return the result as a JSON response.
In the same way as we did in previous sections, we have coded two scripts in order to perform a POST request to the Keras deep learning REST API. The request_keras_rest_api.py script performs the POST request and prints the results. The request_keras_rest_api_drawing.py script performs the POST request, prints the results, and also creates an image to render the obtained results. For the sake of simplification, only the request_keras_rest_api_drawing.py script is shown, as follows:
# Import required packages:
import cv2
import numpy as np
import requests
from matplotlib import pyplot as plt
def show_img_with_matplotlib(color_img, title, pos):
"""Shows an image using matplotlib capabilities"""
img_RGB = color_img[:, :, ::-1]
ax = plt.subplot(1, 1, pos)
plt.imshow(img_RGB)
plt.title(title)
plt.axis('off')
KERAS_REST_API_URL = "http://localhost:5000/predict"
IMAGE_PATH = "car.jpg"
# Load the image and construct the payload:
image = open(IMAGE_PATH, "rb").read()
payload = {"image": image}
# Submit the POST request:
r = requests.post(KERAS_REST_API_URL, files=payload).json()
# Convert the loaded image to the OpenCV format:
image_array = np.asarray(bytearray(image), dtype=np.uint8)
img_opencv = cv2.imdecode(image_array, -1)
img_opencv = cv2.resize(img_opencv, (500, 500))
y_pos = 40
# Show the results:
if r["success"]:
# Iterate over the predictions
for (i, result) in enumerate(r["predictions"]):
# Print the results:
print("{}. {}: {:.4f}".format(i + 1, result["label"], result["probability"]))
# Render the results in the image:
cv2.putText(img_opencv, "{}. {}: {:.4f}".format(i + 1, result["label"], result["probability"]),
(20, y_pos), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 0, 255), 2)
y_pos += 30
else:
print("Request failed")
# Create the dimensions of the figure and set title:
fig = plt.figure(figsize=(8, 6))
plt.suptitle("Using Keras Deep Learning REST API", fontsize=14, fontweight='bold')
fig.patch.set_facecolor('silver')
# Show the output image
show_img_with_matplotlib(img_opencv, "Classification results (NASNetMobile)", 1)
# Show the Figure:
plt.show()
As you can see, we perform a POST request to the Keras deep learning REST API. In order to show the results, we iterate over the obtained predictions. For each prediction, we both print the results and render the results in the image.
The output of this script can be seen in the next screenshot:
In the previous screenshot, you can see the top 5 predictions corresponding to the input car.jpg image.