본문 바로가기
Artificial Intelligence/60. Python

[PYTHON] Triton Inference Server를 활용한 3가지 멀티 프레임워크 모델 서빙 통합 해결 방법

by Papa Martino V 2026. 4. 20.
728x90

Triton Inference Server
Triton Inference Server

 

서론: 왜 Triton Inference Server인가?

현대 AI 서비스 개발 환경에서는 데이터 과학자들이 각기 다른 프레임워크(PyTorch, TensorFlow, Scikit-learn 등)를 사용하여 모델을 개발합니다. 하지만 운영 단계(MLOps)에서는 이 모든 모델을 각각의 플라스크(Flask)나 패스트API(FastAPI) 서버로 구축할 경우, 자원 낭비와 관리 복잡성이 기하급수적으로 증가합니다.

NVIDIA의 Triton Inference Server는 이러한 문제를 해결하기 위한 강력한 오픈소스 소프트웨어입니다. 본 가이드에서는 Python 기반의 클라이언트 구현부터 멀티 프레임워크 모델의 효율적인 배포 전략까지 실무 밀착형 지식을 전달합니다.


1. 멀티 프레임워크 모델 서빙 방식의 비교

기존 방식과 Triton을 이용한 통합 방식의 차이점을 분석합니다.

비교 항목 전통적인 Flask/FastAPI 방식 Triton Inference Server 방식
프레임워크 지원 라이브러리별 별도 컨테이너 필요 단일 서버 내 멀티 백엔드 지원
GPU 가속 수동 최적화 및 복잡한 메모리 관리 Dynamic Batching 및 자동 최적화
모델 동적 로딩 서버 재시작 필수 Model Control API로 실시간 로드/언로드
처리량(Throughput) 상대적으로 낮음 동시 실행(Concurrent Execution)으로 극대화
유지보수 비용 모델별 개별 API 규격 관리 필요 표준화된 gRPC/HTTP 프로토콜 사용

2. 실무 적용을 위한 Triton Repository 구조 설계

Triton은 특정 디렉토리 구조를 엄격히 따릅니다. 이를 이해하는 것이 모델 서빙의 첫걸음입니다.

Model Repository Structure:
models/
  ├── resnet50_pytorch/
  │  ├── config.pbtxt (설정 파일)
  │  └── 1/ (버전 폴더)
  │      └── model.pt
  └── inception_tf/
      ├── config.pbtxt
      └── 1/
          └── model.savedmodel/

3. 개발자 실무 적용 Sample Example (7가지 핵심 코드)

아래 예제들은 Python 환경에서 Triton 서버와 통신하거나 설정을 최적화할 때 즉시 사용 가능합니다.

Example 1: PyTorch 모델을 위한 config.pbtxt 설정 방법


name: "resnet50_pytorch"
platform: "pytorch_libtorch"
max_batch_size: 8
input [
  {
    name: "input__0"
    data_type: TYPE_FP32
    dims: [ 3, 224, 224 ]
  }
]
output [
  {
    name: "output__0"
    data_type: TYPE_FP32
    dims: [ 1000 ]
  }
]
instance_group [
  {
    count: 2
    kind: KIND_GPU
  }
]

Example 2: Python Client를 이용한 gRPC 추론 요청


import tritonclient.grpc as grpcclient
import numpy as np

# 1. 서버 연결 설정
client = grpcclient.InferenceServerClient(url="localhost:8001")

# 2. 데이터 준비
input_data = np.random.randn(1, 3, 224, 224).astype(np.float32)
inputs = [grpcclient.InferInput("input__0", input_data.shape, "FP32")]
inputs[0].set_data_from_numpy(input_data)

# 3. 추론 실행
outputs = [grpcclient.InferRequestedOutput("output__0")]
response = client.infer(model_name="resnet50_pytorch", inputs=inputs, outputs=outputs)

# 4. 결과 출력
result = response.as_numpy("output__0")
print(f"Inference Result Shape: {result.shape}")

Example 3: 동적 배칭(Dynamic Batching) 활성화 해결 방법

처리량을 2배 이상 높이기 위한 가장 중요한 설정입니다.


