KFServing InferenceService 배포와 예측 – Scikit-Learn

Scikit-Learn를 사용하는 InferenceService

학습이 완료된 scikit-learn모델을 피클로 저장 한 경우, KFServing에서 제공하는 sklearn 서버를 사용하여 간단히 배포 할 수 있습니다.

전제 조건

  • 모델 피클은 joblib을 사용하여 저장해야 합니다. 그리고 파일명은 model.joblib 이어야 합니다.
  • 현재 sklearn 0.20.3 버전을 사용합니다. 피클 모델은 이 버전과 호환되어야 합니다.

모델 생성

SKLearn 서버를 테스트하려면 먼저 파이썬을 사용하여 간단한 scikit-learn 모델을 생성해야합니다.

Scikit-learn의 기본적인 데이터셋 중의 하나인 아이리스 꽃 데이터를 사용하여, 아이리스 꽃을 분류하는 모델을 작성해 보겠습니다. 모델 피클은 joblib을 사용하여 저장해야 하고, 파일명은 model.joblib 이어야 합니다.

from joblib import dump
from sklearn import datasets
from sklearn import svm

clf = svm.SVC(gamma='scale')
iris = datasets.load_iris()
X, y = iris.data, iris.target
clf.fit(X, y)
dump(clf, 'model.joblib')

생성 된 모델을 사용하여 scikit-learn 서버를 실행하고 예측을 수행 할 수 있습니다. 모델은 PV, S3 호환 가능 개체 저장소, Azure Blob 저장소 또는 Google Cloud Storage에 있을 수 있습니다.

모델 저장하기

쿠버네티스의 퍼시스턴스 볼륨에 모델을 저장해 보겠습니다. PVC 는 앞서 생성한 kfserving-models-pvc 을 사용하겠습니다. 모델을 학습시키기 위해서 쿠버네티스 잡(Job)을 사용하겠습니다. Job을 생성할 때 모델을 저장하기 위한 PVC를 마운트 해줍니다.

모델 코드 작성하기

아이리스 꽃을 분류하는 간단한 모델입니다. 모델을 저장할 위치를 --model_path 파라미터로 입력받게 하였습니다.

iris.py

import argparse
import os

from joblib import dump
from sklearn import datasets
from sklearn import svm


def train():
    parser = argparse.ArgumentParser()
    parser.add_argument('--model_path', default='/mnt/pv/models/sklearn/iris', type=str)
    args = parser.parse_args()

    if not (os.path.isdir(args.model_path)):
        os.makedirs(args.model_path)

    model_file = os.path.join(args.model_path, 'model.joblib')

    clf = svm.SVC(gamma='scale')
    iris = datasets.load_iris()
    X, y = iris.data, iris.target
    clf.fit(X, y)
    dump(clf, model_file)


if __name__ == '__main__':
    train()

컨테이너 이미지를 만들기

컨테이너 이미지를 만들기 위한 Dockerfile 입니다. 파이썬을 기본 이미지로 사용하고, scikit-learn 패키지를 추가로 설치합니다.

Dockerfile

FROM python:3.6-slim

RUN pip install scikit-learn==0.20.3 joblib

RUN mkdir -p /app
ADD iris.py /app/

쿠버네티스 잡 실행하기

컨테이너 이미지를 빌드하고, 컨테이너 이미지 레지스트리에 푸시 한 다음, 쿠버네티스 잡(Job)을 생성하겠습니다.

Job을 생성할 때는 모델을 저장하기 위해서 PVC를 마운트 해줍니다. 이 일련의 작업들은 직접 실행 할 수 있습니다. 하지만 좀 더 편하게 하기 위해서 앞서 배운 Kubeflow Fairing을 사용하겠습니다.

다음은 로컬 개발 환경에서 Fairing을 사용하여 컨테이너 이미지를 만들고, 쿠버네티스 잡을 실행하는 예제입니다.

fairing-local-docker.py

import uuid
from kubeflow import fairing
from kubeflow.fairing.kubernetes import utils as k8s_utils

CONTAINER_REGISTRY = 'kangwoo'

namespace = 'admin'
job_name = f'sklean-iris-job-{uuid.uuid4().hex[:4]}'

command=["python", "iris.py", "--model_path", "/mnt/pv/models/sklearn/iris"]
output_map = {
    "Dockerfile": "Dockerfile",
    "iris.py": "iris.py"
}

fairing.config.set_preprocessor('python', command=command, path_prefix="/app", output_map=output_map)

fairing.config.set_builder('docker', registry=CONTAINER_REGISTRY, image_name="sklean-iris", dockerfile_path="Dockerfile")

fairing.config.set_deployer('job', namespace=namespace, job_name=job_name,
                            pod_spec_mutators=[k8s_utils.mounting_pvc(pvc_name='kfserving-models-pvc', pvc_mount_path='/mnt/pv')],
                            cleanup=False, stream_log=True)

fairing.config.run()

fairing을 실행하면 쿠버네티스 잡이 생성되고, 학습이 완료된 모델이 지정한 경로에 저장됩니다.

SKLearn을 사용하는 InferenceService 로 예측 하기

InferenceService 생성

InferenceService 매니페스트를 작성합니다. predictor로 sklearn 을 사용합니다. storageUri 필드로 모델 저장 위치를 지정해 줍니다. pvc 의 이름이 kfserving-models-pvc 이고 저장 위치가 models/sklearn/iris 이므로, pvc://kfserving-models-pvc/models/sklearn/iris 라고 지정해 줍니다.

sklearn.yaml

