앞서 TorchServe 를 소개했는데요,
이번에는 Nvidia 에서 발표한 Inference server 인 'Triton' 을 소개합니다.
Triton 의 풀네임(?) 은 Triton inference server 인데요,
저는 TorchServe 에서는 쓰이지 않던 ‘Inference server’ 라는 명칭에 주목했습니다.
과연 'Inference server' 는 일반 모델 서빙 프레임워크와 어떤 차이가 있을까요?
Triton 공식 홈페이지에서 내세우는 장점은 다음과 같습니다.
Model Navigator
Triton Model Analyzer
Triton 은 Pytorch, TensorFlow, Onnx, TensorRT 4가지 프레임워크를 지원합니다.
저는 TorchServe 와 비교하기 위해 조건을 똑같이 맞춰서 PyTorch 배포만을 설명하겠습니다.
모델, 토크나이저 학습 후 저장
모델과 토크나이저를 Pytorch 로 각각 학습시킨 후 저장합니다.
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 을 이용하므로 이미지를 여기서 따로 다운로드할 필요는 없습니다.)
Pytorch 모델을 TorchScript 로 변환
Inference server 세팅
Client Server 세팅 & Inference (query to server)
Usage 3번부터 공식 튜토리얼에 따라 진행하겠습니다.
sudo docker run -it --gpus all -v ${PWD}:/workspace nvcr.io/nvidia/pytorch:22.05-py3
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 가 생성됩니다.
model_repository
|
+-- roberta
|
+-- config.pbtxt
+-- 1
|
+-- model.pt
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]
}
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 에서 확인할 수 있습니다.
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 로 쿼리를 날려 추론을 수행합니다.
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)
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