# config.pbtxt 하단에 추가
dynamic_batching {
  preferred_batch_size: [ 4, 8 ]
  max_queue_delay_microseconds: 100
}

Example 4: Python Backend를 활용한 전처리 로직 통합


# model.py (Triton Python Backend용)
import triton_python_backend_utils as pb_utils
import numpy as np

class TritonPythonModel:
    def execute(self, requests):
        responses = []
        for request in requests:
            # 입력 데이터 추출
            in_0 = pb_utils.get_input_tensor_by_name(request, "INPUT0")
            img = in_0.as_numpy()
            
            # 여기서 전처리 수행 (예: 정규화)
            processed_img = img / 255.0
            
            # 결과 생성
            out_tensor = pb_utils.Tensor("OUTPUT0", processed_img.astype(np.float32))
            responses.append(pb_utils.InferenceResponse(output_tensors=[out_tensor]))
        return responses

Example 5: HTTP Protocol을 이용한 모델 헬스 체크


import requests

def check_model_ready(model_name, host="localhost", port=8000):
    url = f"http://{host}:{port}/v2/models/{model_name}/ready"
    response = requests.get(url)
    if response.status_code == 200:
        print(f"Model {model_name} is ready for inference!")
    else:
        print(f"Model {model_name} is not available.")

check_model_ready("resnet50_pytorch")

Example 6: 비동기(Asynchronous) 추론 요청 처리


from functools import partial

def callback(user_data, result, error):
    if error:
        user_data.append(error)
    else:
        user_data.append(result)

results = []
client.async_infer(
    model_name="resnet50_pytorch",
    inputs=inputs,
    callback=partial(callback, results),
    outputs=outputs
)
# 다른 작업 수행 가능...

Example 7: 모델 앙상블(Ensemble) 파이프라인 구성

전처리와 모델 추론을 하나의 요청으로 묶는 해결 방법입니다.


name: "ensemble_model"
platform: "ensemble"
input [ { name: "INPUT", data_type: TYPE_FP32, dims: [ -1 ] } ]
output [ { name: "OUTPUT", data_type: TYPE_FP32, dims: [ -1 ] } ]
ensemble_scheduling {
  step [
    {
      model_name: "preprocessing_python"
      model_version: -1
      input_map { key: "INPUT", value: "INPUT" }
      output_map { key: "OUTPUT", value: "preprocessed_data" }
    },
    {
      model_name: "resnet50_pytorch"
      model_version: -1
      input_map { key: "input__0", value: "preprocessed_data" }
      output_map { key: "output__0", value: "OUTPUT" }
    }
  ]
}

4. 고성능 서빙을 위한 10가지 최적화 체크리스트

  • Shared Memory: 대용량 데이터 전송 시 공유 메모리를 사용하여 오버헤드를 줄였는가?
  • Model Control Mode: 모델 업데이트 시 다운타임 방지를 위해 explicit 모드를 사용하고 있는가?
  • Response Cache: 동일 입력에 대해 캐싱을 활성화하여 응답 속도를 개선했는가?
  • Rate Limiter: 자원 경합 방지를 위해 요청 속도 제한 설정을 고려했는가?
  • CUDA 최적화: 최신 TensorRT 백엔드를 활용하여 추론 속도를 3배 이상 향상시켰는가?

결론 및 요약

Triton Inference Server는 단순히 모델을 서빙하는 툴을 넘어, 기업의 AI 인프라를 표준화하는 핵심 솔루션입니다. Python 개발자라면 위 7가지 예제를 바탕으로 자신만의 고성능 추론 서버를 구축할 수 있습니다. 특히 멀티 프레임워크 환경에서의 통합은 운영 비용 절감뿐만 아니라 서비스의 안정성을 크게 보장합니다.


내용 출처:

  • NVIDIA Triton Inference Server 공식 문서 (2025-2026 업데이트 버전)
  • MLOps 실무 가이드: 고성능 딥러닝 모델 서빙 전략 리포트
  • Python 기반 gRPC/HTTP 통신 아키텍처 기술 세미나 자료
728x90