avataralpha2phi

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

7204

Abstract

ing">curl</span> -<span class="hljs-string">O</span> <span class="hljs-string">https</span>://<span class="hljs-string">bootstrap</span>.<span class="hljs-string">pypa</span>.<span class="hljs-string">io</span>/<span class="hljs-built_in">get-pip.py</span> $ <span class="hljs-string">python3</span> <span class="hljs-built_in">get-pip.py</span></pre></div><h2 id="76f1">Install Machine Learning Libraries to EFS</h2><p id="b55e">For the machine learning APIs that I am going to deploy as Lambda function, I need to use <code>torch</code> and <code>torchvision</code> libraries.</p><p id="d249">Create a file called <code>requirements.txt</code> with the <a href="https://download.pytorch.org/whl/torch_stable.html">required libraries</a> (<code>cp37</code> means CPU and Python 3.7).</p><div id="4a99"><pre><span class="hljs-attribute">https</span>://download.pytorch.org/whl/cpu/torch-<span class="hljs-number">1</span>.<span class="hljs-number">7</span>.<span class="hljs-number">1</span>%<span class="hljs-number">2</span>Bcpu-cp37-cp37m-linux_x86_64.whl <span class="hljs-attribute">https</span>://download.pytorch.org/whl/cpu/torchvision-<span class="hljs-number">0</span>.<span class="hljs-number">8</span>.<span class="hljs-number">2</span>%<span class="hljs-number">2</span>Bcpu-cp37-cp37m-linux_x86_64.whl</pre></div><p id="e189">Then I run the pip command to install the libraries to /home/ec2-user/efs/lib</p><div id="5804"><pre><span class="hljs-meta prompt_"># </span><span class="language-bash">pip install --target=/home/ec2-user/efs/lib -r requirements.txt</span></pre></div><figure id="838d"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*OtjGDcYXEl1gnPc0slmm5A.png"><figcaption>PyTorch Installed to EFS</figcaption></figure><h2 id="addc">Deploy Machine Learning Models to EFS</h2><p id="3450">The machine learning models that I will be using is from Torch Hub.</p><p id="91ee">I create a Python file called <code>download_models.py</code> with the following content to download the models into <code>/home/ec2-user/efs/.cache</code></p><div id="9abd"><pre><span class="hljs-keyword">import</span> torch </pre></div><div id="406b"><pre><span class="hljs-function"><span class="hljs-title">print</span><span class="hljs-params">(f<span class="hljs-string">"Pytorch version - {torch.version}"</span>)</span></span> </pre></div><div id="4334"><pre>torch<span class="hljs-selector-class">.hub</span><span class="hljs-selector-class">.set_dir</span>(<span class="hljs-string">"/home/ec2-user/efs/.cache"</span>) </pre></div><div id="4d86"><pre><span class="hljs-attr">model</span> = torch.hub.load(<span class="hljs-string">"pytorch/vision:v0.6.0"</span>,<span class="hljs-string">"deeplabv3_resnet101"</span>, pretrained=<span class="hljs-literal">True</span>) </pre></div><div id="94d3"><pre><span class="hljs-function"><span class="hljs-title">print</span><span class="hljs-params">(<span class="hljs-string">"Model downloaded"</span>)</span></span> </pre></div><div id="aaa8"><pre>model.<span class="hljs-built_in">eval</span>() </pre></div><p id="7104">Run the file to download the models.</p><div id="0890"><pre># <span class="hljs-keyword">python3</span> download_models.<span class="hljs-keyword">py</span></pre></div><figure id="1005"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*gZ6eRTeTwM2ongkd0hV3vg.png"><figcaption>Download Machine Learning Models to EFS</figcaption></figure><p id="696b">Refer to this article on how I automate these manual steps using AWS CDK.</p><div id="5289" class="link-block"> <a href="https://alpha2phi.medium.com/iac-using-aws-cdk-1163c1cf978b"> <div> <div> <h2>IaC using AWS CDK</h2> <div><h3>Overview</h3></div> <div><p>alpha2phi.medium.com</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/1*RKiGXzcjEETWRf_VcffK7g.png)"></div> </div> </div> </a> </div><h1 id="6d5d">The Code</h1><p id="2fe0">With the machine learning libraries and models deployed to EFS, let’s look at the code now. Just like previous article, I am using <a href="https://www.serverless.com/">serverless</a> framework to deploy the Lambda function and API.</p><h2 id="d4e2">serverless.xml</h2><p id="681d">The full serverless.xml is available <a href="https://github.com/alpha2phi/serverless/blob/main/ml-api/serverless.yml">here</a>. There are few things to highlight.</p><div id="936e"><pre><span class="hljs-attribute">functions</span><span class="hljs-punctuation">:</span> <span class="hljs-attribute">vision</span><span class="hljs-punctuation">:</span> <span class="hljs-attribute">handler</span><span class="hljs-punctuation">:</span> <span class="hljs-string">mllib/vision.main</span> <span class="hljs-attribute">fileSystemConfig</span><span class="hljs-punctuation">:</span> <span class="hljs-attribute">localMountPath</span><span class="hljs-punctuation">:</span> <span class="hljs-string">/mnt/efs</span> <span class="hljs-attribute">arn</span><span class="hljs-punctuation">:</span> <span class="hljs-string">arn:aws:elasticfilesystem:ap-southeast-1:450266975445:access-point/fsap-069947df394f6436c</span> <span class="hljs-attribute">vpc</span><span class="hljs-punctuation">:</span> <span class="hljs-attribute">securityGroupIds</span><span class="hljs-punctuation">:</span> <span class="hljs-bullet">-</span> <span class="hljs-string">sg-9cae01ec</span> <span class="hljs-attribute">subnetIds</span><span class="hljs-punctuation">:</span> <span class="hljs-bullet">-</span> <span class="hljs-string">subnet-ee22e788</span> <span class="hljs-attribute">memorySize</span><span class="hljs-punctuation">:</span> <span class="hljs-string">3008</span> <span class="hljs-attribute">timeout</span><span class="hljs-punctuation">:</span> <span class="hljs-string">300</span> <span class="hljs-comment"># layers:</span> <span class="hljs-comment"># - { Ref: PythonRequirementsLambdaLayer }</span> <span class="hljs-attribute">events</span><span class="hljs-punctuation">:</span> <span class="hljs-bullet">-</span> <span class="hljs-string">httpApi:</span> <span class="hljs-attribute">path</span><span class="hljs-punctuation">:</span> <span class="hljs-string">/vision</span> <span class="hljs-attribute">method</span><span class="hljs-punctuation">:</span> <span class="hljs-string">post</span> <span class="hljs-attribute">warmup</span><span class="hljs-punctuation">:</span> <span class="hljs-attribute">default</span><span class="hljs-punctuation">:</span> <span class="hljs-attribute">enabled</span><span class="hljs-punctuation">:</span> <span class="hljs-string">true</span></pre></div><ul><li><code>fileSystemConfig</code> — I mounted the EFS folder to <code>/mnt/efs</code> inside the Lambda container providing the required ARN, security group and subnet.</li><li><code>memorySize</code> — Set to 3GB</li><li><code>warmup</code> — I use <a href="https://github.com/juanj

