1편에서 생성한 Lambda의 스펙을 다시 한번 살펴보고 이번에는 구체적으로 해석해보자.
ApiFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName:
Fn::Sub: ${StageName}-mlops-api-function
Handler: lambda_invoke.lambda_handler
Runtime: python3.7
CodeUri: s3://your-bucket/serverless/code.zip
Environment:
Variables:
LOG_LEVEL:
Ref: LogLevel
STAGE_NAME:
Ref: StageName
애플리케이션의 기능을 구현한 코드는 "your-bucket"이라는 이름의 s3 버킷에 "serverless/code.zip"이라는 zip 파일로 저장되어있다. 이 zip 파일을 열어보면 lambda_invoke.py라는 파일이 있고 그 안에 lambda_handler라는 함수에 애플리케이션의 핵심 기능이 구현되었다. 본 Lambda를 호출할 때마다 이 함수가 실행되는 것이다. 템플릿에서 선언한 환경 변수 LOG_LEVEL과 STAGE_NAME은 os 라이브러리를 이용하여 접근할 수 있다.
lambda_handler에 SageMaker 엔드포인트로부터 머신러닝 모델 추론 결과를 받아서 응답으로 내보내는 로직을 구현해보자. "SM_ENDPOINT_TEST"라는 이름의 SageMaker 엔드포인트가 미리 배포되었다고 가정하고 해당 엔드포인트에 학습된 "resnet"과 "vggnet"이라는 모델들이 서빙 중이라고 가정하자. SageMaker 엔드포인트와 통신하기 위하여 boto3 sagemaker-runtime client가 필요하다.
import boto3
import random
import json
import os
import logging
LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO").upper()
STAGE_NAME = os.environ["STAGE_NAME"]
logger = logging.getLogger()
logger.setLevel(LOG_LEVEL)
sm_runtime = boto3.client("sagemaker-runtime")
def lambda_handler(event, context):
path = event["path"]
data = event["body"]
method = event["httpMethod"]
content_type = "application/json"
if path == "/api/v1/resnet":
variant_name = "resnet"
elif path == "/api/v1/vggnet":
variant_name = "vggnet"
response = sm_runtime.invoke_endpoint(
EndpointName="SM_ENDPOINT_TEST",
ContentType=content_type,
TargetVariant=variant_name,
Body=data
)
invoked_variant = response["InvokedProductionVariant"]
predictions = json.loads(response["Body"].read())["predictions"]
result = {
"invoked_variant": invoked_variant,
"predictions": predictions
}
status_code = 200
return {"statusCode": status_code, "body": json.dumps(result)}
Lambda로 실행될 함수는 event와 context라는 인자를 받는다. event 인자에는 요청에 관한 각종 정보가 들어있다.
- event["path"] : 클라이언트가 요청을 보낸 url 경로로 {HOST-NAME}/dev 뒷 부분. String 타입.
- event["body"] : 요청 바디. JSON 타입.
- event["httpMethod"] : Http 메서드 타입. String 타입. ex."GET", "POST", "PUT", ...
편의상 배포 stage를 dev로 가정했다. 요청 경로가 "{HOST-NAME}/dev/api/v1/resnet"인 경우 "resnet", "{HOST-NAME}/dev/api/v1/vggnet"인 경우 "vggnet" 모델로 추론 요청을 보내도록 했다. 돌아오는 response는 파이썬 딕셔너리 타입으로 추론에 사용된 모델/variant의 이름과 추론 결과 값을 갖고 있다. 예시 코드에서 사용된 variant의 이름을 invoked_variant, 추론 결과값을 predictions라는 변수에 담았다.
마지막으로 lambda_handler는 다음 형식의 딕셔너리를 반환해야한다.
{
"statusCode" : Http 상태 코드. Int 타입,
"body" : 응답 바디. JSON 타입.
}
'MLOps' 카테고리의 다른 글
Triton Python Backend 사용하기 (1) | 2023.05.14 |
---|---|
NVIDIA Triton 한 눈에 알아보기 (0) | 2023.01.09 |
AWS Serverless 1편 (0) | 2023.01.02 |
Amazon SageMaker (0) | 2022.04.25 |
Multi-Armed Bandit with Seldon Core (0) | 2022.02.20 |