[내일 출근인데 어떡하지] MLOps : Triton 으로 모델 배포하기 🪐

Judy·2023년 7월 2일
2

앞서 TorchServe 를 소개했는데요,
이번에는 Nvidia 에서 발표한 Inference server 인 'Triton' 을 소개합니다.

Triton

Triton 의 풀네임(?) 은 Triton inference server 인데요,
저는 TorchServe 에서는 쓰이지 않던 ‘Inference server’ 라는 명칭에 주목했습니다.
과연 'Inference server' 는 일반 모델 서빙 프레임워크와 어떤 차이가 있을까요?

Triton 공식 홈페이지에서 내세우는 장점은 다음과 같습니다.

  • TF, pytorch, onnx, TensorRT 프레임워크 지원
    • *앞서 소개한 TorchServe 는 pytorch 로 개발한 모델 내지 torchscript 로 변환한 모델만 배포 가능한데
      Triton 은 다양한 프레임워크로 개발한 모델을 지원할 수 있는 장점이 있네요.
  • 하드웨어 활용 극대화
    • *같은 WS에서 torchserve 는 CUDA out of memory 발생!
  • 모델 동시 실행
    • 특정 모델의 여러 복사본과 서로 다른 복수의 모델들을 동일한 GPU에서 병렬로 실행 가능
  • 모델 배포 프로세스 간소화
    • Model Navigator
      • 프레임워크의 종류(이번 릴리스에서는 TensorFlow와 PyTorch가 지원됩니다)와 상관없이 입력 모델을 TensorRT로 변환하고 그에 따른 정확도를 검증하며, 최적의 모델 구성을 자동으로 찾고 생성
      • 모델 배포를 위한 repo 구조 생성
  • Inference 성능 최적화
    • Triton Model Analyzer
      • 사용자의 제약 조건 하에서 최상의 성능을 구현하는 구성을 찾음
  • 모니터링 지원

Usage

Triton 은 Pytorch, TensorFlow, Onnx, TensorRT 4가지 프레임워크를 지원합니다.
저는 TorchServe 와 비교하기 위해 조건을 똑같이 맞춰서 PyTorch 배포만을 설명하겠습니다.

  1. 모델, 토크나이저 학습 후 저장
    모델과 토크나이저를 Pytorch 로 각각 학습시킨 후 저장합니다.

  2. Nvidia version check
    현재 사용중인 cuda 버전을 확인하고, Nvidia 공식 docker image 배포 사이트에서 cuda 버전과 맞는 이미지 버전을 찾습니다.
    예를 들어, 저는 cuda 11.7 버전을 사용중이므로 triton docker 이미지는 해당 cuda 버전을 지원하는 22.05 버전을 이용하겠습니다.
    Triton Inference Server Release Note
    (공식 docker image는 여기에서 다운로드할 수 있는데,
    https://catalog.ngc.nvidia.com/orgs/nvidia/containers/tritonserver/tags
    공식 튜토리얼을 따라하면 docker run 을 이용하므로 이미지를 여기서 따로 다운로드할 필요는 없습니다.)

  3. Pytorch 모델을 TorchScript 로 변환

  4. Inference server 세팅

    • 모델 리포지토리 지정
      • TorchScript 로 변환한 모델을 지정된 리포지토리에 저장
    • config.pbtxt 작성
      • 모델 input, output 값의 data type 과 dimension 지정
    • docker container 생성
  5. Client Server 세팅 & Inference (query to server)

    • Client 서버 docker container 생성
    • 4에서 생성한 Inference server 에 inference query 전송 (=Inference)

Practice!

Usage 3번부터 공식 튜토리얼에 따라 진행하겠습니다.

1. Export the model

  1. PyTorch 모델을 Torchscript 로 변환하기 위해 환경 세팅을 하겠습니다.
    개인적으로 Triton 튜토리얼의 흥미로운 점은 대부분 docker container 를 생성하는 형태로 환경을 세팅한다는 점입니다.
sudo docker run -it --gpus all -v ${PWD}:/workspace nvcr.io/nvidia/pytorch:22.05-py3
  1. -it 옵션으로 실행하였기 때문에 container 가 생성되면 곧바로 container 의 bash shell 로 진입할 텐데요,
    bash shell 에서 바로 pytorch 모델을 torchscript 로 변환하는 파이썬 코드를 실행시켜 줍니다.
import os

import torch
from scipy.special import softmax
import numpy as np

from transformers import AutoTokenizer, AutoModelForSequenceClassification
import urllib.request
import csv

tokenizer = AutoTokenizer.from_pretrained("cardiffnlp/twitter-roberta-base-sentiment")

origin_model = AutoModelForSequenceClassification.from_pretrained("cardiffnlp/twitter-roberta-base-sentiment", return_dict=False)

text = "Good night 😊"
encoded_input = tokenizer(text, return_tensors='pt')
folder_save = "twitter-roberta-base-sentiment"
if not os.path.exists(folder_save):
    os.mkdir(folder_save)

cpu_traced = torch.jit.trace(origin_model, (encoded_input["input_ids"], encoded_input["attention_mask"]))

torch.jit.save(cpu_traced, os.path.join(folder_save, "model.pt"))
tokenizer.save_pretrained(folder_save)

실행이 끝나면 model.pt 가 생성됩니다.

2. Set Up Triton Inference Server

  1. 모델 리포지토리를 지정하고, 파일을 옮기고 새로 생성합니다.
    지정된 구조대로 리포지토리를 지정하면 Inference Server 구동 시 알아서 경로를 참조해서 모델을 불러 옵니다.