Options

oDiaz/serverless-plugin-warmup"><code>serverless-plugin-w</code>arm</a> to warm up the Lambda function. Alternatively for a simpler solution just set the <a href="https://www.serverless.com/blog/aws-lambda-provisioned-concurrency"><code>provisionedconcurre</code>ncy</a>.</li></ul><div id="b760"><pre><span class="hljs-attr">custom:</span> <span class="hljs-attr">region:</span> <span class="hljs-string">{opt:region,</span> <span class="hljs-string">self:provider.region}</span> <span class="hljs-attr">stage:</span> <span class="hljs-string">{opt:stage,</span> <span class="hljs-string">self:provider.stage}</span> <span class="hljs-attr">pythonRequirements:</span> <span class="hljs-attr">dockerizePip:</span> <span class="hljs-literal">true</span> <span class="hljs-attr">zip:</span> <span class="hljs-literal">true</span> <span class="hljs-attr">slim:</span> <span class="hljs-literal">true</span> <span class="hljs-attr">strip:</span> <span class="hljs-literal">false</span> <span class="hljs-attr">nodeploy:</span> <span class="hljs-bullet">-</span> <span class="hljs-string">pip</span> <span class="hljs-bullet">-</span> <span class="hljs-string">setuptools</span> <span class="hljs-bullet">-</span> <span class="hljs-string">six</span> <span class="hljs-attr">usestaticcache:</span> <span class="hljs-literal">true</span> <span class="hljs-attr">usedownloadcache:</span> <span class="hljs-literal">true</span> <span class="hljs-attr">cachelocation:</span> <span class="hljs-string">"/mnt/efs/.cache"</span> <span class="hljs-comment"># layer: true</span></pre></div><div id="1adb"><pre><span class="hljs-attr">warmup:</span> <span class="hljs-attr">events:</span> <span class="hljs-bullet">-</span> <span class="hljs-attr">schedule:</span> <span class="hljs-string">"rate(5 minutes)"</span> <span class="hljs-attr">timeout:</span> <span class="hljs-number">50</span> <span class="hljs-attr">default:</span> <span class="hljs-attr">enabled:</span> <span class="hljs-literal">true</span> <span class="hljs-attr">role:</span> <span class="hljs-string">IamRoleLambdaExecution</span></pre></div><p id="9700">As an additional example, I also use <a href="https://github.com/UnitedIncome/serverless-python-requirements"><code>serverless-python-requirements</code></a><code> </code>to bundle some requirements using <code>requirements.txt</code>. Note that I set <code>zip:true</code> to indicate I want to zip up the libraries. Later in the Python code I am going to use the code provided by the plugin to unzip it under <code>/tmp</code> folder inside Lambda container.</p><h2 id="da6f">vision.py</h2><p id="c225">The full source code of <code>vision.py</code> is available <a href="https://github.com/alpha2phi/serverless/blob/main/ml-api/mllib/vision.py">here</a>.</p><p id="7703">You can see these code snippets at the beginning of the file.</p><div id="dfed"><pre><span class="hljs-meta"># Load from EFS mounted folder</span> <span class="hljs-title">try</span>: <span class="hljs-keyword">import</span> sys <span class="hljs-keyword">import</span> os</pre></div><div id="1915"><pre>sys.path.append(<span class="hljs-string">"/mnt/efs/lib"</span>) <span class="hljs-keyword">except</span> ImportError: <span class="hljs-keyword">pass</span></pre></div><div id="2e9e"><pre><span class="hljs-comment"># Load from /tmp</span> <span class="hljs-keyword">try</span>: <span class="hljs-keyword">import</span> unzip_requirements <span class="hljs-keyword">except</span> ImportError: <span class="hljs-keyword">pass</span></pre></div><ul><li>The 1st part of the code is to add <code>/mnt/efs/lib</code> to Python <code>sys.path</code></li><li>The 2nd part uses <a href="https://github.com/UnitedIncome/serverless-python-requirements/blob/master/unzip_requirements.py">code snippet</a> from <code>serverless-python-requirements </code>to unzip the libraries to <code>/tmp</code> and add the path to <code>sys.path</code></li></ul><div id="b46f"><pre><span class="hljs-function"><span class="hljs-title">print</span><span class="hljs-params">(f<span class="hljs-string">"Pytorch version is {torch.version}"</span>)</span></span></pre></div><div id="bd18"><pre>torch<span class="hljs-selector-class">.hub</span><span class="hljs-selector-class">.set_dir</span>(<span class="hljs-string">"/mnt/efs/.cache"</span>) model = torch<span class="hljs-selector-class">.hub</span><span class="hljs-selector-class">.load</span>(<span class="hljs-string">"pytorch/vision:v0.6.0"</span>, <span class="hljs-string">"deeplabv3_resnet101"</span>, pretrained=True) model<span class="hljs-selector-class">.eval</span>()</pre></div><div id="f654"><pre><span class="hljs-function"><span class="hljs-title">print</span><span class="hljs-params">(<span class="hljs-string">"Model is loaded successfully."</span>)</span></span></pre></div><p id="b3d4">For Torch Hub I also set it to use the <code>.cache </code>folder under EFS.</p><h1 id="f9f5">Deployment and Testing</h1><h2 id="2503">Deployment</h2><p id="94d7">To deploy the API, just run <code>serverless deploy</code> or <code>sls deploy</code>. The deployment should be fast as I am not bundling large libraries into the package.</p><div id="8e73"><pre><span class="hljs-meta"># sls deploy</span></pre></div><h2 id="308f">Testing</h2><p id="b093">Run the <code>serverless logs</code> command to monitor the CloudWatch log.</p><p id="01da">In case you need to retrieve information regarding the deployed APIs, run <code>sls info</code>.</p><div id="4295"><pre><span class="hljs-meta"># sls logs -f vision -t</span></pre></div><p id="e03f">Monitor the log file until the Lambda function is warm up.</p><p id="de26">Use the notebook available <a href="https://github.com/alpha2phi/serverless/blob/main/ml-api/notebooks/ml-api-test.ipynb">here</a> to send the image to the API for testing.</p><figure id="ec51"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*DPNnIDmmQy38Y6ix4_6-4w.png"><figcaption>Jupyter Notebook For Testing</figcaption></figure><h1 id="0ec8">Summary</h1><p id="16ca">As you can see it is possible to deploy machine learning APIs on AWS using Lambda, API Gateway and EFS, though it may not be so straight forward.</p><p id="a103">However, currently there is no GPU support for AWS Lambda. If your models require GPU support for good performance, Lambda may not be the right solution for you.</p><p id="1495">You may also want to check out this article.</p><div id="93ba" class="link-block"> <a href="https://readmedium.com/serving-machine-learning-models-dcgan-pgan-resnext-using-fastapi-and-streamlit-2ef426f2e9de"> <div> <div> <h2>Serving Machine Learning Models (DCGAN, PGAN, ResNext) using FastAPI and Streamlit</h2> <div><h3>Overview</h3></div> <div><p>medium.com</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/1*T0MnJkNTLUFXBtfjTpLiYQ.png)"></div> </div> </div> </a> </div></article></body>

