Hosting your ML model on AWS Lambdas + API Gateway Part 1 | by Evan Miller | Towards Data Science

But now someone wants to use your model. That’s great news ain’t it?
It definitely is, but a whole new problem comes up. You’ve gotta put it somewhere and make it available to other people in the business.
I’ll show you how to do it easily and cheaply on AWS.
For my other articles on Model Deployment check out the link above the title.
This tutorial series will show you how to use AWS to do this. In specific we’ll be using the following components:
S3 buckets
Lambda functions
Lambda layers
API gateway (coming in part 2)
I’m not using Sagemaker because it can be quite expensive £100 p/m per model opposed to lambda functions where you just pay per request.
That can result in lambdas being 1/5th to 1/10th of the cost of running the same models on Sagemaker, especially if you’ve got a few models going to deployment with low traffic.
You’ll need a few things to complete this. You’ll need an installation of Python (scikit learn, pandas etc) and Docker installed. Docker will be needed to build the correct lambda layer files if you are on a Windows machine (I learned this the hard way).
So you’ll need a model first. I’m going to build my model off the UK house price dataset on Kaggle(the data can be found here and my code here).
Lambdas are small runtimes that do very specific tasks. They can take awhile to configure but they are fully managed by AWS so all you need to configure is the memory of your lambda.
They can have installations of Python on them but they won’t have the packages installed to run the model out of the box. To enable that functionality we need to use lambda layers.
Lambda layers are very similar to Docker images if you’re familiar with them. Each layer inherits the layer above’s functionality. But there’s a few things you’ll need to know about them.
Lambda layers need to be zip files
You can only have five lambda layers for a given lambda function
The lambda layers can’t be bigger than 250MB (in total, unzipped)
For this example we’ll need to use 4 lambda layers
Numpy / scipy layer as we’ll need these packages for later layers (pre-built by AWS)Pandas layer to allow us to use the ColumnTransformer used in our modelSklearn layer to enable use of the scikit-learn libraryModel layer where our model will reside
Numpy / scipy layer as we’ll need these packages for later layers (pre-built by AWS)
Pandas layer to allow us to use the ColumnTransformer used in our model
Sklearn layer to enable use of the scikit-learn library
Model layer where our model will reside
So next I’ll show you how to build your own AWS lambda layer to allow your lambda function to use Pandas
These steps will be the same between both Pandas/scikit-learn layers so we’ll focus on nailing them here and you can repeat the steps for the scikit-learn layer.
Next you’ll need open bash/Powershell and to change directory to the layers/Pandas directory.
Then run this command:
docker run --rm -it -v ${PWD}:/var/task lambci/lambda:build-python3.6 bash
NB: ${PWD} mounts the current working directory to the image in Windows environments in Powershell. If you’re using mac/linux $pwd should work fine.
This simple command does a few things:
Pulls down the docker image for lambci. This docker image emulates the runtime of the Python 3.6 lambda environment and allows us to build the files in the same environment as they will run in (this is hella important for Windows users)
Mounts the current directory as a volume so the docker image can output the lambda build files
Allows us to bash into the docker image directly
Now run the following script to build the python files for your lambda layer in the docker image bash (exactly the same for the sklearn layer too):
pip install -r requirements.txt --no-deps -t python/lib/python3.6/site-packages/
This builds the python required files for using Pandas in your lambda function. The main difference is all your file extensions in the __pycache__ should have .pyc file types. These files are needed to run the code on the lambda linux environment.
Next we need to create a zip file for the code to be used.
Lambda layers need to have a specific folder structure in the zip file:
- python  - lib    - python3.6      - site-packages        - all your python package files will be included in here
So go through and run the code in zip_layers.py which will create zip files that will work as lambda layers.
Next steps are:
Upload your pandas_layer.zip to S3Copy the path of your pandas_lambda.zip file in the S3 bucketSelect Lambda on AWS servicesClick the left hand panel and select layersCreate a new layer
Upload your pandas_layer.zip to S3
Copy the path of your pandas_lambda.zip file in the S3 bucket
Select Lambda on AWS services
Click the left hand panel and select layers
Create a new layer
Viola, you’ve created your first lambda layer! But now we need to test that it works. To do this you’ll need to create a lambda function with a Python 3.6 runtime.
To add lambda layers you’ll need to click the Layers icon in the lambda function template and then click the Add a layer button.
Then you’ll select numpy/scipy from the list of runtime compatible layers and then select your Pandas layer you just built.
But be sure to put the numpy/scipy layer first. Otherwise the pandas layer won’t be able use the numpy dependency from the layer above it.
And don’t forget to click save!!
Next you’ll need to refresh your page and go through and edit the lambda function. Use the following code to test that the Pandas functionality is working as you’d expect:
import jsonimport pandas as pddef lambda_handler(event, context):        print((pd.DataFrame(data={'col1': [1, 2, 3, 4]})))
Save your function and click test. You’ll need to create a test case but just give the sample a name as we don’t need it until we build the model layer.
If you see the below output then great success, you’ve got pandas working on your lambda funciton. Woooooo.
Now we’ll need to repeat the above steps to use docker to build the files for us to use sklearn. Repeat the above steps (with the sklearn resources.txt from my github) to create the new sklearn_lambda.zip and upload it to S3.
Now we’ll need to test that the sklearn installation is working on the lambda function. To use this we’ll just update the lambda function code from above to include references to sklearn.
import jsonimport pandas as pdimport sklearndef lambda_handler(event, context):        print((pd.DataFrame(data={'col1': [1, 2, 3, 4]})))    print(sklearn.__version__)
If you see that 0.20.3 is added to the output of the lambda then you’ve done very well, almost all of the hard work is done!! Next we’ll add the model to the lambda function so we can start returning model predictions.
From running the build_model.py you’ll have a perfectly formatted zip for using the model on your lambdas.
To add this to your function you‘ll repeat the above steps and get use that zip file (upload the zip to S3, create a new model layer and then add the layer to your lambda function).
To test this we’ll need to do a bit more work. Firstly we’ll need to configure the JSON to allow for inputting the fields needed for the model.
If you didn’t change the basic test case in the lambdas your test JSON will look like this:
{    "key1": "value1",  "key2": "value2",  "key3": "value3"}
Now you’ll want to update that to work with our required model inputs.
{    "Property Type": "S",     "Old/New": "Y",     "Duration": "L"}
Once you’ve linked up your model lambda layer to your lambda function you should be ready to go.
Update your lambda function to this code and you’ll be able to return predictions from your model. The lambda function will have taken your model layer and saved your .pkl file to /opt/model_name.pkl in your lambda function.
import jsonimport pandas as pdfrom sklearn.externals import joblibmodel = joblib.load('/opt/house_price_model.pkl')def lambda_handler(event, context):            df = pd.DataFrame([event])        # Returning the value from the list    result = model.predict(df)[0]         return result
And that’s it. If all the steps have worked then you should get a result. I get 164344.6062626412, but it’ll depend on your random seed, number of features etc.
But that’s it. It isn’t too scary, but it can take awhile if you don’t know the ins and outs.
Next I’ll hook this lambda into the API gateway so we can call our model API using the requests package in Python.