RESNET-50를 사용하는 AWS의 DLR(Deep Learning Runtime) 이미지 분류 모델을 이용하여 추론을 수행하고자 합니다.
전체적인 Architecture는 아래와 같습니다. 이미지 분류를 사용하는 Client는 RESTful API로 syncronous하게 이미지를 분류할 수 있습니다. API요청시 API Gateway의 address를 Endpoint로 이용합니다. 이때 API 이름으로 "/classifier"를 이용하면 API Gateway와 연결된 Lambda로 요청이 event의 형태로 인입되어서, 이미지 분류를 위한 추론이 수행됩니다. Lambda는 Container로 배포되는데 이미지 추론에는 DLR Model을 사용합니다. Lambda Function URL이 아닌 API Gateway를 사용하는것은 외부에서 public하게 open되는 케이스를 고려하기 위함입니다. Lambda 및 API Gateway의 배포시에 AWS CDK와 ECR을 이용합니다.
event의 "body-json"으로 들어온 upload된 이미지를 base64로 encoding후 UTF8로 decoding하여 이미지 데이터를 추출 합니다.
data = base64.b64decode(event['body-json'])
# convert string of image data to uint8
encoded_img = np.fromstring(data, dtype = np.uint8)
image_data = cv2.imdecode(encoded_img, cv2.IMREAD_COLOR)
이미지 데이터를 json 포맷으로 바꾸어 추론(inference)를 수행하는 inference.py에 아래와 같이 요청합니다. 추론결과의 가장 높은 확율을 가지는 object의 label을 리턴합니다.
event = {
'body': image_data
}
try:
result = inference.handler(event,"")
return result['body'][0]['Label']
except:
traceback.print_exc()
Container 생성시 필요한 Dockerfile은 아래와 같습니다.
FROM amazon/aws-lambda-python:3.8
RUN pip3 install --upgrade pip
RUN pip3 install scikit-build wheel
RUN pip3 install opencv-python==4.6.0.66
RUN python -m pip install joblib awsiotsdk pandas
RUN yum install libglvnd-glx -y
RUN python -m pip install dlr
RUN pip3 install dlr==1.6.0
WORKDIR /var/task/image-classifier
COPY inference.py /var/task
COPY classifier.py /var/task
COPY . .
CMD ["classifier.run"]
인프라 설치는 아래와 같이 수행합니다.
git clone https://github.com/kyopark2014/image-classification-api-server
cd cdk-lambda-api && npm install aws-cdk-lib@2.64.0 path
cdk deploy
배포후 아래와 같은 값을 얻습니다.
여기서 ApiGatewayUrl의 주소는 "https://f8wr4q0nlj.execute-api.ap-northeast-2.amazonaws.com/dev/classifier" 와 같고 Web으로 접속할 주소는 "https://d1twzjcpb87z2n.cloudfront.net/classifier.html"임을 알 수 있습니다.
아래와 같이 Web으로 접속해서 [Choose File]을 선택하여 이미지를 지정하고 [Send]를 선택하여 Classification을 요청합니다.
Postman을 이용해 테스트시에 아래와 같이 수행합니다.
- Content-Type으로 "image/jpeg"을 입력합니다.
- body에서 파일을 선택합니다.
아래와 같은 이미지를 업로드합니다.
이때의 결과는 아래와 같습니다.
{
"statusCode": 200,
"label": "Weimaraner"
}
- "label": "cup"
- "label": "coffee mug"
- "label": "ashcan, trash can, garbage can, wastebin, ash bin, ash-bin, ashbin, dustbin, trash barrel, trash bin"
- "label": "sports car, sport car"
- "label": "crash helmet"