콘텐츠로 이동

04. LMI co-host: GPU 한 장에 모델 여러 개

GPU 비용을 아끼면서 인코더 여러 개를 co-host 할 수 있을까요?

LMI(DJL Serving)를 사용할 수 있습니다. 이 실험에서는 GPU 한 장에 모델 3개를 배포했습니다.

어떻게 GPU 1장에 여러 모델이 올라가나요?

container 하나가 Java router와 모델별 Python process로 실행되고, process들이 같은 GPU를 공유합니다. SageMaker에서는 container 하나로 보이므로 inference component의 GPU 장 단위 할당 제약이 걸리지 않습니다.

로컬 L40S에서 모델 3개가 GPU memory 5.7GB를 사용했고 각각 정상 응답했습니다. 자세한 구조는 LMI 내부 구조에 있습니다.

과금

ml.g5.xlarge는 시간당 과금됩니다. 로컬 검증 (bash 04_gpu_cohost_lmi/scripts/serve_local_lmi.sh)을 먼저 하세요.

03(inference component)은 component copy마다 GPU를 최소 한 장 할당합니다. LMI는 container 내부에서 여러 모델이 GPU 한 장을 공유하지만, 모델별 독립 scaling과 routing 기능은 제공하지 않습니다.

03 inference component 04 LMI
GPU 1장에 모델 3개
필요 인스턴스 ml.g6.12xlarge (GPU 4장) ml.g5.xlarge (GPU 1장)
시간당 요금 $5.752 $1.408
GPU 메모리 (모델 3개) 장당 1개씩 점유 5.7GB / 46GB
모델 추가 컴포넌트 생성 S3 업로드만
대상 지정 InferenceComponentName TargetModel

요금은 us-east-1 on-demand hosting 기준이며 2026-08-07에 AWS Pricing API로 조회했습니다.

실측 결과 (max_len=512 고정)

p50 p90 p95 p99 b=8 throughput batch efficiency 100만 건 비용
02 CPU+ONNX 58.3 ms 63.0 ms 63.5 ms 64.2 ms 27/s 1.6x $4.20
03 inference component 25.8 ms 27.4 ms 28.3 ms 28.4 ms 78/s 2.0x $20.48
04 GPU LMI 49.7 ms 50.9 ms 51.5 ms 52.8 ms 104/s 5.2x $3.76

요금은 us-east-1 on-demand hosting 기준이며 2026-08-07에 AWS Pricing API로 조회했습니다. 100만 건 비용은 인스턴스가 그 시간 동안 계속 떠 있다고 가정한 값입니다.

batch=1 latency는 inference component가 낮았고, 처리량 기준 비용은 LMI가 낮았습니다. 전체 수치는 docs/benchmark/results.md에 있습니다.

concurrency 8에서는 inference component가 61 req/s로 LMI(39)보다 앞섭니다(GPU 4장의 여유). LMI에서 concurrency를 올리려면 gpu.maxWorkers를 늘리세요(GPU 메모리 여유가 있습니다).

실행

# 로컬 검증 (과금 없음): GPU 1장에 3개가 올라가는지 먼저 확인
bash 04_gpu_cohost_lmi/scripts/serve_local_lmi.sh

# 클라우드
uv run python 04_gpu_cohost_lmi/deploy.py --dry-run     # S3 업로드, endpoint 인스턴스 생성 안 함
uv run python 04_gpu_cohost_lmi/deploy.py               # 모델 3개
uv run python 04_gpu_cohost_lmi/deploy.py --models mdeberta minilm

uv run python 04_gpu_cohost_lmi/invoke.py --endpoint <ep> --mode cloud --all
uv run python -m benchmark.run --mode cloud --endpoint <ep> \
    --target-model mdeberta.tar.gz --pad-to-max --sweep-batch

uv run python -m common.cleanup --delete-all     # 실습 리소스 삭제

어떻게 동작하나요

SageMaker MME 규약을 씁니다(multi-models=true 라벨 확인). S3의 한 prefix 아래에 모델별 model.tar.gz를 두고 TargetModel로 호출합니다.

s3://bucket/encoder-serving/lmi/04-lmi/
├── mdeberta.tar.gz      serving.properties만 들어 있음
├── minilm.tar.gz
└── xlmr-large.tar.gz

각 tarball에는 serving.properties만 있고 model weight는 없습니다. option.model_id를 지정하면 container가 Hugging Face Hub에서 model을 내려받습니다. 실습에서는 큰 model Artifact를 S3에 올리는 과정을 줄일 수 있습니다. 운영 환경에서는 시작 시간과 재현성을 위해 weight를 S3에 저장하는 방식을 검토하세요.

engine=Python
option.model_id=MoritzLaurer/mDeBERTa-v3-base-xnli-multilingual-nli-2mil7
option.task=text-classification
option.rolling_batch=disable
gpu.minWorkers=1
gpu.maxWorkers=1
required_memory_mb=2048

LMI가 인코더를 인식합니다

LmiConfigRecommender: The model task architecture [DebertaV2ForSequenceClassification]
is not supported for optimized inference. LMI will attempt to load the model using
HuggingFace Accelerate. Optimized inference is only available for the following
task architectures: [ForConditionalGeneration, LMHeadModel, ForCausalLM]

Detected rolling_batch: disable, for modelType: deberta-v2

rolling_batch: disable자동 선택합니다. 인코더에는 continuous batching이 의미가 없으므로 적절한 선택입니다. serving.properties에 명시하면 판단 단계를 건너뛰어 시작이 빠릅니다.

vLLM은 지원하지 않는 architecture를 거부하지만 LMI는 Hugging Face Accelerate 경로로 fallback합니다. 이 경로로 DeBERTa를 서빙할 수 있습니다 (repository의 08_engine_comparison/ 참고).

놓치기 쉬운 것들

Mode: "MultiModel"과 prefix. ModelDataUrl에 파일이 아니라 prefix를 줍니다. 파일로 주면 단일 모델 endpoint가 됩니다.

TargetModel은 tar.gz 이름입니다 (mdeberta.tar.gz). 모델 키가 아닙니다.

첫 호출에는 model load 시간이 포함됩니다. LMI가 요청 시점에 모델을 로드하므로 benchmark 전에 충분한 --warmup을 적용하세요.

막힌 경우 → docs/troubleshooting.md

다음으로 읽을 것

유휴 시간 비용을 없애려면 → 05_gpu_scale_to_zero (이 endpoint에 MinInstanceCount: 0을 붙입니다)

전체 실측 결과: docs/concepts/findings.md, docs/benchmark/results.md