backend

Triton 백엔드 (개념·API)

Triton 백엔드는 모델을 실행하는 구현체예요. 백엔드는 PyTorch, TensorFlow, TensorRT, ONNX Runtime 같은 딥러닝 프레임워크를 감싼 구현일 수도 있고, 이미지 전처리 같은 임의의 연산을 수행하는 커스텀 C/C++ 로직일 수도 있어요.

이 저장소(backend repo)에는 Triton 백엔드에 대한 문서와, 백엔드를 만드는 데 쓰는 소스·스크립트·유틸리티가 들어 있어요. 백엔드를 만들 때 이 저장소의 내용을 꼭 써야 하는 건 아니지만, 유용하게 쓰일 가능성이 높아요.

자주 묻는 질문 (FAQ)

Triton에 사용 가능한 모든 백엔드는 어디서 찾나요?

누구나 Triton 백엔드를 개발할 수 있으므로 모든 백엔드를 알 수는 없어요. 하지만 Triton 프로젝트는 각 Triton 릴리스마다 테스트되고 갱신되는 지원 백엔드 세트를 제공해요.

  • TensorRT: TensorRT 모델을 실행하는 백엔드 (tensorrt_backend repo)
  • ONNX Runtime: ONNX 모델을 실행하는 백엔드 (onnxruntime_backend repo)
  • TensorFlow: GraphDef와 SavedModel 형식 모두를 실행하는 백엔드. TensorFlow 1·2 모델 모두 같은 백엔드를 써요 (tensorflow_backend repo)
  • PyTorch: TorchScript와 PyTorch 2.0 형식 모두를 실행하는 백엔드 (pytorch_backend repo)
  • OpenVINO: OpenVINO 모델을 실행하는 백엔드 (openvino_backend repo)
  • Python: 모델 로직을 Python으로 작성하게 해 주는 백엔드. Python으로 짠 전/후처리 코드를 실행하거나, PyTorch Python 스크립트를 TorchScript로 변환하지 않고 직접 실행할 수 있어요 (python_backend repo)
  • DALI: 딥러닝 입력 데이터의 전처리를 가속하는 라이브러리. DALI 백엔드는 DALI 파이프라인을 Triton 안에서 실행하게 해 줘요 (dali_backend repo)
  • FIL (Forest Inference Library): XGBoost, LightGBM, Scikit-Learn random forest, cuML random forest 등 트리 기반 ML 모델을 실행하는 백엔드 (fil_backend repo)
  • TensorRT-LLM: TensorRT-LLM 모델을 Triton Server로 서빙하게 해 주는 백엔드 (tensorrtllm_backend repo)
  • vLLM: 지원되는 모델을 vLLM 엔진 위에서 실행하는 백엔드. vLLM으로 모델을 로드·서빙하기 위해 python_backend에 의존해요 (vllm_backend repo)

중요: 위 백엔드 모두가 Triton이 지원하는 모든 플랫폼에서 지원되는 건 아니에요. Backend-Platform Support Matrix를 확인해 보세요.

내 백엔드를 어떻게 개발하나요?

먼저 메인 Triton 이슈 페이지에서 이미 존재하는 백엔드를 중복 개발하고 있지 않은지 확인해요. 그다음 튜토리얼을 따라 첫 단순 트리 기반 백엔드를 만들고 점진적으로 기능을 추가하면 돼요. Triton 백엔드에 대한 전체 문서도 읽어보는 게 좋아요.

기존 Triton 설치본에 백엔드를 추가(또는 제거)할 수 있나요?

네. 백엔드를 구현하는 공유 라이브러리를 Triton이 어떻게 관리하는지는 Backend Shared Library를, 릴리스된 Triton Docker 이미지에 백엔드를 추가하는 문서는 Triton with Unsupported and Custom Backends를 참고해요. 표준 설치에서 전역적으로 사용 가능한 백엔드는 /opt/tritonserver/backends에 있어요.

"legacy custom backend" API로 만든 백엔드는?

legacy custom API는 Triton에서 제거됐어요. 이전 API로 만든 커스텀 백엔드가 있다면 새 Triton Backend API로 이식해야 해요.

백엔드

