├── .gitignore ├── .idea └── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── blazingtext-text-classification-train-in-sagemaker-deploy-with-lambda ├── README.md ├── blazingtext-text-classification-train-in-sagemaker-deploy-with-lambda.ipynb ├── container │ ├── Dockerfile │ └── app │ │ └── app.py └── events │ └── event.json ├── djl-object-detection-inference-docker-lambda ├── Dockerfile ├── README.md ├── build.gradle ├── events │ └── event.json ├── gradle │ ├── lambda-build-init.gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── src │ ├── main │ │ └── java │ │ │ └── com │ │ │ └── example │ │ │ ├── App.java │ │ │ └── Request.java │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ ├── AppTest.java │ │ ├── MockContext.java │ │ └── MockLogger.java └── template.yaml ├── djl-tensorflow-lite-inference-docker-lambda ├── Dockerfile ├── README.md ├── build.gradle ├── events │ └── event.json ├── gradle │ ├── lambda-build-init.gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── src │ ├── main │ │ └── java │ │ │ └── com │ │ │ └── example │ │ │ ├── App.java │ │ │ └── Request.java │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ ├── AppTest.java │ │ ├── MockContext.java │ │ └── MockLogger.java └── template.yaml ├── hebert-sentiment-analysis-inference-docker-lambda ├── .gitignore ├── Dockerfile ├── README.md ├── app │ └── app.py ├── events │ └── event.json ├── hebert_model.py ├── requirements.txt └── template.yaml ├── img ├── aws_lambda.png ├── aws_ml.png ├── djl_object_detection_configure_test_event.png ├── djl_object_detection_execution_result.png ├── djl_tensorflow_lite_configure_test_event.png ├── djl_tensorflow_lite_execution_result.png ├── docker.png ├── fasttext_configure_test_event.png ├── fasttext_execution_result.png ├── hebert_configure_test_event.png ├── hebert_execution_result.png ├── pytorch_configure_test_event.png ├── pytorch_execution_result.png ├── scikit-learn_configure_test_event.png ├── scikit-learn_execution_result.png ├── tensorflow_configure_test_event.png ├── tensorflow_execution_result.png ├── tensorflow_mnist_sagemaker_configure_test_event.png ├── tensorflow_mnist_sagemaker_execution_result.png ├── xgboost-built-in-algo-train-in-sagemaker-deploy-with-lambda-copy-outputs.png ├── xgboost_arm_64_arch_view.png ├── xgboost_arm_64_execution_result.png ├── xgboost_configure_test_event.png ├── xgboost_direct_marketing_configure_test_event.png ├── xgboost_direct_marketing_execution_result.png ├── xgboost_execution_result.png └── xgboost_x86_64_arm64_improvement.png ├── online-machine-learning-aws-lambda ├── .gitignore ├── README.md ├── __init__.py ├── app │ ├── lambda_inference │ │ ├── Dockerfile │ │ ├── __init__.py │ │ ├── app.py │ │ └── requirements.txt │ └── lambda_training │ │ ├── Dockerfile │ │ ├── __init__.py │ │ ├── app.py │ │ └── requirements.txt ├── env.json ├── events │ ├── inference_event.json │ └── train_event.json ├── img │ └── architecture_diagram.png ├── notebooks │ └── test_notebook.ipynb └── template.yml ├── pytorch-inference-docker-lambda ├── .gitignore ├── Dockerfile ├── README.md ├── app │ └── app.py ├── events │ └── event.json ├── model │ └── resnet.py ├── requirements.txt └── template.yaml ├── scikit-learn-inference-docker-lambda ├── .gitignore ├── Dockerfile ├── README.md ├── app │ └── app.py ├── events │ └── event.json ├── requirements.txt ├── template.yaml └── train-code │ └── scikit_learn_iris.py ├── tensorflow-inference-docker-lambda ├── .gitignore ├── Dockerfile ├── README.md ├── app │ └── app.py ├── events │ └── event.json ├── requirements.txt └── template.yaml ├── tensorflow-train-in-sagemaker-deploy-with-lambda ├── README.md ├── container │ ├── Dockerfile │ ├── app │ │ └── app.py │ └── requirements.txt ├── events │ └── event.json ├── mnist-2.py ├── template.yaml └── tensorflow_script_mode_training_in_sagemaker_and_serving_with_lambda.ipynb ├── xgboost-built-in-algo-train-in-sagemaker-deploy-with-lambda ├── .gitignore ├── Dockerfile ├── README.md ├── app │ └── app.py ├── events │ └── event.json ├── notebooks │ └── xgboost_direct_marketing_sagemaker_inference_with_lambda.ipynb ├── requirements.txt └── template.yaml ├── xgboost-inference-arm64-docker-lambda ├── .gitignore ├── Dockerfile ├── README.md ├── app │ └── app.py ├── events │ └── event.json ├── invoke_x86_64_arm64_lambdas.py ├── requirements.txt ├── template.yaml └── train-code │ └── bc_xgboost_train.py └── xgboost-inference-docker-lambda ├── .gitignore ├── Dockerfile ├── README.md ├── app └── app.py ├── events └── event.json ├── requirements.txt ├── template.yaml └── train-code └── bc_xgboost_train.py /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | /dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *main* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 10 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 11 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 12 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 13 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Pay as you go inference with AWS Lambda (Container Image Support) 2 | ![AWS ML](img/aws_ml.png) ![AWS Lambda](img/aws_lambda.png) ![Docker](img/docker.png) 3 | 4 | This repository contains resources to help you deploy Lambda Functions based on Python and Java [Docker Images](https://aws.amazon.com/blogs/aws/new-for-aws-lambda-container-image-support/). 5 | 6 | The applications deployed illustrate how to perform inference for scikit-learn, XGBoost, TensorFlow and PyTorch models using Lambda Function. 7 | 8 | ## Overview 9 | 10 | AWS Lambda is one of the most cost-effective service that lets you run code without provisioning or managing servers. 11 | 12 | It offers many advantages when working with serverless infrastructure. When you break down the logic of your machine learning service into a single Lambda function for a single request, things become much simpler and easy to scale. 13 | 14 | You can forget all about the resource handling needed for the parallel requests coming into your model. 15 | 16 | **If your usage is sparse and tolerable to a higher latency, Lambda is a great choice among various solutions.** 17 | 18 | ### Repository Structure 19 | 20 | The repository contains the following resources: 21 | 22 | - **scikit-learn resources:** 23 | 24 | - [**Serverless scikit-learn Model Serving**](scikit-learn-inference-docker-lambda): This examples illustrates how to serve scikit-learn model on Lambda Function to predict based on iris dataset. 25 | 26 | - **XGBoost resources:** 27 | 28 | - [**Serverless XGBoost Model Serving**](xgboost-inference-docker-lambda): This examples illustrates how to serve XGBoost model on Lambda Function to predict breast cancer. 29 | - [**Serverless XGBoost Model Serving on Graviton2 architecture**](xgboost-inference-arm64-docker-lambda): This examples illustrates how to serve XGBoost model on Lambda Function on Graviton2 architecture to predict breast cancer. 30 | - **TensorFlow resources:** 31 | 32 | - [**Serverless TensorFlow Model Serving**](tensorflow-inference-docker-lambda): This examples illustrates how to serve TensorFlow model on Lambda Function for Object Detection. 33 | - [**Train a TensorFlow algorithm in SageMaker, inference with AWS Lambda**](tensorflow-train-in-sagemaker-deploy-with-lambda): This examples illustrates how to use a TensorFlow Python script to train a classification model on the MNIST dataset. You train the model using SageMaker and inference with AWS Lambda. 34 | 35 | - **PyTorch resources:** 36 | 37 | - [**Serverless PyTorch Model Serving**](pytorch-inference-docker-lambda): This examples illustrates how to serve PyTorch model on Lambda Function for Image Classification. 38 | - [**Serverless HeBERT Model Serving for sentiment analysis in Hebrew**](hebert-sentiment-analysis-inference-docker-lambda): This example illustrates how to serve HeBERT model on Lambda Function for sentiment analysis in Hebrew. 39 | 40 | - **SageMaker Built-in Algorithms resources:** 41 | 42 | - [**Train XGBoost built-in algorithm in SageMaker, inference with AWS Lambda**](xgboost-built-in-algo-train-in-sagemaker-deploy-with-lambda): This example illustrates how to target Direct Marketing with Amazon SageMaker XGBoost built-in algorithm. You train the model using SageMaker and inference with AWS Lambda. 43 | - [**Train a BlazingText text classification algorithm in SageMaker, inference with AWS Lambda**](blazingtext-text-classification-train-in-sagemaker-deploy-with-lambda): This example illustrates how to use a BlazingText text classification training with SageMaker, and serving with AWS Lambda. 44 | 45 | - **Deep Java Library (DJL) resources:** 46 | 47 | - [**Serverless Object Detection Model Serving with Deep Java Library (DJL)**](djl-object-detection-inference-docker-lambda): This example illustrates how to serve TensorFlow Object Detection model on Lambda Function using [Deep Java Library (DJL)](http://djl.ai). 48 | 49 | - [**Serverless TensorFlow Lite Image Classification Model Serving with Deep Java Library (DJL)**](djl-tensorflow-lite-inference-docker-lambda): This example illustrates how to serve TensorFlow Lite Image Classification model on Lambda Function using [Deep Java Library (DJL)](http://djl.ai). 50 | 51 | ### Installation Instructions 52 | 53 | 1. [Create an AWS account](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html) if you do not already have one and login. 54 | 55 | 2. Install [Docker Desktop](https://www.docker.com/products/docker-desktop) 56 | 57 | 3. [Install the AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2-mac.html#cliv2-mac-install-gui) and [Configure AWS credentials](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-config). 58 | 59 | 4. Clone the repo onto your local development machine using `git clone`. 60 | 61 | 5. Open the project in any IDE of your choice in order to run the example Python and Java files. 62 | 63 | 6. Follow the instructions in each of the example README.md file. 64 | 65 | ## Questions? 66 | 67 | Please contact [@e_sela](https://twitter.com/e_sela) or raise an issue on this repo. 68 | 69 | ## License 70 | 71 | This library is licensed under the MIT-0 License. See the LICENSE file. 72 | 73 | -------------------------------------------------------------------------------- /blazingtext-text-classification-train-in-sagemaker-deploy-with-lambda/README.md: -------------------------------------------------------------------------------- 1 | ## Train a BlazingText text classification algorithm in SageMaker, inference with AWS Lambda 2 | 3 | This example illustrates how to use a BlazingText text classification training with SageMaker, and serving with AWS Lambda. 4 | 5 | For both supervised (text classification) and unsupervised (Word2Vec) modes, the binaries (*.bin) produced by BlazingText can be cross-consumed by fastText and vice versa. You can use binaries produced by BlazingText by fastText. Likewise, you can host the model binaries created with fastText using BlazingText. 6 | 7 | This project contains source code and supporting files for a serverless application that you can deploy with the notebook. It includes the following files and folders. 8 | 9 | - blazingtext-text-classification-train-in-sagemaker-deploy-with-lambda.ipynb - Notebook to run training with SageMaker, and deploy the Lambda function. 10 | - container - The container directory has all the components you need to package the sample Lambda function. 11 | - events - Invocation events that you can use to invoke the function. 12 | 13 | ## Train a BlazingText text classification algorithm 14 | You'll be running the [BlazingText text classification training with SageMaker, and serving with AWS Lambda](./blazingtext-text-classification-train-in-sagemaker-deploy-with-lambda.ipynb) notebook to train a TensorFlow classification model on the MNIST dataset. 15 | 16 | You can run this notebook in [SageMaker Notebook instance](https://docs.aws.amazon.com/sagemaker/latest/dg/nbi.html) 17 | 18 | **Note: this notebook will not run on SageMaker Studio since you are building a Docker Image.** 19 | 20 | This notebooks is identical to the original [BlazingText text classification](https://github.com/aws/amazon-sagemaker-examples/blob/master/introduction_to_amazon_algorithms/blazingtext_text_classification_dbpedia/blazingtext_text_classification_dbpedia.ipynb) notebook, except the fact that you'll deploy the model in Lambda function. 21 | 22 | ## Testing your Lambda function in the Cloud 23 | 24 | 1. In the [Lambda Console](https://console.aws.amazon.com/lambda/), select Configure test events from the Test events dropdown. 25 | 2. For Event Name, enter InferenceTestEvent. 26 | 3. Copy the event JSON from [here](./events/event.json) and paste in the dialog box. 27 | 4. Choose _**Create**_. 28 | 29 | ![Configure test event](../img/fasttext_configure_test_event.png) 30 | 31 | After saving, you see InferenceTestEvent in the Test list. Now choose _**Test**_. 32 | 33 | You see the Lambda function inference result, log output, and duration: 34 | 35 | ![Lambda execution result](../img/fasttext_execution_result.png) 36 | -------------------------------------------------------------------------------- /blazingtext-text-classification-train-in-sagemaker-deploy-with-lambda/container/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/lambda/python:3.7 2 | 3 | RUN yum install git -y 4 | RUN yum install gcc-c++ -y 5 | 6 | RUN git clone https://github.com/facebookresearch/fastText.git 7 | RUN cd fastText && python setup.py install 8 | RUN cd fastText && pip3 install --trusted-host pypi.python.org . 9 | 10 | COPY ./model/model.tar.gz . 11 | RUN tar -xzf model.tar.gz 12 | 13 | COPY ./app/app.py ./ 14 | 15 | CMD ["app.handler"] -------------------------------------------------------------------------------- /blazingtext-text-classification-train-in-sagemaker-deploy-with-lambda/container/app/app.py: -------------------------------------------------------------------------------- 1 | import fasttext 2 | import json 3 | 4 | loaded_model = fasttext.load_model('./model.bin') 5 | 6 | 7 | def handler(event, context): 8 | print('Received event: ' + json.dumps(event, indent=2)) 9 | 10 | prediction = loaded_model.predict(event["text"]) 11 | 12 | print("Returning: {}".format(prediction)) 13 | return(json.dumps({"prediction": prediction[0][0]})) 14 | 15 | 16 | -------------------------------------------------------------------------------- /blazingtext-text-classification-train-in-sagemaker-deploy-with-lambda/events/event.json: -------------------------------------------------------------------------------- 1 | { 2 | "text": "Which baking dish is best to bake a banana bread ?" 3 | } -------------------------------------------------------------------------------- /djl-object-detection-inference-docker-lambda/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8 as build-image 2 | 3 | ARG SCRATCH_DIR=/var/task/build 4 | WORKDIR /var/task 5 | 6 | COPY src/ src/ 7 | COPY gradle/ gradle/ 8 | COPY build.gradle gradlew ./ 9 | 10 | RUN mkdir build 11 | COPY gradle/lambda-build-init.gradle ./build 12 | 13 | RUN echo $SCRATCH_DIR 14 | 15 | RUN ./gradlew --project-cache-dir $SCRATCH_DIR/gradle-cache -Dsoftware.amazon.aws.lambdabuilders.scratch-dir=$SCRATCH_DIR --init-script $SCRATCH_DIR/lambda-build-init.gradle build 16 | RUN rm -r $SCRATCH_DIR/gradle-cache 17 | RUN rm -r $SCRATCH_DIR/lambda-build-init.gradle 18 | RUN cp -r $SCRATCH_DIR/*/build/distributions/lambda-build/* . 19 | 20 | FROM public.ecr.aws/lambda/java:8 21 | 22 | COPY --from=build-image /var/task/META-INF ./ 23 | COPY --from=build-image /var/task/com ./com 24 | COPY --from=build-image /var/task/lib/ ./lib 25 | # Command can be overwritten by providing a different command in the template directly. 26 | CMD ["com.example.App::handleRequest"] 27 | -------------------------------------------------------------------------------- /djl-object-detection-inference-docker-lambda/README.md: -------------------------------------------------------------------------------- 1 | ## Serverless Object Detection Model Serving with Deep Java Library (DJL) 2 | 3 | This example illustrates how to serve TensorFlow Object Detection model on Lambda Function using [Deep Java Library (DJL)](http://djl.ai). 4 | 5 | This project contains source code and supporting files for a serverless application that you can deploy with the SAM CLI. It includes the following files and folders. 6 | 7 | - src/main - Code for the application's Lambda function. 8 | - events - Invocation events that you can use to invoke the function. 9 | - src/test - Unit tests for the application code. 10 | - template.yaml - A template that defines the application's AWS resources. 11 | 12 | The application uses several AWS resources, including Lambda functions. These resources are defined in the `template.yaml` file in this project. You can update the template to add AWS resources through the same deployment process that updates your application code. 13 | 14 | ## Deploy the sample application 15 | 16 | The Serverless Application Model Command Line Interface (SAM CLI) is an extension of the AWS CLI that adds functionality for building and testing Lambda applications. It uses Docker to run your functions in an Amazon Linux environment that matches Lambda. It can also emulate your application's build environment and API. 17 | 18 | To use the SAM CLI, you need the following tools. 19 | 20 | * SAM CLI - [Install the SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) 21 | * Docker - [Install Docker community edition](https://hub.docker.com/search/?type=edition&offering=community) 22 | 23 | You may need the following for local testing. 24 | * Java8 - [Install the Java SE Development Kit 8](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html) 25 | 26 | To build and deploy your application for the first time, run the following in your shell: 27 | 28 | ```bash 29 | sam build 30 | sam deploy --guided 31 | ``` 32 | 33 | The first command will build a docker image from a Dockerfile and then copy the source of your application inside the Docker image. The second command will package and deploy your application to AWS, with a series of prompts: 34 | 35 | * **Stack Name**: The name of the stack to deploy to CloudFormation. This should be unique to your account and region, and a good starting point would be something matching your project name. 36 | * **AWS Region**: The AWS region you want to deploy your app to. 37 | * **Confirm changes before deploy**: If set to yes, any change sets will be shown to you before execution for manual review. If set to no, the AWS SAM CLI will automatically deploy application changes. 38 | * **Allow SAM CLI IAM role creation**: Many AWS SAM templates, including this example, create AWS IAM roles required for the AWS Lambda function(s) included to access AWS services. By default, these are scoped down to minimum required permissions. To deploy an AWS CloudFormation stack which creates or modified IAM roles, the `CAPABILITY_IAM` value for `capabilities` must be provided. If permission isn't provided through this prompt, to deploy this example you must explicitly pass `--capabilities CAPABILITY_IAM` to the `sam deploy` command. 39 | * **Save arguments to samconfig.toml**: If set to yes, your choices will be saved to a configuration file inside the project, so that in the future you can just re-run `sam deploy` without parameters to deploy changes to your application. 40 | 41 | ## Use the SAM CLI to build and test locally 42 | 43 | Build your application with the `sam build` command. 44 | 45 | ```bash 46 | djl-object-detection-inference-docker-lambda$ sam build 47 | ``` 48 | 49 | The SAM CLI builds a docker image from a Dockerfile and then installs dependencies defined in `build.gradle` inside the docker image. The processed template file is saved in the `.aws-sam/build` folder. 50 | 51 | Test a single function by invoking it directly with a test event. An event is a JSON document that represents the input that the function receives from the event source. Test events are included in the `events` folder in this project. 52 | 53 | Run functions locally and invoke them with the `sam local invoke` command. 54 | 55 | ```bash 56 | djl-object-detection-inference-docker-lambda$ sam local invoke DjlObjectDetectionInferenceFunction --event events/event.json 57 | ``` 58 | 59 | ## Testing your Lambda function in the Cloud 60 | 61 | 1. In the [Lambda Console](https://console.aws.amazon.com/lambda/), select Configure test events from the Test events dropdown. 62 | 2. For Event Name, enter InferenceTestEvent. 63 | 3. Copy the event JSON from [here](./events/event.json) and paste in the dialog box. 64 | 4. Choose _**Create**_. 65 | 66 | ![Configure test event](../img/djl_object_detection_configure_test_event.png) 67 | 68 | After saving, you see InferenceTestEvent in the Test list. Now choose _**Test**_. 69 | 70 | You see the Lambda function inference result, log output, and duration: 71 | 72 | ![Lambda execution result](../img/djl_object_detection_execution_result.png) 73 | 74 | ## Fetch, tail, and filter Lambda function logs 75 | 76 | To simplify troubleshooting, SAM CLI has a command called `sam logs`. `sam logs` lets you fetch logs generated by your deployed Lambda function from the command line. In addition to printing the logs on the terminal, this command has several nifty features to help you quickly find the bug. 77 | 78 | `NOTE`: This command works for all AWS Lambda functions; not just the ones you deploy using SAM. 79 | 80 | ```bash 81 | djl-object-detection-inference-docker-lambda$ sam logs -n DjlObjectDetectionInferenceFunction --stack-name djl-object-detection-inference-docker-lambda --tail 82 | ``` 83 | 84 | You can find more information and examples about filtering Lambda function logs in the [SAM CLI Documentation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-logging.html). 85 | 86 | ## Unit tests 87 | 88 | Tests are defined in the `src/test` folder in this project. 89 | 90 | ```bash 91 | djl-object-detection-inference-docker-lambda$ gradle test 92 | ``` 93 | 94 | ## Cleanup 95 | 96 | To delete the sample application that you created, use the AWS CLI. Assuming you used your project name for the stack name, you can run the following: 97 | 98 | ```bash 99 | aws cloudformation delete-stack --stack-name djl-object-detection-inference-docker-lambda 100 | ``` 101 | 102 | ## Resources 103 | 104 | See the [AWS SAM developer guide](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html) for an introduction to SAM specification, the SAM CLI, and serverless application concepts. 105 | 106 | -------------------------------------------------------------------------------- /djl-object-detection-inference-docker-lambda/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | } 4 | 5 | repositories { 6 | mavenCentral() 7 | } 8 | 9 | dependencies { 10 | implementation 'com.amazonaws:aws-lambda-java-core:1.2.1' 11 | implementation 'com.amazonaws:aws-lambda-java-events:3.1.0' 12 | implementation platform("ai.djl:bom:0.9.0") 13 | 14 | implementation "ai.djl.tensorflow:tensorflow-engine" 15 | implementation "ai.djl.tensorflow:tensorflow-native-auto" 16 | implementation "ai.djl.tensorflow:tensorflow-model-zoo" 17 | 18 | testImplementation 'org.testng:testng:6.14.3' 19 | 20 | } 21 | -------------------------------------------------------------------------------- /djl-object-detection-inference-docker-lambda/events/event.json: -------------------------------------------------------------------------------- 1 | { 2 | "inputImageUrl": "https://github.com/awslabs/djl/raw/master/examples/src/test/resources/dog_bike_car.jpg" 3 | } -------------------------------------------------------------------------------- /djl-object-detection-inference-docker-lambda/gradle/lambda-build-init.gradle: -------------------------------------------------------------------------------- 1 | import groovy.io.FileType 2 | import java.nio.file.FileAlreadyExistsException 3 | import java.nio.file.Files 4 | import java.nio.file.FileVisitOption 5 | import java.nio.file.FileVisitResult 6 | import java.nio.file.Path 7 | import java.nio.file.Paths 8 | import java.nio.file.SimpleFileVisitor 9 | import java.security.MessageDigest 10 | import java.util.zip.ZipInputStream 11 | import java.util.zip.ZipOutputStream 12 | import java.util.zip.ZipEntry 13 | 14 | gradle.ext.SCRATCH_DIR_PROPERTY = 'software.amazon.aws.lambdabuilders.scratch-dir' 15 | 16 | // Called after the project has been evaluated 17 | gradle.afterProject({p -> 18 | def buildDir = buildDirForProject(p) 19 | p.buildDir = buildDir 20 | }) 21 | 22 | gradle.taskGraph.afterTask{ t -> 23 | if (t.name != 'build') { 24 | return; 25 | } 26 | 27 | def artifactJars = t.project.configurations.archives.artifacts.files.files 28 | 29 | def runtimeCpJars = t.project.configurations.runtimeClasspath.files 30 | 31 | def artifactDir = createArtifactDir(t.project) 32 | 33 | copyToArtifactDir(artifactDir, artifactJars, runtimeCpJars) 34 | } 35 | 36 | def buildDirForProject(p) { 37 | def scratchDir = System.properties[SCRATCH_DIR_PROPERTY] 38 | if (scratchDir == null) { 39 | throw new RuntimeException("Missing '${SCRATCH_DIR_PROPERTY}' value") 40 | } 41 | return Paths.get(scratchDir, scratchDirForProject(p), 'build') 42 | } 43 | 44 | def scratchDirForProject(p) { 45 | def sha1 = MessageDigest.getInstance('SHA-1') 46 | return sha1.digest(p.projectDir.toString().getBytes('UTF-8')).encodeHex().toString() 47 | } 48 | 49 | def assertExpectedBuildDir(p) { 50 | def expected = buildDirForProject(p) 51 | if (!expected.equals(p.buildDir.toPath())) { 52 | throw new RuntimeException("Project buildDir was changed by the project build script! Expected $expected but found ${p.buildDir}") 53 | } 54 | } 55 | 56 | def createArtifactDir(project) { 57 | def distsDir = project.buildDir.toPath().resolve(project.distsDirName).resolve('lambda-build') 58 | return makeDirs(distsDir) 59 | } 60 | 61 | def copyToArtifactDir(artifactDir, artifactJars, classPathJars) { 62 | artifactJars.each { 63 | it.withInputStream({ jis -> 64 | def zipIs = new ZipInputStream(jis) 65 | for (def e = zipIs.getNextEntry(); e != null; e = zipIs.getNextEntry()) { 66 | def entryPath = artifactDir.resolve(e.name) 67 | if (e.isDirectory()) { 68 | makeDirs(entryPath) 69 | } else { 70 | copyToFile(zipIs, entryPath) 71 | } 72 | zipIs.closeEntry() 73 | } 74 | zipIs.close() 75 | }) 76 | } 77 | 78 | def libDir = artifactDir.resolve('lib') 79 | makeDirs(libDir) 80 | classPathJars.each { 81 | def jarPath = libDir.resolve(it.name) 82 | it.withInputStream({ jIs -> 83 | copyToFile(jIs, jarPath) 84 | }) 85 | } 86 | } 87 | 88 | def makeDirs(p) { 89 | try { 90 | Files.createDirectories(p) 91 | } catch (FileAlreadyExistsException e) { 92 | // ignored 93 | } 94 | return p 95 | } 96 | 97 | def copyToFile(zipIs, path) { 98 | path.withOutputStream({ fos -> 99 | byte[] buff = new byte[4096] 100 | int bytesRead 101 | while ((bytesRead = zipIs.read(buff)) != -1) { 102 | fos.write(buff, 0, bytesRead) 103 | } 104 | }) 105 | } 106 | -------------------------------------------------------------------------------- /djl-object-detection-inference-docker-lambda/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-lambda-docker-serverless-inference/df108386292aa99cd8213f01b4473eb9f99e7b17/djl-object-detection-inference-docker-lambda/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /djl-object-detection-inference-docker-lambda/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /djl-object-detection-inference-docker-lambda/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS='"-Xmx64m"' 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /djl-object-detection-inference-docker-lambda/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS="-Xmx64m" 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /djl-object-detection-inference-docker-lambda/src/main/java/com/example/App.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import ai.djl.Application; 4 | import ai.djl.ModelException; 5 | import ai.djl.engine.Engine; 6 | import ai.djl.inference.Predictor; 7 | import ai.djl.modality.cv.Image; 8 | import ai.djl.modality.cv.ImageFactory; 9 | import ai.djl.modality.cv.output.DetectedObjects; 10 | import ai.djl.repository.zoo.Criteria; 11 | import ai.djl.repository.zoo.ModelZoo; 12 | import ai.djl.repository.zoo.ZooModel; 13 | import ai.djl.translate.TranslateException; 14 | import ai.djl.util.Utils; 15 | import com.amazonaws.services.lambda.runtime.Context; 16 | import com.amazonaws.services.lambda.runtime.LambdaLogger; 17 | import com.amazonaws.services.lambda.runtime.RequestStreamHandler; 18 | import com.google.gson.Gson; 19 | import com.google.gson.GsonBuilder; 20 | 21 | import java.io.IOException; 22 | import java.io.InputStream; 23 | import java.io.OutputStream; 24 | import java.nio.charset.StandardCharsets; 25 | 26 | /** 27 | * Handler for requests to Lambda function. 28 | */ 29 | public class App implements RequestStreamHandler { 30 | 31 | private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); 32 | 33 | static { 34 | // DJL saves model and native libraries in cache folder. 35 | // In AWS-Lambda only /tmp folder is writable. 36 | System.setProperty("DJL_CACHE_DIR", "/tmp/djl_cache"); 37 | } 38 | 39 | public void handleRequest(InputStream is, OutputStream os, Context context) throws IOException { 40 | LambdaLogger logger = context.getLogger(); 41 | String input = Utils.toString(is); 42 | 43 | Request request = GSON.fromJson(input, Request.class); 44 | String inputImageUrl = request.getInputImageUrl(); 45 | logger.log("inputImageUrl: " + inputImageUrl); 46 | 47 | 48 | String backbone; 49 | if ("TensorFlow".equals(Engine.getInstance().getEngineName())) { 50 | backbone = "mobilenet_v2"; 51 | } else { 52 | backbone = "resnet50"; 53 | } 54 | logger.log("backbone: " + backbone); 55 | 56 | Criteria criteria = 57 | Criteria.builder() 58 | .optApplication(Application.CV.OBJECT_DETECTION) 59 | .setTypes(Image.class, DetectedObjects.class) 60 | .optFilter("backbone", backbone) 61 | .build(); 62 | 63 | try { 64 | try (ZooModel model = ModelZoo.loadModel(criteria)) { 65 | try (Predictor predictor = model.newPredictor()) { 66 | Image image = ImageFactory.getInstance().fromUrl(inputImageUrl); 67 | DetectedObjects detection = predictor.predict(image); 68 | logger.log("detection: " + detection); 69 | os.write(GSON.toJson(detection).getBytes(StandardCharsets.UTF_8)); 70 | } 71 | } 72 | } catch (RuntimeException | ModelException | TranslateException e) { 73 | logger.log("Failed handle input: " + input); 74 | logger.log(e.toString()); 75 | String msg = "{\"status\": \"invoke failed: " + e.toString() + "\"}"; 76 | os.write(msg.getBytes(StandardCharsets.UTF_8)); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /djl-object-detection-inference-docker-lambda/src/main/java/com/example/Request.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | public class Request { 4 | 5 | private String inputImageUrl; 6 | 7 | public String getInputImageUrl() { 8 | return inputImageUrl; 9 | } 10 | 11 | public void setInputImageUrl(String inputImageUrl) { 12 | this.inputImageUrl = inputImageUrl; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /djl-object-detection-inference-docker-lambda/src/test/java/com/example/AppTest.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import ai.djl.modality.Classifications; 4 | import com.amazonaws.services.lambda.runtime.Context; 5 | import com.google.gson.Gson; 6 | import com.google.gson.reflect.TypeToken; 7 | import java.io.ByteArrayInputStream; 8 | import java.io.ByteArrayOutputStream; 9 | import java.io.IOException; 10 | import java.io.InputStream; 11 | import java.lang.reflect.Type; 12 | import java.nio.charset.StandardCharsets; 13 | import java.util.List; 14 | import org.testng.Assert; 15 | import org.testng.annotations.Test; 16 | 17 | public class AppTest { 18 | 19 | @Test 20 | public void invokeTest() throws IOException { 21 | Context context = new MockContext(); 22 | App app = new App(); 23 | 24 | Request request = new Request(); 25 | request.setInputImageUrl("https://github.com/awslabs/djl/raw/master/examples/src/test/resources/dog_bike_car.jpg"); 26 | Gson gson = new Gson(); 27 | byte[] buf = gson.toJson(request).getBytes(StandardCharsets.UTF_8); 28 | 29 | InputStream is = new ByteArrayInputStream(buf); 30 | ByteArrayOutputStream os = new ByteArrayOutputStream(); 31 | app.handleRequest(is, os, context); 32 | String result = os.toString(StandardCharsets.UTF_8.name()); 33 | 34 | Assert.assertNotNull(result); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /djl-object-detection-inference-docker-lambda/src/test/java/com/example/MockContext.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import com.amazonaws.services.lambda.runtime.ClientContext; 4 | import com.amazonaws.services.lambda.runtime.CognitoIdentity; 5 | import com.amazonaws.services.lambda.runtime.Context; 6 | import com.amazonaws.services.lambda.runtime.LambdaLogger; 7 | 8 | public class MockContext implements Context { 9 | 10 | @Override 11 | public String getAwsRequestId() { 12 | return "495b12a8-xmpl-4eca-8168-160484189f99"; 13 | } 14 | 15 | @Override 16 | public String getLogGroupName() { 17 | return "/aws/lambda/my-function"; 18 | } 19 | 20 | @Override 21 | public String getLogStreamName() { 22 | return "2020/02/26/[$LATEST]704f8dxmpla04097b9134246b8438f1a"; 23 | } 24 | 25 | @Override 26 | public String getFunctionName() { 27 | return "my-function"; 28 | } 29 | 30 | @Override 31 | public String getFunctionVersion() { 32 | return "$LATEST"; 33 | } 34 | 35 | @Override 36 | public String getInvokedFunctionArn() { 37 | return "arn:aws:lambda:us-east-2:123456789012:function:my-function"; 38 | } 39 | 40 | @Override 41 | public CognitoIdentity getIdentity() { 42 | return null; 43 | } 44 | 45 | @Override 46 | public ClientContext getClientContext() { 47 | return null; 48 | } 49 | 50 | @Override 51 | public int getRemainingTimeInMillis() { 52 | return 300000; 53 | } 54 | 55 | @Override 56 | public int getMemoryLimitInMB() { 57 | return 512; 58 | } 59 | 60 | @Override 61 | public LambdaLogger getLogger() { 62 | return new MockLogger(); 63 | } 64 | } -------------------------------------------------------------------------------- /djl-object-detection-inference-docker-lambda/src/test/java/com/example/MockLogger.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import com.amazonaws.services.lambda.runtime.LambdaLogger; 4 | import java.nio.charset.StandardCharsets; 5 | 6 | public class MockLogger implements LambdaLogger { 7 | 8 | @Override 9 | public void log(String message) { 10 | System.out.println(message); 11 | } 12 | 13 | @Override 14 | public void log(byte[] message) { 15 | System.out.println(new String(message, StandardCharsets.UTF_8)); 16 | } 17 | } -------------------------------------------------------------------------------- /djl-object-detection-inference-docker-lambda/template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | Description: > 4 | djl-object-detection-inference-docker-lambda 5 | 6 | SAM Template for djl-object-detection-inference-docker-lambda 7 | 8 | Resources: 9 | DjlObjectDetectionInferenceFunction: 10 | Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction 11 | Properties: 12 | PackageType: Image 13 | MemorySize: 1536 14 | Timeout: 120 15 | Metadata: 16 | DockerTag: java8-gradle-v1 17 | DockerContext: . 18 | Dockerfile: Dockerfile 19 | 20 | Outputs: 21 | DjlObjectDetectionInferenceFunction: 22 | Description: "DjlObjectDetectionInference Lambda Function ARN" 23 | Value: !GetAtt DjlObjectDetectionInferenceFunction.Arn 24 | DjlObjectDetectionInferenceFunctionIamRole: 25 | Description: "Implicit IAM Role created for DjlObjectDetectionInference function" 26 | Value: !GetAtt DjlObjectDetectionInferenceFunctionRole.Arn 27 | -------------------------------------------------------------------------------- /djl-tensorflow-lite-inference-docker-lambda/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8 as build-image 2 | 3 | ARG SCRATCH_DIR=/var/task/build 4 | WORKDIR /var/task 5 | 6 | COPY src/ src/ 7 | COPY gradle/ gradle/ 8 | COPY build.gradle gradlew ./ 9 | 10 | RUN mkdir build 11 | COPY gradle/lambda-build-init.gradle ./build 12 | 13 | RUN echo $SCRATCH_DIR 14 | 15 | RUN ./gradlew --project-cache-dir $SCRATCH_DIR/gradle-cache -Dsoftware.amazon.aws.lambdabuilders.scratch-dir=$SCRATCH_DIR --init-script $SCRATCH_DIR/lambda-build-init.gradle build 16 | RUN rm -r $SCRATCH_DIR/gradle-cache 17 | RUN rm -r $SCRATCH_DIR/lambda-build-init.gradle 18 | RUN cp -r $SCRATCH_DIR/*/build/distributions/lambda-build/* . 19 | 20 | FROM public.ecr.aws/lambda/java:8 21 | 22 | COPY --from=build-image /var/task/META-INF ./ 23 | COPY --from=build-image /var/task/com ./com 24 | COPY --from=build-image /var/task/lib/ ./lib 25 | # Command can be overwritten by providing a different command in the template directly. 26 | CMD ["com.example.App::handleRequest"] 27 | -------------------------------------------------------------------------------- /djl-tensorflow-lite-inference-docker-lambda/README.md: -------------------------------------------------------------------------------- 1 | ## Serverless TensorFlow Lite Image Classification Model Serving with Deep Java Library (DJL) 2 | 3 | This example illustrates how to serve TensorFlow Lite Image Classification model on Lambda Function using [Deep Java Library (DJL)](http://djl.ai). 4 | 5 | This project contains source code and supporting files for a serverless application that you can deploy with the SAM CLI. It includes the following files and folders. 6 | 7 | - src/main - Code for the application's Lambda function. 8 | - events - Invocation events that you can use to invoke the function. 9 | - src/test - Unit tests for the application code. 10 | - template.yaml - A template that defines the application's AWS resources. 11 | 12 | The application uses several AWS resources, including Lambda functions. These resources are defined in the `template.yaml` file in this project. You can update the template to add AWS resources through the same deployment process that updates your application code. 13 | 14 | ## Deploy the sample application 15 | 16 | The Serverless Application Model Command Line Interface (SAM CLI) is an extension of the AWS CLI that adds functionality for building and testing Lambda applications. It uses Docker to run your functions in an Amazon Linux environment that matches Lambda. It can also emulate your application's build environment and API. 17 | 18 | To use the SAM CLI, you need the following tools. 19 | 20 | * SAM CLI - [Install the SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) 21 | * Docker - [Install Docker community edition](https://hub.docker.com/search/?type=edition&offering=community) 22 | 23 | You may need the following for local testing. 24 | * Java8 - [Install the Java SE Development Kit 8](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html) 25 | 26 | To build and deploy your application for the first time, run the following in your shell: 27 | 28 | ```bash 29 | sam build 30 | sam deploy --guided 31 | ``` 32 | 33 | The first command will build a docker image from a Dockerfile and then copy the source of your application inside the Docker image. The second command will package and deploy your application to AWS, with a series of prompts: 34 | 35 | * **Stack Name**: The name of the stack to deploy to CloudFormation. This should be unique to your account and region, and a good starting point would be something matching your project name. 36 | * **AWS Region**: The AWS region you want to deploy your app to. 37 | * **Confirm changes before deploy**: If set to yes, any change sets will be shown to you before execution for manual review. If set to no, the AWS SAM CLI will automatically deploy application changes. 38 | * **Allow SAM CLI IAM role creation**: Many AWS SAM templates, including this example, create AWS IAM roles required for the AWS Lambda function(s) included to access AWS services. By default, these are scoped down to minimum required permissions. To deploy an AWS CloudFormation stack which creates or modified IAM roles, the `CAPABILITY_IAM` value for `capabilities` must be provided. If permission isn't provided through this prompt, to deploy this example you must explicitly pass `--capabilities CAPABILITY_IAM` to the `sam deploy` command. 39 | * **Save arguments to samconfig.toml**: If set to yes, your choices will be saved to a configuration file inside the project, so that in the future you can just re-run `sam deploy` without parameters to deploy changes to your application. 40 | 41 | ## Use the SAM CLI to build and test locally 42 | 43 | Build your application with the `sam build` command. 44 | 45 | ```bash 46 | djl-tensorflow-lite-inference-docker-lambda$ sam build 47 | ``` 48 | 49 | The SAM CLI builds a docker image from a Dockerfile and then installs dependencies defined in `build.gradle` inside the docker image. The processed template file is saved in the `.aws-sam/build` folder. 50 | 51 | Test a single function by invoking it directly with a test event. An event is a JSON document that represents the input that the function receives from the event source. Test events are included in the `events` folder in this project. 52 | 53 | Run functions locally and invoke them with the `sam local invoke` command. 54 | 55 | ```bash 56 | djl-tensorflow-lite-inference-docker-lambda$ sam local invoke DjlTFLiteInferenceFunction --event events/event.json 57 | ``` 58 | 59 | ## Testing your Lambda function in the Cloud 60 | 61 | 1. In the [Lambda Console](https://console.aws.amazon.com/lambda/), select Configure test events from the Test events dropdown. 62 | 2. For Event Name, enter InferenceTestEvent. 63 | 3. Copy the event JSON from [here](./events/event.json) and paste in the dialog box. 64 | 4. Choose _**Create**_. 65 | 66 | ![Configure test event](../img/djl_tensorflow_lite_configure_test_event.png) 67 | 68 | After saving, you see InferenceTestEvent in the Test list. Now choose _**Test**_. 69 | 70 | You see the Lambda function inference result, log output, and duration: 71 | 72 | ![Lambda execution result](../img/djl_tensorflow_lite_execution_result.png) 73 | 74 | ## Fetch, tail, and filter Lambda function logs 75 | 76 | To simplify troubleshooting, SAM CLI has a command called `sam logs`. `sam logs` lets you fetch logs generated by your deployed Lambda function from the command line. In addition to printing the logs on the terminal, this command has several nifty features to help you quickly find the bug. 77 | 78 | `NOTE`: This command works for all AWS Lambda functions; not just the ones you deploy using SAM. 79 | 80 | ```bash 81 | djl-tensorflow-lite-inference-docker-lambda$ sam logs -n DjlTFLiteInferenceFunction --stack-name djl-tensorflow-lite-inference-docker-lambda --tail 82 | ``` 83 | 84 | You can find more information and examples about filtering Lambda function logs in the [SAM CLI Documentation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-logging.html). 85 | 86 | ## Unit tests 87 | 88 | Tests are defined in the `src/test` folder in this project. 89 | 90 | ```bash 91 | djl-tensorflow-lite-inference-docker-lambda$ gradle test 92 | ``` 93 | 94 | ## Cleanup 95 | 96 | To delete the sample application that you created, use the AWS CLI. Assuming you used your project name for the stack name, you can run the following: 97 | 98 | ```bash 99 | aws cloudformation delete-stack --stack-name djl-tensorflow-lite-inference-docker-lambda 100 | ``` 101 | 102 | ## Resources 103 | 104 | See the [AWS SAM developer guide](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html) for an introduction to SAM specification, the SAM CLI, and serverless application concepts. 105 | 106 | -------------------------------------------------------------------------------- /djl-tensorflow-lite-inference-docker-lambda/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | } 4 | 5 | repositories { 6 | mavenCentral() 7 | } 8 | 9 | dependencies { 10 | implementation 'com.amazonaws:aws-lambda-java-core:1.2.1' 11 | implementation 'com.amazonaws:aws-lambda-java-events:3.1.0' 12 | 13 | implementation 'ai.djl:api:0.10.0' 14 | implementation 'ai.djl:model-zoo:0.10.0' 15 | implementation 'ai.djl.tflite:tflite-engine:0.10.0' 16 | implementation 'org.slf4j:slf4j-api:1.7.26' 17 | implementation 'org.slf4j:slf4j-simple:1.7.26' 18 | implementation 'net.java.dev.jna:jna:5.3.0' 19 | 20 | implementation 'ai.djl.tflite:tflite-native-auto:2.4.1' 21 | 22 | testImplementation 'org.testng:testng:6.14.3' 23 | 24 | } 25 | -------------------------------------------------------------------------------- /djl-tensorflow-lite-inference-docker-lambda/events/event.json: -------------------------------------------------------------------------------- 1 | { 2 | "inputImageUrl": "https://resources.djl.ai/images/sachertorte.jpg" 3 | } -------------------------------------------------------------------------------- /djl-tensorflow-lite-inference-docker-lambda/gradle/lambda-build-init.gradle: -------------------------------------------------------------------------------- 1 | import groovy.io.FileType 2 | import java.nio.file.FileAlreadyExistsException 3 | import java.nio.file.Files 4 | import java.nio.file.FileVisitOption 5 | import java.nio.file.FileVisitResult 6 | import java.nio.file.Path 7 | import java.nio.file.Paths 8 | import java.nio.file.SimpleFileVisitor 9 | import java.security.MessageDigest 10 | import java.util.zip.ZipInputStream 11 | import java.util.zip.ZipOutputStream 12 | import java.util.zip.ZipEntry 13 | 14 | gradle.ext.SCRATCH_DIR_PROPERTY = 'software.amazon.aws.lambdabuilders.scratch-dir' 15 | 16 | // Called after the project has been evaluated 17 | gradle.afterProject({p -> 18 | def buildDir = buildDirForProject(p) 19 | p.buildDir = buildDir 20 | }) 21 | 22 | gradle.taskGraph.afterTask{ t -> 23 | if (t.name != 'build') { 24 | return; 25 | } 26 | 27 | def artifactJars = t.project.configurations.archives.artifacts.files.files 28 | 29 | def runtimeCpJars = t.project.configurations.runtimeClasspath.files 30 | 31 | def artifactDir = createArtifactDir(t.project) 32 | 33 | copyToArtifactDir(artifactDir, artifactJars, runtimeCpJars) 34 | } 35 | 36 | def buildDirForProject(p) { 37 | def scratchDir = System.properties[SCRATCH_DIR_PROPERTY] 38 | if (scratchDir == null) { 39 | throw new RuntimeException("Missing '${SCRATCH_DIR_PROPERTY}' value") 40 | } 41 | return Paths.get(scratchDir, scratchDirForProject(p), 'build') 42 | } 43 | 44 | def scratchDirForProject(p) { 45 | def sha1 = MessageDigest.getInstance('SHA-1') 46 | return sha1.digest(p.projectDir.toString().getBytes('UTF-8')).encodeHex().toString() 47 | } 48 | 49 | def assertExpectedBuildDir(p) { 50 | def expected = buildDirForProject(p) 51 | if (!expected.equals(p.buildDir.toPath())) { 52 | throw new RuntimeException("Project buildDir was changed by the project build script! Expected $expected but found ${p.buildDir}") 53 | } 54 | } 55 | 56 | def createArtifactDir(project) { 57 | def distsDir = project.buildDir.toPath().resolve(project.distsDirName).resolve('lambda-build') 58 | return makeDirs(distsDir) 59 | } 60 | 61 | def copyToArtifactDir(artifactDir, artifactJars, classPathJars) { 62 | artifactJars.each { 63 | it.withInputStream({ jis -> 64 | def zipIs = new ZipInputStream(jis) 65 | for (def e = zipIs.getNextEntry(); e != null; e = zipIs.getNextEntry()) { 66 | def entryPath = artifactDir.resolve(e.name) 67 | if (e.isDirectory()) { 68 | makeDirs(entryPath) 69 | } else { 70 | copyToFile(zipIs, entryPath) 71 | } 72 | zipIs.closeEntry() 73 | } 74 | zipIs.close() 75 | }) 76 | } 77 | 78 | def libDir = artifactDir.resolve('lib') 79 | makeDirs(libDir) 80 | classPathJars.each { 81 | def jarPath = libDir.resolve(it.name) 82 | it.withInputStream({ jIs -> 83 | copyToFile(jIs, jarPath) 84 | }) 85 | } 86 | } 87 | 88 | def makeDirs(p) { 89 | try { 90 | Files.createDirectories(p) 91 | } catch (FileAlreadyExistsException e) { 92 | // ignored 93 | } 94 | return p 95 | } 96 | 97 | def copyToFile(zipIs, path) { 98 | path.withOutputStream({ fos -> 99 | byte[] buff = new byte[4096] 100 | int bytesRead 101 | while ((bytesRead = zipIs.read(buff)) != -1) { 102 | fos.write(buff, 0, bytesRead) 103 | } 104 | }) 105 | } 106 | -------------------------------------------------------------------------------- /djl-tensorflow-lite-inference-docker-lambda/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-lambda-docker-serverless-inference/df108386292aa99cd8213f01b4473eb9f99e7b17/djl-tensorflow-lite-inference-docker-lambda/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /djl-tensorflow-lite-inference-docker-lambda/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /djl-tensorflow-lite-inference-docker-lambda/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS='"-Xmx64m"' 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /djl-tensorflow-lite-inference-docker-lambda/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS="-Xmx64m" 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /djl-tensorflow-lite-inference-docker-lambda/src/main/java/com/example/App.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import ai.djl.ModelException; 4 | import ai.djl.inference.Predictor; 5 | import ai.djl.modality.Classifications; 6 | import ai.djl.modality.cv.Image; 7 | import ai.djl.modality.cv.ImageFactory; 8 | import ai.djl.repository.zoo.Criteria; 9 | import ai.djl.repository.zoo.ModelZoo; 10 | import ai.djl.repository.zoo.ZooModel; 11 | import ai.djl.translate.TranslateException; 12 | import ai.djl.util.Utils; 13 | import com.amazonaws.services.lambda.runtime.Context; 14 | import com.amazonaws.services.lambda.runtime.LambdaLogger; 15 | import com.amazonaws.services.lambda.runtime.RequestStreamHandler; 16 | import com.google.gson.Gson; 17 | import com.google.gson.GsonBuilder; 18 | 19 | import java.io.IOException; 20 | import java.io.InputStream; 21 | import java.io.OutputStream; 22 | import java.nio.charset.StandardCharsets; 23 | 24 | /** 25 | * Handler for requests to Lambda function. 26 | */ 27 | public class App implements RequestStreamHandler { 28 | 29 | private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); 30 | 31 | static { 32 | // DJL saves model and native libraries in cache folder. 33 | // In AWS-Lambda only /tmp folder is writable. 34 | System.setProperty("DJL_CACHE_DIR", "/tmp/djl_cache"); 35 | } 36 | 37 | public void handleRequest(InputStream is, OutputStream os, Context context) throws IOException { 38 | LambdaLogger logger = context.getLogger(); 39 | String input = Utils.toString(is); 40 | 41 | Request request = GSON.fromJson(input, Request.class); 42 | String inputImageUrl = request.getInputImageUrl(); 43 | logger.log("inputImageUrl: " + inputImageUrl); 44 | 45 | try { 46 | 47 | Criteria criteria = Criteria.builder() 48 | .setTypes(Image.class, Classifications.class) 49 | .optEngine("TFLite") 50 | .optFilter("dataset", "aiyDish") 51 | .build(); 52 | ZooModel model = ModelZoo.loadModel(criteria); 53 | 54 | Predictor predictor = model.newPredictor(); 55 | 56 | Image image = ImageFactory.getInstance().fromUrl(inputImageUrl); 57 | 58 | Classifications classifications = predictor.predict(image); 59 | 60 | logger.log("Classifications: " + classifications); 61 | os.write(GSON.toJson(classifications.best()).getBytes(StandardCharsets.UTF_8)); 62 | 63 | } catch (RuntimeException | ModelException | TranslateException e) { 64 | logger.log("Failed handle input: " + input); 65 | logger.log(e.toString()); 66 | String msg = "{\"status\": \"invoke failed: " + e.toString() + "\"}"; 67 | os.write(msg.getBytes(StandardCharsets.UTF_8)); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /djl-tensorflow-lite-inference-docker-lambda/src/main/java/com/example/Request.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | public class Request { 4 | 5 | private String inputImageUrl; 6 | 7 | public String getInputImageUrl() { 8 | return inputImageUrl; 9 | } 10 | 11 | public void setInputImageUrl(String inputImageUrl) { 12 | this.inputImageUrl = inputImageUrl; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /djl-tensorflow-lite-inference-docker-lambda/src/test/java/com/example/AppTest.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import ai.djl.modality.Classifications; 4 | import com.amazonaws.services.lambda.runtime.Context; 5 | import com.google.gson.Gson; 6 | import com.google.gson.reflect.TypeToken; 7 | import java.io.ByteArrayInputStream; 8 | import java.io.ByteArrayOutputStream; 9 | import java.io.IOException; 10 | import java.io.InputStream; 11 | import java.lang.reflect.Type; 12 | import java.nio.charset.StandardCharsets; 13 | import java.util.List; 14 | import org.testng.Assert; 15 | import org.testng.annotations.Test; 16 | 17 | public class AppTest { 18 | 19 | @Test 20 | public void invokeTest() throws IOException { 21 | Context context = new MockContext(); 22 | App app = new App(); 23 | 24 | Request request = new Request(); 25 | request.setInputImageUrl("https://resources.djl.ai/images/sachertorte.jpg"); 26 | Gson gson = new Gson(); 27 | byte[] buf = gson.toJson(request).getBytes(StandardCharsets.UTF_8); 28 | 29 | InputStream is = new ByteArrayInputStream(buf); 30 | ByteArrayOutputStream os = new ByteArrayOutputStream(); 31 | app.handleRequest(is, os, context); 32 | String result = os.toString(StandardCharsets.UTF_8.name()); 33 | 34 | Assert.assertNotNull(result); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /djl-tensorflow-lite-inference-docker-lambda/src/test/java/com/example/MockContext.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import com.amazonaws.services.lambda.runtime.ClientContext; 4 | import com.amazonaws.services.lambda.runtime.CognitoIdentity; 5 | import com.amazonaws.services.lambda.runtime.Context; 6 | import com.amazonaws.services.lambda.runtime.LambdaLogger; 7 | 8 | public class MockContext implements Context { 9 | 10 | @Override 11 | public String getAwsRequestId() { 12 | return "495b12a8-xmpl-4eca-8168-160484189f99"; 13 | } 14 | 15 | @Override 16 | public String getLogGroupName() { 17 | return "/aws/lambda/my-function"; 18 | } 19 | 20 | @Override 21 | public String getLogStreamName() { 22 | return "2020/02/26/[$LATEST]704f8dxmpla04097b9134246b8438f1a"; 23 | } 24 | 25 | @Override 26 | public String getFunctionName() { 27 | return "my-function"; 28 | } 29 | 30 | @Override 31 | public String getFunctionVersion() { 32 | return "$LATEST"; 33 | } 34 | 35 | @Override 36 | public String getInvokedFunctionArn() { 37 | return "arn:aws:lambda:us-east-2:123456789012:function:my-function"; 38 | } 39 | 40 | @Override 41 | public CognitoIdentity getIdentity() { 42 | return null; 43 | } 44 | 45 | @Override 46 | public ClientContext getClientContext() { 47 | return null; 48 | } 49 | 50 | @Override 51 | public int getRemainingTimeInMillis() { 52 | return 300000; 53 | } 54 | 55 | @Override 56 | public int getMemoryLimitInMB() { 57 | return 512; 58 | } 59 | 60 | @Override 61 | public LambdaLogger getLogger() { 62 | return new MockLogger(); 63 | } 64 | } -------------------------------------------------------------------------------- /djl-tensorflow-lite-inference-docker-lambda/src/test/java/com/example/MockLogger.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import com.amazonaws.services.lambda.runtime.LambdaLogger; 4 | import java.nio.charset.StandardCharsets; 5 | 6 | public class MockLogger implements LambdaLogger { 7 | 8 | @Override 9 | public void log(String message) { 10 | System.out.println(message); 11 | } 12 | 13 | @Override 14 | public void log(byte[] message) { 15 | System.out.println(new String(message, StandardCharsets.UTF_8)); 16 | } 17 | } -------------------------------------------------------------------------------- /djl-tensorflow-lite-inference-docker-lambda/template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | Description: > 4 | djl-tf-lite-image-classification-docker-lambda 5 | 6 | SAM Template for djl-tf-lite-image-classification-docker-lambda 7 | 8 | Resources: 9 | DjlTFLiteInferenceFunction: 10 | Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction 11 | Properties: 12 | PackageType: Image 13 | MemorySize: 512 14 | Timeout: 120 15 | Metadata: 16 | DockerTag: java8-gradle-v1 17 | DockerContext: . 18 | Dockerfile: Dockerfile 19 | 20 | Outputs: 21 | DjlTFLiteInferenceFunction: 22 | Description: "DjlTFLiteInference Lambda Function ARN" 23 | Value: !GetAtt DjlTFLiteInferenceFunction.Arn 24 | DjlTFLiteInferenceFunctionIamRole: 25 | Description: "Implicit IAM Role created for DjlTFLiteInference function" 26 | Value: !GetAtt DjlTFLiteInferenceFunctionRole.Arn 27 | -------------------------------------------------------------------------------- /hebert-sentiment-analysis-inference-docker-lambda/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/osx,linux,python,windows,pycharm,visualstudiocode 3 | 4 | ### Linux ### 5 | *~ 6 | 7 | # temporary files which can be created if a process still has a handle open of a deleted file 8 | .fuse_hidden* 9 | 10 | # KDE directory preferences 11 | .directory 12 | 13 | # Linux trash folder which might appear on any partition or disk 14 | .Trash-* 15 | 16 | # .nfs files are created when an open file is removed but is still being accessed 17 | .nfs* 18 | 19 | ### OSX ### 20 | *.DS_Store 21 | .AppleDouble 22 | .LSOverride 23 | 24 | # Icon must end with two \r 25 | Icon 26 | 27 | # Thumbnails 28 | ._* 29 | 30 | # Files that might appear in the root of a volume 31 | .DocumentRevisions-V100 32 | .fseventsd 33 | .Spotlight-V100 34 | .TemporaryItems 35 | .Trashes 36 | .VolumeIcon.icns 37 | .com.apple.timemachine.donotpresent 38 | 39 | # Directories potentially created on remote AFP share 40 | .AppleDB 41 | .AppleDesktop 42 | Network Trash Folder 43 | Temporary Items 44 | .apdisk 45 | 46 | ### PyCharm ### 47 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 48 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 49 | 50 | # User-specific stuff: 51 | .idea/**/workspace.xml 52 | .idea/**/tasks.xml 53 | .idea/dictionaries 54 | 55 | # Sensitive or high-churn files: 56 | .idea/**/dataSources/ 57 | .idea/**/dataSources.ids 58 | .idea/**/dataSources.xml 59 | .idea/**/dataSources.local.xml 60 | .idea/**/sqlDataSources.xml 61 | .idea/**/dynamic.xml 62 | .idea/**/uiDesigner.xml 63 | 64 | # Gradle: 65 | .idea/**/gradle.xml 66 | .idea/**/libraries 67 | 68 | # CMake 69 | cmake-build-debug/ 70 | 71 | # Mongo Explorer plugin: 72 | .idea/**/mongoSettings.xml 73 | 74 | ## File-based project format: 75 | *.iws 76 | 77 | ## Plugin-specific files: 78 | 79 | # IntelliJ 80 | /out/ 81 | 82 | # mpeltonen/sbt-idea plugin 83 | .idea_modules/ 84 | 85 | # JIRA plugin 86 | atlassian-ide-plugin.xml 87 | 88 | # Cursive Clojure plugin 89 | .idea/replstate.xml 90 | 91 | # Ruby plugin and RubyMine 92 | /.rakeTasks 93 | 94 | # Crashlytics plugin (for Android Studio and IntelliJ) 95 | com_crashlytics_export_strings.xml 96 | crashlytics.properties 97 | crashlytics-build.properties 98 | fabric.properties 99 | 100 | ### PyCharm Patch ### 101 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 102 | 103 | # *.iml 104 | # modules.xml 105 | # .idea/misc.xml 106 | # *.ipr 107 | 108 | # Sonarlint plugin 109 | .idea/sonarlint 110 | 111 | ### Python ### 112 | # Byte-compiled / optimized / DLL files 113 | __pycache__/ 114 | *.py[cod] 115 | *$py.class 116 | 117 | # C extensions 118 | *.so 119 | 120 | # Distribution / packaging 121 | .Python 122 | build/ 123 | develop-eggs/ 124 | dist/ 125 | downloads/ 126 | eggs/ 127 | .eggs/ 128 | lib/ 129 | lib64/ 130 | parts/ 131 | sdist/ 132 | var/ 133 | wheels/ 134 | *.egg-info/ 135 | .installed.cfg 136 | *.egg 137 | 138 | # PyInstaller 139 | # Usually these files are written by a python script from a template 140 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 141 | *.manifest 142 | *.spec 143 | 144 | # Installer logs 145 | pip-log.txt 146 | pip-delete-this-directory.txt 147 | 148 | # Unit test / coverage reports 149 | htmlcov/ 150 | .tox/ 151 | .coverage 152 | .coverage.* 153 | .cache 154 | .pytest_cache/ 155 | nosetests.xml 156 | coverage.xml 157 | *.cover 158 | .hypothesis/ 159 | 160 | # Translations 161 | *.mo 162 | *.pot 163 | 164 | # Flask stuff: 165 | instance/ 166 | .webassets-cache 167 | 168 | # Scrapy stuff: 169 | .scrapy 170 | 171 | # Sphinx documentation 172 | docs/_build/ 173 | 174 | # PyBuilder 175 | target/ 176 | 177 | # Jupyter Notebook 178 | .ipynb_checkpoints 179 | 180 | # pyenv 181 | .python-version 182 | 183 | # celery beat schedule file 184 | celerybeat-schedule.* 185 | 186 | # SageMath parsed files 187 | *.sage.py 188 | 189 | # Environments 190 | .env 191 | .venv 192 | env/ 193 | venv/ 194 | ENV/ 195 | env.bak/ 196 | venv.bak/ 197 | 198 | # Spyder project settings 199 | .spyderproject 200 | .spyproject 201 | 202 | # Rope project settings 203 | .ropeproject 204 | 205 | # mkdocs documentation 206 | /site 207 | 208 | # mypy 209 | .mypy_cache/ 210 | 211 | ### VisualStudioCode ### 212 | .vscode/* 213 | !.vscode/settings.json 214 | !.vscode/tasks.json 215 | !.vscode/launch.json 216 | !.vscode/extensions.json 217 | .history 218 | 219 | ### Windows ### 220 | # Windows thumbnail cache files 221 | Thumbs.db 222 | ehthumbs.db 223 | ehthumbs_vista.db 224 | 225 | # Folder config file 226 | Desktop.ini 227 | 228 | # Recycle Bin used on file shares 229 | $RECYCLE.BIN/ 230 | 231 | # Windows Installer files 232 | *.cab 233 | *.msi 234 | *.msm 235 | *.msp 236 | 237 | # Windows shortcuts 238 | *.lnk 239 | 240 | # Build folder 241 | 242 | */build/* 243 | 244 | # End of https://www.gitignore.io/api/osx,linux,python,windows,pycharm,visualstudiocode -------------------------------------------------------------------------------- /hebert-sentiment-analysis-inference-docker-lambda/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/lambda/python:3.7 2 | 3 | COPY requirements.txt ./requirements.txt 4 | RUN pip install -r requirements.txt 5 | 6 | COPY ./hebert_model.py ./ 7 | RUN python hebert_model.py 8 | 9 | COPY ./app/app.py ./ 10 | 11 | CMD ["app.handler"] 12 | -------------------------------------------------------------------------------- /hebert-sentiment-analysis-inference-docker-lambda/README.md: -------------------------------------------------------------------------------- 1 | ## Serverless HeBERT Model Serving for Sentiment Analysis in Hebrew 2 | 3 | This example illustrates how to serve HeBERT model on a Lambda Function for sentiment analysis in Hebrew. 4 | 5 | ### HeBERT: Pre-trained BERT for Polarity Analysis and Emotion Recognition 6 | 7 | HeBERT is a Hebrew pretrained language model. It is based on Google's BERT architecture and it is BERT-Based config. 8 | 9 | Chriqui, A., & Yahav, I. (2021). HeBERT & HebEMO: a Hebrew BERT Model and a Tool for Polarity Analysis and Emotion Recognition. arXiv preprint arXiv:2102.01909. 10 | ``` 11 | @article{chriqui2021hebert, 12 | title={HeBERT \& HebEMO: a Hebrew BERT Model and a Tool for Polarity Analysis and Emotion Recognition}, 13 | author={Chriqui, Avihay and Yahav, Inbal}, 14 | journal={arXiv preprint arXiv:2102.01909}, 15 | year={2021} 16 | } 17 | ``` 18 | 19 | [Link to GitHub repository](https://github.com/avichaychriqui/HeBERT) 20 | 21 | This project contains source code and supporting files for a serverless application that you can deploy with the SAM CLI. It includes the following files and folders: 22 | 23 | - app - Code for the application's Lambda function. 24 | - events - Invocation events that you can use to invoke the function. 25 | - template.yaml - A template that defines the application's AWS resources. 26 | 27 | The application uses several AWS resources, including Lambda functions. These resources are defined in the `template.yaml` file in this project. You can update the template to add AWS resources through the same deployment process that updates your application code. 28 | 29 | ## Deploy the sample application 30 | 31 | The Serverless Application Model Command Line Interface (SAM CLI) is an extension of the AWS CLI that adds functionality for building and testing Lambda applications. It uses Docker to run your functions in an Amazon Linux environment that matches Lambda. It can also emulate your application's build environment and API. 32 | 33 | To use the SAM CLI, you need the following tools. 34 | 35 | * SAM CLI - [Install the SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) 36 | * Docker - [Install Docker community edition](https://hub.docker.com/search/?type=edition&offering=community) 37 | 38 | You may need the following for local testing. 39 | * [Python 3 installed](https://www.python.org/downloads/) 40 | 41 | To build and deploy your application for the first time, run the following in your shell: 42 | 43 | ```bash 44 | sam build 45 | sam deploy --guided 46 | ``` 47 | 48 | The first command will build a docker image from a Dockerfile and then copy the source of your application inside the Docker image. The second command will package and deploy your application to AWS, with a series of prompts: 49 | 50 | * **Stack Name**: The name of the stack to deploy to CloudFormation. This should be unique to your account and region, and a good starting point would be something matching your project name. 51 | * **AWS Region**: The AWS region you want to deploy your app to. 52 | * **Confirm changes before deploy**: If set to yes, any change sets will be shown to you before execution for manual review. If set to no, the AWS SAM CLI will automatically deploy application changes. 53 | * **Allow SAM CLI IAM role creation**: Many AWS SAM templates, including this example, create AWS IAM roles required for the AWS Lambda function(s) included to access AWS services. By default, these are scoped down to minimum required permissions. To deploy an AWS CloudFormation stack which creates or modified IAM roles, the `CAPABILITY_IAM` value for `capabilities` must be provided. If permission isn't provided through this prompt, to deploy this example you must explicitly pass `--capabilities CAPABILITY_IAM` to the `sam deploy` command. 54 | * **Save arguments to samconfig.toml**: If set to yes, your choices will be saved to a configuration file inside the project, so that in the future you can just re-run `sam deploy` without parameters to deploy changes to your application. 55 | 56 | ## Use the SAM CLI to build and test locally 57 | 58 | Build your application with the `sam build` command. 59 | 60 | ```bash 61 | hebert-sentiment-analysis-inference-docker-lambda$ sam build 62 | ``` 63 | 64 | The SAM CLI builds a docker image from a Dockerfile and then installs dependencies defined in `requirements.txt` inside the docker image. The processed template file is saved in the `.aws-sam/build` folder. 65 | 66 | Test a single function by invoking it directly with a test event. An event is a JSON document that represents the input that the function receives from the event source. Test events are included in the `events` folder in this project. 67 | 68 | Run functions locally and invoke them with the `sam local invoke` command. 69 | 70 | ```bash 71 | hebert-sentiment-analysis-inference-docker-lambda$ sam local invoke HeBERTInferenceFunction --event events/event.json 72 | ``` 73 | ## Testing your Lambda function in the Cloud 74 | 75 | 1. In the [Lambda Console](https://console.aws.amazon.com/lambda/), select your Lambda function, then, the `Test` tab, and configure the Test event. 76 | 2. For Event Name, enter `InferenceTestEvent`. 77 | 3. Copy the event JSON from [here](./events/event.json) and paste in the dialog box. 78 | 4. Choose _**Test**_. 79 | 80 | ![Configure test event](../img/hebert_configure_test_event.png) 81 | 82 | After saving, you see InferenceTestEvent in the Test list. Now choose _**Test**_. 83 | 84 | You see the Lambda function inference result, log output, and duration: 85 | 86 | ![Lambda execution result](../img/hebert_execution_result.png) 87 | 88 | ## Fetch, tail, and filter Lambda function logs 89 | 90 | To simplify troubleshooting, SAM CLI has a command called `sam logs`. `sam logs` lets you fetch logs generated by your deployed Lambda function from the command line. In addition to printing the logs on the terminal, this command has several nifty features to help you quickly find the bug. 91 | 92 | `NOTE`: This command works for all AWS Lambda functions; not just the ones you deploy using SAM. 93 | 94 | ```bash 95 | hebert-sentiment-analysis-inference-docker-lambda$ sam logs -n HeBERTInferenceFunction --stack-name hebert-sentiment-analysis-inference-docker-lambda --tail 96 | ``` 97 | 98 | You can find more information and examples about filtering Lambda function logs in the [SAM CLI Documentation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-logging.html). 99 | 100 | 101 | ## Cleanup 102 | 103 | To delete the sample application that you created, use the AWS CLI. Assuming you used your project name for the stack name, you can run the following: 104 | 105 | ```bash 106 | aws cloudformation delete-stack --stack-name hebert-sentiment-analysis-inference-docker-lambda 107 | ``` 108 | 109 | ## Resources 110 | 111 | See the [AWS SAM developer guide](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html) for an introduction to SAM specification, the SAM CLI, and serverless application concepts. 112 | -------------------------------------------------------------------------------- /hebert-sentiment-analysis-inference-docker-lambda/app/app.py: -------------------------------------------------------------------------------- 1 | from transformers import pipeline 2 | import json 3 | 4 | 5 | sentiment_analysis = pipeline( 6 | "sentiment-analysis", 7 | model="./model", 8 | tokenizer="./model", 9 | return_all_scores = True 10 | ) 11 | 12 | def handler(event, context): 13 | print('Received event: ' + json.dumps(event, indent=2)) 14 | hebrew_text = event['hebrew_text'] 15 | 16 | result = sentiment_analysis(hebrew_text) 17 | 18 | print('result: {}'.format(result)) 19 | 20 | return json.dumps(result) 21 | -------------------------------------------------------------------------------- /hebert-sentiment-analysis-inference-docker-lambda/events/event.json: -------------------------------------------------------------------------------- 1 | {"hebrew_text":"אני אוהב לעבוד באמזון"} -------------------------------------------------------------------------------- /hebert-sentiment-analysis-inference-docker-lambda/hebert_model.py: -------------------------------------------------------------------------------- 1 | from transformers import pipeline 2 | 3 | 4 | sentiment_analysis = pipeline( 5 | "sentiment-analysis", 6 | model="avichr/heBERT_sentiment_analysis", 7 | tokenizer="avichr/heBERT_sentiment_analysis", 8 | return_all_scores = True 9 | ) 10 | 11 | sentiment_analysis.save_pretrained("./model") 12 | -------------------------------------------------------------------------------- /hebert-sentiment-analysis-inference-docker-lambda/requirements.txt: -------------------------------------------------------------------------------- 1 | --find-links https://download.pytorch.org/whl/torch_stable.html 2 | 3 | torch==1.7.1 4 | transformers==4.38.0 -------------------------------------------------------------------------------- /hebert-sentiment-analysis-inference-docker-lambda/template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | Description: > 4 | pytorch-inference-docker-lambda 5 | 6 | SAM Template for pytorch-inference-docker-lambda 7 | 8 | Resources: 9 | HeBERTInferenceFunction: 10 | Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction 11 | Properties: 12 | PackageType: Image 13 | MemorySize: 2048 14 | Timeout: 120 15 | Metadata: 16 | DockerTag: python3.7-v1 17 | DockerContext: . 18 | Dockerfile: Dockerfile 19 | 20 | Outputs: 21 | HeBERTInferenceFunction: 22 | Description: "HeBERTInference Lambda Function ARN" 23 | Value: !GetAtt HeBERTInferenceFunction.Arn 24 | HeBERTInferenceFunctionIamRole: 25 | Description: "Implicit IAM Role created for HeBERTInference function" 26 | Value: !GetAtt HeBERTInferenceFunctionRole.Arn 27 | -------------------------------------------------------------------------------- /img/aws_lambda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-lambda-docker-serverless-inference/df108386292aa99cd8213f01b4473eb9f99e7b17/img/aws_lambda.png -------------------------------------------------------------------------------- /img/aws_ml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-lambda-docker-serverless-inference/df108386292aa99cd8213f01b4473eb9f99e7b17/img/aws_ml.png -------------------------------------------------------------------------------- /img/djl_object_detection_configure_test_event.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-lambda-docker-serverless-inference/df108386292aa99cd8213f01b4473eb9f99e7b17/img/djl_object_detection_configure_test_event.png -------------------------------------------------------------------------------- /img/djl_object_detection_execution_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-lambda-docker-serverless-inference/df108386292aa99cd8213f01b4473eb9f99e7b17/img/djl_object_detection_execution_result.png -------------------------------------------------------------------------------- /img/djl_tensorflow_lite_configure_test_event.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-lambda-docker-serverless-inference/df108386292aa99cd8213f01b4473eb9f99e7b17/img/djl_tensorflow_lite_configure_test_event.png -------------------------------------------------------------------------------- /img/djl_tensorflow_lite_execution_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-lambda-docker-serverless-inference/df108386292aa99cd8213f01b4473eb9f99e7b17/img/djl_tensorflow_lite_execution_result.png -------------------------------------------------------------------------------- /img/docker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-lambda-docker-serverless-inference/df108386292aa99cd8213f01b4473eb9f99e7b17/img/docker.png -------------------------------------------------------------------------------- /img/fasttext_configure_test_event.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-lambda-docker-serverless-inference/df108386292aa99cd8213f01b4473eb9f99e7b17/img/fasttext_configure_test_event.png -------------------------------------------------------------------------------- /img/fasttext_execution_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-lambda-docker-serverless-inference/df108386292aa99cd8213f01b4473eb9f99e7b17/img/fasttext_execution_result.png -------------------------------------------------------------------------------- /img/hebert_configure_test_event.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-lambda-docker-serverless-inference/df108386292aa99cd8213f01b4473eb9f99e7b17/img/hebert_configure_test_event.png -------------------------------------------------------------------------------- /img/hebert_execution_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-lambda-docker-serverless-inference/df108386292aa99cd8213f01b4473eb9f99e7b17/img/hebert_execution_result.png -------------------------------------------------------------------------------- /img/pytorch_configure_test_event.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-lambda-docker-serverless-inference/df108386292aa99cd8213f01b4473eb9f99e7b17/img/pytorch_configure_test_event.png -------------------------------------------------------------------------------- /img/pytorch_execution_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-lambda-docker-serverless-inference/df108386292aa99cd8213f01b4473eb9f99e7b17/img/pytorch_execution_result.png -------------------------------------------------------------------------------- /img/scikit-learn_configure_test_event.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-lambda-docker-serverless-inference/df108386292aa99cd8213f01b4473eb9f99e7b17/img/scikit-learn_configure_test_event.png -------------------------------------------------------------------------------- /img/scikit-learn_execution_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-lambda-docker-serverless-inference/df108386292aa99cd8213f01b4473eb9f99e7b17/img/scikit-learn_execution_result.png -------------------------------------------------------------------------------- /img/tensorflow_configure_test_event.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-lambda-docker-serverless-inference/df108386292aa99cd8213f01b4473eb9f99e7b17/img/tensorflow_configure_test_event.png -------------------------------------------------------------------------------- /img/tensorflow_execution_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-lambda-docker-serverless-inference/df108386292aa99cd8213f01b4473eb9f99e7b17/img/tensorflow_execution_result.png -------------------------------------------------------------------------------- /img/tensorflow_mnist_sagemaker_configure_test_event.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-lambda-docker-serverless-inference/df108386292aa99cd8213f01b4473eb9f99e7b17/img/tensorflow_mnist_sagemaker_configure_test_event.png -------------------------------------------------------------------------------- /img/tensorflow_mnist_sagemaker_execution_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-lambda-docker-serverless-inference/df108386292aa99cd8213f01b4473eb9f99e7b17/img/tensorflow_mnist_sagemaker_execution_result.png -------------------------------------------------------------------------------- /img/xgboost-built-in-algo-train-in-sagemaker-deploy-with-lambda-copy-outputs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-lambda-docker-serverless-inference/df108386292aa99cd8213f01b4473eb9f99e7b17/img/xgboost-built-in-algo-train-in-sagemaker-deploy-with-lambda-copy-outputs.png -------------------------------------------------------------------------------- /img/xgboost_arm_64_arch_view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-lambda-docker-serverless-inference/df108386292aa99cd8213f01b4473eb9f99e7b17/img/xgboost_arm_64_arch_view.png -------------------------------------------------------------------------------- /img/xgboost_arm_64_execution_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-lambda-docker-serverless-inference/df108386292aa99cd8213f01b4473eb9f99e7b17/img/xgboost_arm_64_execution_result.png -------------------------------------------------------------------------------- /img/xgboost_configure_test_event.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-lambda-docker-serverless-inference/df108386292aa99cd8213f01b4473eb9f99e7b17/img/xgboost_configure_test_event.png -------------------------------------------------------------------------------- /img/xgboost_direct_marketing_configure_test_event.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-lambda-docker-serverless-inference/df108386292aa99cd8213f01b4473eb9f99e7b17/img/xgboost_direct_marketing_configure_test_event.png -------------------------------------------------------------------------------- /img/xgboost_direct_marketing_execution_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-lambda-docker-serverless-inference/df108386292aa99cd8213f01b4473eb9f99e7b17/img/xgboost_direct_marketing_execution_result.png -------------------------------------------------------------------------------- /img/xgboost_execution_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-lambda-docker-serverless-inference/df108386292aa99cd8213f01b4473eb9f99e7b17/img/xgboost_execution_result.png -------------------------------------------------------------------------------- /img/xgboost_x86_64_arm64_improvement.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-lambda-docker-serverless-inference/df108386292aa99cd8213f01b4473eb9f99e7b17/img/xgboost_x86_64_arm64_improvement.png -------------------------------------------------------------------------------- /online-machine-learning-aws-lambda/.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io/api/osx,linux,python,windows,pycharm,visualstudiocode 2 | 3 | ### Linux ### 4 | *~ 5 | 6 | # temporary files which can be created if a process still has a handle open of a deleted file 7 | .fuse_hidden* 8 | 9 | # KDE directory preferences 10 | .directory 11 | 12 | # Linux trash folder which might appear on any partition or disk 13 | .Trash-* 14 | 15 | # .nfs files are created when an open file is removed but is still being accessed 16 | .nfs* 17 | 18 | ### OSX ### 19 | *.DS_Store 20 | .AppleDouble 21 | .LSOverride 22 | 23 | # Icon must end with two \r 24 | Icon 25 | 26 | # Thumbnails 27 | ._* 28 | 29 | # Files that might appear in the root of a volume 30 | .DocumentRevisions-V100 31 | .fseventsd 32 | .Spotlight-V100 33 | .TemporaryItems 34 | .Trashes 35 | .VolumeIcon.icns 36 | .com.apple.timemachine.donotpresent 37 | 38 | # Directories potentially created on remote AFP share 39 | .AppleDB 40 | .AppleDesktop 41 | Network Trash Folder 42 | Temporary Items 43 | .apdisk 44 | 45 | ### PyCharm ### 46 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 47 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 48 | 49 | # User-specific stuff: 50 | .idea/**/workspace.xml 51 | .idea/**/tasks.xml 52 | .idea/dictionaries 53 | 54 | # Sensitive or high-churn files: 55 | .idea/**/dataSources/ 56 | .idea/**/dataSources.ids 57 | .idea/**/dataSources.xml 58 | .idea/**/dataSources.local.xml 59 | .idea/**/sqlDataSources.xml 60 | .idea/**/dynamic.xml 61 | .idea/**/uiDesigner.xml 62 | 63 | # Gradle: 64 | .idea/**/gradle.xml 65 | .idea/**/libraries 66 | 67 | # CMake 68 | cmake-build-debug/ 69 | 70 | # Mongo Explorer plugin: 71 | .idea/**/mongoSettings.xml 72 | 73 | ## File-based project format: 74 | *.iws 75 | 76 | ## Plugin-specific files: 77 | 78 | # IntelliJ 79 | /out/ 80 | 81 | # mpeltonen/sbt-idea plugin 82 | .idea_modules/ 83 | 84 | # JIRA plugin 85 | atlassian-ide-plugin.xml 86 | 87 | # Cursive Clojure plugin 88 | .idea/replstate.xml 89 | 90 | # Ruby plugin and RubyMine 91 | /.rakeTasks 92 | 93 | # Crashlytics plugin (for Android Studio and IntelliJ) 94 | com_crashlytics_export_strings.xml 95 | crashlytics.properties 96 | crashlytics-build.properties 97 | fabric.properties 98 | 99 | ### PyCharm Patch ### 100 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 101 | 102 | # *.iml 103 | # modules.xml 104 | # .idea/misc.xml 105 | # *.ipr 106 | 107 | # Sonarlint plugin 108 | .idea/sonarlint 109 | 110 | ### Python ### 111 | # Byte-compiled / optimized / DLL files 112 | __pycache__/ 113 | *.py[cod] 114 | *$py.class 115 | 116 | # C extensions 117 | *.so 118 | 119 | # Distribution / packaging 120 | .Python 121 | build/ 122 | develop-eggs/ 123 | dist/ 124 | downloads/ 125 | eggs/ 126 | .eggs/ 127 | lib/ 128 | lib64/ 129 | parts/ 130 | sdist/ 131 | var/ 132 | wheels/ 133 | *.egg-info/ 134 | .installed.cfg 135 | *.egg 136 | 137 | # PyInstaller 138 | # Usually these files are written by a python script from a template 139 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 140 | *.manifest 141 | *.spec 142 | 143 | # Installer logs 144 | pip-log.txt 145 | pip-delete-this-directory.txt 146 | 147 | # Unit test / coverage reports 148 | htmlcov/ 149 | .tox/ 150 | .coverage 151 | .coverage.* 152 | .cache 153 | .pytest_cache/ 154 | nosetests.xml 155 | coverage.xml 156 | *.cover 157 | .hypothesis/ 158 | 159 | # Translations 160 | *.mo 161 | *.pot 162 | 163 | # Flask stuff: 164 | instance/ 165 | .webassets-cache 166 | 167 | # Scrapy stuff: 168 | .scrapy 169 | 170 | # Sphinx documentation 171 | docs/_build/ 172 | 173 | # PyBuilder 174 | target/ 175 | 176 | # Jupyter Notebook 177 | .ipynb_checkpoints 178 | 179 | # pyenv 180 | .python-version 181 | 182 | # celery beat schedule file 183 | celerybeat-schedule.* 184 | 185 | # SageMath parsed files 186 | *.sage.py 187 | 188 | # Environments 189 | .env 190 | .venv 191 | env/ 192 | venv/ 193 | ENV/ 194 | env.bak/ 195 | venv.bak/ 196 | .aws-sam 197 | .idea 198 | # Spyder project settings 199 | .spyderproject 200 | .spyproject 201 | 202 | # Rope project settings 203 | .ropeproject 204 | 205 | # mkdocs documentation 206 | /site 207 | 208 | # mypy 209 | .mypy_cache/ 210 | 211 | ### VisualStudioCode ### 212 | .vscode/* 213 | !.vscode/settings.json 214 | !.vscode/tasks.json 215 | !.vscode/launch.json 216 | !.vscode/extensions.json 217 | .history 218 | 219 | ### Windows ### 220 | # Windows thumbnail cache files 221 | Thumbs.db 222 | ehthumbs.db 223 | ehthumbs_vista.db 224 | 225 | # Folder config file 226 | Desktop.ini 227 | 228 | # Recycle Bin used on file shares 229 | $RECYCLE.BIN/ 230 | 231 | # Windows Installer files 232 | *.cab 233 | *.msi 234 | *.msm 235 | *.msp 236 | 237 | # Windows shortcuts 238 | *.lnk 239 | 240 | # Build folder 241 | 242 | */build/* 243 | 244 | # End of https://www.gitignore.io/api/osx,linux,python,windows,pycharm,visualstudiocode 245 | -------------------------------------------------------------------------------- /online-machine-learning-aws-lambda/README.md: -------------------------------------------------------------------------------- 1 | # Serverless scikit-learn training and inference 2 | 3 | This project contains source code and supporting files for a serverless application for training and serving a Machine Learning model in [scikit-learn](https://scikit-learn.org/). The following image illustrates the application's architecture: 4 | 5 | ![Alt text](./img/architecture_diagram.png?raw=true "Title") 6 | 7 | This example includes the following files and folders: 8 | 9 | - app/lambda_inference/ - Code for the application's inference Lambda function. 10 | - app/lambda_training/ - Code for the application's training Lambda function. 11 | - app/*/app.py - Code for the application's Lambda function. 12 | - app/*/Dockerfile - The Dockerfile to build the container image. 13 | - app/*/requirements.txt - The pip requirements to be installed during the container build. 14 | - template.yaml - A template that defines the application's AWS resources. 15 | - events/inference_event.json - A sample payload to test the inference Lambda function locally. 16 | - events/train_event.json - A sample payload to test the training Lambda function locally. 17 | - env.json - Json file to add the bucket name of your deployed S3 model bucket for local testing of the Lambda functions. 18 | - notebooks/test_notebook.ipynb - A Jupyter notebook to test the lambda function in the cloud by invoking them directly and through API Gateway. 19 | 20 | The application uses several AWS resources, including Lambda functions and an API Gateway API. These resources are defined in the `template.yaml` file in this project. You can update the template to add AWS resources through the same deployment process that updates your application code. 21 | 22 | While this template does not use any auth, you will almost certainly want to use auth in order to productionize. Please follow [these instructions](https://github.com/aws/serverless-application-model/blob/master/versions/2016-10-31.md#function-auth-object) to set up auth with SAM. 23 | 24 | ## Deploy the sample application 25 | 26 | The Serverless Application Model Command Line Interface (SAM CLI) is an extension of the AWS CLI that adds functionality for building and testing Lambda applications. It uses Docker to run your functions in an Amazon Linux environment that matches Lambda. It can also emulate your application's build environment and API. 27 | 28 | To use the SAM CLI, you need the following tools. 29 | 30 | * SAM CLI - [Install the SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) 31 | * Docker - [Install Docker community edition](https://hub.docker.com/search/?type=edition&offering=community) 32 | 33 | You may need the following for local testing. 34 | * [Python 3 installed](https://www.python.org/downloads/) 35 | 36 | To build and deploy your application for the first time, run the following in your shell: 37 | 38 | ```bash 39 | sam build 40 | sam deploy --guided 41 | ``` 42 | 43 | The first command will build a docker image from a Dockerfile and then copy the source of your application inside the Docker image. The second command will package and deploy your application to AWS, with a series of prompts: 44 | 45 | * **Stack Name**: The name of the stack to deploy to CloudFormation. This should be unique to your account and region, and a good starting point would be something matching your project name. 46 | * **AWS Region**: The AWS region you want to deploy your app to. 47 | * **Confirm changes before deploy**: If set to yes, any change sets will be shown to you before execution for manual review. If set to no, the AWS SAM CLI will automatically deploy application changes. 48 | * **Allow SAM CLI IAM role creation**: Many AWS SAM templates, including this example, create AWS IAM roles required for the AWS Lambda function(s) included to access AWS services. By default, these are scoped down to minimum required permissions. To deploy an AWS CloudFormation stack which creates or modifies IAM roles, the `CAPABILITY_IAM` value for `capabilities` must be provided. If permission isn't provided through this prompt, to deploy this example you must explicitly pass `--capabilities CAPABILITY_IAM` to the `sam deploy` command. 49 | * **Save arguments to samconfig.toml**: If set to yes, your choices will be saved to a configuration file inside the project, so that in the future you can just re-run `sam deploy` without parameters to deploy changes to your application. 50 | 51 | You can find your API Gateway Endpoint URL in the output values displayed after deployment. 52 | 53 | ## Use the SAM CLI to build and test locally 54 | 55 | Build your application with the `sam build` command. 56 | 57 | ```bash 58 | online-ml$ sam build 59 | ``` 60 | 61 | The SAM CLI builds a docker image from a Dockerfile and then installs dependencies defined in `app/*/requirements.txt` inside the docker image. The processed template file is saved in the `.aws-sam/build` folder. 62 | 63 | Test a single function by invoking it directly with a test event. An event is a JSON document that represents the input that the function receives from the event source. Test events are included in the `events` folder in this project. 64 | 65 | In order to have your local lambda function access the correct S3 bucket, access the AWS console, go to `CloudFormation` under stacks click on `serverless-online-ml`, click on `Resources` and copy the `Physical ID` of your `ModelBucket`. 66 | Paste the physical ID in the `env.json` in the respective fields of the two lambda functions: 67 | 68 | ```json 69 | { 70 | "TrainingFunction": { 71 | "BUCKET_NAME": "serverless-online-ml-modelbucket-xxxxxxxxxx" //Replace this string with your physical ID 72 | }, 73 | "InferenceFunction": { 74 | "BUCKET_NAME": "serverless-online-ml-modelbucket-xxxxxxxxxx" //Replace this string with your physical ID 75 | } 76 | } 77 | ``` 78 | Run functions locally and invoke them with the `sam local invoke` command. 79 | ```bash 80 | online-ml$ sam local invoke TrainingFunction --event events/train_event.json --env-vars env.json 81 | online-ml$ sam local invoke InferenceFunction --event events/inference_event.json --env-vars env.json 82 | ``` 83 | 84 | ## Add a resource to your application 85 | The application template uses AWS Serverless Application Model (AWS SAM) to define application resources. AWS SAM is an extension of AWS CloudFormation with a simpler syntax for configuring common serverless application resources such as functions, triggers, and APIs. For resources not included in [the SAM specification](https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md), you can use standard [AWS CloudFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html) resource types. 86 | 87 | ## Fetch, tail, and filter Lambda function logs 88 | 89 | To simplify troubleshooting, SAM CLI has a command called `sam logs`. `sam logs` lets you fetch logs generated by your deployed Lambda function from the command line. In addition to printing the logs on the terminal, this command has several nifty features to help you quickly find the bug. 90 | 91 | `NOTE`: This command works for all AWS Lambda functions; not just the ones you deploy using SAM. 92 | 93 | ```bash 94 | online-ml$ sam logs -n InferenceFunction --stack-name online-ml --tail 95 | ``` 96 | 97 | You can find more information and examples about filtering Lambda function logs in the [SAM CLI Documentation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-logging.html). 98 | 99 | ## Cleanup 100 | 101 | To delete the sample application that you created, use the AWS CLI. Assuming you used your project name for the stack name, you can run the following: 102 | 103 | ```bash 104 | aws cloudformation delete-stack --stack-name online-ml 105 | ``` 106 | 107 | ## Resources 108 | 109 | See the [AWS SAM developer guide](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html) for an introduction to SAM specification, the SAM CLI, and serverless application concepts. 110 | 111 | Next, you can use AWS Serverless Application Repository to deploy ready to use Apps that go beyond hello world samples and learn how authors developed their applications: [AWS Serverless Application Repository main page](https://aws.amazon.com/serverless/serverlessrepo/) 112 | -------------------------------------------------------------------------------- /online-machine-learning-aws-lambda/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-lambda-docker-serverless-inference/df108386292aa99cd8213f01b4473eb9f99e7b17/online-machine-learning-aws-lambda/__init__.py -------------------------------------------------------------------------------- /online-machine-learning-aws-lambda/app/lambda_inference/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/lambda/python:3.8 2 | 3 | COPY requirements.txt ./ 4 | 5 | RUN python3.8 -m pip install -r requirements.txt -t . 6 | 7 | COPY app.py ./ 8 | 9 | CMD ["app.lambda_handler"] 10 | -------------------------------------------------------------------------------- /online-machine-learning-aws-lambda/app/lambda_inference/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-lambda-docker-serverless-inference/df108386292aa99cd8213f01b4473eb9f99e7b17/online-machine-learning-aws-lambda/app/lambda_inference/__init__.py -------------------------------------------------------------------------------- /online-machine-learning-aws-lambda/app/lambda_inference/app.py: -------------------------------------------------------------------------------- 1 | import json 2 | import boto3 3 | import os 4 | from aws_lambda_powertools import Logger 5 | from aws_lambda_powertools.utilities.data_classes import APIGatewayProxyEvent 6 | import tempfile 7 | import joblib 8 | 9 | s3 = boto3.client('s3') 10 | logger = Logger(service="inference") 11 | 12 | BUCKET_NAME = os.environ['BUCKET_NAME'] 13 | model_name = 'model.joblib' 14 | 15 | 16 | def _download_model_from_s3(model_key): 17 | with tempfile.TemporaryFile() as fp: 18 | s3.download_fileobj(BUCKET_NAME, model_key, fp) 19 | fp.seek(0) 20 | model = joblib.load(fp) 21 | return model 22 | 23 | 24 | # Lambda handler code 25 | @logger.inject_lambda_context 26 | def lambda_handler(event, _): 27 | event = APIGatewayProxyEvent(event) 28 | logger.info(event.__dict__) 29 | # parse input event 30 | data = event.get('body') 31 | data = json.loads(data) 32 | data = data.get("data") 33 | # download current model from s3 34 | regr = _download_model_from_s3(model_name) 35 | # make prediction 36 | pred = regr.predict(data) 37 | # log prediction 38 | logger.info({ 39 | "data": data, 40 | "prediction": pred, 41 | }) 42 | 43 | return { 44 | 'statusCode': 200, 45 | 'body': json.dumps( 46 | { 47 | "prediction": json.dumps(pred.tolist()), 48 | } 49 | ) 50 | } 51 | -------------------------------------------------------------------------------- /online-machine-learning-aws-lambda/app/lambda_inference/requirements.txt: -------------------------------------------------------------------------------- 1 | aws-lambda-powertools==1.18.1 2 | scikit-learn==1.5.0 -------------------------------------------------------------------------------- /online-machine-learning-aws-lambda/app/lambda_training/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/lambda/python:3.8 2 | 3 | COPY requirements.txt ./ 4 | 5 | RUN python3.8 -m pip install -r requirements.txt -t . 6 | 7 | COPY app.py ./ 8 | 9 | CMD ["app.lambda_handler"] 10 | -------------------------------------------------------------------------------- /online-machine-learning-aws-lambda/app/lambda_training/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-lambda-docker-serverless-inference/df108386292aa99cd8213f01b4473eb9f99e7b17/online-machine-learning-aws-lambda/app/lambda_training/__init__.py -------------------------------------------------------------------------------- /online-machine-learning-aws-lambda/app/lambda_training/app.py: -------------------------------------------------------------------------------- 1 | import json 2 | import boto3 3 | import os 4 | from aws_lambda_powertools import Logger 5 | from aws_lambda_powertools.utilities.data_classes import APIGatewayProxyEvent 6 | from sklearn import linear_model 7 | from sklearn.metrics import mean_squared_error, r2_score 8 | 9 | import tempfile 10 | import joblib 11 | 12 | s3 = boto3.client('s3') 13 | logger = Logger(service="training") 14 | 15 | BUCKET_NAME = os.environ['BUCKET_NAME'] 16 | model_name = 'model.joblib' 17 | 18 | 19 | def _upload_model_to_s3(model, model_key): 20 | with tempfile.TemporaryFile() as fp: 21 | joblib.dump(model, fp) 22 | fp.seek(0) 23 | s3.upload_fileobj(fp, BUCKET_NAME, model_key) 24 | 25 | 26 | def _train_regression_model(X_train, y_train): 27 | # Create linear regression object 28 | regr = linear_model.LinearRegression() 29 | # Train the model using the training sets 30 | regr.fit(X_train, y_train) 31 | return regr 32 | 33 | 34 | def _test_model(model, X_test, y_test): 35 | # Make predictions using the testing set 36 | y_pred = model.predict(X_test) 37 | # calculate quality coefficients 38 | mse = mean_squared_error(y_test, y_pred) 39 | r2 = r2_score(y_test, y_pred) 40 | return mse, r2 41 | 42 | 43 | def _parse_input(event): 44 | # extract input data from event 45 | data = event.get('body') 46 | d = json.loads(data) 47 | print('data', d.get("data")) 48 | logger.info(d) 49 | X = d["data"]['X'] 50 | y = d["data"]['y'] 51 | # Split the data into training/testing sets 52 | X_train = X[:-20] 53 | X_test = X[-20:] 54 | # Split the targets into training/testing sets 55 | y_train = y[:-20] 56 | y_test = y[-20:] 57 | return X_train, X_test, y_train, y_test 58 | 59 | 60 | # Lambda handler code 61 | @logger.inject_lambda_context 62 | def lambda_handler(event, _): 63 | event = APIGatewayProxyEvent(event) 64 | print(f'bucketname: {BUCKET_NAME}') 65 | logger.info(event.__dict__) 66 | # parse input event and split dataset 67 | X_train, X_test, y_train, y_test = _parse_input(event) 68 | # train regression model 69 | regr = _train_regression_model(X_train, y_train) 70 | # test model 71 | mse, r2 = _test_model(regr, X_test, y_test) 72 | logger.info({ 73 | "message": "model training successful", 74 | 'mean_squared_error': mse, 75 | 'r_squared': r2 76 | }) 77 | 78 | # save trained model to s3 79 | _upload_model_to_s3(regr, model_name) 80 | logger.info({ 81 | "message": "model saved to s3", 82 | 'bucket_name': BUCKET_NAME, 83 | 'model_name': model_name 84 | }) 85 | 86 | return { 87 | 'statusCode': 200, 88 | 'body': json.dumps( 89 | { 90 | 'training': 'success', 91 | 'mean_squared_error': mse, 92 | 'r_squared': r2 93 | } 94 | ) 95 | } 96 | -------------------------------------------------------------------------------- /online-machine-learning-aws-lambda/app/lambda_training/requirements.txt: -------------------------------------------------------------------------------- 1 | aws-lambda-powertools==1.18.1 2 | scikit-learn==1.5.0 -------------------------------------------------------------------------------- /online-machine-learning-aws-lambda/env.json: -------------------------------------------------------------------------------- 1 | { 2 | "TrainingFunction": { 3 | "BUCKET_NAME": "PASTE-YOUR-MODELBUCKET-PHYSICAL-ID-HERE" 4 | }, 5 | "InferenceFunction": { 6 | "BUCKET_NAME": "PASTE-YOUR-MODELBUCKET-PHYSICAL-ID-HERE" 7 | } 8 | } -------------------------------------------------------------------------------- /online-machine-learning-aws-lambda/events/inference_event.json: -------------------------------------------------------------------------------- 1 | {"body": "{\"data\": [[0.9473429517203873], [-1.5162175245908844], [-0.7679804504925086], [-0.25457912401249333], [0.8077631177897462], [0.011471399836209494], [-1.1764034147643736], [0.6300387294413464], [0.04633336927184777], [1.212773169664432]]}"} -------------------------------------------------------------------------------- /online-machine-learning-aws-lambda/img/architecture_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-lambda-docker-serverless-inference/df108386292aa99cd8213f01b4473eb9f99e7b17/online-machine-learning-aws-lambda/img/architecture_diagram.png -------------------------------------------------------------------------------- /online-machine-learning-aws-lambda/template.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | 4 | Globals: 5 | Function: 6 | Timeout: 50 7 | MemorySize: 5000 8 | 9 | Resources: 10 | ModelBucket: 11 | Type: AWS::S3::Bucket 12 | InferenceFunction: 13 | Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction 14 | Properties: 15 | PackageType: Image 16 | Events: 17 | Inference: 18 | Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api 19 | Properties: 20 | Path: /inference 21 | Method: post 22 | Policies: 23 | - S3ReadPolicy: 24 | BucketName: !Ref ModelBucket 25 | Environment: 26 | Variables: 27 | BUCKET_NAME: !Ref ModelBucket 28 | Metadata: 29 | Dockerfile: Dockerfile 30 | DockerContext: ./app/lambda_inference 31 | DockerTag: python3.8-v1 32 | TrainingFunction: 33 | Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction 34 | Properties: 35 | PackageType: Image 36 | Events: 37 | Inference: 38 | Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api 39 | Properties: 40 | Path: /training 41 | Method: post 42 | Policies: 43 | - S3WritePolicy: 44 | BucketName: !Ref ModelBucket 45 | Environment: 46 | Variables: 47 | BUCKET_NAME: !Ref ModelBucket 48 | ReservedConcurrentExecutions: 1 49 | Metadata: 50 | Dockerfile: Dockerfile 51 | DockerContext: ./app/lambda_training 52 | DockerTag: python3.8-v1 53 | 54 | Outputs: 55 | # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function 56 | # Find out more about other implicit resources you can reference within SAM 57 | # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api 58 | InferenceApi: 59 | Description: "API Gateway endpoint URL for Prod stage for Inference function" 60 | Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/inference/" 61 | InferenceFunction: 62 | Description: "Inference Lambda Function ARN" 63 | Value: !GetAtt InferenceFunction.Arn 64 | InferenceFunctionIamRole: 65 | Description: "Implicit IAM Role created for Inference function" 66 | Value: !GetAtt InferenceFunction.Arn 67 | TrainingApi: 68 | Description: "API Gateway endpoint URL for Prod stage for Training function" 69 | Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/training/" 70 | TrainingFunction: 71 | Description: "Training Lambda Function ARN" 72 | Value: !GetAtt TrainingFunction.Arn 73 | TrainingFunctionIamRole: 74 | Description: "Implicit IAM Role created for Training function" 75 | Value: !GetAtt TrainingFunction.Arn -------------------------------------------------------------------------------- /pytorch-inference-docker-lambda/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/osx,linux,python,windows,pycharm,visualstudiocode 3 | 4 | ### Linux ### 5 | *~ 6 | 7 | # temporary files which can be created if a process still has a handle open of a deleted file 8 | .fuse_hidden* 9 | 10 | # KDE directory preferences 11 | .directory 12 | 13 | # Linux trash folder which might appear on any partition or disk 14 | .Trash-* 15 | 16 | # .nfs files are created when an open file is removed but is still being accessed 17 | .nfs* 18 | 19 | ### OSX ### 20 | *.DS_Store 21 | .AppleDouble 22 | .LSOverride 23 | 24 | # Icon must end with two \r 25 | Icon 26 | 27 | # Thumbnails 28 | ._* 29 | 30 | # Files that might appear in the root of a volume 31 | .DocumentRevisions-V100 32 | .fseventsd 33 | .Spotlight-V100 34 | .TemporaryItems 35 | .Trashes 36 | .VolumeIcon.icns 37 | .com.apple.timemachine.donotpresent 38 | 39 | # Directories potentially created on remote AFP share 40 | .AppleDB 41 | .AppleDesktop 42 | Network Trash Folder 43 | Temporary Items 44 | .apdisk 45 | 46 | ### PyCharm ### 47 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 48 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 49 | 50 | # User-specific stuff: 51 | .idea/**/workspace.xml 52 | .idea/**/tasks.xml 53 | .idea/dictionaries 54 | 55 | # Sensitive or high-churn files: 56 | .idea/**/dataSources/ 57 | .idea/**/dataSources.ids 58 | .idea/**/dataSources.xml 59 | .idea/**/dataSources.local.xml 60 | .idea/**/sqlDataSources.xml 61 | .idea/**/dynamic.xml 62 | .idea/**/uiDesigner.xml 63 | 64 | # Gradle: 65 | .idea/**/gradle.xml 66 | .idea/**/libraries 67 | 68 | # CMake 69 | cmake-build-debug/ 70 | 71 | # Mongo Explorer plugin: 72 | .idea/**/mongoSettings.xml 73 | 74 | ## File-based project format: 75 | *.iws 76 | 77 | ## Plugin-specific files: 78 | 79 | # IntelliJ 80 | /out/ 81 | 82 | # mpeltonen/sbt-idea plugin 83 | .idea_modules/ 84 | 85 | # JIRA plugin 86 | atlassian-ide-plugin.xml 87 | 88 | # Cursive Clojure plugin 89 | .idea/replstate.xml 90 | 91 | # Ruby plugin and RubyMine 92 | /.rakeTasks 93 | 94 | # Crashlytics plugin (for Android Studio and IntelliJ) 95 | com_crashlytics_export_strings.xml 96 | crashlytics.properties 97 | crashlytics-build.properties 98 | fabric.properties 99 | 100 | ### PyCharm Patch ### 101 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 102 | 103 | # *.iml 104 | # modules.xml 105 | # .idea/misc.xml 106 | # *.ipr 107 | 108 | # Sonarlint plugin 109 | .idea/sonarlint 110 | 111 | ### Python ### 112 | # Byte-compiled / optimized / DLL files 113 | __pycache__/ 114 | *.py[cod] 115 | *$py.class 116 | 117 | # C extensions 118 | *.so 119 | 120 | # Distribution / packaging 121 | .Python 122 | build/ 123 | develop-eggs/ 124 | dist/ 125 | downloads/ 126 | eggs/ 127 | .eggs/ 128 | lib/ 129 | lib64/ 130 | parts/ 131 | sdist/ 132 | var/ 133 | wheels/ 134 | *.egg-info/ 135 | .installed.cfg 136 | *.egg 137 | 138 | # PyInstaller 139 | # Usually these files are written by a python script from a template 140 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 141 | *.manifest 142 | *.spec 143 | 144 | # Installer logs 145 | pip-log.txt 146 | pip-delete-this-directory.txt 147 | 148 | # Unit test / coverage reports 149 | htmlcov/ 150 | .tox/ 151 | .coverage 152 | .coverage.* 153 | .cache 154 | .pytest_cache/ 155 | nosetests.xml 156 | coverage.xml 157 | *.cover 158 | .hypothesis/ 159 | 160 | # Translations 161 | *.mo 162 | *.pot 163 | 164 | # Flask stuff: 165 | instance/ 166 | .webassets-cache 167 | 168 | # Scrapy stuff: 169 | .scrapy 170 | 171 | # Sphinx documentation 172 | docs/_build/ 173 | 174 | # PyBuilder 175 | target/ 176 | 177 | # Jupyter Notebook 178 | .ipynb_checkpoints 179 | 180 | # pyenv 181 | .python-version 182 | 183 | # celery beat schedule file 184 | celerybeat-schedule.* 185 | 186 | # SageMath parsed files 187 | *.sage.py 188 | 189 | # Environments 190 | .env 191 | .venv 192 | env/ 193 | venv/ 194 | ENV/ 195 | env.bak/ 196 | venv.bak/ 197 | 198 | # Spyder project settings 199 | .spyderproject 200 | .spyproject 201 | 202 | # Rope project settings 203 | .ropeproject 204 | 205 | # mkdocs documentation 206 | /site 207 | 208 | # mypy 209 | .mypy_cache/ 210 | 211 | ### VisualStudioCode ### 212 | .vscode/* 213 | !.vscode/settings.json 214 | !.vscode/tasks.json 215 | !.vscode/launch.json 216 | !.vscode/extensions.json 217 | .history 218 | 219 | ### Windows ### 220 | # Windows thumbnail cache files 221 | Thumbs.db 222 | ehthumbs.db 223 | ehthumbs_vista.db 224 | 225 | # Folder config file 226 | Desktop.ini 227 | 228 | # Recycle Bin used on file shares 229 | $RECYCLE.BIN/ 230 | 231 | # Windows Installer files 232 | *.cab 233 | *.msi 234 | *.msm 235 | *.msp 236 | 237 | # Windows shortcuts 238 | *.lnk 239 | 240 | # Build folder 241 | 242 | */build/* 243 | 244 | # End of https://www.gitignore.io/api/osx,linux,python,windows,pycharm,visualstudiocode -------------------------------------------------------------------------------- /pytorch-inference-docker-lambda/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/lambda/python:3.8 2 | 3 | RUN yum install -y wget 4 | 5 | COPY requirements.txt ./requirements.txt 6 | RUN pip install -r requirements.txt 7 | 8 | COPY ./model/resnet.py ./ 9 | RUN python resnet.py 10 | 11 | RUN wget https://raw.githubusercontent.com/pytorch/hub/master/imagenet_classes.txt 12 | 13 | COPY ./app/app.py ./ 14 | 15 | CMD ["app.handler"] 16 | -------------------------------------------------------------------------------- /pytorch-inference-docker-lambda/README.md: -------------------------------------------------------------------------------- 1 | ## Serverless PyTorch Model Serving 2 | 3 | This examples illustrates how to serve PyTorch model on Lambda Function for Image Classification. 4 | 5 | This project contains source code and supporting files for a serverless application that you can deploy with the SAM CLI. It includes the following files and folders. 6 | 7 | - app - Code for the application's Lambda function. 8 | - model - Code for downloading and saving resnet34 pre-trained model. 9 | - events - Invocation events that you can use to invoke the function. 10 | - template.yaml - A template that defines the application's AWS resources. 11 | 12 | The application uses several AWS resources, including Lambda functions. These resources are defined in the `template.yaml` file in this project. You can update the template to add AWS resources through the same deployment process that updates your application code. 13 | 14 | ## Deploy the sample application 15 | 16 | The Serverless Application Model Command Line Interface (SAM CLI) is an extension of the AWS CLI that adds functionality for building and testing Lambda applications. It uses Docker to run your functions in an Amazon Linux environment that matches Lambda. It can also emulate your application's build environment and API. 17 | 18 | To use the SAM CLI, you need the following tools. 19 | 20 | * SAM CLI - [Install the SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) 21 | * Docker - [Install Docker community edition](https://hub.docker.com/search/?type=edition&offering=community) 22 | 23 | You may need the following for local testing. 24 | * [Python 3 installed](https://www.python.org/downloads/) 25 | 26 | To build and deploy your application for the first time, run the following in your shell: 27 | 28 | ```bash 29 | sam build 30 | sam deploy --guided 31 | ``` 32 | 33 | The first command will build a docker image from a Dockerfile and then copy the source of your application inside the Docker image. The second command will package and deploy your application to AWS, with a series of prompts: 34 | 35 | * **Stack Name**: The name of the stack to deploy to CloudFormation. This should be unique to your account and region, and a good starting point would be something matching your project name. 36 | * **AWS Region**: The AWS region you want to deploy your app to. 37 | * **Confirm changes before deploy**: If set to yes, any change sets will be shown to you before execution for manual review. If set to no, the AWS SAM CLI will automatically deploy application changes. 38 | * **Allow SAM CLI IAM role creation**: Many AWS SAM templates, including this example, create AWS IAM roles required for the AWS Lambda function(s) included to access AWS services. By default, these are scoped down to minimum required permissions. To deploy an AWS CloudFormation stack which creates or modified IAM roles, the `CAPABILITY_IAM` value for `capabilities` must be provided. If permission isn't provided through this prompt, to deploy this example you must explicitly pass `--capabilities CAPABILITY_IAM` to the `sam deploy` command. 39 | * **Save arguments to samconfig.toml**: If set to yes, your choices will be saved to a configuration file inside the project, so that in the future you can just re-run `sam deploy` without parameters to deploy changes to your application. 40 | 41 | ## Use the SAM CLI to build and test locally 42 | 43 | Build your application with the `sam build` command. 44 | 45 | ```bash 46 | pytorch-inference-docker-lambda$ sam build 47 | ``` 48 | 49 | The SAM CLI builds a docker image from a Dockerfile and then installs dependencies defined in `requirements.txt` inside the docker image. The processed template file is saved in the `.aws-sam/build` folder. 50 | 51 | Test a single function by invoking it directly with a test event. An event is a JSON document that represents the input that the function receives from the event source. Test events are included in the `events` folder in this project. 52 | 53 | Run functions locally and invoke them with the `sam local invoke` command. 54 | 55 | ```bash 56 | pytorch-inference-docker-lambda$ sam local invoke PyTorchInferenceFunction --event events/event.json 57 | ``` 58 | ## Testing your Lambda function in the Cloud 59 | 60 | 1. In the [Lambda Console](https://console.aws.amazon.com/lambda/), select Configure test events from the Test events dropdown. 61 | 2. For Event Name, enter InferenceTestEvent. 62 | 3. Copy the event JSON from [here](./events/event.json) and paste in the dialog box. 63 | 4. Choose _**Create**_. 64 | 65 | ![Configure test event](../img/pytorch_configure_test_event.png) 66 | 67 | After saving, you see InferenceTestEvent in the Test list. Now choose _**Test**_. 68 | 69 | You see the Lambda function inference result, log output, and duration: 70 | 71 | ![Lambda execution result](../img/pytorch_execution_result.png) 72 | 73 | ## Fetch, tail, and filter Lambda function logs 74 | 75 | To simplify troubleshooting, SAM CLI has a command called `sam logs`. `sam logs` lets you fetch logs generated by your deployed Lambda function from the command line. In addition to printing the logs on the terminal, this command has several nifty features to help you quickly find the bug. 76 | 77 | `NOTE`: This command works for all AWS Lambda functions; not just the ones you deploy using SAM. 78 | 79 | ```bash 80 | pytorch-inference-docker-lambda$ sam logs -n PyTorchInferenceFunction --stack-name pytorch-inference-docker-lambda --tail 81 | ``` 82 | 83 | You can find more information and examples about filtering Lambda function logs in the [SAM CLI Documentation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-logging.html). 84 | 85 | 86 | ## Cleanup 87 | 88 | To delete the sample application that you created, use the AWS CLI. Assuming you used your project name for the stack name, you can run the following: 89 | 90 | ```bash 91 | aws cloudformation delete-stack --stack-name pytorch-inference-docker-lambda 92 | ``` 93 | 94 | ## Resources 95 | 96 | See the [AWS SAM developer guide](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html) for an introduction to SAM specification, the SAM CLI, and serverless application concepts. 97 | -------------------------------------------------------------------------------- /pytorch-inference-docker-lambda/app/app.py: -------------------------------------------------------------------------------- 1 | import urllib 2 | import json 3 | import os 4 | 5 | import torch 6 | from PIL import Image 7 | from torchvision import transforms 8 | 9 | 10 | transform_test = transforms.Compose([ 11 | transforms.Resize(256), 12 | transforms.CenterCrop(224), 13 | transforms.ToTensor(), 14 | transforms.Normalize([0.485, 0.456, 0.406], 15 | [0.229, 0.224, 0.225]) 16 | ]) 17 | 18 | 19 | def handler(event, context): 20 | print('Received event: ' + json.dumps(event, indent=2)) 21 | url = event['url'] 22 | 23 | img = Image.open(urllib.request.urlopen(url)) 24 | scaled_img = transform_test(img) 25 | torch_image = scaled_img.unsqueeze(0) 26 | 27 | model = torch.jit.load('./resnet34.pt') 28 | predicted_class = model(torch_image).argmax().item() 29 | print('predicted_class: {}'.format(predicted_class)) 30 | 31 | # Read the categories 32 | with open("imagenet_classes.txt", "r") as f: 33 | categories = [s.strip() for s in f.readlines()] 34 | 35 | print('Categories count: {}'.format(len(categories))) 36 | 37 | return json.dumps({ 38 | "class": categories[predicted_class] 39 | }) 40 | -------------------------------------------------------------------------------- /pytorch-inference-docker-lambda/events/event.json: -------------------------------------------------------------------------------- 1 | {"url":"https://github.com/pytorch/hub/raw/master/images/dog.jpg"} -------------------------------------------------------------------------------- /pytorch-inference-docker-lambda/model/resnet.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from torchvision.models import resnet 3 | 4 | model = resnet.resnet34(pretrained=True) 5 | model.eval() 6 | 7 | traced_model = torch.jit.trace(model, torch.randn(1,3,224,224)) 8 | traced_model.save('./resnet34.pt') -------------------------------------------------------------------------------- /pytorch-inference-docker-lambda/requirements.txt: -------------------------------------------------------------------------------- 1 | --find-links https://download.pytorch.org/whl/torch_stable.html 2 | 3 | torch==1.7.1+cpu 4 | torchvision==0.8.2+cpu -------------------------------------------------------------------------------- /pytorch-inference-docker-lambda/template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | Description: > 4 | pytorch-inference-docker-lambda 5 | 6 | SAM Template for pytorch-inference-docker-lambda 7 | 8 | Resources: 9 | PyTorchInferenceFunction: 10 | Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction 11 | Properties: 12 | PackageType: Image 13 | MemorySize: 768 14 | Timeout: 120 15 | Metadata: 16 | DockerTag: python3.7-v1 17 | DockerContext: . 18 | Dockerfile: Dockerfile 19 | 20 | Outputs: 21 | PyTorchInferenceFunction: 22 | Description: "PyTorchInference Lambda Function ARN" 23 | Value: !GetAtt PyTorchInferenceFunction.Arn 24 | PyTorchInferenceFunctionIamRole: 25 | Description: "Implicit IAM Role created for PyTorchInference function" 26 | Value: !GetAtt PyTorchInferenceFunction.Arn 27 | -------------------------------------------------------------------------------- /scikit-learn-inference-docker-lambda/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/osx,linux,python,windows,pycharm,visualstudiocode 3 | 4 | ### Linux ### 5 | *~ 6 | 7 | # temporary files which can be created if a process still has a handle open of a deleted file 8 | .fuse_hidden* 9 | 10 | # KDE directory preferences 11 | .directory 12 | 13 | # Linux trash folder which might appear on any partition or disk 14 | .Trash-* 15 | 16 | # .nfs files are created when an open file is removed but is still being accessed 17 | .nfs* 18 | 19 | ### OSX ### 20 | *.DS_Store 21 | .AppleDouble 22 | .LSOverride 23 | 24 | # Icon must end with two \r 25 | Icon 26 | 27 | # Thumbnails 28 | ._* 29 | 30 | # Files that might appear in the root of a volume 31 | .DocumentRevisions-V100 32 | .fseventsd 33 | .Spotlight-V100 34 | .TemporaryItems 35 | .Trashes 36 | .VolumeIcon.icns 37 | .com.apple.timemachine.donotpresent 38 | 39 | # Directories potentially created on remote AFP share 40 | .AppleDB 41 | .AppleDesktop 42 | Network Trash Folder 43 | Temporary Items 44 | .apdisk 45 | 46 | ### PyCharm ### 47 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 48 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 49 | 50 | # User-specific stuff: 51 | .idea/**/workspace.xml 52 | .idea/**/tasks.xml 53 | .idea/dictionaries 54 | 55 | # Sensitive or high-churn files: 56 | .idea/**/dataSources/ 57 | .idea/**/dataSources.ids 58 | .idea/**/dataSources.xml 59 | .idea/**/dataSources.local.xml 60 | .idea/**/sqlDataSources.xml 61 | .idea/**/dynamic.xml 62 | .idea/**/uiDesigner.xml 63 | 64 | # Gradle: 65 | .idea/**/gradle.xml 66 | .idea/**/libraries 67 | 68 | # CMake 69 | cmake-build-debug/ 70 | 71 | # Mongo Explorer plugin: 72 | .idea/**/mongoSettings.xml 73 | 74 | ## File-based project format: 75 | *.iws 76 | 77 | ## Plugin-specific files: 78 | 79 | # IntelliJ 80 | /out/ 81 | 82 | # mpeltonen/sbt-idea plugin 83 | .idea_modules/ 84 | 85 | # JIRA plugin 86 | atlassian-ide-plugin.xml 87 | 88 | # Cursive Clojure plugin 89 | .idea/replstate.xml 90 | 91 | # Ruby plugin and RubyMine 92 | /.rakeTasks 93 | 94 | # Crashlytics plugin (for Android Studio and IntelliJ) 95 | com_crashlytics_export_strings.xml 96 | crashlytics.properties 97 | crashlytics-build.properties 98 | fabric.properties 99 | 100 | ### PyCharm Patch ### 101 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 102 | 103 | # *.iml 104 | # modules.xml 105 | # .idea/misc.xml 106 | # *.ipr 107 | 108 | # Sonarlint plugin 109 | .idea/sonarlint 110 | 111 | ### Python ### 112 | # Byte-compiled / optimized / DLL files 113 | __pycache__/ 114 | *.py[cod] 115 | *$py.class 116 | 117 | # C extensions 118 | *.so 119 | 120 | # Distribution / packaging 121 | .Python 122 | build/ 123 | develop-eggs/ 124 | dist/ 125 | downloads/ 126 | eggs/ 127 | .eggs/ 128 | lib/ 129 | lib64/ 130 | parts/ 131 | sdist/ 132 | var/ 133 | wheels/ 134 | *.egg-info/ 135 | .installed.cfg 136 | *.egg 137 | 138 | # PyInstaller 139 | # Usually these files are written by a python script from a template 140 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 141 | *.manifest 142 | *.spec 143 | 144 | # Installer logs 145 | pip-log.txt 146 | pip-delete-this-directory.txt 147 | 148 | # Unit test / coverage reports 149 | htmlcov/ 150 | .tox/ 151 | .coverage 152 | .coverage.* 153 | .cache 154 | .pytest_cache/ 155 | nosetests.xml 156 | coverage.xml 157 | *.cover 158 | .hypothesis/ 159 | 160 | # Translations 161 | *.mo 162 | *.pot 163 | 164 | # Flask stuff: 165 | instance/ 166 | .webassets-cache 167 | 168 | # Scrapy stuff: 169 | .scrapy 170 | 171 | # Sphinx documentation 172 | docs/_build/ 173 | 174 | # PyBuilder 175 | target/ 176 | 177 | # Jupyter Notebook 178 | .ipynb_checkpoints 179 | 180 | # pyenv 181 | .python-version 182 | 183 | # celery beat schedule file 184 | celerybeat-schedule.* 185 | 186 | # SageMath parsed files 187 | *.sage.py 188 | 189 | # Environments 190 | .env 191 | .venv 192 | env/ 193 | venv/ 194 | ENV/ 195 | env.bak/ 196 | venv.bak/ 197 | 198 | # Spyder project settings 199 | .spyderproject 200 | .spyproject 201 | 202 | # Rope project settings 203 | .ropeproject 204 | 205 | # mkdocs documentation 206 | /site 207 | 208 | # mypy 209 | .mypy_cache/ 210 | 211 | ### VisualStudioCode ### 212 | .vscode/* 213 | !.vscode/settings.json 214 | !.vscode/tasks.json 215 | !.vscode/launch.json 216 | !.vscode/extensions.json 217 | .history 218 | 219 | ### Windows ### 220 | # Windows thumbnail cache files 221 | Thumbs.db 222 | ehthumbs.db 223 | ehthumbs_vista.db 224 | 225 | # Folder config file 226 | Desktop.ini 227 | 228 | # Recycle Bin used on file shares 229 | $RECYCLE.BIN/ 230 | 231 | # Windows Installer files 232 | *.cab 233 | *.msi 234 | *.msm 235 | *.msp 236 | 237 | # Windows shortcuts 238 | *.lnk 239 | 240 | # Build folder 241 | 242 | */build/* 243 | 244 | # End of https://www.gitignore.io/api/osx,linux,python,windows,pycharm,visualstudiocode -------------------------------------------------------------------------------- /scikit-learn-inference-docker-lambda/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/lambda/python:3.7 2 | 3 | COPY requirements.txt ./ 4 | RUN python3.7 -m pip install -r requirements.txt -t . 5 | 6 | COPY ./train-code/scikit_learn_iris.py ./ 7 | RUN python scikit_learn_iris.py 8 | 9 | COPY ./app/app.py ./ 10 | 11 | CMD ["app.handler"] -------------------------------------------------------------------------------- /scikit-learn-inference-docker-lambda/README.md: -------------------------------------------------------------------------------- 1 | ## Serverless scikit-learn Model Serving 2 | 3 | This examples illustrates how to serve scikit-learn model on Lambda Function to predict based on iris dataset. 4 | 5 | This project contains source code and supporting files for a serverless application that you can deploy with the SAM CLI. It includes the following files and folders. 6 | 7 | - app - Code for the application's Lambda function. 8 | - train-code - Code for training scikit-learn model based on iris dataset. 9 | - events - Invocation events that you can use to invoke the function. 10 | - template.yaml - A template that defines the application's AWS resources. 11 | 12 | The application uses several AWS resources, including Lambda functions. These resources are defined in the `template.yaml` file in this project. You can update the template to add AWS resources through the same deployment process that updates your application code. 13 | 14 | ## Deploy the sample application 15 | 16 | The Serverless Application Model Command Line Interface (SAM CLI) is an extension of the AWS CLI that adds functionality for building and testing Lambda applications. It uses Docker to run your functions in an Amazon Linux environment that matches Lambda. It can also emulate your application's build environment and API. 17 | 18 | To use the SAM CLI, you need the following tools. 19 | 20 | * SAM CLI - [Install the SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) 21 | * Docker - [Install Docker community edition](https://hub.docker.com/search/?type=edition&offering=community) 22 | 23 | You may need the following for local testing. 24 | * [Python 3 installed](https://www.python.org/downloads/) 25 | 26 | To build and deploy your application for the first time, run the following in your shell: 27 | 28 | ```bash 29 | sam build 30 | sam deploy --guided 31 | ``` 32 | 33 | The first command will build a docker image from a Dockerfile and then copy the source of your application inside the Docker image. The second command will package and deploy your application to AWS, with a series of prompts: 34 | 35 | * **Stack Name**: The name of the stack to deploy to CloudFormation. This should be unique to your account and region, and a good starting point would be something matching your project name. 36 | * **AWS Region**: The AWS region you want to deploy your app to. 37 | * **Confirm changes before deploy**: If set to yes, any change sets will be shown to you before execution for manual review. If set to no, the AWS SAM CLI will automatically deploy application changes. 38 | * **Allow SAM CLI IAM role creation**: Many AWS SAM templates, including this example, create AWS IAM roles required for the AWS Lambda function(s) included to access AWS services. By default, these are scoped down to minimum required permissions. To deploy an AWS CloudFormation stack which creates or modified IAM roles, the `CAPABILITY_IAM` value for `capabilities` must be provided. If permission isn't provided through this prompt, to deploy this example you must explicitly pass `--capabilities CAPABILITY_IAM` to the `sam deploy` command. 39 | * **Save arguments to samconfig.toml**: If set to yes, your choices will be saved to a configuration file inside the project, so that in the future you can just re-run `sam deploy` without parameters to deploy changes to your application. 40 | 41 | ## Use the SAM CLI to build and test locally 42 | 43 | Build your application with the `sam build` command. 44 | 45 | ```bash 46 | scikit-learn-inference-docker-lambda$ sam build 47 | ``` 48 | 49 | The SAM CLI builds a docker image from a Dockerfile and then installs dependencies defined in `requirements.txt` inside the docker image. The processed template file is saved in the `.aws-sam/build` folder. 50 | 51 | Test a single function by invoking it directly with a test event. An event is a JSON document that represents the input that the function receives from the event source. Test events are included in the `events` folder in this project. 52 | 53 | Run functions locally and invoke them with the `sam local invoke` command. 54 | 55 | ```bash 56 | scikit-learn-inference-docker-lambda$ sam local invoke ScikitLearnInferenceFunction --event events/event.json 57 | ``` 58 | 59 | ## Testing your Lambda function in the Cloud 60 | 61 | 1. In the [Lambda Console](https://console.aws.amazon.com/lambda/), select Configure test events from the Test events dropdown. 62 | 2. For Event Name, enter InferenceTestEvent. 63 | 3. Copy the event JSON from [here](./events/event.json) and paste in the dialog box. 64 | 4. Choose _**Create**_. 65 | 66 | ![Configure test event](../img/scikit-learn_configure_test_event.png) 67 | 68 | After saving, you see InferenceTestEvent in the Test list. Now choose _**Test**_. 69 | 70 | You see the Lambda function inference result, log output, and duration: 71 | 72 | ![Lambda execution result](../img/scikit-learn_execution_result.png) 73 | 74 | ## Fetch, tail, and filter Lambda function logs 75 | 76 | To simplify troubleshooting, SAM CLI has a command called `sam logs`. `sam logs` lets you fetch logs generated by your deployed Lambda function from the command line. In addition to printing the logs on the terminal, this command has several nifty features to help you quickly find the bug. 77 | 78 | `NOTE`: This command works for all AWS Lambda functions; not just the ones you deploy using SAM. 79 | 80 | ```bash 81 | scikit-learn-inference-docker-lambda$ sam logs -n ScikitLearnInferenceFunction --stack-name scikit-learn-inference-docker-lambda --tail 82 | ``` 83 | 84 | You can find more information and examples about filtering Lambda function logs in the [SAM CLI Documentation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-logging.html). 85 | 86 | ## Cleanup 87 | 88 | To delete the sample application that you created, use the AWS CLI. Assuming you used your project name for the stack name, you can run the following: 89 | 90 | ```bash 91 | aws cloudformation delete-stack --stack-name scikit-learn-inference-docker-lambda 92 | ``` 93 | 94 | ## Resources 95 | 96 | See the [AWS SAM developer guide](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html) for an introduction to SAM specification, the SAM CLI, and serverless application concepts. 97 | 98 | -------------------------------------------------------------------------------- /scikit-learn-inference-docker-lambda/app/app.py: -------------------------------------------------------------------------------- 1 | import joblib 2 | import json 3 | from sklearn.datasets import load_iris 4 | 5 | loaded_model = joblib.load('./iris_classifier_knn.joblib') 6 | iris = load_iris() 7 | 8 | def handler(event, context): 9 | print('Received event: ' + json.dumps(event, indent=2)) 10 | 11 | predictions = loaded_model.predict(event["data"]) 12 | predictions_species = [iris.target_names[p] for p in predictions] 13 | 14 | print("Returning: {}".format(predictions_species)) 15 | return(json.dumps({"predictions": predictions_species})) 16 | 17 | 18 | -------------------------------------------------------------------------------- /scikit-learn-inference-docker-lambda/events/event.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [[5, 5, 3, 2], [2, 4, 3, 5]] 3 | } -------------------------------------------------------------------------------- /scikit-learn-inference-docker-lambda/requirements.txt: -------------------------------------------------------------------------------- 1 | joblib 2 | scikit-learn -------------------------------------------------------------------------------- /scikit-learn-inference-docker-lambda/template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | Description: > 4 | scikit-learn-inference-docker-lambda 5 | 6 | SAM Template for scikit-learn-inference-docker-lambda 7 | 8 | Resources: 9 | ScikitLearnInferenceFunction: 10 | Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction 11 | Properties: 12 | PackageType: Image 13 | MemorySize: 256 14 | Timeout: 60 15 | Metadata: 16 | DockerTag: python3.7-v1 17 | DockerContext: . 18 | Dockerfile: Dockerfile 19 | 20 | Outputs: 21 | ScikitLearnInferenceFunction: 22 | Description: "ScikitLearnInference Lambda Function ARN" 23 | Value: !GetAtt ScikitLearnInferenceFunction.Arn 24 | ScikitLearnInferenceFunctionIamRole: 25 | Description: "Implicit IAM Role created for ScikitLearnInference function" 26 | Value: !GetAtt ScikitLearnInferenceFunction.Arn 27 | -------------------------------------------------------------------------------- /scikit-learn-inference-docker-lambda/train-code/scikit_learn_iris.py: -------------------------------------------------------------------------------- 1 | from sklearn.datasets import load_iris 2 | from sklearn.model_selection import train_test_split 3 | from sklearn.neighbors import KNeighborsClassifier 4 | from sklearn import metrics 5 | import joblib 6 | 7 | iris = load_iris() 8 | X = iris.data 9 | y = iris.target 10 | 11 | X_train, X_test, y_train, y_test = train_test_split( 12 | X, y, test_size = 0.4, random_state=1 13 | ) 14 | 15 | classifier_knn = KNeighborsClassifier(n_neighbors = 3) 16 | classifier_knn.fit(X_train, y_train) 17 | y_pred = classifier_knn.predict(X_test) 18 | 19 | # Finding accuracy by comparing actual response values(y_test)with predicted response value(y_pred) 20 | print("Model Accuracy:", metrics.accuracy_score(y_test, y_pred)) 21 | # Providing sample data and the model will make prediction out of that data 22 | 23 | # save the trained model file 24 | model_file_name = "iris_classifier_knn.joblib" 25 | joblib.dump(classifier_knn, model_file_name) 26 | print("Model file {} saved successfully".format(model_file_name)) 27 | -------------------------------------------------------------------------------- /tensorflow-inference-docker-lambda/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/osx,linux,python,windows,pycharm,visualstudiocode 3 | 4 | ### Linux ### 5 | *~ 6 | 7 | # temporary files which can be created if a process still has a handle open of a deleted file 8 | .fuse_hidden* 9 | 10 | # KDE directory preferences 11 | .directory 12 | 13 | # Linux trash folder which might appear on any partition or disk 14 | .Trash-* 15 | 16 | # .nfs files are created when an open file is removed but is still being accessed 17 | .nfs* 18 | 19 | ### OSX ### 20 | *.DS_Store 21 | .AppleDouble 22 | .LSOverride 23 | 24 | # Icon must end with two \r 25 | Icon 26 | 27 | # Thumbnails 28 | ._* 29 | 30 | # Files that might appear in the root of a volume 31 | .DocumentRevisions-V100 32 | .fseventsd 33 | .Spotlight-V100 34 | .TemporaryItems 35 | .Trashes 36 | .VolumeIcon.icns 37 | .com.apple.timemachine.donotpresent 38 | 39 | # Directories potentially created on remote AFP share 40 | .AppleDB 41 | .AppleDesktop 42 | Network Trash Folder 43 | Temporary Items 44 | .apdisk 45 | 46 | ### PyCharm ### 47 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 48 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 49 | 50 | # User-specific stuff: 51 | .idea/**/workspace.xml 52 | .idea/**/tasks.xml 53 | .idea/dictionaries 54 | 55 | # Sensitive or high-churn files: 56 | .idea/**/dataSources/ 57 | .idea/**/dataSources.ids 58 | .idea/**/dataSources.xml 59 | .idea/**/dataSources.local.xml 60 | .idea/**/sqlDataSources.xml 61 | .idea/**/dynamic.xml 62 | .idea/**/uiDesigner.xml 63 | 64 | # Gradle: 65 | .idea/**/gradle.xml 66 | .idea/**/libraries 67 | 68 | # CMake 69 | cmake-build-debug/ 70 | 71 | # Mongo Explorer plugin: 72 | .idea/**/mongoSettings.xml 73 | 74 | ## File-based project format: 75 | *.iws 76 | 77 | ## Plugin-specific files: 78 | 79 | # IntelliJ 80 | /out/ 81 | 82 | # mpeltonen/sbt-idea plugin 83 | .idea_modules/ 84 | 85 | # JIRA plugin 86 | atlassian-ide-plugin.xml 87 | 88 | # Cursive Clojure plugin 89 | .idea/replstate.xml 90 | 91 | # Ruby plugin and RubyMine 92 | /.rakeTasks 93 | 94 | # Crashlytics plugin (for Android Studio and IntelliJ) 95 | com_crashlytics_export_strings.xml 96 | crashlytics.properties 97 | crashlytics-build.properties 98 | fabric.properties 99 | 100 | ### PyCharm Patch ### 101 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 102 | 103 | # *.iml 104 | # modules.xml 105 | # .idea/misc.xml 106 | # *.ipr 107 | 108 | # Sonarlint plugin 109 | .idea/sonarlint 110 | 111 | ### Python ### 112 | # Byte-compiled / optimized / DLL files 113 | __pycache__/ 114 | *.py[cod] 115 | *$py.class 116 | 117 | # C extensions 118 | *.so 119 | 120 | # Distribution / packaging 121 | .Python 122 | build/ 123 | develop-eggs/ 124 | dist/ 125 | downloads/ 126 | eggs/ 127 | .eggs/ 128 | lib/ 129 | lib64/ 130 | parts/ 131 | sdist/ 132 | var/ 133 | wheels/ 134 | *.egg-info/ 135 | .installed.cfg 136 | *.egg 137 | 138 | # PyInstaller 139 | # Usually these files are written by a python script from a template 140 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 141 | *.manifest 142 | *.spec 143 | 144 | # Installer logs 145 | pip-log.txt 146 | pip-delete-this-directory.txt 147 | 148 | # Unit test / coverage reports 149 | htmlcov/ 150 | .tox/ 151 | .coverage 152 | .coverage.* 153 | .cache 154 | .pytest_cache/ 155 | nosetests.xml 156 | coverage.xml 157 | *.cover 158 | .hypothesis/ 159 | 160 | # Translations 161 | *.mo 162 | *.pot 163 | 164 | # Flask stuff: 165 | instance/ 166 | .webassets-cache 167 | 168 | # Scrapy stuff: 169 | .scrapy 170 | 171 | # Sphinx documentation 172 | docs/_build/ 173 | 174 | # PyBuilder 175 | target/ 176 | 177 | # Jupyter Notebook 178 | .ipynb_checkpoints 179 | 180 | # pyenv 181 | .python-version 182 | 183 | # celery beat schedule file 184 | celerybeat-schedule.* 185 | 186 | # SageMath parsed files 187 | *.sage.py 188 | 189 | # Environments 190 | .env 191 | .venv 192 | env/ 193 | venv/ 194 | ENV/ 195 | env.bak/ 196 | venv.bak/ 197 | 198 | # Spyder project settings 199 | .spyderproject 200 | .spyproject 201 | 202 | # Rope project settings 203 | .ropeproject 204 | 205 | # mkdocs documentation 206 | /site 207 | 208 | # mypy 209 | .mypy_cache/ 210 | 211 | ### VisualStudioCode ### 212 | .vscode/* 213 | !.vscode/settings.json 214 | !.vscode/tasks.json 215 | !.vscode/launch.json 216 | !.vscode/extensions.json 217 | .history 218 | 219 | ### Windows ### 220 | # Windows thumbnail cache files 221 | Thumbs.db 222 | ehthumbs.db 223 | ehthumbs_vista.db 224 | 225 | # Folder config file 226 | Desktop.ini 227 | 228 | # Recycle Bin used on file shares 229 | $RECYCLE.BIN/ 230 | 231 | # Windows Installer files 232 | *.cab 233 | *.msi 234 | *.msm 235 | *.msp 236 | 237 | # Windows shortcuts 238 | *.lnk 239 | 240 | # Build folder 241 | 242 | */build/* 243 | 244 | # End of https://www.gitignore.io/api/osx,linux,python,windows,pycharm,visualstudiocode -------------------------------------------------------------------------------- /tensorflow-inference-docker-lambda/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/lambda/python:3.8 2 | 3 | COPY requirements.txt ./requirements.txt 4 | RUN pip install -r requirements.txt 5 | 6 | RUN yum -y install tar gzip 7 | RUN mkdir ./model 8 | RUN curl https://storage.googleapis.com/tfhub-modules/google/openimages_v4/ssd/mobilenet_v2/1.tar.gz --output /tmp/1.tar.gz 9 | RUN tar zxf /tmp/1.tar.gz -C ./model 10 | RUN chmod 774 ./model/* 11 | 12 | COPY ./app/app.py ./ 13 | 14 | CMD ["app.handler"] 15 | -------------------------------------------------------------------------------- /tensorflow-inference-docker-lambda/README.md: -------------------------------------------------------------------------------- 1 | ## Serverless TensorFlow Model Serving 2 | 3 | This examples illustrates how to serve TensorFlow model on Lambda Function for Object Detection. 4 | 5 | This project contains source code and supporting files for a serverless application that you can deploy with the SAM CLI. It includes the following files and folders. 6 | 7 | - app - Code for the application's Lambda function. 8 | - events - Invocation events that you can use to invoke the function. 9 | - template.yaml - A template that defines the application's AWS resources. 10 | 11 | The application uses several AWS resources, including Lambda functions. These resources are defined in the `template.yaml` file in this project. You can update the template to add AWS resources through the same deployment process that updates your application code. 12 | 13 | ## Deploy the sample application 14 | 15 | The Serverless Application Model Command Line Interface (SAM CLI) is an extension of the AWS CLI that adds functionality for building and testing Lambda applications. It uses Docker to run your functions in an Amazon Linux environment that matches Lambda. It can also emulate your application's build environment and API. 16 | 17 | To use the SAM CLI, you need the following tools. 18 | 19 | * SAM CLI - [Install the SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) 20 | * Docker - [Install Docker community edition](https://hub.docker.com/search/?type=edition&offering=community) 21 | 22 | You may need the following for local testing. 23 | * [Python 3 installed](https://www.python.org/downloads/) 24 | 25 | To build and deploy your application for the first time, run the following in your shell: 26 | 27 | ```bash 28 | sam build 29 | sam deploy --guided 30 | ``` 31 | 32 | The first command will build a docker image from a Dockerfile and then copy the source of your application inside the Docker image. The second command will package and deploy your application to AWS, with a series of prompts: 33 | 34 | * **Stack Name**: The name of the stack to deploy to CloudFormation. This should be unique to your account and region, and a good starting point would be something matching your project name. 35 | * **AWS Region**: The AWS region you want to deploy your app to. 36 | * **Confirm changes before deploy**: If set to yes, any change sets will be shown to you before execution for manual review. If set to no, the AWS SAM CLI will automatically deploy application changes. 37 | * **Allow SAM CLI IAM role creation**: Many AWS SAM templates, including this example, create AWS IAM roles required for the AWS Lambda function(s) included to access AWS services. By default, these are scoped down to minimum required permissions. To deploy an AWS CloudFormation stack which creates or modified IAM roles, the `CAPABILITY_IAM` value for `capabilities` must be provided. If permission isn't provided through this prompt, to deploy this example you must explicitly pass `--capabilities CAPABILITY_IAM` to the `sam deploy` command. 38 | * **Save arguments to samconfig.toml**: If set to yes, your choices will be saved to a configuration file inside the project, so that in the future you can just re-run `sam deploy` without parameters to deploy changes to your application. 39 | 40 | ## Use the SAM CLI to build and test locally 41 | 42 | Build your application with the `sam build` command. 43 | 44 | ```bash 45 | tensorflow-inference-docker-lambda$ sam build 46 | ``` 47 | 48 | The SAM CLI builds a docker image from a Dockerfile and then installs dependencies defined in `requirements.txt` inside the docker image. The processed template file is saved in the `.aws-sam/build` folder. 49 | 50 | Test a single function by invoking it directly with a test event. An event is a JSON document that represents the input that the function receives from the event source. Test events are included in the `events` folder in this project. 51 | 52 | Run functions locally and invoke them with the `sam local invoke` command. 53 | 54 | ```bash 55 | tensorflow-inference-docker-lambda$ sam local invoke TensorFlowInferenceFunction --event events/event.json 56 | ``` 57 | 58 | ## Testing your Lambda function in the Cloud 59 | 60 | 1. In the [Lambda Console](https://console.aws.amazon.com/lambda/), select Configure test events from the Test events dropdown. 61 | 2. For Event Name, enter InferenceTestEvent. 62 | 3. Copy the event JSON from [here](./events/event.json) and paste in the dialog box. 63 | 4. Choose _**Create**_. 64 | 65 | ![Configure test event](../img/tensorflow_configure_test_event.png) 66 | 67 | After saving, you see InferenceTestEvent in the Test list. Now choose _**Test**_. 68 | 69 | You see the Lambda function inference result, log output, and duration: 70 | 71 | ![Lambda execution result](../img/tensorflow_execution_result.png) 72 | 73 | ## Fetch, tail, and filter Lambda function logs 74 | 75 | To simplify troubleshooting, SAM CLI has a command called `sam logs`. `sam logs` lets you fetch logs generated by your deployed Lambda function from the command line. In addition to printing the logs on the terminal, this command has several nifty features to help you quickly find the bug. 76 | 77 | `NOTE`: This command works for all AWS Lambda functions; not just the ones you deploy using SAM. 78 | 79 | ```bash 80 | tensorflow-inference-docker-lambda$ sam logs -n TensorFlowInferenceFunction --stack-name tensorflow-inference-docker-lambda --tail 81 | ``` 82 | 83 | You can find more information and examples about filtering Lambda function logs in the [SAM CLI Documentation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-logging.html). 84 | 85 | 86 | ## Cleanup 87 | 88 | To delete the sample application that you created, use the AWS CLI. Assuming you used your project name for the stack name, you can run the following: 89 | 90 | ```bash 91 | aws cloudformation delete-stack --stack-name tensorflow-inference-docker-lambda 92 | ``` 93 | 94 | ## Resources 95 | 96 | See the [AWS SAM developer guide](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html) for an introduction to SAM specification, the SAM CLI, and serverless application concepts. 97 | 98 | -------------------------------------------------------------------------------- /tensorflow-inference-docker-lambda/app/app.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import json 4 | import string 5 | import time 6 | import io 7 | import requests 8 | 9 | # Importing TensorFlow 10 | import tensorflow as tf 11 | 12 | # Loading model 13 | model_path = './model/' 14 | loaded_model = tf.saved_model.load(model_path) 15 | detector = loaded_model.signatures['default'] 16 | 17 | def handler(event, context): 18 | r = requests.get(event['url']) 19 | img = tf.image.decode_jpeg(r.content, channels=3) 20 | 21 | # Executing inference. 22 | converted_img = tf.image.convert_image_dtype(img, tf.float32)[tf.newaxis, ...] 23 | start_time = time.time() 24 | result = detector(converted_img) 25 | end_time = time.time() 26 | 27 | obj = { 28 | 'detection_boxes' : result['detection_boxes'].numpy().tolist(), 29 | 'detection_scores': result['detection_scores'].numpy().tolist(), 30 | 'detection_class_entities': [el.decode('UTF-8') for el in result['detection_class_entities'].numpy()] 31 | } 32 | 33 | return { 34 | 'statusCode': 200, 35 | 'body': json.dumps(obj) 36 | } -------------------------------------------------------------------------------- /tensorflow-inference-docker-lambda/events/event.json: -------------------------------------------------------------------------------- 1 | {"url":"https://images.pexels.com/photos/310983/pexels-photo-310983.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940"} -------------------------------------------------------------------------------- /tensorflow-inference-docker-lambda/requirements.txt: -------------------------------------------------------------------------------- 1 | tensorflow -------------------------------------------------------------------------------- /tensorflow-inference-docker-lambda/template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | Description: > 4 | tensorflow-inference-docker-lambda 5 | 6 | SAM Template for tensorflow-inference-docker-lambda 7 | 8 | Resources: 9 | TensorFlowInferenceFunction: 10 | Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction 11 | Properties: 12 | PackageType: Image 13 | MemorySize: 1536 14 | Timeout: 120 15 | Metadata: 16 | DockerTag: python3.7-v1 17 | DockerContext: . 18 | Dockerfile: Dockerfile 19 | 20 | Outputs: 21 | TensorFlowInferenceFunction: 22 | Description: "TensorFlowInference Lambda Function ARN" 23 | Value: !GetAtt TensorFlowInferenceFunction.Arn 24 | TensorFlowInferenceFunctionIamRole: 25 | Description: "Implicit IAM Role created for TensorFlowInference function" 26 | Value: !GetAtt TensorFlowInferenceFunction.Arn 27 | -------------------------------------------------------------------------------- /tensorflow-train-in-sagemaker-deploy-with-lambda/README.md: -------------------------------------------------------------------------------- 1 | ## Train a TensorFlow algorithm in SageMaker, inference with AWS Lambda 2 | 3 | This example illustrates how to use a TensorFlow Python script to train a classification model on the MNIST dataset. You train the model using SageMaker and inference with AWS Lambda. 4 | 5 | This project contains source code and supporting files for a serverless application that you can deploy with the notebook. It includes the following files and folders. 6 | 7 | - tensorflow_script_mode_training_in_sagemaker_and_serving_with_lambda.ipynb - Notebook to run training with SageMaker, and deploy the Lambda function. 8 | - container - The container directory has all the components you need to package the sample Lambda function. 9 | - events - Invocation events that you can use to invoke the function. 10 | 11 | ## Train a TensorFlow classification model on the MNIST dataset 12 | You'll be running the [TensorFlow script mode training with SageMaker, and serving with AWS Lambda](./tensorflow_script_mode_training_in_sagemaker_and_serving_with_lambda.ipynb) notebook to train a TensorFlow classification model on the MNIST dataset. 13 | 14 | You can run this notebook in [SageMaker Notebook instance](https://docs.aws.amazon.com/sagemaker/latest/dg/nbi.html) 15 | 16 | This notebooks is identical to the original [TensorFlow script mode training and serving](https://github.com/aws/amazon-sagemaker-examples/blob/master/sagemaker-python-sdk/tensorflow_script_mode_training_and_serving/tensorflow_script_mode_training_and_serving.ipynb) notebook, except the fact that you'll deploy the model in Lambda function. 17 | 18 | ## Testing your Lambda function in the Cloud 19 | 20 | 1. In the [Lambda Console](https://console.aws.amazon.com/lambda/), select Configure test events from the Test events dropdown. 21 | 2. For Event Name, enter InferenceTestEvent. 22 | 3. Copy the event JSON from [here](./events/event.json) and paste in the dialog box. 23 | 4. Choose _**Create**_. 24 | 25 | ![Configure test event](../img/tensorflow_mnist_sagemaker_configure_test_event.png) 26 | 27 | After saving, you see InferenceTestEvent in the Test list. Now choose _**Test**_. 28 | 29 | You see the Lambda function inference result, log output, and duration: 30 | 31 | ![Lambda execution result](../img/tensorflow_mnist_sagemaker_execution_result.png) 32 | -------------------------------------------------------------------------------- /tensorflow-train-in-sagemaker-deploy-with-lambda/container/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/lambda/python:3.7 2 | 3 | COPY requirements.txt ./requirements.txt 4 | RUN pip install -r requirements.txt 5 | 6 | COPY ./model/model.tar.gz . 7 | RUN tar -xzf model.tar.gz 8 | 9 | COPY ./app/app.py ./ 10 | 11 | CMD ["app.handler"] 12 | -------------------------------------------------------------------------------- /tensorflow-train-in-sagemaker-deploy-with-lambda/container/app/app.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | import boto3 4 | import numpy as np 5 | import tensorflow as tf 6 | 7 | s3 = boto3.client('s3') 8 | 9 | # Loading model 10 | model_path = './000000001/' 11 | loaded_model = tf.saved_model.load(model_path) 12 | infer = loaded_model.signatures['serving_default'] 13 | 14 | def handler(event, context): 15 | print('Received event: ' + json.dumps(event, indent=2)) 16 | 17 | destination = '/tmp/' + event["file"] 18 | s3.download_file(event["bucket"], event["prefix"] + event["file"], destination) 19 | data = np.load(destination) 20 | 21 | predictions = infer(tf.constant(data))['dense_1'] 22 | print('predictions: {}'.format(predictions)) 23 | 24 | result=[] 25 | for element in predictions: 26 | prediction = np.argmax(element) 27 | result.append(int(prediction)) 28 | 29 | print('Returning result: {}'.format(result)) 30 | 31 | return { 32 | 'statusCode': 200, 33 | 'body': json.dumps(result) 34 | } -------------------------------------------------------------------------------- /tensorflow-train-in-sagemaker-deploy-with-lambda/container/requirements.txt: -------------------------------------------------------------------------------- 1 | boto3 2 | tensorflow -------------------------------------------------------------------------------- /tensorflow-train-in-sagemaker-deploy-with-lambda/events/event.json: -------------------------------------------------------------------------------- 1 | { 2 | "bucket":"sagemaker-sample-data-us-east-1", 3 | "prefix":"tensorflow/mnist/", 4 | "file": "train_data.npy" 5 | } -------------------------------------------------------------------------------- /tensorflow-train-in-sagemaker-deploy-with-lambda/mnist-2.py: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"). You 4 | # may not use this file except in compliance with the License. A copy of 5 | # the License is located at 6 | # 7 | # http://aws.amazon.com/apache2.0/ 8 | # 9 | # or in the "license" file accompanying this file. This file is 10 | # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 11 | # ANY KIND, either express or implied. See the License for the specific 12 | # language governing permissions and limitations under the License.import tensorflow as tf 13 | 14 | import tensorflow as tf 15 | import argparse 16 | import os 17 | import numpy as np 18 | import json 19 | 20 | 21 | def model(x_train, y_train, x_test, y_test): 22 | """Generate a simple model""" 23 | model = tf.keras.models.Sequential([ 24 | tf.keras.layers.Flatten(), 25 | tf.keras.layers.Dense(1024, activation=tf.nn.relu), 26 | tf.keras.layers.Dropout(0.4), 27 | tf.keras.layers.Dense(10, activation=tf.nn.softmax) 28 | ]) 29 | 30 | model.compile(optimizer='adam', 31 | loss='sparse_categorical_crossentropy', 32 | metrics=['accuracy']) 33 | model.fit(x_train, y_train) 34 | model.evaluate(x_test, y_test) 35 | 36 | return model 37 | 38 | 39 | def _load_training_data(base_dir): 40 | """Load MNIST training data""" 41 | x_train = np.load(os.path.join(base_dir, 'train_data.npy')) 42 | y_train = np.load(os.path.join(base_dir, 'train_labels.npy')) 43 | return x_train, y_train 44 | 45 | 46 | def _load_testing_data(base_dir): 47 | """Load MNIST testing data""" 48 | x_test = np.load(os.path.join(base_dir, 'eval_data.npy')) 49 | y_test = np.load(os.path.join(base_dir, 'eval_labels.npy')) 50 | return x_test, y_test 51 | 52 | 53 | def _parse_args(): 54 | parser = argparse.ArgumentParser() 55 | 56 | # Data, model, and output directories 57 | # model_dir is always passed in from SageMaker. By default this is a S3 path under the default bucket. 58 | parser.add_argument('--model_dir', type=str) 59 | parser.add_argument('--sm-model-dir', type=str, default=os.environ.get('SM_MODEL_DIR')) 60 | parser.add_argument('--train', type=str, default=os.environ.get('SM_CHANNEL_TRAINING')) 61 | parser.add_argument('--hosts', type=list, default=json.loads(os.environ.get('SM_HOSTS'))) 62 | parser.add_argument('--current-host', type=str, default=os.environ.get('SM_CURRENT_HOST')) 63 | 64 | return parser.parse_known_args() 65 | 66 | 67 | if __name__ == "__main__": 68 | args, unknown = _parse_args() 69 | 70 | train_data, train_labels = _load_training_data(args.train) 71 | eval_data, eval_labels = _load_testing_data(args.train) 72 | 73 | mnist_classifier = model(train_data, train_labels, eval_data, eval_labels) 74 | 75 | if args.current_host == args.hosts[0]: 76 | # save model to an S3 directory with version number '00000001' in Tensorflow SavedModel Format 77 | # To export the model as h5 format use model.save('my_model.h5') 78 | mnist_classifier.save(os.path.join(args.sm_model_dir, '000000001')) 79 | -------------------------------------------------------------------------------- /tensorflow-train-in-sagemaker-deploy-with-lambda/template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | Description: > 4 | tensorflow-mnist-inference-docker-lambda 5 | 6 | SAM Template for tensorflow-mnist-inference-docker-lambda 7 | 8 | Resources: 9 | TensorFlowMnistInferenceFunction: 10 | Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction 11 | Properties: 12 | PackageType: Image 13 | MemorySize: 1536 14 | Timeout: 120 15 | Metadata: 16 | DockerTag: python3.7-v1 17 | DockerContext: ./container/ 18 | Dockerfile: Dockerfile 19 | 20 | Outputs: 21 | TensorFlowMnistInferenceFunction: 22 | Description: "TensorFlowMnistInference Lambda Function ARN" 23 | Value: !GetAtt TensorFlowMnistInferenceFunction.Arn 24 | TensorFlowInferenceFunctionIamRole: 25 | Description: "Implicit IAM Role created for TensorFlowMnistInference function" 26 | Value: !GetAtt TensorFlowMnistInferenceFunction.Arn 27 | -------------------------------------------------------------------------------- /xgboost-built-in-algo-train-in-sagemaker-deploy-with-lambda/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/osx,linux,python,windows,pycharm,visualstudiocode 3 | 4 | ### Linux ### 5 | *~ 6 | 7 | # temporary files which can be created if a process still has a handle open of a deleted file 8 | .fuse_hidden* 9 | 10 | # KDE directory preferences 11 | .directory 12 | 13 | # Linux trash folder which might appear on any partition or disk 14 | .Trash-* 15 | 16 | # .nfs files are created when an open file is removed but is still being accessed 17 | .nfs* 18 | 19 | ### OSX ### 20 | *.DS_Store 21 | .AppleDouble 22 | .LSOverride 23 | 24 | # Icon must end with two \r 25 | Icon 26 | 27 | # Thumbnails 28 | ._* 29 | 30 | # Files that might appear in the root of a volume 31 | .DocumentRevisions-V100 32 | .fseventsd 33 | .Spotlight-V100 34 | .TemporaryItems 35 | .Trashes 36 | .VolumeIcon.icns 37 | .com.apple.timemachine.donotpresent 38 | 39 | # Directories potentially created on remote AFP share 40 | .AppleDB 41 | .AppleDesktop 42 | Network Trash Folder 43 | Temporary Items 44 | .apdisk 45 | 46 | ### PyCharm ### 47 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 48 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 49 | 50 | # User-specific stuff: 51 | .idea/**/workspace.xml 52 | .idea/**/tasks.xml 53 | .idea/dictionaries 54 | 55 | # Sensitive or high-churn files: 56 | .idea/**/dataSources/ 57 | .idea/**/dataSources.ids 58 | .idea/**/dataSources.xml 59 | .idea/**/dataSources.local.xml 60 | .idea/**/sqlDataSources.xml 61 | .idea/**/dynamic.xml 62 | .idea/**/uiDesigner.xml 63 | 64 | # Gradle: 65 | .idea/**/gradle.xml 66 | .idea/**/libraries 67 | 68 | # CMake 69 | cmake-build-debug/ 70 | 71 | # Mongo Explorer plugin: 72 | .idea/**/mongoSettings.xml 73 | 74 | ## File-based project format: 75 | *.iws 76 | 77 | ## Plugin-specific files: 78 | 79 | # IntelliJ 80 | /out/ 81 | 82 | # mpeltonen/sbt-idea plugin 83 | .idea_modules/ 84 | 85 | # JIRA plugin 86 | atlassian-ide-plugin.xml 87 | 88 | # Cursive Clojure plugin 89 | .idea/replstate.xml 90 | 91 | # Ruby plugin and RubyMine 92 | /.rakeTasks 93 | 94 | # Crashlytics plugin (for Android Studio and IntelliJ) 95 | com_crashlytics_export_strings.xml 96 | crashlytics.properties 97 | crashlytics-build.properties 98 | fabric.properties 99 | 100 | ### PyCharm Patch ### 101 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 102 | 103 | # *.iml 104 | # modules.xml 105 | # .idea/misc.xml 106 | # *.ipr 107 | 108 | # Sonarlint plugin 109 | .idea/sonarlint 110 | 111 | ### Python ### 112 | # Byte-compiled / optimized / DLL files 113 | __pycache__/ 114 | *.py[cod] 115 | *$py.class 116 | 117 | # C extensions 118 | *.so 119 | 120 | # Distribution / packaging 121 | .Python 122 | build/ 123 | develop-eggs/ 124 | dist/ 125 | downloads/ 126 | eggs/ 127 | .eggs/ 128 | lib/ 129 | lib64/ 130 | parts/ 131 | sdist/ 132 | var/ 133 | wheels/ 134 | *.egg-info/ 135 | .installed.cfg 136 | *.egg 137 | 138 | # PyInstaller 139 | # Usually these files are written by a python script from a template 140 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 141 | *.manifest 142 | *.spec 143 | 144 | # Installer logs 145 | pip-log.txt 146 | pip-delete-this-directory.txt 147 | 148 | # Unit test / coverage reports 149 | htmlcov/ 150 | .tox/ 151 | .coverage 152 | .coverage.* 153 | .cache 154 | .pytest_cache/ 155 | nosetests.xml 156 | coverage.xml 157 | *.cover 158 | .hypothesis/ 159 | 160 | # Translations 161 | *.mo 162 | *.pot 163 | 164 | # Flask stuff: 165 | instance/ 166 | .webassets-cache 167 | 168 | # Scrapy stuff: 169 | .scrapy 170 | 171 | # Sphinx documentation 172 | docs/_build/ 173 | 174 | # PyBuilder 175 | target/ 176 | 177 | # Jupyter Notebook 178 | .ipynb_checkpoints 179 | 180 | # pyenv 181 | .python-version 182 | 183 | # celery beat schedule file 184 | celerybeat-schedule.* 185 | 186 | # SageMath parsed files 187 | *.sage.py 188 | 189 | # Environments 190 | .env 191 | .venv 192 | env/ 193 | venv/ 194 | ENV/ 195 | env.bak/ 196 | venv.bak/ 197 | 198 | # Spyder project settings 199 | .spyderproject 200 | .spyproject 201 | 202 | # Rope project settings 203 | .ropeproject 204 | 205 | # mkdocs documentation 206 | /site 207 | 208 | # mypy 209 | .mypy_cache/ 210 | 211 | ### VisualStudioCode ### 212 | .vscode/* 213 | !.vscode/settings.json 214 | !.vscode/tasks.json 215 | !.vscode/launch.json 216 | !.vscode/extensions.json 217 | .history 218 | 219 | ### Windows ### 220 | # Windows thumbnail cache files 221 | Thumbs.db 222 | ehthumbs.db 223 | ehthumbs_vista.db 224 | 225 | # Folder config file 226 | Desktop.ini 227 | 228 | # Recycle Bin used on file shares 229 | $RECYCLE.BIN/ 230 | 231 | # Windows Installer files 232 | *.cab 233 | *.msi 234 | *.msm 235 | *.msp 236 | 237 | # Windows shortcuts 238 | *.lnk 239 | 240 | # Build folder 241 | 242 | */build/* 243 | 244 | # End of https://www.gitignore.io/api/osx,linux,python,windows,pycharm,visualstudiocode -------------------------------------------------------------------------------- /xgboost-built-in-algo-train-in-sagemaker-deploy-with-lambda/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/lambda/python:3.7 2 | 3 | COPY requirements.txt ./ 4 | RUN python3.7 -m pip install -r requirements.txt -t . 5 | 6 | COPY ./model/model.tar.gz . 7 | RUN tar -xzf model.tar.gz 8 | 9 | COPY ./app/app.py ./ 10 | 11 | CMD ["app.handler"] -------------------------------------------------------------------------------- /xgboost-built-in-algo-train-in-sagemaker-deploy-with-lambda/app/app.py: -------------------------------------------------------------------------------- 1 | import json 2 | import pickle as pkl 3 | 4 | import boto3 5 | import numpy as np 6 | import pandas as pd 7 | import xgboost as xgb 8 | 9 | s3 = boto3.client('s3') 10 | model = pkl.load(open('xgboost-model', 'rb')) 11 | 12 | def handler(event, context): 13 | print('Received event: ' + json.dumps(event, indent=2)) 14 | 15 | destination = '/tmp/' + event["file"] 16 | s3.download_file(event["bucket"], event["prefix"] + event["file"], destination) 17 | data_csv = pd.read_csv(destination) 18 | 19 | dtest = xgb.DMatrix(data_csv.drop(['y_no', 'y_yes'], axis=1).values) 20 | predictions_local = model.predict(dtest) 21 | result = np.round(predictions_local).tolist() 22 | 23 | print("Returning: {}".format(result)) 24 | return(json.dumps({"result": result})) 25 | 26 | 27 | -------------------------------------------------------------------------------- /xgboost-built-in-algo-train-in-sagemaker-deploy-with-lambda/events/event.json: -------------------------------------------------------------------------------- 1 | { 2 | "bucket":"", 3 | "prefix":"", 4 | "file": "test.csv" 5 | } -------------------------------------------------------------------------------- /xgboost-built-in-algo-train-in-sagemaker-deploy-with-lambda/requirements.txt: -------------------------------------------------------------------------------- 1 | boto3 2 | xgboost==1.2.1 3 | pandas 4 | sklearn -------------------------------------------------------------------------------- /xgboost-built-in-algo-train-in-sagemaker-deploy-with-lambda/template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | Description: > 4 | xgboost-direct-marketing-inference-docker-lambda 5 | 6 | SAM Template for xgboost-direct-marketing-inference-docker-lambda 7 | 8 | Resources: 9 | XGBoostDMInferenceFunction: 10 | Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction 11 | Properties: 12 | PackageType: Image 13 | MemorySize: 256 14 | Timeout: 60 15 | Policies: 16 | - AmazonS3FullAccess 17 | Metadata: 18 | DockerTag: python3.7-v1 19 | DockerContext: . 20 | Dockerfile: Dockerfile 21 | 22 | Outputs: 23 | XGBoostDMInferenceFunction: 24 | Description: "XGBoostDMInference Lambda Function ARN" 25 | Value: !GetAtt XGBoostDMInferenceFunction.Arn 26 | XGBoostDMInferenceFunctionIamRole: 27 | Description: "Implicit IAM Role created for XGBoostDMInference function" 28 | Value: !GetAtt XGBoostDMInferenceFunction.Arn 29 | -------------------------------------------------------------------------------- /xgboost-inference-arm64-docker-lambda/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/osx,linux,python,windows,pycharm,visualstudiocode 3 | 4 | ### Linux ### 5 | *~ 6 | 7 | # temporary files which can be created if a process still has a handle open of a deleted file 8 | .fuse_hidden* 9 | 10 | # KDE directory preferences 11 | .directory 12 | 13 | # Linux trash folder which might appear on any partition or disk 14 | .Trash-* 15 | 16 | # .nfs files are created when an open file is removed but is still being accessed 17 | .nfs* 18 | 19 | ### OSX ### 20 | *.DS_Store 21 | .AppleDouble 22 | .LSOverride 23 | 24 | # Icon must end with two \r 25 | Icon 26 | 27 | # Thumbnails 28 | ._* 29 | 30 | # Files that might appear in the root of a volume 31 | .DocumentRevisions-V100 32 | .fseventsd 33 | .Spotlight-V100 34 | .TemporaryItems 35 | .Trashes 36 | .VolumeIcon.icns 37 | .com.apple.timemachine.donotpresent 38 | 39 | # Directories potentially created on remote AFP share 40 | .AppleDB 41 | .AppleDesktop 42 | Network Trash Folder 43 | Temporary Items 44 | .apdisk 45 | 46 | ### PyCharm ### 47 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 48 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 49 | 50 | # User-specific stuff: 51 | .idea/**/workspace.xml 52 | .idea/**/tasks.xml 53 | .idea/dictionaries 54 | 55 | # Sensitive or high-churn files: 56 | .idea/**/dataSources/ 57 | .idea/**/dataSources.ids 58 | .idea/**/dataSources.xml 59 | .idea/**/dataSources.local.xml 60 | .idea/**/sqlDataSources.xml 61 | .idea/**/dynamic.xml 62 | .idea/**/uiDesigner.xml 63 | 64 | # Gradle: 65 | .idea/**/gradle.xml 66 | .idea/**/libraries 67 | 68 | # CMake 69 | cmake-build-debug/ 70 | 71 | # Mongo Explorer plugin: 72 | .idea/**/mongoSettings.xml 73 | 74 | ## File-based project format: 75 | *.iws 76 | 77 | ## Plugin-specific files: 78 | 79 | # IntelliJ 80 | /out/ 81 | 82 | # mpeltonen/sbt-idea plugin 83 | .idea_modules/ 84 | 85 | # JIRA plugin 86 | atlassian-ide-plugin.xml 87 | 88 | # Cursive Clojure plugin 89 | .idea/replstate.xml 90 | 91 | # Ruby plugin and RubyMine 92 | /.rakeTasks 93 | 94 | # Crashlytics plugin (for Android Studio and IntelliJ) 95 | com_crashlytics_export_strings.xml 96 | crashlytics.properties 97 | crashlytics-build.properties 98 | fabric.properties 99 | 100 | ### PyCharm Patch ### 101 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 102 | 103 | # *.iml 104 | # modules.xml 105 | # .idea/misc.xml 106 | # *.ipr 107 | 108 | # Sonarlint plugin 109 | .idea/sonarlint 110 | 111 | ### Python ### 112 | # Byte-compiled / optimized / DLL files 113 | __pycache__/ 114 | *.py[cod] 115 | *$py.class 116 | 117 | # C extensions 118 | *.so 119 | 120 | # Distribution / packaging 121 | .Python 122 | build/ 123 | develop-eggs/ 124 | dist/ 125 | downloads/ 126 | eggs/ 127 | .eggs/ 128 | lib/ 129 | lib64/ 130 | parts/ 131 | sdist/ 132 | var/ 133 | wheels/ 134 | *.egg-info/ 135 | .installed.cfg 136 | *.egg 137 | 138 | # PyInstaller 139 | # Usually these files are written by a python script from a template 140 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 141 | *.manifest 142 | *.spec 143 | 144 | # Installer logs 145 | pip-log.txt 146 | pip-delete-this-directory.txt 147 | 148 | # Unit test / coverage reports 149 | htmlcov/ 150 | .tox/ 151 | .coverage 152 | .coverage.* 153 | .cache 154 | .pytest_cache/ 155 | nosetests.xml 156 | coverage.xml 157 | *.cover 158 | .hypothesis/ 159 | 160 | # Translations 161 | *.mo 162 | *.pot 163 | 164 | # Flask stuff: 165 | instance/ 166 | .webassets-cache 167 | 168 | # Scrapy stuff: 169 | .scrapy 170 | 171 | # Sphinx documentation 172 | docs/_build/ 173 | 174 | # PyBuilder 175 | target/ 176 | 177 | # Jupyter Notebook 178 | .ipynb_checkpoints 179 | 180 | # pyenv 181 | .python-version 182 | 183 | # celery beat schedule file 184 | celerybeat-schedule.* 185 | 186 | # SageMath parsed files 187 | *.sage.py 188 | 189 | # Environments 190 | .env 191 | .venv 192 | env/ 193 | venv/ 194 | ENV/ 195 | env.bak/ 196 | venv.bak/ 197 | 198 | # Spyder project settings 199 | .spyderproject 200 | .spyproject 201 | 202 | # Rope project settings 203 | .ropeproject 204 | 205 | # mkdocs documentation 206 | /site 207 | 208 | # mypy 209 | .mypy_cache/ 210 | 211 | ### VisualStudioCode ### 212 | .vscode/* 213 | !.vscode/settings.json 214 | !.vscode/tasks.json 215 | !.vscode/launch.json 216 | !.vscode/extensions.json 217 | .history 218 | 219 | ### Windows ### 220 | # Windows thumbnail cache files 221 | Thumbs.db 222 | ehthumbs.db 223 | ehthumbs_vista.db 224 | 225 | # Folder config file 226 | Desktop.ini 227 | 228 | # Recycle Bin used on file shares 229 | $RECYCLE.BIN/ 230 | 231 | # Windows Installer files 232 | *.cab 233 | *.msi 234 | *.msm 235 | *.msp 236 | 237 | # Windows shortcuts 238 | *.lnk 239 | 240 | # Build folder 241 | 242 | */build/* 243 | 244 | # End of https://www.gitignore.io/api/osx,linux,python,windows,pycharm,visualstudiocode -------------------------------------------------------------------------------- /xgboost-inference-arm64-docker-lambda/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/lambda/python:3.8-arm64 2 | 3 | COPY requirements.txt ./ 4 | RUN python3.8 -m pip install -r requirements.txt -t . 5 | 6 | COPY ./train-code/bc_xgboost_train.py ./ 7 | RUN python bc_xgboost_train.py 8 | 9 | COPY ./app/app.py ./ 10 | 11 | CMD ["app.handler"] -------------------------------------------------------------------------------- /xgboost-inference-arm64-docker-lambda/README.md: -------------------------------------------------------------------------------- 1 | ## Serverless XGBoost Model Serving on Graviton2 architecture 2 | 3 | This examples illustrates how to serve XGBoost model on Lambda Function on Graviton2 architecture to predict breast cancer. 4 | 5 | In addition, there is a code sample to help you compare performance of the XGBoost x86_64 Lambda Function with Arm64 (Graviton2) one. 6 | 7 | This project contains source code and supporting files for a serverless application that you can deploy with the SAM CLI. It includes the following files and folders. 8 | 9 | - app - Code for the application's Lambda function. 10 | - train-code - Code for training XGBoost model based on breast cancer dataset. 11 | - events - Invocation events that you can use to invoke the function. 12 | - template.yaml - A template that defines the application's AWS resources. 13 | - invoke_x86_64_arm64_lambdas.py - Code to invoke x86_64 and Arm64 (Graviton2) Lambda Functions and compare performance. 14 | 15 | The application uses several AWS resources, including Lambda functions. These resources are defined in the `template.yaml` file in this project. You can update the template to add AWS resources through the same deployment process that updates your application code. 16 | 17 | ## Deploy the sample application 18 | 19 | The Serverless Application Model Command Line Interface (SAM CLI) is an extension of the AWS CLI that adds functionality for building and testing Lambda applications. It uses Docker to run your functions in an Amazon Linux environment that matches Lambda. It can also emulate your application's build environment and API. 20 | 21 | To use the SAM CLI, you need the following tools. 22 | 23 | * SAM CLI - [Install the SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) 24 | * Docker - [Install Docker community edition](https://hub.docker.com/search/?type=edition&offering=community) 25 | 26 | You may need the following for local testing. 27 | * [Python 3 installed](https://www.python.org/downloads/) 28 | 29 | To build and deploy your application for the first time, run the following in your shell: 30 | 31 | ```bash 32 | sam build 33 | sam deploy --guided 34 | ``` 35 | 36 | The first command will build a docker image from a Dockerfile and then copy the source of your application inside the Docker image. The second command will package and deploy your application to AWS, with a series of prompts: 37 | 38 | * **Stack Name**: The name of the stack to deploy to CloudFormation. This should be unique to your account and region, and a good starting point would be something matching your project name. 39 | * **AWS Region**: The AWS region you want to deploy your app to. 40 | * **Confirm changes before deploy**: If set to yes, any change sets will be shown to you before execution for manual review. If set to no, the AWS SAM CLI will automatically deploy application changes. 41 | * **Allow SAM CLI IAM role creation**: Many AWS SAM templates, including this example, create AWS IAM roles required for the AWS Lambda function(s) included to access AWS services. By default, these are scoped down to minimum required permissions. To deploy an AWS CloudFormation stack which creates or modified IAM roles, the `CAPABILITY_IAM` value for `capabilities` must be provided. If permission isn't provided through this prompt, to deploy this example you must explicitly pass `--capabilities CAPABILITY_IAM` to the `sam deploy` command. 42 | * **Save arguments to samconfig.toml**: If set to yes, your choices will be saved to a configuration file inside the project, so that in the future you can just re-run `sam deploy` without parameters to deploy changes to your application. 43 | 44 | ## Use the SAM CLI to build and test locally 45 | 46 | Build your application with the `sam build` command. 47 | 48 | ```bash 49 | xgboost-inference-arm64-docker-lambda$ sam build 50 | ``` 51 | 52 | The SAM CLI builds a docker image from a Dockerfile and then installs dependencies defined in `requirements.txt` inside the docker image. The processed template file is saved in the `.aws-sam/build` folder. 53 | 54 | Test a single function by invoking it directly with a test event. An event is a JSON document that represents the input that the function receives from the event source. Test events are included in the `events` folder in this project. 55 | 56 | Run functions locally and invoke them with the `sam local invoke` command. 57 | 58 | ```bash 59 | xgboost-inference-arm64-docker-lambda$ sam local invoke XGBoostInferenceArm64Function --event events/event.json 60 | ``` 61 | 62 | ## View your Lambda Architecture 63 | 64 | 1. In the [Lambda Console](https://console.aws.amazon.com/lambda/), select the `Image` tab and scrll down to the `Image` section. 65 | 2. For `Architecture` you should see `arm64` 66 | 67 | ![arm64 Architecture](../img/xgboost_arm_64_arch_view.png) 68 | 69 | ## Compare performance of x86_64 Lambda Function with Arm64 (Graviton2) one 70 | 71 | You can achieve up to 34% better price/performance with AWS Lambda Functions powered by AWS Graviton2 processor. 72 | 73 | To test the performance improvements of the XGBoost x86_64 Lambda Function with an Arm64 (Graviton2) one yourself, please execute the following steps: 74 | 1. Deploy the XGBoost x86_64 Lambda Function, as described [here](../xgboost-inference-docker-lambda/) 75 | 2. Open `invoke_x86_64_arm64_lambdas.py` file. 76 | 3. Replace `` with XGBoost x86_64 Lambda Function ARN. 77 | 4. Replace `` with XGBoost Arm64 (Graviton2) Lambda Function ARN. 78 | 5. Run the following command: `python invoke_x86_64_arm64_lambdas.py` 79 | 80 | ![xgboost x86_64 vs. arm64 improvement](../img/xgboost_x86_64_arm64_improvement.png) 81 | 82 | **We can see that the Arm64 (Graviton2) Lambda Function has performance improvements of 36% over the x86_64 one!** 83 | 84 | ## Testing your Lambda function in the Cloud 85 | 86 | 1. In the [Lambda Console](https://console.aws.amazon.com/lambda/), select Configure test events from the Test events dropdown. 87 | 2. For Event Name, enter InferenceTestEvent. 88 | 3. Copy the event JSON from [here](./events/event.json) and paste in the dialog box. 89 | 4. Choose _**Create**_. 90 | 91 | ![Configure test event](../img/xgboost_configure_test_event.png) 92 | 93 | After saving, you see InferenceTestEvent in the Test list. Now choose _**Test**_. 94 | 95 | You see the Lambda function inference result, log output, and duration: 96 | 97 | ![Lambda execution result](../img/xgboost_arm_64_execution_result.png) 98 | 99 | ## Fetch, tail, and filter Lambda function logs 100 | 101 | To simplify troubleshooting, SAM CLI has a command called `sam logs`. `sam logs` lets you fetch logs generated by your deployed Lambda function from the command line. In addition to printing the logs on the terminal, this command has several nifty features to help you quickly find the bug. 102 | 103 | `NOTE`: This command works for all AWS Lambda functions; not just the ones you deploy using SAM. 104 | 105 | ```bash 106 | xgboost-inference-arm64-docker-lambda$ sam logs -n XGBoostInferenceArm64Function --stack-name xgboost-inference-arm64-docker-lambda --tail 107 | ``` 108 | 109 | You can find more information and examples about filtering Lambda function logs in the [SAM CLI Documentation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-logging.html). 110 | 111 | ## Cleanup 112 | 113 | To delete the sample application that you created, use the AWS CLI. Assuming you used your project name for the stack name, you can run the following: 114 | 115 | ```bash 116 | aws cloudformation delete-stack --stack-name xgboost-inference-arm64-docker-lambda 117 | ``` 118 | 119 | ## Resources 120 | 121 | See the [AWS SAM developer guide](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html) for an introduction to SAM specification, the SAM CLI, and serverless application concepts. 122 | 123 | -------------------------------------------------------------------------------- /xgboost-inference-arm64-docker-lambda/app/app.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import json 4 | import joblib 5 | import xgboost as xgb 6 | import pandas as pd 7 | 8 | loaded_model = joblib.load('./bc-xgboost-model') 9 | 10 | def handler(event, context): 11 | print('Received event: ' + json.dumps(event, indent=2)) 12 | 13 | payload_df = pd.json_normalize([event]) 14 | result = loaded_model.predict(payload_df) 15 | 16 | print("Returning: {}".format(result[0])) 17 | return(json.dumps({"result": result[0]})) 18 | 19 | 20 | -------------------------------------------------------------------------------- /xgboost-inference-arm64-docker-lambda/events/event.json: -------------------------------------------------------------------------------- 1 | { 2 | "radius_mean": 13.49, 3 | "texture_mean": 22.3, 4 | "perimeter_mean": 86.91, 5 | "area_mean": 561, 6 | "smoothness_mean": 0.08752, 7 | "compactness_mean": 0.07697999999999999, 8 | "concavity_mean": 0.047510000000000004, 9 | "concave points_mean": 0.033839999999999995, 10 | "symmetry_mean": 0.1809, 11 | "fractal_dimension_mean": 0.057179999999999995, 12 | "radius_se": 0.2338, 13 | "texture_se": 1.3530000000000002, 14 | "perimeter_se": 1.735, 15 | "area_se": 20.2, 16 | "smoothness_se": 0.004455, 17 | "compactness_se": 0.013819999999999999, 18 | "concavity_se": 0.02095, 19 | "concave points_se": 0.01184, 20 | "symmetry_se": 0.01641, 21 | "fractal_dimension_se": 0.001956, 22 | "radius_worst": 15.15, 23 | "texture_worst": 31.82, 24 | "perimeter_worst": 99, 25 | "area_worst": 698.8, 26 | "smoothness_worst": 0.1162, 27 | "compactness_worst": 0.1711, 28 | "concavity_worst": 0.2282, 29 | "concave points_worst": 0.1282, 30 | "symmetry_worst": 0.2871, 31 | "fractal_dimension_worst": 0.06917000000000001 32 | } -------------------------------------------------------------------------------- /xgboost-inference-arm64-docker-lambda/invoke_x86_64_arm64_lambdas.py: -------------------------------------------------------------------------------- 1 | import boto3 2 | import json 3 | import base64 4 | import re 5 | import sys 6 | 7 | client = boto3.client('lambda') 8 | 9 | f= open('./events/event.json') 10 | json_input = json.load(f) 11 | 12 | 13 | def call_XGBoost_x86_64_Lambda(): 14 | response = client.invoke( 15 | FunctionName='', 16 | InvocationType='RequestResponse', 17 | LogType='Tail', 18 | Payload=json.dumps(json_input) 19 | ) 20 | return(find_duration(response)) 21 | 22 | 23 | def call_XGBoost_arm64_Lambda(): 24 | response = client.invoke( 25 | FunctionName='', 26 | InvocationType='RequestResponse', 27 | LogType='Tail', 28 | Payload=json.dumps(json_input) 29 | ) 30 | 31 | return(find_duration(response)) 32 | 33 | 34 | def find_duration(response): 35 | log_result = base64.b64decode(response['LogResult']).decode('utf-8') 36 | result = re.findall(r'Duration: (\d+\.\d+) ms', log_result) 37 | return (float(result[0])) 38 | 39 | # Warm the two Lambda Functions first 40 | print("Warming x86_64 and arm64 Lambda Functions") 41 | call_XGBoost_x86_64_Lambda() 42 | call_XGBoost_arm64_Lambda() 43 | 44 | print("Warming x86_64 and arm64 Lambda Functions - Done") 45 | print("Sending events to x86_64 and arm64 Lambda Functions") 46 | 47 | counter=1 48 | num_calls=100 49 | total_duration_x86_64=0 50 | total_duration_arm64=0 51 | 52 | while counter < num_calls: 53 | duration_x86_64 = call_XGBoost_x86_64_Lambda() 54 | # print(f'call_XGBoost_x86_64_Lambda duration: {duration_x86_64}') 55 | total_duration_x86_64 = total_duration_x86_64 + duration_x86_64 56 | 57 | duration_arm64 = call_XGBoost_arm64_Lambda() 58 | # print(f'call_XGBoost_arm64_Lambda duration: {duration_arm64}') 59 | total_duration_arm64 = total_duration_arm64 + duration_arm64 60 | 61 | sys.stdout.write(('=' * counter) + ('' * (num_calls - counter)) + ("\r [ %d" % counter + "% ] ")) 62 | sys.stdout.flush() 63 | 64 | counter = counter + 1 65 | 66 | print("\nSending events to x86_64 and arm64 Lambda Functions - Done") 67 | 68 | avg_duration_x86_64 = total_duration_x86_64/num_calls 69 | avg_duration_arm64 = total_duration_arm64/num_calls 70 | improvement_percentage= "{:.0%}".format(1 - (avg_duration_arm64 / avg_duration_x86_64)) 71 | 72 | print('Average duration x86_64: {:.2f} ms'.format(total_duration_x86_64/num_calls)) 73 | print('Average duration arm64: {:.2f} ms'.format(total_duration_arm64/num_calls)) 74 | print(f'*** Improvement of arm64 (Graviton2) over x86_64: {improvement_percentage} ***') -------------------------------------------------------------------------------- /xgboost-inference-arm64-docker-lambda/requirements.txt: -------------------------------------------------------------------------------- 1 | requests 2 | joblib 3 | xgboost 4 | pandas 5 | sklearn -------------------------------------------------------------------------------- /xgboost-inference-arm64-docker-lambda/template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | Description: > 4 | xgboost-inference-arm64-docker-lambda 5 | 6 | SAM Template for xgboost-inference-arm64-docker-lambda 7 | 8 | Resources: 9 | XGBoostInferenceArm64Function: 10 | Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction 11 | Properties: 12 | PackageType: Image 13 | MemorySize: 256 14 | Timeout: 60 15 | Architectures: 16 | - arm64 17 | Metadata: 18 | DockerTag: python3.7-v1 19 | DockerContext: . 20 | Dockerfile: Dockerfile 21 | 22 | Outputs: 23 | XGBoostInferenceArm64Function: 24 | Description: "XGBoostInference Arm64 Lambda Function ARN" 25 | Value: !GetAtt XGBoostInferenceArm64Function.Arn 26 | XGBoostInferenceArm64FunctionIamRole: 27 | Description: "Implicit IAM Role created for XGBoostInference Arm64 function" 28 | Value: !GetAtt XGBoostInferenceArm64FunctionRole.Arn 29 | -------------------------------------------------------------------------------- /xgboost-inference-arm64-docker-lambda/train-code/bc_xgboost_train.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | import joblib 4 | 5 | from sklearn.model_selection import train_test_split 6 | import xgboost as xgb 7 | from sklearn.metrics import accuracy_score 8 | 9 | data = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/wdbc.data', header = None) 10 | 11 | # specify columns extracted from wbdc.names 12 | data.columns = ["id","diagnosis","radius_mean","texture_mean","perimeter_mean","area_mean","smoothness_mean", 13 | "compactness_mean","concavity_mean","concave points_mean","symmetry_mean","fractal_dimension_mean", 14 | "radius_se","texture_se","perimeter_se","area_se","smoothness_se","compactness_se","concavity_se", 15 | "concave points_se","symmetry_se","fractal_dimension_se","radius_worst","texture_worst", 16 | "perimeter_worst","area_worst","smoothness_worst","compactness_worst","concavity_worst", 17 | "concave points_worst","symmetry_worst","fractal_dimension_worst"] 18 | 19 | # save the data 20 | data.to_csv("data.csv", sep=',', index=False) 21 | 22 | # print the shape of the data file 23 | print(data.shape) 24 | 25 | y = data["diagnosis"] 26 | X = data.drop(["id", "diagnosis"], axis=1) 27 | X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.20, random_state=42) 28 | 29 | model = xgb.XGBClassifier().fit(X_train, y_train) 30 | 31 | # make prediction 32 | y_pred = model.predict(X_test) 33 | accuracy = accuracy_score(y_test, y_pred) 34 | print("Model Accuracy: %.2f%%" % (accuracy * 100.0)) 35 | 36 | # save the trained model file 37 | model_file_name = "bc-xgboost-model" 38 | joblib.dump(model, model_file_name) 39 | print("Model file {} saved successfully".format(model_file_name)) 40 | 41 | -------------------------------------------------------------------------------- /xgboost-inference-docker-lambda/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/osx,linux,python,windows,pycharm,visualstudiocode 3 | 4 | ### Linux ### 5 | *~ 6 | 7 | # temporary files which can be created if a process still has a handle open of a deleted file 8 | .fuse_hidden* 9 | 10 | # KDE directory preferences 11 | .directory 12 | 13 | # Linux trash folder which might appear on any partition or disk 14 | .Trash-* 15 | 16 | # .nfs files are created when an open file is removed but is still being accessed 17 | .nfs* 18 | 19 | ### OSX ### 20 | *.DS_Store 21 | .AppleDouble 22 | .LSOverride 23 | 24 | # Icon must end with two \r 25 | Icon 26 | 27 | # Thumbnails 28 | ._* 29 | 30 | # Files that might appear in the root of a volume 31 | .DocumentRevisions-V100 32 | .fseventsd 33 | .Spotlight-V100 34 | .TemporaryItems 35 | .Trashes 36 | .VolumeIcon.icns 37 | .com.apple.timemachine.donotpresent 38 | 39 | # Directories potentially created on remote AFP share 40 | .AppleDB 41 | .AppleDesktop 42 | Network Trash Folder 43 | Temporary Items 44 | .apdisk 45 | 46 | ### PyCharm ### 47 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 48 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 49 | 50 | # User-specific stuff: 51 | .idea/**/workspace.xml 52 | .idea/**/tasks.xml 53 | .idea/dictionaries 54 | 55 | # Sensitive or high-churn files: 56 | .idea/**/dataSources/ 57 | .idea/**/dataSources.ids 58 | .idea/**/dataSources.xml 59 | .idea/**/dataSources.local.xml 60 | .idea/**/sqlDataSources.xml 61 | .idea/**/dynamic.xml 62 | .idea/**/uiDesigner.xml 63 | 64 | # Gradle: 65 | .idea/**/gradle.xml 66 | .idea/**/libraries 67 | 68 | # CMake 69 | cmake-build-debug/ 70 | 71 | # Mongo Explorer plugin: 72 | .idea/**/mongoSettings.xml 73 | 74 | ## File-based project format: 75 | *.iws 76 | 77 | ## Plugin-specific files: 78 | 79 | # IntelliJ 80 | /out/ 81 | 82 | # mpeltonen/sbt-idea plugin 83 | .idea_modules/ 84 | 85 | # JIRA plugin 86 | atlassian-ide-plugin.xml 87 | 88 | # Cursive Clojure plugin 89 | .idea/replstate.xml 90 | 91 | # Ruby plugin and RubyMine 92 | /.rakeTasks 93 | 94 | # Crashlytics plugin (for Android Studio and IntelliJ) 95 | com_crashlytics_export_strings.xml 96 | crashlytics.properties 97 | crashlytics-build.properties 98 | fabric.properties 99 | 100 | ### PyCharm Patch ### 101 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 102 | 103 | # *.iml 104 | # modules.xml 105 | # .idea/misc.xml 106 | # *.ipr 107 | 108 | # Sonarlint plugin 109 | .idea/sonarlint 110 | 111 | ### Python ### 112 | # Byte-compiled / optimized / DLL files 113 | __pycache__/ 114 | *.py[cod] 115 | *$py.class 116 | 117 | # C extensions 118 | *.so 119 | 120 | # Distribution / packaging 121 | .Python 122 | build/ 123 | develop-eggs/ 124 | dist/ 125 | downloads/ 126 | eggs/ 127 | .eggs/ 128 | lib/ 129 | lib64/ 130 | parts/ 131 | sdist/ 132 | var/ 133 | wheels/ 134 | *.egg-info/ 135 | .installed.cfg 136 | *.egg 137 | 138 | # PyInstaller 139 | # Usually these files are written by a python script from a template 140 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 141 | *.manifest 142 | *.spec 143 | 144 | # Installer logs 145 | pip-log.txt 146 | pip-delete-this-directory.txt 147 | 148 | # Unit test / coverage reports 149 | htmlcov/ 150 | .tox/ 151 | .coverage 152 | .coverage.* 153 | .cache 154 | .pytest_cache/ 155 | nosetests.xml 156 | coverage.xml 157 | *.cover 158 | .hypothesis/ 159 | 160 | # Translations 161 | *.mo 162 | *.pot 163 | 164 | # Flask stuff: 165 | instance/ 166 | .webassets-cache 167 | 168 | # Scrapy stuff: 169 | .scrapy 170 | 171 | # Sphinx documentation 172 | docs/_build/ 173 | 174 | # PyBuilder 175 | target/ 176 | 177 | # Jupyter Notebook 178 | .ipynb_checkpoints 179 | 180 | # pyenv 181 | .python-version 182 | 183 | # celery beat schedule file 184 | celerybeat-schedule.* 185 | 186 | # SageMath parsed files 187 | *.sage.py 188 | 189 | # Environments 190 | .env 191 | .venv 192 | env/ 193 | venv/ 194 | ENV/ 195 | env.bak/ 196 | venv.bak/ 197 | 198 | # Spyder project settings 199 | .spyderproject 200 | .spyproject 201 | 202 | # Rope project settings 203 | .ropeproject 204 | 205 | # mkdocs documentation 206 | /site 207 | 208 | # mypy 209 | .mypy_cache/ 210 | 211 | ### VisualStudioCode ### 212 | .vscode/* 213 | !.vscode/settings.json 214 | !.vscode/tasks.json 215 | !.vscode/launch.json 216 | !.vscode/extensions.json 217 | .history 218 | 219 | ### Windows ### 220 | # Windows thumbnail cache files 221 | Thumbs.db 222 | ehthumbs.db 223 | ehthumbs_vista.db 224 | 225 | # Folder config file 226 | Desktop.ini 227 | 228 | # Recycle Bin used on file shares 229 | $RECYCLE.BIN/ 230 | 231 | # Windows Installer files 232 | *.cab 233 | *.msi 234 | *.msm 235 | *.msp 236 | 237 | # Windows shortcuts 238 | *.lnk 239 | 240 | # Build folder 241 | 242 | */build/* 243 | 244 | # End of https://www.gitignore.io/api/osx,linux,python,windows,pycharm,visualstudiocode -------------------------------------------------------------------------------- /xgboost-inference-docker-lambda/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/lambda/python:3.7 2 | 3 | COPY requirements.txt ./ 4 | RUN python3.7 -m pip install -r requirements.txt -t . 5 | 6 | COPY ./train-code/bc_xgboost_train.py ./ 7 | RUN python bc_xgboost_train.py 8 | 9 | COPY ./app/app.py ./ 10 | 11 | CMD ["app.handler"] -------------------------------------------------------------------------------- /xgboost-inference-docker-lambda/README.md: -------------------------------------------------------------------------------- 1 | ## Serverless XGBoost Model Serving 2 | 3 | This examples illustrates how to serve XGBoost model on Lambda Function to predict breast cancer. 4 | 5 | This project contains source code and supporting files for a serverless application that you can deploy with the SAM CLI. It includes the following files and folders. 6 | 7 | - app - Code for the application's Lambda function. 8 | - train-code - Code for training XGBoost model based on breast cancer dataset. 9 | - events - Invocation events that you can use to invoke the function. 10 | - template.yaml - A template that defines the application's AWS resources. 11 | 12 | The application uses several AWS resources, including Lambda functions. These resources are defined in the `template.yaml` file in this project. You can update the template to add AWS resources through the same deployment process that updates your application code. 13 | 14 | ## Deploy the sample application 15 | 16 | The Serverless Application Model Command Line Interface (SAM CLI) is an extension of the AWS CLI that adds functionality for building and testing Lambda applications. It uses Docker to run your functions in an Amazon Linux environment that matches Lambda. It can also emulate your application's build environment and API. 17 | 18 | To use the SAM CLI, you need the following tools. 19 | 20 | * SAM CLI - [Install the SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) 21 | * Docker - [Install Docker community edition](https://hub.docker.com/search/?type=edition&offering=community) 22 | 23 | You may need the following for local testing. 24 | * [Python 3 installed](https://www.python.org/downloads/) 25 | 26 | To build and deploy your application for the first time, run the following in your shell: 27 | 28 | ```bash 29 | sam build 30 | sam deploy --guided 31 | ``` 32 | 33 | The first command will build a docker image from a Dockerfile and then copy the source of your application inside the Docker image. The second command will package and deploy your application to AWS, with a series of prompts: 34 | 35 | * **Stack Name**: The name of the stack to deploy to CloudFormation. This should be unique to your account and region, and a good starting point would be something matching your project name. 36 | * **AWS Region**: The AWS region you want to deploy your app to. 37 | * **Confirm changes before deploy**: If set to yes, any change sets will be shown to you before execution for manual review. If set to no, the AWS SAM CLI will automatically deploy application changes. 38 | * **Allow SAM CLI IAM role creation**: Many AWS SAM templates, including this example, create AWS IAM roles required for the AWS Lambda function(s) included to access AWS services. By default, these are scoped down to minimum required permissions. To deploy an AWS CloudFormation stack which creates or modified IAM roles, the `CAPABILITY_IAM` value for `capabilities` must be provided. If permission isn't provided through this prompt, to deploy this example you must explicitly pass `--capabilities CAPABILITY_IAM` to the `sam deploy` command. 39 | * **Save arguments to samconfig.toml**: If set to yes, your choices will be saved to a configuration file inside the project, so that in the future you can just re-run `sam deploy` without parameters to deploy changes to your application. 40 | 41 | ## Use the SAM CLI to build and test locally 42 | 43 | Build your application with the `sam build` command. 44 | 45 | ```bash 46 | xgboost-inference-docker-lambda$ sam build 47 | ``` 48 | 49 | The SAM CLI builds a docker image from a Dockerfile and then installs dependencies defined in `requirements.txt` inside the docker image. The processed template file is saved in the `.aws-sam/build` folder. 50 | 51 | Test a single function by invoking it directly with a test event. An event is a JSON document that represents the input that the function receives from the event source. Test events are included in the `events` folder in this project. 52 | 53 | Run functions locally and invoke them with the `sam local invoke` command. 54 | 55 | ```bash 56 | xgboost-inference-docker-lambda$ sam local invoke XGBoostInferenceFunction --event events/event.json 57 | ``` 58 | 59 | ## Testing your Lambda function in the Cloud 60 | 61 | 1. In the [Lambda Console](https://console.aws.amazon.com/lambda/), select Configure test events from the Test events dropdown. 62 | 2. For Event Name, enter InferenceTestEvent. 63 | 3. Copy the event JSON from [here](./events/event.json) and paste in the dialog box. 64 | 4. Choose _**Create**_. 65 | 66 | ![Configure test event](../img/xgboost_configure_test_event.png) 67 | 68 | After saving, you see InferenceTestEvent in the Test list. Now choose _**Test**_. 69 | 70 | You see the Lambda function inference result, log output, and duration: 71 | 72 | ![Lambda execution result](../img/xgboost_execution_result.png) 73 | 74 | ## Fetch, tail, and filter Lambda function logs 75 | 76 | To simplify troubleshooting, SAM CLI has a command called `sam logs`. `sam logs` lets you fetch logs generated by your deployed Lambda function from the command line. In addition to printing the logs on the terminal, this command has several nifty features to help you quickly find the bug. 77 | 78 | `NOTE`: This command works for all AWS Lambda functions; not just the ones you deploy using SAM. 79 | 80 | ```bash 81 | xgboost-inference-docker-lambda$ sam logs -n XGBoostInferenceFunction --stack-name xgboost-inference-docker-lambda --tail 82 | ``` 83 | 84 | You can find more information and examples about filtering Lambda function logs in the [SAM CLI Documentation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-logging.html). 85 | 86 | ## Cleanup 87 | 88 | To delete the sample application that you created, use the AWS CLI. Assuming you used your project name for the stack name, you can run the following: 89 | 90 | ```bash 91 | aws cloudformation delete-stack --stack-name xgboost-inference-docker-lambda 92 | ``` 93 | 94 | ## Resources 95 | 96 | See the [AWS SAM developer guide](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html) for an introduction to SAM specification, the SAM CLI, and serverless application concepts. 97 | 98 | -------------------------------------------------------------------------------- /xgboost-inference-docker-lambda/app/app.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import json 4 | import joblib 5 | import xgboost as xgb 6 | import pandas as pd 7 | 8 | loaded_model = joblib.load('./bc-xgboost-model') 9 | 10 | def handler(event, context): 11 | print('Received event: ' + json.dumps(event, indent=2)) 12 | 13 | payload_df = pd.json_normalize([event]) 14 | result = loaded_model.predict(payload_df) 15 | 16 | print("Returning: {}".format(result[0])) 17 | return(json.dumps({"result": result[0]})) 18 | 19 | 20 | -------------------------------------------------------------------------------- /xgboost-inference-docker-lambda/events/event.json: -------------------------------------------------------------------------------- 1 | { 2 | "radius_mean": 13.49, 3 | "texture_mean": 22.3, 4 | "perimeter_mean": 86.91, 5 | "area_mean": 561, 6 | "smoothness_mean": 0.08752, 7 | "compactness_mean": 0.07697999999999999, 8 | "concavity_mean": 0.047510000000000004, 9 | "concave points_mean": 0.033839999999999995, 10 | "symmetry_mean": 0.1809, 11 | "fractal_dimension_mean": 0.057179999999999995, 12 | "radius_se": 0.2338, 13 | "texture_se": 1.3530000000000002, 14 | "perimeter_se": 1.735, 15 | "area_se": 20.2, 16 | "smoothness_se": 0.004455, 17 | "compactness_se": 0.013819999999999999, 18 | "concavity_se": 0.02095, 19 | "concave points_se": 0.01184, 20 | "symmetry_se": 0.01641, 21 | "fractal_dimension_se": 0.001956, 22 | "radius_worst": 15.15, 23 | "texture_worst": 31.82, 24 | "perimeter_worst": 99, 25 | "area_worst": 698.8, 26 | "smoothness_worst": 0.1162, 27 | "compactness_worst": 0.1711, 28 | "concavity_worst": 0.2282, 29 | "concave points_worst": 0.1282, 30 | "symmetry_worst": 0.2871, 31 | "fractal_dimension_worst": 0.06917000000000001 32 | } -------------------------------------------------------------------------------- /xgboost-inference-docker-lambda/requirements.txt: -------------------------------------------------------------------------------- 1 | requests 2 | joblib 3 | xgboost==1.1.1 4 | pandas 5 | sklearn -------------------------------------------------------------------------------- /xgboost-inference-docker-lambda/template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | Description: > 4 | xgboost-inference-docker-lambda 5 | 6 | SAM Template for xgboost-inference-docker-lambda 7 | 8 | Resources: 9 | XGBoostInferenceFunction: 10 | Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction 11 | Properties: 12 | PackageType: Image 13 | MemorySize: 256 14 | Timeout: 60 15 | Metadata: 16 | DockerTag: python3.7-v1 17 | DockerContext: . 18 | Dockerfile: Dockerfile 19 | 20 | Outputs: 21 | XGBoostInferenceFunction: 22 | Description: "XGBoostInference Lambda Function ARN" 23 | Value: !GetAtt XGBoostInferenceFunction.Arn 24 | XGBoostInferenceFunctionIamRole: 25 | Description: "Implicit IAM Role created for XGBoostInference function" 26 | Value: !GetAtt XGBoostInferenceFunction.Arn 27 | -------------------------------------------------------------------------------- /xgboost-inference-docker-lambda/train-code/bc_xgboost_train.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | import joblib 4 | 5 | from sklearn.model_selection import train_test_split 6 | import xgboost as xgb 7 | from sklearn.metrics import accuracy_score 8 | 9 | data = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/wdbc.data', header = None) 10 | 11 | # specify columns extracted from wbdc.names 12 | data.columns = ["id","diagnosis","radius_mean","texture_mean","perimeter_mean","area_mean","smoothness_mean", 13 | "compactness_mean","concavity_mean","concave points_mean","symmetry_mean","fractal_dimension_mean", 14 | "radius_se","texture_se","perimeter_se","area_se","smoothness_se","compactness_se","concavity_se", 15 | "concave points_se","symmetry_se","fractal_dimension_se","radius_worst","texture_worst", 16 | "perimeter_worst","area_worst","smoothness_worst","compactness_worst","concavity_worst", 17 | "concave points_worst","symmetry_worst","fractal_dimension_worst"] 18 | 19 | # save the data 20 | data.to_csv("data.csv", sep=',', index=False) 21 | 22 | # print the shape of the data file 23 | print(data.shape) 24 | 25 | y = data["diagnosis"] 26 | X = data.drop(["id", "diagnosis"], axis=1) 27 | X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.20, random_state=42) 28 | 29 | model = xgb.XGBClassifier().fit(X_train, y_train) 30 | 31 | # make prediction 32 | y_pred = model.predict(X_test) 33 | accuracy = accuracy_score(y_test, y_pred) 34 | print("Model Accuracy: %.2f%%" % (accuracy * 100.0)) 35 | 36 | # save the trained model file 37 | model_file_name = "bc-xgboost-model" 38 | joblib.dump(model, model_file_name) 39 | print("Model file {} saved successfully".format(model_file_name)) 40 | 41 | --------------------------------------------------------------------------------