Skip to content

cr21/imagenet-1k-restnet-aws-lambda-serverless-deployment

Repository files navigation

imagenet-1k-restnet-aws-lambda-serverless-deployment

  • Objective of this project is to deploy fastapi based Imagenet classifier endpoint to AWS lambda function.
  • Generate function url which will be used to run inference.

AWS Lambda

aws lambda

Key Concepts of AWS Lambda:

1. Event Driven Execution: AWS Lambda functions are triggered by events from various AWS services or custom sources. This allow you to execute code in response to specific event, making it ideal for task like data processing, model inference and post-processing. e.g whenever file uploaded to s3 bucket take some action, message publish to topic (SNS event), new message arrive in SQS

2. Stateless: Each lambda invocation is stateless, it does not maintain state between invocations

3. Scalling: AWS Lambda automatically scales your functions based on the incoming load. It can run thousands of functions in parallel, ensuring responsiveness even during spikes in traffic.

4. Pay-as-you-Go: you pay only for compute time that you consume. no charges when it's not running. Lambda is billed per ms of execution time (after free tier)

5. Integration: Lambda integrates seamlessly with other AWS services, such as Amazon S3, Amazon DynamoDB, Amazon SNS, and more. This makes it easy to build end-to-end workflows.

Deploy Imagenet classifier FastAPI Endpoint

  • we will use onnxruntime to do inference.
  1. requirements_dev.txt
# requirements_dev.txt
--extra-index-url https://download.pytorch.org/whl/cpu
torch
torchvision
onnx
aws-cdk-lib
gradio
# create virtual env and install requirements
python3 -m venv venv
source venv/bin/activate
pip install -r requirements_dev.txt
  1. app.py
from typing import Annotated
import io
import numpy as np
import onnxruntime as ort
from PIL import Image
from fastapi import FastAPI, File, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from fastapi.responses import JSONResponse, HTMLResponse
from fasthtml import FastHTML
from fasthtml.common import (
    Html,
    Script,
    Head,
    Title,
    Body,
    Div,
    Form,
    Input,
    Img,
    P,
    to_xml,
)
from shad4fast import (
    ShadHead,
    Card,
    CardHeader,
    CardTitle,
    CardDescription,
    CardContent,
    CardFooter,
    Alert,
    AlertTitle,
    AlertDescription,
    Button,
    Badge,
    Separator,
    Lucide,
    Progress,
)
import base64
app = FastAPI(
    title="Imagenet 1K  Classification API",
    description="FastAPI application serving an ONNX model for Imagenet1k  image classification",
    version="1.0.0",
)
IS_MODEL_LOADED = False
# Add CORS middleware
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)
INPUT_SIZE = (224, 224)
MEAN = np.array([0.485, 0.456, 0.406])
STD = np.array([0.229, 0.224, 0.225])
IMAGENET_LABELS=[]
with open('imagenet_1k_classes.txt', 'r') as f:
    for line in f:
        IMAGENET_LABELS.append(line.strip())

# try load onnx model
try:
    print("Loading ONNX model...")
    ort_session = ort.InferenceSession("models/resnet50_imagenet_1k_model.onnx")
    ort_session.run(
        ["output"], {"input": np.random.randn(1, 3, *INPUT_SIZE).astype(np.float32)}
    )
    print("Model loaded successfully")
    IS_MODEL_LOADED = True
except Exception as e:
    print(f"Error loading model: {str(e)}")
    raise

class PredictionResponse(BaseModel):
    """Response model for predictions"""

    predictions: dict  # Change to dict for class probabilities
    success: bool
    message: str

def preprocess_image(image: Image.Image) -> np.ndarray:
    """
    Preprocess the input image for model inference

    Args:
        image (PIL.Image): Input image

    Returns:
        np.ndarray: Preprocessed image array
    """
    # Convert to RGB if not already
    image = image.convert("RGB")

    # Resize
    image = image.resize(INPUT_SIZE)

    # Convert to numpy array and normalize
    img_array = np.array(image).astype(np.float32) / 255.0

    # Apply mean and std normalization
    img_array = (img_array - MEAN) / STD

    # Transpose to channel-first format (NCHW)
    img_array = img_array.transpose(2, 0, 1)

    # Add batch dimension
    img_array = np.expand_dims(img_array, 0)

    return img_array

