AWS Lambda, Docker 및 AWS CDK를 사용하여 Tensorflow 모델을 생산에 투입

Tensorflow 모델을 Lambda에 배포할 수 있도록 이전 기사에서 개념을 함께 가져옵니다. 이 기사는 Lambda에 모델을 배포하는 방법에 관한 것이므로 모델 교육이나 모델 사용에 대해서는 다루지 않겠습니다.
  • Tensorflow 라이브러리를 보유할 수 있을 만큼 큰 Lambda 함수를 구축하려면 .
  • 예측 시간을 개선하기 위해 다음을 수행할 수 있습니다. 이렇게 하면 대부분 S3에서 모델을 로드하지 않아도 됩니다.
  • 예측 결과를 얻기 위해 HTTP GET( )을 사용하여 쿼리할 수 있는 HTTPS 끝점을 노출하는 데 사용합니다.
  • , Joblib를 사용합니다.

  • Github 저장소를 찾을 수 있습니다here.

    스택과 기능 구축을 시작합시다!

    스택 설계



    나는 우리가 찾고 있는 기능을 유지하면서 이 디자인을 가능한 한 최소화하려고 노력했습니다. 연결된 파일 시스템을 포함하여 Tensorflow가 설치된 도커 배포 Lambda 함수와 HTTP로 쿼리할 수 있는 HTTPS 엔드포인트가 있습니다. GET 메시지.

    from aws_cdk import CfnOutput as Output
    from aws_cdk import CfnResource, Duration, RemovalPolicy, Stack
    from aws_cdk import aws_ec2 as ec2
    from aws_cdk import aws_efs as efs
    from aws_cdk import aws_lambda as _lambda
    from aws_cdk import aws_s3 as s3
    from aws_cdk import aws_s3_deployment as s3_deployment
    from constructs import Construct
    
    
    class CdkTensorflowStack(Stack):
        def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
            super().__init__(scope, construct_id, **kwargs)
    
            # Let's list all of our physical resources getting deployed
            self.vpc = None
            self.access_point = None
            self.prediction_lambda = None
            self.models_bucket = None
    
            # convenient deployment
            self.build_infrastructure()
    
        def build_infrastructure(self):
            self.build_vpc()
            self.build_filesystem()
            self.build_lambda()
            self.build_bucket()
            self.build_function_url()
    
        def build_vpc(self):
            # Need the VPC for the lambda filesystem
            self.vpc = ec2.Vpc(scope=self, id="VPC", vpc_name="ExampleVPC")
    
        def build_filesystem(self):
            file_system = efs.FileSystem(
                scope=self,
                id="ExampleEFS",
                vpc=self.vpc,
                file_system_name="ExampleEFS",
                removal_policy=RemovalPolicy.DESTROY,
            )
            # create a new access point from the filesystem
            self.access_point = file_system.add_access_point(
                "AccessPoint",
                # set /export/lambda as the root of the access point
                path="/export/lambda",
                # as /export/lambda does not exist in a new efs filesystem, the efs will create the directory with the following createAcl
                create_acl=efs.Acl(
                    owner_uid="1001", owner_gid="1001", permissions="750"
                ),
                # enforce the POSIX identity so lambda function will access with this identity
                posix_user=efs.PosixUser(uid="1001", gid="1001"),
            )
    
        def build_lambda(self):
            self.prediction_lambda = _lambda.DockerImageFunction(
                scope=self,
                id="TensorflowLambda",
                function_name="TensorflowLambda",
                code=_lambda.DockerImageCode.from_image_asset(
                    directory="lambda_funcs/TensorflowLambda"
                ),
                # I've found inferences can be made with my simple model in < 20 sec
                timeout=Duration.seconds(60 * 0.5),
                memory_size=128 * 6 * 1,  # mb
                # Attach the EFS file system
                filesystem=_lambda.FileSystem.from_efs_access_point(
                    ap=self.access_point, mount_path="/mnt/models"
                )
                if self.access_point
                else None,
                # Needs to be placed in the same VPC as the EFS file system
                vpc=self.vpc,
            )
    
        def build_bucket(self):
            self.models_bucket = s3.Bucket(
                scope=self,
                id="ExampleModelsBucket",
                bucket_name="models-bucket",
                # These settings will make sure things get deleted when we take down the stack
                removal_policy=RemovalPolicy.DESTROY,
                auto_delete_objects=True,
            )
            # We can add files to our new bucket from a local source
            s3_deployment.BucketDeployment(
                self,
                "save_model_to_s3",
                sources=[s3_deployment.Source.asset("model_files")],
                destination_bucket=self.models_bucket,
            )
            # Make sure to give the lambda permission to retrieve the model file
            self.models_bucket.grant_read(identity=self.prediction_lambda)
    
        def build_function_url(self):
            # Set up the Lambda Function URL
            cfnFuncUrl = CfnResource(
                scope=self,
                id="lambdaFuncUrl",
                type="AWS::Lambda::Url",
                properties={
                    "TargetFunctionArn": self.prediction_lambda.function_arn,
                    "AuthType": "NONE",
                    "Cors": {"AllowOrigins": ["*"]},
                },
            )
    
            # Give everyone permission to invoke the Function URL
            CfnResource(
                scope=self,
                id="funcURLPermission",
                type="AWS::Lambda::Permission",
                properties={
                    "FunctionName": self.prediction_lambda.function_name,
                    "Principal": "*",
                    "Action": "lambda:InvokeFunctionUrl",
                    "FunctionUrlAuthType": "NONE",
                },
            )
    
            # Get the Function URL as output
            Output(
                scope=self,
                id="funcURLOutput",
                value=cfnFuncUrl.get_att(attribute_name="FunctionUrl").to_string(),
            )
    
    


    람다 함수 설계



    cdk_tensorflow/lambda_funcs/TensorflowLambda/tensorflow_lambda.py



    다시 말하지만, 최소한의 작업 예제를 보여주려고 합니다. 이 Lambda 함수는 EFS에서 모델을 로드하려고 시도합니다. 찾을 수 없는 경우(처음 실행할 때와 같이) 생성한 S3 버킷에서 모델을 복사하고 EFS에 저장한 다음 다시 로드합니다. 모델이 로드되면 이를 사용하여 추론할 수 있습니다. 처리기는 추론을 쿼리한 클라이언트로 다시 보냅니다.

    # import tempfile
    from pathlib import Path
    from typing import Tuple
    
    import boto3
    import joblib
    
    
    def get_model() -> Tuple:
        """
        Gets model from EFS if exists. Otherwise load model from S3, save to EFS
        """
        local_path = Path(f"/mnt/models/model.tensorflow")
        try:
            with open(local_path, "rb") as f:
                f.seek(0)
                model = joblib.load(f)
        except FileNotFoundError:
            client = boto3.client("s3")
            # Save model to EFS
            client.download_file(
                "models-bucket",
                "model.tensorflow",
                str(local_path),
            )
    
            with open(local_path, "rb") as f:
                f.seek(0)
                model = joblib.load(f)
    
        return model
    
    
    model = get_model()
    
    
    def get_prediction(model, input_data):
        # Do what you need to do to feed input data to your model
        return 1
        # return output_data
    
    
    def handler(event, context):
        # This is the data we get from the client query
        data = event["queryStringParameters"]["q"]
        # I pass the data as a list to the API, but it gets converted into a string.
        # This is some fancy way to get back the list from the str(list)
        split_str = data.split(",")
        formatted_data = (
            [float(split_str[0].split("[")[-1])]
            + [float(y) for y in split_str[1:-1]]
            + [float(split_str[-1].split("]")[0])]
        )
        assert isinstance(formatted_data, list)
    
        # Get a prediction by feeding your formatted input data into model
        prediction = get_prediction(model=model, input_data=formatted_data)
        response = {
            "isBase64Encoded": False,
            "statusCode": 200,
            "headers": {
                "Access-Control-Allow-Origin": "*",
            },
            "body": f"The predicted value is {prediction}",
        }
    
        return response
    
    


    cdk_tensorflow/lambda_funcs/TensorflowLambda/Dockerfile



    Lambda 함수를 빌드하기 위한 빌드 지침을 제공합니다.

    FROM amazon/aws-lambda-python:latest
    
    LABEL maintainer="Wesley Cheek"
    RUN yum update -y && \
        yum install -y python3 python3-dev python3-pip gcc && \
        rm -Rf /var/cache/yum
    COPY requirements.txt ./
    RUN pip install -r requirements.txt
    COPY tensorflow_lambda.py ./
    
    CMD ["tensorflow_lambda.handler"]
    


    cdk_tensorflow/lambda_funcs/TensorflowLambda/requirements.txt




    joblib
    # I use tensorflow-cpu because it's half the size of the gpu version and Lambda doesn't have a GPU anyway.
    tensorflow-cpu
    boto3
    


    전개


    cdk deploy를 실행할 수 있으며 인프라가 자동으로 배포됩니다. 폴더model_files의 모든 파일은 생성한 s3 버킷에 업로드됩니다. Lambda 함수는 Docker를 사용하여 번들로 제공되며 ECR에 저장됩니다.

    Lambda 함수 테스트 및 쿼리



    테스트는 모델에 따라 다릅니다. 시작하기에 충분한 개요를 알려드렸기를 바랍니다. 새로 배포된 Lambda 함수로 데이터를 보내려면 CDK 배포가 완료된 후의 출력 또는 AWS Lambda 콘솔에서 함수 URL을 찾을 수 있습니다.



    아래에 표시된 데이터는 "hello!"입니다. - 당신에게는 무엇이든 될 수 있습니다. 예를 들어 내 모델은 값 목록을 받습니다.



    완료되면 요금이 부과되지 않도록 cdk destroy를 확인하십시오!

    이 기사가 Lambda를 사용하여 신경망 또는 기타 기계 학습 알고리즘을 배포하는 데 좋은 출발점이 되었기를 바랍니다.

    좋은 웹페이지 즐겨찾기