01. 단일 endpoint: one model, one container¶
278M 인코더에 GPU가 필요한가요? batching과 worker 수는 어떻게 정하나요?
01에서 CPU와 GPU, batching, worker 설정을 비교합니다. 이 결과를 뒤 시나리오의 baseline으로 사용합니다.
가장 단순한 형태입니다. 모델 하나가 컨테이너 하나를 쓰고, 그 컨테이너가 인스턴스를 독차지 합니다(one model, one container). 02 부터는 여기서 무엇을 공유하기 시작하는지가 갈립니다.
| 시나리오 | 공유 단위 | 모델 : 컨테이너 |
|---|---|---|
| 01 (여기) | 공유 없음 | 1 : 1 |
| 02 멀티컨테이너 | 인스턴스를 컨테이너들이 나눠 씀 | 1 : 1 (컨테이너가 여러 개) |
| 03 inference component | 인스턴스의 GPU를 컴포넌트들이 나눠 씀 | 1 : 1 (컴포넌트마다 컨테이너) |
| 04 LMI | 컨테이너 하나를 모델들이 공유 | N : 1 |
01은 baseline입니다. 여기서 정한 인스턴스 유형, batching policy, worker 수를 기준으로 Co-host 구성의 latency, throughput, 비용을 비교합니다.
과금
클라우드 endpoint는 삭제할 때까지 시간당 비용이 발생합니다. 로컬 Docker 검증을 먼저 실행하고, 실습 후 endpoint를 삭제하세요.
먼저 로컬에서 확인합니다¶
Endpoint를 만들기 전에 로컬 Docker에서 같은 DLC image를 실행합니다. SageMaker container
contract(/ping, /invocations)와 payload 형식을 확인할 수 있습니다. IAM, network,
capacity 같은 클라우드 환경 문제는 별도로 확인해야 합니다.
bash 01_single_endpoint/scripts/serve_local.sh # GPU, mdeberta
DEVICE=cpu bash 01_single_endpoint/scripts/serve_local.sh
WORKERS=4 bash 01_single_endpoint/scripts/serve_local.sh
MODEL_KEY=minilm bash 01_single_endpoint/scripts/serve_local.sh
uv run python 01_single_endpoint/invoke.py --mode local
uv run python -m benchmark.run --mode local --pad-to-max --sweep-batch
uv run python -m benchmark.run --mode local --pad-to-max --sweep-concurrency
bash 01_single_endpoint/scripts/cleanup_local.sh
클라우드에 배포합니다¶
uv run python 01_single_endpoint/deploy.py --dry-run # endpoint 인스턴스 생성 전 API 구성 확인
uv run python 01_single_endpoint/deploy.py # CPU
uv run python 01_single_endpoint/deploy.py --gpu --workers 4
uv run python 01_single_endpoint/invoke.py --mode cloud --endpoint <name>
uv run python -m benchmark.run --mode cloud --endpoint <name> --pad-to-max --sweep-batch
uv run python 01_single_endpoint/cleanup.py --endpoint <name> # endpoint와 관련 리소스 삭제
실측 결과¶
GPU vs CPU¶
mDeBERTa, workers=4, 실제 SageMaker endpoint 실측입니다.
| 인스턴스 | 런타임 | b=1 p50 | 정확도 |
|---|---|---|---|
| ml.c6i.2xlarge | PyTorch | 1810 ms | 100% |
| ml.c6i.2xlarge | ONNX | 58 ms | 100% |
| ml.g5.xlarge | PyTorch | 28 ms | 100% |
이 실험에서 ONNX Runtime CPU의 p50은 58ms, GPU의 p50은 28ms였습니다. 수십 ms 수준의 Latency를 허용한다면 인스턴스 비용과 함께 CPU 배포를 비교할 수 있습니다.
ONNX 경로는 02 CPU co-host (멀티컨테이너)에 있습니다.
배칭: payload에 batch_size를 명시해야 합니다¶
inputs에 리스트만 넣으면 배칭되지 않습니다. transformers pipeline이 batch_size 미지정 시
한 건씩 순차 처리합니다.
| batch 32, 한 요청 | latency |
|---|---|
parameters 없음 |
510 ms |
parameters.batch_size=32 |
25 ms |
common/payload.py의 build_batch_payload가 이 값을 추가합니다. 직접 payload를 만들 때도
같은 값을 넣어야 합니다.
GPU 배치 확장(실제 문장 길이 기준):
| batch | samples/s | vs batch=1 | efficiency |
|---|---|---|---|
| 1 | 55.2 | 1.00x | 1.00 |
| 8 | 408.6 | 7.40x | 0.93 |
| 32 | 1280.8 | 23.21x | 0.73 |
Batch가 커질수록 efficiency가 낮아지므로 latency와 throughput 요구사항을 함께 비교하세요.
Worker 수: concurrent request throughput을 결정합니다¶
| concurrency | workers=1 | workers=4 |
|---|---|---|
| 1 | 57 req/s | 53 req/s |
| 4 | 60 req/s | 168 req/s |
| 8 | 60 req/s | 183 req/s |
| 16 | - | 183 req/s |
Worker 1개에서는 concurrency를 올려도 throughput이 약 60 req/s에 머물고 latency가 증가했습니다. worker 4개에서는 약 183 req/s까지 증가했습니다. endpoint 인스턴스를 늘리기 전에 worker 설정을 확인하세요.
ONNX 서빙에서는 session이 worker마다 모델을 따로 로드하므로 worker 수를 제한해야 합니다.
512 고정 조건 실측 (다른 시나리오와 비교 가능)¶
--pad-to-max --warmup 20, ml.g5.xlarge, workers=4 입니다. 이 조건이 02~06 과 같아서
요약 표에 그대로 들어갑니다.
| batch | p50 | p90 | p95 | p99 | throughput | 정확도 |
|---|---|---|---|---|---|---|
| 1 | 26.8 ms | 29.8 ms | 32.7 ms | 45.4 ms | 35.5 req/s | 100% |
| 8 | 70.7 ms | - | - | 74.1 ms | 112.6 samples/s | - |
01~06의 HF DLC 기반 구성 중에서는 모델 하나를 배포한 01의 throughput이 가장 높았습니다.
같은 ml.g5.xlarge에서 batch=8 throughput은 01이 113 samples/s, 모델 3개를 co-host한 LMI가
104 samples/s였습니다. 모델 하나에는 01을 baseline으로 사용하고, 여러 모델이 GPU를
공유해야 할 때 LMI를 비교하세요. 더 낮은 latency가 필요하면 07(Triton과 TensorRT)을
검토합니다.
측정 조건이 수치를 바꿉니다¶
목표 workload가 max_len=512이므로 --pad-to-max로 같은 조건을 만듭니다. worker가 모두
모델을 로드하도록 충분한 warmup도 적용하세요.
| 조건 | mdeberta b=1 p50 | p99 |
|---|---|---|
| 실제 문장 길이 (59 tok), warmup 3 | 28.2 ms | 819.7 ms |
| max_len=512 고정, warmup 20 | 26.8 ms | 45.4 ms |
p99가 819ms였던 run에서는 측정 중 worker의 모델 로드가 포함됐습니다. 이 실험은 workers=4에서 warmup 20회를 사용했습니다.
다음으로 읽을 것¶
- CPU co-host (ONNX) → 02 CPU co-host (멀티컨테이너)
- GPU 1장에 모델 여러 개 → 04 GPU co-host (LMI)
- vLLM을 검토 중이라면 → 인코더는 왜 다른가 (이 mDeBERTa architecture는 미지원)
막힌 경우 → 트러블슈팅