CODEX

Serverless Machine Learning APIs using Lambda and EFS

Photo by Arseny Togulev on Unsplash

Overview

In previous article I walk through with you on how to set up a serverless API to test out web pages under different resolutions. In that solution in order to work around AWS Lambda limitation I use the chrome-aws-lambda binary instead of the full Puppeteer library.

However, this definitely will not work if we need to host machine learning APIs. Specifically AWS Lambda has the limitation of

There are basically 2 issues here related to hosting serverless machine learning APIs, not including the lack of GPU support currently.

Size of Machine Learning Libraries

With the recent torch and torchvision libraries, the unzipped files size already exceed the above limits.

Size of Machine Learning Models

Machine learning models, with millions or billions of parameters, definitely take up storage way beyond the AWS Lambda limits.

Also API gateway has a limit of 30 seconds so it is necessary to warm up the AWS Lambda function for better performance.

In this article I am going to show you how to host a machine learning API using AWS Lambda and AWS EFS to overcome some of the limitations imposed.

I am going to deploy the DeepLabV3 model with a ResNet-101 backbone.

DEEPLABV3-RESNET101

Solutions

AWS Lambda Layers — Not Working

As mentioned in AWS documentation, AWS Lambda layers do count into the unzipped deployment package size. Using AWS Lambda layers will reduce your deployment time but is not going to solve the issue on size limitations.

