| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
This is an example machine learning image recognition stack using Lambda Container Images. Container images can include more source assets than traditional ZIP packages (10 GB vs 250 MB image sizes), allowing for larger ML models to be used.
This example contains an AWS Lambda function that uses the Open Images Dataset TensorFlow model to detect objects in an image. When you invoke the /detector API route with a URL to an image the function will download the image, use the tensorflow model to detect objects in it, then return an annotated version of the image back to the client.
Here is an overview of the files in this repo:
.
├── .gitignore <-- Gitignore for Stackery
├── .stackery-config.yaml <-- Default CLI parameters for root directory
├── LICENSE <-- MIT!
├── README.md <-- This README file
├── src
│ └── Recognizer
│ ├── Dockerfile <-- Dockerfile for building Recognizer Function
│ ├── font
│ │ ├── Apache License.txt <-- License for OpenSans font used for annotation labels
│ │ └── OpenSans-Regular.ttf <-- OpenSans font used for annotation labels
│ ├── handler.py <-- Recognizer Function Python source
│ └── requirements.txt <-- Recognizer Function Python dependencies
└── template.yaml <-- SAM infrastructure-as-code template
The repository contains a complete example stack that can be imported directly into Stackery and deployed. The rest of this README walks you through building your own ML stack using Stackery.
# Download the Open Images TensorFlow model and extract it to the `model`
# folder.
FROM alpine AS builder
RUN mkdir model
RUN wget -c https://storage.googleapis.com/tfhub-modules/google/openimages_v4/ssd/mobilenet_v2/1.tar.gz -O - | tar xz -C model
# Make sure it's world-readable so the Lambda service user can access it.
RUN chmod -R a+r model
# Build the runtime image from the official AWS Lambda Python base image.
FROM public.ecr.aws/lambda/python
# Copy the extracted Open Images model into the source code space.
COPY --from=builder model model
# Copy in the sources.
COPY handler.py requirements.txt ./
# Copy the OpenSans font for annotation use
COPY font ./font
# Install the Python dependencies
RUN python3 -m pip install -r requirements.txt
# Tell the Lambda runtime where the function handler is located.
CMD ["handler.lambda_handler"]requests tensorflow Pillow
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# Copyright Stackery, Inc. All Rights Reserved.
# SPDX-License-Identifier: MIT-0
import base64
from io import BytesIO
from PIL import Image, ImageDraw, ImageFont
import requests
import tensorflow as tf
# Detect and annotate top N objects
NUM_OBJECTS = 3
# Loading model
loaded_model = tf.saved_model.load('model')
detector = loaded_model.signatures['default']
# Loading font
font = ImageFont.truetype('font/OpenSans-Regular.ttf', 25)
def lambda_handler(event, context):
# Get image URL from `url` querystring parameter
r = requests.get(event['queryStringParameters']['url'])
# Detect objects from image
objects = detect_objects(r.content)
# Annotate objects onto image
img = annotate_image(r.content, objects)
# Encode image back into original format
with BytesIO() as output:
img.save(output, format=img.format)
body = output.getvalue()
# Send 200 response with annotated image back to client
return {
'statusCode': 200,
'isBase64Encoded': True,
'headers': {
'Content-Type': img.get_format_mimetype()
},
'body': base64.b64encode(body)
}
def detect_objects(image_content):
img = tf.io.decode_image(image_content)
# Executing inference.
converted_img = tf.image.convert_image_dtype(img, tf.float32)[tf.newaxis, ...]
result = detector(converted_img)
return [
{
# TF results are in [ ymin, xmin, ymax, xmax ] format, switch to [ ( xmin, ymin ), ( xmax, ymax ) ] for PIL
'box': [ ( result['detection_boxes'][i][1], result['detection_boxes'][i][0] ), ( result['detection_boxes'][i][3], result['detection_boxes'][i][2] ) ],
'score': result['detection_scores'][i].numpy(),
'class': result['detection_class_entities'][i].numpy().decode('UTF-8')
} for i in range(NUM_OBJECTS)
]
def annotate_image(image_content, objects):
img = Image.open(BytesIO(image_content))
draw = ImageDraw.Draw(img)
for object in objects:
# Multiply input coordinates, which range from 0 to 1, to number of pixels
box = [ ( object['box'][0][0] * img.width, object['box'][0][1] * img.height ), ( object['box'][1][0] * img.width, object['box'][1][1] * img.height ) ]
# Draw red rectangle around object
draw.rectangle(box, outline='red', width=5)
# Create label text and figure out how much space it uses
label = f"{object['class']} ({round(object['score'] * 100)}%)"
label_size = font.getsize(label)
# Draw background rectangle for label
draw.rectangle([ box[0], ( box[0][0] + label_size[0], box[0][1] + label_size[1]) ], fill='red')
# Draw label text
draw.text(box[0], label, fill='white', font=font)
return img;You can easily test the stack by opening the API in your browser. First, we need to find the domain name of your API. You can do this either from the Stackery CLI or the Stackery dashboard.
Now, open your API in your browser by pasting in the url to your domain and appending /detector?url=https%3A%2F%2Fimages.pexels.com%2Fphotos%2F310983%2Fpexels-photo-310983.jpeg%3Fauto%3Dcompress%26cs%3Dtinysrgb%26dpr%3D2%26h%3D650%26w%3D940. This will tell the API to download this image and annotate it with the three objects it is most confident about identifying:
Note: It can take a minute or two for TensorFlow to load the image model and begin processing. This means the first time you use the API after a few minutes of inactivity it will timeout after 29 seconds while it is still loading. The Function will run to completion, but the HTTP API stops waiting after 29 seconds. So, try to hit the url, and after a few timeouts you should be able to load the result. It takes less than a second to process the image when the Lambda Function is warm. If you want to ensure you always have a warm function, consider adding Provisioned Concurrency, though keep in mind the cost considerations of doing so.
We love hearing if we've helped folks learn more about AWS, serverless, or any other aspect of building this ML project! If you're so inclined, give us a shout out on Twitter @stackeryio. We'd love to send some thanks your way, too!
| Back | FazBrowse Home | New Git URL |