model_repository
|
+-- roberta
    |
    +-- config.pbtxt
    +-- 1
        |
        +-- model.pt
  1. config.pbtxt 파일 내용을 작성합니다.
    이 파일은 모델 input 및 output 값의 데이터 타입과 차원을 정의하는 역할을 합니다.
    RoBERTa 의 경우 다음과 같이 작성합니다.
name: "roberta"
platform: "pytorch_libtorch"
input [
 {
    name: "input__0"
    data_type: TYPE_INT32
    dims: [1, 256]
  },
  {
    name: "input__1"
    data_type: TYPE_INT32
    dims: [1, 256]
  }
]
output {
    name: "output__0"
    data_type: TYPE_FP32
    dims: [1, 3]
  }
  1. Inference server docker container 를 생성하여 inference server 를 구동시킵니다.
sudo docker run --gpus all --rm \
-p <custom port>:8000 \
-p <custom port>:8001 \
-p <custom port>:8002 \
-v ${PWD}/model_repository:/models nvcr.io/nvidia/tritonserver:22.05-py3 \
tritonserver --model-repository=/models

여기서 8000 포트는 http, 8001 포트는 grpc, 8002 포트는 metric (측정) 을 위해 사용됩니다.

모델이 정상적으로 로드되면 container log 에서 확인할 수 있습니다.

3. Using a Triton Client to Query the Server

Inference server 에 쿼리를 날려 inference 즉 추론을 하기 위해 client server 를 생성합니다.
마찬가지로 docker container 를 생성하여 client server 를 구동시킵니다.
이 때 docker image 는 sdk 를 이용합니다.

sudo docker run -it --net=host -v ${PWD}:/workspace/ nvcr.io/nvidia/tritonserver:22.05-py3-sdk bash

-it 옵션을 주어 실행시켰으므로 1번과 마찬가지로 컨테이너의 bash shell 로 바로 진입할 텐데요,
여기서 inference 파이썬 코드를 실행시켜 inference server 로 쿼리를 날려 추론을 수행합니다.

  • 현재 예시 코드는 뭔가 문제가 있어서 3회 이상 추론 시 에러가 발생하는데요 😂
    해결 방법을 아시는 분은... 댓글로 알려주시면 감사하겠습니다.... 😂😂
import torch
import time
from scipy.special import softmax

from transformers import AutoTokenizer, AutoModelForSequenceClassification

import tritonclient.http as httpclient
from tritonclient.utils import triton_to_np_dtype

import numpy as np

tokenizer = AutoTokenizer.from_pretrained("cardiffnlp/twitter-roberta-base-sentiment")

input_name = ['input__0', 'input__1']
output_name = 'output__0'

def run_inference(sentence):

    triton_client = httpclient.InferenceServerClient(url="localhost:6700")

    data_type = np.int32
    desired_dims = (1, 256)

    inputs = tokenizer(sentence, max_length=256, padding='max_length', return_tensors='pt')

    input_ids = inputs['input_ids']
    # 텐서를 numpy 배열로 변환합니다.
    input_ids = input_ids.numpy()
    # 텐서를 원하는 크기로 reshape 합니다.
    input_ids = np.reshape(input_ids, desired_dims)
    # 데이터 타입을 변경합니다.
    input_ids = input_ids.astype(data_type)


    mask = inputs['attention_mask']
    # 텐서를 numpy 배열로 변환합니다.
    mask = mask.numpy()
    # 텐서를 원하는 크기로 reshape 합니다.
    mask = np.reshape(mask, desired_dims)
    # 데이터 타입을 변경합니다.
    mask = mask.astype(data_type)


    input0 = httpclient.InferInput(input_name[0], desired_dims, 'INT32')
    input0.set_data_from_numpy(input_ids, binary_data=False)
    input1 = httpclient.InferInput(input_name[1], desired_dims, 'INT32')
    input1.set_data_from_numpy(mask, binary_data=False)
    
    output = httpclient.InferRequestedOutput(output_name)

    response = triton_client.infer(model_name="roberta", inputs=[input0, input1], outputs=[output])
    logits = response.as_numpy('output__0')
    scores = softmax(logits, axis=1)
    max_index = np.argmax(scores)

    return max_index


sentence = "so sleepy"
result = run_inference(sentence)
print(result)

Reference

Triton-RoBERTa tutorial
https://medium.com/nvidia-ai/how-to-deploy-almost-any-hugging-face-model-on-nvidia-triton-inference-server-with-an-8ee7ec0e6fc4
xlm roberta
https://github.com/DinoHub/appstore-ai/tree/fbdd6ade8c56bef6b5d29f6144f08ce0e9028842/inference-services/examples/xlm-roberta-triton
tutorial
https://github.com/triton-inference-server/tutorials/blob/main/Quick_Deploy/PyTorch/README.md
generate torch script
https://github.com/haicheviet/fullstack-machine-learning-inference/blob/f2c7a4073b0f34bdb1a5bf755dd22dd16261fbd0/generate_torch_script.py#L11
Triton 의 장점
https://code.debro.co.kr/58
torchscript 변환 시 forward 유/무 차이
https://data-gardner.tistory.com/105
모델 서빙 최적화를 위한 프레임워크 선정과 서빙 성능 극대화하기
https://tech.kakaopay.com/post/model-serving-framework/
Triton Inference Server로 모델 서빙 성능 끌어올리기
https://smilegate.ai/2023/06/15/triton-inference-server로-모델-서빙-성능-끌어올리기/
RoBERTa 모델을 torchscript 로 변환하는 예제
https://github.com/haicheviet/fullstack-machine-learning-inference/blob/f2c7a4073b0f34bdb1a5bf755dd22dd16261fbd0/generate_torch_script.py#L11

profile
NLP Researcher

0개의 댓글