Qwen3-Coder-480B-A35B-Instruct

H100 GPU에서 최적화하여 서빙하기

by Dr Jenna

최근 Table QA Agent를 구축하기 위해 초대형 MoE 기반 코드 모델인 Qwen3-Coder-480B-A35B-Instruct를 직접 서빙해야 했습니다. 이 모델은 480B 파라미터 규모, 160명의 Expert 중 8명이 활성화되는 MoE 아키텍처, 그리고 native context length 256k를 갖추고 있습니다.

Table QA라는 특성상 응답 지연(latency)이 무엇보다 중요했고, 그다음으로 VRAM 최적화, 마지막으로 throughput을 고려했습니다. 따라서 병렬화 전략과 vLLM 설정 모두 "지연 최소화"를 우선 목표로 잡았습니다.




모델 아키텍처와 병렬화 고려


MoE 모델을 효율적으로 서빙하기 위해서는 DP(Data Parallel), TP(Tensor Parallel), EP(Expert Parallel), PP(Pipeline Parallel)를 어떻게 설정할지가 중요합니다.

PP는 inference에서 버블/스케줄링 오버헤드가 크므로 1로 고정했습니다.

EP는 vLLM에서 --enable-expert-parallel을 켜면 자동으로 DP × TP가 됩니다.

따라서 실질적으로 조정해야 하는 축은 DP와 TP였습니다.

최종 선택:

FP8 가중치 (VRAM 여유 확보)

DP=8, TP=2, EP=16, PP=1

총 16장 GPU를 활용하여 latency와 VRAM을 균형 있게 확보



이 조합은 TP=2로 통신 오버헤드를 최소화하면서, EP=16으로 Expert 가중치를 GPU당 10명으로 분산해 VRAM을 안전하게 사용하도록 해줍니다. 만약 FP8에서도 메모리 부족이 발생한다면 TP=4로 늘려 shard를 더 쪼개는 fallback 전략을 두었습니다.




vLLM 서빙 설정


모델은 vLLM의 API 서버로 띄워 엔드포인트를 제공합니다. 주요 실행 옵션은 다음과 같았습니다:

python -m vllm.entrypoints.openai.api_server \

--model Qwen/Qwen3-Coder-480B-A35B-Instruct \

--tensor-parallel-size 2 \

--enable-expert-parallel \

--max-model-len 65536 \

--gpu-memory-utilization 0.9 \

--kv-cache-dtype auto \

--disable-log-requests \

--disable-log-stats


--tensor-parallel-size 2: 통신 오버헤드 최소화

--enable-expert-parallel: MoE 분산

--max-model-len 65536: 64k new tokens 대응 (OOM 시 32k로 완화 가능)

--gpu-memory-utilization 0.9: OOM 방지

--kv-cache-dtype auto: 필요시 q8/q4로 전환해 VRAM 절감

로그 최소화 옵션: 실시간 경로에서 latency overhead 제거




성능 벤치마크


서빙 성능은 vLLM에서 제공하는 benchmark_serving.py

스크립트를 활용했습니다:

python -m vllm.benchmark.benchmark_serving \

--backend openai \

--host 127.0.0.1

--port 8000 \

--num-prompts 800 \

--concurrency 8 16 32 \

--prompt-length 1024 4096 \

--output-length 1024 4096 \

--random-input


측정 지표는 다음과 같습니다:

Request throughput (req/s)

Output token throughput (tok/s)

TTFT (Time To First Token)

ITL (Inter-Token Latency)

Latency p50/p90/p99


이 과정을 통해 단일 요청 지연과 동시 처리량 간 trade-off를 확인할 수 있었고,

max-num-seqs와 max-num-batched-tokens를 조정하여 latency 중심의 최적점을 찾았습니다.




품질 평가


Table QA 모델 품질은 내부적으로 구축한 NL2SQL 벤치마크 데이터셋을 기반으로 평가했습니다. 이 데이터셋은

DB schema 정보

자연어 질문

정답 SQL

로 구성되어 있습니다.


평가 지표는 두 가지를 사용했습니다:

Execution Accuracy : 모델이 생성한 SQL을 실제 DB에 실행한 결과와 정답 결과를 비교. NL2SQL 태스크의 실질적인 성능을 보여주는 지표로, 최종 품질 판단에 핵심 기준으로 삼았습니다.

Perplexity (PPL) : 동일한 벤치마크에서 정답 SQL을 모델에 입력하여 토큰 시퀀스의 확률 분포 기반 perplexity를 계산. 이는 모델이 “정답 SQL을 얼마나 자연스럽고 가능성 높게 예측하는지”를 나타냅니다. Execution Accuracy가 실제 효용을 보여준다면, Perplexity는 모델의 언어 모델링 능력 및 학습 적합성을 보완적으로 측정합니다.


이렇게 두 지표를 함께 평가함으로써, 모델이 정답을 정확히 실행 가능한 SQL로 내는지(Execution)와 SQL 자체를 얼마나 낮은 불확실성으로 생성하는지(Perplexity)를 모두 확인할 수 있었습니다.




