콘텐츠로 이동

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.pybuild_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을 결정합니다

SAGEMAKER_MODEL_SERVER_WORKERS
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회를 사용했습니다.

다음으로 읽을 것

막힌 경우 → 트러블슈팅