{ "cells": [ { "cell_type": "markdown", "id": "7f466960", "metadata": {}, "source": [ "# Test Training and Inference Lambda Function with Sample Data" ] }, { "cell_type": "markdown", "id": "a28fd8af", "metadata": {}, "source": [ "##### This notebook showcases the usage of the training and inference Lambda Function by creating sample data and invoking the Lambda functions." ] }, { "cell_type": "markdown", "id": "5e80fcc6", "metadata": {}, "source": [ "## 01) Imports & Setup" ] }, { "cell_type": "code", "execution_count": null, "id": "fe6e75ef", "metadata": {}, "outputs": [], "source": [ "import boto3\n", "from sklearn import datasets\n", "import json\n", "import matplotlib.pyplot as plt\n", "import requests" ] }, { "cell_type": "code", "execution_count": null, "id": "d68935aa", "metadata": {}, "outputs": [], "source": [ "# boto 3 Lambda client to invoke the Lambda functions programmatically\n", "lambda_client = boto3.client('lambda')" ] }, { "cell_type": "code", "execution_count": null, "id": "0e21389f", "metadata": {}, "outputs": [], "source": [ "# Set Lambda function names\n", "\n", "# inference Lambda function\n", "inference_function_name = '' # replace with your Lambda function name\n", "# training Lambda function\n", "training_function_name = '' # replace with your Lambda function name" ] }, { "cell_type": "markdown", "id": "219e05be", "metadata": {}, "source": [ "## 02) Test Access to Lambda Function" ] }, { "cell_type": "markdown", "id": "d8745a68", "metadata": {}, "source": [ "First we test whether we have sufficient IAM permissions to invoke the two Lambda functions" ] }, { "cell_type": "code", "execution_count": null, "id": "6b283f26", "metadata": {}, "outputs": [], "source": [ "# invoke Lambda function in \"dry-run\" mode\n", "response = lambda_client.invoke(\n", " FunctionName=inference_function_name,\n", " InvocationType='DryRun',\n", " LogType='Tail'\n", ")\n", "\n", "# check if status indicates successful access\n", "if response.get('StatusCode') == 204:\n", " print('Access to inference Lambda function successful')\n", "else:\n", " print('Access to inference Lambda function not successful. Please make sure your notebook\\'s IAM role has sufficient permissions to invoke the Lambda function.')" ] }, { "cell_type": "code", "execution_count": null, "id": "ef658310", "metadata": {}, "outputs": [], "source": [ "# invoke Lambda function in \"dry-run\" mode\n", "response = lambda_client.invoke(\n", " FunctionName=training_function_name,\n", " InvocationType='DryRun',\n", " LogType='Tail'\n", ")\n", "\n", "# check if status indicates successful access\n", "if response.get('StatusCode') == 204:\n", " print('Access to training Lambda function successful')\n", "else:\n", " print('Access to training Lambda function not successful. Please make sure your notebook\\'s IAM role has sufficient permissions to invoke the Lambda function.')" ] }, { "cell_type": "markdown", "id": "654fe0ce", "metadata": {}, "source": [ "## 03) Test Lambda Function" ] }, { "cell_type": "markdown", "id": "c8ccad4c", "metadata": {}, "source": [ "### 03a) Training" ] }, { "cell_type": "markdown", "id": "693eb009", "metadata": {}, "source": [ "Now that we have ensured sufficient IAM permissions, we can test the training Lambda functions with sample data." ] }, { "cell_type": "code", "execution_count": null, "id": "89f1311c", "metadata": {}, "outputs": [], "source": [ "# create sample data\n", "X, y = datasets.make_regression(\n", " n_samples=500,\n", " n_features=1,\n", " n_informative=1,\n", " n_targets=1,\n", " bias=20,\n", " noise=30\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "d6e85867", "metadata": {}, "outputs": [], "source": [ "# inspect the training data\n", "plt.scatter(X, y, color='black')" ] }, { "cell_type": "markdown", "id": "b7bfc0bd", "metadata": {}, "source": [ "We can see that our data can be approximated with a linear regression." ] }, { "cell_type": "code", "execution_count": null, "id": "08409737", "metadata": {}, "outputs": [], "source": [ "# prepare payload\n", "data = {\n", " \"data\": {\n", " \"X\": X.tolist(),\n", " \"y\": y.tolist()\n", " }\n", "}\n", "event = {\n", " \"body\": json.dumps(data)\n", "}\n", "payload = json.dumps(event)" ] }, { "cell_type": "code", "execution_count": null, "id": "4d361b84", "metadata": {}, "outputs": [], "source": [ "# invoke training Lambda function\n", "# the first call will take longer than succeeding ones, as the Lambda function warms up after a period of inactivates.\n", "response = lambda_client.invoke(\n", " FunctionName=training_function_name,\n", " InvocationType='RequestResponse',\n", " LogType='Tail',\n", " Payload=payload\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "b35c5bb3", "metadata": {}, "outputs": [], "source": [ "# investigate response\n", "response_payload = response.get('Payload').read()\n", "print(json.loads(response_payload))" ] }, { "cell_type": "markdown", "id": "4811a111", "metadata": {}, "source": [ "### 03b) Inference" ] }, { "cell_type": "markdown", "id": "48e9d9c9", "metadata": {}, "source": [ "Now that we have successfully invoked the training Lambda function, which trained a regression model and saved the trained model to s3,\n", "we can test the inference Lambda function. It will download the latest trained model from s3 and make predictions based on the\n", "data we send in with the invocation call." ] }, { "cell_type": "code", "execution_count": null, "id": "feaad04e", "metadata": {}, "outputs": [], "source": [ "# create sample inference data\n", "X_test, y_test = datasets.make_regression(\n", " n_samples=10,\n", " n_features=1,\n", " n_informative=1,\n", " n_targets=1,\n", " bias=30,\n", " noise=50\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "0ce8935d", "metadata": {}, "outputs": [], "source": [ "# prepare payload\n", "data = {\n", " \"data\": X_test.tolist()\n", "}\n", "event = {\n", " \"body\": json.dumps(data)\n", "}\n", "payload = json.dumps(event)" ] }, { "cell_type": "code", "execution_count": null, "id": "2aed5016", "metadata": {}, "outputs": [], "source": [ "# invoke inference Lambda function\n", "# the first call will take longer than succeeding ones, as the Lambda function warms up after a period of inactivates.\n", "response = lambda_client.invoke(\n", " FunctionName=inference_function_name,\n", " InvocationType='RequestResponse',\n", " LogType='Tail',\n", " Payload=payload\n", ")\n", "response_payload = response.get('Payload').read()" ] }, { "cell_type": "code", "execution_count": null, "id": "33971b3d", "metadata": {}, "outputs": [], "source": [ "# unpack response\n", "response_body = json.loads(response_payload).get('body')\n", "prediction = json.loads(response_body).get('prediction')\n", "prediction = json.loads(prediction)" ] }, { "cell_type": "code", "execution_count": null, "id": "91febe8f", "metadata": {}, "outputs": [], "source": [ "# visualize prediction vs. ground truth\n", "plt.scatter(X_test, y_test, color='black')\n", "plt.plot(X_test, prediction, color='blue', linewidth=3)\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "3a493167", "metadata": {}, "source": [ "The above plot visualizes the ground truth (black dots) vs our model prediction (blue line)" ] }, { "cell_type": "markdown", "id": "90c90cac", "metadata": {}, "source": [ "## 04) Test with API Gateway" ] }, { "cell_type": "markdown", "id": "fd12ce4e", "metadata": {}, "source": [ "Instead of invoking the Lambda functions directly, we can also use the deployed API gateway, which could be used to offer the train and inference functionality to external applications. " ] }, { "cell_type": "markdown", "id": "6d994bae", "metadata": {}, "source": [ "### 04a) Training" ] }, { "cell_type": "code", "execution_count": null, "id": "6bf78c98", "metadata": {}, "outputs": [], "source": [ "# setup API parameters\n", "url = '' #paste your API URL here\n", "headers = {'Content-Type': \"application/json\", 'Accept': \"application/json\"}\n", "\n", "# format payload\n", "data = {\n", " \"data\": {\n", " \"X\": X.tolist(),\n", " \"y\": y.tolist()\n", " }\n", "}" ] }, { "cell_type": "code", "execution_count": null, "id": "c1c85327", "metadata": {}, "outputs": [], "source": [ "# invoke API\n", "response = requests.post(url, json=data, headers=headers)" ] }, { "cell_type": "code", "execution_count": null, "id": "44d1dadb", "metadata": {}, "outputs": [], "source": [ "# investigate response\n", "response_content = json.loads(response.content)\n", "print(response_content)" ] }, { "cell_type": "markdown", "id": "853d61a1", "metadata": {}, "source": [ "### 04b) Inference" ] }, { "cell_type": "code", "execution_count": null, "id": "01cd7ffb", "metadata": {}, "outputs": [], "source": [ "# setup API parameters\n", "url = '' #paste your API URL here\n", "headers = {'Content-Type': \"application/json\", 'Accept': \"application/json\"}\n", "\n", "# format payload\n", "data = {\n", " \"data\": X_test.tolist()\n", "}" ] }, { "cell_type": "code", "execution_count": null, "id": "9439c04c", "metadata": {}, "outputs": [], "source": [ "# invoke API\n", "response = requests.post(url, json=data, headers=headers)" ] }, { "cell_type": "code", "execution_count": null, "id": "d7dd107f", "metadata": {}, "outputs": [], "source": [ "# investigate response\n", "response_content = json.loads(response.content)\n", "print(response_content)" ] } ], "metadata": { "kernelspec": { "display_name": "conda_python3", "language": "python", "name": "conda_python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.13" } }, "nbformat": 4, "nbformat_minor": 5 }