결론

H100 16장을 활용해 Qwen3-Coder-480B-A35B-Instruct를 Table QA Agent용으로 직접 서빙.

지연 최소화 > VRAM 최적화 > 처리량 순으로 목표를 잡고, FP8 + DP=8, TP=2, EP=16, PP=1 구성을 최적 조합으로 선택.

vLLM의 API 서버와 벤치마크 스크립트로 latency/throughput 지표를 측정하고, Execution Accuracy로 정밀 품질을 검증.

향후에는 YARN을 적용해 1M context까지 확장하거나, KV 캐시 quantization으로 메모리 최적화를 추가할 수 있음.





FAQ

1) Replica를 늘리면 자원을 어떻게 조정해야 하나요?

Replica 수를 늘리면 DP(Data Parallel)를 키워 throughput을 확장하는 게 기본 전략입니다.

총 GPU 수 = DP × TP × (PP=1), EP는 자동으로 DP × TP.

Throughput↑ 목적이면 DP↑, VRAM 절약이 필요하면 TP↑.

Latency가 중요하면 TP는 2~4 사이에서 유지하고, DP를 늘리는 쪽으로 확장하는 게 일반적입니다.



---

2) GPU가 8장뿐이라면 어떻게 최적화하나요?

16장 대비 자원이 절반이므로:

조합 예시: DP=4, TP=2 → EP=8

VRAM 부족 시: FP8 가중치 + --kv-cache-dtype q8 또는 q4_1

토큰 길이 완화: max_new_tokens 64k → 32k

배치 제한: --max-num-seqs와 --max-num-batched-tokens를 낮추어 TTFT/ITL 개선
즉, 지연 최소화 기준은 TP=2 유지, VRAM이 힘들면 max_new_tokens를 줄입니다.



---

3) 왜 TP=2를 선호하나요? TP=4는 언제 쓰나요?

TP는 각 레이어마다 AllReduce/AllGather 통신이 추가되므로 TP가 커질수록 latency↑.

TP=2는 latency와 VRAM 절감 간의 균형점입니다.

TP=4는 VRAM이 모자라 OOM 위험이 있는 경우 fallback으로 선택. latency는 조금 손해지만, 메모리 확보가 가능해집니다.



---

4) EP는 직접 세팅 안 하나요?

vLLM에선 --enable-expert-parallel만 켜면 EP=DP×TP로 자동 결정됩니다.
즉, EP는 DP와 TP의 곱으로 간접적으로 설정됩니다. 원하는 EP 크기를 맞추려면 DP와 TP 값을 조정하면 됩니다.


---

5) OOM 발생 시 어떻게 대응하나요?

대응 순서는:

1. KV 캐시 압축: --kv-cache-dtype auto/q8/q4_1


2. max_new_tokens 완화: 64k → 32k


3. TP 확장: 2 → 4 (통신 증가 감수)


4. 프롬프트 관리: prefix caching, 프롬프트 축약
이 순서로 latency 희생을 최소화하며 OOM을 회피할 수 있습니다.




---

6) Native context 256k인데 max_new_tokens는 왜 64k 제한인가요?

Native context length = 프롬프트+생성 합계로 256k까지 지원.

max_new_tokens = 엔진(vLLM)에서 OOM 방지를 위해 걸어둔 출력 길이 상한.
즉, 모델이 256k를 처리할 수 있지만, 안전하게 GPU VRAM을 보호하기 위해 max_new_tokens를 별도로 제한하는 것입니다.



---

7) YARN을 써서 1M context까지 확장하면 무엇이 바뀌나요?

YARN은 RoPE 주파수를 재스케일링하여 native context(256k)를 초과하는 초장문 입력을 처리할 수 있게 해 줍니다.

장점: context 1M까지 확장 가능.

단점: KV 메모리 사용량이 선형으로 늘어나고, native 범위를 벗어난 부분에서는 품질이 다소 떨어질 수 있습니다.
Table QA처럼 64k 응답이면 YARN 필요성은 크지 않습니다.



---

8) 활성 Expert가 8개인데 EP≥8을 권장하는 이유는?

MoE에서 토큰마다 활성 전문가(k개)를 고릅니다.

EP < k이면 한 GPU에 여러 전문가가 몰려 연산/메모리 핫스팟이 생길 수 있습니다.

EP ≥ k이면 토큰이 GPU에 더 균등하게 분산 → 안정성↑.
따라서 활성 Expert=8이면 EP≥8, 만약 활성 Expert=16이면 EP≥16을 권장합니다.



---

9) Speculative decoding은 어떻게 동작하나요? Draft 모델은 꼭 필요한가요?

네, Draft 모델이 필요합니다.

Draft 모델: 작고 빠른 모델, 여러 토큰을 미리 예측.

Target 모델: 메인 모델(Qwen3-480B), draft 결과를 한 번에 검증.

일치하면 승인, 다르면 수정.
vLLM에서는 --speculative-model <draft_model> 옵션으로 draft 모델 경로를 지정해야 합니다. Draft 없이 speculative는 불가능합니다.