모델은 반드시 백엔드와 연결되어야 해요. 모델의 백엔드는 모델 구성의 backend 설정으로 지정해요. TensorRT 백엔드를 쓰려면 이 값을 tensorrt로, PyTorch·ONNX·TensorFlow는 각각 pytorch, onnxruntime, tensorflow로 설정하면 돼요. 다른 모든 백엔드는 backend를 백엔드 이름으로 설정해야 해요. 일부 백엔드는 모델을 분류하기 위해 platform 설정도 확인해요 (예: TensorFlow 백엔드에서는 모델 형식에 따라 tensorflow_savedmodel 또는 tensorflow_graphdef).

백엔드 공유 라이브러리 (Backend Shared Library)

각 백엔드는 공유 라이브러리로 구현되어야 하고, 그 이름은 libtriton_<backend-name>.so여야 해요. 예를 들어 백엔드 이름이 mybackend면 모델 구성 backendmybackend로 설정하고, Triton은 해당 백엔드를 구현하는 libtriton_mybackend.so를 찾아요.

백엔드 B를 지정한 모델 M에 대해 Triton은 다음 위치 순서로 백엔드 공유 라이브러리를 찾아요.

  1. <model_repository>/M/<version_directory>/libtriton_B.so
  2. <model_repository>/M/libtriton_B.so
  3. <global_backend_directory>/B/libtriton_B.so

여기서 <global_backend_directory>는 기본적으로 /opt/tritonserver/backends예요. --backend-directory 플래그로 기본값을 덮어쓸 수 있어요. 보통 백엔드를 이 전역 백엔드 디렉터리에 설치해요.

24.01부터 모델 구성에 런타임 설정을 제공해 기본 백엔드 공유 라이브러리 이름을 바꿀 수 있어요.

runtime: "my_backend_shared_library_name.so"

Triton Backend API

Triton 백엔드는 tritonbackend.h에 정의된 C 인터페이스를 구현해야 해요. API가 쓰는 추상화는 다음과 같아요.

TRITONBACKEND_Backend

백엔드 자체를 나타내는 객체예요. 같은 백엔드 객체는 그 백엔드를 쓰는 모든 모델이 공유해요. TRITONBACKEND_BackendName 같은 관련 API는 백엔드 정보를 얻고 사용자 정의 상태를 연관시키는 데 쓰여요. 백엔드는 선택적으로 TRITONBACKEND_InitializeTRITONBACKEND_Finalize를 구현해 백엔드 객체 생성/파괴 알림을 받을 수 있어요.

TRITONBACKEND_Model

모델을 나타내는 객체예요. Triton이 로드한 각 모델은 TRITONBACKEND_Model과 연결돼요. 모델 객체는 그 모델의 모든 인스턴스가 공유해요. 대부분의 백엔드는 TRITONBACKEND_ModelInitializeTRITONBACKEND_ModelFinalize를 구현해 모델별 초기화와 사용자 정의 상태를 관리해요.

백엔드는 이 함수들을 구현할 때 스레드 문제를 고려해야 해요. Triton은 주어진 모델에 대해 이 함수를 동시에 여러 번 호출하지 않지만, 백엔드를 여러 모델이 쓰면 모델마다 다른 스레드로 동시 호출할 수 있어요. 모범 사례는 이 함수들에서 함수-로컬과 모델별 사용자 정의 상태만 쓰는 거예요.

TRITONBACKEND_ModelInstance

모델 인스턴스를 나타내는 객체예요. Triton은 모델 구성의 instance_group 설정에 따라 모델 인스턴스를 하나 이상 만드는데, 각 인스턴스가 TRITONBACKEND_ModelInstance 객체와 연결돼요.

백엔드가 반드시 구현해야 하는 유일한 함수는 **TRITONBACKEND_ModelInstanceExecute**예요. 이 함수는 Triton이 배치된 추론 요청에 대해 추론/연산을 수행하도록 호출해요. 대부분의 백엔드는 TRITONBACKEND_ModelInstanceInitializeTRITONBACKEND_ModelInstanceFinalize도 구현해요. 선택적으로 TRITONBACKEND_ModelInstanceReady를 구현해 인스턴스가 요청을 처리할 준비가 됐는지 확인할 수 있어요 (준비되면 nullptr, 아니면 TRITONSERVER_Error 반환).

TRITONBACKEND_Request

