본문 바로가기

MLOps

Ensemble with Seldon Core

머신러닝에서 앙상블(ensemble)은 여러 모델의 예측을 결합하여 최종 결과를 내는 기법을 의미한다. 예를 들면 분류(classification) 문제에서 가장 많은 모델이 선택한 클래스(class)를 최종 답으로 채택하거나 회귀(regression) 문제에서 여러 모델의 예측값을 가중치 평균내는 것이다. 그 외에도 여러 앙상블 기법들이 있다.

 

이번 포스트에서는 셀던 코어의 combiner라는 기능을 이용하여 앙상블 파이프라인을 쿠버네티스에 배포해보고자 한다.

 

Ensemble Pipeline 설계

모델 A와 모델 B의 결과를 앙상블하는 파이프라인이다. 두 모델은 전처리된 데이터를 받은 다음 예측값을 combiner 컴포넌트에게 보낸다. Combiner는 두 모델의 예측값을 결합하여 최종 결과를 도출한다.

 

A/B Testing with Seldon Core에서 만든 전처리와 모델 A, B의 inference 도커 이미지를 재사용할 것이다. Combiner 컴포넌트의 도커 이미지만 새로 빌드하면 된다. 우리의 파이프라인에서는 combiner가 모델 A와 모델 B의 예측값들을 평균 내도록 구현할 것이다.

 

Combiner 컴포넌트 구현 및 도커 이미지 빌드

Combiner.py에 구현해보자. 셀던 코어에서 여러 child 컴포넌트의 아웃풋을 받아 결합하는 기능을 가진 컴포넌트의 컴포넌트 타입이 COMBINER이다.

 

from seldon_core.user_model import SeldonComponent
import numpy as np

class Combiner(SeldonComponent):
    def __init__(self):
    	super(Combiner, self).__init__()
        
    def aggregate(self, Xs, features_names=None):
        x = np.stack(Xs, axis=0)
        return np.mean(x, axis=0)

 

aggregate 함수 안에 child 컴포넌트들의 아웃풋을 평균내는 코드를 구현하였다. 파라미터 Xs에 child 컴포넌트들의 아웃풋, 즉 이 문제에서는 모델 A와 모델 B의 예측값을 담은 list가 들어온다.

 

아래 도커파일을 작성하고 이미지 빌드, 푸쉬하면 된다.

 

FROM python:3.7
RUN mkdir /home/app && chmod -R 777 /home/app

COPY ./Combiner.py /home/app/Combiner.py
WORKDIR /home/app

EXPOSE 9000

ENV GUNICORN_WORKERS {구니콘 워커 수}
ENV MODEL_NAME Combiner
ENV SERVICE_TYPE COMBINER

RUN pip install numpy==1.18.5 seldon-core==1.6.0

CMD exec seldon-core-microservice $MODEL_NAME --service-type $SERVICE_TYPE --workers $GUNICORN_WORKERS

 

YAML 파일 작성

앙상블 파이프라인을 위한 seldon_deployment.yaml을 작성하자.

 

apiVersion: machinelearning.seldon.io/v1alpha2
kind: SeldonDeployment
metadata:
  labels:
    app: seldon
  name: ensemble
spec:
  name: ensemble-deployment
  predictors:
  - componentSpecs:
    - spec:
        containers:
        - image: {전처리 컴포넌트 이미지 URL}
          imagePullPolicy: Always
          name: {전처리 컨테이너 이름}
          resources:
            requests:
              cpu: "2"
              memory: 1Gi
            limits:
              cpu: "4"
              memory: 2Gi
        - image: {Combiner 컴포넌트 이미지 URL}
          imagePullPolicy: Always
          name: {Combiner 컨테이너 이름}
          resources:
            requests:
              cpu: "2" 
              memory: 1Gi
            limits:
              cpu: "4"
              memory: 2Gi
        - image: {Inference 컴포넌트 이미지 URL}
          imagePullPolicy: Always
          name: {모델 A inference 컨테이너 이름}
          resources:
            requests:
              cpu: "1" 
              memory: 1Gi
            limits:
              cpu: "2"
              memory: 2Gi         
        - image: {Inference 컴포넌트 이미지 URL}
          imagePullPolicy: Always
          name: {모델 B inference 컨테이너 이름}
          resources:
            requests:
              cpu: "1" 
              memory: 1Gi
            limits:
              cpu: "2"
              memory: 2Gi   
    graph:
      name: {전처리 컨테이너 이름}
      endpoint:
        type: REST
      type: TRANSFORMER
      parameters:
        - name: container_name
          type: STRING
          value: 
        - name: run_name
          type: STRING
          value:
      children:
        - name: {Combiner 컨테이너 이름}
          endpoint:
            type: REST
          type: COMBINER
          children:
            - name: {모델 A inference 컨테이너 이름}
              endpoint:
                type: REST
              type: MODEL
              parameters:
                - name: container_name
                  type: STRING
                  value:
                - name: run_name
                  type: STRING
                  value:
              children: []
            - name: {모델 B inference 컨테이너 이름}
              endpoint:
                type: REST
              type: MODEL
              parameters:
                - name: container_name
                  type: STRING
                  value:
                - name: run_name
                  type: STRING
                  value:
              children: []            
    name: ensemble-deployment
    replicas: {Pod 개수}

 

새로운 모델을 추가하고 싶으면 spec > predictors > componentSpecs > spec > containers에 컨테이너를 추가하고 ('image: {Inference 컴포넌트 이미지 URL}') graph에서 combiner 컨테이너의 children에 새로 추가해주면 된다.

 

Kubernetes에 배포하고 요청 보내는 방법은 A/B Testing 파이프라인과 동일하다.

 

 

 

'MLOps' 카테고리의 다른 글

AWS Serverless 1편  (0) 2023.01.02
Amazon SageMaker  (0) 2022.04.25
Multi-Armed Bandit with Seldon Core  (0) 2022.02.20
셀던 코어와 텐서플로우 서빙  (0) 2022.02.07
A/B Testing with Seldon Core  (0) 2022.02.07