@app.get("/", response_class=HTMLResponse)
async def ui_home():
    content = Html(
        Head(
            Title("Imagenet 1K Image Classifier"),
            ShadHead(tw_cdn=True, theme_handle=True),
            Script(
                src="https://unpkg.com/htmx.org@2.0.3",
                integrity="sha384-0895/pl2MU10Hqc6jd4RvrthNlDiE9U1tWmX7WRESftEDRosgxNsQG/Ze9YMRzHq",
                crossorigin="anonymous",
            ),
        ),
        Body(
            Div(
                Card(
                    CardHeader(
                        Div(
                            CardTitle("Imagenet 1K Image Classifier"),
                            Badge("AI Powered", variant="secondary", cls="w-fit"),
                            cls="flex items-center justify-between",
                        ),
                        CardDescription(
                            "Upload an image to classify it from 1000 different categories!"
                        ),
                    ),
                    CardContent(
                        Form(
                            Div(
                                Div(
                                    Input(
                                        type="file",
                                        name="file",
                                        accept="image/*",
                                        required=True,
                                        cls="mb-4 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-primary file:text-primary-foreground hover:file:bg-primary/90 file:cursor-pointer",
                                    ),
                                    P(
                                        "Drag and drop an image or click to browse",
                                        cls="text-sm text-muted-foreground text-center mt-2",
                                    ),
                                    cls="border-2 border-dashed rounded-lg p-4 hover:border-primary/50 transition-colors",
                                ),
                                Button(
                                    Lucide("sparkles", cls="mr-2 h-4 w-4"),
                                    "Classify Image",
                                    type="submit",
                                    cls="w-full",
                                ),
                                cls="space-y-4",
                            ),
                            enctype="multipart/form-data",
                            hx_post="/classify",
                            hx_target="#result",
                        ),
                        Div(id="result", cls="mt-6"),
                    ),
                    cls="w-full max-w-3xl shadow-lg",
                    standard=True,
                ),
                cls="container flex flex-col items-center justify-center min-h-screen p-4 space-y-6",
            ),
            cls="bg-background text-foreground",
        ),
    )
    return to_xml(content)


@app.post("/classify", response_class=HTMLResponse)
async def ui_handle_classify(file: Annotated[bytes, File()]):
    try:
        response = await predict(file)
        image_b64 = base64.b64encode(file).decode("utf-8")

        # Sort predictions by confidence
        sorted_predictions = sorted(response.predictions.items(), key=lambda x: x[1], reverse=True)[:5]
        print("sorted_predictions : ",sorted_predictions)

        # Generate HTML for predictions
        prediction_html = Div(
            Div(
                Div(cls="absolute inset-y-0 left-0 bg-primary/20 opacity-50 z-0 confidence-bar"),
                Div(
                    f"{pred[0].replace('_', ' ').title()}",
                    cls="relative z-10 text-sm font-medium"
                ),
                Div(
                    f"{pred[1]*100:.2f}%",
                    cls="text-xs text-muted-foreground"
                ),
                cls=f"prediction-row relative flex justify-between items-center p-2 border-b last:border-b-0 hover:bg-secondary/20 transition-colors",
                data_confidence=str(pred[1])
            ) for pred in sorted_predictions
        )

        # Include the original image
        image_preview = Div(
            Img(
                src=f"data:image/jpeg;base64,{image_b64}",
                cls="max-w-full max-h-64 object-contain rounded-lg mx-auto mb-4"
            ),
            cls="mb-4"
        )

        return to_xml(Div(
            image_preview,
            Div(
                Div("Top 5 Predictions", cls="text-lg font-semibold mb-3"),
                prediction_html,
                cls="bg-background border rounded-lg shadow-sm"
            )
        ))
    except Exception as e:
        return to_xml(Div(
            f"Error processing image: {str(e)}",
            cls="text-red-500 p-4 bg-red-50 rounded-lg"
        ))


@app.post("/predict", response_model=PredictionResponse)
async def predict(file: Annotated[bytes, File(description="Image file to classify")]):
    try:
        image = Image.open(io.BytesIO(file))
        processed_image = preprocess_image(image)

        outputs = ort_session.run(
            ["output"], {"input": processed_image.astype(np.float32)}
        )

        logits = outputs[0][0]
        probabilities = np.exp(logits) / np.sum(np.exp(logits))

        predictions = {IMAGENET_LABELS[i]: float(prob) for i, prob in enumerate(probabilities)}

        return PredictionResponse(
            predictions=predictions, success=True, message="Classification successful"
        )

    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Error processing image: {str(e)}")