apiVersion: "serving.kubeflow.org/v1alpha2"
kind: "InferenceService"
metadata:
  name: "sklearn-iris"
spec:
  default:
    predictor:
      sklearn:
        storageUri: "pvc://kfserving-models-pvc/models/sklearn/iris"

InferenceService 를 생성합니다.

다음은 admin 네임스페이스 InferenceService 를 생성하는 예제입니다.

kubectl -n admin apply -f sklearn.yaml

생성한 InferenceService를 조회해 보겠습니다.

kubectl -n admin get inferenceservice

InferenceService 가 정상적으로 생성되면 다음과 같은 응답 결과를 확인할 수 있습니다.

NAME           URL                                                            READY   DEFAULT TRAFFIC   CANARY TRAFFIC   AGE
sklearn-iris   <http://sklearn-iris.admin.example.com/v1/models/sklearn-iris>   True    100                                19s

예측 실행하기

예측을 요청하기 위해서는 모델 서버에 접근해야 합니다. 모델 서버는 ingressgateway 를 통해서 접근할 수 있습니다. ingressgateway 는 모델 서버들을 구분하기 위해서 호스트 이름을 사용합니다. ingressgateway에 접근하 기 위한 주소는 앞서 정의한 CLUSTER_IP 를 사용하겠습니다.

예측을 요청할 데이터를 json 파일로 작성합니다.

iris-input.json

{
  "instances": [
    [6.8,  2.8,  4.8,  1.4],
    [6.0,  3.4,  4.5,  1.6]
  ]
}

다음은 admin 네임스페이스의 sklearn-iris InferenceService 에 예측을 요청하는 예제입니다.

MODEL_NAME=sklearn-iris
SERVICE_HOSTNAME=$(kubectl -n admin get inferenceservice sklearn-iris -o jsonpath='{.status.url}' | cut -d "/" -f 3)

INPUT_PATH=@./iris-input.json
curl -v -H "Host: ${SERVICE_HOSTNAME}" http://$CLUSTER_IP/v1/models/$MODEL_NAME:predict -d $INPUT_PATH

정상적으로 실행되면 다음과 같은 응답 결과를 확인 할 수 있습니다.

*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> POST /v1/models/sklearn-iris:predict HTTP/1.1
> Host: sklearn-iris.admin.example.com
> User-Agent: curl/7.64.1
> Accept: */*
> Content-Length: 76
> Content-Type: application/x-www-form-urlencoded
> 
* upload completely sent off: 76 out of 76 bytes
< HTTP/1.1 200 OK
< content-length: 23
< content-type: text/html; charset=UTF-8
< date: Sat, 29 Mar 2020 15:20:23 GMT
< server: istio-envoy
< x-envoy-upstream-service-time: 9032
< 
* Connection #0 to host localhost left intact
{"predictions": [1, 1]}

“KFServing InferenceService 배포와 예측 – Scikit-Learn”에 대한 4개의 댓글

  1. 안녕하세요. 좋은 글 올려주셔서 너무 감사합니다!
    근데 한 가지 궁금한 점이 있어서요!
    inferenceservice 까지 만들었는데 상태가 False가 떠서.. 혹시 무엇 때문에 그럴까요.. 흠.. 이 부분에서 진행이 안되네요.. ㅎㅎ

    01. fairing 돌리면 아래처럼 파드는 생성 됐습니다.
    [W 200517 14:07:28 manager:296] Waiting for sklean-iris-job-b2bd-f5c9f to start…
    [I 200517 14:08:19 manager:302] Pod started running True

    02. 파드 조회도 정상적으로 되구요. completed 가 맞을까요?
    $ kubectl get po -n anonymous
    NAME READY STATUS RESTARTS AGE
    sklean-iris-job-b2bd-f5c9f 0/1 Completed 0 2m27s

    03. inferenceservice도 메니페스트 정상 실행 된 것 같은데..
    $ kubectl -n anonymous apply -f sklearn.yaml
    inferenceservice.serving.kubeflow.org/sklearn-iris created

    04. 막상 조회를 해보면 False가..
    kubectl get inferenceservice -n anonymous
    NAME URL READY DEFAULT TRAFFIC CANARY TRAFFIC AGE
    sklearn-iris False 16s

    혹시 이런 경우 없으셨나요??

    1. 이 부분이 사용하는 쿠버네티스 환경에 따라서 좀 다릅니다.
      정확한 답변을 위해서는 사용하 쿠버네티스 환경이랑, kubeflow 환경, istio 설정 정보가 필요한데, 그냥 추측해서 말씀드리겠습니다.
      kubeflow 1.0 + 인증 환경이라면,istio-ingressgateway 에는 인증(?) 부분이 부여되어 있어서, 일반적인 방법으로는 접근이 차단됩니다.
      그래서 별도의 ingressgateway 를 만들어서 사용하는게 편합니다.
      주말쯤에 정리해서 올리도록 해볼께요.

      1. 답글 주셔서 감사합니다 ㅎㅎ
        사용하고 있는 환경에 대해 간단히 말씀드리자면
        – k8s: azure aks 1.15.10
        – registry: azure acr
        – kubeflow: 1.0.1
        – istio: 1.1.6 (버전 확인법을 몰라 대략 추측.. istio namespace의 pods들을 보면 대부분 1.1.6 이라..)
        – kfserving: 0.2.2
        정도인 것 같습니다~

        꼭 참고해보겠습니다.
        개념적으로도 제겐 어려운데 beta버전이라 더욱 복잡한 것 같내요 ㅠㅠ
        좋은 글 항상 감사합니다!

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다