AWS S3 — Partial Solution

You can use AWS S3 to store the machine learning models and load them when Lambda function starts. This resolves the issue on machine learning model storage. However this solution does not help in resolving the issue related to large libraries and binaries.

AWS Lambda /tmp Folder — Partial Solution

AWS Lambda /tmp folder can store files up to 512MB. The serverless-python-requirements plugin can zip up the libraries specified in requirements.txt and unzip the files into /tmp, set the Python sys.path when the Lambda function starts.

However, due to the 512MB limitation, this only resolves the issue partially. What if the libraries or the models go beyond 512MB?

I will demonstrate this feature later in this article.

AWS EFS

Using AWS EFS together with AWS Lambda resolves the storage issue for large libraries/binaries and machine learning models. By keeping Lambda functions warm and leveraging AWS EFS, you can develop reasonable good performing machine learning APIs.

Setting up AWS EFS for Lambda

I am assuming you have some basic knowledge of AWS on how to set up EC2 and EFS. If not check out the links to the documentation in below steps.

Create EFS File System and Access Point

Follow the documentation to create a EFS file system and access point. Below are screenshots on what I have created for my Lambda functions.

EFS File System
EFS Access Point

Launch EC2 and Attach to EFS

Launch a t2-micro EC2 instance using Amazon Linux 2 AMI (make sure the security group is same as the one you use to create EFS).

Login to the EC2 instance and mount the EFS folder. In my case I mount it to /home/ec2-user/efs.

# sudo mount -t efs -o tls,accesspoint=fsap-069947df394f6436c fs-4e23c80e:/ /home/ec2-user/efs
EC2 Connected to EFS

Install Python and Pip

I need to install Python and Pip in order to set up the libraries in EFS folder. For my Lambda function I use Python 3.7 runtime.

$ sudo yum install python37
$ curl -O https://bootstrap.pypa.io/get-pip.py
$ python3 get-pip.py

Install Machine Learning Libraries to EFS

For the machine learning APIs that I am going to deploy as Lambda function, I need to use torch and torchvision libraries.

Create a file called requirements.txt with the required libraries (cp37 means CPU and Python 3.7).

https://download.pytorch.org/whl/cpu/torch-1.7.1%2Bcpu-cp37-cp37m-linux_x86_64.whl
https://download.pytorch.org/whl/cpu/torchvision-0.8.2%2Bcpu-cp37-cp37m-linux_x86_64.whl