@app.get("/health")
async def health_check():
    return JSONResponse(
        content={"status": "healthy", "model_loaded": IS_MODEL_LOADED}, status_code=200
    )


if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)
  1. client .py
import requests
import os
from pathlib import Path

def predict_image(image_path: str, api_url: str = "http://localhost:8000/predict") -> dict:
    """
    Send an image to the prediction API and get results
    
    Args:
        image_path (str): Path to the image file
        api_url (str): URL of the prediction endpoint
        
    Returns:
        dict: Prediction results
    """
    # Check if file exists
    if not os.path.exists(image_path):
        raise FileNotFoundError(f"Image file not found: {image_path}")
    
    # Prepare the file for upload
    with open(image_path, "rb") as f:
        files = {"file": (Path(image_path).name, f, "image/jpeg")}
        
        # Make the request
        response = requests.post(api_url, files=files)
        
        # Check if request was successful
        response.raise_for_status()
        
        return response.json()

def main():
    # Test images
    test_images = ["./sample_data/lobster.png"]
    
    print("Testing  Image Classification API")
    print("-" * 30)
    
    for image_path in test_images:
        try:
            print(f"\nTesting image: {image_path}")
            result = predict_image(image_path)
            
            # Print predictions
            print("Predictions:")
            print("-" * 30  )
            for class_name, probability in sorted(result["predictions"].items(), key=lambda x: x[1], reverse=True)[:5]:
                print(f"{class_name}: {probability:.4f}")
            print("-" * 30  )
                
        except Exception as e:
            print(f"Error processing {image_path}: {str(e)}")

if __name__ == "__main__":
    main() 
  1. Dockerfile
FROM public.ecr.aws/docker/library/python:3.12-slim

# Install AWS Lambda Web Adapter
# Adapter allows you to use AWS Lambda as a HTTP service
# to avoid using mangum service
COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.8.4 /lambda-adapter /opt/extensions/lambda-adapter

# Set environment variables
ENV PORT=8080

WORKDIR /var/task

# Copy and install requirements
COPY requirements.txt ./
RUN pip install --no-cache-dir  -r requirements.txt

# Copy application code and models
COPY app.py ./
COPY icons.py ./
COPY models/ ./models/
COPY sample_data/ ./sample_data/
COPY imagenet_1k_classes.txt ./imagenet_1k_classes.txt
EXPOSE 8080
# Set command
CMD exec uvicorn --host 0.0.0.0 --port $PORT app:app 
  1. Run docker container and test client
docker build -t lambda-app . 

❯ docker run -p 8080:8080 lambda-app
INFO:     Started server process [1]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8080 (Press CTRL+C to quit)

local app demo

  1. Test Client
❯ python3 client.py
Testing  Image Classification API
------------------------------

Testing image: ./sample_data/lobster.png
Predictions:
------------------------------
American lobster, Northern lobster, Maine lobster, Homarus americanus: 0.9844
crayfish, crawfish, crawdad, crawdaddy: 0.0143
spiny lobster, langouste, rock lobster, crawfish, crayfish, sea crawfish: 0.0011
scorpion: 0.0001
rock crab, Cancer irroratus: 0.0001

How to deploy Fastapi web app as AWS Lambda function url

  • We will use AWS CDK to deploy fastapi web app to run as docker container on AWS Lambda aws cdk

How to deploy lambda function using docker image that will run web app

  1. Install CDK Python Library
pip install aws-cdk-lib==2.168.0
  1. Install CDK cli
