서비스
이 섹션에서는 AI 서비스를 배포하는 방법에 대해 설명합니다.
현재 Nazare 에서는 AI 모델과 해당 모델을 구동하는 함수를 하나의 컨테이너로 배포하는 방법을 추천드리기 때문에 이를 기반으로 설명드리겠습니다.
파이썬 기반의 AI 서비스를 빠르고 쉽게 개발할 수 있도록, Nazare 로부터 ArrowIPC 를 이용하여 실시간 데이터를 전달받고 분석 결과를 전달하는 공용 런타임을 제공하고 있으며, 이를 이용하여 빠르게 Resnet50 모델 기반으로 이미지를 분류하는 서비스를 개발해 보겠습니다. 공용 런타임에서는 Nazare 로부터 ArrowIPC 를 이용하여 실시간 데이터를 전달받아 Pandas 데이터프레임으로 변환하여 사용자가 제공하는 함수에 전달하고, 사용자가 제공하는 함수에서 분석 결과를 Pandas 데이터프레임으로 전달하면 ArrowIPC 로 변환하여 Nazare 에 전달합니다.
아래 예제(onnx.py)를 보시면, 전달받은 데이터프레임(inputs)에서 이미지 주소(url)를 가져와서 AI 모델(resnet50)을 이용하여 분류한 다음, 이미지 주소(image)와 이미지 분류 결과(class)를 데이터프레임으로 만들어 전달합니다.
import os
import numpy as np
from skimage import io
from skimage.transform import resize
import onnxruntime
import pandas as pd
def inference(inputs):
images = []
classes = []
for row in inputs.itertuples():
image = row.url
input = resize(io.imread(image), (224, 224))
input = np.expand_dims(np.array(input, dtype=np.float32), axis=0)
input = np.array(np.repeat(input, 32, axis=0), dtype=np.float32)
input = np.transpose(input, (0, 3, 1, 2))
session = onnxruntime.InferenceSession(
os.getenv("ONNX_MODEL", "resnet50.onnx"),
providers=[os.getenv("ONNX_EXECUTION", "CPUExecutionProvider")],
)
output = session.run([], {"input.1": input})
output = np.array(output)
output = output.reshape(-1)
output = np.exp(output - np.max(output))
output = output / output.sum(axis=0)
output = output.tolist()
output = np.argmax(output)
images.append(image)
classes.append(output)
return pd.DataFrame({"image": images, "class": classes})
아래는 공용 런타임(ingkle/asruntime:pyruntime)을 이용하여 AI 모델과 위의 구동 함수를 컨테이너로 만드는 Dockerfile 입니다. 추가 패키지를 설치하고 AI 모델과 구동 함수를 복사한 다음, 몇 가지 환경 변수를 설정하면 필요한 준비는 모두 끝났습니다.
FROM ingkle/asruntime:pyruntime
RUN pip3 install numpy scikit-image onnxruntime
COPY onnx.py onnx.py
COPY resnet50.onnx resnet50.onnx
ENV PYTHONPATH=/opt
ENV ONNX_MODEL=resnet50.onnx
ENV ONNX_EXECUTION=CPUExecutionProvider
위의 컨테이너는 이미 공개해놓았으니(ingkle/asruntime:pyonnx) 자유롭게 사용하시고, Nazare 에 이를 배포하기 위해서는 아래와 같이 요청하시면 됩니다. 아래 요청에서 첫 번째 인자는 AI 서비스 이름(pyonnx)을 의미하고, 두 번째 인자는 사용할 컨테이너 이미지 주소(ingkle/asruntime:pyonnx)를, 그리고 세 번째 인자는 사용자가 제공하는 함수를 포함하고 있는 모듈의 이름(onnx)을 의미합니다.
CALL k8s@create_runtime('pyonnx', 'ingkle/asruntime:pyonnx', 'onnx');
위의 요청이 성공하면 Nazare 에 해당 컨테이너를 실행하는 파드(Pod)와 해당 파드에 접근할 수 있는 서비스(Service)가 생성된 것입니다. 아래 쿼리를 통해 위의 컨테이너가 정상적으로 동작 중인지 확인할 수 있습니다.
CALL k8s@check_runtime('pyonnx');
위의 쿼리 결과(result)가 'running' 이면 등록된 AI 서비스가 정상적으로 동작 중입니다.