딥러닝 모델의 성능을 최적화하고 배포하는 것은 현대 AI 애플리케이션의 핵심 요소 중 하나입니다. 그 중에서도 모델을 효율적으로 관리하고 운영하는 것은 매우 중요합니다. Triton Inference Server는 이러한 요구에 부응하기 위해 설계된 강력한 도구입니다. 이번 시리즈에서는 Triton Inference Server에 대해 샅샅히 파헤처보는 글을 작성해보려고 합니다.
지난 포스트 다시보기
Concurrent Model Execution
Triton 아키텍처를 사용하면 동일한 시스템에서 여러 모델 및/또는 동일한 모델의 여러 인스턴스를 병렬로 실행할 수 있습니다. 시스템에는 GPU가 0개, 1개 또는 다수 있을 수 있습니다. 다음 그림은 두 가지 모델의 예를 보여줍니다.
Triton이 현재 어떤 요청도 처리하고 있지 않다고 가정할 때, 각 모델에 대해 하나씩 두 개의 요청이 동시에 도착하면 Triton은 즉시 두 요청을 모두 GPU에 예약하고 GPU의 하드웨어 스케줄러는 두 계산을 병렬로 작업하기 시작합니다. 시스템의 CPU에서 실행되는 모델은 각 모델의 CPU 스레드 실행 일정이 시스템의 OS에서 처리된다는 점을 제외하면 Triton에서 유사하게 처리됩니다.
기본적으로 동일한 모델에 대한 여러 요청이 동시에 도착하면 Triton은 다음 그림과 같이 GPU에서 한 번에 하나만 예약하여 실행을 직렬화합니다.
Triton은 각 모델이 해당 모델의 허용되는 병렬 실행 수를 지정할 수 있도록 하는 인스턴스 그룹이라는 모델 구성 옵션을 제공합니다. 활성화된 각 병렬 실행을 인스턴스라고 합니다. 기본적으로 Triton은 시스템에서 사용 가능한 각 GPU에 대해 각 모델에 단일 인스턴스를 제공합니다. 모델 구성의 instance_group 필드를 이용하여 모델의 실행 인스턴스 수를 변경할 수 있습니다. 다음 그림은 model1이 세 개의 인스턴스를 허용하도록 구성된 경우의 모델 실행을 보여줍니다. 그림에 표시된 것처럼 처음 세 개의 model1 추론 요청은 즉시 병렬로 실행됩니다. 네 번째 model1 추론 요청은 시작하기 전에 처음 세 실행 중 하나가 완료될 때까지 기다려야 합니다.
그럼 하나의 GPU에서 여러 모델을 동시에 수행할 수 있다는 것인데, 이는 어떻게 구현되었을까요? Triton Inference Server의 과거 문서의 내용을 참고하면 아래와 같습니다.
위 그림에 표시된 현재 모델 실행 기능을 제공하기 위해 Triton은 가능한 한 CUDA Stream을 사용하여 GPU의 하드웨어 스케줄링 기능을 활용합니다. CUDA Stream을 통해 Triton은 메모리 복사 및 커널 실행의 독립적인 시퀀스를 GPU에 전달할 수 있습니다. GPU의 하드웨어 스케줄러는 독립적인 실행 스트림을 활용하여 독립적인 메모리 복사 및 커널 실행으로 GPU를 채웁니다. 예를 들어, Stream을 사용하면 GPU가 한 모델에 대한 메모리 복사, 다른 모델에 대한 커널, 또 다른 모델에 대한 다른 커널을 동시에 실행할 수 있습니다.
다음 그림은 Triton 내에서 이것이 어떻게 작동하는지에 대한 몇 가지 세부 정보를 보여줍니다. 각 프레임워크 백엔드(TensorRT, TensorFlow, PyTorch, ONNX 등)는 특정 모델을 실행하는 데 사용되는 Execution Context를 생성하기 위한 API를 제공합니다. (각 프레임워크는 이 개념에 대해 서로 다른 용어를 사용하지만 여기서는 일반적으로 Execution Context라고 부릅니다. ).
프레임워크에 따라 각 Execution Context는 전용 CUDA Stream과 연결되거나 CUDA Stream이 공유될 수 있습니다. 이러한 CUDA Stream은 프레임워크에서 Execution Context와 관련된 모델에 필요한 모든 메모리 복사본과 커널을 실행하는 데 사용됩니다. 특정 모델에 대해 Triton은 모델에 지정된 각 실행 인스턴스에 대해 하나의 Execution Context를 생성합니다. 특정 모델에 대한 추론 요청이 도착하면 해당 요청은 해당 모델과 연결된 모델 스케줄러의 대기열에 추가됩니다.
모델 스케줄러는 해당 모델과 연결된 Execution Context가 유휴 상태가 될 때까지 기다린 다음 대기 중인 요청을 컨텍스트에 보냅니다. 그런 다음 Execution Context는 모델을 실행하는 데 필요한 모든 메모리 복사본과 커널 실행을 해당 Execution Context와 연결된 CUDA Stream으로 발행합니다. 각 CUDA Stream의 메모리 복사본과 커널은 다른 CUDA Stream의 메모리 복사본 및 커널과 독립적입니다. GPU 하드웨어 스케줄러는 모든 CUDA Stream을 살펴보고 GPU에서 실행할 독립적인 메모리 복사본과 커널을 찾습니다.
Models And Schedulers
Triton은 각 모델에 대해 독립적으로 선택할 수 있는 여러 스케줄링 및 배치 처리 알고리즘을 지원합니다. 이번에는 Triton Inference Server에서 제공하는 stateless, stateful 및 ensemble 모델과 Triton이 이러한 모델 유형을 지원하기 위해 스케줄러를 제공하는 방법에 대해 알아봅니다. 특정 모델의 경우 스케줄러의 선택 및 구성은 모델의 구성 파일을 사용하여 수행됩니다.
Stateless Models
Triton의 스케줄러와 관련하여 stateless 모델은 추론 요청 간에 state를 유지하지 않습니다. stateless 모델에서 수행된 각 추론은 해당 모델을 사용하는 다른 모든 추론과 독립적입니다.
Stateless 모델의 예로는 이미지 분류 및 객체 감지와 같은 CNN이 있습니다. 기본 스케줄러 또는 dynamic batcher를 이러한 stateless 모델의 스케줄러로 사용할 수 있습니다.
내부 메모리가 있는 RNN 및 유사한 모델은 유지하는 state가 추론 요청에 걸쳐 있지 않는 한 stateless이 될 수 있습니다. 예를 들어 RNN은 배치 처리의 모든 요소를 반복하는 모델 구조인데, 이러한 RNN의 추론 요청 배치 처리 간에 내부 state가 전달되지 않는 경우 Triton에 의해 stateless로 간주됩니다. 이러한 stateless 모델에는 기본 스케줄러를 사용할 수 있습니다. 모델은 일반적으로 배치 처리가 여러 추론 요청을 나타낼 것으로 예상하지 않으므로 dynamic batcher를 사용할 수 없습니다.
Stateful Models
Triton의 스케줄러와 관련하여 stateful 모델은 추론 요청 간에 state를 유지합니다. 모델은 여러 개의 추론 요청을 기대하며, 이 요청들은 함께 추론 시퀀스를 형성합니다. 이 시퀀스는 모델이 유지하는 상태가 올바르게 업데이트될 수 있도록 동일한 모델 인스턴스로 라우팅되어야 합니다. 더욱이, 모델은 Triton이 시퀀스의 시작과 끝을 나타내는 제어 신호와 같은 것들을 제공하도록 요구할 수 있습니다.
이러한 stateful 모델에는 sequence batcher를 사용해야 합니다. 아래 설명된 대로 sequence batcher는 모델이 상태를 올바르게 유지할 수 있도록 시퀀스의 모든 추론 요청이 동일한 모델 인스턴스로 라우팅되도록 합니다. 또한 sequence batcher는 모델과 통신하여 시퀀스가 시작되는 시기, 시퀀스가 종료되는 시기, 시퀀스에 실행할 준비가 된 추론 요청이 있는 시기 및 시퀀스의 correlation ID를 나타냅니다.
Stateful 모델에 대한 추론 요청을 할 때 클라이언트 애플리케이션은 시퀀스의 모든 요청에 동일한 correlation ID를 제공해야 하며 시퀀스의 시작과 끝도 표시해야 합니다. Correlation ID를 통해 Triton은 요청이 동일한 시퀀스에 속해 있음을 식별할 수 있습니다.
Ensemble Models
Ensemble 모델은 하나 이상의 모델로 구성된 파이프라인과 해당 모델 간의 입력 및 출력 텐서 연결을 나타냅니다. Ensemble 모델은 "데이터 전처리 -> 추론 -> 데이터 후처리"와 같은 여러 모델이 포함된 절차를 캡슐화하는 데 사용됩니다. 이러한 목적으로 ensemble 모델을 사용하면 중간 텐서를 전송하는 오버헤드를 방지하고 Triton으로 전송해야 하는 요청 수를 최소화할 수 있습니다.
Ensemble 내 모델이 사용하는 스케줄러와 관계없이 ensemble 모델에는 ensemble 스케줄러를 사용해야 합니다. ensemble 스케줄러의 경우 ensemble 모델은 실제 모델이 아닙니다. 대신 모델 구성의 ModelEnsembling::Step 항목으로 ensemble 내 모델 간의 데이터 흐름을 지정합니다. 스케줄러는 각 단계에서 출력 텐서를 수집하고 사양에 따라 다른 단계의 입력 텐서로 제공합니다. 그럼에도 불구하고 ensemble 모델은 외부적으로 보면 여전히 하나의 모델로 보입니다.
Ensemble 모델은 관련된 모델의 특성을 상속하므로 요청 헤더의 메타데이터는 ensemble 내의 모델을 준수해야 합니다. 예를 들어, 모델 중 하나가 stateful 모델인 경우 ensemble 모델에 대한 추론 요청에는 stateful 모델에 언급된 정보가 포함되어야 하며, 이 정보는 스케줄러에 의해 stateful 모델에 제공됩니다.
예를 들어, 다음과 같은 모델 구성을 갖는 이미지 분류 및 segmentation을 위한 ensemble 모델을 작성할 수 있습니다.
name: "ensemble_model"
platform: "ensemble"
max_batch_size: 1
input [
{
name: "IMAGE"
data_type: TYPE_STRING
dims: [ 1 ]
}
]
output [
{
name: "CLASSIFICATION"
data_type: TYPE_FP32
dims: [ 1000 ]
},
{
name: "SEGMENTATION"
data_type: TYPE_FP32
dims: [ 3, 224, 224 ]
}
]
ensemble_scheduling {
step [
{
model_name: "image_preprocess_model"
model_version: -1
input_map {
key: "RAW_IMAGE"
value: "IMAGE"
}
output_map {
key: "PREPROCESSED_OUTPUT"
value: "preprocessed_image"
}
},
{
model_name: "classification_model"
model_version: -1
input_map {
key: "FORMATTED_IMAGE"
value: "preprocessed_image"
}
output_map {
key: "CLASSIFICATION_OUTPUT"
value: "CLASSIFICATION"
}
},
{
model_name: "segmentation_model"
model_version: -1
input_map {
key: "FORMATTED_IMAGE"
value: "preprocessed_image"
}
output_map {
key: "SEGMENTATION_OUTPUT"
value: "SEGMENTATION"
}
}
]
}
위의 구성을 가진 Ensemble 모델에 대한 추론 요청이 수신되면 ensemble 스케줄러는 다음을 수행합니다.
- 요청의 "IMAGE" 텐서는 전처리 모델의 입력 "RAW_IMAGE"에 매핑됩니다.
- 필요한 입력 텐서가 모두 준비되었으므로 ensemble 내의 모델을 확인하고 전처리 모델에 내부 요청을 보냅니다.
- 내부 요청의 완료를 인식하고 출력 텐서를 수집하고 콘텐츠를 ensemble 내에서 "preprocessed_image"에 매핑합니다.
- 새로 수집된 텐서를 ensemble 내 모델의 입력에 매핑합니다. 이 경우 "classification_model" 및 "segmentation_model"의 입력이 매핑되고 준비된 것으로 표시됩니다.
- 새로 수집된 텐서가 필요한 모델을 확인하고, 입력이 준비된 모델(이 경우 classification 모델, segmentation 모델)에 내부 요청을 보냅니다. 응답은 개별 모델의 로드 및 계산 시간에 따라 임의의 순서로 지정됩니다.
- 더 이상 내부 요청이 전송되지 않을 때까지 3~5단계를 반복한 다음 앙상블 출력 이름에 매핑된 텐서를 사용하여 추론 요청에 응답합니다.
위의 순서를 도식화하면 아래 그림과 같습니다:
Scheduling And Batching
Triton은 개별 추론 요청이 배치 입력을 지정하도록 허용하여 일괄 추론을 지원합니다. 입력 배치에 대한 추론은 동시에 수행되며 이는 추론 처리량을 크게 늘릴 수 있으므로 GPU에 특히 중요합니다. 많은 사용 사례에서 개별 추론 요청은 배치 처리되지 않으므로 배치 처리로 인한 처리량 이점을 누릴 수 없습니다.
Triton Inference Server 서버에는 다양한 모델 유형과 사용 사례를 지원하는 여러 스케줄링 및 배치 처리 알고리즘이 포함되어 있습니다.
Default Scheduler
모델 구성에 scheduling_choice 속성이 지정되지 않은 경우, 기본 스케줄러가 모델에 사용됩니다. 기본 스케줄러는 단순히 모델에 대해 구성된 모든 모델 인스턴스에 추론 요청을 배포합니다.
Dynamic Batcher
Dynamic batching은 서버에서 추론 요청을 결합하여 배치 처리가 동적으로 생성되도록 하는 Triton의 기능입니다. 배치 요청을 생성하면 일반적으로 처리량이 증가합니다. Stateless 모델에는 동적 배처를 사용해야 합니다. 동적으로 생성된 배치는 해당 모델에 대해 구성된 모든 모델 인스턴스에 배포됩니다.
Dynamic batching은 모델 구성의 ModelDynamicBatching 속성을 사용하여 각 모델에 대해 독립적으로 활성화되고 구성됩니다. 이러한 설정은 동적으로 생성된 배치의 기본 크기, 다른 요청이 동적 배치에 참여하도록 허용하기 위해 스케줄러에서 요청을 지연할 수 있는 최대 시간, 큐 크기, 우선 순위 및 시간 초과와 같은 큐 속성을 제어합니다.
위에서 Concurrent Model Execution에 대해서 다루었던 내용을 참고하면 Dynamic batching과 Concurrent Model Execution은 동시에 처리가 가능합니다. Model Instance가 2일 경우, 위의 도표는 아래처럼 수행됩니다.
Dynamic Batcher를 적절히 설정하기 위해서 아래와 같은 것들을 고민해보면 좋습니다.
Preferred Batch Size
Preferred_batch_size 속성은 dynamic batcher가 생성을 시도해야 하는 배치 크기를 나타냅니다. 대부분의 모델의 경우 권장 구성 프로세스에 설명된 대로 Preferred_batch_size를 지정하면 안 됩니다. 다양한 배치 크기에 대해 여러 최적화 프로필을 지정하는 TensorRT 모델은 예외입니다. 이 경우 일부 최적화 프로필은 다른 프로필에 비해 상당한 성능 향상을 제공할 수 있으므로 이러한 고성능 최적화 프로필에서 지원하는 배치 크기에 Preferred_batch_size를 사용하는 것이 합리적일 수 있습니다.
dynamic_batching {
preferred_batch_size: [ 4, 8 ]
}
추론에 모델 인스턴스를 사용할 수 있게 되면 dynamic batcher는 스케줄러에서 사용 가능한 요청에서 배치 생성을 시도합니다. 요청은 요청이 수신된 순서대로 배치 처리에 추가됩니다. dynamic batcher가 기본 크기의 배치를 형성할 수 있는 경우, 가능한 가장 큰 기본 크기의 배치를 생성하여 추론을 위해 보냅니다. dynamic batcher가 기본 크기의 배치를 구성할 수 없는 경우(또는 동적 배처가 기본 배치 크기로 구성되지 않은 경우) 모델에서 허용하는 최대 배치 크기보다 작은 가능한 가장 큰 크기의 배치를 보냅니다.
Delayed Batching
다른 요청이 dynamic batch에 참여할 수 있도록 스케줄러에서 제한된 시간 동안 요청을 지연할 수 있도록 dynamic batcher를 구성할 수 있습니다. 예를 들어 다음 구성은 요청에 대한 최대 지연 시간을 100마이크로초로 설정합니다.
dynamic_batching {
max_queue_delay_microseconds: 100
}
max_queue_delay_microseconds 속성 설정은 최대 크기(또는 기본 크기) 배치를 생성할 수 없을 때 dynamic batcher 동작을 변경합니다. 사용 가능한 요청에서 최대 크기 또는 기본 크기의 배치를 생성할 수 없는 경우 구성된 max_queue_delay_microseconds 값보다 오래 지연되는 요청이 없는 한 동적 배치 처리는 배치 전송을 지연합니다. 이 지연 동안 새 요청이 도착하고 dynamic batcher가 최대 또는 기본 배치 크기의 배치를 형성하도록 허용하는 경우 해당 배치는 추론을 위해 즉시 전송됩니다. 지연이 만료되면 dynamic batcher는 최대 또는 기본 크기가 아니더라도 배치를 있는 그대로 보냅니다.
Priority Levels
기본적으로 dynamic batcher는 모델에 대한 모든 추론 요청을 보관하는 단일 queue를 유지합니다. 요청은 순서대로 처리되고 배치 처리됩니다. Priority_levels 속성을 사용하면 dynamic batcher 내에서 여러 우선순위 수준을 생성하여 우선순위가 높은 요청이 우선순위가 낮은 요청을 우회할 수 있습니다. 동일한 우선순위 수준의 요청은 순서대로 처리됩니다. 우선순위를 설정하지 않은 추론 요청은 default_priority_level 속성을 사용하여 예약됩니다.
Queue Policy
dynamic batcher는 배치 처리를 위해 요청이 queue에 추가되는 방식을 제어하는 여러 설정을 제공합니다.
Priority_levels가 정의되지 않은 경우 default_queue_policy를 사용하여 단일 대기열에 대한 ModelQueuePolicy를 설정할 수 있습니다. Priority_levels가 정의되면 각 우선순위 수준은 default_queue_policy 및 Priority_queue_policy에 지정된 대로 서로 다른 ModelQueuePolicy를 가질 수 있습니다.
ModelQueuePolicy 속성을 사용하면 max_queue_size를 사용하여 최대 대기열 크기를 설정할 수 있습니다. timeout_action, default_timeout_microseconds 및 allow_timeout_override 설정을 사용하면 대기열의 시간이 지정된 시간 초과를 초과하는 경우 개별 요청이 거부되거나 연기되도록 queue를 구성할 수 있습니다.
Sequence Batcher
dynamic batcher와 마찬가지로 sequence batcher는 배치 처리되지 않은 추론 요청을 결합하여 배치 처리가 동적으로 생성됩니다. dynamic batcher와 달리 sequence batcher는 일련의 추론 요청을 동일한 모델 인스턴스로 라우팅해야 하는 stateful 모델에 사용해야 합니다. 동적으로 생성된 배치는 해당 모델에 대해 구성된 모든 모델 인스턴스에 배포됩니다.
sequence batch는 모델 구성의 ModelSequenceBatching 속성을 사용하여 각 모델에 대해 독립적으로 활성화되고 구성됩니다. 이러한 설정은 시퀀스 시간 초과를 제어할 뿐만 아니라 Triton이 시퀀스 시작, 종료, 준비 및 correlation ID를 나타내는 제어 신호를 모델에 보내는 방법을 구성합니다.
Continuous/Inflight Batching with Iterative Sequences
Continuous batching, iteration level batching, 그리고 inflight batching은 각 반복 단계에서 요청 배치 처리를 형성하는 배치 처리 전략을 설명하기 위해 LLM(대형 언어 모델) 추론에 사용되는 용어입니다. 배치를 "Continuous"하게 구성함으로써 추론 서버는 배치의 모든 요청이 완료될 때까지 기다리지 않고 배치 슬롯이 비어 있는 즉시 배치 슬롯을 재사용하여 처리량을 늘릴 수 있습니다.
요청을 처리하는 데 필요한 단계 수가 크게 다를 수 있으므로 기존 요청과 새 요청을 지속적으로 일괄 처리하면 처리량과 대기 시간이 크게 향상될 수 있습니다.
iterative sequences로 진행 중인 배치 처리를 달성하려면 백엔드는 요청 처리를 여러 단계로 나누어야 하며, 각 단계는 하나의 Triton 모델 인스턴스 실행에 해당합니다. 각 단계가 끝나면 모델 인스턴스는 완료된 요청을 해제하고 아직 진행 중인 요청을 다시 예약합니다. 그런 다음 Triton은 새로운 요청과 일정이 변경된 요청을 혼합하는 다음 요청 배치를 구성하고 예약합니다.
'AI > MLOps' 카테고리의 다른 글
LitServe 리뷰 (1) | 2024.08.31 |
---|---|
Triton Inference Server #5. Python Backend (0) | 2024.05.12 |
Triton Inference Server #4. Model Configuration (0) | 2024.05.12 |
Triton Inference Server #3. Model Management & Repository (0) | 2024.05.12 |
Triton Inference Server #1. Triton Inference Server란? (0) | 2024.04.22 |