npm  install -g aws-cdk
  1. Create IAM user with below permission -- permission needed by CDK
{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Sid": "CloudFormationAccess",
			"Effect": "Allow",
			"Action": [
				"cloudformation:CreateStack",
				"cloudformation:DescribeStacks",
				"cloudformation:DescribeStackEvents",
				"cloudformation:GetTemplate",
				"cloudformation:UpdateStack",
				"cloudformation:DeleteStack",
				"cloudformation:DeleteChangeSet",
				"cloudformation:CreateChangeSet",
				"cloudformation:DescribeChangeSet",
				"cloudformation:ExecuteChangeSet"
			],
			"Resource": "*"
		},
		{
			"Sid": "S3AccessForCDKAssets",
			"Effect": "Allow",
			"Action": [
				"s3:CreateBucket",
				"s3:PutObject",
				"s3:GetObject",
				"s3:DeleteObject",
				"s3:ListBucket"
			],
			"Resource": "*"
		},
		{
			"Sid": "ECRAccessForDockerImage",
			"Effect": "Allow",
			"Action": [
				"ecr:CreateRepository",
				"ecr:DescribeRepositories",
				"ecr:DescribeImages",
				"ecr:GetAuthorizationToken",
				"ecr:BatchCheckLayerAvailability",
				"ecr:PutImage",
				"ecr:InitiateLayerUpload",
				"ecr:UploadLayerPart",
				"ecr:CompleteLayerUpload"
			],
			"Resource": "*"
		},
		{
			"Sid": "LambdaFunctionManagement",
			"Effect": "Allow",
			"Action": [
				"lambda:CreateFunction",
				"lambda:UpdateFunctionCode",
				"lambda:UpdateFunctionConfiguration",
				"lambda:GetFunction",
				"lambda:DeleteFunction",
				"lambda:CreateFunctionUrlConfig",
				"lambda:UpdateFunctionUrlConfig",
				"lambda:GetFunctionUrlConfig",
				"lambda:DeleteFunctionUrlConfig"
			],
			"Resource": "*"
		},
		{
			"Sid": "IAMRolesForLambdaAndCFN",
			"Effect": "Allow",
			"Action": [
				"iam:CreateRole",
				"iam:GetRole",
				"iam:AttachRolePolicy",
				"iam:PutRolePolicy",
				"iam:PassRole",
				"iam:DeleteRole",
				"iam:DeleteRolePolicy",
				"iam:DetachRolePolicy"
			],
			"Resource": "*"
		},
		{
			"Sid": "SSMParameterReadOnly",
			"Effect": "Allow",
			"Action": [
				"ssm:GetParameter",
				"ssm:GetParameters",
				"ssm:GetParametersByPath",
				"ssm:DescribeParameters"
			],
			"Resource": "*"
		},
		{
			"Sid": "STSAssumeRoleForBootstrap",
			"Effect": "Allow",
			"Action": "sts:AssumeRole",
			"Resource": "*"
		}
	]
}
  1. Configure the AWS SDK with credentials for the IAM user created above
  • Need to set up AWS configuration so that aws cli command can be executed. Hint: use aws configure to configure user after installing awscli.
  1. cdk.py
import os
from pathlib import Path
from constructs import Construct
from aws_cdk import App, Stack, Environment, Duration, CfnOutput
from aws_cdk.aws_lambda import (
    DockerImageFunction,
    DockerImageCode,
    Architecture,
    FunctionUrlAuthType,
)

# environment setup like what region we should create resouce or stack in

my_environment = Environment(
    account=os.environ["CDK_DEFAULT_ACCOUNT"], region=os.environ["CDK_DEFAULT_REGION"]
)

class Imagenet1KClassifierFastApiStack(Stack):
    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        # Create Lambda function
        # Build Docker image from Dockerfile in the current directory.
        # The Dockerfile should contain necessary dependencies and commands to install fastapi and run the application.
        

        # Create stack and deploy Lambda function
        lambda_fn = DockerImageFunction(
            self,
            "Imagenet1KClassifierFastApi",
            code=DockerImageCode.from_image_asset(str(Path.cwd()), file="Dockerfile"),
            architecture=Architecture.X86_64,
            memory_size=1536,  # 1.5GB memory
            timeout=Duration.minutes(5), # 5 minutes timeout for the Lambda function
        )

        # Add HTTPS URL
        # If we want to expose the Lambda function via HTTPS, we can uncomment the following lines.
        fn_url = lambda_fn.add_function_url(auth_type=FunctionUrlAuthType.NONE)

        CfnOutput(self, "functionUrl", value=fn_url.url)

app = App()
fastapi_lambda = Imagenet1KClassifierFastApiStack(app, "Imagenet1KClassifierFastApiStack", env=my_environment)
app.synth()
  1. Bootstrap CDK
  • Set up the staging area (S3/ECR + roles) so CDK can deploy stuff into this account/region."
