파이썬 - WSL/docker에 구성한 Triton 예제 개발 환경
"Triton Inference Server"는,
//
https://catalog.ngc.nvidia.com/orgs/nvidia/containers/tritonserver
What Is The Triton Inference Server?
Triton Inference Server provides a cloud and edge inferencing solution optimized for both CPUs and GPUs. Triton supports an HTTP/REST and GRPC protocol that allows remote clients to request inferencing for any model being managed by the server. For edge deployments, Triton is available as a shared library with a C API that allows the full functionality of Triton to be included directly in an application.
NVIDIA 측에서 오픈 소스로 공개한 추론 서버로, 기학습된 딥러닝 모델을 쉽고 빠르게 활용할 수 있도록 해줍니다. 사실, 서버 자체는 C/C++로 작성돼 사용이 불편할 거라고 오해할 수 있는데, 다행히 지원하는 백엔드 중의 하나로 파이썬을 제공하므로 적용 난이도가 현저하게 낮아집니다.
대충, 그럼 환경 구성을 해볼까요? ^^
개발 환경을 어지럽히지 않기 위해 이런 경우 docker를 사용하면 좋은데요, (물론
원한다면 소스 코드를 빌드해도 됩니다.) 관련해서
다양한 이미지가 제공되고 있지만,
- The xx.yy-py3 image contains the Triton Inference Server with support for PyTorch, TensorRT, ONNX and OpenVINO models.
- The xx.yy-py3-sdk image contains Python and C++ client libraries, client examples, GenAI-Perf, Performance Analyzer and the Model Analyzer.
- The xx.yy-py3-min image is used as the base for creating custom Triton server containers as described in Customize Triton Container.
- The xx.yy-pyt-python-py3 image contains the Triton Inference Server with support for PyTorch and Python backends only.
- The xx.yy-py3-igpu image contains the Triton Inference Server with support for Jetson Orin devices. Please refer to the Frameworks Support Matrix for information regarding which iGPU hardware/software is supported by which container.
- The xx.yy-py3-igpu-sdk image contains Python and C++ client libraries, client examples, and the Perf Analyzer.
- The xx.yy-py3-igpu-min image is used as the base for creating custom iGPU Triton server containers.
- The xx.yy-vllm-python-py3 image contains the Triton Inference Server with support for vLLM and Python backends only.
- The xx.yy-trtllm-python-py3 image contains the Triton Inference Server with support for TensorRT-LLM and Python backends only.
이번 글에서는 그냥 단순 실습 정도만 할 것이기 때문에 "xx.yy-py3" 이미지를 쓰겠습니다. 그렇다면 이제 버전을 선택해야 하는데요, 제 시스템의 경우 Driver Version과 CUDA Version이 각각 576.02., 12.9로 나오기 때문에,
$ /usr/lib/wsl/lib/nvidia-smi
Tue May 17 11:00:59 2025
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 575.51.02 Driver Version: 576.02 CUDA Version: 12.9 |
|-----------------------------------------+------------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+========================+======================|
| 0 NVIDIA GeForce RTX 4060 Ti On | 00000000:01:00.0 On | N/A |
| 0% 34C P8 9W / 160W | 3643MiB / 8188MiB | 13% Default |
| | | N/A |
+-----------------------------------------+------------------------+----------------------+
+-----------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=========================================================================================|
| No running processes found |
+-----------------------------------------------------------------------------------------+
Triton Inference Server 문서에 따라,
Frameworks Support Matrix
; https://docs.nvidia.com/deeplearning/frameworks/support-matrix/index.html
25.xx container images에 "Release 25.04 is based on CUDA 12.9.0.036 which requires NVIDIA Driver release 575 or later"라고 쓰여있기 때문에 그 버전의 이미지를 사용하겠습니다.
$ mkdir tis
$ cd tis
$ cat dockerfile
FROM nvcr.io/nvidia/tritonserver:25.04-py3
# 이건 필요 없지만 예제에서 사용한 model의 코드가 opencv 패키지를 사용하므로 포함
RUN apt-get update && apt-get install libgl1 -y
SHELL ["/bin/bash", "-c"]
WORKDIR /home/ubuntu
$ docker build -t tis .
(압축 파일 크기만 8GB가 넘고, 설치된 이미지 크기는 30GB가 넘어 시간이 제법 걸립니다.)
띄우기만 하면 뭔가 심심하니, 실제 동작하는 것까지 보고 싶은데요, 이 분야에 처음이라 제가 아는 바가 없어 ^^ 누군가가 작성한 예제를 활용해 보겠습니다.
Triton Inference Server 사용법
; https://velog.io/@dj_/Triton-Inference-Server-사용법
$ git clone https://github.com/fegler/triton_server_example.git
$ cd triton_server_example
우선, git clone을 했으면 save_model.py를 실행해야 하는데요, 이게 torchvision 패키지를 필요로 합니다. 하지만 triton에 올라갈 패키지에는 그것까지 포함할 필요는 없으므로 save_model.py는 별도의 환경에서 빌드하는 것이 좋겠습니다.
// 이번 글에서 사용하는 torchvision 0.20 패키지가 파이썬 3.9 ~ 3.12를 지원
$ conda create --name pybuild python=3.12 -y
$ conda activate pybuild
$ python -m pip install torchvision==0.20
$ python save_model.py
// 이하 작업은 확인 차원이므로 필요 없음
$ conda install opencv
$ python test_model.py
test finish
$ conda deactivate
저렇게 Model까지만 구성해도 triton 서버에서 돌아갈 수는 있는데요, 단지 예제 코드의 경우 파이썬 백엔드에서 pre/post processing 중에 부가적으로 로드하는 패키지들이 있어 좀 더 수고를 해야 합니다. 이에 대한 처리를 쉽게는, 그냥 해당 dockerfile 이미지에 패키지를 설치해 포함하는 것도 가능할 것 같은데요, 여기서는 conda로 패키징을 구성해 넣어 보겠습니다. 왜냐하면, ./triton/preprocessing과 ./triton/postprocessing 디렉터리 아래에 있는 config.pbtxt 파일에 파이썬의 실행 환경을 다음과 같이 명시하고 있기 때문입니다.
name: "preprocessing"
backend: "python"
input [
{
name: "image"
data_type: TYPE_STRING
dims: [-1]
}
]
output [
{
name: "input_image"
data_type: TYPE_FP32
dims: [-1, 3, -1, -1]
}
]
parameters: {
key: "EXECUTION_ENV_PATH",
value: {string_value: "$$TRITON_MODEL_DIRECTORY/pre_env.tar.gz"}
}
instance_group [
{
kind: KIND_CPU
}
]
따라서, pre_env.tar.gz과 (./triton/postprocessing/config.pbtxt에 명시된) post_env.tar.gz 파일을 다음과 같이 각각 생성해 넣어야 합니다.
// Creating Custom Execution Environments
// ; https://github.com/triton-inference-server/python_backend?tab=readme-ov-file#creating-custom-execution-environments
$ export PYTHONNOUSERSITE=True
$ conda create --name triton_sample python=3.12 -y
$ conda activate triton_sample
// triton 25 버전인 경우 libstdcxx-ng=14로 구성
$ conda install -c conda-forge libstdcxx-ng=14 -y
$ conda install pip -y
$ conda install conda-pack -y
$ which conda-pack
/home/testusr/miniconda3/envs/triton_sample/bin/conda-pack
$ pip install -r pre_requirements.txt
$ conda-pack -n triton_sample -o pre_env.tar.gz
$ cp pre_env.tar.gz ./triton/preprocessing/pre_env.tar.gz
$ pip install -r post_requirements.txt
$ conda-pack -n triton_sample -o post_env.tar.gz
$ cp post_env.tar.gz ./triton/postprocessing/post_env.tar.gz
그럼, 최종적으로 이런 식의 Model 구성을 갖게 됩니다.
$ tree ./triton/
./triton/
├── core
│ ├── 1
│ │ └── model.pt
│ └── config.pbtxt
├── ensemble
│ ├── 1
│ │ └── placeholder
│ └── config.pbtxt
├── postprocessing
│ ├── 1
│ │ └── model.py
│ ├── config.pbtxt
│ └── post_env.tar.gz
└── preprocessing
├── 1
│ └── model.py
├── config.pbtxt
└── pre_env.tar.gz
$ ls ./triton/core/1/model.pt -l
-rw-r--r-- 1 kevin kevin 102594763 May 23 11:26 ./triton/core/1/model.pt
마지막으로 docker run 명령어로 triton 서버를 구동하면 끝!
$ export MODEL_FOLDER_PATH=/home/kevin/test/triton_server_example/triton
// gpu device=0 환경 설정
// SSL_CERT_DIR 설정
$ docker run --gpus='"device=0"' -it --rm --shm-size=8g -p 8005:8000 -e SSL_CERT_DIR=/etc/ssl/certs/ -v ${MODEL_FOLDER_PATH}:/model_dir tis tritonserver --model-repository=/model_dir --strict-model-config=false --model-control-mode=poll --repository-poll-secs=10 --backend-config=tensorflow,version=2 --log-verbose=1
고맙게도 triton_server_example repo는 테스트까지 할 수 있는 client.py를 제공하는데요, 적절하게 IP와 이미지 파일 경로만 맞춰준 다음,
$ cat client.py
import base64
import os
import requests
import json
import cv2
import numpy as np
from pytictoc import TicToc
# TicToc 클래스 생성
t = TicToc()
IP = "127.0.0.1" ## use your ip
def inference(image_data, url="localhost", port="8005"):
url = f"http://{url}:{port}/v2/models/ensemble/infer"
data = {
"inputs": [
{
"name": "image",
"shape": [len(image_data)],
"datatype": "BYTES",
"data": image_data,
}
]
}
headers = {"content-type": "application/json"}
t.tic()
response = requests.post(
url, headers=headers, data=json.dumps(data, ensure_ascii=False)
)
tm = t.tocvalue()
return response.text, tm
def read_image_data(im_paths):
encode_ims = []
for p in im_paths:
if not os.path.exists(p):
continue
image = open(p, "rb")
im_encode = base64.b64encode(image.read()).decode("ascii")
encode_ims.append(im_encode)
return encode_ims
if __name__ == "__main__":
im_path = ["/home/testusr/test/triton_server_example/test_image.jpg"]
images = read_image_data(im_path)
response, tm = inference(images, IP)
print("Inference Time: %f" % tm)
response_json = json.loads(response)
response_data = json.loads(response_json["outputs"][0]["data"][0])
pred_probs = response_data["result"]
print(pred_probs)
필요한 패키지 설치 후 triton 서버에 요청/응답까지 할 수 있습니다.
$ conda create --name triton_client -y
$ conda activate triton_client
$ conda install pip -y
$ pip install opencv-python
$ pip install requests
$ pip install pytictoc
$ python client.py
Inference Time: 3.681000
[[0.0007483039516955614, ...[생략]... 0.0009087992366403341]]
뭔지 모르지만... ^^; 아무튼, 잘 동작하는 것 같습니다.
참고로, 패키징된 tar.gz 파일의 경우 trtion 서버에 구동할 때 다시 unpack 작업을 거쳐야 하는데요, 이 과정을 생략할 수 있도록 미리 압축을 해제하는 것도 가능합니다.
예를 들어 위의 예제를 다시 (이번에는 pre/post를 위한 가상 환경을 각각 나눠서) 작성해 보면,
$ export PYTHONNOUSERSITE=True
$ conda create --name triton_sample_pre python=3.12 -y
$ conda activate triton_sample_pre
// triton 25 버전인 경우 libstdcxx-ng=14로 구성
$ conda install -c conda-forge libstdcxx-ng=14 -y
$ conda install pip -y
$ conda install conda-pack -y
$ pip install -r pre_requirements.txt
$ conda-pack -n triton_sample_pre -o pre_env.tar.gz
$ conda deactivate
$ conda create --name triton_sample_post python=3.12 -y
$ conda activate triton_sample_post
// triton 25 버전인 경우 libstdcxx-ng=14로 구성
$ conda install -c conda-forge libstdcxx-ng=14 -y
$ conda install pip -y
$ conda install conda-pack -y
$ pip install -r post_requirements.txt
$ conda-pack -n triton_sample_post -o post_env.tar.gz
$ conda deactivate
각각 pre_env.tar.gz, post_env.tar.gz 파일만 생성해 둔 다음 그대로 Model 디렉터리에 압축을 풀어 놓으면 됩니다.
$ mkdir -p ./triton/preprocessing/python_env
$ tar -xzf pre_env.tar.gz -C ./triton/preprocessing/python_env
$ mkdir -p ./triton/postprocessing/python_env
$ tar -xzf post_env.tar.gz -C ./triton/postprocessing/python_env
그럼 최종적으로 예제 디렉터리는 이런 식으로 구성되고,
./triton
├── core
│ ├── 1
│ │ └── model.pt
│ └── config.pbtxt
├── ensemble
│ ├── 1
│ │ └── placeholder
│ └── config.pbtxt
├── postprocessing
│ ├── 1
│ │ └── model.py
│ ├── config.pbtxt
│ └── python_env
| ...[생략]...
├── postprocessing
│ ├── 1
│ │ └── model.py
│ ├── config.pbtxt
│ └── python_env
...[생략]...
그다음, 각각의 preprocessing, postprocessing 디렉터리에 있는 config.pbtxt 파일의 EXECUTION_ENV_PATH를 다음과 같이 수정합니다.
parameters: {
key: "EXECUTION_ENV_PATH",
value: {string_value: "$$TRITON_MODEL_DIRECTORY/python_env"}
}
끝입니다, 이제 triton 서버를 실행하면 정상적으로, 이전보다 더 빠르게 구동됩니다. ^^
혹시나 이 분야에 연관이 있으신 분들이라면 아래의 글도 마저 읽어보시는 것이 좋을 듯합니다. ^^
Triton Inference Server #1. Triton Inference Server란?
; https://dytis.tistory.com/65
Triton Inference Server #2. 모델 스케쥴링
; https://dytis.tistory.com/66
Triton Inference Server #3. Model Management & Repository
; https://dytis.tistory.com/69
Triton Inference Server #4. Model Configuration
; https://dytis.tistory.com/70
Triton Inference Server #5. Python Backend
; https://dytis.tistory.com/71
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]