---

10) 온라인 벤치 vs 오프라인 벤치 지표 차이는?

온라인 벤치 (엔드투엔드)

Request throughput (req/s)

Token throughput (tok/s)

TTFT (Time To First Token)

ITL (Inter-Token Latency)

Latency 분포 (p50/p90/p99)


오프라인 벤치 (마이크로 성능)

Prefill throughput (프롬프트 인코딩 속도)

Decode throughput (생성 단계 속도)

Batch size vs 처리량 곡선

GPU 메모리 footprint (KV 캐시, 레이어별 소비)

온라인은 “사용자 체감 성능”, 오프라인은 “모델 내부 병목 분석”.


---

11) NL2SQL 태스크에서 Perplexity와 Execution Accuracy는 같은가요?

아닙니다.

Perplexity: 정답 SQL 시퀀스를 모델이 얼마나 높은 확률로 예측하는지 -> 언어 모델링 지표.

Execution Accuracy: 생성된 SQL 실행 결과가 정답과 같은지 -> 태스크 유효성 지표.
즉, Perplexity는 낮은데 Execution Accuracy는 높을 수도 있고(문법 다르지만 결과 동일), 그 반대도 가능합니다.



---

12) Throughput을 더 올리려면 어떻게 해야 하나요?

DP 늘리기: replica 수 확장.

배치 크기 키우기: --max-num-seqs, --max-num-batched-tokens 조정.

Prefix caching: 동일한 프롬프트를 캐싱해 prefill 비용 절감.
단, latency는 trade-off로 늘어날 수 있습니다.



---

13) Latency 튜닝 체크리스트는?

TP=2 유지(통신 최소화)

NVLink/NVSwitch 정상 동작 확인

NCCL 파라미터 튜닝 (CUDA_DEVICE_MAX_CONNECTIONS=1)

핫패스 로그 끄기(--disable-log-requests)

배치 크기 줄여 TTFT 개선

Speculative decoding 검토

프롬프트에서 불필요 토큰 제거



---

14) 블루-그린/카나리 배포와 리그레션 감시는 무엇인가요?

블루-그린: 기존 버전(블루)과 새 버전(그린)을 동시에 띄우고, 트래픽 전환만 스위치. 문제가 생기면 빠르게 롤백 가능.

카나리: 새 버전에 소량 트래픽(5%)만 흘려 안정성 확인 후 점차 확대.

리그레션 감시: 과거에 잘 동작하던 프롬프트와 응답을 저장 -> 새 버전에서 동일 입력으로 비교 -> 품질 하락 여부 즉시 감지.



---

15) SQL 실행 샌드박스란? PII는 무엇인가요?

SQL 샌드박스: 모델이 만든 SQL을 운영 DB에 바로 실행하지 않고, 읽기 전용 replica나 제한된 가상 DB에서만 실행하는 안전장치. DROP/UPDATE 같은 destructive 쿼리는 막음.

PII: Personally Identifiable Information(개인정보). 주민번호, 이메일, 전화번호 등.
NL2SQL 시스템은 PII 컬럼 조회 시 마스킹이나 권한 제어가 필요합니다.



---

16) 8GPU vs 16GPU에서 추천 세팅은?

8GPU: FP8, TP=2, DP=4 -> EP=8, max_new_tokens=32k~64k, kv-cache-dtype auto.

16GPU: FP8, TP=2, DP=8 -> EP=16, max_new_tokens=64k, 필요 시 speculative decoding.



---

17) 왜 TP=6은 에러가 나나요?

TP는 모델 차원이 나눠떨어져야 합니다.
예: num_heads=96, kv_heads=8, hidden=6144, ffn=8192 -> 6으로는 안 나눠짐.
보통 1/2/4/8 같은 2의 거듭제곱 값만 안전합니다.


---

18) 왜 PP=1인가요?

Inference에서는 파이프라인 병렬 시 **버블(빈 슬롯)**과 스케줄링 오버헤드가 발생해 오히려 성능이 떨어집니다.
따라서 학습과 달리 inference에선 PP=1이 일반적입니다.


---

19) 운영 지표는 어떻게 모니터링하나요?

Prometheus로 수집, Grafana로 대시보드 시각화.

vLLM /metrics endpoint 제공.

모니터링 지표: TTFT, ITL, throughput, OOM count, GPU utilization, GPU memory, NVLink 대역폭, 요청 큐 길이, error rate.

Alertmanager와 연동해 Slack/Email 알람 설정.



---

20) 정확도를 높이려면 어떤 방법이 있나요?

프롬프트 강화: 스키마 인식, 온톨로지 힌트 추가

Few-shot 예시 제공: NL2SQL 맥락 강화

후처리 Validator: SELECT-only, LIMIT 통일, 금지 토큰 제거 - > 실행 안정성 up
이를 통해 Execution Accuracy를 직접적으로 높일 수 있습니다.

작가의 이전글NL2SQL (Text-to-SQL) Agents 설계