cdk bootstrap --profile cdk_lambda
 ⏳  Bootstrapping environment aws://575108919357/us-east-1...
Trusted accounts for deployment: (none)
Trusted accounts for lookup: (none)
Using default execution policy of 'arn:aws:iam::aws:policy/AdministratorAccess'. Pass '--cloudformation-execution-policies' to customize.
CDKToolkit: creating CloudFormation changeset...
 ✅  Environment aws://575108919357/us-east-1 bootstrapped.
  1. cdk synthesize
  • CDK takes your infrastructure code (written in TypeScript, Python, Java, C#, etc.), processes the constructs, and outputs the final CloudFormation JSON/YAML template that AWS will use to create resources.
  • Reads cdk.json to find the "app" command.
  • Executes that command to run your CDK app.
  • The app produces a construct tree in memory.
  • CDK synthesizes that tree into a CloudFormation templat
❯ cdk synthesize --profile cdk_lambda
  1. cdk deploy
  • Run CDK app → Executes the command in cdk.json to build the construct tree.
  • Synthesize CloudFormation template → Converts constructs into a CloudFormation template.
  • Upload assets (if any) → Stores Lambda code, Docker images, or static files in the bootstrap S3 bucket or ECR repo.
  • Deploy via CloudFormation → Submits the template to AWS CloudFormation to create/update resources.
  • Show outputs → Prints stack outputs (defined with CfnOutput) after deployment.
cdk deploy --profile cdk_lambda
Imagenet1KClassifierFastApiStack: start: Building Imagenet1KClassifierFastApiStack Template
Imagenet1KClassifierFastApiStack: success: Built Imagenet1KClassifierFastApiStack Template
Imagenet1KClassifierFastApiStack: start: Building Imagenet1KClassifierFastApiEndpoint/AssetImage
Imagenet1KClassifierFastApiStack: start: Publishing Imagenet1KClassifierFastApiStack Template (575108919357-us-east-1-1f947f23)
Imagenet1KClassifierFastApiStack: success: Published Imagenet1KClassifierFastApiStack Template (575108919357-us-east-1-1f947f23)
#0 building with "desktop-linux" instance using docker driver

#1 [internal] load build definition from Dockerfile
#1 transferring dockerfile: 790B 0.0s done
#1 DONE 0.1s

#2 [internal] load metadata for public.ecr.aws/docker/library/python:3.12-slim
#2 ...

#3 [internal] load metadata for public.ecr.aws/awsguru/aws-lambda-adapter:0.8.4
#3 DONE 0.8s

#2 [internal] load metadata for public.ecr.aws/docker/library/python:3.12-slim
#2 DONE 0.8s

#4 [internal] load .dockerignore
#4 transferring context: 2B done
#4 DONE 0.0s

#5 [internal] load build context
#5 ...

#6 FROM public.ecr.aws/awsguru/aws-lambda-adapter:0.8.4@sha256:e2653f741cd15851ba4f13f3cc47d29f2d14377c7d11737bfa272baa1b569007
#6 resolve public.ecr.aws/awsguru/aws-lambda-adapter:0.8.4@sha256:e2653f741cd15851ba4f13f3cc47d29f2d14377c7d11737bfa272baa1b569007 0.0s done
#6 DONE 0.1s

#7 [stage-0  1/10] FROM public.ecr.aws/docker/library/python:3.12-slim@sha256:d86b4c74b936c438cd4cc3a9f7256b9a7c27ad68c7caf8c205e18d9845af0164
#7 resolve public.ecr.aws/docker/library/python:3.12-slim@sha256:d86b4c74b936c438cd4cc3a9f7256b9a7c27ad68c7caf8c205e18d9845af0164 0.0s done
#7 DONE 0.1s

#5 [internal] load build context
#5 transferring context: 206.05MB 2.5s done
#5 DONE 2.5s

#8 [stage-0  4/10] COPY requirements.txt ./
#8 CACHED

#9 [stage-0  2/10] COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.8.4 /lambda-adapter /opt/extensions/lambda-adapter
#9 CACHED

#10 [stage-0  3/10] WORKDIR /var/task
#10 CACHED

#11 [stage-0  5/10] RUN pip install --no-cache-dir  -r requirements.txt
#11 CACHED

#12 [stage-0  8/10] COPY models/ ./models/
#12 CACHED

#13 [stage-0  6/10] COPY app.py ./
#13 CACHED

#14 [stage-0  7/10] COPY icons.py ./
#14 CACHED

#15 [stage-0  9/10] COPY sample_data/ ./sample_data/
#15 CACHED

#16 [stage-0 10/10] COPY imagenet_1k_classes.txt ./imagenet_1k_classes.txt
#16 CACHED

#17 exporting to image
#17 exporting layers 0.0s done
#17 exporting manifest sha256:bf942e5b3c34b2128e06a3d42c8e3511c47a79ed5fc5126a51fba39306daeafe 0.0s done
#17 exporting config sha256:c8c126d42f57073513c88db0b60a47d2774e7b1111f95e1659a31dc16284c3a1 done
#17 naming to docker.io/library/cdkasset-c597698f248729e62e68b8638036dc8cae50dc3c9649bc275f840fd4e8627c2a:latest done
#17 unpacking to docker.io/library/cdkasset-c597698f248729e62e68b8638036dc8cae50dc3c9649bc275f840fd4e8627c2a:latest 0.0s done
#17 DONE 0.1s

View build details: docker-desktop://dashboard/build/desktop-linux/desktop-linux/xp6p2rkj470mscfilnylgblq4

 1 warning found (use docker --debug to expand):
 - JSONArgsRecommended: JSON arguments recommended for CMD to prevent unintended behavior related to OS signals (line 25)
Imagenet1KClassifierFastApiStack: success: Built Imagenet1KClassifierFastApiEndpoint/AssetImage
Imagenet1KClassifierFastApiStack: start: Publishing Imagenet1KClassifierFastApiEndpoint/AssetImage (575108919357-us-east-1-de9ca719)
The push refers to repository [575108919357.dkr.ecr.us-east-1.amazonaws.com/cdk-hnb659fds-container-assets-575108919357-us-east-1]
eb061f016a6c: Waiting
1d96a644cf6c: Waiting
87d06d454ae0: Waiting
5349c7bc58ba: Waiting
6f14f522920b: Waiting
74df2916fcdf: Waiting
d7ecded7702a: Waiting
5c6c3d9dd6a6: Waiting
a7824fff34b8: Waiting
2f8bd7264c4d: Waiting
abbc1b010a9d: Waiting
a4f564a4a58f: Waiting
31ac69cb4246: Waiting
d7ecded7702a: Waiting
5c6c3d9dd6a6: Waiting
a7824fff34b8: Waiting
2f8bd7264c4d: Waiting
abbc1b010a9d: Waiting
a4f564a4a58f: Waiting
31ac69cb4246: Waiting
74df2916fcdf: Waiting
1d96a644cf6c: Waiting
87d06d454ae0: Waiting
5349c7bc58ba: Waiting
6f14f522920b: Waiting
eb061f016a6c: Waiting
87d06d454ae0: Waiting
5349c7bc58ba: Waiting
6f14f522920b: Waiting
eb061f016a6c: Waiting
1d96a644cf6c: Waiting
a7824fff34b8: Waiting
2f8bd7264c4d: Waiting
abbc1b010a9d: Waiting
a4f564a4a58f: Waiting
31ac69cb4246: Waiting
74df2916fcdf: Waiting
d7ecded7702a: Waiting
5c6c3d9dd6a6: Waiting
d7ecded7702a: Waiting
5c6c3d9dd6a6: Waiting
a7824fff34b8: Waiting
2f8bd7264c4d: Waiting
abbc1b010a9d: Waiting
a4f564a4a58f: Waiting
31ac69cb4246: Waiting
74df2916fcdf: Waiting
1d96a644cf6c: Waiting
87d06d454ae0: Waiting
5349c7bc58ba: Waiting
6f14f522920b: Waiting
eb061f016a6c: Waiting
a7824fff34b8: Waiting
a4f564a4a58f: Waiting
1d96a644cf6c: Waiting
87d06d454ae0: Pushed
5349c7bc58ba: Pushed
6f14f522920b: Pushed
abbc1b010a9d: Pushed
31ac69cb4246: Pushed
74df2916fcdf: Pushed
a7824fff34b8: Pushed
5c6c3d9dd6a6: Pushed
1d96a644cf6c: Pushed
a4f564a4a58f: Pushed
d7ecded7702a: Pushed
2f8bd7264c4d: Pushed
eb061f016a6c: Pushed
c597698f248729e62e68b8638036dc8cae50dc3c9649bc275f840fd4e8627c2a: digest: sha256:bf942e5b3c34b2128e06a3d42c8e3511c47a79ed5fc5126a51fba39306daeafe size: 2862
Imagenet1KClassifierFastApiStack: success: Published Imagenet1KClassifierFastApiEndpoint/AssetImage (575108919357-us-east-1-de9ca719)
Stack Imagenet1KClassifierFastApiStack
IAM Statement Changes
┌───┬────────────────────────────────────────────────────────┬────────┬──────────────────────────┬──────────────────────────────┬───────────┐
│   │ Resource                                               │ Effect │ Action                   │ Principal                    │ Condition │
├───┼────────────────────────────────────────────────────────┼────────┼──────────────────────────┼──────────────────────────────┼───────────┤
│ - │ ${Imagenet1KClassifierFastApi976C0932.Arn}             │ Allow  │ lambda:InvokeFunctionUrl │ *                            │           │
├───┼────────────────────────────────────────────────────────┼────────┼──────────────────────────┼──────────────────────────────┼───────────┤
│ - │ ${Imagenet1KClassifierFastApiServiceRole3DB02A53.Arn}  │ Allow  │ sts:AssumeRole           │ Service:lambda.amazonaws.com │           │
├───┼────────────────────────────────────────────────────────┼────────┼──────────────────────────┼──────────────────────────────┼───────────┤
│ + │ ${Imagenet1KClassifierFastApiEndpoint.Arn}             │ Allow  │ lambda:InvokeFunctionUrl │ *                            │           │
│ + │ ${Imagenet1KClassifierFastApiEndpoint.Arn}             │ Allow  │ lambda:InvokeFunction    │ *                            │           │
├───┼────────────────────────────────────────────────────────┼────────┼──────────────────────────┼──────────────────────────────┼───────────┤
│ + │ ${Imagenet1KClassifierFastApiEndpoint/ServiceRole.Arn} │ Allow  │ sts:AssumeRole           │ Service:lambda.amazonaws.com │           │
└───┴────────────────────────────────────────────────────────┴────────┴──────────────────────────┴──────────────────────────────┴───────────┘
IAM Policy Changes
┌───┬────────────────────────────────────────────────────┬────────────────────────────────────────────────────────────────────────────────┐
│   │ Resource                                           │ Managed Policy ARN                                                             │
├───┼────────────────────────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────┤
│ - │ ${Imagenet1KClassifierFastApiServiceRole3DB02A53}  │ arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole │
├───┼────────────────────────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────┤
│ + │ ${Imagenet1KClassifierFastApiEndpoint/ServiceRole} │ arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole │
└───┴────────────────────────────────────────────────────┴────────────────────────────────────────────────────────────────────────────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)