Then I run the pip command to install the libraries to /home/ec2-user/efs/lib

# pip install --target=/home/ec2-user/efs/lib -r requirements.txt
PyTorch Installed to EFS

Deploy Machine Learning Models to EFS

The machine learning models that I will be using is from Torch Hub.

I create a Python file called download_models.py with the following content to download the models into /home/ec2-user/efs/.cache

import torch 
print(f"Pytorch version - {torch.__version__}")  
torch.hub.set_dir("/home/ec2-user/efs/.cache") 
model = torch.hub.load("pytorch/vision:v0.6.0","deeplabv3_resnet101", pretrained=True) 
print("Model downloaded") 
model.eval()

Run the file to download the models.

# python3 download_models.py
Download Machine Learning Models to EFS

Refer to this article on how I automate these manual steps using AWS CDK.

The Code

With the machine learning libraries and models deployed to EFS, let’s look at the code now. Just like previous article, I am using serverless framework to deploy the Lambda function and API.

serverless.xml

The full serverless.xml is available here. There are few things to highlight.

functions:
  vision:
    handler: mllib/vision.main
    fileSystemConfig:
      localMountPath: /mnt/efs
      arn: arn:aws:elasticfilesystem:ap-southeast-1:450266975445:access-point/fsap-069947df394f6436c
    vpc:
      securityGroupIds:
        - sg-9cae01ec
      subnetIds:
        - subnet-ee22e788
    memorySize: 3008
    timeout: 300
    # layers:
    #   - { Ref: PythonRequirementsLambdaLayer }
    events:
      - httpApi:
          path: /vision
          method: post
    warmup:
      default:
        enabled: true
  • fileSystemConfig — I mounted the EFS folder to /mnt/efs inside the Lambda container providing the required ARN, security group and subnet.
  • memorySize — Set to 3GB
  • warmup — I use serverless-plugin-warm to warm up the Lambda function. Alternatively for a simpler solution just set the provisionedconcurrency.
custom:
  region: ${opt:region, self:provider.region}
  stage: ${opt:stage, self:provider.stage}
  pythonRequirements:
    dockerizePip: true
    zip: true
    slim: true
    strip: false
    nodeploy:
      - pip
      - setuptools
      - six
    usestaticcache: true
    usedownloadcache: true
    cachelocation: "/mnt/efs/.cache"
    # layer: true
warmup:
    events:
      - schedule: "rate(5 minutes)"
    timeout: 50
    default:
      enabled: true
      role: IamRoleLambdaExecution

As an additional example, I also use serverless-python-requirements to bundle some requirements using requirements.txt. Note that I set zip:true to indicate I want to zip up the libraries. Later in the Python code I am going to use the code provided by the plugin to unzip it under /tmp folder inside Lambda container.

vision.py

The full source code of vision.py is available here.

You can see these code snippets at the beginning of the file.

# Load from EFS mounted folder
try:
    import sys
    import os
sys.path.append("/mnt/efs/lib")
except ImportError:
    pass
# Load from /tmp
try:
    import unzip_requirements
except ImportError:
    pass
  • The 1st part of the code is to add /mnt/efs/lib to Python sys.path
  • The 2nd part uses code snippet from serverless-python-requirements to unzip the libraries to /tmp and add the path to sys.path
print(f"Pytorch version is {torch.__version__}")
torch.hub.set_dir("/mnt/efs/.cache")
model = torch.hub.load("pytorch/vision:v0.6.0", "deeplabv3_resnet101", pretrained=True)
model.eval()
print("Model is loaded successfully.")

For Torch Hub I also set it to use the .cache folder under EFS.

Deployment and Testing

Deployment

To deploy the API, just run serverless deploy or sls deploy. The deployment should be fast as I am not bundling large libraries into the package.

# sls deploy

Testing

Run the serverless logs command to monitor the CloudWatch log.

In case you need to retrieve information regarding the deployed APIs, run sls info.

# sls logs -f vision -t

Monitor the log file until the Lambda function is warm up.

Use the notebook available here to send the image to the API for testing.

Jupyter Notebook For Testing

Summary

As you can see it is possible to deploy machine learning APIs on AWS using Lambda, API Gateway and EFS, though it may not be so straight forward.

However, currently there is no GPU support for AWS Lambda. If your models require GPU support for good performance, Lambda may not be the right solution for you.

You may also want to check out this article.

Serverless
Python
AWS
Programming
Machine Learning
Recommended from ReadMedium