Deploy A Machine Learning Model As An API On AWS, Step by Step
Deploy A Machine Learning Model As An API On AWS, Step by Step
Deploy A Machine Learning Model As An API On AWS, Step by Step
There are dozens of great articles and tutorials written every day discussing how to
develop all kinds of machine learning models. However, I rarely see articles explaining
how to put models into production. If you want your model to have a real-world
impact, it needs to be accessible to other users and applications.
/
This step-by-step guide will show you how to deploy a model as an API. Building an
API for your model is a great way to integrate your work into your companies systems —
other developers need only learn how to interact with your API to use your model. It’s
also an excellent way for aspiring data scientists to make their portfolio projects
stand out.
This tutorial is for data scientists and aspiring data scientists with little experience in
deploying apps and APIs to the web. By the end, you will know how to:
3. Deploy the model API to the web using AWS Elastic Beanstalk.
Updates are more straightforward as the developers of each system don’t need to
worry about breaking the other.
More resilient, as a failure in the main application does not impact the model API
and vice versa.
The Model
If you’re developing a project portfolio, it’s best to use less conventional datasets to help
you stand out to employers. However, for the sake of this tutorial, I’ll be using the
famous Boston house prices dataset. The dataset contains several features that can be
used to predict the value of residential homes in Boston circa 1980.
I chose to use Random Forest to handle this regression problem. I arbitrarily selected a
subset of features for inclusion in the model. If I were developing a “real-world” model, I
would try out many different models and carefully select features. /
Check out my GitHub repo for instructions to quickly build and save the model. Follow
along, then build an API for your modeling projects!
The API
Create the script app.py in the app/ directory. This directory should also contain the
saved model ( model.pkl ) if you followed the instructions in the repo.
These first few lines in app/app.py import useful functionality from Flask, NumPy, and
pickle. We’re also importing FEATURES from app/features.py which is included below.
Next, we initialize the app and load the model.
# app/app.py
Features
I’ve stored the feature list in a separate script for consistency between model training and
predictions in the API.
# app/features.py
Endpoints
Our Flask app object (defined above as app = Flask(__name__) ) has a useful decorator
method that makes it easy to define endpoints — .route() . In the code below,
/
@app.route('/api') tells the server to execute the api() function, defined directly
below it, whenever http://{your_ip_address}/api receives a request.
# app/app.py (continued)
@app.route('/api', methods=['GET'])
def api():
"""Handle request and output model score in json format."""
# Handle empty requests.
if not request.json:
return jsonify({'error': 'no request received'})
return jsonify(response)
Parse Requests
We need to include the parse_args() function to parse our features out of the JSON
requests.
# app/app.py (continued)
def parse_args(request_dict):
"""Parse model features from incoming requests formatted in
JSON."""
# Initialize missing_data as False.
missing_data = False
/
Start the Application
Finally, run the application on Flask’s development server to make sure it’s working.
# app/app.py (continued)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
Start the server with $ python app.py . In another terminal window, send a request to
the API using curl . Pass the features with the --data flag in JSON format.
{
"ESTIMATE": 18,
"MISSING_DATA": false
}
# app/wsgi.py
Now, run $ gunicorn app:app --bind 0.0.0.0:5000 . You should be able to execute the
/
$ curl -X GET "http://0.0.0.0:5000/api" -H "Content-Type:
application/json" --data '{"INDUS":"5.9", "RM":"4.7", "AGE":"80.5",
"DIS":"3.7", "NOX":"0.7", "PTRATIO":"13.6"}'
{
"ESTIMATE": 18,
"MISSING_DATA": false
}
Docker
Docker is all the rage these days, and much has been written about its benefits. If you’re
interested in learning more about Docker and getting a more in-depth intro, read this.
For this tutorial, you’ll need to get Docker set up on your computer, follow the
instructions here. You’ll also need a Docker Hub account.
Once you’re all set up, let’s dive in! There are two main files you’ll need to build a Docker
image, Dockerfile and requirements.txt .
# app/Dockerfile
# Expose port
EXPOSE 5000
/
requirements.txt contains all of the Python packages needed for our app.
# app/requirements.txt
Flask==1.0.2
itsdangerous==1.1.0
Jinja2==2.10.1
MarkupSafe==1.1.1
simplejson==3.16.0
Werkzeug==0.15.2
numpy==1.16.4
pandas==0.24.2
scikit-learn==0.19.1
scipy==1.0.0
requests==2.22.0
gunicorn==19.9.0
Your application is now running in a Docker container. Rerun the curl command, and
you will get the same output!
{
"ESTIMATE": 18,
"MISSING_DATA": false
}
Next, we’ll create a file that tells AWS where to access our image. Call this
Dockerrun.aws.json . The critical piece here is the “Name” value. My Docker Hub
username is “blemi”, and I’ve named the image “model_api”, so I would put
blemi/model_api:latest as the “Name” value.
{
"AWSEBDockerrunVersion": "1",
"Image": {
"Name": "<your-dockerhub-username>/model_api:latest",
"Update": "true"
},
"Ports": [
{
"ContainerPort": "5000"
}
],
"Logging": "/var/log/nginx"
}
In the AWS console, search for “Elastic Beanstalk” and select it.
Select “Create New Application” in the top righthand corner, add a name and description
to your application, and click “Create.”
/
Click “Create one now.”
/
Fill in a custom value for “Domain” and “Description” if you like. For “Platform”, choose
“Preconfigured platform” and select “Docker” in the dropdown. For “Application code”,
select “Upload your code” and click on the “Upload” button.
Click the “Choose File” button and open the Dockerrun.aws.json file that we created
above. Note: this is only going to work if you’ve pushed your Docker image to Docker
Hub.
/
Click “Upload” then “Create Environment” to deploy the application.
Note: If you’re creating a production-grade API, you’ll likely want to select “Configure
more options” here before selecting “Create Environment” — if you’re interested in
learning about some of the other options to enhance security and scalability, please
contact me. My info is at the bottom of this article.
The app will take a few minutes to deploy, but once it does, you can access it at the URL
provided at the top of the screen:
Now, let’s run the curl command on our API hosted on the web.
{"ESTIMATE":18,"MISSING_DATA":false}
There’s more that needs to be done to make this API production-ready. Within AWS, and
the Flask application itself, there are many configurations you can set to enhance
security. There are also many options to help with scalability if usage is heavy. Flask-
RESTful is a Flask extension that makes conforming with REST API best practices easy. If
you’re interested in using Flask-RESTful, check out this great tutorial.
Get in touch
If you have any feedback or critiques, please share with me. If you found this guide
useful, be sure to follow me, so you don’t miss future articles.
If you would like to get in touch, connect with me on LinkedIn. Thanks for reading!