하이퍼파라미터 튜닝

하이퍼파라미터 튜닝

SGLang 서버를 운영하다 보면 "왜 토큰 생성 속도가 생각만큼 안 나오지?" 하는 순간이 찾아와요. 그럴 때 대부분은 서버가 제대로 꽉 차서 돌고 있는지, 큐에 요청이 얼마나 쌓였는지, KV 캐시를 충분히 쓰고 있는지부터 살펴보게 되는데요. 이 페이지는 오프라인 배치 추론에서 높은 처리량을 얻기 위해 어떤 하이퍼파라미터를 어떻게 잡아가야 하는지를 강사 목소리로 하나씩 설명해 드릴게요. 기술 값과 명령어는 원문 그대로 보존했어요.

출처: 공식문서 - Hyperparameter Tuning

오프라인 배치 추론에서 높은 처리량을 얻기

오프라인 배치 추론에서 높은 처리량을 올리는 가장 핵심은 큰 배치 크기(batch size) 를 달성하는 거예요. 이게 왜 중요한지 감이 잘 안 오면, 서버가 풀로드(steady state)로 안정적으로 돌고 있을 때 로그에서 다음 문장들을 찾아보세요.

Decode batch. #running-req: 233, #token: 370959, token usage: 0.82, cuda graph: True, gen throughput (token/s): 4594.01, #queue-req: 317

이 로그 한 줄이 생각보다 많은 걸 알려줘요. #running-req는 현재 처리 중인 요청 수, token usage는 KV 캐시 메모리 사용률, #queue-req는 대기 중인 요청 수를 뜻해요. 이 값들을 보면서 아래 항목들을 하나씩 맞춰가면 돼요.

요청 제출 속도를 조절해 #queue-req 관리하기

#queue-req는 큐에 쌓여 있는 요청의 개수를 나타내요. 만약 #queue-req: 0이 자주 보인다면, 클라이언트 코드가 요청을 너무 느리게 보내고 있다는 뜻이에요. 정상 범위는 100 - 2000 정도예요. 다만 #queue-req를 너무 크게 만들면 서버의 스케줄링 오버헤드가 늘어나니까 주의하세요.

token usage를 높게 유지하기

token usage는 서버의 KV 캐시 메모리 활용률을 나타내요. token usage > 0.9면 잘 쓰고 있는 거예요.

만약 token usage < 0.9인데 #queue-req > 0인 상황이 자주 보인다면, 서버가 새 요청을 받아들이는 데 너무 보수적이라는 뜻이에요. 이럴 땐 --schedule-conservativeness를 0.3 같은 값으로 낮춰보세요. 이렇게 서버가 지나치게 보수적으로 굴 수 있는 상황은, 사용자가 max_new_tokens가 큰 요청을 많이 보냈는데 실제로는 EOS나 stop 문자열 때문에 요청이 아주 일찍 끝나버리는 경우에 생겨요.

반대로 token usage가 아주 높은데 다음과 같은 경고가 자주 뜨는 경우도 있어요.

KV cache pool is full. Retract requests. #retracted_reqs: 1, #new_token_ratio: 0.9998 -> 1.0000

이때는 --schedule-conservativeness를 1.3 같은 값으로 올려주면 돼요. KV cache pool is full. Retract requests.가 가끔(대략 1분에 1번 정도) 뜨는 건 문제없어요.

--mem-fraction-static을 튜닝해 KV 캐시 풀 용량 늘리기

SGLang은 메모리를 다음과 같이 나눠서 써요.

총 메모리 사용량 = 모델 가중치 + KV 캐시 풀 + CUDA 그래프 버퍼 + activations

--mem-fraction-static은 바로 이 중 처음 두 항목에 얼마만큼의 메모리를 배정할지 결정해요.

mem_fraction_static = (model weights + KV cache pool) / GPU memory capacity