"--require-approval" is enabled and stack includes security-sensitive updates: 'Do you wish to deploy these changes' (y/n) y
Imagenet1KClassifierFastApiStack: deploying... [1/1]
Imagenet1KClassifierFastApiStack: creating CloudFormation changeset...

 ✅  Imagenet1KClassifierFastApiStack

✨  Deployment time: 87.39s

Outputs:
Imagenet1KClassifierFastApiStack.functionUrl = https://ckh4t2xwr7eicid3qpwxowwipq0ohxmf.lambda-url.us-east-1.on.aws/
Stack ARN:
arn:aws:cloudformation:us-east-1:575108919357:stack/Imagenet1KClassifierFastApiStack/dfd0a6c0-8dd1-11f0-adf6-0affca221267

✨  Total time: 140.12s

lambda fn deployed cloud formation stack

Testing Inference endpoint

https://ckh4t2xwr7eicid3qpwxowwipq0ohxmf.lambda-url.us-east-1.on.aws/

  1. wait for sometime (cold start lambda problem for 1st time)

lambda demo run

lambda monitor

lambda cloud watch

  1. cdk destroy
❯ cdk destroy
Are you sure you want to delete: Imagenet1KClassifierFastApiStack (y/n)? y
Imagenet1KClassifierFastApiStack: destroying... [1/1]

 ✅  Imagenet1KClassifierFastApiStack: destroyed

About

Deploy Resnet 50 Model trained on imagent-1k on AWS lambda

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published