최적화
최적화 (Optimization)
Triton Inference Server는 모델의 지연시간(latency)을 낮추고 처리량(throughput)을 높이는 데 쓸 수 있는 많은 기능을 제공합니다. 이 문서는 그 기능들을 소개하고 성능을 개선하는 방법을 보여줍니다. 전제 조건으로 QuickStart를 따라 예제 모델 저장소로 Triton과 클라이언트 예제를 먼저 실행해 보세요.
이 절은 단일 모델에 대한 지연시간·처리량 트레이드오프를 이해하는 데 집중합니다. Model Analyzer 절은 모델의 GPU 메모리 사용률을 파악해 단일 GPU에서 여러 모델을 가장 잘 실행하는 방법을 정하는 데 도움을 주는 도구를 설명해요. Triton에서 모델 성능을 측정할 클라이언트 애플리케이션이 아직 없다면 Performance Analyzer에 익숙해지는 게 좋습니다. Performance Analyzer는 모델 성능을 최적화할 때 꼭 필요한 도구예요.
실행 예시로 우리는 QuickStart로 얻을 수 있는 ONNX Inception 모델을 사용하겠습니다. 기준선(baseline)으로는 성능 기능을 전혀 켜지 않은 기본 모델 구성으로 perf_analyzer를 돌려 성능을 측정합니다.
$ perf_analyzer -m inception_onnx --percentile=95 --concurrency-range 1:4
...
Inferences/Second vs. Client p95 Batch Latency
Concurrency: 1, throughput: 62.6 infer/sec, latency 21371 usec
Concurrency: 2, throughput: 73.2 infer/sec, latency 34381 usec
Concurrency: 3, throughput: 73.2 infer/sec, latency 50298 usec
Concurrency: 4, throughput: 73.4 infer/sec, latency 65569 usec
결과를 보면 최적화하지 않은 모델 구성은 초당 약 73회의 추론 처리량을 냅니다. 동시 요청을 1개에서 2개로 늘릴 때 처리량이 크게 오르고 그 뒤로는 평평해지는 점을 주목하세요. 동시 요청 1개일 때 Triton은 응답을 클라이언트에 돌려주고 다음 요청이 서버에 도착하기까지 유휴 상태예요. 동시 요청 2개가 되면 한 요청의 처리를 다른 요청의 통신과 겹쳐서 처리량이 오릅니다. perf_analyzer를 Triton과 같은 시스템에서 실행하기 때문에 요청 2개면 통신 지연을 완전히 숨기기에 충분합니다.
최적화 설정
대부분의 모델에서 가장 큰 성능 개선을 주는 Triton 기능은 다이나믹 배칭입니다. 이 예제가 개념적으로 더 자세히 풀어줍니다. 모델이 배칭을 지원하지 않는다면 "모델 인스턴스"로 건너뛰어도 됩니다.
다이나믹 배처
다이나믹 배처는 개별 추론 요청을 더 큰 배치로 묶어서, 개별 요청을 각각 실행하는 것보다 훨씬 효율적으로 실행하게 해줍니다. 다이나믹 배처를 켜려면 Triton을 멈추고, inception_onnx 모델 구성 파일 끝에 다음 줄을 추가한 뒤 다시 시작하세요.
dynamic_batching { }
다이나믹 배처는 요청을 합쳐서 추론하므로 Triton이 더 많은 동시 요청을 처리할 수 있게 해줍니다. 이를 보려면 요청 동시성을 1에서 8까지로 perf_analyzer를 실행하세요.
$ perf_analyzer -m inception_onnx --percentile=95 --concurrency-range 1:8
...
Concurrency: 1, throughput: 66.8 infer/sec, latency 19785 usec
Concurrency: 2, throughput: 80.8 infer/sec, latency 30732 usec
Concurrency: 3, throughput: 118 infer/sec, latency 32968 usec
Concurrency: 4, throughput: 165.2 infer/sec, latency 32974 usec
Concurrency: 5, throughput: 194.4 infer/sec, latency 33035 usec
Concurrency: 6, throughput: 217.6 infer/sec, latency 34258 usec
Concurrency: 7, throughput: 249.8 infer/sec, latency 34522 usec
Concurrency: 8, throughput: 272 infer/sec, latency 35988 usec
동시 요청 8개에서 다이나믹 배처는 다이나믹 배처를 안 쓸 때보다 지연시간을 늘리지 않으면서 초당 272회 추론을 제공합니다.
perf_analyzer가 Triton과 같은 시스템에서 돌 때 흔히 적용되는 두 가지 간단한 규칙을 쓸 수도 있어요. 최소 지연 규칙: 요청 동시성을 1로 하고 다이나믹 배처를 끄며 모델 인스턴스 1개만 사용. 최대 처리량 규칙: 요청 동시성을 2*<최대배치크기>*<모델인스턴스수>로 설정. 지금은 모델 인스턴스 1개로 작업하므로, 최대 배치 크기 4라면 요청 동시성을 2*4*1=8로 잡습니다.
$ perf_analyzer -m inception_onnx --percentile=95 --concurrency-range 8
...
Concurrency: 8, throughput: 267.8 infer/sec, latency 35590 usec
모델 인스턴스
Triton은 추론에 사용할 각 모델의 복사본 개수를 지정할 수 있게 해줍니다. 기본적으로 각 모델 사본이 하나지만, 인스턴스 그룹으로 모델 구성에서 원하는 인스턴스 수를 정할 수 있어요. 보통 모델 인스턴스 2개는 성능을 개선하는데, 메모리 전송 연산(예: CPU↔GPU)을 추론 연산과 겹칠 수 있기 때문입니다. 다중 인스턴스는 GPU에서 더 많은 추론 작업을 동시에 실행해 GPU 사용률도 높여줍니다. 작은 모델은 두 개보다 많은 인스턴스가 유리할 수 있으니 perf_analyzer로 실험해 보세요.
inception_onnx 모델의 인스턴스 2개를 지정하려면: Triton을 멈추고, 앞서 추가했을 다이나믹 배칭 설정을 제거하고(다이나믹 배처와 다중 모델 인스턴스 결합은 아래에서 설명), 모델 구성 파일 끝에 다음을 추가한 뒤 다시 시작하세요.
instance_group [ { count: 2 } ]
기준선과 같은 옵션으로 perf_analyzer를 실행합니다.
$ perf_analyzer -m inception_onnx --percentile=95 --concurrency-range 1:4
...
Concurrency: 1, throughput: 70.6 infer/sec, latency 19547 usec
Concurrency: 2, throughput: 106.6 infer/sec, latency 23532 usec
Concurrency: 3, throughput: 110.2 infer/sec, latency 36649 usec
Concurrency: 4, throughput: 108.6 infer/sec, latency 43588 usec
이 경우 인스턴스 2개가 처리량을 인스턴스 1개일 때의 약 73에서 약 110회/초로 끌어올립니다.
다이나믹 배처와 다중 모델 인스턴스를 둘 다 켤 수도 있습니다. 모델 구성 파일을 다음을 포함하도록 바꾸면 돼요.
dynamic_batching { }
instance_group [ { count: 2 } ]
위에서 다이나믹 배처만 쓸 때와 같은 옵션으로 perf_analyzer를 실행하면:
$ perf_analyzer -m inception_onnx --percentile=95 --concurrency-range 16
...
Concurrency: 16, throughput: 289.6 infer/sec, latency 59817 usec
다이나믹 배처 + 인스턴스 1개와 비교해 인스턴스 2개는 지연시간은 늘리면서 처리량은 크게 개선하지 못합니다. 이 모델은 다이나믹 배처만으로 GPU를 완전히 활용할 수 있어 모델 인스턴스를 추가해도 이득이 없기 때문이에요. 일반적으로 다이나믹 배처와 다중 인스턴스의 이점은 모델마다 다르므로 perf_analyzer로 실험해 자신의 처리량·지연 요구에 맞는 설정을 찾아야 합니다.
프레임워크별 최적화
Triton에는 지원되는 모델 프레임워크 중 일부에만 적용되는 여러 최적화 설정이 있습니다. 이 설정은 모델 구성의 최적화 정책으로 제어돼요. 종단 간 논의는 이 가이드를 참고하세요.
ONNX + TensorRT 최적화 (ORT-TRT)
특히 강력한 최적화는 ONNX 모델과 TensorRT를 함께 쓰는 것입니다. ONNX 모델에 TensorRT 최적화를 적용하는 예로, QuickStart로 얻는 ONNX DenseNet 모델을 사용하겠습니다. 기준선은 성능 기능이 없는 기본 구성으로 perf_analyzer로 측정합니다.
$ perf_analyzer -m densenet_onnx --percentile=95 --concurrency-range 1:4
...
Concurrency: 1, 113.2 infer/sec, latency 8939 usec
Concurrency: 2, 138.2 infer/sec, latency 14548 usec
Concurrency: 3, 137.2 infer/sec, latency 21947 usec
Concurrency: 4, 136.8 infer/sec, latency 29661 usec
모델에 TensorRT 최적화를 켜려면: Triton을 멈추고, 모델 구성 파일 끝에 다음을 추가한 뒤 다시 시작하세요.
optimization {
execution_accelerators {
gpu_execution_accelerator : [
{
name : "tensorrt"
parameters { key : "precision_mode" value : "FP16" }
parameters { key : "max_workspace_size_bytes" value : "1073741824" }
}
]
}
}
Triton이 시작할 때 콘솔 출력을 확인하고 "Starting endpoints" 메시지가 나올 때까지 기다리세요. TensorRT 최적화를 켜면 ONNX 모델 로딩이 상당히 느려질 수 있습니다. 운영 환경에서는 모델 워밍업을 써서 이 시작/최적화 지연을 피하세요. 이제 기준선과 같은 옵션으로 perf_analyzer를 실행합니다.
$ perf_analyzer -m densenet_onnx --percentile=95 --concurrency-range 1:4
...
Concurrency: 1, 190.6 infer/sec, latency 5384 usec
Concurrency: 2, 273.8 infer/sec, latency 7347 usec
Concurrency: 3, 272.2 infer/sec, latency 11046 usec
Concurrency: 4, 266.8 infer/sec, latency 15089 usec
TensorRT 최적화는 처리량을 2배 올리면서 지연시간을 절반으로 줄였습니다. TensorRT의 이점은 모델에 따라 다르지만, 일반적으로 상당한 성능 개선을 줄 수 있어요.
ONNX + OpenVINO 최적화
CPU에서 실행되는 ONNX 모델은 OpenVINO를 사용해 가속할 수도 있습니다. ONNX 모델에 OpenVINO 최적화를 켜려면 모델 구성 파일 끝에 다음을 추가하세요.
optimization {
execution_accelerators {
cpu_execution_accelerator : [
{ name : "openvino" }
]
}
}
NUMA 최적화
현대 CPU는 여러 코어·메모리·인터커넥트로 구성되어 있어, 스레드와 데이터를 어떻게 배치하느냐에 따라 성능 특성이 달라집니다. Triton은 시스템의 NUMA 구성을 설명하는 **호스트 정책(host policy)**을 설정하고, 모델 인스턴스를 서로 다른 호스트 정책에 배정해 NUMA 특성을 활용하게 해줍니다.
호스트 정책
Triton은 시작 시 정책 이름과 연결된 호스트 정책을 지정할 수 있게 해줍니다. 모델 인스턴스가 인스턴스 그룹의 host policy 필드로 같은 정책 이름을 지정하면 그 호스트 정책이 적용돼요. 지정하지 않으면 인스턴스 속성에 기반한 기본 이름으로 설정됩니다.
호스트 정책은 커맨드라인에서 이렇게 지정합니다:
--host-policy=<policy_name>,<setting>=<value>
현재 지원되는 설정:
- numa-node: 호스트 정책이 바인딩될 NUMA 노드 id. 이 정책은 메모리 할당을 해당 노드로 제한합니다.
- cpu-cores: 실행할 CPU 코어. 이 호스트 정책이 설정된 인스턴스는 그 CPU 코어 중 하나에서 실행됩니다.
GPU 0이 CPU 코어 0~15를 가진 NUMA 노드 0에 바인딩되도록 구성된 시스템을 가정하면, gpu_0에 대해 numa-node와 cpu-cores 정책을 다음과 같이 설정합니다:
$ tritonserver --host-policy=gpu_0,numa-node=0 --host-policy=gpu_0,cpu-cores=0-15 ...