더 높은 동시성을 받쳐주려면 KV 캐시 풀 용량을 최대한 키워야 하니까, activations와 CUDA 그래프 버퍼에 쓸 메모리를 충분히 남겨두면서 --mem-fraction-static을 가능한 한 높게 잡는 게 좋아요.

SGLang은 --mem-fraction-static 기본값을 단순한 휴리스틱으로 정하지만, 여러분의 사용 사례에 맞게 최적화할 수 있어요. 경험칙으로 activations용 메모리를 5–8 GB 정도 남겨두면 대개 충분해요. 서버가 준비되기 직전 로그를 보면 확인할 수 있어요.

[2025-08-11 17:17:03] max_total_num_tokens=665690, chunked_prefill_size=8192, max_prefill_tokens=16384, max_running_requests=4096, context_len=65536, available_gpu_mem=13.50 GB

여기서 available_gpu_mem 값을 확인해 보세요.

  • 5–8 GB 사이라면 설정이 잘 된 거예요.
  • 너무 높다면(예: 10 - 20 GB) --mem-fraction-static을 올려 KV 캐시에 더 많은 메모리를 주세요.
  • 너무 낮다면 나중에 OOM(out-of-memory) 에러가 날 위험이 있으니 --mem-fraction-static을 내려주세요.

좀 더 단순한 방법도 있어요. 워크로드에서 OOM이 날 때까지 --mem-fraction-static을 0.01씩 올려보는 거예요.

--chunked-prefill-size, --mem-fraction-static, --max-running-requests 튜닝으로 OOM 피하기

OOM(out-of-memory) 에러를 만났다면 다음 파라미터를 조정해 보세요.

  • prefill 중에 OOM이 나면 --chunked-prefill-size4096이나 2048로 줄여보세요. 메모리는 아끼지만 긴 프롬프트의 prefill 속도는 느려져요.
  • decoding 중에 OOM이 나면 --max-running-requests를 낮춰보세요.
  • --mem-fraction-static을 0.8이나 0.7 같은 더 작은 값으로 줄일 수도 있어요. KV 캐시 메모리 풀의 메모리 사용량이 줄어 prefill과 decoding 양쪽에서 OOM을 막아주지만, 최대 동시성(concurrency)이 제한되고 최고 처리량도 줄어들어요.

--cuda-graph-max-bs-decode 튜닝하기

기본적으로 CUDA graph는 작은 배치 크기(예: 160이나 256 미만)에서만 켜져 있어요. 그런데 일부 모델, 특히 텐서 병렬 크기가 큰 경우에는 배치 크기가 512나 768일 때까지도 CUDA graph가 유용할 수 있어요. 그래서 --cuda-graph-max-bs-decode를 더 큰 값으로 올리는 게 도움이 될 수 있어요. CUDA graph는 메모리를 더 쓰니까 동시에 --mem-fraction-static을 줄여야 할 수 있다는 점만 기억해 두세요.

--dp-size--tp-size 튜닝하기

처리량 측면에서는 데이터 병렬(Data parallelism)이 더 좋아요. GPU 메모리가 충분하다면 처리량을 위해 항상 데이터 병렬을 선호하세요. dp_size 파라미터를 쓰는 것보다는 SGLang Model Gateway (이전 Router) 쪽이 더 나은 데이터 병렬을 제공하니 참고해 보세요.

다른 옵션들 시도해 보기

  • torch.compile은 작은 배치 크기의 작은 모델을 가속해 줘요. --enable-torch-compile로 켤 수 있어요.
  • 다른 양자화를 시도해 보세요(예: --quantization fp8로 FP8 양자화).
  • 다른 병렬 전략(예: expert parallelism)이나 deepseek 모델용 DP attention(--enable-dp-attention --dp-size 8 사용)을 시도해 보세요.
  • 공유 프리픽스가 많은 워크로드라면 --schedule-policy lpm을 시도해 보세요. 여기서 lpm은 longest prefix match를 뜻해요. 캐시 히트를 늘리도록 요청 순서를 재배치하지만 스케줄링 오버헤드는 늘어나요.

더 알아보기 (Learn more)