모델에 대한 추론 요청을 나타내는 객체예요. 백엔드는 TRITONBACKEND_ModelInstanceExecute에서 요청 객체의 소유권을 가져오며, 각 요청을 TRITONBACKEND_RequestRelease로 해제해야 해요. 다만 TRITONBACKEND_ModelInstanceExecute가 오류를 반환하면 요청 객체 소유권은 Triton으로 돌아가요. 요청의 각 입력은 TRITONBACKEND_Input 객체로 표현돼요.

TRITONBACKEND_Response

특정 요청에 대해 백엔드가 보내는 응답을 나타내는 객체예요. 백엔드는 응답 API로 각 출력 텐서의 이름·shape·데이터타입·값을 설정해요. 응답은 실패 또는 성공을 나타낼 수 있어요.

TRITONBACKEND_BackendAttribute

백엔드가 특정 기능 지원, 선호 구성, 기타 백엔드별 동작을 Triton에 알리기 위한 속성을 설정하게 해 줘요. 백엔드 초기화 시 Triton은 TRITONBACKEND_GetBackendAttribute(구현 시)를 조회해요. 관련 setter API로는 다음이 있어요.

  • TRITONBACKEND_BackendSetExecutionPolicy — 실행 정책 설정
  • TRITONBACKEND_BackendAttributeAddPreferredInstanceGroup — 모델 구성이 인스턴스 그룹을 명시하지 않을 때 선호할 인스턴스 그룹 우선순위 목록 정의
  • TRITONBACKEND_BackendAttributeSetParallelModelInstanceLoading — 백엔드가 TRITONBACKEND_ModelInstanceInitialize 동시 호출을 안전하게 처리할 수 있는지 정의. 기본적으로 false(병렬 인스턴스 로딩 비활성화)이며, 현재 Python과 ONNXRuntime 백엔드가 병렬 인스턴스 로딩을 지원해요. 병렬 로딩은 대규모 인스턴스 수에서 서버 시작 시간을 줄일 수 있어요.

전체 API 목록은 tritonbackend.h에 정의돼 있어요.

백엔드 생명주기 (Backend Lifecycles)

백엔드는 백엔드 자체, 백엔드를 쓰는 모델·모델 인스턴스, 그리고 그 위에서 실행되는 추론 요청의 생명주기를 신중히 관리해야 해요.

초기화는 Triton이 모델을 로드할 때 시작돼요. 모델이 이미 로드된 모델이 쓰지 않는 백엔드를 요구하면:

  1. Triton이 백엔드를 구현하는 공유 라이브러리를 로드하고 TRITONBACKEND_Backend 객체를 만들어요.
  2. 백엔드가 TRITONBACKEND_Initialize를 구현했다면 호출해요 (완전히 초기화될 때까지 반환하면 안 됨). 오류를 반환하면 Triton은 모델 로드 실패를 보고해요.
  3. Triton이 TRITONBACKEND_Model 객체를 만들고 TRITONBACKEND_ModelInitialize를 호출해요.
  4. 모델 구성에 지정된 각 모델 인스턴스에 대해 TRITONBACKEND_ModelInstance 객체를 만들고 TRITONBACKEND_ModelInstanceInitialize를 호출해요.

**종료(finalization)**는 Triton이 모델을 언로드할 때 시작돼요. 각 모델 인스턴스에 대해 TRITONBACKEND_ModelInstanceFinalize를 호출하고 인스턴스 객체를 파괴하고, 그다음 TRITONBACKEND_ModelFinalize를 호출하고 모델 객체를 파괴해요. 다른 로드된 모델이 백엔드를 요구하지 않아도, Triton은 tritonserver 프로세스가 종료될 때까지 백엔드를 finalize·언로드하지 않아요. 프로세스가 종료될 때 TRITONBACKEND_Finalize를 호출하고 백엔드 객체를 파괴해요.

추론 요청과 응답 (Inference Requests and Responses)

