visit
This is the second and final part of the series on How to build and deploy an NLP model with FastAPI. In the first part, we looked at how to build an NLP model that can classify movie reviews into different sentiments.
In this second and final part, you will learnFastAPI is the fast and modern python web framework for building different APIs. It provides higher performance, easier to code, and comes up with automatic & interactive documentation.
FastAPI is built upon two major python libraries – Starlette(for web handling) and Pydantic(for data handling & validation). FastAPI is very fast compared to Flask because it brings asynchronous function handlers to the table.
pip install fastapi
pip install uvicorn
In this section, we are going to deploy our trained NLP model as a REST API with FastAPI. The code for our API will be saved in a python file called main.py, this file will be responsible for running our FastAPI app.
# text preprocessing modules
from string import punctuation
# text preprocessing modules
from nltk.tokenize import word_tokenize
import nltk
from nltk.corpus import stopwords
from nltk.stem import WordNetLemmatizer
import re # regular expression
import os
from os.path import dirname, join, realpath
import joblib
import uvicorn
from fastapi import FastAPI
app = FastAPI(
title="Sentiment Model API",
description="A simple API that use NLP model to predict the sentiment of the movie's reviews",
version="0.1",
)
To load the model we use joblib.load() method and add the path to the model directory. The name of the NLP model is sentiment_model_pipeline.pkl .
# load the sentiment model
with open(
join(dirname(realpath(__file__)), "models/sentiment_model_pipeline.pkl"), "rb"
) as f:
model = joblib.load(f)
We will use the same function called text_cleaning() from Part 1 that cleans the review data by removing stopwords, numbers, and punctuation, and finally, convert each word into its base form by using the lemmatization process in the NLTK package.
def text_cleaning(text, remove_stop_words=True, lemmatize_words=True):
# Clean the text, with the option to remove stop_words and to lemmatize word
# Clean the text
text = re.sub(r"[^A-Za-z0-9]", " ", text)
text = re.sub(r"\'s", " ", text)
text = re.sub(r"http\S+", " link ", text)
text = re.sub(r"\b\d+(?:\.\d+)?\s+", "", text) # remove numbers
# Remove punctuation from text
text = "".join([c for c in text if c not in punctuation])
# Optionally, remove stop words
if remove_stop_words:
# load stopwords
stop_words = stopwords.words("english")
text = text.split()
text = [w for w in text if not w in stop_words]
text = " ".join(text)
# Optionally, shorten words to their stems
if lemmatize_words:
text = text.split()
lemmatizer = WordNetLemmatizer()
lemmatized_words = [lemmatizer.lemmatize(word) for word in text]
text = " ".join(lemmatized_words)
# Return a list of words
return text
The next step is to add our prediction endpoint called "/predict-review" with the GET request method.
@app.get("/predict-review")
“An API endpoint is the point of entry in a communication channel when two systems are interacting. It refers to touchpoints of the communication between an API and a server.”
Then we define a prediction function for this endpoint. The name of the function is called predict_sentiment() with a review parameter.
The predict_sentiment() function will do the following tasks.@app.get("/predict-review")
def predict_sentiment(review: str):
"""
A simple function that receive a review content and predict the sentiment of the content.
:param review:
:return: prediction, probabilities
"""
# clean the review
cleaned_review = text_cleaning(review)
# perform prediction
prediction = model.predict([cleaned_review])
output = int(prediction[0])
probas = model.predict_proba([cleaned_review])
output_probability = "{:.2f}".format(float(probas[:, output]))
# output dictionary
sentiments = {0: "Negative", 1: "Positive"}
# show results
result = {"prediction": sentiments[output], "Probability": output_probability}
return result
Here are all blocks of codes in the main.py file.
# text preprocessing modules
from string import punctuation
# text preprocessing modules
from nltk.tokenize import word_tokenize
import nltk
from nltk.corpus import stopwords
from nltk.stem import WordNetLemmatizer
import re # regular expression
import os
from os.path import dirname, join, realpath
import joblib
import uvicorn
from fastapi import FastAPI
app = FastAPI(
title="Sentiment Model API",
description="A simple API that use NLP model to predict the sentiment of the movie's reviews",
version="0.1",
)
# load the sentiment model
with open(
join(dirname(realpath(__file__)), "models/sentiment_model_pipeline.pkl"), "rb"
) as f:
model = joblib.load(f)
# cleaning the data
def text_cleaning(text, remove_stop_words=True, lemmatize_words=True):
# Clean the text, with the option to remove stop_words and to lemmatize word
# Clean the text
text = re.sub(r"[^A-Za-z0-9]", " ", text)
text = re.sub(r"\'s", " ", text)
text = re.sub(r"http\S+", " link ", text)
text = re.sub(r"\b\d+(?:\.\d+)?\s+", "", text) # remove numbers
# Remove punctuation from text
text = "".join([c for c in text if c not in punctuation])
# Optionally, remove stop words
if remove_stop_words:
# load stopwords
stop_words = stopwords.words("english")
text = text.split()
text = [w for w in text if not w in stop_words]
text = " ".join(text)
# Optionally, shorten words to their stems
if lemmatize_words:
text = text.split()
lemmatizer = WordNetLemmatizer()
lemmatized_words = [lemmatizer.lemmatize(word) for word in text]
text = " ".join(lemmatized_words)
# Return a list of words
return text
@app.get("/predict-review")
def predict_sentiment(review: str):
"""
A simple function that receive a review content and predict the sentiment of the content.
:param review:
:return: prediction, probabilities
"""
# clean the review
cleaned_review = text_cleaning(review)
# perform prediction
prediction = model.predict([cleaned_review])
output = int(prediction[0])
probas = model.predict_proba([cleaned_review])
output_probability = "{:.2f}".format(float(probas[:, output]))
# output dictionary
sentiments = {0: "Negative", 1: "Positive"}
# show results
result = {"prediction": sentiments[output], "Probability": output_probability}
return result
uvicorn main:app --reload
FastAPI provides an Automatic Interactive API documentation page. To access it navigate to //127.0.0.1:8000/docs in your browser and then you will see the documentation page created automatically by FastAPI.
To make a prediction first click the "predict-review" route and then click on the button "Try it out", it allows you to fill the review parameter and directly interact with the API.
Fill the review field by adding a movie review of your choice. I added the following movie review about Zack Snyder's Justice League movie released in 2021.
"I loved the movie from the beginning to the end. Just like Ray fisher said, I was hoping that the movie doesn't end. The begging scene was mind blowing, liked that scene very much. Unlike 'the Justice League' the movie show every hero is best at their own thing, make us love every character. Thanks, Zack and the whole team."Then click the execute button to make a prediction and get the result.
Finally, the result from the API shows that our NLP model predicts the review provided has Positive sentiment with the probability of 0.70.
pip install requests
Then create a simple python file called python_app.py. This file will be responsible to send our HTTP requests.
We first import requests package.import requests as r
Add a movie review about Godzilla vs Kong (2021) Movie.
# add review
review = "This movie was exactly what I wanted in a Godzilla vs Kong movie. It's big loud, brash and dumb, in the best ways possible. It also has a heart in a the form of Jia (Kaylee Hottle) and a superbly expressionful Kong. The scenes of him in the hollow world are especially impactful and beautifully shot/animated. Kong really is the emotional core of the film (with Godzilla more of an indifferent force of nature), and is done so well he may even convert a few members of Team Godzilla."
keys = {"review": review}
prediction = r.get("//127.0.0.1:8000/predict-review/", params=keys)
results = prediction.json()
print(results["prediction"])
print(results["Probability"])
This will show the prediction and its probability.
Here are the results.
Positive
0.54
You can also find me on Twitter and you can read more articles like this here.
Want to keep up to date with all the latest in machine learning? Subscribe to our newsletter in the footer below!