Triton은 TRITONBACKEND_ModelInstanceExecute로 모델 인스턴스에서 추론 요청을 실행해요. 각 호출은 실행할 요청 배치와 그 요청들을 실행할 모델 인스턴스를 전달해요. 백엔드는 인스턴스가 다음 요청 세트를 처리할 준비가 될 때까지 호출자 스레드가 반환하지 못하게 해야 해요. 보통 TRITONBACKEND_ModelInstanceExecute가 반환되기 전에 응답을 만들고 요청을 해제한다는 뜻이에요. 다만 이 함수가 오류를 반환하면 요청 소유권이 Triton으로 돌아가므로, 백엔드는 요청에 대한 참조를 붙잡거나 접근하면 안 돼요.

단일 응답 (Single Response)

대부분의 백엔드는 요청당 단일 응답을 만들어요. 실행 단계는:

  1. TRITONBACKEND_ResponseNew로 요청에 대한 응답을 만들어요.
  2. 각 입력 텐서에 대해 TRITONBACKEND_InputProperties로 shape·데이터타입·버퍼를 얻어요.
  3. 요청이 반환하길 기대하는 각 출력 텐서에 대해 TRITONBACKEND_ResponseOutput으로 필요한 데이터타입·shape의 출력 텐서를 만들고, TRITONBACKEND_OutputBuffer로 쓰기용 버퍼 포인터를 얻어요.
  4. 입력으로 추론을 수행해 요청된 출력 텐서 내용을 적절한 출력 버퍼에 채워요.
  5. 응답에 파라미터를 선택적으로 설정해요.
  6. TRITONBACKEND_ResponseSend로 응답을 보내요.
  7. TRITONBACKEND_RequestRelease로 요청을 해제해요.

배치 요청의 경우 백엔드는 성능을 위해 개별 요청의 실행을 최대한 결합하려 해야 해요.

분리 응답 (Decoupled Responses)

백엔드가 요청에 여러 응답을 보낼 수도 있어요. 요청 배치가 실행된 순서와 다르게 응답을 보낼 수도 있는데, 이런 백엔드를 decoupled backend라고 해요. decoupled 백엔드는 요청마다 ResponseFactory 객체 하나를 사용해 원하는 만큼 응답을 만들고 보내요. 요청당 최소 하나의 최종 응답(플래그만 있는 응답이어도)을 보내야 해요.

실행 단계는: 각 입력 텐서 속성을 얻고 → TRITONBACKEND_ResponseFactoryNew로 ResponseFactory를 만들고 → TRITONBACKEND_ResponseNewFromFactory로 응답을 만들고 → 출력 텐서를 만들고 채우고 → TRITONBACKEND_ResponseSend로 보내고 → 응답이 끝날 때까지 반복하고 → TRITONSERVER_ResponseCompleteFlag를 쓰거나 TRITONBACKEND_ResponseFactorySendFlags로 마지막 응답을 보내고 → TRITONBACKEND_RequestRelease로 요청을 해제해요.

특수 사례: 요청을 받은 순서와 다르게 응답을 보낼 수 있어요. 요청을 일찍 해제해야 한다면 입력 버퍼 내용을 먼저 복사할 수 있고, 복사본과 ResponseFactory 객체를 백엔드의 별도 스레드에 넘길 수 있어요. 메인 호출 스레드가 TRITONBACKEND_ModelInstanceExecute에서 빠져나와도 ResponseFactory 객체를 들고 있으면 백엔드가 계속 응답을 생성할 수 있어요.

백엔드 유틸리티 빌드

이 저장소의 소스는 백엔드 빌드에 유용한 "backend utilities" 라이브러리 하나로 빌드돼요. 필수는 아니지만 대부분의 백엔드에 도움이 돼요. 보통 이 저장소를 직접 빌드하지 않고, 튜토리얼 예제의 CMakeLists.txt처럼 백엔드 빌드에 포함시켜요.

$ mkdir build
$ cd build
$ cmake -DCMAKE_INSTALL_PREFIX:PATH=`pwd`/install ..
$ make install

Python 기반 백엔드 — Triton은 Python 기반 백엔드를 만드는 옵션도 제공해요. 이 백엔드들은 TritonPythonModel 인터페이스를 구현해야 하며, 여러 모델이 재사용할 수 있어요. 필수 함수는 execute지만 initialize, finalize 같은 헬퍼 함수를 추가로 구현하면 좋아요. 예로는 vLLM이 지원하는 모델을 서빙하는 공통 Python 스크립트를 제공하는 vLLM 백엔드가 있어요.


출처: 공식문서 (Triton Backend)